mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-04-22 13:28:10 +00:00
Merge branch 'v/0.8.0' into 'master'
Release 0.8.0 See merge request !858791
This commit is contained in:
commit
bde3b98c8a
@ -7,8 +7,7 @@
|
|||||||
"lib"
|
"lib"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "rimraf lib && tsc",
|
"build": "rimraf lib && tsc",
|
||||||
"build": "rimraf lib && webpack",
|
|
||||||
"demo": "ts-node -r tsconfig-paths/register ./src/demo/main.ts",
|
"demo": "ts-node -r tsconfig-paths/register ./src/demo/main.ts",
|
||||||
"test": "ava"
|
"test": "ava"
|
||||||
},
|
},
|
||||||
@ -24,11 +23,7 @@
|
|||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"ts-loader": "^6.2.2",
|
"ts-loader": "^6.2.2",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^7.0.1",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0"
|
||||||
"tsconfig-paths-webpack-plugin": "^3.2.0",
|
|
||||||
"webpack": "^4.42.1",
|
|
||||||
"webpack-cli": "^3.3.11",
|
|
||||||
"webpack-node-externals": "^1.7.2"
|
|
||||||
},
|
},
|
||||||
"ava": {
|
"ava": {
|
||||||
"compileEnhancements": false,
|
"compileEnhancements": false,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { IResultDir, IResultFile } from '@/types';
|
import { IResultDir, IResultFile } from '../types';
|
||||||
|
|
||||||
import CodeGenerator from '@/index';
|
import CodeGenerator from '../index';
|
||||||
import { createDiskPublisher } from '@/publisher/disk';
|
import { createDiskPublisher } from '../publisher/disk';
|
||||||
import demoSchema from './simpleDemo';
|
import demoSchema from './simpleDemo';
|
||||||
|
|
||||||
function flatFiles(rootName: string | null, dir: IResultDir): IResultFile[] {
|
function flatFiles(rootName: string | null, dir: IResultDir): IResultFile[] {
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
import { IProjectSchema } from '@/types';
|
import { IProjectSchema } from '../types';
|
||||||
|
|
||||||
// meta: {
|
|
||||||
// title: '测试',
|
|
||||||
// router: '/',
|
|
||||||
// },
|
|
||||||
|
|
||||||
const demoData: IProjectSchema = {
|
const demoData: IProjectSchema = {
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
|
|||||||
@ -11,10 +11,10 @@ import {
|
|||||||
PostProcessor,
|
PostProcessor,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
import ResultDir from '@/model/ResultDir';
|
import ResultDir from '../model/ResultDir';
|
||||||
import SchemaParser from '@/parser/SchemaParser';
|
import SchemaParser from '../parser/SchemaParser';
|
||||||
|
|
||||||
import { createModuleBuilder } from '@/generator/ModuleBuilder';
|
import { createModuleBuilder } from '../generator/ModuleBuilder';
|
||||||
|
|
||||||
interface IModuleInfo {
|
interface IModuleInfo {
|
||||||
moduleName?: string;
|
moduleName?: string;
|
||||||
@ -67,7 +67,7 @@ export class ProjectBuilder implements IProjectBuilder {
|
|||||||
// Parse / Format
|
// Parse / Format
|
||||||
|
|
||||||
// Preprocess
|
// Preprocess
|
||||||
// Colllect Deps
|
// Collect Deps
|
||||||
// Parse JSExpression
|
// Parse JSExpression
|
||||||
const parseResult: IParseResult = schemaParser.parse(schema);
|
const parseResult: IParseResult = schemaParser.parse(schema);
|
||||||
let buildResult: IModuleInfo[] = [];
|
let buildResult: IModuleInfo[] = [];
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
* 低代码引擎的出码模块,负责将编排产出的 Schema 转换成实际可执行的代码。
|
* 低代码引擎的出码模块,负责将编排产出的 Schema 转换成实际可执行的代码。
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import { createProjectBuilder } from '@/generator/ProjectBuilder';
|
import { createProjectBuilder } from './generator/ProjectBuilder';
|
||||||
import { createDiskPublisher } from '@/publisher/disk';
|
import { createDiskPublisher } from './publisher/disk';
|
||||||
import createIceJsProjectBuilder from '@/solutions/icejs';
|
import createIceJsProjectBuilder from './solutions/icejs';
|
||||||
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
|
|||||||
@ -6,10 +6,8 @@
|
|||||||
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
|
import { SUPPORT_SCHEMA_VERSION_LIST } from '../const';
|
||||||
|
|
||||||
import { handleChildren } from '../utils/children';
|
import { handleChildren } from '../utils/children';
|
||||||
import { uniqueArray } from '../utils/common';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChildNodeItem,
|
|
||||||
ChildNodeType,
|
ChildNodeType,
|
||||||
CodeGeneratorError,
|
CodeGeneratorError,
|
||||||
CompatibilityError,
|
CompatibilityError,
|
||||||
@ -86,7 +84,7 @@ class SchemaParser implements ISchemaParser {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new CodeGeneratorError(`Can't find anything to generator.`);
|
throw new CodeGeneratorError(`Can't find anything to generate.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 建立所有容器的内部依赖索引
|
// 建立所有容器的内部依赖索引
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
ChunkType,
|
ChunkType,
|
||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IContainerInfo,
|
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
IJSExpression,
|
IJSExpression,
|
||||||
} from '../../../types';
|
} from '../../../types';
|
||||||
|
|
||||||
import { handleChildren } from '@/utils/children';
|
import { handleChildren } from '../../../utils/children';
|
||||||
import { generateCompositeType } from '../../utils/compositeType';
|
import { generateCompositeType } from '../../utils/compositeType';
|
||||||
import { REACT_CHUNK_NAME } from './const';
|
import { REACT_CHUNK_NAME } from './const';
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
||||||
import { generateCompositeType } from '@/plugins/utils/compositeType';
|
import { generateCompositeType } from '../../plugins/utils/compositeType';
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
ChunkType,
|
ChunkType,
|
||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -7,7 +7,7 @@ import {
|
|||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IPackageJSON,
|
IPackageJSON,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
interface IIceJsPackageJSON extends IPackageJSON {
|
interface IIceJsPackageJSON extends IPackageJSON {
|
||||||
ideMode: {
|
ideMode: {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../../../../const/generator';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IRouterInfo,
|
IRouterInfo,
|
||||||
} from '@/types';
|
} from '../../../../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import ResultFile from '@/model/ResultFile';
|
import ResultFile from '../../../../../../model/ResultFile';
|
||||||
import { IResultFile } from '@/types';
|
import { IResultFile } from '../../../../../../types';
|
||||||
|
|
||||||
export default function getFile(): [string[], IResultFile] {
|
export default function getFile(): [string[], IResultFile] {
|
||||||
const file = new ResultFile(
|
const file = new ResultFile(
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
import ResultDir from '@/model/ResultDir';
|
import ResultDir from '../../../../../model/ResultDir';
|
||||||
import { IProjectTemplate, IResultDir, IResultFile } from '@/types';
|
import {
|
||||||
|
IProjectTemplate,
|
||||||
|
IResultDir,
|
||||||
|
IResultFile,
|
||||||
|
} from '../../../../../types';
|
||||||
|
|
||||||
import file12 from './files/abc.json';
|
import file12 from './files/abc.json';
|
||||||
import file11 from './files/build.json';
|
import file11 from './files/build.json';
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
||||||
import { generateCompositeType } from '@/plugins/utils/compositeType';
|
import { generateCompositeType } from '../../plugins/utils/compositeType';
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
ChunkType,
|
ChunkType,
|
||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IProjectInfo,
|
IProjectInfo,
|
||||||
} from '@/types';
|
} from '../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
import { COMMON_CHUNK_NAME } from '@/const/generator';
|
import { COMMON_CHUNK_NAME } from '../../const/generator';
|
||||||
import { generateCompositeType } from '@/plugins/utils/compositeType';
|
|
||||||
// import { } from '@/plugins/utils/jsExpression';
|
|
||||||
import {
|
import {
|
||||||
BuilderComponentPlugin,
|
BuilderComponentPlugin,
|
||||||
ChunkType,
|
ChunkType,
|
||||||
FileType,
|
FileType,
|
||||||
ICodeStruct,
|
ICodeStruct,
|
||||||
IUtilInfo,
|
IUtilInfo,
|
||||||
} from '@/types';
|
} from '../../types';
|
||||||
|
|
||||||
// TODO: How to merge this logic to common deps
|
// TODO: How to merge this logic to common deps
|
||||||
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
const plugin: BuilderComponentPlugin = async (pre: ICodeStruct) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { CompositeArray, CompositeValue, ICompositeObject } from '@/types';
|
import { CompositeArray, CompositeValue, ICompositeObject } from '../../types';
|
||||||
import { generateValue, isJsExpression } from './jsExpression';
|
import { generateValue, isJsExpression } from './jsExpression';
|
||||||
|
|
||||||
function generateArray(value: CompositeArray): string {
|
function generateArray(value: CompositeArray): string {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import prettier from 'prettier';
|
import prettier from 'prettier';
|
||||||
|
|
||||||
import { PostProcessor } from '@/types';
|
import { PostProcessor } from '../../types';
|
||||||
|
|
||||||
const PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue'];
|
const PARSERS = ['css', 'scss', 'less', 'json', 'html', 'vue'];
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { CodeGeneratorError, IResultDir } from '@/types';
|
import { CodeGeneratorError, IResultDir } from '../../types';
|
||||||
|
|
||||||
export type PublisherFactory<T, U> = (configuration?: Partial<T>) => U;
|
export type PublisherFactory<T, U> = (configuration?: Partial<T>) => U;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { existsSync, mkdir, writeFile } from 'fs';
|
import { existsSync, mkdir, writeFile } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { IResultDir, IResultFile } from '@/types';
|
import { IResultDir, IResultFile } from '../../types';
|
||||||
|
|
||||||
export const writeFolder = async (
|
export const writeFolder = async (
|
||||||
folder: IResultDir,
|
folder: IResultDir,
|
||||||
|
|||||||
@ -1,27 +1,27 @@
|
|||||||
import { IProjectBuilder } from '@/types';
|
import { IProjectBuilder } from '../types';
|
||||||
|
|
||||||
import { createProjectBuilder } from '@/generator/ProjectBuilder';
|
import { createProjectBuilder } from '../generator/ProjectBuilder';
|
||||||
|
|
||||||
import esmodule from '@/plugins/common/esmodule';
|
import esmodule from '../plugins/common/esmodule';
|
||||||
import containerClass from '@/plugins/component/react/containerClass';
|
import containerClass from '../plugins/component/react/containerClass';
|
||||||
import containerInitState from '@/plugins/component/react/containerInitState';
|
import containerInitState from '../plugins/component/react/containerInitState';
|
||||||
// import containerInjectUtils from '@/plugins/component/react/containerInjectUtils';
|
import containerInjectUtils from '../plugins/component/react/containerInjectUtils';
|
||||||
import containerLifeCycle from '@/plugins/component/react/containerLifeCycle';
|
import containerLifeCycle from '../plugins/component/react/containerLifeCycle';
|
||||||
import containerMethod from '@/plugins/component/react/containerMethod';
|
import containerMethod from '../plugins/component/react/containerMethod';
|
||||||
import jsx from '@/plugins/component/react/jsx';
|
import jsx from '../plugins/component/react/jsx';
|
||||||
import reactCommonDeps from '@/plugins/component/react/reactCommonDeps';
|
import reactCommonDeps from '../plugins/component/react/reactCommonDeps';
|
||||||
import css from '@/plugins/component/style/css';
|
import css from '../plugins/component/style/css';
|
||||||
import constants from '@/plugins/project/constants';
|
import constants from '../plugins/project/constants';
|
||||||
import iceJsEntry from '@/plugins/project/framework/icejs/plugins/entry';
|
import iceJsEntry from '../plugins/project/framework/icejs/plugins/entry';
|
||||||
import iceJsEntryHtml from '@/plugins/project/framework/icejs/plugins/entryHtml';
|
import iceJsEntryHtml from '../plugins/project/framework/icejs/plugins/entryHtml';
|
||||||
import iceJsGlobalStyle from '@/plugins/project/framework/icejs/plugins/globalStyle';
|
import iceJsGlobalStyle from '../plugins/project/framework/icejs/plugins/globalStyle';
|
||||||
import iceJsPackageJSON from '@/plugins/project/framework/icejs/plugins/packageJSON';
|
import iceJsPackageJSON from '../plugins/project/framework/icejs/plugins/packageJSON';
|
||||||
import iceJsRouter from '@/plugins/project/framework/icejs/plugins/router';
|
import iceJsRouter from '../plugins/project/framework/icejs/plugins/router';
|
||||||
import template from '@/plugins/project/framework/icejs/template';
|
import template from '../plugins/project/framework/icejs/template';
|
||||||
import i18n from '@/plugins/project/i18n';
|
import i18n from '../plugins/project/i18n';
|
||||||
import utils from '@/plugins/project/utils';
|
import utils from '../plugins/project/utils';
|
||||||
|
|
||||||
import { prettier } from '@/postprocessor';
|
import { prettier } from '../postprocessor';
|
||||||
|
|
||||||
export default function createIceJsProjectBuilder(): IProjectBuilder {
|
export default function createIceJsProjectBuilder(): IProjectBuilder {
|
||||||
return createProjectBuilder({
|
return createProjectBuilder({
|
||||||
@ -31,7 +31,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
|
|||||||
reactCommonDeps,
|
reactCommonDeps,
|
||||||
esmodule,
|
esmodule,
|
||||||
containerClass,
|
containerClass,
|
||||||
// containerInjectUtils,
|
containerInjectUtils,
|
||||||
containerInitState,
|
containerInitState,
|
||||||
containerLifeCycle,
|
containerLifeCycle,
|
||||||
containerMethod,
|
containerMethod,
|
||||||
@ -42,7 +42,7 @@ export default function createIceJsProjectBuilder(): IProjectBuilder {
|
|||||||
reactCommonDeps,
|
reactCommonDeps,
|
||||||
esmodule,
|
esmodule,
|
||||||
containerClass,
|
containerClass,
|
||||||
// containerInjectUtils,
|
containerInjectUtils,
|
||||||
containerInitState,
|
containerInitState,
|
||||||
containerLifeCycle,
|
containerLifeCycle,
|
||||||
containerMethod,
|
containerMethod,
|
||||||
|
|||||||
@ -143,3 +143,8 @@ export interface IProjectBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type PostProcessor = (content: string, fileType: string) => string;
|
export type PostProcessor = (content: string, fileType: string) => string;
|
||||||
|
|
||||||
|
// TODO: temp interface, need modify
|
||||||
|
export interface IPluginOptions {
|
||||||
|
fileDirDepth: number;
|
||||||
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import {
|
|||||||
ChildNodeType,
|
ChildNodeType,
|
||||||
IComponentNodeItem,
|
IComponentNodeItem,
|
||||||
IJSExpression,
|
IJSExpression,
|
||||||
} from '@/types';
|
} from '../types';
|
||||||
|
|
||||||
// tslint:disable-next-line: no-empty
|
// tslint:disable-next-line: no-empty
|
||||||
const noop = () => [];
|
const noop = () => [];
|
||||||
|
|||||||
@ -1,17 +1,12 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"inlineSources": false,
|
|
||||||
"lib": ["es6"],
|
|
||||||
"downlevelIteration": true,
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"]
|
|
||||||
},
|
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
|
"lib": [
|
||||||
|
"es6"
|
||||||
|
],
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
"baseUrl": "." /* Base directory to resolve non-absolute module names. */
|
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const nodeExternals = require('webpack-node-externals');
|
|
||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: 'production',
|
|
||||||
target: 'node',
|
|
||||||
entry: {
|
|
||||||
index: './src/index.ts',
|
|
||||||
// demo: './src/demo/main.ts',
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.tsx?$/,
|
|
||||||
use: 'ts-loader',
|
|
||||||
exclude: /node_modules/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: [ '.tsx', '.ts', '.js' ],
|
|
||||||
plugins: [new TsconfigPathsPlugin({/* options: see below */})],
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
// filename: 'bundle.js',
|
|
||||||
filename: '[name].js',
|
|
||||||
path: path.resolve(__dirname, 'lib'),
|
|
||||||
},
|
|
||||||
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
|
|
||||||
};
|
|
||||||
@ -1,4 +1,6 @@
|
|||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
|
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||||
|
|
||||||
|
|
||||||
module.exports = ({ onGetWebpackConfig }) => {
|
module.exports = ({ onGetWebpackConfig }) => {
|
||||||
onGetWebpackConfig((config) => {
|
onGetWebpackConfig((config) => {
|
||||||
@ -7,6 +9,16 @@ module.exports = ({ onGetWebpackConfig }) => {
|
|||||||
.use(TsconfigPathsPlugin, [{
|
.use(TsconfigPathsPlugin, [{
|
||||||
configFile: "./tsconfig.json"
|
configFile: "./tsconfig.json"
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
||||||
|
config
|
||||||
|
// 定义插件名称
|
||||||
|
.plugin('MonacoWebpackPlugin')
|
||||||
|
// 第一项为具体插件,第二项为插件参数
|
||||||
|
.use(new MonacoWebpackPlugin({
|
||||||
|
languages:["javascript","css","json"]
|
||||||
|
}), []);
|
||||||
|
|
||||||
config.plugins.delete('hot');
|
config.plugins.delete('hot');
|
||||||
config.devServer.hot(false);
|
config.devServer.hot(false);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
"@ali/lowcode-plugin-event-bind-dialog": "^0.8.0",
|
"@ali/lowcode-plugin-event-bind-dialog": "^0.8.0",
|
||||||
"@ali/lowcode-plugin-outline-pane": "^0.8.7",
|
"@ali/lowcode-plugin-outline-pane": "^0.8.7",
|
||||||
"@ali/lowcode-plugin-sample-logo": "^0.8.0",
|
"@ali/lowcode-plugin-sample-logo": "^0.8.0",
|
||||||
|
"@ali/lowcode-plugin-source-editor":"^0.8.2",
|
||||||
"@ali/lowcode-plugin-sample-preview": "^0.8.6",
|
"@ali/lowcode-plugin-sample-preview": "^0.8.6",
|
||||||
"@ali/lowcode-plugin-settings-pane": "^0.8.8",
|
"@ali/lowcode-plugin-settings-pane": "^0.8.8",
|
||||||
"@ali/lowcode-plugin-undo-redo": "^0.8.0",
|
"@ali/lowcode-plugin-undo-redo": "^0.8.0",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"build-plugin-fusion": "^0.1.0",
|
"build-plugin-fusion": "^0.1.0",
|
||||||
"build-plugin-moment-locales": "^0.1.0",
|
"build-plugin-moment-locales": "^0.1.0",
|
||||||
"build-plugin-react-app": "^1.1.2",
|
"build-plugin-react-app": "^1.1.2",
|
||||||
|
"monaco-editor-webpack-plugin":"^1.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.2.0"
|
"tsconfig-paths-webpack-plugin": "^3.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1053,6 +1053,14 @@
|
|||||||
"name": "maxTagCount",
|
"name": "maxTagCount",
|
||||||
"title": "最多显示多少个 tag",
|
"title": "最多显示多少个 tag",
|
||||||
"setter": "ExpressionSetter"
|
"setter": "ExpressionSetter"
|
||||||
|
}, {
|
||||||
|
"name": "color",
|
||||||
|
"title": "颜色选择",
|
||||||
|
"setter": "ColorSetter"
|
||||||
|
}, {
|
||||||
|
"name": "json",
|
||||||
|
"title": "JSON设置",
|
||||||
|
"setter": "JsonSetter"
|
||||||
}, {
|
}, {
|
||||||
"name": "MixinSetter",
|
"name": "MixinSetter",
|
||||||
"placeholder": "混合",
|
"placeholder": "混合",
|
||||||
@ -1081,11 +1089,14 @@
|
|||||||
}, {
|
}, {
|
||||||
"label": "左",
|
"label": "左",
|
||||||
"value": "l"
|
"value": "l"
|
||||||
}]
|
}],
|
||||||
|
"defaultValue": "l"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"name": "NumberSetter",
|
"name": "NumberSetter",
|
||||||
"props": {}
|
"props": {
|
||||||
|
"defaultValue": 5
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
"name": "BoolSetter",
|
"name": "BoolSetter",
|
||||||
"props": {}
|
"props": {}
|
||||||
|
|||||||
@ -83,17 +83,18 @@ module.exports = {
|
|||||||
pluginProps: {
|
pluginProps: {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
pluginKey: 'outlinePane',
|
pluginKey: 'soueceEditor',
|
||||||
type: 'PanelIcon',
|
type: 'PanelIcon',
|
||||||
props: {
|
props: {
|
||||||
align: 'top',
|
align: 'top',
|
||||||
icon: 'shuxingkongjian',
|
icon: 'shuxingkongjian',
|
||||||
title: '大纲树'
|
title: '源码面板'
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
package: '@ali/lowcode-plugin-outline-pane',
|
package: '@ali/lowcode-plugin-source-editor',
|
||||||
version: '^0.8.0'
|
version: '^0.8.2'
|
||||||
},
|
},
|
||||||
pluginProps: {}
|
pluginProps: {}
|
||||||
},
|
},
|
||||||
@ -137,6 +138,7 @@ module.exports = {
|
|||||||
version: '^0.8.0'
|
version: '^0.8.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
hooks: [],
|
hooks: [],
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import Preview from './plugins/provider';
|
|||||||
app.registerRenderer(Renderer);
|
app.registerRenderer(Renderer);
|
||||||
|
|
||||||
// 注册布局组件,可注册多个
|
// 注册布局组件,可注册多个
|
||||||
app.registerLayout('BasicLayout', BasicLayout);
|
app.registerLayout(BasicLayout, { componentName: 'BasicLayout' });
|
||||||
|
|
||||||
// 注册页面 Loading
|
// 注册页面 Loading
|
||||||
app.registerLoading(FusionLoading);
|
app.registerLoading(FusionLoading);
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import zhEn from '@ali/lowcode-plugin-zh-en';
|
|||||||
import settingsPane from '@ali/lowcode-plugin-settings-pane';
|
import settingsPane from '@ali/lowcode-plugin-settings-pane';
|
||||||
import designer from '@ali/lowcode-plugin-designer';
|
import designer from '@ali/lowcode-plugin-designer';
|
||||||
import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
|
import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
|
||||||
|
import variableBindDialog from '@ali/lowcode-plugin-variable-bind-dialog';
|
||||||
|
import sourceEditor from '@ali/lowcode-plugin-source-editor';
|
||||||
export default {
|
export default {
|
||||||
LowcodeSkeleton,
|
LowcodeSkeleton,
|
||||||
logo,
|
logo,
|
||||||
@ -18,5 +20,7 @@ export default {
|
|||||||
zhEn,
|
zhEn,
|
||||||
settingsPane,
|
settingsPane,
|
||||||
designer,
|
designer,
|
||||||
eventBindDialog
|
eventBindDialog,
|
||||||
|
variableBindDialog,
|
||||||
|
sourceEditor
|
||||||
};
|
};
|
||||||
@ -68,7 +68,9 @@ export default {
|
|||||||
"align": "top",
|
"align": "top",
|
||||||
"icon": "zujianku",
|
"icon": "zujianku",
|
||||||
"title": "组件库",
|
"title": "组件库",
|
||||||
"floatable": true
|
"panelProps": {
|
||||||
|
"floatable": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"package": "@ali/lowcode-plugin-components-pane",
|
"package": "@ali/lowcode-plugin-components-pane",
|
||||||
@ -88,7 +90,30 @@ export default {
|
|||||||
"version": "^0.8.0"
|
"version": "^0.8.0"
|
||||||
},
|
},
|
||||||
"pluginProps": {}
|
"pluginProps": {}
|
||||||
}, {
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"pluginKey": "sourceEditor",
|
||||||
|
"type": "PanelIcon",
|
||||||
|
"props": {
|
||||||
|
"align": "top",
|
||||||
|
"icon": "zujianku",
|
||||||
|
"title": "组件库",
|
||||||
|
"panelProps":{
|
||||||
|
"floatable": true,
|
||||||
|
"defaultWidth":500
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-source-editor",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
"pluginKey": "zhEn",
|
"pluginKey": "zhEn",
|
||||||
"type": "Custom",
|
"type": "Custom",
|
||||||
"props": {
|
"props": {
|
||||||
@ -122,7 +147,15 @@ export default {
|
|||||||
"package": "@ali/lowcode-plugin-event-bind-dialog",
|
"package": "@ali/lowcode-plugin-event-bind-dialog",
|
||||||
"version": "^0.8.0"
|
"version": "^0.8.0"
|
||||||
}
|
}
|
||||||
}]
|
},
|
||||||
|
{
|
||||||
|
"pluginKey": "variableBindDialog",
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-variable-bind-dialog",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"hooks": [],
|
"hooks": [],
|
||||||
"shortCuts": [],
|
"shortCuts": [],
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export default class AreaManager {
|
|||||||
this.pluginStatus = clone(editor.pluginStatus);
|
this.pluginStatus = clone(editor.pluginStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean {
|
isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean {
|
||||||
const { pluginStatus } = this.editor;
|
const { pluginStatus } = this.editor;
|
||||||
const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config;
|
const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config;
|
||||||
|
|
||||||
|
|||||||
@ -77,7 +77,7 @@ export default class Editor extends EventEmitter {
|
|||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
public config: EditorConfig;
|
config: EditorConfig;
|
||||||
|
|
||||||
public components: PluginClassSet;
|
public components: PluginClassSet;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import Editor from './editor';
|
import Editor from './editor';
|
||||||
|
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
export * from './definitions';
|
|
||||||
|
|
||||||
export { default as PluginFactory } from './pluginFactory';
|
export { default as PluginFactory } from './pluginFactory';
|
||||||
export { default as EditorContext } from './context';
|
export { default as EditorContext } from './context';
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import Skeleton from './skeleton';
|
import Skeleton from './skeleton';
|
||||||
import Panel from './components/Panel';
|
import Panel from './components/Panel';
|
||||||
import TopIcon from './components/TopIcon';
|
import TopIcon from './components/TopIcon';
|
||||||
|
import TopPlugin from './components/TopPlugin';
|
||||||
|
import LeftPlugin from './components/LeftPlugin';
|
||||||
|
|
||||||
export default Skeleton;
|
export default Skeleton;
|
||||||
|
|
||||||
export { Panel, TopIcon };
|
export { Panel, TopIcon, TopPlugin, LeftPlugin };
|
||||||
|
|||||||
@ -3,6 +3,17 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.9.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-material-parser@0.9.0...@ali/lowcode-material-parser@0.9.1) (2020-04-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix bug of missing ajv ([a37d655](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a37d655))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="0.9.0"></a>
|
<a name="0.9.0"></a>
|
||||||
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-material-parser@0.8.4...@ali/lowcode-material-parser@0.9.0) (2020-03-31)
|
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-material-parser@0.8.4...@ali/lowcode-material-parser@0.9.0) (2020-03-31)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ali/lowcode-material-parser",
|
"name": "@ali/lowcode-material-parser",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"description": "material parser for Ali lowCode engine",
|
"description": "material parser for Ali lowCode engine",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
@ -13,8 +13,6 @@
|
|||||||
"@types/js-yaml": "^3.12.2",
|
"@types/js-yaml": "^3.12.2",
|
||||||
"@types/lodash": "^4.14.149",
|
"@types/lodash": "^4.14.149",
|
||||||
"@types/semver": "^7.1.0",
|
"@types/semver": "^7.1.0",
|
||||||
"ajv": "^6.10.2",
|
|
||||||
"better-ajv-errors": "^0.6.4",
|
|
||||||
"globby": "^10.0.1",
|
"globby": "^10.0.1",
|
||||||
"jest": "^24.8.0",
|
"jest": "^24.8.0",
|
||||||
"jest-watch-typeahead": "^0.3.1",
|
"jest-watch-typeahead": "^0.3.1",
|
||||||
@ -48,6 +46,7 @@
|
|||||||
"@babel/parser": "^7.8.4",
|
"@babel/parser": "^7.8.4",
|
||||||
"@babel/traverse": "^7.8.4",
|
"@babel/traverse": "^7.8.4",
|
||||||
"@babel/types": "^7.8.3",
|
"@babel/types": "^7.8.3",
|
||||||
|
"ajv": "^6.12.0",
|
||||||
"ast-types": "^0.13.3",
|
"ast-types": "^0.13.3",
|
||||||
"cross-spawn-promise": "^0.10.2",
|
"cross-spawn-promise": "^0.10.2",
|
||||||
"debug": "^4.1.1",
|
"debug": "^4.1.1",
|
||||||
|
|||||||
@ -91,6 +91,13 @@ export default class EventBindDialog extends Component<{
|
|||||||
onOk = () => {
|
onOk = () => {
|
||||||
const {editor} = this.props;
|
const {editor} = this.props;
|
||||||
editor.emit('event-setter.bindEvent',this.state.eventName);
|
editor.emit('event-setter.bindEvent',this.state.eventName);
|
||||||
|
// 选中的是新建事件
|
||||||
|
if (this.state.selectedEventName == ''){
|
||||||
|
editor.emit('sourceEditor.addFunction',{
|
||||||
|
functionName:this.state.eventName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
20
packages/plugin-source-editor/CHANGELOG.md
Normal file
20
packages/plugin-source-editor/CHANGELOG.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
<a name="0.8.2"></a>
|
||||||
|
## [0.8.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-plugin-variable-bind-dialog@0.8.1...@ali/lowcode-plugin-variable-bind-dialog@0.8.2) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-plugin-source-editor
|
||||||
|
|
||||||
|
<a name="0.8.1"></a>
|
||||||
|
## 0.8.1 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-plugin-source-editor
|
||||||
1
packages/plugin-source-editor/README.md
Normal file
1
packages/plugin-source-editor/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
## todo
|
||||||
9
packages/plugin-source-editor/build.json
Normal file
9
packages/plugin-source-editor/build.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"build-plugin-component",
|
||||||
|
"build-plugin-fusion",
|
||||||
|
["build-plugin-moment-locales", {
|
||||||
|
"locales": ["zh-cn"]
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
||||||
41
packages/plugin-source-editor/package.json
Normal file
41
packages/plugin-source-editor/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-plugin-source-editor",
|
||||||
|
"version": "0.8.2",
|
||||||
|
"description": "alibaba lowcode editor source-editor plugin",
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build --skip-demo",
|
||||||
|
"test": "ava",
|
||||||
|
"test:snapshot": "ava --update-snapshots"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"lowcode",
|
||||||
|
"editor"
|
||||||
|
],
|
||||||
|
"author": "zude.hzd",
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-editor-core": "^0.8.0",
|
||||||
|
"@alifd/next": "^1.19.16",
|
||||||
|
"react": "^16.8.1",
|
||||||
|
"react-dom": "^16.8.1",
|
||||||
|
"prettier":"^1.18.2",
|
||||||
|
"js-beautify": "^1.10.1",
|
||||||
|
"react-monaco-editor": "^0.36.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.3",
|
||||||
|
"@types/react": "^16.9.13",
|
||||||
|
"@types/react-dom": "^16.9.4",
|
||||||
|
"build-plugin-component": "^0.2.7-1",
|
||||||
|
"build-plugin-fusion": "^0.1.0",
|
||||||
|
"build-plugin-moment-locales": "^0.1.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/plugin-source-editor/src/index.scss
Normal file
23
packages/plugin-source-editor/src/index.scss
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.source-editor-container{
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
.next-tabs {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next-tabs-content{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next-tabs-tabpane.active {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
296
packages/plugin-source-editor/src/index.tsx
Normal file
296
packages/plugin-source-editor/src/index.tsx
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
import { Component, isValidElement, ReactElement, ReactNode } from 'react';
|
||||||
|
import { Tab, Search, Input, Button } from '@alifd/next';
|
||||||
|
import Editor from '@ali/lowcode-editor-core';
|
||||||
|
import { js_beautify, css_beautify } from 'js-beautify';
|
||||||
|
import MonacoEditor from 'react-monaco-editor';
|
||||||
|
|
||||||
|
// import lolizer from './sorceEditorPlugin',
|
||||||
|
|
||||||
|
import { Designer } from '@ali/lowcode-designer';
|
||||||
|
const TAB_KEY = {
|
||||||
|
JS_TAB: 'js_tab',
|
||||||
|
CSS_TAB: 'css_tab',
|
||||||
|
};
|
||||||
|
|
||||||
|
import './index.scss';
|
||||||
|
import transfrom from './transform';
|
||||||
|
|
||||||
|
const defaultEditorOption = {
|
||||||
|
width: '100%',
|
||||||
|
height: '96%',
|
||||||
|
options: {
|
||||||
|
readOnly: false,
|
||||||
|
automaticLayout: true,
|
||||||
|
folding: true, //默认开启折叠代码功能
|
||||||
|
lineNumbers: 'on',
|
||||||
|
wordWrap: 'off',
|
||||||
|
formatOnPaste: true,
|
||||||
|
fontSize: 12,
|
||||||
|
tabSize: 2,
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
fixedOverflowWidgets: false,
|
||||||
|
snippetSuggestions: 'top',
|
||||||
|
minimap: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
scrollbar: {
|
||||||
|
vertical: 'auto',
|
||||||
|
horizontal: 'auto',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FunctionEventParam {
|
||||||
|
functionName: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class SourceEditor extends Component<{
|
||||||
|
editor: Editor;
|
||||||
|
}> {
|
||||||
|
private monocoEditer: Object;
|
||||||
|
private editorCmd: Object;
|
||||||
|
|
||||||
|
state = {
|
||||||
|
isShow: false,
|
||||||
|
tabKey: TAB_KEY.JS_TAB,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
const { editor } = this.props;
|
||||||
|
editor.on('leftPanel.show', (key: String) => {
|
||||||
|
if (key === 'sourceEditor' && !this.monocoEditer) {
|
||||||
|
this.setState({
|
||||||
|
isShow: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加函数
|
||||||
|
editor.on('sourceEditor.addFunction', (params: FunctionEventParam) => {
|
||||||
|
this.callEditorEvent('sourceEditor.addFunction', params);
|
||||||
|
this.openPluginPannel();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定位函数
|
||||||
|
editor.on('sourceEditor.focusByFunction',(params:FunctionEventParam)=>{
|
||||||
|
this.callEditorEvent('sourceEditor.focusByFunction', params);
|
||||||
|
this.openPluginPannel();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
editor.once('designer.mount', (designer: Designer) => {
|
||||||
|
// let schema = designer.project.getSchema();
|
||||||
|
// mock data
|
||||||
|
let schema = {
|
||||||
|
componentTree: [
|
||||||
|
{
|
||||||
|
state: {
|
||||||
|
// 初始state: 选填 对象类型/变量表达式
|
||||||
|
btnText: 'submit', // 默认数据值: 选填 变量表达式
|
||||||
|
},
|
||||||
|
css: 'body {font-size: 12px;} .botton{widht:100px;color:#ff00ff}', //css样式描述: 选填
|
||||||
|
lifeCycles: {
|
||||||
|
//生命周期: 选填 对象类型
|
||||||
|
didMount: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: "function() {\n \t\tconsole.log('did mount');\n\t}",
|
||||||
|
},
|
||||||
|
willUnmount: {
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: "function() {\n \t\tconsole.log('will umount');\n\t}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
//自定义方法对象: 选填 对象类型
|
||||||
|
getData: {
|
||||||
|
//自定义方法: 选填 函数类型
|
||||||
|
type: 'JSExpression',
|
||||||
|
value: "function() {\n \t\tconsole.log('testFunc');\n \t}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
this.initCode(schema);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openPluginPannel = () => {
|
||||||
|
const {editor} = this.props;
|
||||||
|
// 判断面板是否处于激活状态
|
||||||
|
if (!editor.leftNav || editor.leftNav != 'sourceEditor') {
|
||||||
|
// 打开面板
|
||||||
|
editor.emit('leftNav.change', 'sourceEditor');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callEditorEvent = (eventName, params) => {
|
||||||
|
if (!this.monocoEditer) {
|
||||||
|
this.editorCmd = {
|
||||||
|
eventName,
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventName === 'sourceEditor.addFunction') {
|
||||||
|
this.addFunction(params);
|
||||||
|
}else if (eventName === 'sourceEditor.focusByFunction'){
|
||||||
|
this.focusByFunctionName(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
initCode = (schema) => {
|
||||||
|
let jsCode = js_beautify(transfrom.schema2Code(schema), { indent_size: 2, indent_empty_lines: true });
|
||||||
|
let css;
|
||||||
|
|
||||||
|
if (schema.componentTree[0].css) {
|
||||||
|
css = css_beautify(schema.componentTree[0].css, { indent_size: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
jsCode,
|
||||||
|
css,
|
||||||
|
selectTab: TAB_KEY.JS_TAB,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在js面板中添加一个新函数
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
addFunction(params: FunctionEventParam) {
|
||||||
|
const count = this.monocoEditer.getModel().getLineCount() || 0;
|
||||||
|
const range = new monaco.Range(count, 1, count, 1);
|
||||||
|
const functionCode = transfrom.getNewFunctionCode(params.functionName);
|
||||||
|
this.monocoEditer.executeEdits('log-source', [
|
||||||
|
{ identifier: 'event_id', range: range, text: functionCode, forceMoveMarkers: true },
|
||||||
|
]);
|
||||||
|
setTimeout(() => {
|
||||||
|
let newPosition = new monaco.Position(count + 1, 2);
|
||||||
|
this.monocoEditer.setPosition(newPosition);
|
||||||
|
this.monocoEditer.focus();
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
this.updateCode(this.monocoEditer.getModel().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据函数名进行定位
|
||||||
|
* @param functionName
|
||||||
|
*/
|
||||||
|
focusByFunctionName(params: FunctionEventParam) {
|
||||||
|
const functionName = params.functionName;
|
||||||
|
const matchedResult = this.monocoEditer
|
||||||
|
.getModel()
|
||||||
|
.findMatches(`${functionName}\\s*\\([\\s\\S]*\\)[\\s\\S]*\\{`, false, true)[0];
|
||||||
|
if (matchedResult) {
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.monocoEditer.revealLineInCenter(matchedResult.range.startLineNumber);
|
||||||
|
this.monocoEditer.setPosition({
|
||||||
|
column: matchedResult.range.endColumn,
|
||||||
|
lineNumber: matchedResult.range.endLineNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.monocoEditer.focus();
|
||||||
|
},100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editorDidMount = (editor, monaco) => {
|
||||||
|
console.log('editorDidMount', editor);
|
||||||
|
this.monocoEditer = editor;
|
||||||
|
|
||||||
|
if (this.editorCmd) {
|
||||||
|
this.callEditorEvent(this.editorCmd.eventName, this.editorCmd.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// var commandId = editor.addCommand(
|
||||||
|
// 0,
|
||||||
|
// function() {
|
||||||
|
// // services available in `ctx`
|
||||||
|
// alert('my command is executing!');
|
||||||
|
// },
|
||||||
|
// '',
|
||||||
|
// );
|
||||||
|
|
||||||
|
// monaco.languages.registerCodeLensProvider('javascript', {
|
||||||
|
// provideCodeLenses: function(model, token) {
|
||||||
|
// return {
|
||||||
|
// lenses: [
|
||||||
|
// {
|
||||||
|
// range: {
|
||||||
|
// startLineNumber: 1,
|
||||||
|
// startColumn: 1,
|
||||||
|
// endLineNumber: 1,
|
||||||
|
// endColumn: 1,
|
||||||
|
// },
|
||||||
|
// id: 'First Line',
|
||||||
|
// command: {
|
||||||
|
// id: commandId,
|
||||||
|
// title: 'First Line',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// };
|
||||||
|
// },
|
||||||
|
// resolveCodeLens: function(model, codeLens, token) {
|
||||||
|
// return codeLens;
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|
||||||
|
onTabChange = (key) => {
|
||||||
|
this.setState({
|
||||||
|
selectTab: key,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
updateCode = (newCode) => {
|
||||||
|
const { selectTab } = this.state;
|
||||||
|
if (selectTab === TAB_KEY.JS_TAB) {
|
||||||
|
this.setState({
|
||||||
|
jsCode: newCode,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
css: newCode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
transfrom.code2Schema(newCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isShow, selectTab, jsCode, css } = this.state;
|
||||||
|
const tabs = [
|
||||||
|
{ tab: 'index.js', key: TAB_KEY.JS_TAB },
|
||||||
|
{ tab: 'style.css', key: TAB_KEY.CSS_TAB },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="source-editor-container">
|
||||||
|
<Tab size="small" shape="wrapped" onChange={this.onTabChange}>
|
||||||
|
{tabs.map((item) => (
|
||||||
|
<Tab.Item key={item.key} title={item.tab}>
|
||||||
|
{isShow && (
|
||||||
|
<MonacoEditor
|
||||||
|
value={selectTab == TAB_KEY.JS_TAB ? jsCode : css}
|
||||||
|
{...defaultEditorOption}
|
||||||
|
{...{ language: selectTab == TAB_KEY.JS_TAB ? 'javascript' : 'css' }}
|
||||||
|
onChange={(newCode) => this.updateCode(newCode)}
|
||||||
|
editorDidMount={this.editorDidMount}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Tab.Item>
|
||||||
|
))}
|
||||||
|
</Tab>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
98
packages/plugin-source-editor/src/transform.ts
Normal file
98
packages/plugin-source-editor/src/transform.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import walkSourcePlugin from './sorceEditorPlugin';
|
||||||
|
|
||||||
|
const transfrom = {
|
||||||
|
schema2Code(schema: Object) {
|
||||||
|
let componentSchema = schema.componentTree[0];
|
||||||
|
let code =
|
||||||
|
`export default class {
|
||||||
|
${initStateCode(componentSchema)}
|
||||||
|
${initLifeCycleCode(componentSchema)}
|
||||||
|
${initMethodsCode(componentSchema)}
|
||||||
|
}`;
|
||||||
|
console.log(code);
|
||||||
|
return code;
|
||||||
|
},
|
||||||
|
|
||||||
|
code2Schema(code: String) {
|
||||||
|
|
||||||
|
let newCode = code.replace(/export default class/,'class A');
|
||||||
|
|
||||||
|
let A,a;
|
||||||
|
try {
|
||||||
|
A = eval('('+newCode + ')');
|
||||||
|
a = new A();
|
||||||
|
}catch(e){
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let functionNameList = Object.getOwnPropertyNames(a.__proto__);
|
||||||
|
|
||||||
|
let functionMap = {};
|
||||||
|
|
||||||
|
functionNameList.map((functionName)=>{
|
||||||
|
if (functionName != 'constructor'){
|
||||||
|
let functionCode = a[functionName].toString().replace(new RegExp(functionName),'function');
|
||||||
|
functionMap[functionName] = functionCode;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(JSON.stringify(a.state));
|
||||||
|
|
||||||
|
console.log(functionMap);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getNewFunctionCode(functionName:String){
|
||||||
|
return `\n\t${functionName}(){\n\t}\n`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function initStateCode(componentSchema:Object) {
|
||||||
|
if (componentSchema.state){
|
||||||
|
return `state = ${JSON.stringify(componentSchema.state)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function initLifeCycleCode(componentSchema: Object) {
|
||||||
|
if (componentSchema.lifeCycles) {
|
||||||
|
let lifeCycles = componentSchema.lifeCycles;
|
||||||
|
let codeList = [];
|
||||||
|
|
||||||
|
for (let key in lifeCycles) {
|
||||||
|
codeList.push(createFunctionCode(key, lifeCycles[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeList.join('');
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initMethodsCode(componentSchema: Object) {
|
||||||
|
if (componentSchema.methods) {
|
||||||
|
let methods = componentSchema.methods;
|
||||||
|
let codeList = [];
|
||||||
|
|
||||||
|
for (let key in methods) {
|
||||||
|
codeList.push(createFunctionCode(key, methods[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeList.join('');
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFunctionCode(functionName: String, functionNode: Object) {
|
||||||
|
if (functionNode.type === 'JSExpression') {
|
||||||
|
let functionCode = functionNode.value;
|
||||||
|
functionCode = functionCode.replace(/function/, functionName);
|
||||||
|
return functionCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default transfrom;
|
||||||
9
packages/plugin-source-editor/tsconfig.json
Normal file
9
packages/plugin-source-editor/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
packages/rax-provider/CHANGELOG.md
Normal file
4
packages/rax-provider/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
1
packages/rax-provider/README.md
Normal file
1
packages/rax-provider/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 低代码引擎运行时框架
|
||||||
11
packages/rax-provider/build.json
Normal file
11
packages/rax-provider/build.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-rax-component",
|
||||||
|
{
|
||||||
|
"type": "rax",
|
||||||
|
"targets": ["web"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
30
packages/rax-provider/package.json
Normal file
30
packages/rax-provider/package.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-rax-provider",
|
||||||
|
"version": "0.8.14-beta.0",
|
||||||
|
"description": "Rax Provider for Runtime",
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "build-scripts start",
|
||||||
|
"build": "build-scripts build"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-runtime": "^0.8.14-beta.0",
|
||||||
|
"rax": "1.1.2",
|
||||||
|
"driver-universal": "^3.1.3",
|
||||||
|
"rax-use-router": "^3.0.0",
|
||||||
|
"history": "^4.10.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"build-plugin-rax-component": "^0.2.0"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
packages/rax-provider/src/index.js
Normal file
5
packages/rax-provider/src/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import RaxProvider from './provider';
|
||||||
|
import getRouter from './router';
|
||||||
|
|
||||||
|
export { getRouter };
|
||||||
|
export default RaxProvider;
|
||||||
28
packages/rax-provider/src/lazy-component.js
Normal file
28
packages/rax-provider/src/lazy-component.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { createElement, useState, useEffect } from 'rax';
|
||||||
|
import { app } from '@ali/lowcode-runtime';
|
||||||
|
|
||||||
|
export default function LazyComponent(props) {
|
||||||
|
const [schema, setSchema] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const { getPageData } = props || {};
|
||||||
|
if (getPageData && !schema) {
|
||||||
|
const data = await getPageData();
|
||||||
|
setSchema(data);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getPageData, ...restProps } = props || {};
|
||||||
|
const Renderer = app.getRenderer();
|
||||||
|
const Loading = app.getLoading();
|
||||||
|
if (!Renderer || !schema) {
|
||||||
|
if (!Loading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// loading扩展点
|
||||||
|
return createElement(Loading);
|
||||||
|
}
|
||||||
|
return createElement(Renderer, { schema, loading: Loading ? createElement(Loading) : null, ...restProps });
|
||||||
|
}
|
||||||
103
packages/rax-provider/src/provider.js
Normal file
103
packages/rax-provider/src/provider.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { createElement, render } from 'rax';
|
||||||
|
import UniversalDriver from 'driver-universal';
|
||||||
|
import { app, Provider } from '@ali/lowcode-runtime';
|
||||||
|
import LazyComponent from './lazy-component';
|
||||||
|
import getRouter from './router';
|
||||||
|
|
||||||
|
export default class RaxProvider extends Provider {
|
||||||
|
// 定制构造根组件的逻辑,如切换路由机制
|
||||||
|
createApp() {
|
||||||
|
const RouterView = this.getRouterView();
|
||||||
|
let App;
|
||||||
|
const layoutConfig = this.getLayoutConfig();
|
||||||
|
if (!layoutConfig || !layoutConfig.componentName) {
|
||||||
|
App = (props) => (RouterView ? createElement(RouterView, { ...props }) : null);
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
const { componentName: layoutName, props: layoutProps } = layoutConfig;
|
||||||
|
const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
|
||||||
|
const sectionalRender = this.isSectionalRender();
|
||||||
|
if (!sectionalRender && Layout) {
|
||||||
|
App = (props) =>
|
||||||
|
createElement(
|
||||||
|
Layout,
|
||||||
|
{ ...layoutProps, ...extraLayoutProps },
|
||||||
|
RouterView ? createElement(RouterView, props) : null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
App = (props) => (RouterView ? createElement(RouterView, props) : null);
|
||||||
|
}
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
|
||||||
|
runApp(App, config) {
|
||||||
|
render(createElement(App), document.getElementById(config?.containerId || 'App'), { driver: UniversalDriver });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内置实现 for 动态化渲染
|
||||||
|
getRouterView() {
|
||||||
|
const routerConfig = this.getRouterConfig();
|
||||||
|
if (!routerConfig) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const routes = [];
|
||||||
|
let homePageId = this.getHomePage();
|
||||||
|
Object.keys(routerConfig).forEach((pageId, idx) => {
|
||||||
|
if (!pageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = routerConfig[pageId];
|
||||||
|
routes.push({
|
||||||
|
path,
|
||||||
|
component: (props: any) =>
|
||||||
|
this.getLazyComponent(pageId, {
|
||||||
|
components: this.getComponents(),
|
||||||
|
utils: this.getUtils(),
|
||||||
|
componentsMap: this.getComponentsMapObj(),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
if (homePageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (idx === 0 || path === '/') {
|
||||||
|
homePageId = pageId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (homePageId) {
|
||||||
|
routes.push({
|
||||||
|
path: '**',
|
||||||
|
component: (props) =>
|
||||||
|
this.getLazyComponent(homePageId, {
|
||||||
|
components: this.getComponents(),
|
||||||
|
utils: this.getUtils(),
|
||||||
|
componentsMap: this.getComponentsMapObj(),
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const Router = getRouter({
|
||||||
|
history: this.getHistory(),
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
const RouterView = (props) => createElement(Router, props);
|
||||||
|
return RouterView;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLazyComponent(pageId, props) {
|
||||||
|
if (!pageId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this.getlazyElement(pageId)) {
|
||||||
|
return this.getlazyElement(pageId);
|
||||||
|
}
|
||||||
|
const lazyElement = createElement(LazyComponent, {
|
||||||
|
// eslint-disable-next-line no-return-await
|
||||||
|
getPageData: async () => await this.getPageData(pageId),
|
||||||
|
key: pageId,
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
this.setlazyElement(pageId, lazyElement);
|
||||||
|
return lazyElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
packages/rax-provider/src/router.js
Normal file
26
packages/rax-provider/src/router.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useRouter } from 'rax-use-router';
|
||||||
|
import { createHashHistory, createBrowserHistory } from 'history';
|
||||||
|
|
||||||
|
const getConfig = (config) => {
|
||||||
|
let { history } = config;
|
||||||
|
const { routes } = config;
|
||||||
|
if (typeof history === 'string') {
|
||||||
|
if (history === 'hash') {
|
||||||
|
history = createHashHistory();
|
||||||
|
} else if (history === 'browser') {
|
||||||
|
history = createBrowserHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => ({
|
||||||
|
history,
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function getRouter(config) {
|
||||||
|
return function Router() {
|
||||||
|
const configWrapper = getConfig(config);
|
||||||
|
const { component } = useRouter(configWrapper);
|
||||||
|
return component;
|
||||||
|
};
|
||||||
|
}
|
||||||
4
packages/react-provider/CHANGELOG.md
Normal file
4
packages/react-provider/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
1
packages/react-provider/README.md
Normal file
1
packages/react-provider/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# 低代码引擎运行时框架
|
||||||
5
packages/react-provider/build.json
Normal file
5
packages/react-provider/build.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"build-plugin-component"
|
||||||
|
]
|
||||||
|
}
|
||||||
43
packages/react-provider/package.json
Normal file
43
packages/react-provider/package.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-react-provider",
|
||||||
|
"version": "0.8.14",
|
||||||
|
"description": "React Provider for Runtime",
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build --skip-demo",
|
||||||
|
"test": "ava",
|
||||||
|
"test:snapshot": "ava --update-snapshots"
|
||||||
|
},
|
||||||
|
"ava": {
|
||||||
|
"compileEnhancements": false,
|
||||||
|
"snapshotDir": "test/fixtures/__snapshots__",
|
||||||
|
"extensions": [
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"require": [
|
||||||
|
"ts-node/register"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ali/lowcode-runtime": "^0.8.13",
|
||||||
|
"react": "^16",
|
||||||
|
"react-dom": "^16",
|
||||||
|
"@recore/router": "^1.0.11"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"build-plugin-component": "^0.2.16",
|
||||||
|
"@types/node": "^13.7.1",
|
||||||
|
"@types/react": "^16",
|
||||||
|
"@types/react-dom": "^16"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
5
packages/react-provider/src/index.ts
Normal file
5
packages/react-provider/src/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import ReactProvider from './provider';
|
||||||
|
import { Router } from '@recore/router';
|
||||||
|
|
||||||
|
export { Router };
|
||||||
|
export default ReactProvider;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { Component, createElement } from 'react';
|
import { Component, createElement } from 'react';
|
||||||
import app from '../../index';
|
import { app } from '@ali/lowcode-runtime';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
getPageData: () => any;
|
getPageData: () => any;
|
||||||
@ -38,6 +38,6 @@ export default class LazyComponent extends Component<IProps, IState> {
|
|||||||
// loading扩展点
|
// loading扩展点
|
||||||
return createElement(Loading);
|
return createElement(Loading);
|
||||||
}
|
}
|
||||||
return createElement(Renderer as any, { schema, ...restProps });
|
return createElement(Renderer as any, { schema, loading: Loading ? createElement(Loading) : null, ...restProps });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,39 +1,76 @@
|
|||||||
import { createElement, ReactElement } from 'react';
|
import { createElement, ReactType, ReactElement } from 'react';
|
||||||
import { Router } from '@ali/recore';
|
import ReactDOM from 'react-dom';
|
||||||
import app from '../../index';
|
import { Router } from '@recore/router';
|
||||||
import Provider from '..';
|
import { app, Provider } from '@ali/lowcode-runtime';
|
||||||
import LazyComponent from './lazy-component';
|
import LazyComponent from './lazy-component';
|
||||||
|
|
||||||
export default class ReactProvider extends Provider {
|
export default class ReactProvider extends Provider {
|
||||||
// 定制构造根组件的逻辑,如切换路由机制
|
// 定制构造根组件的逻辑,如切换路由机制
|
||||||
createApp() {
|
createApp() {
|
||||||
|
const RouterView = this.getRouterView();
|
||||||
|
let App;
|
||||||
|
const layoutConfig = this.getLayoutConfig();
|
||||||
|
if (!layoutConfig || !layoutConfig.componentName) {
|
||||||
|
App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null);
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
const { componentName: layoutName, props: layoutProps } = layoutConfig;
|
||||||
|
const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
|
||||||
|
const sectionalRender = this.isSectionalRender();
|
||||||
|
if (!sectionalRender && Layout) {
|
||||||
|
App = (props: any) =>
|
||||||
|
createElement(
|
||||||
|
Layout,
|
||||||
|
{ ...layoutProps, ...extraLayoutProps },
|
||||||
|
RouterView ? createElement(RouterView, props) : null,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
App = (props: any) => (RouterView ? createElement(RouterView, props) : null);
|
||||||
|
}
|
||||||
|
return App;
|
||||||
|
}
|
||||||
|
|
||||||
|
runApp(App: any, config: any) {
|
||||||
|
ReactDOM.render(<App />, document.getElementById(config?.containerId || 'App'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内置实现 for 动态化渲染
|
||||||
|
getRouterView(): ReactType | null {
|
||||||
const routerConfig = this.getRouterConfig();
|
const routerConfig = this.getRouterConfig();
|
||||||
if (!routerConfig) {
|
if (!routerConfig) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
const routes: Array<{ path: string; children: any; exact: boolean; keepAlive: boolean }> = [];
|
const routes: Array<{
|
||||||
let homePageId = '';
|
path: string;
|
||||||
|
children: any;
|
||||||
|
exact: boolean;
|
||||||
|
defined: { keepAlive: boolean; [key: string]: any };
|
||||||
|
}> = [];
|
||||||
|
let homePageId = this.getHomePage();
|
||||||
Object.keys(routerConfig).forEach((pageId: string, idx: number) => {
|
Object.keys(routerConfig).forEach((pageId: string, idx: number) => {
|
||||||
if (!pageId) {
|
if (!pageId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = routerConfig[pageId];
|
const path = routerConfig[pageId];
|
||||||
if (idx === 0 || path === '/') {
|
|
||||||
homePageId = pageId;
|
|
||||||
}
|
|
||||||
routes.push({
|
routes.push({
|
||||||
path,
|
path,
|
||||||
children: (props: any) => this.getLazyComponent(pageId, props),
|
children: (props: any) => this.getLazyComponent(pageId, props),
|
||||||
exact: true,
|
exact: true,
|
||||||
keepAlive: true,
|
defined: { keepAlive: true },
|
||||||
});
|
});
|
||||||
|
if (homePageId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (idx === 0 || path === '/') {
|
||||||
|
homePageId = pageId;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (homePageId) {
|
if (homePageId) {
|
||||||
routes.push({
|
routes.push({
|
||||||
path: '**',
|
path: '**',
|
||||||
children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
|
children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
|
||||||
exact: true,
|
exact: true,
|
||||||
keepAlive: true,
|
defined: { keepAlive: true },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const RouterView = (props: any) => {
|
const RouterView = (props: any) => {
|
||||||
@ -45,20 +82,7 @@ export default class ReactProvider extends Provider {
|
|||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let App;
|
return RouterView;
|
||||||
const layoutConfig = this.getLayoutConfig();
|
|
||||||
if (!layoutConfig || !layoutConfig.componentName) {
|
|
||||||
App = (props: any) => createElement(RouterView, { ...props });
|
|
||||||
return App;
|
|
||||||
}
|
|
||||||
const { componentName: layoutName, props: layoutProps } = layoutConfig;
|
|
||||||
const Layout = app.getLayout(layoutName);
|
|
||||||
if (Layout) {
|
|
||||||
App = (props: any) => createElement(Layout, layoutProps, RouterView({ props }));
|
|
||||||
} else {
|
|
||||||
App = (props: any) => createElement(RouterView, props);
|
|
||||||
}
|
|
||||||
return App;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLazyComponent(pageId: string, props: any): ReactElement | null {
|
getLazyComponent(pageId: string, props: any): ReactElement | null {
|
||||||
9
packages/react-provider/tsconfig.json
Normal file
9
packages/react-provider/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import { createElement, render, useState } from 'rax';
|
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import DriverUniversal from 'driver-universal';
|
|
||||||
import { Engine } from '@ali/iceluna-rax';
|
|
||||||
import findDOMNode from 'rax-find-dom-node';
|
|
||||||
|
|
||||||
let updateRax = () => {};
|
|
||||||
|
|
||||||
export default class Rax extends PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const RaxEngine = () => {
|
|
||||||
const [config, setConfig] = useState(this.props);
|
|
||||||
updateRax = setConfig;
|
|
||||||
return createElement(Engine, {
|
|
||||||
...config,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
render(createElement(RaxEngine), document.getElementById('luna-rax-container'), { driver: DriverUniversal });
|
|
||||||
}
|
|
||||||
componentDidUpdate() {
|
|
||||||
updateRax(this.props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div id="luna-rax-container" />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rax.findDOMNode = findDOMNode;
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
import { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import AppContext from '../../context/appContext';
|
|
||||||
import { isEmpty, generateI18n, goldlog } from '../../utils';
|
|
||||||
|
|
||||||
export default class Addon extends PureComponent {
|
|
||||||
static displayName = 'lunaAddon';
|
|
||||||
static propTypes = {
|
|
||||||
config: PropTypes.object,
|
|
||||||
locale: PropTypes.string,
|
|
||||||
messages: PropTypes.object,
|
|
||||||
};
|
|
||||||
static defaultProps = {
|
|
||||||
config: {},
|
|
||||||
};
|
|
||||||
static contextType = AppContext;
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
if (isEmpty(props.config) || !props.config.addonKey) {
|
|
||||||
console.warn('luna addon has wrong config');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 插件上下文中的appHelper使用IDE的appHelper
|
|
||||||
context.appHelper = (window.__ctx && window.__ctx.appHelper) || context.appHelper;
|
|
||||||
context.locale = props.locale;
|
|
||||||
context.messages = props.messages;
|
|
||||||
// 注册插件
|
|
||||||
this.appHelper = context.appHelper;
|
|
||||||
let { locale, messages } = props;
|
|
||||||
this.i18n = generateI18n(locale, messages);
|
|
||||||
this.addonKey = props.config.addonKey;
|
|
||||||
this.appHelper.addons = this.appHelper.addons || {};
|
|
||||||
this.appHelper.addons[this.addonKey] = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillUnmount() {
|
|
||||||
// 销毁插件
|
|
||||||
const config = this.props.config || {};
|
|
||||||
if (config && this.appHelper.addons) {
|
|
||||||
delete this.appHelper.addons[config.addonKey];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open = () => {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
close = () => {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
goldlog = (goKey, params) => {
|
|
||||||
const { addonKey, addonConfig = {} } = this.props.config || {};
|
|
||||||
goldlog(
|
|
||||||
goKey,
|
|
||||||
{
|
|
||||||
addonKey,
|
|
||||||
package: addonConfig.package,
|
|
||||||
version: addonConfig.version,
|
|
||||||
...this.appHelper.logParams,
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
'addon',
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
get utils() {
|
|
||||||
return this.appHelper.utils;
|
|
||||||
}
|
|
||||||
|
|
||||||
get constants() {
|
|
||||||
return this.appHelper.constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
get history() {
|
|
||||||
return this.appHelper.history;
|
|
||||||
}
|
|
||||||
|
|
||||||
get location() {
|
|
||||||
return this.appHelper.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,729 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { on, off } from '@ali/b3-one/lib/event';
|
|
||||||
import AppHelper from '../../utils/appHelper';
|
|
||||||
import SchemaHelper from '../../utils/schemaHelper';
|
|
||||||
import DndHelper from '../../utils/dndHelper';
|
|
||||||
import Engine from '../../engine';
|
|
||||||
|
|
||||||
import CompFactory from '../../hoc/compFactory';
|
|
||||||
import {
|
|
||||||
isSchema,
|
|
||||||
isFileSchema,
|
|
||||||
isEmpty,
|
|
||||||
isJSSlot,
|
|
||||||
jsonuri,
|
|
||||||
registShortCuts,
|
|
||||||
unRegistShortCuts,
|
|
||||||
generateUtils,
|
|
||||||
parseObj,
|
|
||||||
shallowEqual,
|
|
||||||
addCssTag,
|
|
||||||
transformSchemaToPure,
|
|
||||||
goldlog,
|
|
||||||
} from '../../utils';
|
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
const DESIGN_MODE = {
|
|
||||||
EXTEND: 'extend',
|
|
||||||
BORDER: 'border',
|
|
||||||
PREVIEW: 'preview',
|
|
||||||
};
|
|
||||||
|
|
||||||
const DEFAULT_PLACEHOLDER = {
|
|
||||||
emptyImage: '//img.alicdn.com/tfs/TB1zpkUoUT1gK0jSZFhXXaAtVXa-620-430.png',
|
|
||||||
emptyText: '当前页面为空~\n请拖拽组件放入页面容器内吧!',
|
|
||||||
nullImage: '//img.alicdn.com/tfs/TB1m_oSoND1gK0jSZFsXXbldVXa-620-430.png',
|
|
||||||
nullText: '编辑内容不存在~!',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class Canvas extends PureComponent {
|
|
||||||
static displayName = 'Canvas';
|
|
||||||
static propTypes = {
|
|
||||||
appHelper: PropTypes.object,
|
|
||||||
components: PropTypes.object,
|
|
||||||
engine: PropTypes.element,
|
|
||||||
onCreate: PropTypes.func,
|
|
||||||
initSchema: PropTypes.object,
|
|
||||||
shortCuts: PropTypes.array,
|
|
||||||
utils: PropTypes.object,
|
|
||||||
};
|
|
||||||
static defaultProps = {
|
|
||||||
components: {},
|
|
||||||
engine: Engine,
|
|
||||||
onCreate: () => {},
|
|
||||||
initSchema: {},
|
|
||||||
shortCuts: [],
|
|
||||||
utils: {},
|
|
||||||
};
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.appHelper = props.appHelper || new AppHelper();
|
|
||||||
if (!this.appHelper.schemaHelper) {
|
|
||||||
this.appHelper.set('schemaHelper', new SchemaHelper(props.initSchema || {}, this.appHelper));
|
|
||||||
}
|
|
||||||
this.appHelper.set('basicSchemaHelper', this.appHelper.schemaHelper);
|
|
||||||
if (!this.appHelper.dndHelper) {
|
|
||||||
this.appHelper.set('dndHelper', new DndHelper(this.appHelper));
|
|
||||||
}
|
|
||||||
this.appHelper.dndHelper.setCanvasWin(window);
|
|
||||||
if (this.appHelper.designMode === undefined) {
|
|
||||||
this.appHelper.designMode = 'extend';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.canvasAppHelper = new AppHelper({
|
|
||||||
history: this.appHelper.history,
|
|
||||||
location: this.appHelper.location,
|
|
||||||
match: this.appHelper.match,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.updateCanvasAppHelper(props);
|
|
||||||
this.appHelper.once('ide.ready', () => {
|
|
||||||
this.updateCanvasAppHelper(props);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.__ctx = {
|
|
||||||
appHelper: this.appHelper,
|
|
||||||
canvasAppHelper: this.canvasAppHelper,
|
|
||||||
components: this.props.components,
|
|
||||||
};
|
|
||||||
|
|
||||||
window.goldlog = window.goldlog || window.parent.goldlog;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
canvasStack: [
|
|
||||||
{
|
|
||||||
lunaKey: 'root',
|
|
||||||
lunaPath: '',
|
|
||||||
name: 'root',
|
|
||||||
schemaHelper: this.appHelper.schemaHelper,
|
|
||||||
schema: this.appHelper.schemaHelper.get('schema'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
this.appHelper.set('canvasStack', this.state.canvasStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.batchOn(['behavior.undo', 'behavior.redo'], this.handleUndoRedo);
|
|
||||||
appHelper.on('schema.reset', this.handleSchemaReset);
|
|
||||||
appHelper.on('material.move', this.handleMaterialMove);
|
|
||||||
appHelper.on('material.add', this.handleMaterialAdd);
|
|
||||||
appHelper.on('material.remove', this.handleMaterialRemove);
|
|
||||||
appHelper.on('material.up', this.handleMaterialMoveUp);
|
|
||||||
appHelper.on('material.down', this.handleMaterialMoveDown);
|
|
||||||
appHelper.on('material.copy', this.handleMaterialCopy);
|
|
||||||
appHelper.on('material.update', this.handleMaterialUpdate);
|
|
||||||
appHelper.on('material.select', this.handleMaterialSelect);
|
|
||||||
appHelper.on('schemaHelper.schema.afterUpdate', this.handleReset);
|
|
||||||
appHelper.on('designMode.change', this.handleDesignModeChange);
|
|
||||||
appHelper.on('preview.change', this.handlePreviewChange);
|
|
||||||
appHelper.on('canvas.stack.push', this.handleCanvasPush);
|
|
||||||
appHelper.on('canvas.stack.pop', this.handleCanvasPop);
|
|
||||||
appHelper.on('canvas.stack.jump', this.handleCanvasJump);
|
|
||||||
appHelper.on('style.update', this.updateStyle);
|
|
||||||
appHelper.batchOn(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate);
|
|
||||||
appHelper.on('viewPort.update', this.handleForceUpdate);
|
|
||||||
|
|
||||||
registShortCuts(this.props.shortCuts, this.appHelper);
|
|
||||||
this.appHelper.set('canvas', this);
|
|
||||||
this.props.onCreate(this.appHelper);
|
|
||||||
appHelper.emit('canvas.ready', this);
|
|
||||||
goldlog(
|
|
||||||
'EXP',
|
|
||||||
{
|
|
||||||
action: 'appear',
|
|
||||||
},
|
|
||||||
'canvas',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.batchOff(['behavior.undo', 'behavior.redo'], this.handleUndoRedo);
|
|
||||||
appHelper.on('schema.reset', this.handleSchemaReset);
|
|
||||||
appHelper.off('material.move', this.handleMaterialMove);
|
|
||||||
appHelper.off('material.add', this.handleMaterialAdd);
|
|
||||||
appHelper.off('material.remove', this.handleMaterialRemove);
|
|
||||||
appHelper.off('material.up', this.handleMaterialMoveUp);
|
|
||||||
appHelper.off('material.down', this.handleMaterialMoveDown);
|
|
||||||
appHelper.off('material.copy', this.handleMaterialCopy);
|
|
||||||
appHelper.off('material.update', this.handleMaterialUpdate);
|
|
||||||
appHelper.off('material.select', this.handleMaterialSelect);
|
|
||||||
appHelper.off('schemaHelper.schema.afterUpdate', this.handleReset);
|
|
||||||
appHelper.off('designMode.change', this.handleDesignModeChange);
|
|
||||||
appHelper.off('preview.change', this.handlePreviewChange);
|
|
||||||
appHelper.off('canvas.stack.push', this.handleCanvasPush);
|
|
||||||
appHelper.off('canvas.stack.pop', this.handleCanvasPop);
|
|
||||||
appHelper.off('canvas.stack.jump', this.handleCanvasJump);
|
|
||||||
appHelper.off('style.update', this.updateStyle);
|
|
||||||
appHelper.batchOff(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate);
|
|
||||||
appHelper.off('viewPort.update', this.handleForceUpdate);
|
|
||||||
unRegistShortCuts(this.props.shortCuts);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消息处理
|
|
||||||
|
|
||||||
handleMaterialMove = ({ lunaKey, targetKey, direction }) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.schemaHelper.move(lunaKey, targetKey, direction);
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialAdd = ({ schema, targetKey, direction }) => {
|
|
||||||
if (!isSchema(schema)) {
|
|
||||||
throw new Error('物料schema结构异常,无法添加!');
|
|
||||||
}
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const addSchema = Array.isArray(schema) ? schema[0] : schema;
|
|
||||||
// 对于没有设置文件名的容器组件,交给画布外层处理
|
|
||||||
if (isFileSchema(addSchema) && !addSchema.fileName) {
|
|
||||||
return appHelper.emit('onFileNameMaterial.add', { schema: addSchema, targetKey, direction });
|
|
||||||
}
|
|
||||||
|
|
||||||
const addKey = appHelper.schemaHelper.add(schema, targetKey, direction);
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
this.autoSelectComponent(addKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialRemove = (lunaKey) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const schemaHelper = appHelper.schemaHelper;
|
|
||||||
const currCompSchema = schemaHelper.schemaMap[lunaKey];
|
|
||||||
// 获取当前删除物料的相邻物料
|
|
||||||
const nextCompSchema = jsonuri.get(
|
|
||||||
schemaHelper.schema,
|
|
||||||
currCompSchema.__ctx.lunaPath.replace(/\/(\d+)$/, (res, idx) => `/${parseInt(idx) + 1}`),
|
|
||||||
);
|
|
||||||
const activeKey = (nextCompSchema && nextCompSchema.__ctx.lunaKey) || currCompSchema.__ctx.parentKey;
|
|
||||||
appHelper.schemaHelper.remove(lunaKey);
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
this.autoSelectComponent(activeKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialMoveUp = (lunaKey) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'up');
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialMoveDown = (lunaKey) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'down');
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialCopy = (lunaKey) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const addKey = appHelper.schemaHelper.copy(lunaKey);
|
|
||||||
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
this.autoSelectComponent(addKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialUpdate = ({ lunaKey, props, propsKey }) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.schemaHelper.update(lunaKey, props);
|
|
||||||
appHelper.emit('behavior.record', { lunaKey, propsKey });
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaterialSelect = (lunaKey, options) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
if (appHelper.activeKey === lunaKey) return;
|
|
||||||
appHelper.set('activeKey', lunaKey);
|
|
||||||
appHelper.emit('material.select.change', lunaKey, options);
|
|
||||||
const preNode = document.querySelectorAll('[data-active=true]');
|
|
||||||
if (preNode[0] && preNode[0].dataset.lunaKey === lunaKey) return;
|
|
||||||
(preNode || []).forEach((item) => {
|
|
||||||
item.removeAttribute('data-active');
|
|
||||||
item.removeAttribute('data-nochild');
|
|
||||||
});
|
|
||||||
//判断是否容器组件且没有子元素
|
|
||||||
if (!lunaKey) {
|
|
||||||
window.parent.t = window.t = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let schema = appHelper.schemaHelper.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
let componentInfo = appHelper.componentsMap[schema.componentName];
|
|
||||||
const currentNode = document.querySelectorAll(`[data-luna-key=${lunaKey}]`);
|
|
||||||
(currentNode || []).forEach((item) => {
|
|
||||||
item.setAttribute('data-active', 'true');
|
|
||||||
if (componentInfo && componentInfo.isContainer && schema && (!schema.children || !schema.children.length)) {
|
|
||||||
item.setAttribute('data-nochild', 'true');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// for debug
|
|
||||||
let ctx = this.appHelper.schemaHelper.compCtxMap[lunaKey];
|
|
||||||
let ref = this.appHelper.schemaHelper.compThisMap[lunaKey];
|
|
||||||
let t = {
|
|
||||||
ctx,
|
|
||||||
schema,
|
|
||||||
ref,
|
|
||||||
};
|
|
||||||
t.__proto__ = ctx;
|
|
||||||
window.parent.t = window.t = t;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleDesignModeChange = (designMode) => {
|
|
||||||
this.appHelper.set('designMode', designMode);
|
|
||||||
this.forceUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
handlePreviewChange = (isPreview) => {
|
|
||||||
this.appHelper.set('isPreview', isPreview);
|
|
||||||
this.forceUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleUndoRedo = (schema) => {
|
|
||||||
this.appHelper.schemaHelper.reset(schema);
|
|
||||||
this.autoSelectComponent();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleSchemaReset = (schema) => {
|
|
||||||
this.appHelper.schemaHelper.reset(schema);
|
|
||||||
this.appHelper.emit('behavior.record');
|
|
||||||
this.autoSelectComponent();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleReset = () => {
|
|
||||||
this.updateCanvasStack();
|
|
||||||
this.forceUpdate();
|
|
||||||
this.updateStyle();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCanvasAppHelperUpdate = () => {
|
|
||||||
this.updateCanvasAppHelper();
|
|
||||||
this.forceUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleForceUpdate = () => {
|
|
||||||
this.forceUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCanvasPush = ({ schema, lunaKey, name }) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
appHelper.emit('canvas.stack.beforePush');
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
const tempSchema = {
|
|
||||||
componentName: 'Temp',
|
|
||||||
fileName: 'temp',
|
|
||||||
props: {},
|
|
||||||
children: isJSSlot(schema) ? schema.value : schema, //兼容slot
|
|
||||||
};
|
|
||||||
const schemaHelper = new SchemaHelper(transformSchemaToPure(tempSchema), this.appHelper);
|
|
||||||
const schemaMap = this.appHelper.schemaHelper.schemaMap || {};
|
|
||||||
const compCtxMap = this.appHelper.schemaHelper.compCtxMap || {};
|
|
||||||
const currentComp = schemaMap[lunaKey];
|
|
||||||
const undoRedoKey = `${lunaKey}_${canvasStack.length}`;
|
|
||||||
//若是第一层下钻需要先给最上层加上从appHelper中获取的undoRedoKey
|
|
||||||
if (canvasStack.length === 1) {
|
|
||||||
canvasStack[0].undoRedoKey = this.appHelper.undoRedoKey;
|
|
||||||
}
|
|
||||||
const currentData = {
|
|
||||||
lunaKey,
|
|
||||||
lunaPath: currentComp.__ctx.lunaPath,
|
|
||||||
name,
|
|
||||||
schema,
|
|
||||||
schemaHelper,
|
|
||||||
ctx: compCtxMap[lunaKey],
|
|
||||||
undoRedoKey,
|
|
||||||
componentName: currentComp.componentName,
|
|
||||||
};
|
|
||||||
appHelper.set('schemaHelper', schemaHelper);
|
|
||||||
appHelper.undoRedoHelper && appHelper.undoRedoHelper.create(undoRedoKey, tempSchema);
|
|
||||||
appHelper.set('undoRedoKey', undoRedoKey);
|
|
||||||
appHelper.set('activeKey', null);
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
canvasStack: [...this.state.canvasStack, currentData],
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.appHelper.set('canvasStack', this.state.canvasStack);
|
|
||||||
this.appHelper.emit('canvas.stack.afterPush', currentData, this.state.canvasStack);
|
|
||||||
this.autoSelectComponent();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCanvasPop = () => {
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
if (canvasStack.length > 1) {
|
|
||||||
this.handleCanvasJump(null, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCanvasJump = (idx, isPop) => {
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
let preIdx = idx + 1;
|
|
||||||
if (isPop) {
|
|
||||||
appHelper.emit('canvas.stack.beforePop');
|
|
||||||
preIdx = canvasStack.length - 1;
|
|
||||||
idx = preIdx - 1;
|
|
||||||
} else {
|
|
||||||
appHelper.emit('canvas.stack.beforeJump');
|
|
||||||
}
|
|
||||||
if (idx < 0 || idx > canvasStack.length - 1) return;
|
|
||||||
const preData = canvasStack[preIdx];
|
|
||||||
const currentData = canvasStack[idx];
|
|
||||||
appHelper.set('schemaHelper', currentData.schemaHelper);
|
|
||||||
appHelper.set('undoRedoKey', currentData.undoRedoKey);
|
|
||||||
appHelper.undoRedoHelper && appHelper.undoRedoHelper.delete(preData.undoRedoKey);
|
|
||||||
this.setState(
|
|
||||||
{
|
|
||||||
canvasStack: canvasStack.slice(0, idx + 1),
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
appHelper.set('canvasStack', this.state.canvasStack);
|
|
||||||
appHelper.schemaHelper.reset(appHelper.schemaHelper.schema);
|
|
||||||
appHelper.emit('behavior.record');
|
|
||||||
appHelper.emit(`canvas.stack.${isPop ? 'afterPop' : 'afterJump'}`, preData, this.state.canvasStack);
|
|
||||||
this.autoSelectComponent(preData.lunaKey);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 引擎处理函数
|
|
||||||
|
|
||||||
handleCompGetCtx = (schema, ctx) => {
|
|
||||||
const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
|
|
||||||
if (!lunaKey) return;
|
|
||||||
// console.log('+++++ getCtx', lunaKey, ctx);
|
|
||||||
this.appHelper.schemaHelper.compCtxMap[lunaKey] = ctx;
|
|
||||||
// for debug
|
|
||||||
if (this.appHelper.activeKey && lunaKey === this.appHelper.activeKey) {
|
|
||||||
let ref = this.appHelper.schemaHelper.compThisMap[lunaKey];
|
|
||||||
let t = {
|
|
||||||
ctx,
|
|
||||||
schema,
|
|
||||||
ref,
|
|
||||||
};
|
|
||||||
t.__proto__ = ctx;
|
|
||||||
window.parent.t = window.t = t;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleCompGetRef = (schema, ref, topLevel) => {
|
|
||||||
const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
|
|
||||||
if (!lunaKey) return;
|
|
||||||
// console.log('----- getRef', lunaKey, ref);
|
|
||||||
const schemaHelper = this.appHelper.schemaHelper;
|
|
||||||
schemaHelper.compThisMap[lunaKey] = ref;
|
|
||||||
if (ref && !ref.__design) {
|
|
||||||
this.updateDesignMode(ref, schema, topLevel);
|
|
||||||
const didUpdate = ref.componentDidUpdate;
|
|
||||||
ref.componentDidUpdate = (...args) => {
|
|
||||||
didUpdate && didUpdate.apply(ref, args);
|
|
||||||
this.updateDesignMode(ref, schema, topLevel);
|
|
||||||
};
|
|
||||||
const willUnmount = ref.componentWillUnmount;
|
|
||||||
ref.componentWillUnmount = (...args) => {
|
|
||||||
willUnmount && willUnmount.apply(ref, args);
|
|
||||||
// console.log('----- destroy', lunaKey, ref);
|
|
||||||
delete schemaHelper.compThisMap[lunaKey];
|
|
||||||
delete schemaHelper.compCtxMap[lunaKey];
|
|
||||||
};
|
|
||||||
ref.__design = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleDnd = (type, ev, schema) => {
|
|
||||||
const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
|
|
||||||
const designMode = this.appHelper.designMode;
|
|
||||||
if (!lunaKey || ![DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode)) return;
|
|
||||||
const dndHelper = this.appHelper && this.appHelper.dndHelper;
|
|
||||||
if (dndHelper) {
|
|
||||||
dndHelper[`handle${type}`](ev, lunaKey);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//自动选中组件
|
|
||||||
autoSelectComponent = (lunaKey) => {
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
// 若未指定需要选中的组件,且当前有选中的组件不做处理
|
|
||||||
if (appHelper.activeKey && !lunaKey) return;
|
|
||||||
if (!lunaKey) {
|
|
||||||
// 若没有指定的组件,且当前又没有选中组件,默认选中顶部组件,如果是下钻编辑则默认选中第一个子组件
|
|
||||||
const schema = appHelper.schemaHelper.schema;
|
|
||||||
if (schema) {
|
|
||||||
if (schema.componentName === 'Temp') {
|
|
||||||
lunaKey = schema.children && schema.children[0] && schema.children[0].__ctx.lunaKey;
|
|
||||||
} else {
|
|
||||||
lunaKey = schema.__ctx.lunaKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appHelper.emit('material.select', lunaKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 构造低代码组件
|
|
||||||
generateLowComps = (props = this.props) => {
|
|
||||||
const { components } = props;
|
|
||||||
const { utils, constants } = this.canvasAppHelper || {};
|
|
||||||
const componentsMap = this.appHelper.componentsMap || {};
|
|
||||||
Object.keys(componentsMap).forEach((key) => {
|
|
||||||
const comp = componentsMap[key];
|
|
||||||
// 对自定义组件做特殊处理
|
|
||||||
if (comp.version === '0.0.0' && comp.code) {
|
|
||||||
let schema = parseObj(comp.code);
|
|
||||||
if (isFileSchema(schema) && schema.componentName === 'Component') {
|
|
||||||
components[comp.name] = CompFactory(schema, components, componentsMap, {
|
|
||||||
utils,
|
|
||||||
constants,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return components;
|
|
||||||
};
|
|
||||||
|
|
||||||
updateCanvasAppHelper = (props = this.props) => {
|
|
||||||
const { utils } = props;
|
|
||||||
const { entityInfo = {}, componentsMap } = this.appHelper;
|
|
||||||
this.canvasAppHelper.set({
|
|
||||||
componentsMap,
|
|
||||||
utils: entityInfo.utils ? generateUtils(utils, parseObj(entityInfo.utils)) : utils,
|
|
||||||
constants: parseObj((entityInfo && entityInfo.constants) || {}),
|
|
||||||
});
|
|
||||||
this.canvasAppHelper.set('components', this.generateLowComps(props));
|
|
||||||
};
|
|
||||||
|
|
||||||
updateStyle = () => {
|
|
||||||
const entityInfo = this.appHelper.entityInfo || {};
|
|
||||||
const blockSchemaMap = (this.appHelper.schemaHelper && this.appHelper.schemaHelper.blockSchemaMap) || {};
|
|
||||||
const componentsMap = this.appHelper.componentsMap || {};
|
|
||||||
const cssMap = {};
|
|
||||||
// 区块中的样式
|
|
||||||
Object.keys(blockSchemaMap).forEach((item) => {
|
|
||||||
const schema = blockSchemaMap[item];
|
|
||||||
cssMap[schema.fileName] = schema.css || (schema.__ctx && schema.__ctx.css) || '';
|
|
||||||
});
|
|
||||||
// 低代码自定义组件中的样式
|
|
||||||
Object.keys(componentsMap).forEach((item) => {
|
|
||||||
const comp = componentsMap[item];
|
|
||||||
// 对自定义组件做特殊处理
|
|
||||||
if (comp.version === '0.0.0' && comp.code && comp.css) {
|
|
||||||
cssMap[comp.name] = comp.css;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cssMap.__global = entityInfo.css || '';
|
|
||||||
if (shallowEqual(this.cacheCssMap, cssMap)) return;
|
|
||||||
this.cacheCssMap = cssMap;
|
|
||||||
const { __global, ...other } = cssMap;
|
|
||||||
addCssTag(
|
|
||||||
'luna-canvas-style',
|
|
||||||
`${__global}\n${Object.keys(other || {})
|
|
||||||
.map((item) => cssMap[item])
|
|
||||||
.join('\n')}`,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
updateCanvasStack = () => {
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
if (canvasStack.length < 2) return;
|
|
||||||
for (let idx = canvasStack.length - 1; idx > 0; idx--) {
|
|
||||||
const currentData = canvasStack[idx];
|
|
||||||
const { lunaPath, name, schemaHelper, schema } = currentData;
|
|
||||||
const preData = canvasStack[idx - 1];
|
|
||||||
let data = schemaHelper.getPureSchema().children;
|
|
||||||
// 如果情况内容则删除属性
|
|
||||||
if (isEmpty(data)) {
|
|
||||||
jsonuri.rm(
|
|
||||||
preData.schemaHelper.schema,
|
|
||||||
name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isJSSlot(schema)) {
|
|
||||||
data = {
|
|
||||||
...schema,
|
|
||||||
value: data,
|
|
||||||
};
|
|
||||||
} else if (name !== 'children') {
|
|
||||||
data = {
|
|
||||||
type: 'JSSlot',
|
|
||||||
value: data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
jsonuri.set(
|
|
||||||
preData.schemaHelper.schema,
|
|
||||||
name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`,
|
|
||||||
data,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
updateDesignMode = (ref, schema, topLevel) => {
|
|
||||||
if (!ref || (ref && ref.current === null) || !schema.__ctx) return;
|
|
||||||
const { engine } = this.props;
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const { activeKey, isPreview, viewPortConfig } = appHelper;
|
|
||||||
const designMode = isPreview ? 'preview' : appHelper.designMode;
|
|
||||||
const node = engine.findDOMNode(ref.current || ref);
|
|
||||||
|
|
||||||
if (!node || !node.getAttribute) return;
|
|
||||||
// 渲染引擎可以通过设置__disableDesignMode属性的方式阻止组件的可视模式;
|
|
||||||
const hasDesignMode =
|
|
||||||
[DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode) && !ref.props.__disableDesignMode;
|
|
||||||
node.setAttribute('data-design-mode', designMode && hasDesignMode ? `luna-design-${designMode}` : '');
|
|
||||||
if (topLevel) {
|
|
||||||
node.setAttribute('top-container', true);
|
|
||||||
}
|
|
||||||
const lunaKey = schema.__ctx.lunaKey;
|
|
||||||
let instanceName = schema.componentName + (window.parent.__isDebug ? (lunaKey || '_').split('_')[1] : '');
|
|
||||||
switch (schema.componentName) {
|
|
||||||
case 'Page':
|
|
||||||
instanceName = '页面容器 ' + instanceName;
|
|
||||||
break;
|
|
||||||
case 'Block':
|
|
||||||
instanceName = '区块容器 ' + instanceName;
|
|
||||||
break;
|
|
||||||
case 'Component':
|
|
||||||
instanceName = '低代码组件容器 ' + instanceName;
|
|
||||||
break;
|
|
||||||
case 'Addon':
|
|
||||||
instanceName = '插件容器 ' + instanceName;
|
|
||||||
break;
|
|
||||||
case 'Temp':
|
|
||||||
instanceName = '下钻编辑器容器';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topLevel && viewPortConfig) {
|
|
||||||
node.style.transform = `scale(${viewPortConfig.scale ? viewPortConfig.scale / 100 : 1})`;
|
|
||||||
}
|
|
||||||
node.setAttribute('data-instance-name', instanceName);
|
|
||||||
node.setAttribute('data-luna-key', lunaKey);
|
|
||||||
node.setAttribute('data-luna-path', schema.__ctx.lunaPath);
|
|
||||||
|
|
||||||
if (hasDesignMode) {
|
|
||||||
if (activeKey && activeKey === lunaKey) {
|
|
||||||
node.setAttribute('data-active', true);
|
|
||||||
} else {
|
|
||||||
node.removeAttribute('data-active');
|
|
||||||
}
|
|
||||||
// 点击
|
|
||||||
if (!node.compEvent && schema.componentName !== 'Temp') {
|
|
||||||
node.compEvent = (ev) => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
appHelper.emit('material.select', lunaKey, { isFromCanvas: true });
|
|
||||||
};
|
|
||||||
on(node, 'mousedown', node.compEvent, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// drag and drop
|
|
||||||
if (!node.draggableFlag) {
|
|
||||||
if (topLevel) {
|
|
||||||
node.ondragleave = (ev) => this.handleDnd('DragLeave', ev, schema);
|
|
||||||
node.ondrop = (ev) => this.handleDnd('Drop', ev, schema);
|
|
||||||
} else {
|
|
||||||
node.setAttribute('draggable', 'true');
|
|
||||||
node.ondragstart = (ev) => this.handleDnd('DragStart', ev, schema);
|
|
||||||
node.ondragend = (ev) => this.handleDnd('DragEnd', ev, schema);
|
|
||||||
}
|
|
||||||
node.ondragover = (ev) => this.handleDnd('DragOver', ev, schema);
|
|
||||||
node.draggableFlag = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//点击
|
|
||||||
if (node.compEvent) {
|
|
||||||
off(node, 'mousedown', node.compEvent, false);
|
|
||||||
delete node.compEvent;
|
|
||||||
}
|
|
||||||
//drag and drop
|
|
||||||
if (node.draggableFlag) {
|
|
||||||
node.removeAttribute('draggable');
|
|
||||||
delete node.ondragstart;
|
|
||||||
delete node.ondragover;
|
|
||||||
delete node.ondragend;
|
|
||||||
delete node.ondragleave;
|
|
||||||
delete node.ondrop;
|
|
||||||
delete node.draggableFlag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderCanvasStack = () => {
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
const lastIndex = canvasStack.length - 1;
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const canvasAppHelper = this.canvasAppHelper;
|
|
||||||
const designMode = appHelper.isPreview ? 'preview' : appHelper.designMode;
|
|
||||||
const Engine = this.props.engine;
|
|
||||||
|
|
||||||
return (canvasStack || []).map((item, idx) => (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
'engine-wrapper',
|
|
||||||
designMode,
|
|
||||||
item.schemaHelper.schema &&
|
|
||||||
item.schemaHelper.schema.props.style && {
|
|
||||||
'fixed-width': item.schemaHelper.schema.props.style.width,
|
|
||||||
'fixed-height': item.schemaHelper.schema.props.style.height,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
key={`${item.lunaKey}_${item.name}`}
|
|
||||||
>
|
|
||||||
<Engine
|
|
||||||
schema={item.schemaHelper.schema}
|
|
||||||
__ctx={item.ctx}
|
|
||||||
designMode={designMode}
|
|
||||||
appHelper={canvasAppHelper}
|
|
||||||
components={canvasAppHelper.components}
|
|
||||||
componentsMap={appHelper.componentsMap}
|
|
||||||
suspended={idx !== lastIndex}
|
|
||||||
onCompGetCtx={this.handleCompGetCtx}
|
|
||||||
onCompGetRef={this.handleCompGetRef}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { canvasStack } = this.state;
|
|
||||||
const lastIndex = canvasStack.length - 1;
|
|
||||||
const schema = canvasStack[lastIndex] && canvasStack[lastIndex].schemaHelper.schema;
|
|
||||||
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
const { entityInfo = {}, viewPortConfig = {}, canvasPlaceholder = {} } = appHelper;
|
|
||||||
const components = this.canvasAppHelper.components || {};
|
|
||||||
|
|
||||||
const placeholder = { ...DEFAULT_PLACEHOLDER, ...canvasPlaceholder };
|
|
||||||
const layoutComp = entityInfo.layoutInfo && entityInfo.layoutInfo.name;
|
|
||||||
const layoutProps = (entityInfo.layoutInfo && entityInfo.layoutInfo.realProps) || {};
|
|
||||||
const Layout = layoutComp && components[layoutComp];
|
|
||||||
const { hideLayout } = viewPortConfig;
|
|
||||||
const isDrillDown = canvasStack && canvasStack.length > 1;
|
|
||||||
const isSchemaEmpty = isSchema(schema) && isEmpty(schema.children);
|
|
||||||
const isSchemaNull = schema === null;
|
|
||||||
const canvasStyle = {};
|
|
||||||
if (!isDrillDown) {
|
|
||||||
if (isSchemaEmpty) {
|
|
||||||
canvasStyle.backgroundImage = `url(${placeholder.emptyImage})`;
|
|
||||||
} else if (isSchemaNull) {
|
|
||||||
canvasStyle.backgroundImage = `url(${placeholder.nullImage})`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames('luna-canvas-inner', {
|
|
||||||
empty: isSchemaEmpty,
|
|
||||||
null: isSchemaNull,
|
|
||||||
'drill-down': isDrillDown,
|
|
||||||
})}
|
|
||||||
style={canvasStyle}
|
|
||||||
data-placeholder-text={isSchemaEmpty ? placeholder.emptyText : isSchemaNull ? placeholder.nullText : ''}
|
|
||||||
>
|
|
||||||
{Layout && !hideLayout ? (
|
|
||||||
<Layout location={appHelper.location} history={appHelper.history} {...layoutProps}>
|
|
||||||
{this.renderCanvasStack()}
|
|
||||||
</Layout>
|
|
||||||
) : (
|
|
||||||
this.renderCanvasStack()
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,361 +0,0 @@
|
|||||||
/*增加标签函数*/
|
|
||||||
@mixin labelFun($type: before) {
|
|
||||||
&:#{$type} {
|
|
||||||
content: attr(data-instance-name) !important;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
right: unset;
|
|
||||||
bottom: unset;
|
|
||||||
color: #666 !important;
|
|
||||||
font-size: 12px !important;
|
|
||||||
float: left;
|
|
||||||
padding: 0 5px !important;
|
|
||||||
line-height: 12px !important;
|
|
||||||
height: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: rgba(222, 222, 222, 0.7);
|
|
||||||
z-index: 2;
|
|
||||||
border-left: 3px solid transparent;
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.luna-block,
|
|
||||||
&.luna-page,
|
|
||||||
&.luna-comp {
|
|
||||||
&:#{$type} {
|
|
||||||
border-color: #2077ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-active='true'] {
|
|
||||||
&:#{$type} {
|
|
||||||
color: #fff !important;
|
|
||||||
background: #1861d5 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-design-mode='luna-design-border'] {
|
|
||||||
&:#{$type} {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-active='true'] {
|
|
||||||
&:#{$type} {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.luna-canvas-inner {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
&.empty,
|
|
||||||
&.null {
|
|
||||||
position: relative;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: calc(50% - 180px) 50%;
|
|
||||||
background-size: 310px 215px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: attr(data-placeholder-text);
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
margin: -40px 0 0 20px;
|
|
||||||
height: 80px;
|
|
||||||
line-height: 40px;
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 24px;
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.empty {
|
|
||||||
&.drill-down {
|
|
||||||
&:before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: '请拖入组件';
|
|
||||||
text-align: center;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.engine-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
display: none;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
&.extend,
|
|
||||||
&.border {
|
|
||||||
padding: 1px;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fixed-width > div {
|
|
||||||
min-width: unset;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fixed-height > div {
|
|
||||||
min-height: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
transform-origin: left top;
|
|
||||||
min-width: 100%;
|
|
||||||
width: fit-content;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
|
||||||
span:not(.next-input-group):not(.next-input) {
|
|
||||||
&[data-design-mode*='luna-design-'] {
|
|
||||||
display: inline-block;
|
|
||||||
min-height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-luna-key] {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-design-mode='luna-design-border'] {
|
|
||||||
min-height: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-design-mode='luna-design-extend'] {
|
|
||||||
min-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-design-mode*='luna-design-'] {
|
|
||||||
position: relative;
|
|
||||||
outline: 1px dotted #d9d9d9;
|
|
||||||
zoom: 1;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
outline: 1px dotted #2077ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[draggable='true'] {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.next-card-body {
|
|
||||||
overflow: inherit !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.next-loading {
|
|
||||||
pointer-events: all !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-active='true'] {
|
|
||||||
outline: 1px solid #1861d5 !important;
|
|
||||||
|
|
||||||
&[data-nochild='true']:not(.next-step-item):not([top-container='true']) {
|
|
||||||
min-height: 60px;
|
|
||||||
min-width: 200px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: '请拖入组件';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto;
|
|
||||||
opacity: 1 !important;
|
|
||||||
visibility: visible !important;
|
|
||||||
line-height: 30px;
|
|
||||||
height: 30px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #ccc;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.next-tag):not(.next-icon):not(.anticon):not(.icon) {
|
|
||||||
@include labelFun(before);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.next-tag,
|
|
||||||
&.next-icon,
|
|
||||||
&.anticon,
|
|
||||||
&.icon {
|
|
||||||
@include labelFun(after);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.next-tabs-tabpane.hidden {
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ant-loop:after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
clear: both;
|
|
||||||
line-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-tabs-tabpane {
|
|
||||||
padding: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ide-design-placeholder {
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed #d9d9d9;
|
|
||||||
outline: none;
|
|
||||||
padding: 0 !important;
|
|
||||||
min-height: 20px;
|
|
||||||
min-width: 80px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: attr(data-prop);
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #e9e9e9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-instance-name='TableGroupHeaderF'] {
|
|
||||||
clear: both;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
clear: both;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-design-mode='luna-design-extend'] {
|
|
||||||
&[data-luna-key*='luna_'] {
|
|
||||||
&:not([class*='-input']):not([class*='-picker']):not([class*='-table']):not([class*='-switch']):not([class*='-select']):not(img):not([class*='-btn']):not(.next-tag):not(input):not([class*='-rating']):not([class*='next-menu']) {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.ant-loop {
|
|
||||||
padding: 10px 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*='-form-item-control'] {
|
|
||||||
& > [data-design-mode*='luna-design-'] {
|
|
||||||
&:not(button):not(input):not([class*='-input']):not([class*='luna-comp-']) {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#luna-canvas-effect {
|
|
||||||
position: fixed;
|
|
||||||
background: #1aab11;
|
|
||||||
z-index: 10000000;
|
|
||||||
text-align: center;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 2px;
|
|
||||||
height: 2px;
|
|
||||||
border: 4px solid #1aab11;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.left,
|
|
||||||
&.right {
|
|
||||||
width: 2px;
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
left: -4px;
|
|
||||||
border-left-color: transparent;
|
|
||||||
border-right-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
top: 0;
|
|
||||||
border-bottom-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
bottom: 0;
|
|
||||||
border-top-width: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.top,
|
|
||||||
&.bottom,
|
|
||||||
&.in {
|
|
||||||
height: 2px;
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
top: -4px;
|
|
||||||
border-top-color: transparent;
|
|
||||||
border-bottom-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
left: 0;
|
|
||||||
border-right-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
right: 0;
|
|
||||||
border-left-width: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.in {
|
|
||||||
b {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
top: -12px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 10px;
|
|
||||||
color: #fff;
|
|
||||||
background: #1aab11;
|
|
||||||
height: 16px !important;
|
|
||||||
line-height: 16px !important;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 11px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55
packages/react-renderer/src/hoc/addonFactory.js
vendored
55
packages/react-renderer/src/hoc/addonFactory.js
vendored
@ -1,55 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import AddonEngine from '../engine/addonEngine';
|
|
||||||
import BlockEngine from '../engine/blockEngine';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import { forEach, isFileSchema } from '../utils';
|
|
||||||
export default function addonFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
|
||||||
class LNAddonView extends PureComponent {
|
|
||||||
static dislayName = 'luna-addon-factory';
|
|
||||||
static version = config.version || '0.0.0';
|
|
||||||
static contextType = AppContext;
|
|
||||||
static propTypes = {
|
|
||||||
forwardedRef: PropTypes.func,
|
|
||||||
};
|
|
||||||
render() {
|
|
||||||
if (!schema || schema.componentName !== 'Addon' || !isFileSchema(schema)) {
|
|
||||||
console.warn('编辑器插件模型结构异常!');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { forwardedRef, ...otherProps } = this.props;
|
|
||||||
const props = {
|
|
||||||
...schema.defaultProps,
|
|
||||||
...otherProps,
|
|
||||||
__schema: schema,
|
|
||||||
ref: forwardedRef,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
appHelper: window.__ctx && window.__ctx.appHelper, // 插件上下文中的appHelper使用IDE的appHelper
|
|
||||||
components: { ...components, Addon: AddonEngine, Block: BlockEngine },
|
|
||||||
componentsMap,
|
|
||||||
config,
|
|
||||||
locale: props.locale,
|
|
||||||
messages: props.messages,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<AddonEngine
|
|
||||||
{...props}
|
|
||||||
__components={{ ...components, Addon: AddonEngine, Block: BlockEngine }}
|
|
||||||
__componentsMap={componentsMap}
|
|
||||||
__appHelper={window.__ctx && window.__ctx.appHelper}
|
|
||||||
/>
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const ResComp = React.forwardRef((props, ref) => <LNAddonView {...props} forwardedRef={ref} />);
|
|
||||||
forEach(schema.static, (val, key) => {
|
|
||||||
ResComp[key] = val;
|
|
||||||
});
|
|
||||||
ResComp.version = config.version || '0.0.0';
|
|
||||||
return ResComp;
|
|
||||||
}
|
|
||||||
75
packages/react-renderer/src/hoc/compFactory.js
vendored
75
packages/react-renderer/src/hoc/compFactory.js
vendored
@ -1,75 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import CompEngine from '../engine/compEngine';
|
|
||||||
import BlockEngine from '../engine/blockEngine';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
import AppHelper from '../utils/appHelper';
|
|
||||||
import { forEach, isFileSchema } from '../utils';
|
|
||||||
export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
|
|
||||||
// 自定义组件需要有自己独立的appHelper
|
|
||||||
const appHelper = new AppHelper(config);
|
|
||||||
class LNCompView extends PureComponent {
|
|
||||||
static dislayName = 'luna-comp-factory';
|
|
||||||
static version = config.version || '0.0.0';
|
|
||||||
static contextType = AppContext;
|
|
||||||
static propTypes = {
|
|
||||||
forwardedRef: PropTypes.func,
|
|
||||||
};
|
|
||||||
render() {
|
|
||||||
if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) {
|
|
||||||
console.warn('自定义组件模型结构异常!');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { forwardedRef, ...otherProps } = this.props;
|
|
||||||
// 低代码组件透传应用上下文
|
|
||||||
const appCtx = ['utils', 'constants'];
|
|
||||||
appCtx.forEach((key) => {
|
|
||||||
if (!appHelper[key] && this.context && this.context.appHelper && this.context.appHelper[key]) {
|
|
||||||
appHelper.set(key, this.context.appHelper[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const routerCtx = ['history', 'location', 'match'];
|
|
||||||
routerCtx.forEach((key) => {
|
|
||||||
if (this.context && this.context.appHelper && this.context.appHelper[key]) {
|
|
||||||
appHelper.set(key, this.context.appHelper[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 支持通过context透传国际化配置
|
|
||||||
const localeProps = {};
|
|
||||||
const { locale, messages } = this.context;
|
|
||||||
if (locale && messages && messages[schema.fileName]) {
|
|
||||||
localeProps.locale = locale;
|
|
||||||
localeProps.messages = messages[schema.fileName];
|
|
||||||
}
|
|
||||||
const props = {
|
|
||||||
...schema.defaultProps,
|
|
||||||
...localeProps,
|
|
||||||
...otherProps,
|
|
||||||
__schema: schema,
|
|
||||||
ref: forwardedRef,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AppContext.Provider
|
|
||||||
value={{
|
|
||||||
...this.context,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CompEngine
|
|
||||||
{...props}
|
|
||||||
__appHelper={appHelper}
|
|
||||||
__components={{ ...components, Component: CompEngine, Block: BlockEngine }}
|
|
||||||
__componentsMap={componentsMap}
|
|
||||||
/>
|
|
||||||
</AppContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ResComp = React.forwardRef((props, ref) => <LNCompView {...props} forwardedRef={ref} />);
|
|
||||||
forEach(schema.static, (val, key) => {
|
|
||||||
ResComp[key] = val;
|
|
||||||
});
|
|
||||||
ResComp.version = config.version || '0.0.0';
|
|
||||||
return ResComp;
|
|
||||||
}
|
|
||||||
29
packages/react-renderer/src/hoc/localeConfig.js
vendored
29
packages/react-renderer/src/hoc/localeConfig.js
vendored
@ -1,29 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import AppContext from '../context/appContext';
|
|
||||||
export default function localeConfig(componentName, Component) {
|
|
||||||
class LNLocaleConfigView extends PureComponent {
|
|
||||||
static dislayName = 'luna-locale-config';
|
|
||||||
static contextType = AppContext;
|
|
||||||
static propTypes = {
|
|
||||||
forwardedRef: PropTypes.func,
|
|
||||||
};
|
|
||||||
render() {
|
|
||||||
const { forwardedRef, ...otherProps } = this.props;
|
|
||||||
const { locale, messages } = this.context;
|
|
||||||
const localeProps = {};
|
|
||||||
if (locale && messages && messages[componentName]) {
|
|
||||||
localeProps.locale = locale;
|
|
||||||
localeProps.messages = messages[componentName];
|
|
||||||
}
|
|
||||||
const props = {
|
|
||||||
...localeProps,
|
|
||||||
...otherProps,
|
|
||||||
ref: forwardedRef,
|
|
||||||
};
|
|
||||||
return <Component {...props} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return React.forwardRef((props, ref) => <LNLocaleConfigView {...props} forwardedRef={ref} />);
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import React, { PureComponent, Suspense } from 'react';
|
|
||||||
export default function SuspenseWrapper(fallback = null) {
|
|
||||||
return function(Component) {
|
|
||||||
class SuspenseWrapper extends PureComponent {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Suspense fallback={fallback}>
|
|
||||||
<Component {...this.props} />
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SuspenseWrapper;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
49
packages/react-renderer/src/utils/appHelper.js
vendored
49
packages/react-renderer/src/utils/appHelper.js
vendored
@ -1,49 +0,0 @@
|
|||||||
import EventEmitter from 'events';
|
|
||||||
import Debug from 'debug';
|
|
||||||
let instance = null;
|
|
||||||
const debug = Debug('utils:appHelper');
|
|
||||||
EventEmitter.defaultMaxListeners = 100;
|
|
||||||
|
|
||||||
export default class AppHelper extends EventEmitter {
|
|
||||||
static getInstance = () => {
|
|
||||||
if (!instance) {
|
|
||||||
instance = new AppHelper();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(config) {
|
|
||||||
super();
|
|
||||||
instance = this;
|
|
||||||
Object.assign(this, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key) {
|
|
||||||
return this[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key, val) {
|
|
||||||
if (typeof key === 'string') {
|
|
||||||
this[key] = val;
|
|
||||||
} else if (typeof key === 'object') {
|
|
||||||
Object.keys(key).forEach((item) => {
|
|
||||||
this[item] = key[item];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
batchOn(events, lisenter) {
|
|
||||||
if (!Array.isArray(events)) return;
|
|
||||||
events.forEach((event) => this.on(event, lisenter));
|
|
||||||
}
|
|
||||||
|
|
||||||
batchOnce(events, lisenter) {
|
|
||||||
if (!Array.isArray(events)) return;
|
|
||||||
events.forEach((event) => this.once(event, lisenter));
|
|
||||||
}
|
|
||||||
|
|
||||||
batchOff(events, lisenter) {
|
|
||||||
if (!Array.isArray(events)) return;
|
|
||||||
events.forEach((event) => this.off(event, lisenter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
574
packages/react-renderer/src/utils/dndHelper.js
vendored
574
packages/react-renderer/src/utils/dndHelper.js
vendored
@ -1,574 +0,0 @@
|
|||||||
import ReactDOM from 'react-dom';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import { isFileSchema, isEmpty, throttle, deepEqual } from './index';
|
|
||||||
const DICT = {
|
|
||||||
left: '左',
|
|
||||||
right: '右',
|
|
||||||
top: '上',
|
|
||||||
bottom: '下',
|
|
||||||
in: '里',
|
|
||||||
};
|
|
||||||
const TOP_COMPONENT = ['Page', 'Component', 'Temp']; // 顶端模块,不支持放置兄弟节点
|
|
||||||
const debug = Debug('utils:dndHelper');
|
|
||||||
export default class DndHelper {
|
|
||||||
constructor(appHelper) {
|
|
||||||
this.appHelper = appHelper;
|
|
||||||
this.dragDom = null;
|
|
||||||
this.canvasEffectDom = null;
|
|
||||||
this.treeEffectDom = null;
|
|
||||||
this.containrDom = null;
|
|
||||||
this.sourceEntity = null;
|
|
||||||
this.tempEntity = null;
|
|
||||||
this.dragInfo = null;
|
|
||||||
this.canvasClearTimer = null;
|
|
||||||
this.treeClearTimer = null;
|
|
||||||
this.isDragging = false;
|
|
||||||
this.dragOverFunc = throttle(this.dragOverFunc, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
setCanvasWin(win) {
|
|
||||||
this.canvasWin = win;
|
|
||||||
if (this.canvasEffectDom) {
|
|
||||||
this.canvasWin.document.body.appendChild(this.canvasEffectDom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(msg, ...args) {
|
|
||||||
this.appHelper && this.appHelper.emit(msg, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
dragOverFunc(ev, schemaOrNode, isTree) {
|
|
||||||
if (!this.isDragging || !this.sourceEntity) return;
|
|
||||||
const entity = isTree
|
|
||||||
? this.getTreeEntity(schemaOrNode, ev)
|
|
||||||
: {
|
|
||||||
target: ev.currentTarget,
|
|
||||||
schema: schemaOrNode,
|
|
||||||
};
|
|
||||||
if (this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaKey === entity.schema.__ctx.lunaKey)
|
|
||||||
return;
|
|
||||||
let dragInfo = null;
|
|
||||||
if (isTree) {
|
|
||||||
dragInfo = this.getTreeDragInfo(ev, entity);
|
|
||||||
} else {
|
|
||||||
dragInfo = this.getDragInfo(ev, entity);
|
|
||||||
}
|
|
||||||
if (!dragInfo || deepEqual(this.dragInfo, dragInfo)) return;
|
|
||||||
this.dragInfo = dragInfo;
|
|
||||||
this.tempEntity = dragInfo.entity;
|
|
||||||
this.clearEffect(isTree);
|
|
||||||
this.addEffect(isTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeCanvas() {
|
|
||||||
debug('change canvas', this.sourceEntity, this.tempEntity);
|
|
||||||
if (!this.sourceEntity || !this.tempEntity) return;
|
|
||||||
if (this.sourceEntity.isAdd) {
|
|
||||||
debug('add material', this.sourceEntity.schema, this.tempEntity.schema.__ctx.lunaKey, this.dragInfo.position);
|
|
||||||
this.emit('material.add', {
|
|
||||||
schema: this.sourceEntity.schema,
|
|
||||||
targetKey: this.tempEntity.schema.__ctx.lunaKey,
|
|
||||||
direction: this.dragInfo.position,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.emit('material.move', {
|
|
||||||
lunaKey: this.sourceEntity.schema.__ctx.lunaKey,
|
|
||||||
targetKey: this.tempEntity.schema.__ctx.lunaKey,
|
|
||||||
direction: this.dragInfo.position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getTreeEntity(node, ev) {
|
|
||||||
if (!node) return;
|
|
||||||
const schemaHelper = this.appHelper.schemaHelper;
|
|
||||||
const lunaKey = node.props.eventKey;
|
|
||||||
const schema = schemaHelper.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
const ref = schemaHelper.compThisMap[lunaKey];
|
|
||||||
const currentTarget = ev.currentTarget;
|
|
||||||
return {
|
|
||||||
schema,
|
|
||||||
target: ref && ReactDOM.findDOMNode(ref),
|
|
||||||
treeNodeTarget: currentTarget,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getDragTagDom(tagName) {
|
|
||||||
if (!this.dragDom) {
|
|
||||||
const dragDom = document.createElement('div');
|
|
||||||
dragDom.id = 'luna-drag-dom';
|
|
||||||
dragDom.style.height = '24px';
|
|
||||||
dragDom.style.position = 'absolute';
|
|
||||||
dragDom.style.zIndex = 10000000;
|
|
||||||
dragDom.style.transform = 'translateY(-10000px)';
|
|
||||||
dragDom.style.background = 'rgba(0, 0, 0, .5)';
|
|
||||||
dragDom.style.lineHeight = '24px';
|
|
||||||
dragDom.style.color = '#fff';
|
|
||||||
dragDom.style.padding = '0px 10px';
|
|
||||||
dragDom.style.display = 'inline-block';
|
|
||||||
document.body.appendChild(dragDom);
|
|
||||||
this.dragDom = dragDom;
|
|
||||||
}
|
|
||||||
this.dragDom.innerHTML = `<i class="next-icon next-icon-zujianku next-small"></i> ${tagName}`;
|
|
||||||
return this.dragDom;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCanvasEffectDom() {
|
|
||||||
if (!this.canvasWin) {
|
|
||||||
throw new Error('should set the canvasWin first');
|
|
||||||
}
|
|
||||||
if (this.canvasClearTimer) {
|
|
||||||
clearTimeout(this.canvasClearTimer);
|
|
||||||
this.canvasClearTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { position } = this.dragInfo;
|
|
||||||
let canvasEffectDom = this.canvasEffectDom;
|
|
||||||
if (!canvasEffectDom) {
|
|
||||||
canvasEffectDom = document.createElement('div');
|
|
||||||
this.canvasWin.document.body.appendChild(canvasEffectDom);
|
|
||||||
this.canvasEffectDom = canvasEffectDom;
|
|
||||||
}
|
|
||||||
canvasEffectDom.id = 'luna-canvas-effect';
|
|
||||||
canvasEffectDom.innerHTML = `<b>${DICT[position]}</b>`;
|
|
||||||
canvasEffectDom.className = position;
|
|
||||||
canvasEffectDom.style.display = 'block';
|
|
||||||
|
|
||||||
return canvasEffectDom;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTreeEffectDom() {
|
|
||||||
if (this.treeClearTimer) {
|
|
||||||
clearTimeout(this.treeClearTimer);
|
|
||||||
this.treeClearTimer = null;
|
|
||||||
}
|
|
||||||
let treeEffectDom = this.treeEffectDom;
|
|
||||||
if (!treeEffectDom) {
|
|
||||||
treeEffectDom = document.createElement('div');
|
|
||||||
this.treeEffectDom = treeEffectDom;
|
|
||||||
}
|
|
||||||
treeEffectDom.id = 'luna-tree-effect';
|
|
||||||
treeEffectDom.style.display = 'block';
|
|
||||||
return treeEffectDom;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLunaContainerDom(target) {
|
|
||||||
if (!target) return null;
|
|
||||||
let parent = target.parentNode;
|
|
||||||
while (parent && (!parent.dataset || !parent.dataset.lunaKey)) {
|
|
||||||
parent = parent.parentNode;
|
|
||||||
}
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCompTreeEffect() {
|
|
||||||
const container = document.querySelector('.luna-comp-tree');
|
|
||||||
if (!container) return;
|
|
||||||
|
|
||||||
let treeItems = container.querySelectorAll('.tree-item');
|
|
||||||
(treeItems || []).forEach((item) => {
|
|
||||||
const classList = item.classList;
|
|
||||||
if (classList) {
|
|
||||||
classList.remove('top');
|
|
||||||
classList.remove('in');
|
|
||||||
classList.remove('bottom');
|
|
||||||
classList.remove('tree-item');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDragInfo(ev, entity) {
|
|
||||||
if (!this.sourceEntity || !entity) return null;
|
|
||||||
const { target, schema } = entity;
|
|
||||||
const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath;
|
|
||||||
const targetPath = schema.__ctx.lunaPath;
|
|
||||||
const sourceTarget = this.sourceEntity.target;
|
|
||||||
|
|
||||||
if (sourcePath === targetPath) return null;
|
|
||||||
if (targetPath && targetPath.startsWith(sourcePath)) return null;
|
|
||||||
const componentsMap = this.appHelper.get('componentsMap');
|
|
||||||
// if (!componentsMap || !componentsMap[schema.componentName]) return null;
|
|
||||||
let isContainer =
|
|
||||||
(componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件
|
|
||||||
if (schema.children && typeof schema.children !== 'object') {
|
|
||||||
//如果children是文本, 非模型结构,则非容器;
|
|
||||||
isContainer = false;
|
|
||||||
}
|
|
||||||
const rect = target.getBoundingClientRect();
|
|
||||||
const isSupportIn =
|
|
||||||
isContainer &&
|
|
||||||
(!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children)));
|
|
||||||
const sourceIsInline = sourceTarget && ['inline-block', 'inline'].includes(getComputedStyle(sourceTarget).display);
|
|
||||||
const isInline = ['inline-block', 'inline'].includes(getComputedStyle(target).display) && sourceIsInline;
|
|
||||||
const measure = isInline ? 'width' : 'height';
|
|
||||||
|
|
||||||
let sn = 0;
|
|
||||||
let position = 'top';
|
|
||||||
if (isContainer) {
|
|
||||||
sn = isSupportIn ? rect[measure] * 0.25 : Math.min(rect[measure] * 0.5, 10);
|
|
||||||
} else {
|
|
||||||
sn = rect[measure] * 0.5;
|
|
||||||
}
|
|
||||||
if (TOP_COMPONENT.includes(schema.componentName)) {
|
|
||||||
// 顶端组件,拖拽over时,只能放在其内部
|
|
||||||
position = 'in';
|
|
||||||
} else if (isInline && !isContainer) {
|
|
||||||
if (Math.abs(ev.clientX - rect.left) <= sn) {
|
|
||||||
position = 'left';
|
|
||||||
} else if (Math.abs(ev.clientX - rect.right) <= sn) {
|
|
||||||
position = 'right';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (Math.abs(ev.clientY - rect.top) <= sn) {
|
|
||||||
position = 'top';
|
|
||||||
} else if (Math.abs(ev.clientY - rect.bottom) <= sn) {
|
|
||||||
position = 'bottom';
|
|
||||||
} else {
|
|
||||||
position = 'in';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否是相邻元素, 往左|上拖
|
|
||||||
const isPrevSibling = sourceTarget === target.nextElementSibling;
|
|
||||||
if (isPrevSibling) {
|
|
||||||
if (position === 'right') position = 'left';
|
|
||||||
if (position === 'bottom') {
|
|
||||||
position = isContainer ? 'in' : 'top';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 判断是否相邻元素,往右|下拖
|
|
||||||
const isPostSibling = sourceTarget === target.previousElementSibling;
|
|
||||||
if (isPostSibling) {
|
|
||||||
if (position === 'left') position = 'right';
|
|
||||||
if (position === 'top') {
|
|
||||||
position = isContainer ? 'in' : 'bottom';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//如果是容器组件,且包含有子组件,且是in状态,进行智能识别处理;
|
|
||||||
let subChildren = [];
|
|
||||||
const getChildren = (node) => {
|
|
||||||
if (!node || !node.childNodes || node.childNodes.length === 0) return;
|
|
||||||
node.childNodes.forEach((child) => {
|
|
||||||
if (child === sourceTarget) return;
|
|
||||||
if (child && child.getAttribute && child.getAttribute('draggable')) {
|
|
||||||
const isInline = ['inline', 'inline-block'].includes(getComputedStyle(child).display) && sourceIsInline;
|
|
||||||
const rect = child.getBoundingClientRect();
|
|
||||||
const l = Math.abs(ev.clientX - rect.left);
|
|
||||||
const r = Math.abs(ev.clientX - rect.right);
|
|
||||||
const t = Math.abs(ev.clientY - rect.top);
|
|
||||||
const b = Math.abs(ev.clientY - rect.bottom);
|
|
||||||
const minXDistance = Math.min(l, r);
|
|
||||||
const minYDistance = Math.min(t, b);
|
|
||||||
subChildren.push({
|
|
||||||
lunaKey: child.dataset.lunaKey,
|
|
||||||
node: child,
|
|
||||||
minDistance: isInline ? [minXDistance, minYDistance] : [minYDistance, minXDistance],
|
|
||||||
position: isInline ? (l > r ? 'right' : 'left') : b > t ? 'top' : 'bottom',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
getChildren(child);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (position === 'in' && isContainer && !isSupportIn) {
|
|
||||||
getChildren(target);
|
|
||||||
subChildren = subChildren.sort((a, b) => {
|
|
||||||
if (a.minDistance[0] === b.minDistance[0]) {
|
|
||||||
return a.minDistance[1] - b.minDistance[1];
|
|
||||||
}
|
|
||||||
return a.minDistance[0] - b.minDistance[0];
|
|
||||||
});
|
|
||||||
const tempChild = subChildren[0];
|
|
||||||
if (tempChild) {
|
|
||||||
if (sourceTarget === tempChild.node.nextElementSibling && ['bottom', 'right'].includes(tempChild.position))
|
|
||||||
return null;
|
|
||||||
if (sourceTarget === tempChild.node.previousElementSibling && ['top', 'left'].includes(tempChild.position))
|
|
||||||
return null;
|
|
||||||
position = tempChild.position;
|
|
||||||
entity = {
|
|
||||||
target: tempChild.node,
|
|
||||||
schema: this.appHelper.schemaHelper.schemaMap[tempChild.lunaKey],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const containrDom = position === 'in' ? entity.target : this.getLunaContainerDom(entity.target);
|
|
||||||
if (this.containrDom !== containrDom) {
|
|
||||||
if (this.containrDom) {
|
|
||||||
this.containrDom.style.outline = '';
|
|
||||||
}
|
|
||||||
this.containrDom = containrDom;
|
|
||||||
}
|
|
||||||
if (this.containrDom) {
|
|
||||||
containrDom.style.outline = '1px solid #1aab11';
|
|
||||||
}
|
|
||||||
// debug('drag info:', position, isSupportIn, isContainer, entity);
|
|
||||||
return {
|
|
||||||
position,
|
|
||||||
isSupportIn,
|
|
||||||
isContainer,
|
|
||||||
entity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getTreeDragInfo(ev, entity) {
|
|
||||||
if (!this.sourceEntity || !entity) return null;
|
|
||||||
const { schema, treeNodeTarget } = entity;
|
|
||||||
const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath;
|
|
||||||
const targetPath = schema.__ctx.lunaPath;
|
|
||||||
if (sourcePath === targetPath) return null;
|
|
||||||
if (targetPath && targetPath.startsWith(sourcePath)) return null;
|
|
||||||
const componentsMap = this.appHelper.get('componentsMap');
|
|
||||||
// if (!componentsMap || !componentsMap[schema.componentName]) return null;
|
|
||||||
let isContainer =
|
|
||||||
(componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件
|
|
||||||
if (schema.children && typeof schema.children !== 'object') {
|
|
||||||
//如果children是文本, 非模型结构,则非容器;
|
|
||||||
isContainer = false;
|
|
||||||
}
|
|
||||||
const rect = treeNodeTarget.getBoundingClientRect();
|
|
||||||
const isSupportIn =
|
|
||||||
isContainer &&
|
|
||||||
(!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children)));
|
|
||||||
|
|
||||||
const sn = isContainer && isSupportIn ? rect.height * 0.25 : rect.height * 0.5;
|
|
||||||
let position = 'in';
|
|
||||||
if (Math.abs(ev.clientY - rect.top) <= sn) {
|
|
||||||
position = 'top';
|
|
||||||
} else if (Math.abs(ev.clientY - rect.bottom) <= sn) {
|
|
||||||
position = 'bottom';
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
position,
|
|
||||||
isSupportIn,
|
|
||||||
isContainer,
|
|
||||||
entity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
addEffect(isTree) {
|
|
||||||
if (!this.tempEntity) return;
|
|
||||||
const { position } = this.dragInfo;
|
|
||||||
const { target, treeNodeTarget } = this.tempEntity;
|
|
||||||
// this.clearCompTreeEffect();
|
|
||||||
if (isTree) {
|
|
||||||
//画父元素外框
|
|
||||||
let status = true;
|
|
||||||
let node = treeNodeTarget.parentNode;
|
|
||||||
while (status) {
|
|
||||||
if (node && node.parentNode) {
|
|
||||||
if (node.parentNode.tagName == 'LI' && node.parentNode.classList.contains('next-tree-node')) {
|
|
||||||
status = false;
|
|
||||||
if (this.treeNodeTargetParent !== node.parentNode || position === 'in') {
|
|
||||||
this.treeNodeTargetParent && this.treeNodeTargetParent.classList.remove('selected');
|
|
||||||
}
|
|
||||||
this.treeNodeTargetParent = node.parentNode;
|
|
||||||
if (position !== 'in') this.treeNodeTargetParent.classList.add('selected');
|
|
||||||
} else {
|
|
||||||
node = node.parentNode;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
treeNodeTarget.appendChild(this.getTreeEffectDom());
|
|
||||||
this.treeEffectDom.className = position;
|
|
||||||
} else {
|
|
||||||
const effectDom = this.getCanvasEffectDom();
|
|
||||||
const rect = target.getBoundingClientRect();
|
|
||||||
effectDom.style.left = (position === 'right' ? rect.right : rect.left) + 'px';
|
|
||||||
effectDom.style.top =
|
|
||||||
(position === 'bottom' ? rect.bottom : position === 'in' ? (rect.top + rect.bottom) / 2 : rect.top) + 'px';
|
|
||||||
effectDom.style.height = ['top', 'in', 'bottom'].includes(position) ? '2px' : rect.height + 'px';
|
|
||||||
effectDom.style.width = ['left', 'right'].includes(position) ? '2px' : rect.width + 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearCanvasEffect() {
|
|
||||||
if (this.canvasEffectDom) {
|
|
||||||
this.canvasEffectDom.style.display = 'none';
|
|
||||||
}
|
|
||||||
if (this.containrDom) {
|
|
||||||
this.containrDom.style.outline = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTreeEffect() {
|
|
||||||
if (this.treeEffectDom) {
|
|
||||||
this.treeEffectDom.style.display = 'none';
|
|
||||||
}
|
|
||||||
if (this.treeNodeTargetParent) {
|
|
||||||
this.treeNodeTargetParent.classList.remove('selected');
|
|
||||||
}
|
|
||||||
const tempTarget = this.tempEntity && this.tempEntity.treeNodeTarget;
|
|
||||||
const classList = tempTarget && tempTarget.classList;
|
|
||||||
if (classList) {
|
|
||||||
classList.remove('top');
|
|
||||||
classList.remove('bottom');
|
|
||||||
classList.remove('in');
|
|
||||||
classList.remove('tree-item');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearEffect(isTree) {
|
|
||||||
if (this.isDragging) {
|
|
||||||
// if (isTree) {
|
|
||||||
if (this.treeClearTimer) {
|
|
||||||
clearTimeout(this.treeClearTimer);
|
|
||||||
this.treeClearTimer = null;
|
|
||||||
}
|
|
||||||
this.treeClearTimer = setTimeout(() => {
|
|
||||||
this.clearTreeEffect();
|
|
||||||
}, 300);
|
|
||||||
// } else {
|
|
||||||
if (this.canvasClearTimer) {
|
|
||||||
clearTimeout(this.canvasClearTimer);
|
|
||||||
this.canvasClearTimer = null;
|
|
||||||
}
|
|
||||||
this.canvasClearTimer = setTimeout(() => {
|
|
||||||
this.clearCanvasEffect();
|
|
||||||
}, 300);
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
// if (isTree) {
|
|
||||||
this.clearTreeEffect();
|
|
||||||
// } else {
|
|
||||||
this.clearCanvasEffect();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragStart(ev, lunaKey) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
const target = ev.currentTarget;
|
|
||||||
target.style.filter = 'blur(2px)';
|
|
||||||
const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
|
|
||||||
ev.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0);
|
|
||||||
this.sourceEntity = {
|
|
||||||
target,
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
this.isDragging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragEnd(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
this.isDragging = false;
|
|
||||||
if (!this.sourceEntity) return;
|
|
||||||
if (this.sourceEntity.target) {
|
|
||||||
this.sourceEntity.target.style.filter = '';
|
|
||||||
}
|
|
||||||
this.clearEffect();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragOver(ev, lunaKey) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
this.isDragging = true;
|
|
||||||
const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
|
|
||||||
this.dragOverFunc(
|
|
||||||
{
|
|
||||||
clientX: ev.clientX,
|
|
||||||
clientY: ev.clientY,
|
|
||||||
currentTarget: ev.currentTarget,
|
|
||||||
},
|
|
||||||
schema,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDragLeave(ev) {
|
|
||||||
//避免移动到treeEffectDom上的抖动
|
|
||||||
ev.stopPropagation();
|
|
||||||
if (!this.tempEntity) return;
|
|
||||||
const rect = ev.target.getBoundingClientRect();
|
|
||||||
// 如果鼠标位置还在当前元素范围内则不认为是dragLeave
|
|
||||||
if (ev.x >= rect.left && ev.x <= rect.right && ev.y >= rect.top && ev.y <= rect.bottom) return;
|
|
||||||
debug('canvas drag leave', ev);
|
|
||||||
this.clearEffect();
|
|
||||||
this.dragInfo = null;
|
|
||||||
this.isDragging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDrop(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
debug('drop+++++');
|
|
||||||
this.isDragging = false;
|
|
||||||
this.changeCanvas();
|
|
||||||
this.clearEffect();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTreeDragStart(ev) {
|
|
||||||
const { event, node } = ev;
|
|
||||||
event.stopPropagation();
|
|
||||||
const lunaKey = node.props.eventKey;
|
|
||||||
const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
|
|
||||||
event.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0);
|
|
||||||
this.sourceEntity = this.getTreeEntity(node, event);
|
|
||||||
if (this.sourceEntity.target) {
|
|
||||||
this.sourceEntity.target.style.filter = 'blur(2px)';
|
|
||||||
}
|
|
||||||
this.isDragging = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTreeDragEnd(ev) {
|
|
||||||
const { event } = ev;
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
this.isDragging = false;
|
|
||||||
if (!this.sourceEntity) return;
|
|
||||||
if (this.sourceEntity.target) {
|
|
||||||
this.sourceEntity.target.style.filter = '';
|
|
||||||
}
|
|
||||||
this.clearEffect(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTreeDragOver(ev) {
|
|
||||||
const { event, node } = ev;
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.isDragging = true;
|
|
||||||
this.dragOverFunc(
|
|
||||||
{
|
|
||||||
clientX: event.clientX,
|
|
||||||
clientY: event.clientY,
|
|
||||||
currentTarget: event.currentTarget.children[0],
|
|
||||||
},
|
|
||||||
node,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTreeDragLeave(ev) {
|
|
||||||
const { event } = ev;
|
|
||||||
event.stopPropagation();
|
|
||||||
if (!this.tempEntity) return;
|
|
||||||
//避免移动到treeEffectDom上的抖动
|
|
||||||
if (this.treeEffectDom && this.treeEffectDom.parentNode.parentNode === event.currentTarget) return;
|
|
||||||
debug('++++ drag leave tree', ev, this.isDragging);
|
|
||||||
this.clearEffect(true);
|
|
||||||
this.isDragging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleTreeDrop(ev) {
|
|
||||||
const { event } = ev;
|
|
||||||
event.stopPropagation();
|
|
||||||
this.isDragging = false;
|
|
||||||
this.changeCanvas();
|
|
||||||
this.clearEffect(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleResourceDragStart(ev, title, schema) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.dataTransfer.setDragImage(this.getDragTagDom(title), -2, -2);
|
|
||||||
this.sourceEntity = {
|
|
||||||
isAdd: true,
|
|
||||||
schema,
|
|
||||||
};
|
|
||||||
this.isDragging = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
import EventEmitter from 'events';
|
|
||||||
import Debug from 'debug';
|
|
||||||
const debug = Debug('utils:postMessager');
|
|
||||||
EventEmitter.defaultMaxListeners = 100;
|
|
||||||
|
|
||||||
export class InnerMessager extends EventEmitter {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.handleReceive = this.handleReceive.bind(this);
|
|
||||||
window.addEventListener('message', this.handleReceive, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg(type, data, targetOrigin = '*') {
|
|
||||||
window.parent &&
|
|
||||||
window.parent.postMessage(
|
|
||||||
{
|
|
||||||
type,
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
targetOrigin,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleReceive(e) {
|
|
||||||
if (!e.data || !e.data.type) return;
|
|
||||||
this.emit(e.data.type, e.data.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
window.removeEventListener('message', this.handleReceive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class OuterMessager extends EventEmitter {
|
|
||||||
constructor(innerWindow) {
|
|
||||||
super();
|
|
||||||
this.innerWindow = innerWindow;
|
|
||||||
this.handleReceive = this.handleReceive.bind(this);
|
|
||||||
window.addEventListener('message', this.handleReceive, false);
|
|
||||||
}
|
|
||||||
sendMsg(type, data, targetOrigin = '*') {
|
|
||||||
this.innerWindow &&
|
|
||||||
this.innerWindow.postMessage(
|
|
||||||
{
|
|
||||||
type,
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
targetOrigin,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleReceive(e) {
|
|
||||||
if (!e.data || !e.data.type) return;
|
|
||||||
this.emit(e.data.type, e.data.data);
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
window.removeEventListener('message', this.handleReceive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
482
packages/react-renderer/src/utils/schemaHelper.js
vendored
482
packages/react-renderer/src/utils/schemaHelper.js
vendored
@ -1,482 +0,0 @@
|
|||||||
import { forEach } from '@ali/b3-one/lib/obj';
|
|
||||||
import {
|
|
||||||
clone,
|
|
||||||
fastClone,
|
|
||||||
jsonuri,
|
|
||||||
isSchema,
|
|
||||||
isFileSchema,
|
|
||||||
isJSFunction,
|
|
||||||
isJSExpression,
|
|
||||||
parseObj,
|
|
||||||
transformSchemaToPure,
|
|
||||||
transformSchemaToStandard,
|
|
||||||
isEmpty,
|
|
||||||
moveArrayItem,
|
|
||||||
serialize,
|
|
||||||
deepEqual,
|
|
||||||
} from './index';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import compFactory from '../hoc/compFactory';
|
|
||||||
const debug = Debug('utils:schemaHelper');
|
|
||||||
let keyIndex = 0;
|
|
||||||
export default class SchemaHelper {
|
|
||||||
constructor(schema, appHelper) {
|
|
||||||
this.appHelper = appHelper;
|
|
||||||
this.reset(schema, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
reset(schema, isInit) {
|
|
||||||
debug('start reset');
|
|
||||||
this.emit('schemaHelper.schema.beforeReset');
|
|
||||||
this.schemaMap = {};
|
|
||||||
this.blockSchemaMap = {};
|
|
||||||
this.compThisMap = {};
|
|
||||||
this.blockTree = {};
|
|
||||||
this.compTreeMap = {};
|
|
||||||
this.compCtxMap = {};
|
|
||||||
this.rebuild(schema, isInit);
|
|
||||||
this.emit('schemaHelper.schema.afterReset');
|
|
||||||
}
|
|
||||||
|
|
||||||
add(schema, targetKey, direction) {
|
|
||||||
this.emit('schemaHelper.material.beforeAdd');
|
|
||||||
const targetSchema = this.schemaMap[targetKey];
|
|
||||||
if (isEmpty(schema) || !targetSchema) return;
|
|
||||||
let targetPath = targetSchema.__ctx.lunaPath;
|
|
||||||
if (targetPath === '' && direction !== 'in') {
|
|
||||||
console.warn('add error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let newSchema = [];
|
|
||||||
if (Array.isArray(schema)) {
|
|
||||||
newSchema = schema.filter((item) => isSchema(item, true));
|
|
||||||
} else if (isSchema(schema)) {
|
|
||||||
newSchema = [schema];
|
|
||||||
} else {
|
|
||||||
console.error('模型结构异常');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (direction === 'in') {
|
|
||||||
const targetNode = jsonuri.get(this.schema, targetPath);
|
|
||||||
targetNode.children = (targetNode.children || []).concat(newSchema);
|
|
||||||
//jsonuri.set(this.schema, targetPath, targetNode);
|
|
||||||
} else {
|
|
||||||
direction = ['left', 'top'].includes(direction) ? 'before' : 'after';
|
|
||||||
newSchema.reverse().forEach((item) => {
|
|
||||||
jsonuri.insert(this.schema, targetPath, item, direction);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const addKey = `luna_${keyIndex + 1}`;
|
|
||||||
this.rebuild(this.schema);
|
|
||||||
this.emit('schemaHelper.material.afterAdd', addKey);
|
|
||||||
return addKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(lunaKey) {
|
|
||||||
this.emit('schemaHelper.material.beforeRemove');
|
|
||||||
const schema = this.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
const lunaPath = schema.__ctx.lunaPath;
|
|
||||||
if (lunaPath === '') {
|
|
||||||
console.warn('root node can not be removed');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonuri.rm(this.schema, lunaPath);
|
|
||||||
delete this.schemaMap[lunaKey];
|
|
||||||
delete this.blockSchemaMap[lunaKey];
|
|
||||||
this.rebuild(this.schema);
|
|
||||||
this.emit('schemaHelper.material.afterRemove');
|
|
||||||
}
|
|
||||||
|
|
||||||
move(lunaKey, targetKey, direction) {
|
|
||||||
this.emit('schemaHelper.material.beforeMove');
|
|
||||||
debug('start move');
|
|
||||||
const schema = this.schemaMap[lunaKey];
|
|
||||||
const targetSchema = this.schemaMap[targetKey];
|
|
||||||
if (!schema || !targetSchema) return;
|
|
||||||
let lunaPath = schema.__ctx.lunaPath;
|
|
||||||
let targetPath = targetSchema.__ctx.lunaPath;
|
|
||||||
if (lunaPath === '' || (targetPath === '' && direction !== 'in')) {
|
|
||||||
console.warn('move error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const res = /(.*)\/(\d+)$/.exec(lunaPath);
|
|
||||||
const prefix = res && res[1];
|
|
||||||
const attr = res && res[2];
|
|
||||||
if (!prefix || !attr) {
|
|
||||||
console.warn('异常结构');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const sourceIdx = parseInt(attr);
|
|
||||||
const reg = new RegExp(`^${prefix}/(\\d+)$`);
|
|
||||||
const regRes = reg.exec(targetPath);
|
|
||||||
const sourceParent = jsonuri.get(this.schema, prefix);
|
|
||||||
direction = direction === 'in' ? 'in' : ['left', 'top'].includes(direction) ? 'before' : 'after';
|
|
||||||
if (regRes && regRes[1] && direction !== 'in') {
|
|
||||||
const distIdx = parseInt(regRes[1]);
|
|
||||||
moveArrayItem(sourceParent, sourceIdx, distIdx, direction);
|
|
||||||
} else {
|
|
||||||
if (direction === 'in') {
|
|
||||||
const targetNode = jsonuri.get(this.schema, targetPath);
|
|
||||||
targetNode.children = targetNode.children || [];
|
|
||||||
if (Array.isArray(targetNode.children)) {
|
|
||||||
targetNode.children.push(schema);
|
|
||||||
}
|
|
||||||
jsonuri.set(this.schema, targetPath, targetNode);
|
|
||||||
} else {
|
|
||||||
jsonuri.insert(this.schema, targetPath, schema, direction);
|
|
||||||
}
|
|
||||||
sourceParent.splice(sourceIdx, 1);
|
|
||||||
}
|
|
||||||
this.rebuild(this.schema);
|
|
||||||
this.emit('schemaHelper.material.afterMove');
|
|
||||||
}
|
|
||||||
|
|
||||||
//组件上移 下移
|
|
||||||
// direction 取值 down/up
|
|
||||||
slide(lunaKey, direction) {
|
|
||||||
const schema = this.schemaMap[lunaKey];
|
|
||||||
if (!schema || !direction) return;
|
|
||||||
const lunaPath = schema.__ctx && schema.__ctx.lunaPath;
|
|
||||||
if (!lunaPath) return;
|
|
||||||
if (direction === 'up' && lunaPath.endsWith('/0')) return;
|
|
||||||
const targetPath = lunaPath.replace(/\/(\d+)$/, (res, idx) => {
|
|
||||||
return `/${direction === 'down' ? parseInt(idx) + 1 : parseInt(idx) - 1}`;
|
|
||||||
});
|
|
||||||
const targetSchema = this.getSchemaByPath(targetPath);
|
|
||||||
const targetKey = targetSchema && targetSchema.__ctx && targetSchema.__ctx.lunaKey;
|
|
||||||
if (!targetKey) return;
|
|
||||||
this.move(lunaKey, targetKey, direction === 'down' ? 'bottom' : 'top');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 快速复制
|
|
||||||
copy(lunaKey) {
|
|
||||||
this.emit('schemaHelper.material.beforeCopy');
|
|
||||||
const schema = this.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
const newSchema = transformSchemaToPure(fastClone(schema));
|
|
||||||
delete newSchema.__ctx;
|
|
||||||
const addKey = this.add(newSchema, schema.__ctx.lunaKey, 'bottom');
|
|
||||||
this.emit('schemaHelper.material.afterCopy', addKey);
|
|
||||||
return addKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(lunaKey, props) {
|
|
||||||
this.emit('schemaHelper.material.beforeUpdate');
|
|
||||||
const schema = this.schemaMap[lunaKey];
|
|
||||||
if (!schema) return;
|
|
||||||
const {
|
|
||||||
__state,
|
|
||||||
__defaultProps,
|
|
||||||
__fileName,
|
|
||||||
__scss,
|
|
||||||
__loop,
|
|
||||||
__loopArgs,
|
|
||||||
__condition,
|
|
||||||
__lifeCycles,
|
|
||||||
__methods,
|
|
||||||
__dataSource,
|
|
||||||
children,
|
|
||||||
...otherProps
|
|
||||||
} = props;
|
|
||||||
debug('update props', props);
|
|
||||||
|
|
||||||
//自定义组件才处理defaultProps
|
|
||||||
if (schema.componentName === 'Component' && '__defaultProps' in props) {
|
|
||||||
if (!__defaultProps || typeof __defaultProps !== 'object' || isEmpty(__defaultProps)) {
|
|
||||||
delete schema.defaultProps;
|
|
||||||
} else {
|
|
||||||
schema.defaultProps = __defaultProps;
|
|
||||||
}
|
|
||||||
this.appHelper.components[schema.fileName.replace(/^\w/, (a) => a.toUpperCase())] = compFactory(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果loop值没有设置有效值,则删除schema中这个的字段
|
|
||||||
if ('__loop' in props) {
|
|
||||||
if (!__loop || isEmpty(__loop)) {
|
|
||||||
delete schema.loop;
|
|
||||||
} else {
|
|
||||||
schema.loop = __loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 指定循环上下文变量名
|
|
||||||
if ('__loopArgs' in props) {
|
|
||||||
if (
|
|
||||||
__loopArgs === undefined ||
|
|
||||||
(typeof __loopArgs === 'object' && isEmpty(__loopArgs)) ||
|
|
||||||
!Array.isArray(__loopArgs) ||
|
|
||||||
__loopArgs.every((item) => !item)
|
|
||||||
) {
|
|
||||||
delete schema.loopArgs;
|
|
||||||
} else {
|
|
||||||
schema.loopArgs = __loopArgs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断条件
|
|
||||||
if ('__condition' in props) {
|
|
||||||
if (__condition === undefined) {
|
|
||||||
delete schema.condition;
|
|
||||||
} else {
|
|
||||||
schema.condition = __condition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理容器类组件需要考虑的字段
|
|
||||||
if (isFileSchema(schema)) {
|
|
||||||
// filename
|
|
||||||
if ('__fileName' in props) {
|
|
||||||
schema.fileName = __fileName;
|
|
||||||
}
|
|
||||||
// state
|
|
||||||
if ('__state' in props) {
|
|
||||||
// 重走生命周期
|
|
||||||
schema.__ctx && ++schema.__ctx.idx;
|
|
||||||
if (!__state || typeof __state !== 'object' || isEmpty(__state)) {
|
|
||||||
delete schema.state;
|
|
||||||
} else {
|
|
||||||
schema.state = __state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 生命周期
|
|
||||||
if ('__lifeCycles' in props) {
|
|
||||||
if (!__lifeCycles || typeof __lifeCycles !== 'object' || isEmpty(__lifeCycles)) {
|
|
||||||
delete schema.lifeCycles;
|
|
||||||
} else {
|
|
||||||
schema.lifeCycles = __lifeCycles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 自定义方法
|
|
||||||
if ('__methods' in props) {
|
|
||||||
if (!__methods || typeof __methods !== 'object' || isEmpty(__methods)) {
|
|
||||||
delete schema.methods;
|
|
||||||
} else {
|
|
||||||
schema.methods = __methods;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数据源设置
|
|
||||||
if ('__dataSource' in props) {
|
|
||||||
if (this.needContainerReload(schema.dataSource, __dataSource)) {
|
|
||||||
schema.__ctx && ++schema.__ctx.idx;
|
|
||||||
}
|
|
||||||
if (__dataSource === undefined || (typeof __dataSource === 'object' && isEmpty(__dataSource))) {
|
|
||||||
delete schema.dataSource;
|
|
||||||
} else {
|
|
||||||
schema.dataSource = __dataSource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果scss值没有设置有效值,则删除schema中这个的字段
|
|
||||||
if ('__scss' in props) {
|
|
||||||
if (!__scss) {
|
|
||||||
delete schema.scss;
|
|
||||||
} else {
|
|
||||||
schema.scss = __scss;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 子组件
|
|
||||||
if ('children' in props) {
|
|
||||||
if (children === undefined || (typeof children === 'object' && isEmpty(children))) {
|
|
||||||
delete schema.children;
|
|
||||||
} else {
|
|
||||||
schema.children = children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
schema.props = {
|
|
||||||
...schema.props,
|
|
||||||
...otherProps,
|
|
||||||
};
|
|
||||||
|
|
||||||
//过滤undefined属性
|
|
||||||
Object.keys(schema.props).map((key) => {
|
|
||||||
if (schema.props[key] === undefined) {
|
|
||||||
delete schema.props[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rebuild(this.schema);
|
|
||||||
this.emit('schemaHelper.material.afterUpdate');
|
|
||||||
}
|
|
||||||
|
|
||||||
createSchema(componentName, props, isContainer) {
|
|
||||||
const schema = {
|
|
||||||
componentName,
|
|
||||||
props: props || {},
|
|
||||||
__ctx: {
|
|
||||||
lunaKey: ++this.lunaKey,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (isContainer) {
|
|
||||||
schema.children = [];
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuild(schema, isInit) {
|
|
||||||
if (!isFileSchema(schema)) {
|
|
||||||
debug('top schema should be a file type');
|
|
||||||
//对于null的schema特殊处理一下
|
|
||||||
if (schema === null) {
|
|
||||||
this.schema = schema;
|
|
||||||
this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.blockTree = null;
|
|
||||||
this.compTreeMap = {};
|
|
||||||
this.compTree = null;
|
|
||||||
this.schemaMap = {};
|
|
||||||
this.blockSchemaMap = {};
|
|
||||||
this.compCtxMap = {};
|
|
||||||
const buildSchema = (schema, parentBlockNode, parentCompNode, path = '') => {
|
|
||||||
if (Array.isArray(schema)) {
|
|
||||||
return schema.map((item, idx) => buildSchema(item, parentBlockNode, parentCompNode, `${path}/${idx}`));
|
|
||||||
} else if (typeof schema === 'object') {
|
|
||||||
// 对于undefined及null直接返回
|
|
||||||
if (!schema) return schema;
|
|
||||||
//JSFunction转函数
|
|
||||||
if (isJSFunction(schema)) {
|
|
||||||
if (typeof schema.value === 'string') {
|
|
||||||
let tarFun = parseObj(schema.value);
|
|
||||||
if (typeof tarFun === 'function') {
|
|
||||||
return tarFun;
|
|
||||||
}
|
|
||||||
} else if (typeof schema.value === 'function') {
|
|
||||||
return schema.value;
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
//如果是对象且是JSExpression
|
|
||||||
if (isJSExpression(schema)) {
|
|
||||||
return '{{' + schema.value + '}}';
|
|
||||||
}
|
|
||||||
const res = {};
|
|
||||||
if (isSchema(schema)) {
|
|
||||||
res.__ctx = schema.__ctx;
|
|
||||||
if (!res.__ctx) {
|
|
||||||
const lunaKey = `luna_${++keyIndex}`;
|
|
||||||
res.__ctx = {
|
|
||||||
idx: 0,
|
|
||||||
lunaKey,
|
|
||||||
lunaPath: path,
|
|
||||||
parentKey: parentCompNode && parentCompNode.lunaKey,
|
|
||||||
blockKey: parentBlockNode && parentBlockNode.lunaKey,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
res.__ctx.lunaPath = path;
|
|
||||||
}
|
|
||||||
const label = schema.componentName + (schema.fileName ? '-' + schema.fileName : '');
|
|
||||||
const lunaKey = res.__ctx && res.__ctx.lunaKey;
|
|
||||||
this.schemaMap[lunaKey] = res;
|
|
||||||
if (isFileSchema(schema)) {
|
|
||||||
this.blockSchemaMap[lunaKey] = res;
|
|
||||||
|
|
||||||
const blockNode = {
|
|
||||||
label,
|
|
||||||
lunaKey,
|
|
||||||
isFile: true,
|
|
||||||
children: [],
|
|
||||||
};
|
|
||||||
this.compTreeMap[lunaKey] = blockNode;
|
|
||||||
const compNode = clone(blockNode);
|
|
||||||
if (parentBlockNode) {
|
|
||||||
parentBlockNode.children.push(blockNode);
|
|
||||||
} else {
|
|
||||||
this.blockTree = blockNode;
|
|
||||||
}
|
|
||||||
parentBlockNode = blockNode;
|
|
||||||
if (parentCompNode) {
|
|
||||||
parentCompNode.children.push(compNode);
|
|
||||||
} else {
|
|
||||||
this.compTree = compNode;
|
|
||||||
}
|
|
||||||
parentCompNode = compNode;
|
|
||||||
} else {
|
|
||||||
const compNode = {
|
|
||||||
label,
|
|
||||||
lunaKey,
|
|
||||||
children: [],
|
|
||||||
};
|
|
||||||
parentCompNode.children.push(compNode);
|
|
||||||
parentCompNode = compNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
forEach(schema, (val, key) => {
|
|
||||||
if (key.startsWith('__')) {
|
|
||||||
res[key] = val;
|
|
||||||
} else {
|
|
||||||
res[key] = buildSchema(val, parentBlockNode, parentCompNode, `${path}/${key}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return schema;
|
|
||||||
};
|
|
||||||
this.emit(`schemaHelper.schema.${isInit ? 'beforeInit' : 'beforeUpdate'}`);
|
|
||||||
this.schema = buildSchema(schema);
|
|
||||||
this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
needContainerReload(preData = {}, nextData = {}) {
|
|
||||||
if (
|
|
||||||
typeof preData.dataHandler === 'function' &&
|
|
||||||
typeof nextData.dataHandler === 'function' &&
|
|
||||||
preData.dataHandler.toString() !== nextData.dataHandler.toString()
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
} else if (preData.dataHandler !== nextData.dataHandler) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return !deepEqual(
|
|
||||||
(preData.list || []).filter((item) => item.isInit),
|
|
||||||
(nextData.list || []).filter((item) => item.isInit),
|
|
||||||
(pre, next) => {
|
|
||||||
if (typeof pre === 'function' && next === 'function') {
|
|
||||||
return pre.toString() === next.toString();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(msg, ...args) {
|
|
||||||
this.appHelper && this.appHelper.emit(msg, ...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key) {
|
|
||||||
return this[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchemaByPath(path) {
|
|
||||||
return jsonuri.get(this.schema, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSchema() {
|
|
||||||
return this.schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPureSchema() {
|
|
||||||
return transformSchemaToPure(this.schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPureSchemaStr() {
|
|
||||||
return serialize(this.getPureSchema(), {
|
|
||||||
unsafe: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getStandardSchema() {
|
|
||||||
return transformSchemaToStandard(this.schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
getStandardSchemaStr() {
|
|
||||||
return serialize(this.getStandardSchema(), {
|
|
||||||
unsafe: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
import localforage from 'localforage';
|
|
||||||
import Debug from 'debug';
|
|
||||||
import { serialize } from './index';
|
|
||||||
|
|
||||||
const debug = Debug('utils:storageHelper');
|
|
||||||
export default class StorageHelper {
|
|
||||||
constructor(name) {
|
|
||||||
this.store = localforage.createInstance(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
getItem(key) {
|
|
||||||
if (!this.store) {
|
|
||||||
throw new Error('store instance not exist');
|
|
||||||
}
|
|
||||||
return this.store.getItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
setItem(key, value) {
|
|
||||||
if (!this.store) {
|
|
||||||
throw new Error('store instance not exist');
|
|
||||||
}
|
|
||||||
return this.store.setItem(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeItem(key) {
|
|
||||||
if (!this.store) {
|
|
||||||
throw new Error('store instance not exist');
|
|
||||||
}
|
|
||||||
return this.store.removeItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
if (!this.store) {
|
|
||||||
throw new Error('store instance not exist');
|
|
||||||
}
|
|
||||||
return this.store.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
addHistory(key, code, limit = 10) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
key = '__luna_history_' + key;
|
|
||||||
this.store
|
|
||||||
.getItem(key)
|
|
||||||
.then((res) => {
|
|
||||||
let codeStr = serialize(code, {
|
|
||||||
unsafe: true,
|
|
||||||
});
|
|
||||||
if (res && res[0] && res[0].code) {
|
|
||||||
if (codeStr === res[0].code) return;
|
|
||||||
}
|
|
||||||
res = res || [];
|
|
||||||
let newId = 1;
|
|
||||||
if (res && res[0] && res[0].id) {
|
|
||||||
newId = res[0].id + 1;
|
|
||||||
}
|
|
||||||
res.unshift({
|
|
||||||
id: newId,
|
|
||||||
time: +new Date(),
|
|
||||||
code: codeStr,
|
|
||||||
});
|
|
||||||
this.store
|
|
||||||
.setItem(key, res.slice(0, limit))
|
|
||||||
.then((res) => {
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getHistory(key) {
|
|
||||||
key = '__luna_history_' + key;
|
|
||||||
return this.store.getItem(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearHistory(key) {
|
|
||||||
key = '__luna_history_' + key;
|
|
||||||
this.store.removeItem(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
import Debug from 'debug';
|
|
||||||
import { fastClone } from './index';
|
|
||||||
const DEFAULT_CONFIG = {
|
|
||||||
limit: 20,
|
|
||||||
};
|
|
||||||
const debug = Debug('utils:undoRedoHelper');
|
|
||||||
export default class UndoRedoHelper {
|
|
||||||
constructor(config) {
|
|
||||||
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
||||||
this.data = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
create(key, value, forceCreate) {
|
|
||||||
if (!this.data[key] || forceCreate) {
|
|
||||||
this.data[key] = {
|
|
||||||
list: [fastClone(value)],
|
|
||||||
idx: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return this.data[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(key) {
|
|
||||||
delete this.data[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
resetRecord(key, value) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list) return;
|
|
||||||
data.list = data.list.slice(0, data.idx + 1);
|
|
||||||
data.list[data.idx] = fastClone(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
record(key, value) {
|
|
||||||
const data = this.data[key];
|
|
||||||
const limit = this.config.limit;
|
|
||||||
if (!data || !data.list) return;
|
|
||||||
data.list = data.list.slice(0, data.idx + 1);
|
|
||||||
if (data.list.length >= limit) {
|
|
||||||
data.list.shift();
|
|
||||||
}
|
|
||||||
data.list.push(fastClone(value));
|
|
||||||
++data.idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
undo(key) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list) return null;
|
|
||||||
//若没有前置操作,返回当前数据
|
|
||||||
if (data.idx <= 0) return data.list[data.idx];
|
|
||||||
--data.idx;
|
|
||||||
return data.list[data.idx];
|
|
||||||
}
|
|
||||||
redo(key) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list) return null;
|
|
||||||
//若没有后续操作,返回当前数据
|
|
||||||
if (data.idx >= data.list.length - 1) return data.list[data.idx];
|
|
||||||
++data.idx;
|
|
||||||
return data.list[data.idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
past(key) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list || data.idx <= 0) return null;
|
|
||||||
return data.list[data.idx - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
present(key) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list) return null;
|
|
||||||
return data.list[data.idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
future(key) {
|
|
||||||
const data = this.data[key];
|
|
||||||
if (!data || !data.list || data.idx >= data.list.length - 1) return null;
|
|
||||||
return data.list[data.idx + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key) {
|
|
||||||
return {
|
|
||||||
past: this.past(key),
|
|
||||||
present: this.present(key),
|
|
||||||
future: this.future(key),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
packages/react-renderer/src/utils/wsHelper.js
vendored
87
packages/react-renderer/src/utils/wsHelper.js
vendored
@ -1,87 +0,0 @@
|
|||||||
import Debug from 'debug';
|
|
||||||
import client from 'socket.io-client';
|
|
||||||
import { parseUrl } from '@ali/b3-one/lib/url';
|
|
||||||
const debug = Debug('utils:wsHelper');
|
|
||||||
|
|
||||||
export default class WSHelper {
|
|
||||||
constructor(appHelper, namespace, options) {
|
|
||||||
this.appHelper = appHelper;
|
|
||||||
this.ws = null;
|
|
||||||
this.init(namespace, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(namespace = '/', options = {}) {
|
|
||||||
if (this.ws) {
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
const urlInfo = parseUrl();
|
|
||||||
const ws = (this.ws = client(namespace, {
|
|
||||||
reconnectionDelay: 3000,
|
|
||||||
transports: ['websocket'],
|
|
||||||
query: urlInfo.params,
|
|
||||||
...options,
|
|
||||||
}));
|
|
||||||
const appHelper = this.appHelper;
|
|
||||||
debug('ws.init');
|
|
||||||
|
|
||||||
ws.on('connect', (msg) => {
|
|
||||||
appHelper.emit('wsHelper.connect.success', msg);
|
|
||||||
debug('ws.connect');
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('error', (msg) => {
|
|
||||||
appHelper.emit('wsHelper.connect.error', msg);
|
|
||||||
debug('ws.error', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('disconnect', (msg) => {
|
|
||||||
appHelper.emit('wsHelper.connect.break', msg);
|
|
||||||
debug('ws.disconnect', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('reconnecting', (msg) => {
|
|
||||||
appHelper.emit('wsHelper.connect.retry', msg);
|
|
||||||
debug('ws.reconnecting', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('ping', (msg) => {
|
|
||||||
debug('ws.ping', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('pong', (msg) => {
|
|
||||||
debug('ws.pong', msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.on('data', (msg) => {
|
|
||||||
appHelper.emit('wsHelper.data.receive', msg);
|
|
||||||
if (msg.eventName) {
|
|
||||||
appHelper.emit(`wsHelper.result.${msg.eventName}`, msg);
|
|
||||||
}
|
|
||||||
debug('ws.data', msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
if (!this.ws) return;
|
|
||||||
this.ws.close();
|
|
||||||
this.ws = null;
|
|
||||||
this.appHelper.emit('wsHelper.connect.close');
|
|
||||||
}
|
|
||||||
|
|
||||||
send(eventName, ...args) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
this.appHelper.emit('wsHelper.data.request', {
|
|
||||||
eventName,
|
|
||||||
params: args,
|
|
||||||
});
|
|
||||||
this.appHelper.once(`wsHelper.result.${eventName}`, resolve);
|
|
||||||
this.ws && this.ws.emit(eventName, ...args);
|
|
||||||
debug('ws.send', eventName);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('websocket error:', err);
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,5 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"build-plugin-component",
|
"build-plugin-component"
|
||||||
"build-plugin-fusion",
|
|
||||||
["build-plugin-moment-locales", {
|
|
||||||
"locales": ["zh-cn"]
|
|
||||||
}]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user