2022-04-22 12:16:39 +08:00

252 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { random } from 'lodash-es';
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
import { NodeType } from '@tmagic/schema';
import type StageCore from '@tmagic/stage';
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
import { Layout } from '@editor/type';
export const COPY_STORAGE_KEY = '$MagicEditorCopyData';
export const generateId = (type: string | number): string => `${type}_${random(10000, false)}`;
/**
* 获取所有页面配置
* @param app DSL跟节点
* @returns 所有页面配置
*/
export const getPageList = (app: MApp): MPage[] => {
if (app.items && Array.isArray(app.items)) {
return app.items.filter((item: MPage) => item.type === NodeType.PAGE);
}
return [];
};
/**
* 获取所有页面名称
* @param pages 所有页面配置
* @returns 所有页面名称
*/
export const getPageNameList = (pages: MPage[]): string[] => pages.map((page: MPage) => page.name || 'index');
/**
* 新增页面时,生成页面名称
* @param {Object} pageNameList 所有页面名称
* @returns {string}
*/
export const generatePageName = (pageNameList: string[]): string => {
let pageLength = pageNameList.length;
if (!pageLength) return 'index';
let pageName = `page_${pageLength}`;
while (pageNameList.includes(pageName)) {
pageLength += 1;
pageName = `page_${pageLength}`;
}
return pageName;
};
/**
* 新增页面时,生成页面名称
* @param {Object} app 所有页面配置
* @returns {string}
*/
export const generatePageNameByApp = (app: MApp): string => generatePageName(getPageNameList(getPageList(app)));
/**
* 复制页面时需要把组件下关联的弹窗id换测复制出来的弹窗的id
* @param {number} oldId 复制的源弹窗id
* @param {number} popId 新的弹窗id
* @param {Object} pageConfig 页面配置
*/
const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
pageConfig.items?.forEach((config) => {
if (config.pop === oldId) {
config.pop = popId;
return;
}
if (config.popId === oldId) {
config.popId = popId;
return;
}
if (Array.isArray(config.items)) {
updatePopId(oldId, popId, config as MPage);
}
});
};
/**
* 将组件与组件的子元素配置中的id都设置成一个新的ID
* @param {Object} config 组件配置
*/
/* eslint no-param-reassign: ["error", { "props": false }] */
export const setNewItemId = (config: MNode, parent?: MPage) => {
const oldId = config.id;
config.id = generateId(config.type || 'component');
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
// 只有弹窗在页面下的一级子元素才有效
if (isPop(config) && parent?.type === NodeType.PAGE) {
updatePopId(oldId, config.id, parent);
}
if (config.items && Array.isArray(config.items)) {
config.items.forEach((item) => setNewItemId(item, config as MPage));
}
};
/**
* @param {Object} node
* @returns {boolean}
*/
export const isFixed = (node: MNode): boolean => node.style?.position === 'fixed';
export const getNodeIndex = (node: MNode, parent: MContainer): number => {
const items = parent?.items || [];
return items.findIndex((item: MNode) => `${item.id}` === `${node.id}`);
};
export const toRelative = (node: MNode) => {
node.style = {
...(node.style || {}),
position: 'relative',
top: 0,
left: 0,
};
return node;
};
const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
const style = node.style || {};
const height = style.height || 0;
if (!stage || style.top || !parentNode.style || !isNumber(height)) return style;
const { height: parentHeight } = parentNode.style;
if (isPage(parentNode)) {
const { scrollTop = 0, wrapperHeight } = stage.mask;
style.top = (wrapperHeight - height) / 2 + scrollTop;
} else {
style.top = (parentHeight - height) / 2;
}
return style;
};
export const initPosition = (node: MNode, layout: Layout, parentNode: MNode, stage: StageCore) => {
if (layout === Layout.ABSOLUTE) {
node.style = {
position: 'absolute',
...setTop2Middle(node, parentNode, stage),
};
return node;
}
if (layout === Layout.RELATIVE) {
return toRelative(node);
}
return node;
};
export const setLayout = (node: MNode, layout: Layout) => {
node.items?.forEach((child: MNode) => {
if (isPop(child)) return;
child.style = child.style || {};
// 是 fixed 不做处理
if (child.style.position === 'fixed') return;
if (layout !== Layout.RELATIVE) {
child.style.position = 'absolute';
} else {
toRelative(child);
child.style.right = 'auto';
child.style.bottom = 'auto';
}
});
return node;
};
export const change2Fixed = (node: MNode, root: MApp) => {
const path = getNodePath(node.id, root.items);
const offset = {
left: 0,
top: 0,
};
path.forEach((value) => {
offset.left = offset.left + globalThis.parseFloat(value.style?.left || 0);
offset.top = offset.top + globalThis.parseFloat(value.style?.top || 0);
});
node.style = {
...(node.style || {}),
...offset,
};
return node;
};
export const Fixed2Other = async (
node: MNode,
root: MApp,
getLayout: (parent: MNode, node?: MNode) => Promise<Layout>,
) => {
const path = getNodePath(node.id, root.items);
const cur = path.pop();
const offset = {
left: cur?.style?.left || 0,
top: cur?.style?.top || 0,
right: '',
bottom: '',
};
path.forEach((value) => {
offset.left = offset.left - globalThis.parseFloat(value.style?.left || 0);
offset.top = offset.top - globalThis.parseFloat(value.style?.top || 0);
});
const parent = path.pop();
if (!parent) {
return toRelative(node);
}
const layout = await getLayout(parent);
if (layout !== Layout.RELATIVE) {
node.style = {
...(node.style || {}),
...offset,
position: 'absolute',
};
return node;
}
return toRelative(node);
};