mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-07-30 18:05:47 +00:00
refactor(utils): 新增 isPageOrFragment 统一页面与页面片判断
This commit is contained in:
parent
21baf58cda
commit
b85eaa9452
@ -7,8 +7,7 @@ import {
|
||||
DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX,
|
||||
dataSourceTemplateRegExp,
|
||||
getValueByKeyPath,
|
||||
isPage,
|
||||
isPageFragment,
|
||||
isPageOrFragment,
|
||||
NODE_CONDS_KEY,
|
||||
replaceChildNode,
|
||||
} from '@tmagic/core';
|
||||
@ -68,7 +67,7 @@ export const compliedConditions = (node: { [NODE_CONDS_KEY]?: DisplayCond[] }, d
|
||||
};
|
||||
|
||||
export const updateNode = (node: MNode, dsl: MApp) => {
|
||||
if (isPage(node) || isPageFragment(node)) {
|
||||
if (isPageOrFragment(node)) {
|
||||
const index = dsl.items?.findIndex((child: MNode) => child.id === node.id);
|
||||
dsl.items.splice(index, 1, node as MPage | MPageFragment);
|
||||
} else {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import { computed, markRaw, useTemplateRef } from 'vue';
|
||||
import { Files, Plus } from '@element-plus/icons-vue';
|
||||
|
||||
import { isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import ContentMenu from '@editor/components/ContentMenu.vue';
|
||||
import { useServices } from '@editor/hooks/use-services';
|
||||
@ -101,7 +101,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
type: 'button',
|
||||
text: '全部折叠',
|
||||
icon: FolderMinusIcon,
|
||||
display: () => isPage(node.value) || isPageFragment(node.value),
|
||||
display: () => isPageOrFragment(node.value),
|
||||
handler: () => {
|
||||
emit('collapse-all');
|
||||
},
|
||||
|
||||
@ -2,7 +2,7 @@ import { computed, type ComputedRef, nextTick, type Ref, type ShallowRef } from
|
||||
import { throttle } from 'lodash-es';
|
||||
|
||||
import { Id, MNode } from '@tmagic/core';
|
||||
import { getElById, isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { getElById, isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import type { LayerNodeStatus, Services, TreeNodeData } from '@editor/type';
|
||||
import { UI_SELECT_MODE_EVENT_NAME } from '@editor/utils/const';
|
||||
@ -36,7 +36,7 @@ export const useClick = (
|
||||
};
|
||||
|
||||
const multiSelect = async (data: MNode) => {
|
||||
if (isPage(data) || isPageFragment(data)) {
|
||||
if (isPageOrFragment(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ export const useClick = (
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPage(node) || isPageFragment(node)) {
|
||||
if (isPageOrFragment(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
|
||||
import type { Id, MApp, MNode, MPage, MPageFragment } from '@tmagic/core';
|
||||
import { getNodePath, isPage, isPageFragment, traverseNode } from '@tmagic/utils';
|
||||
import { getNodePath, isPageOrFragment, traverseNode } from '@tmagic/utils';
|
||||
|
||||
import type { LayerNodeStatus, Services } from '@editor/type';
|
||||
import { updateStatus } from '@editor/utils/tree';
|
||||
@ -136,7 +136,7 @@ export const useNodeStatus = ({ editorService }: Services) => {
|
||||
|
||||
const addHandler = (newNodes: MNode[]) => {
|
||||
newNodes.forEach((node) => {
|
||||
if (isPage(node) || isPageFragment(node)) return;
|
||||
if (isPageOrFragment(node)) return;
|
||||
|
||||
traverseNode(node, (node: MNode) => {
|
||||
nodeStatusMap.value?.set(node.id, {
|
||||
|
||||
@ -7,7 +7,7 @@ import { computed, markRaw, ref, useTemplateRef, watch } from 'vue';
|
||||
import { Bottom, Top } from '@element-plus/icons-vue';
|
||||
|
||||
import { NodeType } from '@tmagic/core';
|
||||
import { isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import ContentMenu from '@editor/components/ContentMenu.vue';
|
||||
import { useServices } from '@editor/hooks/use-services';
|
||||
@ -59,14 +59,14 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
direction: 'horizontal',
|
||||
display: () => {
|
||||
if (!node.value) return false;
|
||||
return !isPage(node.value) && !isPageFragment(node.value);
|
||||
return !isPageOrFragment(node.value);
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'button',
|
||||
text: '上移一层',
|
||||
icon: markRaw(Top),
|
||||
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
||||
display: () => !isPageOrFragment(node.value) && !props.isMultiSelect,
|
||||
handler: () => {
|
||||
editorService.moveLayer(1, { historySource: 'stage-contextmenu' });
|
||||
},
|
||||
@ -75,7 +75,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
type: 'button',
|
||||
text: '下移一层',
|
||||
icon: markRaw(Bottom),
|
||||
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
||||
display: () => !isPageOrFragment(node.value) && !props.isMultiSelect,
|
||||
handler: () => {
|
||||
editorService.moveLayer(-1, { historySource: 'stage-contextmenu' });
|
||||
},
|
||||
@ -84,7 +84,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
type: 'button',
|
||||
text: '置顶',
|
||||
icon: markRaw(Top),
|
||||
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
||||
display: () => !isPageOrFragment(node.value) && !props.isMultiSelect,
|
||||
handler: () => {
|
||||
editorService.moveLayer(LayerOffset.TOP, { historySource: 'stage-contextmenu' });
|
||||
},
|
||||
@ -93,7 +93,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
type: 'button',
|
||||
text: '置底',
|
||||
icon: markRaw(Bottom),
|
||||
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
||||
display: () => !isPageOrFragment(node.value) && !props.isMultiSelect,
|
||||
handler: () => {
|
||||
editorService.moveLayer(LayerOffset.BOTTOM, { historySource: 'stage-contextmenu' });
|
||||
},
|
||||
@ -102,7 +102,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
|
||||
{
|
||||
type: 'divider',
|
||||
direction: 'horizontal',
|
||||
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
||||
display: () => !isPageOrFragment(node.value) && !props.isMultiSelect,
|
||||
},
|
||||
useDeleteMenu('stage-contextmenu'),
|
||||
{
|
||||
|
||||
@ -357,7 +357,7 @@ class History extends BaseService {
|
||||
* 派发「页面 / 页面片结构变更」事件(`page-structure-change`)。
|
||||
*
|
||||
* 常规 `editorService.add` / `remove` 页面节点不会写入 `page` 历史栈(见 editor.add / remove 中
|
||||
* 对 isPage / isPageFragment 的分支),因此不会产生任何 historyService 事件。该方法用于在这些
|
||||
* 对 isPageOrFragment 的分支),因此不会产生任何 historyService 事件。该方法用于在这些
|
||||
* 场景(以及 setRoot 整体替换 DSL 增删页面)下,向外统一通知页面结构的增删变化,供业务方感知。
|
||||
*
|
||||
* 一次操作涉及多个页面时,调用方应把本次增删的页面**合并为一个 change 一次性传入**,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import KeyController, { KeyControllerEvent } from 'keycon';
|
||||
|
||||
import { isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import { KeyBindingCacheItem, KeyBindingCommand, KeyBindingItem } from '@editor/type';
|
||||
|
||||
@ -19,7 +19,7 @@ class Keybinding extends BaseService {
|
||||
[KeyBindingCommand.DELETE_NODE]: () => {
|
||||
const nodes = editorService.get('nodes');
|
||||
|
||||
if (!nodes || isPage(nodes[0]) || isPageFragment(nodes[0])) return;
|
||||
if (!nodes || isPageOrFragment(nodes[0])) return;
|
||||
editorService.remove(nodes, { historySource: 'shortcut' });
|
||||
},
|
||||
[KeyBindingCommand.COPY_NODE]: () => {
|
||||
@ -29,7 +29,7 @@ class Keybinding extends BaseService {
|
||||
[KeyBindingCommand.CUT_NODE]: () => {
|
||||
const nodes = editorService.get('nodes');
|
||||
|
||||
if (!nodes || isPage(nodes[0]) || isPageFragment(nodes[0])) return;
|
||||
if (!nodes || isPageOrFragment(nodes[0])) return;
|
||||
editorService.copy(nodes);
|
||||
editorService.remove(nodes, { historySource: 'shortcut' });
|
||||
},
|
||||
|
||||
@ -2,7 +2,7 @@ import { computed, markRaw, type ShallowRef } from 'vue';
|
||||
import { CopyDocument, Delete, DocumentCopy } from '@element-plus/icons-vue';
|
||||
|
||||
import { cloneDeep, Id, MContainer, NodeType } from '@tmagic/core';
|
||||
import { calcValueByFontsize, isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { calcValueByFontsize, isPage, isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import ContentMenu from '@editor/components/ContentMenu.vue';
|
||||
import type { HistoryOpSource, MenuButton, Services } from '@editor/type';
|
||||
@ -20,7 +20,7 @@ export const useDeleteMenu = (historySource?: HistoryOpSource): MenuButton => ({
|
||||
icon: Delete,
|
||||
display: ({ editorService }) => {
|
||||
const node = editorService.get('node');
|
||||
return node?.type !== NodeType.ROOT && !isPage(node) && !isPageFragment(node);
|
||||
return node?.type !== NodeType.ROOT && !isPageOrFragment(node);
|
||||
},
|
||||
handler: ({ editorService }) => {
|
||||
const nodes = editorService.get('nodes');
|
||||
|
||||
@ -3,7 +3,7 @@ import { isEmpty } from 'lodash-es';
|
||||
|
||||
import type { Id, MContainer, MNode } from '@tmagic/core';
|
||||
import { NodeType } from '@tmagic/core';
|
||||
import { calcValueByFontsize, getElById, isPage, isPageFragment } from '@tmagic/utils';
|
||||
import { calcValueByFontsize, getElById, isPage, isPageOrFragment } from '@tmagic/utils';
|
||||
|
||||
import editorService from '@editor/services/editor';
|
||||
import propsService from '@editor/services/props';
|
||||
@ -58,7 +58,7 @@ export const beforePaste = (position: PastePosition, config: MNode[], doc?: Docu
|
||||
};
|
||||
}
|
||||
const root = editorService.get('root');
|
||||
if ((isPage(pasteConfig) || isPageFragment(pasteConfig)) && root) {
|
||||
if (isPageOrFragment(pasteConfig) && root) {
|
||||
pasteConfig.name = generatePageNameByApp(root, isPage(pasteConfig) ? NodeType.PAGE : NodeType.PAGE_FRAGMENT);
|
||||
}
|
||||
return pasteConfig as MNode;
|
||||
|
||||
@ -144,7 +144,6 @@ vi.mock('@tmagic/utils', async () => {
|
||||
...actual,
|
||||
getDepNodeIds: vi.fn(() => []),
|
||||
getNodes: vi.fn(() => []),
|
||||
isPage: vi.fn((n: any) => n?.type === 'page'),
|
||||
isValueIncludeDataSource: vi.fn((v: any) => /\$\{/.test(String(v))),
|
||||
};
|
||||
});
|
||||
|
||||
@ -28,15 +28,6 @@ vi.mock('@editor/utils/content-menu', () => ({
|
||||
useMoveToMenu: () => ({ type: 'button', text: 'moveto' }),
|
||||
}));
|
||||
|
||||
vi.mock('@tmagic/utils', async () => {
|
||||
const actual = await vi.importActual<any>('@tmagic/utils');
|
||||
return {
|
||||
...actual,
|
||||
isPage: (n: any) => n?.type === 'page',
|
||||
isPageFragment: (n: any) => n?.type === 'page-fragment',
|
||||
};
|
||||
});
|
||||
|
||||
const showMock = vi.fn();
|
||||
vi.mock('@editor/components/ContentMenu.vue', () => ({
|
||||
default: defineComponent({
|
||||
|
||||
@ -17,8 +17,6 @@ vi.mock('@tmagic/utils', async () => {
|
||||
const actual = await vi.importActual<any>('@tmagic/utils');
|
||||
return {
|
||||
...actual,
|
||||
isPage: (n: any) => n.type === 'page',
|
||||
isPageFragment: (n: any) => n.type === 'page-fragment',
|
||||
getElById: () => (_doc: any, id: any) => (id === 'no-el' ? null : { id }),
|
||||
};
|
||||
});
|
||||
|
||||
@ -12,13 +12,7 @@ vi.mock('@tmagic/utils', async () => {
|
||||
const actual = await vi.importActual<any>('@tmagic/utils');
|
||||
return {
|
||||
...actual,
|
||||
isPage: (n: any) => n.type === 'page',
|
||||
isPageFragment: (n: any) => n.type === 'page-fragment',
|
||||
getNodePath: vi.fn(() => []),
|
||||
traverseNode: (node: any, fn: any) => {
|
||||
fn(node);
|
||||
node.items?.forEach((c: any) => fn(c));
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -24,11 +24,6 @@ vi.mock('@editor/hooks/use-services', () => ({
|
||||
useServices: () => ({ editorService }),
|
||||
}));
|
||||
|
||||
vi.mock('@tmagic/utils', () => ({
|
||||
isPage: (n: any) => n?.type === 'page',
|
||||
isPageFragment: (n: any) => n?.type === 'page-fragment',
|
||||
}));
|
||||
|
||||
vi.mock('@editor/utils/content-menu', () => ({
|
||||
useCopyMenu: () => ({ type: 'button', text: '复制', handler: vi.fn() }),
|
||||
usePasteMenu: () => ({ type: 'button', text: '粘贴', handler: vi.fn() }),
|
||||
|
||||
@ -142,7 +142,7 @@ export const getNodeInfo = (id: Id, root: { id: Id; items?: MNode[] } | null, sk
|
||||
info.parent = path[path.length - 2] as MContainer;
|
||||
|
||||
for (const item of path) {
|
||||
if (isPage(item) || isPageFragment(item)) {
|
||||
if (isPageOrFragment(item)) {
|
||||
info.page = item as MPage | MPageFragment;
|
||||
break;
|
||||
}
|
||||
@ -279,6 +279,10 @@ export const isPageFragment = (node?: Pick<MComponent, 'type'> | null): boolean
|
||||
return Boolean(node.type?.toLowerCase() === NodeType.PAGE_FRAGMENT);
|
||||
};
|
||||
|
||||
/** 是否为页面或页面片 */
|
||||
export const isPageOrFragment = (node?: Pick<MComponent, 'type'> | null): boolean =>
|
||||
isPage(node) || isPageFragment(node);
|
||||
|
||||
export const isNumber = (value: any) =>
|
||||
(typeof value === 'number' && !isNaN(value)) || /^(-?\d+)(\.\d+)?$/.test(`${value}`);
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@ import {
|
||||
isNumber,
|
||||
isObject,
|
||||
isPageFragment,
|
||||
isPageOrFragment,
|
||||
isPercentage,
|
||||
isPop,
|
||||
isValueIncludeDataSource,
|
||||
@ -112,6 +113,14 @@ describe('node 类型判断', () => {
|
||||
expect(isPageFragment(null)).toBe(false);
|
||||
});
|
||||
|
||||
test('isPageOrFragment 识别 page 与 page-fragment', () => {
|
||||
expect(isPageOrFragment({ id: 1, type: NodeType.PAGE })).toBe(true);
|
||||
expect(isPageOrFragment({ id: 1, type: NodeType.PAGE_FRAGMENT })).toBe(true);
|
||||
expect(isPageOrFragment({ id: 1, type: 'text' })).toBe(false);
|
||||
expect(isPageOrFragment(undefined)).toBe(false);
|
||||
expect(isPageOrFragment(null)).toBe(false);
|
||||
});
|
||||
|
||||
test('isDslNode 默认为 true,手动 false 关闭', () => {
|
||||
expect(isDslNode({ type: 'text' } as any)).toBe(true);
|
||||
expect(isDslNode({ type: 'text', [IS_DSL_NODE_KEY]: false } as any)).toBe(false);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user