chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
@@ -26,7 +26,7 @@ export const ActionBarContext = createContext<{
|
||||
controller: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
hideActionBar: () => {},
|
||||
// 重新定位
|
||||
// reposition
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
rePosition: () => {},
|
||||
},
|
||||
|
||||
@@ -135,7 +135,7 @@ export const ActionBar: React.FC<PropsWithChildren<ActionBarProps>> = props => {
|
||||
// }
|
||||
|
||||
editor.$on('mousedown', handleMousedown);
|
||||
// 不使用 editor.$on 监听 mouseup 事件,因为鼠标可能不在编辑器内
|
||||
// Do not use editor. $on to listen for mouseup events because the mouse may not be in the editor
|
||||
document.addEventListener('mouseup', handleMouseup);
|
||||
editor.$on('selectionChange', handleSelectionChange);
|
||||
// editor.$on('blur', handleBlur);
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from '../constant';
|
||||
|
||||
export namespace ExpressionEditorParserBuiltin {
|
||||
/** 计算开始和结束标识的序号 */
|
||||
/** Calculate the serial number of the start and end tags */
|
||||
export const tokenOffset = (line: {
|
||||
lineContent: string;
|
||||
lineOffset: number;
|
||||
@@ -49,7 +49,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
firstEndTokenOffset + 2,
|
||||
);
|
||||
if (endChars !== ExpressionEditorToken.FullEnd) {
|
||||
// 结束符号 "}}" 不完整
|
||||
// End symbol "}}" is incomplete
|
||||
return;
|
||||
}
|
||||
const lastStartTokenOffset = content.lastIndexOf(
|
||||
@@ -61,7 +61,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
lastStartTokenOffset + 1,
|
||||
);
|
||||
if (startChars !== ExpressionEditorToken.FullStart) {
|
||||
// 开始符号 "{{" 不完整
|
||||
// The opening symbol "{{" is incomplete
|
||||
return;
|
||||
}
|
||||
return {
|
||||
@@ -70,7 +70,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
};
|
||||
};
|
||||
|
||||
/** 从行内容提取内容 */
|
||||
/** Extract content from line content */
|
||||
export const extractContent = (params: {
|
||||
lineContent: string;
|
||||
lineOffset: number;
|
||||
@@ -99,7 +99,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
};
|
||||
};
|
||||
|
||||
/** 根据 offset 将文本内容切分为可用与不可用 */
|
||||
/** Split text content into available and unavailable by offset */
|
||||
export const sliceReachable = (params: {
|
||||
content: string;
|
||||
offset: number;
|
||||
@@ -116,29 +116,29 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
};
|
||||
};
|
||||
|
||||
/** 切分文本 */
|
||||
/** Split text */
|
||||
export const splitText = (pathString: string): string[] => {
|
||||
// 得到的分割数组,初始为原字符串以"."分割的结果
|
||||
// The obtained split array, initially the result of splitting the original string with "."
|
||||
const segments = pathString.split(ExpressionEditorToken.Separator);
|
||||
|
||||
// 定义结果数组,并处理连续的"."导致的空字符串
|
||||
// Define the result array and handle empty strings resulting from consecutive "."
|
||||
const result: string[] = [];
|
||||
|
||||
segments.forEach(segment => {
|
||||
if (!segment.match(/\[\d+\]/)) {
|
||||
// 如果不是数组索引,直接加入结果数组,即使是空字符串也加入以保持正确的分割
|
||||
// If it is not an array index, add the result array directly, even if it is an empty string, to maintain the correct segmentation
|
||||
result.push(segment);
|
||||
return;
|
||||
}
|
||||
// 如果当前段是数组索引,将前面的字符串和当前数组索引分别加入结果数组
|
||||
// If the current segment is an array index, add the previous string and the current array index to the result array, respectively
|
||||
const lastSegmentIndex = segment.lastIndexOf(
|
||||
ExpressionEditorToken.ArrayStart,
|
||||
);
|
||||
const key = segment.substring(0, lastSegmentIndex);
|
||||
const index = segment.substring(lastSegmentIndex);
|
||||
// {{array[0]}} 中的 array
|
||||
// Array in {{array [0]}}
|
||||
result.push(key);
|
||||
// {{array[0]}} 中的 [0]
|
||||
// [0] in {{array [0]}}
|
||||
result.push(index);
|
||||
return;
|
||||
});
|
||||
@@ -146,14 +146,14 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
return result;
|
||||
};
|
||||
|
||||
/** 字符串解析为路径 */
|
||||
/** String parsed as path */
|
||||
export const toSegments = (
|
||||
text: string,
|
||||
): ExpressionEditorSegment[] | undefined => {
|
||||
const textSegments = ExpressionEditorParserBuiltin.splitText(text);
|
||||
const segments: ExpressionEditorSegment[] = [];
|
||||
const validate = textSegments.every((textSegment, index) => {
|
||||
// 数组下标
|
||||
// array subscript
|
||||
if (
|
||||
textSegment.startsWith(ExpressionEditorToken.ArrayStart) &&
|
||||
textSegment.endsWith(ExpressionEditorToken.ArrayEnd)
|
||||
@@ -161,7 +161,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
const arrayIndexString = textSegment.slice(1, -1);
|
||||
const arrayIndex = Number(arrayIndexString);
|
||||
if (arrayIndexString === '' || Number.isNaN(arrayIndex)) {
|
||||
// index 必须是数字
|
||||
// Index must be a number
|
||||
return false;
|
||||
}
|
||||
const lastSegment = segments[segments.length - 1];
|
||||
@@ -169,7 +169,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
!lastSegment ||
|
||||
lastSegment.type !== ExpressionEditorSegmentType.ObjectKey
|
||||
) {
|
||||
// 数组索引必须在 key 之后
|
||||
// The array index must be after the key
|
||||
return false;
|
||||
}
|
||||
segments.push({
|
||||
@@ -178,7 +178,7 @@ export namespace ExpressionEditorParserBuiltin {
|
||||
arrayIndex,
|
||||
});
|
||||
}
|
||||
// 最后一行空文本
|
||||
// The last empty line of text
|
||||
else if (index === textSegments.length - 1 && textSegment === '') {
|
||||
segments.push({
|
||||
type: ExpressionEditorSegmentType.EndEmpty,
|
||||
|
||||
@@ -43,7 +43,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
const lastSegment = segments[segments.length - 1];
|
||||
const segmentsRemovedLast =
|
||||
lastSegment.type === ExpressionEditorSegmentType.ArrayIndex
|
||||
? segments.slice(0, segments.length - 2) // 数组索引属于上一层级,需要去除两层
|
||||
? segments.slice(0, segments.length - 2) // The array index belongs to the previous level, and two layers need to be removed.
|
||||
: segments.slice(0, segments.length - 1);
|
||||
let treeLayer = tree;
|
||||
segmentsRemovedLast.forEach(segment => {
|
||||
@@ -53,7 +53,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
const treeChildren = treeLayer.filter(
|
||||
node => node.label === segment.objectKey,
|
||||
);
|
||||
// 兼容变量名重复,但子字段不同的场景
|
||||
// Compatible variable names are duplicated, but the subfields are different
|
||||
if (treeChildren?.length) {
|
||||
treeLayer = treeChildren.reduce(
|
||||
(pre: ExpressionEditorTreeNode[], cur: ExpressionEditorTreeNode) => {
|
||||
@@ -80,7 +80,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
const pathList: { objectKey: string; arrayIndex?: number }[] = [];
|
||||
while (current) {
|
||||
if (current.variable?.type === ViewVariableType.ArrayObject) {
|
||||
// 默认第0个
|
||||
// Default 0th
|
||||
pathList.unshift({
|
||||
objectKey: current.label,
|
||||
arrayIndex: 0,
|
||||
@@ -100,7 +100,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
const pathItem = pathList[pathIndex];
|
||||
pathIndex++;
|
||||
if (pathItem.objectKey !== segment.objectKey) {
|
||||
// 退出循环
|
||||
// exit the loop
|
||||
return true;
|
||||
}
|
||||
const nextSegment = segments[index + 1];
|
||||
@@ -140,7 +140,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
return false;
|
||||
};
|
||||
const beforeTreeNode = treeBranch[treeBranch.length - 1];
|
||||
// 确认非法情况:是否对非数组类型使用数组索引
|
||||
// Verify Illegal Case: Whether to Use Array Indexing for Non-Array Types
|
||||
if (
|
||||
segment.type === ExpressionEditorSegmentType.ArrayIndex &&
|
||||
beforeTreeNode &&
|
||||
@@ -148,7 +148,7 @@ export namespace ExpressionEditorTreeHelper {
|
||||
) {
|
||||
return itemInvalid();
|
||||
}
|
||||
// 确认非法情况:数组只能跟随数组下标
|
||||
// Confirm illegal condition: Array can only follow array subscript
|
||||
if (
|
||||
beforeTreeNode?.variable?.type &&
|
||||
isArrayType(beforeTreeNode.variable.type) &&
|
||||
@@ -156,12 +156,12 @@ export namespace ExpressionEditorTreeHelper {
|
||||
) {
|
||||
return itemInvalid();
|
||||
}
|
||||
// 忽略
|
||||
// ignore
|
||||
if (segment.type !== ExpressionEditorSegmentType.ObjectKey) {
|
||||
return itemValid();
|
||||
}
|
||||
const treeNode = treeLayer.find(node => node.label === segment.objectKey);
|
||||
// 确认非法情况:每一个 object key 必须对应一个 variable node
|
||||
// Verify illegal condition: each object key must correspond to a variable node
|
||||
if (!treeNode) {
|
||||
return itemInvalid();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface Variable {
|
||||
type: VariableType;
|
||||
name: string;
|
||||
children?: Variable[];
|
||||
// 用户自定义节点名展示
|
||||
// user-defined node name display
|
||||
label?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ function useSelection(editor: ExpressionEditorAPI | undefined) {
|
||||
const view = editor.$view;
|
||||
|
||||
function updateSelection(update?: ViewUpdate) {
|
||||
// 忽略 replaceTextByRange 导致的 selection change(效果:不触发 selection 变更,进而不显示推荐面板)
|
||||
// Ignore the selection change caused by replaceTextByRange (effect: no selection change is triggered, and the recommendation panel is not displayed)
|
||||
if (update?.transactions.some(tr => isSkipSelectionChangeUserEvent(tr))) {
|
||||
setSelection(undefined);
|
||||
return;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { generateUniqueId, getSearchValue, useLatest } from '../../shared';
|
||||
import { type ExpressionEditorTreeNode } from '../../core';
|
||||
import { type CompletionContext } from './types';
|
||||
|
||||
// 在数据更新后,强制 Tree 组件重新渲染
|
||||
// Force the Tree component to re-render after the data update
|
||||
function useTreeRefresh(filteredVariableTree: ExpressionEditorTreeNode[]) {
|
||||
const [treeRefreshKey, setTreeRefreshKey] = useState('');
|
||||
|
||||
@@ -33,7 +33,7 @@ function useTreeRefresh(filteredVariableTree: ExpressionEditorTreeNode[]) {
|
||||
return treeRefreshKey;
|
||||
}
|
||||
|
||||
// Tree 组件重新渲染后进行搜索
|
||||
// Search after the Tree component is re-rendered
|
||||
// eslint-disable-next-line max-params
|
||||
function useTreeSearch(
|
||||
treeRefreshKey: string,
|
||||
|
||||
@@ -140,10 +140,10 @@ function Popover({
|
||||
const { elements } = optionsInfo;
|
||||
selectNodeByIndex(elements, 0);
|
||||
});
|
||||
// selected 仅用于 Tree 组件对应项展示蓝色选中效果,无其他用途
|
||||
// Selected is only used to display the blue selection effect for the corresponding item of the Tree component, and has no other purpose.
|
||||
const selected = useSelectedValue(completionContext?.text, variableTree);
|
||||
|
||||
// 基于用户选中项,替换所在 {{}} 中的内容
|
||||
// Replace content in {{}} based on user selection
|
||||
const handleSelect = useCallback(
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
(_: string, __: boolean, node: TreeNodeData) => {
|
||||
@@ -166,7 +166,7 @@ function Popover({
|
||||
Boolean(emptyContent));
|
||||
|
||||
const [allowVisible, setAllowVisible] = useState(false);
|
||||
// 选区变化时,清除锁定效果
|
||||
// Clear the lock effect when the selection changes
|
||||
useEffect(() => {
|
||||
setAllowVisible(true);
|
||||
}, [selection]);
|
||||
@@ -180,14 +180,14 @@ function Popover({
|
||||
treeRef,
|
||||
);
|
||||
|
||||
// 上下键切换推荐项,回车填入
|
||||
// Press the up and down keys to switch the recommended items, and press Enter to fill in.
|
||||
useKeyboard(visible, {
|
||||
ArrowUp: prev,
|
||||
ArrowDown: next,
|
||||
Enter: apply,
|
||||
});
|
||||
|
||||
// ESC 关闭
|
||||
// ESC Close
|
||||
useKeyboard(visible, {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
Escape() {
|
||||
@@ -195,7 +195,7 @@ function Popover({
|
||||
},
|
||||
});
|
||||
|
||||
// 推荐面板出现时,禁用 ArrowUp/ArrowDown/Enter 的默认行为(行为改为上下键切换推荐项 & 回车插入)
|
||||
// When the recommendation panel appears, disable the default behavior of ArrowUp/ArrowDown/Enter (the behavior is changed to up and down keys to switch recommendations & enter to insert)
|
||||
useEffect(() => {
|
||||
if (visible === true) {
|
||||
editorRef.current?.disableKeybindings(['ArrowUp', 'ArrowDown', 'Enter']);
|
||||
|
||||
@@ -62,7 +62,7 @@ const getOptionInfoFromDOM = (
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有的选项元素
|
||||
// Get all option elements
|
||||
const foundNodes = root.querySelectorAll(
|
||||
'.semi-tree-option-list .semi-tree-option',
|
||||
);
|
||||
@@ -73,7 +73,7 @@ const getOptionInfoFromDOM = (
|
||||
|
||||
const optionElements = [...foundNodes];
|
||||
|
||||
// 找到当前高亮的选项
|
||||
// Find the currently highlighted option
|
||||
const selectedIndex = optionElements.findIndex(element =>
|
||||
element.classList.contains(getSelectedClassName()),
|
||||
);
|
||||
|
||||
@@ -33,10 +33,10 @@ function useLatest<T>(value: T): MutableRefObject<T> {
|
||||
return ref;
|
||||
}
|
||||
|
||||
// 解除 parent 导致的循环依赖(否则无法深比较)
|
||||
// Remove circular dependencies caused by parents (otherwise no deep comparison is possible)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function cloneWithout(target: any, keys: string[]) {
|
||||
// target 为 undefined 时会抛错
|
||||
// An error is thrown when target is undefined
|
||||
try {
|
||||
return JSON.parse(
|
||||
JSON.stringify(target, function (key, value) {
|
||||
@@ -85,7 +85,7 @@ function getSearchValue(textBefore: string) {
|
||||
const lastSegment =
|
||||
segments[segments.length - 1].type ===
|
||||
ExpressionEditorSegmentType.ArrayIndex
|
||||
? segments[segments.length - 2] // 数组索引属于上一层级,需要去除防止影响到搜索值
|
||||
? segments[segments.length - 2] // The array index belongs to the previous level and needs to be removed to prevent it from affecting the search value
|
||||
: segments[segments.length - 1];
|
||||
if (
|
||||
!lastSegment ||
|
||||
|
||||
@@ -70,9 +70,9 @@ function Validation({ variableTree }: Props) {
|
||||
|
||||
if (
|
||||
cursor.name === 'JinjaExpression' &&
|
||||
// 由于 parser 存在容错能力
|
||||
// 可能出现缺少右花括号也被正常解析为 Interpolation 的情况
|
||||
// 如:{{variable
|
||||
// Due to the fault tolerance of the parser
|
||||
// It is possible that the missing right curly brace is also parsed normally as Interpolation
|
||||
// Such as: {{variable
|
||||
cursor.node.firstChild?.name === 'JinjaExpressionStart' &&
|
||||
cursor.node.lastChild?.name === 'JinjaExpressionEnd'
|
||||
) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
/**
|
||||
* 前端变量类型
|
||||
* Front-end variable type
|
||||
*/
|
||||
export enum ViewVariableType {
|
||||
String = 1,
|
||||
@@ -39,7 +39,7 @@ export enum ViewVariableType {
|
||||
Svg,
|
||||
Voice,
|
||||
Time,
|
||||
// 上面是 api 中定义的 InputType。下面是整合后的。从 99 开始,避免和后端定义撞车
|
||||
// The above is the InputType defined in the api. The following is the integrated one. Start from 99 to avoid collisions with the backend definition.
|
||||
ArrayString = 99,
|
||||
ArrayInteger,
|
||||
ArrayBoolean,
|
||||
|
||||
@@ -57,7 +57,7 @@ export const useSelectionInJinjaRaw = () => {
|
||||
|
||||
editor.$on('viewUpdate', checkInJinjaRaw);
|
||||
|
||||
// 初始检查
|
||||
// Initial inspection
|
||||
checkInJinjaRaw();
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -39,7 +39,7 @@ export const ConfigModeWidgetPopover = (props: {
|
||||
}
|
||||
const handleViewUpdate = (e: ViewUpdate) => {
|
||||
if (e.docChanged) {
|
||||
// 判断当前光标是否在 slot 节点内
|
||||
// Determine whether the current cursor is in the slot node
|
||||
const { state } = e;
|
||||
const range = templateParser.getCursorInMarkNodeRange(state);
|
||||
if (!range) {
|
||||
|
||||
@@ -91,7 +91,7 @@ export class LibraryBlockWidgetType extends WidgetType {
|
||||
}
|
||||
|
||||
if (!this.mounted) {
|
||||
// 同步渲染,避免抖动
|
||||
// Synchronized rendering to avoid jitter
|
||||
this.renderLibraryBlock(this.options);
|
||||
this.renderTooltip(this.options);
|
||||
this.mounted = true;
|
||||
@@ -271,7 +271,7 @@ export const LibraryBlockWidgetReactCom = (props: {
|
||||
</span>
|
||||
);
|
||||
|
||||
// 只在tooltipConfig存在时渲染Tooltip
|
||||
// Render Tooltip only if tooltipConfig exists
|
||||
if (!tooltipConfig) {
|
||||
return baseElement;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ export const LibrarySearchPopover = ({
|
||||
setToPosition(toB);
|
||||
setVisible(true);
|
||||
} else {
|
||||
// 一些场景输入 { 不应该弹出提示面板
|
||||
// 如:光标在 {{ }} 内,或在 {% %} 内,或在 {# #} 内
|
||||
// Some scene input {should not pop up the prompt panel
|
||||
// For example, the cursor is within {{ }} , or within {% %} , or within {# #}
|
||||
setVisible(false);
|
||||
}
|
||||
} else {
|
||||
@@ -114,7 +114,7 @@ export const LibrarySearchPopover = ({
|
||||
}),
|
||||
},
|
||||
});
|
||||
// 去除插入的快捷键, 因为原来自动添加了
|
||||
// Remove the inserted shortcut, because the original was automatically added
|
||||
templateParser.insertTemplateByRange(editor, template, {
|
||||
from: position,
|
||||
to: toPosition,
|
||||
|
||||
@@ -57,7 +57,7 @@ const defaultLibraryBlockInfo: Record<
|
||||
icon: imageIcon,
|
||||
},
|
||||
};
|
||||
// 根据资源类型获取对应的信息
|
||||
// Get the corresponding information according to the resource type
|
||||
export const getLibraryBlockInfoFromTemplate = (props: {
|
||||
template: string;
|
||||
templateParser: TemplateParser;
|
||||
|
||||
@@ -129,7 +129,7 @@ export const ContentSearchPopover = ({
|
||||
activeKey={activeTab}
|
||||
onChange={key => {
|
||||
setActiveTab(key);
|
||||
// 保证切换tab后光标仍然定位在编辑器上
|
||||
// Make sure the cursor is still positioned on the editor after switching tabs
|
||||
setTimeout(() => {
|
||||
editorRef.current?.$view.focus();
|
||||
}, 0);
|
||||
|
||||
@@ -43,7 +43,7 @@ const getOptionInfoFromDOM = (
|
||||
|
||||
const optionElements = [...foundNodes];
|
||||
|
||||
// 找到当前高亮的选项
|
||||
// Find the currently highlighted option
|
||||
const selectedIndex = optionElements.findIndex(element =>
|
||||
element.classList.contains(SELECTED_OPTION_CLASSNAME),
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function useVariablesTree({
|
||||
|
||||
const selected = useSelectedValue(completionContext?.text, variableTree);
|
||||
|
||||
// 基于用户选中项,替换所在 {{}} 中的内容
|
||||
// Replace content in {{}} based on user selection
|
||||
const handleSelect = useCallback(
|
||||
(_: string, __: boolean, node: TreeNodeData) => {
|
||||
if (!editor || !completionContext) {
|
||||
@@ -101,7 +101,7 @@ export default function useVariablesTree({
|
||||
treeRef,
|
||||
);
|
||||
|
||||
// 上下键切换推荐项,回车填入
|
||||
// Press the up and down keys to switch the recommended items, and press Enter to fill in.
|
||||
useKeyboard(enableKeyboard, {
|
||||
ArrowUp: prev,
|
||||
ArrowDown: next,
|
||||
|
||||
@@ -30,7 +30,7 @@ export interface MarkRangeInfo {
|
||||
close: MarkRange;
|
||||
}
|
||||
|
||||
// 解析模板字符串: {#slot name="slot_name" #}xxx{#/slot#}
|
||||
// Parse template string: {#slot name = "slot_name" #} xxx {#/slot #}
|
||||
export class TemplateParser {
|
||||
public mark!: 'LibraryBlock' | 'InputSlot';
|
||||
private openReg!: RegExp;
|
||||
@@ -125,28 +125,28 @@ export class TemplateParser {
|
||||
return close;
|
||||
}
|
||||
|
||||
// 解析模板字符串: {#slot id="slot_id" value="slot_value"#},获取所有属性
|
||||
// Parse template string: {#slot id = "slot_id" value = "slot_value" #}, get all properties
|
||||
getData(templateString: string): { [key: string]: string } | null {
|
||||
// 根据传入的类型构造正则表达式,例如 slot 或 block
|
||||
// Constructs regular expressions based on the type passed in, such as slots or blocks
|
||||
const regex = new RegExp(`\\{#${this.mark}\\s+([^#]+)#\\}`, 'g');
|
||||
const match = regex.exec(templateString);
|
||||
if (match !== null) {
|
||||
const attributes = match[1].trim(); // 匹配到的属性部分
|
||||
const attributes = match[1].trim(); // Matched attribute part
|
||||
const attrRegex = /(\w+)\s*=\s*"([^"]*)"/g;
|
||||
const obj: { [key: string]: string } = {}; // 初始对象
|
||||
const obj: { [key: string]: string } = {}; // initial object
|
||||
let attrMatch: RegExpExecArray | null;
|
||||
while (true) {
|
||||
attrMatch = attrRegex.exec(attributes);
|
||||
if (attrMatch === null) {
|
||||
break;
|
||||
}
|
||||
obj[attrMatch[1]] = attrMatch[2]; // 将匹配的键值对添加到对象中
|
||||
obj[attrMatch[1]] = attrMatch[2]; // Adds a matching key-value pair to the object
|
||||
}
|
||||
|
||||
return obj; // 返回解析结果
|
||||
return obj; // Return the parsing result
|
||||
}
|
||||
|
||||
return null; // 没有匹配时返回 null
|
||||
return null; // Returns null if there is no match
|
||||
}
|
||||
|
||||
getCursorTemplateData(state: EditorState) {
|
||||
@@ -218,8 +218,8 @@ export class TemplateParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改当前光标所在位置的模板数据: {#slot placeholder="default_placeholder"#} 修改为 {#slot placeholder="new_placeholder"#}
|
||||
* 新增: {#slot placeholder="default_placeholder"#} 新增 {#slot value="new_value" placeholder="new_placeholder"#}
|
||||
* Modify the template data for the current cursor position: {#slot placeholder = "default_placeholder" #} Modify to {#slot placeholder = "new_placeholder" #}
|
||||
* Added: {#slot placeholder = "default_placeholder" #} Added {#slot value = "new_value" placeholder = "new_placeholder" #}
|
||||
*/
|
||||
updateCursorTemplateData(editor: EditorAPI, data: { [key: string]: string }) {
|
||||
const { state } = editor.$view;
|
||||
@@ -347,14 +347,14 @@ export class TemplateParser {
|
||||
},
|
||||
});
|
||||
}
|
||||
// 提取模板中内容{#InputSlot placeholder="placeholder"#}123{#/InputSlot#}xxx,嵌套模板下内部所有的content
|
||||
// Extract the content in the template {#InputSlot placeholder = "placeholder" #} 123 {#/InputSlot #} xxx, all the internal content under the nested template
|
||||
extractTemplateContent(template: string) {
|
||||
// 使用正则表达式匹配 {#InputSlot ... #} 的部分
|
||||
// Use regular expressions to match parts of {#InputSlot... #}
|
||||
const regex = new RegExp(
|
||||
`\\{#${this.mark}\\s+[^#]+#\\}|\\{#\\/${this.mark}#\\}`,
|
||||
'g',
|
||||
);
|
||||
// 使用 replace 方法替换掉匹配的部分
|
||||
// Use the replace method to replace the matching part
|
||||
const result = template.replace(regex, '');
|
||||
console.log('extractTemplateContent', result);
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user