diff --git a/packages/editor/.eslintrc.js b/packages/editor/.eslintrc.js index 18ae6baa7..1c034b884 100644 --- a/packages/editor/.eslintrc.js +++ b/packages/editor/.eslintrc.js @@ -3,5 +3,6 @@ const { eslint, deepmerge } = require('@ice/spec'); module.exports = deepmerge(eslint, { rules: { "global-require": 0, + "interface-name" : [true, "never-prefix"] }, }); diff --git a/packages/editor/package.json b/packages/editor/package.json index 3ebc396ef..62c301598 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -8,8 +8,6 @@ "@alifd/next": "^1.x", "@alife/dpl-iceluna": "^2.3.2", "@icedesign/theme": "^1.x", - "@types/react": "^16.8.3", - "@types/react-dom": "^16.8.2", "events": "^3.1.0", "intl-messageformat": "^8.2.1", "keymaster": "^1.6.2", @@ -18,10 +16,13 @@ "react": "^16.8.1", "react-dom": "^16.8.1", "react-router-dom": "^5.1.2", + "serialize-javascript": "^3.0.0", "store": "^2.0.12" }, "devDependencies": { "@ice/spec": "^0.1.1", + "@types/react": "^16.8.3", + "@types/react-dom": "^16.8.2", "@types/debug": "^4.1.5", "@types/events": "^3.0.0", "@types/store": "^2.0.2", diff --git a/packages/editor/src/config/skeleton.js b/packages/editor/src/config/skeleton.js index 765aa6c10..d8bcd02a3 100644 --- a/packages/editor/src/config/skeleton.js +++ b/packages/editor/src/config/skeleton.js @@ -253,13 +253,15 @@ export default { pluginProps: {} } ], - centerArea: [{ - pluginKey: 'designer', - config: { - package: '@ali/lowcode-plugin-designer', - version: '1.0.0' + centerArea: [ + { + pluginKey: 'designer', + config: { + package: '@ali/lowcode-plugin-designer', + version: '1.0.0' + } } - }] + ] }, hooks: [], shortCuts: [] diff --git a/packages/editor/src/framework/areaManager.ts b/packages/editor/src/framework/areaManager.ts index 6dd029b45..ac7f1ed3c 100644 --- a/packages/editor/src/framework/areaManager.ts +++ b/packages/editor/src/framework/areaManager.ts @@ -1,16 +1,16 @@ -import Editor from './index'; import { PluginConfig, PluginStatus } from './definitions'; -import { clone, deepEqual, transformToPromise } from './utils'; +import Editor from './index'; +import { clone, deepEqual } from './utils'; export default class AreaManager { private pluginStatus: PluginStatus; - private config: Array; + private config: PluginConfig[]; constructor(private editor: Editor, private area: string) { this.config = (editor && editor.config && editor.config.plugins && editor.config.plugins[this.area]) || []; this.pluginStatus = clone(editor.pluginStatus); } - isPluginStatusUpdate(pluginType?: string): boolean { + public isPluginStatusUpdate(pluginType?: string): boolean { const { pluginStatus } = this.editor; const list = pluginType ? this.config.filter(item => item.type === pluginType) : this.config; @@ -19,14 +19,14 @@ export default class AreaManager { return isUpdate; } - getVisiblePluginList(pluginType?: string): Array { + public getVisiblePluginList(pluginType?: string): PluginConfig[] { const res = this.config.filter(item => { return !this.pluginStatus[item.pluginKey] || this.pluginStatus[item.pluginKey].visible; }); return pluginType ? res.filter(item => item.type === pluginType) : res; } - getPluginConfig(): Array { + public getPluginConfig(): PluginConfig[] { return this.config; } } diff --git a/packages/editor/src/framework/definitions.ts b/packages/editor/src/framework/definitions.ts index 5e30a4466..dd6cbfb0d 100644 --- a/packages/editor/src/framework/definitions.ts +++ b/packages/editor/src/framework/definitions.ts @@ -106,7 +106,7 @@ export interface I18nConfig { 'ja-JP'?: I18nMessages; } -export type I18nFunction = (key: string, params: object) => string; +export type I18nFunction = (key: string, params: any) => string; export interface Utils { [propName: string]: (...args) => any; @@ -124,9 +124,9 @@ export interface PluginComponents { export interface PluginStatus { [propName: string]: { - disabled: boolean; - visible: boolean; - marked: boolean; - locked: boolean; + disabled?: boolean; + visible?: boolean; + marked?: boolean; + locked?: boolean; }; } diff --git a/packages/editor/src/framework/editor.ts b/packages/editor/src/framework/editor.ts index 4918a4f4b..9fe46806a 100644 --- a/packages/editor/src/framework/editor.ts +++ b/packages/editor/src/framework/editor.ts @@ -1,9 +1,9 @@ -import EventEmitter from 'events'; import Debug from 'debug'; +import EventEmitter from 'events'; import store from 'store'; -import { EditorConfig, Utils, PluginComponents, PluginStatus, LocaleType, HooksConfig } from './definitions'; +import { EditorConfig, HooksConfig, LocaleType, PluginComponents, PluginStatus, Utils } from './definitions'; -import { unRegistShortCuts, registShortCuts, transformToPromise } from './utils'; +import { registShortCuts, transformToPromise, unRegistShortCuts } from './utils'; // 根据url参数设置debug选项 const res = /_?debug=(.*?)(&|$)/.exec(location.search); @@ -15,17 +15,19 @@ if (res && res[1]) { store.remove('debug'); } -//重要,用于矫正画布执行new Function的window对象上下文 +// 重要,用于矫正画布执行new Function的window对象上下文 window.__newFunc = funContext => { return new Function(funContext); }; -//关闭浏览器前提醒,只有产生过交互才会生效 +// 关闭浏览器前提醒,只有产生过交互才会生效 window.onbeforeunload = function(e) { e = e || window.event; // 本地调试不生效 - if (location.href.indexOf('localhost') > 0) return; - var msg = '您确定要离开此页面吗?'; + if (location.href.indexOf('localhost') > 0) { + return; + } + const msg = '您确定要离开此页面吗?'; e.cancelBubble = true; e.returnValue = msg; if (e.stopPropagation) { @@ -45,15 +47,13 @@ export interface HooksFuncs { } export default class Editor extends EventEmitter { - static getInstance = (config: EditorConfig, components: PluginComponents, utils?: Utils): Editor => { + public static getInstance = (config: EditorConfig, components: PluginComponents, utils?: Utils): Editor => { if (!instance) { instance = new Editor(config, components, utils); } return instance; }; - private hooksFuncs: HooksFuncs; - public pluginStatus: PluginStatus; public plugins: PluginComponents; public locale: LocaleType; @@ -63,13 +63,15 @@ export default class Editor extends EventEmitter { public once: (msg: string, handler: (...args) => void) => void; public off: (msg: string, handler: (...args) => void) => void; + private hooksFuncs: HooksFuncs; + constructor(public config: EditorConfig, public components: PluginComponents, public utils?: Utils) { super(); instance = this; this.init(); } - init(): Promise { + public init(): Promise { const { hooks, shortCuts = [], lifeCycles } = this.config || {}; this.locale = store.get('lowcode-editor-locale') || 'zh-CN'; // this.messages = this.messagesSet[this.locale]; @@ -92,24 +94,26 @@ export default class Editor extends EventEmitter { }); } - destroy() { + public destroy() { debug('destroy'); try { const { hooks = [], shortCuts = [], lifeCycles = {} } = this.config; unRegistShortCuts(shortCuts); this.destroyHooks(hooks); - lifeCycles.destroy && lifeCycles.destroy(this); + if (lifeCycles.destroy) { + lifeCycles.destroy(this); + } } catch (err) { console.warn(err); return; } } - get(key: string): any { + public get(key: string): any { return this[key]; } - set(key: string | object, val: any): void { + public set(key: string | object, val: any): void { if (typeof key === 'string') { if (['init', 'destroy', 'get', 'set', 'batchOn', 'batchOff', 'batchOnce'].includes(key)) { console.error('init, destroy, get, set, batchOn, batchOff, batchOnce is private attribute'); @@ -123,22 +127,28 @@ export default class Editor extends EventEmitter { } } - batchOn(events: Array, lisenter: (...args) => void): void { - if (!Array.isArray(events)) return; + public batchOn(events: string[], lisenter: (...args) => void): void { + if (!Array.isArray(events)) { + return; + } events.forEach(event => this.on(event, lisenter)); } - batchOnce(events: Array, lisenter: (...args) => void): void { - if (!Array.isArray(events)) return; + public batchOnce(events: string[], lisenter: (...args) => void): void { + if (!Array.isArray(events)) { + return; + } events.forEach(event => this.once(event, lisenter)); } - batchOff(events: Array, lisenter: (...args) => void): void { - if (!Array.isArray(events)) return; + public batchOff(events: string[], lisenter: (...args) => void): void { + if (!Array.isArray(events)) { + return; + } events.forEach(event => this.off(event, lisenter)); } - //销毁hooks中的消息监听 + // 销毁hooks中的消息监听 private destroyHooks(hooks: HooksConfig = []) { hooks.forEach((item, idx) => { if (typeof this.hooksFuncs[idx] === 'function') { @@ -148,7 +158,7 @@ export default class Editor extends EventEmitter { delete this.hooksFuncs; } - //初始化hooks中的消息监听 + // 初始化hooks中的消息监听 private initHooks(hooks: HooksConfig = []): void { this.hooksFuncs = hooks.map(item => { const func = (...args) => { @@ -162,10 +172,12 @@ export default class Editor extends EventEmitter { private initPluginStatus() { const { plugins = {} } = this.config; const pluginAreas = Object.keys(plugins); - const res = {}; + const res: PluginStatus = {}; pluginAreas.forEach(area => { (plugins[area] || []).forEach(plugin => { - if (plugin.type === 'Divider') return; + if (plugin.type === 'Divider') { + return; + } const { visible, disabled, marked } = plugin.props || {}; res[plugin.pluginKey] = { visible: typeof visible === 'boolean' ? visible : true, diff --git a/packages/editor/src/framework/pluginFactory.tsx b/packages/editor/src/framework/pluginFactory.tsx index b3a83ee83..dea2cd602 100644 --- a/packages/editor/src/framework/pluginFactory.tsx +++ b/packages/editor/src/framework/pluginFactory.tsx @@ -1,10 +1,9 @@ -import React, { PureComponent, createRef } from 'react'; +import React, { createRef, PureComponent } from 'react'; import EditorContext from './context'; +import { I18nFunction, PluginConfig } from './definitions'; import Editor from './editor'; -import { isEmpty, generateI18n, transformToPromise, acceptsRef } from './utils'; -import { PluginConfig, I18nFunction } from './definitions'; -import Editor from './index'; +import { acceptsRef, generateI18n, isEmpty, transformToPromise } from './utils'; export interface PluginProps { editor: Editor; @@ -19,12 +18,12 @@ export default function pluginFactory( Comp: React.ComponentType ): React.ComponentType { class LowcodePlugin extends PureComponent { - static displayName = 'LowcodeEditorPlugin'; - static defaultProps = { + public static displayName = 'LowcodeEditorPlugin'; + public static defaultProps = { config: {} }; - static contextType = EditorContext; - static init = Comp.init; + public static contextType = EditorContext; + public static init = Comp.init; public ref = createRef(); private editor: Editor; private pluginKey: string; @@ -47,28 +46,28 @@ export default function pluginFactory( }); } - componentWillUnmount() { + public componentWillUnmount() { // 销毁插件 if (this.editor && this.editor.plugins) { delete this.editor.plugins[this.pluginKey]; } } - open = (): Promise => { + public open = (): Promise => { if (this.ref && this.ref.open && typeof this.ref.open === 'function') { return transformToPromise(this.ref.open()); } return Promise.resolve(); }; - close = () => { + public close = () => { if (this.ref && this.ref.close && typeof this.ref.close === 'function') { return transformToPromise(this.ref.close()); } return Promise.resolve(); }; - render() { + public render() { const { config } = this.props; const props = { i18n: this.i18n, diff --git a/packages/editor/src/framework/utils.ts b/packages/editor/src/framework/utils.ts index d4a6e4061..794b0c9d3 100644 --- a/packages/editor/src/framework/utils.ts +++ b/packages/editor/src/framework/utils.ts @@ -1,14 +1,14 @@ import IntlMessageFormat from 'intl-messageformat'; import keymaster from 'keymaster'; -import { EditorConfig, LocaleType, I18nMessages, I18nFunction, ShortCutsConfig } from './definitions'; +import { EditorConfig, I18nFunction, I18nMessages, LocaleType, ShortCutsConfig } from './definitions'; import Editor from './editor'; -import _pick from 'lodash/pick'; -import _deepEqual from 'lodash/isEqualWith'; import _clone from 'lodash/cloneDeep'; -import _isEmpty from 'lodash/isEmpty'; -import _throttle from 'lodash/throttle'; import _debounce from 'lodash/debounce'; +import _isEmpty from 'lodash/isEmpty'; +import _deepEqual from 'lodash/isEqualWith'; +import _pick from 'lodash/pick'; +import _throttle from 'lodash/throttle'; export const pick = _pick; export const deepEqual = _deepEqual; @@ -36,22 +36,14 @@ export interface IDEMessageParams { }; } -export interface Window { - sendIDEMessage: (IDEMessageParams) => void; - goldlog: { - record: (logKey: string, gmKey: string, goKey: string, method: 'GET' | 'POST') => void; - }; - parent: Window; - is_theia: boolean; - vscode: boolean; -} - -/** +/* * 用于构造国际化字符串处理函数 */ export function generateI18n(locale: LocaleType = 'zh-CN', messages: I18nMessages = {}): I18nFunction { - return (key, values = {}) => { - if (!messages || !messages[key]) return ''; + return (key: string, values): string => { + if (!messages || !messages[key]) { + return ''; + } const formater = new IntlMessageFormat(messages[key], locale); return formater.format(values); }; @@ -61,10 +53,14 @@ export function generateI18n(locale: LocaleType = 'zh-CN', messages: I18nMessage * 序列化参数 */ export function serializeParams(obj: object): string { - if (typeof obj !== 'object') return ''; - const res: Array = []; + if (typeof obj !== 'object') { + return ''; + } + const res: string[] = []; Object.entries(obj).forEach(([key, val]) => { - if (val === null || val === undefined || val === '') return; + if (val === null || val === undefined || val === '') { + return; + } if (typeof val === 'object') { res.push(`${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(val))}`); } else { @@ -81,8 +77,7 @@ export function serializeParams(obj: object): string { * @param {String} logKey 属性串 */ export function goldlog(gmKey: string, params: object = {}, logKey: string = 'other'): void { - const global = window as Window; - const sendIDEMessage = global.sendIDEMessage || global.parent.sendIDEMessage; + const sendIDEMessage = window.sendIDEMessage || window.parent.sendIDEMessage; const goKey = serializeParams({ env: getEnv(), ...params @@ -97,7 +92,9 @@ export function goldlog(gmKey: string, params: object = {}, logKey: string = 'ot } }); } - global.goldlog && global.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST'); + if (window.goldlog) { + window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST'); + } } /** @@ -106,9 +103,13 @@ export function goldlog(gmKey: string, params: object = {}, logKey: string = 'ot export function getEnv(): string { const userAgent = navigator.userAgent; const isVscode = /Electron\//.test(userAgent); - if (isVscode) return ENV.VSCODE; + if (isVscode) { + return ENV.VSCODE; + } const isTheia = window.is_theia === true; - if (isTheia) return ENV.WEBIDE; + if (isTheia) { + return ENV.WEBIDE; + } return ENV.WEB; } @@ -137,7 +138,9 @@ export function unRegistShortCuts(config: ShortCutsConfig): void { * 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve */ export function transformToPromise(input: any): Promise<{}> { - if (input instanceof Promise) return input; + if (input instanceof Promise) { + return input; + } return new Promise((resolve, reject) => { if (input || input === undefined) { resolve(); @@ -153,13 +156,19 @@ export function transformToPromise(input: any): Promise<{}> { interface MapOf { [propName: string]: T; } -export function transformArrayToMap(arr: Array, key: string, overwrite: boolean = true): MapOf { - if (isEmpty(arr) || !Array.isArray(arr)) return {}; +export function transformArrayToMap(arr: T[], key: string, overwrite: boolean = true): MapOf { + if (isEmpty(arr) || !Array.isArray(arr)) { + return {}; + } const res = {}; arr.forEach(item => { const curKey = item[key]; - if (item[key] === undefined) return; - if (res[curKey] && !overwrite) return; + if (item[key] === undefined) { + return; + } + if (res[curKey] && !overwrite) { + return; + } res[curKey] = item; }); return res; @@ -172,16 +181,18 @@ interface Query { [propName: string]: string; } export function parseSearch(search: string): Query { - if (!search || typeof search !== 'string') return {}; + if (!search || typeof search !== 'string') { + return {}; + } const str = search.replace(/^\?/, ''); - let paramStr = str.split('&'); - let res = {}; - for (let i = 0; i < paramStr.length; i++) { - let regRes = paramStr[i].split('='); + const paramStr = str.split('&'); + const res = {}; + paramStr.forEach(item => { + const regRes = item.split('='); if (regRes[0] && regRes[1]) { res[regRes[0]] = decodeURIComponent(regRes[1]); } - } + }); return res; } @@ -238,8 +249,8 @@ export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig * @param {*} Comp 需要判断的组件 */ export function acceptsRef(Comp: React.ComponentType) { - const hasSymbol = typeof Symbol === 'function' && Symbol['for']; - const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol['for']('react.forward_ref') : 0xead0; + const hasSymbol = typeof Symbol === 'function' && Symbol.for; + const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; return ( (Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent) ); diff --git a/packages/editor/src/index.d.ts b/packages/editor/src/index.d.ts new file mode 100644 index 000000000..1fe34f40d --- /dev/null +++ b/packages/editor/src/index.d.ts @@ -0,0 +1,8 @@ +interface Window { + sendIDEMessage?: (IDEMessageParams) => void; + goldlog?: { + record: (logKey: string, gmKey: string, goKey: string, method: 'GET' | 'POST') => void; + }; + is_theia?: boolean; + vscode?: boolean; +} diff --git a/packages/editor/src/plugins/designer/index.scss b/packages/editor/src/plugins/designer/index.scss index 0d512ea9a..1c03f5a94 100644 --- a/packages/editor/src/plugins/designer/index.scss +++ b/packages/editor/src/plugins/designer/index.scss @@ -2,4 +2,4 @@ background-color: #ffffff; width: 100%; height: 100%; -} \ No newline at end of file +} diff --git a/packages/editor/src/plugins/designer/index.tsx b/packages/editor/src/plugins/designer/index.tsx index 6b5960548..9997c4b7b 100644 --- a/packages/editor/src/plugins/designer/index.tsx +++ b/packages/editor/src/plugins/designer/index.tsx @@ -190,7 +190,7 @@ export default class DesignerPlugin extends PureComponent { id: 'next', level: 2 } - ], + ] // simulatorUrl: ['/statics/simulator-renderer.css', '/statics/simulator-renderer.js'] }} /> diff --git a/packages/editor/src/plugins/undoRedo/index.tsx b/packages/editor/src/plugins/undoRedo/index.tsx index 2b1a47460..d5af0badf 100644 --- a/packages/editor/src/plugins/undoRedo/index.tsx +++ b/packages/editor/src/plugins/undoRedo/index.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, { useState } from 'react'; import './index.scss'; import Editor from '../../framework/index'; import { PluginConfig } from '../../framework/definitions';