mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-14 13:03:07 +00:00
daily tag
This commit is contained in:
parent
c9d139bf30
commit
baa6adb199
4
packages/editor/.prettierrc
Normal file
4
packages/editor/.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"singleQuote": true
|
||||
}
|
||||
@ -8,15 +8,21 @@
|
||||
"@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",
|
||||
"moment": "^2.23.0",
|
||||
"prop-types": "^15.5.8",
|
||||
"react": "^16.4.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-router-dom": "^5.1.2"
|
||||
"react": "^16.8.1",
|
||||
"react-dom": "^16.8.1",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"store": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ice/spec": "^0.1.1",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/events": "^3.0.0",
|
||||
"@types/store": "^2.0.2",
|
||||
"css-modules-typescript-loader": "^2.0.4",
|
||||
"eslint": "^6.0.1",
|
||||
"ice-plugin-fusion": "^0.1.4",
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import topBalloonIcon from '@ali/iceluna-addon-2';
|
||||
import topDialogIcon from '@ali/iceluna-addon-2';
|
||||
import leftPanelIcon from '@ali/iceluna-addon-2';
|
||||
@ -15,10 +14,10 @@ export default {
|
||||
topBalloonIcon: PluginFactory(topBalloonIcon),
|
||||
topDialogIcon: PluginFactory(topDialogIcon),
|
||||
leftPanelIcon: PluginFactory(leftPanelIcon),
|
||||
leftBalloonIcon:PluginFactory(leftBalloonIcon),
|
||||
leftDialogIcon:PluginFactory(leftDialogIcon),
|
||||
rightPanel1:PluginFactory(rightPanel1),
|
||||
rightPanel2:PluginFactory(rightPanel2),
|
||||
leftBalloonIcon: PluginFactory(leftBalloonIcon),
|
||||
leftDialogIcon: PluginFactory(leftDialogIcon),
|
||||
rightPanel1: PluginFactory(rightPanel1),
|
||||
rightPanel2: PluginFactory(rightPanel2),
|
||||
rightPanel3: PluginFactory(rightPanel3),
|
||||
rightPanel4: PluginFactory(rightPanel4),
|
||||
rightPanel4: PluginFactory(rightPanel4)
|
||||
};
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export default {
|
||||
namespace: 'page',
|
||||
namespace: 'page'
|
||||
};
|
||||
|
||||
@ -6,5 +6,5 @@ export default {
|
||||
'en-US': en_us,
|
||||
'zh-CN': zh_cn,
|
||||
'zh-TW': zh_tw,
|
||||
'ja-JP': ja_jp,
|
||||
'ja-JP': ja_jp
|
||||
};
|
||||
|
||||
@ -3,12 +3,12 @@ export default {
|
||||
theme: {
|
||||
dpl: {
|
||||
package: '@alife/dpl-iceluna',
|
||||
version: '^2.3.0',
|
||||
version: '^2.3.0'
|
||||
},
|
||||
scss: '',
|
||||
scss: ''
|
||||
},
|
||||
constants: {
|
||||
namespace: 'page',
|
||||
namespace: 'page'
|
||||
},
|
||||
utils: [],
|
||||
plugins: {
|
||||
@ -21,21 +21,21 @@ export default {
|
||||
title: 'balloon',
|
||||
icon: 'dengpao',
|
||||
balloonProps: {
|
||||
triggerType: 'click',
|
||||
},
|
||||
triggerType: 'click'
|
||||
}
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'divider',
|
||||
type: 'Divider',
|
||||
props: {
|
||||
align: 'left',
|
||||
},
|
||||
align: 'left'
|
||||
}
|
||||
},
|
||||
{
|
||||
pluginKey: 'topDialogIcon',
|
||||
@ -43,13 +43,13 @@ export default {
|
||||
props: {
|
||||
align: 'left',
|
||||
title: 'dialog',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'topLinkIcon',
|
||||
@ -60,11 +60,11 @@ export default {
|
||||
icon: 'dengpao',
|
||||
linkProps: {
|
||||
href: '//www.taobao.com',
|
||||
target: 'blank',
|
||||
},
|
||||
target: 'blank'
|
||||
}
|
||||
},
|
||||
config: {},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'topIcon',
|
||||
@ -75,11 +75,11 @@ export default {
|
||||
icon: 'dengpao',
|
||||
onClick: function(editor) {
|
||||
alert('icon addon invoke, current activeKey: ' + editor.activeKey);
|
||||
},
|
||||
}
|
||||
},
|
||||
config: {},
|
||||
pluginProps: {},
|
||||
},
|
||||
pluginProps: {}
|
||||
}
|
||||
],
|
||||
leftArea: [
|
||||
{
|
||||
@ -88,13 +88,13 @@ export default {
|
||||
props: {
|
||||
align: 'top',
|
||||
title: 'panel',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'leftBalloonIcon',
|
||||
@ -102,13 +102,13 @@ export default {
|
||||
props: {
|
||||
align: 'top',
|
||||
title: 'balloon',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'leftDialogIcon',
|
||||
@ -116,13 +116,13 @@ export default {
|
||||
props: {
|
||||
align: 'bottom',
|
||||
title: 'dialog',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'leftLinkIcon',
|
||||
@ -133,11 +133,11 @@ export default {
|
||||
icon: 'dengpao',
|
||||
linkProps: {
|
||||
href: '//www.taobao.com',
|
||||
target: 'blank',
|
||||
},
|
||||
target: 'blank'
|
||||
}
|
||||
},
|
||||
config: {},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'leftIcon',
|
||||
@ -148,11 +148,11 @@ export default {
|
||||
icon: 'dengpao',
|
||||
onClick: function(editor) {
|
||||
alert('icon addon invoke, current activeKey: ' + editor.activeKey);
|
||||
},
|
||||
}
|
||||
},
|
||||
config: {},
|
||||
pluginProps: {},
|
||||
},
|
||||
pluginProps: {}
|
||||
}
|
||||
],
|
||||
rightArea: [
|
||||
{
|
||||
@ -160,56 +160,56 @@ export default {
|
||||
type: 'Panel',
|
||||
props: {
|
||||
title: 'panel1',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'rightPanel2',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
title: 'panel2',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'rightPanel3',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
title: 'panel3',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
pluginProps: {}
|
||||
},
|
||||
{
|
||||
pluginKey: 'rightPanel4',
|
||||
type: 'Panel',
|
||||
props: {
|
||||
title: 'panel4',
|
||||
icon: 'dengpao',
|
||||
icon: 'dengpao'
|
||||
},
|
||||
config: {
|
||||
package: '@ali/iceluna-addon-2',
|
||||
version: '^1.0.0',
|
||||
version: '^1.0.0'
|
||||
},
|
||||
pluginProps: {},
|
||||
},
|
||||
pluginProps: {}
|
||||
}
|
||||
],
|
||||
centerArea: [],
|
||||
centerArea: []
|
||||
},
|
||||
hooks: [],
|
||||
shortCuts: [],
|
||||
shortCuts: []
|
||||
};
|
||||
|
||||
@ -1,4 +1,17 @@
|
||||
export interface EditorConfig {}
|
||||
import * as React from 'react';
|
||||
import Editor from './editor';
|
||||
|
||||
export interface EditorConfig {
|
||||
skeleton?: SkeletonConfig;
|
||||
theme?: ThemeConfig;
|
||||
plugins?: PluginsConfig;
|
||||
hooks?: HooksConfig;
|
||||
shortCuts?: ShortCutsConfig;
|
||||
utils?: UtilsConfig;
|
||||
constants?: ConstantsConfig;
|
||||
lifeCycles?: lifeCyclesConfig;
|
||||
i18n?: I18nConfig;
|
||||
}
|
||||
|
||||
export interface NpmConfig {
|
||||
version: string;
|
||||
@ -25,17 +38,92 @@ export interface ThemeConfig {
|
||||
}
|
||||
|
||||
export interface PluginsConfig {
|
||||
[key]: Array<PluginConfig>;
|
||||
[propName: string]: Array<PluginConfig>;
|
||||
}
|
||||
|
||||
export interface PluginConfig {
|
||||
pluginKey: string;
|
||||
type: string;
|
||||
props: object;
|
||||
config: NpmConfig;
|
||||
pluginProps: object;
|
||||
props: {
|
||||
icon?: string;
|
||||
title?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
visible?: boolean;
|
||||
disabled?: boolean;
|
||||
marked?: boolean;
|
||||
align?: 'left' | 'right' | 'top' | 'bottom';
|
||||
onClick?: () => void;
|
||||
dialogProps?: object;
|
||||
balloonProps?: object;
|
||||
panelProps?: object;
|
||||
linkProps?: object;
|
||||
};
|
||||
config?: NpmConfig;
|
||||
pluginProps?: object;
|
||||
}
|
||||
|
||||
export type HooksConfig = Array<HookConfig>;
|
||||
|
||||
export interface HookConfig {}
|
||||
export interface HookConfig {
|
||||
message: string;
|
||||
type: 'on' | 'once';
|
||||
handler: (editor: Editor, ...args) => void;
|
||||
}
|
||||
|
||||
export type ShortCutsConfig = Array<ShortCutConfig>;
|
||||
|
||||
export interface ShortCutConfig {
|
||||
keyboard: string;
|
||||
handler: (editor: Editor, ev: React.KeyboardEventHandler<HTMLElement>, keymaster: any) => void;
|
||||
}
|
||||
|
||||
export type UtilsConfig = Array<UtilConfig>;
|
||||
|
||||
export interface UtilConfig {
|
||||
name: string;
|
||||
type: 'npm' | 'function';
|
||||
content: NpmConfig | ((...args) => any);
|
||||
}
|
||||
|
||||
export type ConstantsConfig = object;
|
||||
|
||||
export interface lifeCyclesConfig {
|
||||
init?: (editor: Editor) => any;
|
||||
destroy?: (editor: Editor) => any;
|
||||
}
|
||||
|
||||
export type LocaleType = 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP';
|
||||
|
||||
export interface I18nMessages {
|
||||
[propName: string]: string;
|
||||
}
|
||||
|
||||
export interface I18nConfig {
|
||||
'zh-CN'?: I18nMessages;
|
||||
'zh-TW'?: I18nMessages;
|
||||
'en-US'?: I18nMessages;
|
||||
'ja-JP'?: I18nMessages;
|
||||
}
|
||||
|
||||
export type I18nFunction = (key: string, params: object) => string;
|
||||
|
||||
export interface Utils {
|
||||
[propName: string]: (...args) => any;
|
||||
}
|
||||
|
||||
export interface PluginClass extends React.Component {
|
||||
init?: (editor: Editor) => void;
|
||||
}
|
||||
|
||||
export interface PluginComponents {
|
||||
[propName: string]: PluginClass;
|
||||
}
|
||||
|
||||
export interface PluginStatus {
|
||||
[propName: string]: {
|
||||
disabled: boolean;
|
||||
visible: boolean;
|
||||
marked: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import EventEmitter from 'events';
|
||||
import Debug from 'debug';
|
||||
import store from 'store';
|
||||
import { EditorConfig, Utils, PluginComponents, PluginStatus, LocaleType, HooksConfig } from './definitions';
|
||||
|
||||
import {
|
||||
unRegistShortCuts,
|
||||
registShortCuts,
|
||||
transformToPromise,
|
||||
generateI18n,
|
||||
} from './utils';
|
||||
import { unRegistShortCuts, registShortCuts, transformToPromise } from './utils';
|
||||
|
||||
// 根据url参数设置debug选项
|
||||
const res = /_?debug=(.*?)(&|$)/.exec(location.search);
|
||||
@ -39,35 +35,47 @@ window.onbeforeunload = function(e) {
|
||||
return msg;
|
||||
};
|
||||
|
||||
let instance = null;
|
||||
let instance: Editor;
|
||||
|
||||
const debug = Debug('editor');
|
||||
EventEmitter.defaultMaxListeners = 100;
|
||||
|
||||
export interface HooksFuncs {
|
||||
[idx: number]: (msg: string, handler: (...args) => void) => void;
|
||||
}
|
||||
|
||||
export default class Editor extends EventEmitter {
|
||||
static getInstance = () => {
|
||||
static getInstance = (config: EditorConfig, components: PluginComponents, utils?: Utils): Editor => {
|
||||
if (!instance) {
|
||||
instance = new Editor();
|
||||
instance = new Editor(config, components, utils);
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
constructor(config, utils, components) {
|
||||
private hooksFuncs: HooksFuncs;
|
||||
|
||||
public pluginStatus: PluginStatus;
|
||||
public plugins: PluginComponents;
|
||||
public locale: LocaleType;
|
||||
|
||||
public emit: (msg: string, ...args) => void;
|
||||
public on: (msg: string, handler: (...args) => void) => void;
|
||||
public once: (msg: string, handler: (...args) => void) => void;
|
||||
public off: (msg: string, handler: (...args) => void) => void;
|
||||
|
||||
constructor(public config: EditorConfig, public components: PluginComponents, public utils?: Utils) {
|
||||
super();
|
||||
instance = this;
|
||||
this.config = config;
|
||||
this.utils = utils;
|
||||
this.components = components;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
const { hooks, shortCuts, lifeCycles } = this.config || {};
|
||||
init(): Promise<any> {
|
||||
const { hooks, shortCuts = [], lifeCycles } = this.config || {};
|
||||
this.locale = store.get('lowcode-editor-locale') || 'zh-CN';
|
||||
// this.messages = this.messagesSet[this.locale];
|
||||
// this.i18n = generateI18n(this.locale, this.messages);
|
||||
this.pluginStatus = this.initPluginStatus();
|
||||
this.initHooks(hooks);
|
||||
this.initHooks(hooks || []);
|
||||
|
||||
this.emit('editor.beforeInit');
|
||||
const init = (lifeCycles && lifeCycles.init) || (() => {});
|
||||
@ -77,6 +85,7 @@ export default class Editor extends EventEmitter {
|
||||
// 注册快捷键
|
||||
registShortCuts(shortCuts, this);
|
||||
this.emit('editor.afterInit');
|
||||
return true;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
@ -84,11 +93,12 @@ export default class Editor extends EventEmitter {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
debug('destroy');
|
||||
try {
|
||||
const { hooks = [], shortCuts = [], lifeCycles = {} } = this.config;
|
||||
unRegistShortCuts(shortCuts);
|
||||
this.destroyHooks(hooks);
|
||||
lifeCycles.destroy && lifeCycles.destroy();
|
||||
lifeCycles.destroy && lifeCycles.destroy(this);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
return;
|
||||
@ -101,20 +111,8 @@ export default class Editor extends EventEmitter {
|
||||
|
||||
set(key: string | object, val: any): void {
|
||||
if (typeof key === 'string') {
|
||||
if (
|
||||
[
|
||||
'init',
|
||||
'destroy',
|
||||
'get',
|
||||
'set',
|
||||
'batchOn',
|
||||
'batchOff',
|
||||
'batchOnce',
|
||||
].includes(key)
|
||||
) {
|
||||
console.warning(
|
||||
'init, destroy, get, set, batchOn, batchOff, batchOnce is private attribute',
|
||||
);
|
||||
if (['init', 'destroy', 'get', 'set', 'batchOn', 'batchOff', 'batchOnce'].includes(key)) {
|
||||
console.error('init, destroy, get, set, batchOn, batchOff, batchOnce is private attribute');
|
||||
return;
|
||||
}
|
||||
this[key] = val;
|
||||
@ -125,34 +123,34 @@ export default class Editor extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
batchOn(events: Array<string>, lisenter: function): void {
|
||||
batchOn(events: Array<string>, lisenter: (...args) => void): void {
|
||||
if (!Array.isArray(events)) return;
|
||||
events.forEach(event => this.on(event, lisenter));
|
||||
}
|
||||
|
||||
batchOnce(events: Array<string>, lisenter: function): void {
|
||||
batchOnce(events: Array<string>, lisenter: (...args) => void): void {
|
||||
if (!Array.isArray(events)) return;
|
||||
events.forEach(event => this.once(event, lisenter));
|
||||
}
|
||||
|
||||
batchOff(events: Array<string>, lisenter: function): void {
|
||||
batchOff(events: Array<string>, lisenter: (...args) => void): void {
|
||||
if (!Array.isArray(events)) return;
|
||||
events.forEach(event => this.off(event, lisenter));
|
||||
}
|
||||
|
||||
//销毁hooks中的消息监听
|
||||
private destroyHooks(hooks = []) {
|
||||
private destroyHooks(hooks: HooksConfig = []) {
|
||||
hooks.forEach((item, idx) => {
|
||||
if (typeof this.__hooksFuncs[idx] === 'function') {
|
||||
this.off(item.message, this.__hooksFuncs[idx]);
|
||||
if (typeof this.hooksFuncs[idx] === 'function') {
|
||||
this.off(item.message, this.hooksFuncs[idx]);
|
||||
}
|
||||
});
|
||||
delete this.__hooksFuncs;
|
||||
delete this.hooksFuncs;
|
||||
}
|
||||
|
||||
//初始化hooks中的消息监听
|
||||
private initHooks(hooks = []) {
|
||||
this.__hooksFuncs = hooks.map(item => {
|
||||
private initHooks(hooks: HooksConfig = []): void {
|
||||
this.hooksFuncs = hooks.map(item => {
|
||||
const func = (...args) => {
|
||||
item.handler(this, ...args);
|
||||
};
|
||||
@ -168,11 +166,11 @@ export default class Editor extends EventEmitter {
|
||||
pluginAreas.forEach(area => {
|
||||
(plugins[area] || []).forEach(plugin => {
|
||||
if (plugin.type === 'Divider') return;
|
||||
const { visible, disabled, dotted } = plugin.props || {};
|
||||
const { visible, disabled, marked } = plugin.props || {};
|
||||
res[plugin.pluginKey] = {
|
||||
visible: typeof visible === 'boolean' ? visible : true,
|
||||
disabled: typeof disabled === 'boolean' ? disabled : false,
|
||||
dotted: typeof dotted === 'boolean' ? dotted : false,
|
||||
marked: typeof marked === 'boolean' ? marked : false
|
||||
};
|
||||
const pluginClass = this.components[plugin.pluginKey];
|
||||
// 判断如果编辑器插件有init静态方法,则在此执行init方法
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
import Editor from './editor';
|
||||
export { default as PluginFactory } from './plugin';
|
||||
export { default as EditorContext } from './context';
|
||||
|
||||
import * as editorUtils from './utils';
|
||||
import * as editorDefinitions from './definitions';
|
||||
export default Editor;
|
||||
|
||||
export const utils = editorUtils;
|
||||
export const definitions = editorDefinitions;
|
||||
|
||||
@ -1,23 +1,41 @@
|
||||
import React, { PureComponent, creatRef} from 'react';
|
||||
import React, { PureComponent, createRef } from 'react';
|
||||
|
||||
import EditorContext from './context';
|
||||
import { isEmpty, generateI18n, goldlog } from './utils';
|
||||
import Editor from './editor';
|
||||
import { isEmpty, generateI18n } from './utils';
|
||||
import { PluginConfig, I18nFunction } from './definitions';
|
||||
|
||||
export interface PluginProps {
|
||||
editor: Editor;
|
||||
config: PluginConfig;
|
||||
}
|
||||
|
||||
export default function plugin(Comp) {
|
||||
class LowcodePlugin extends PureComponent {
|
||||
export interface InjectedPluginProps {
|
||||
i18n?: I18nFunction;
|
||||
}
|
||||
|
||||
export default function plugin(
|
||||
Comp: React.ComponentType<PluginProps & InjectedPluginProps>
|
||||
): React.ComponentType<PluginProps> {
|
||||
class LowcodePlugin extends PureComponent<PluginProps> {
|
||||
static displayName = 'LowcodeEditorPlugin';
|
||||
static defaultProps = {
|
||||
config: {},
|
||||
config: {}
|
||||
};
|
||||
static contextType = EditorContext;
|
||||
static init = Comp.init;
|
||||
public ref = createRef<React.Component>();
|
||||
private editor: Editor;
|
||||
private pluginKey: string;
|
||||
private i18n: I18nFunction;
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
if (isEmpty(props.config) || !props.config.pluginKey) {
|
||||
console.warn('lowcode editor plugin has wrong config');
|
||||
return;
|
||||
}
|
||||
this.ref = React.createRef();
|
||||
const { locale, messages, editor } = props;
|
||||
// 注册插件
|
||||
this.editor = editor;
|
||||
@ -36,19 +54,9 @@ export default function plugin(Comp) {
|
||||
|
||||
render() {
|
||||
const { config } = this.props;
|
||||
return (
|
||||
<Comp
|
||||
ref={this.ref}
|
||||
i18n={this.i18n}
|
||||
editor={this.editor}
|
||||
config={config}
|
||||
{...config.pluginProps}
|
||||
/>
|
||||
);
|
||||
return <Comp ref={this.ref} i18n={this.i18n} editor={this.editor} config={config} {...config.pluginProps} />;
|
||||
}
|
||||
}
|
||||
|
||||
LowcodePlugin.init = Comp.init;
|
||||
|
||||
return LowcodePlugin;
|
||||
}
|
||||
@ -1,15 +1,41 @@
|
||||
import IntlMessageFormat from 'intl-messageformat';
|
||||
import keymaster from 'keymaster';
|
||||
import _isEmpty from 'lodash/isEmpty';
|
||||
import { EditorConfig, LocaleType, I18nMessages, I18nFunction, ShortCutsConfig } from './definitions';
|
||||
import Editor from './editor';
|
||||
|
||||
export const isEmpty = _isEmpty;
|
||||
|
||||
const ENV = {
|
||||
TBE: 'TBE',
|
||||
WEBIDE: 'WEB-IDE',
|
||||
VSCODE: 'VSCODE',
|
||||
WEB: 'WEB'
|
||||
};
|
||||
|
||||
export interface IDEMessageParams {
|
||||
action: string;
|
||||
data: {
|
||||
logKey: string;
|
||||
gmKey: string;
|
||||
goKey: string;
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于构造国际化字符串处理函数
|
||||
* @param {*} locale 国际化标识,例如 zh-CN、en-US
|
||||
* @param {*} messages 国际化语言包
|
||||
*/
|
||||
export function generateI18n(locale = 'zh-CN', messages = {}) {
|
||||
export function generateI18n(locale: LocaleType = 'zh-CN', messages: I18nMessages = {}): I18nFunction {
|
||||
return (key, values = {}) => {
|
||||
if (!messages || !messages[key]) return '';
|
||||
const formater = new IntlMessageFormat(messages[key], locale);
|
||||
@ -19,18 +45,14 @@ export function generateI18n(locale = 'zh-CN', messages = {}) {
|
||||
|
||||
/**
|
||||
* 序列化参数
|
||||
* @param {*} obj 参数
|
||||
*/
|
||||
export function serializeParams(obj: object): string {
|
||||
if (typeof obj !== 'object') return '';
|
||||
|
||||
const res: Array<string> = [];
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (val === null || val === undefined || val === '') return;
|
||||
if (typeof val === 'object') {
|
||||
res.push(
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(val))}`,
|
||||
);
|
||||
res.push(`${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(val))}`);
|
||||
} else {
|
||||
res.push(`${encodeURIComponent(key)}=${encodeURIComponent(val)}`);
|
||||
}
|
||||
@ -44,12 +66,12 @@ export function serializeParams(obj: object): string {
|
||||
* @param {Object} params 参数
|
||||
* @param {String} logKey 属性串
|
||||
*/
|
||||
export function goldlog(gmKey, params = {}, logKey = 'other') {
|
||||
const sendIDEMessage = window.sendIDEMessage || window.parent.sendIDEMessage;
|
||||
export function goldlog(gmKey: string, params: object = {}, logKey: string = 'other'): void {
|
||||
const global = window as Window;
|
||||
const sendIDEMessage = global.sendIDEMessage || global.parent.sendIDEMessage;
|
||||
const goKey = serializeParams({
|
||||
sdkVersion: pkg.version,
|
||||
env: getEnv(),
|
||||
...params,
|
||||
...params
|
||||
});
|
||||
if (sendIDEMessage) {
|
||||
sendIDEMessage({
|
||||
@ -57,18 +79,17 @@ export function goldlog(gmKey, params = {}, logKey = 'other') {
|
||||
data: {
|
||||
logKey: `/iceluna.core.${logKey}`,
|
||||
gmKey,
|
||||
goKey,
|
||||
},
|
||||
goKey
|
||||
}
|
||||
});
|
||||
}
|
||||
window.goldlog &&
|
||||
window.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
||||
global.goldlog && global.goldlog.record(`/iceluna.core.${logKey}`, gmKey, goKey, 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前编辑器环境
|
||||
*/
|
||||
export function getEnv() {
|
||||
export function getEnv(): string {
|
||||
const userAgent = navigator.userAgent;
|
||||
const isVscode = /Electron\//.test(userAgent);
|
||||
if (isVscode) return ENV.VSCODE;
|
||||
@ -78,131 +99,17 @@ export function getEnv() {
|
||||
}
|
||||
|
||||
// 注册快捷键
|
||||
export function registShortCuts(config, editor) {
|
||||
const keyboardFilter = (keymaster.filter = event => {
|
||||
let eTarget = event.target || event.srcElement;
|
||||
let tagName = eTarget.tagName;
|
||||
let isInput = !!(
|
||||
tagName == 'INPUT' ||
|
||||
tagName == 'SELECT' ||
|
||||
tagName == 'TEXTAREA'
|
||||
);
|
||||
let isContenteditable = !!eTarget.getAttribute('contenteditable');
|
||||
if (isInput || isContenteditable) {
|
||||
if (event.metaKey === true && [70, 83].includes(event.keyCode))
|
||||
event.preventDefault(); //禁止触发chrome原生的页面保存或查找
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const ideMessage = editor.utils && editor.utils.ideMessage;
|
||||
|
||||
//复制
|
||||
if (!document.copyListener) {
|
||||
document.copyListener = e => {
|
||||
if (!keyboardFilter(e) || editor.isCopying) return;
|
||||
const schema =
|
||||
editor.schemaHelper &&
|
||||
editor.schemaHelper.schemaMap[editor.activeKey];
|
||||
if (!schema || !isSchema(schema)) return;
|
||||
editor.isCopying = true;
|
||||
const schemaStr = serialize(transformSchemaToPure(schema), {
|
||||
unsafe: true,
|
||||
});
|
||||
setClipboardData(schemaStr)
|
||||
.then(() => {
|
||||
ideMessage &&
|
||||
ideMessage(
|
||||
'success',
|
||||
'当前内容已复制到剪贴板,请使用快捷键Command+v进行粘贴',
|
||||
);
|
||||
editor.emit('schema.copy', schemaStr, schema);
|
||||
editor.isCopying = false;
|
||||
})
|
||||
.catch(errMsg => {
|
||||
ideMessage && ideMessage('error', errMsg);
|
||||
editor.isCopying = false;
|
||||
});
|
||||
};
|
||||
document.addEventListener('copy', document.copyListener);
|
||||
if (window.parent.vscode) {
|
||||
keymaster('command+c', document.copyListener);
|
||||
}
|
||||
}
|
||||
|
||||
//粘贴
|
||||
if (!document.pasteListener) {
|
||||
const doPaste = (e, text) => {
|
||||
if (!keyboardFilter(e) || editor.isPasting) return;
|
||||
const schemaHelper = editor.schemaHelper;
|
||||
let targetKey = editor.activeKey;
|
||||
let direction = 'after';
|
||||
const topKey =
|
||||
schemaHelper.schema &&
|
||||
schemaHelper.schema.__ctx &&
|
||||
schemaHelper.schema.__ctx.lunaKey;
|
||||
if (!targetKey || topKey === targetKey) {
|
||||
const schemaHelper = editor.schemaHelper;
|
||||
const topKey =
|
||||
schemaHelper.schema &&
|
||||
schemaHelper.schema.__ctx &&
|
||||
schemaHelper.schema.__ctx.lunaKey;
|
||||
if (!topKey) return;
|
||||
targetKey = topKey;
|
||||
direction = 'in';
|
||||
}
|
||||
editor.isPasting = true;
|
||||
const schema = parseObj(text);
|
||||
if (!isSchema(schema)) {
|
||||
editor.emit('illegalSchema.paste', text);
|
||||
// ideMessage && ideMessage('error', '当前内容不是模型结构,不能粘贴进来!');
|
||||
console.warn('paste schema illegal');
|
||||
editor.isPasting = false;
|
||||
return;
|
||||
}
|
||||
editor.emit('material.add', {
|
||||
schema,
|
||||
targetKey,
|
||||
direction,
|
||||
});
|
||||
editor.isPasting = false;
|
||||
editor.emit('schema.paste', schema);
|
||||
};
|
||||
document.pasteListener = e => {
|
||||
const clipboardData = e.clipboardData || window.clipboardData;
|
||||
const text = clipboardData && clipboardData.getData('text');
|
||||
doPaste(e, text);
|
||||
};
|
||||
document.addEventListener('paste', document.pasteListener);
|
||||
if (window.parent.vscode) {
|
||||
keymaster('command+v', e => {
|
||||
const sendIDEMessage = window.parent.sendIDEMessage;
|
||||
sendIDEMessage &&
|
||||
sendIDEMessage({
|
||||
action: 'readClipboard',
|
||||
})
|
||||
.then(text => {
|
||||
doPaste(e, text);
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function registShortCuts(config: ShortCutsConfig, editor: Editor): void {
|
||||
(config || []).forEach(item => {
|
||||
keymaster(item.keyboard, ev => {
|
||||
ev.preventDefault();
|
||||
item.handler(ev, editor, keymaster);
|
||||
item.handler(editor, ev, keymaster);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 取消注册快捷
|
||||
export function unRegistShortCuts(config) {
|
||||
export function unRegistShortCuts(config: ShortCutsConfig): void {
|
||||
(config || []).forEach(item => {
|
||||
keymaster.unbind(item.keyboard);
|
||||
});
|
||||
@ -210,18 +117,12 @@ export function unRegistShortCuts(config) {
|
||||
keymaster.unbind('command+c');
|
||||
keymaster.unbind('command+v');
|
||||
}
|
||||
if (document.copyListener) {
|
||||
document.removeEventListener('copy', document.copyListener);
|
||||
delete document.copyListener;
|
||||
}
|
||||
if (document.pasteListener) {
|
||||
document.removeEventListener('paste', document.pasteListener);
|
||||
delete document.pasteListener;
|
||||
}
|
||||
}
|
||||
|
||||
// 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
||||
export function transformToPromise(input) {
|
||||
/**
|
||||
* 将函数返回结果转成promise形式,如果函数有返回值则根据返回值的bool类型判断是reject还是resolve,若函数无返回值默认执行resolve
|
||||
*/
|
||||
export function transformToPromise(input: any): Promise<{}> {
|
||||
if (input instanceof Promise) return input;
|
||||
return new Promise((resolve, reject) => {
|
||||
if (input || input === undefined) {
|
||||
@ -232,7 +133,13 @@ export function transformToPromise(input) {
|
||||
});
|
||||
}
|
||||
|
||||
export function transformArrayToMap(arr, key, overwrite = true) {
|
||||
/**
|
||||
* 将数组类型转换为Map类型
|
||||
*/
|
||||
interface MapOf<T> {
|
||||
[propName: string]: T;
|
||||
}
|
||||
export function transformArrayToMap<T>(arr: Array<T>, key: string, overwrite: boolean = true): MapOf<T> {
|
||||
if (isEmpty(arr) || !Array.isArray(arr)) return {};
|
||||
const res = {};
|
||||
arr.forEach(item => {
|
||||
@ -244,7 +151,13 @@ export function transformArrayToMap(arr, key, overwrite = true) {
|
||||
return res;
|
||||
}
|
||||
|
||||
export function parseSearch(search) {
|
||||
/**
|
||||
* 解析url的查询参数
|
||||
*/
|
||||
interface Query {
|
||||
[propName: string]: string;
|
||||
}
|
||||
export function parseSearch(search: string): Query {
|
||||
if (!search || typeof search !== 'string') return {};
|
||||
const str = search.replace(/^\?/, '');
|
||||
let paramStr = str.split('&');
|
||||
@ -258,63 +171,50 @@ export function parseSearch(search) {
|
||||
return res;
|
||||
}
|
||||
|
||||
export function comboEditorConfig(defaultConfig = {}, customConfig = {}) {
|
||||
const {
|
||||
skeleton,
|
||||
theme,
|
||||
plugins,
|
||||
hooks,
|
||||
shortCuts,
|
||||
lifeCycles,
|
||||
constants,
|
||||
utils,
|
||||
i18n,
|
||||
} = customConfig || {};
|
||||
export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig: EditorConfig): EditorConfig {
|
||||
const { skeleton, theme, plugins, hooks, shortCuts, lifeCycles, constants, utils, i18n } = customConfig || {};
|
||||
|
||||
if (skeleton && skeleton.handler && typeof skeleton.handler === 'function') {
|
||||
return skeleton.handler({
|
||||
skeleton,
|
||||
...defaultConfig,
|
||||
...defaultConfig
|
||||
});
|
||||
}
|
||||
|
||||
const defaultShortCuts = transformArrayToMap(
|
||||
defaultConfig.shortCuts,
|
||||
'keyboard',
|
||||
);
|
||||
const customShortCuts = transformArrayToMap(shortCuts, 'keyboard');
|
||||
const defaultShortCuts = transformArrayToMap(defaultConfig.shortCuts || [], 'keyboard');
|
||||
const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard');
|
||||
const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP'];
|
||||
const i18nConfig = {};
|
||||
localeList.forEach(key => {
|
||||
i18nConfig[key] = {
|
||||
...(defaultConfig.i18n && defaultConfig.i18n[key]),
|
||||
...(i18n && i18n[key]),
|
||||
...(i18n && i18n[key])
|
||||
};
|
||||
});
|
||||
return {
|
||||
skeleton,
|
||||
theme: {
|
||||
...defaultConfig.theme,
|
||||
...theme,
|
||||
...theme
|
||||
},
|
||||
plugins: {
|
||||
...defaultConfig.plugins,
|
||||
...plugins,
|
||||
...plugins
|
||||
},
|
||||
hooks: [...(defaultConfig.hooks || []), ...(hooks || [])],
|
||||
shortCuts: Object.values({
|
||||
...defaultShortCuts,
|
||||
...customShortCuts,
|
||||
...customShortCuts
|
||||
}),
|
||||
lifeCycles: {
|
||||
...defaultConfig.lifeCycles,
|
||||
...lifeCycles,
|
||||
...lifeCycles
|
||||
},
|
||||
constants: {
|
||||
...defaultConfig.constants,
|
||||
...constants,
|
||||
...constants
|
||||
},
|
||||
utils: [...(defaultConfig.utils || []), ...(utils || [])],
|
||||
i18n: i18nConfig,
|
||||
i18n: i18nConfig
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
body {
|
||||
font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma,
|
||||
Arial, PingFang SC-Light, Microsoft YaHei;
|
||||
font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma, Arial, PingFang SC-Light, Microsoft YaHei;
|
||||
font-size: 12px;
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
||||
@ -28,5 +28,5 @@ ReactDOM.render(
|
||||
constants={constants}
|
||||
components={components}
|
||||
/>,
|
||||
ICE_CONTAINER,
|
||||
ICE_CONTAINER
|
||||
);
|
||||
|
||||
@ -1,26 +1,42 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Balloon, Dialog, Icon, Badge } from '@alife/next';
|
||||
import { Balloon, Dialog, Icon, Badge } from '@alifd/next';
|
||||
|
||||
import './index.scss';
|
||||
export default class LeftPlugin extends PureComponent {
|
||||
static displayName = 'lowcodeLeftPlugin';
|
||||
import Editor from '../../../framework/editor';
|
||||
import { PluginConfig, PluginClass } from '../../../framework/definitions';
|
||||
|
||||
export interface LeftPluginProps {
|
||||
active?: boolean;
|
||||
config: PluginConfig;
|
||||
disabled?: boolean;
|
||||
editor: Editor;
|
||||
locked?: boolean;
|
||||
marked?: boolean;
|
||||
onClick?: () => void;
|
||||
pluginClass: PluginClass;
|
||||
}
|
||||
|
||||
export interface LeftPluginState {
|
||||
dialogVisible: boolean;
|
||||
}
|
||||
|
||||
export default class LeftPlugin extends PureComponent<LeftPluginProps, LeftPluginState> {
|
||||
static displayName = 'LowcodeLeftPlugin';
|
||||
|
||||
static defaultProps = {
|
||||
active: false,
|
||||
config: {},
|
||||
disabled: false,
|
||||
dotted: false,
|
||||
marked: false,
|
||||
locked: false,
|
||||
onClick: () => {},
|
||||
onClick: () => {}
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
dialogVisible: false,
|
||||
dialogVisible: false
|
||||
};
|
||||
}
|
||||
|
||||
@ -60,7 +76,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
handleOpen = () => {
|
||||
// todo 对话框类型的插件初始时拿不到插件实例
|
||||
this.setState({
|
||||
dialogVisible: true,
|
||||
dialogVisible: true
|
||||
});
|
||||
};
|
||||
|
||||
@ -75,15 +91,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
};
|
||||
|
||||
renderIcon = clickCallback => {
|
||||
const {
|
||||
active,
|
||||
disabled,
|
||||
dotted,
|
||||
locked,
|
||||
onClick,
|
||||
config,
|
||||
editor,
|
||||
} = this.props;
|
||||
const { active, disabled, marked, locked, onClick, config, editor } = this.props;
|
||||
const { pluginKey, props } = config || {};
|
||||
const { icon, title } = props || {};
|
||||
return (
|
||||
@ -91,7 +99,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
className={classNames('lowcode-left-plugin', pluginKey, {
|
||||
active,
|
||||
disabled,
|
||||
locked,
|
||||
locked
|
||||
})}
|
||||
data-tooltip={title}
|
||||
onClick={() => {
|
||||
@ -101,7 +109,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
onClick && onClick();
|
||||
}}
|
||||
>
|
||||
{dotted ? (
|
||||
{marked ? (
|
||||
<Badge dot>
|
||||
<Icon type={icon} size="small" />
|
||||
</Badge>
|
||||
@ -113,15 +121,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
dotted,
|
||||
locked,
|
||||
active,
|
||||
disabled,
|
||||
config,
|
||||
editor,
|
||||
pluginClass: Comp,
|
||||
} = this.props;
|
||||
const { marked, locked, active, disabled, config, editor, pluginClass: Comp } = this.props;
|
||||
const { pluginKey, props, type, pluginProps } = config || {};
|
||||
const { onClick, title } = props || {};
|
||||
const { dialogVisible } = this.state;
|
||||
@ -197,7 +197,7 @@ export default class LeftPlugin extends PureComponent {
|
||||
this.handleOpen();
|
||||
});
|
||||
case 'Custom':
|
||||
return dotted ? <Badge dot>{node}</Badge> : node;
|
||||
return marked ? <Badge dot>{node}</Badge> : node;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import './index.scss';
|
||||
export default class Panel extends PureComponent {
|
||||
static displayName = 'Panel';
|
||||
|
||||
export interface PanelProps {
|
||||
children: Plugin;
|
||||
}
|
||||
|
||||
export default class Panel extends PureComponent<PanelProps> {
|
||||
static displayName = 'LowcodePanel';
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -13,7 +18,7 @@ export default class Panel extends PureComponent {
|
||||
<div
|
||||
className="lowcode-panel"
|
||||
style={{
|
||||
width: 240,
|
||||
width: 240
|
||||
}}
|
||||
>
|
||||
{this.props.children}
|
||||
|
||||
@ -1,23 +1,25 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Icon, Button } from '@alifd/next';
|
||||
|
||||
import './index.scss';
|
||||
export default class TopIcon extends PureComponent {
|
||||
static displayName = 'TopIcon';
|
||||
static propTypes = {
|
||||
active: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
icon: PropTypes.string,
|
||||
id: PropTypes.string,
|
||||
locked: PropTypes.bool,
|
||||
onClick: PropTypes.func,
|
||||
showTitle: PropTypes.bool,
|
||||
style: PropTypes.object,
|
||||
title: PropTypes.string,
|
||||
};
|
||||
|
||||
export interface TopIconProps {
|
||||
active?: boolean;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
icon: string;
|
||||
id?: string;
|
||||
locked?: boolean;
|
||||
marked?: boolean;
|
||||
onClick?: () => void;
|
||||
showTitle?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export default class TopIcon extends PureComponent<TopIconProps> {
|
||||
static displayName = 'LowcodeTopIcon';
|
||||
static defaultProps = {
|
||||
active: false,
|
||||
className: '',
|
||||
@ -28,22 +30,11 @@ export default class TopIcon extends PureComponent {
|
||||
onClick: () => {},
|
||||
showTitle: false,
|
||||
style: {},
|
||||
title: '',
|
||||
title: ''
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
active,
|
||||
disabled,
|
||||
icon,
|
||||
locked,
|
||||
title,
|
||||
className,
|
||||
id,
|
||||
style,
|
||||
showTitle,
|
||||
onClick,
|
||||
} = this.props;
|
||||
const { active, disabled, icon, locked, title, className, id, style, showTitle, onClick } = this.props;
|
||||
return (
|
||||
<Button
|
||||
type="normal"
|
||||
@ -52,11 +43,11 @@ export default class TopIcon extends PureComponent {
|
||||
className={classNames('lowcode-top-btn', className, {
|
||||
active,
|
||||
disabled,
|
||||
locked,
|
||||
locked
|
||||
})}
|
||||
id={id}
|
||||
style={style}
|
||||
onClick={disabled ? null : onClick}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
>
|
||||
<div>
|
||||
<Icon size="large" type={icon} />
|
||||
|
||||
@ -1,26 +1,43 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import TopIcon from '../TopIcon';
|
||||
import { Balloon, Badge, Dialog } from '@alifd/next';
|
||||
|
||||
import './index.scss';
|
||||
export default class TopPlugin extends PureComponent {
|
||||
static displayName = 'lowcodeTopPlugin';
|
||||
import { PluginConfig, PluginClass } from '../../../framework/definitions';
|
||||
import Editor from '../../../framework/editor';
|
||||
|
||||
export interface TopPluginProps {
|
||||
active?: boolean;
|
||||
config: PluginConfig;
|
||||
disabled?: boolean;
|
||||
editor: Editor;
|
||||
locked?: boolean;
|
||||
marked?: boolean;
|
||||
onClick?: () => void;
|
||||
pluginClass: PluginClass;
|
||||
}
|
||||
|
||||
export interface TopPluginState {
|
||||
dialogVisible: boolean;
|
||||
}
|
||||
|
||||
export default class TopPlugin extends PureComponent<TopPluginProps, TopPluginState> {
|
||||
static displayName = 'LowcodeTopPlugin';
|
||||
|
||||
static defaultProps = {
|
||||
active: false,
|
||||
config: {},
|
||||
disabled: false,
|
||||
dotted: false,
|
||||
marked: false,
|
||||
locked: false,
|
||||
onClick: () => {},
|
||||
onClick: () => {}
|
||||
};
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
dialogVisible: false,
|
||||
dialogVisible: false
|
||||
};
|
||||
}
|
||||
|
||||
@ -70,20 +87,12 @@ export default class TopPlugin extends PureComponent {
|
||||
handleOpen = () => {
|
||||
// todo dialog类型的插件初始时拿不动插件实例
|
||||
this.setState({
|
||||
dialogVisible: true,
|
||||
dialogVisible: true
|
||||
});
|
||||
};
|
||||
|
||||
renderIcon = clickCallback => {
|
||||
const {
|
||||
active,
|
||||
disabled,
|
||||
dotted,
|
||||
locked,
|
||||
config,
|
||||
onClick,
|
||||
editor,
|
||||
} = this.props;
|
||||
const { active, disabled, marked, locked, config, onClick, editor } = this.props;
|
||||
const { pluginKey, props } = config || {};
|
||||
const { icon, title } = props || {};
|
||||
const node = (
|
||||
@ -103,19 +112,11 @@ export default class TopPlugin extends PureComponent {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return dotted ? <Badge dot>{node}</Badge> : node;
|
||||
return marked ? <Badge dot>{node}</Badge> : node;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
active,
|
||||
dotted,
|
||||
locked,
|
||||
disabled,
|
||||
config,
|
||||
editor,
|
||||
pluginClass: Comp,
|
||||
} = this.props;
|
||||
const { active, marked, locked, disabled, config, editor, pluginClass: Comp } = this.props;
|
||||
const { pluginKey, pluginProps, props, type } = config || {};
|
||||
const { onClick, title } = props || {};
|
||||
const { dialogVisible } = this.state;
|
||||
@ -184,7 +185,7 @@ export default class TopPlugin extends PureComponent {
|
||||
</Balloon>
|
||||
);
|
||||
case 'Custom':
|
||||
return dotted ? <Badge dot>{node}</Badge> : node;
|
||||
return marked ? <Badge dot>{node}</Badge> : node;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
body {
|
||||
font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma,
|
||||
Arial, PingFang SC-Light, Microsoft YaHei;
|
||||
font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma, Arial, PingFang SC-Light, Microsoft YaHei;
|
||||
font-size: 12px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { HashRouter as Router, Route } from 'react-router-dom';
|
||||
import Editor from '../framework/editor';
|
||||
import { comboEditorConfig, parseSearch } from '../framework/utils';
|
||||
import { Loading, ConfigProvider } from '@alifd/next';
|
||||
|
||||
import Editor from '../framework/editor';
|
||||
import { EditorConfig, Utils, PluginComponents } from '../framework/definitions';
|
||||
import { comboEditorConfig, parseSearch } from '../framework/utils';
|
||||
|
||||
import defaultConfig from './config/skeleton';
|
||||
import skeletonUtils from './config/utils';
|
||||
|
||||
@ -16,20 +19,35 @@ import './global.scss';
|
||||
|
||||
let renderIdx = 0;
|
||||
|
||||
export default class Skeleton extends PureComponent {
|
||||
export interface SkeletonProps {
|
||||
components: PluginComponents;
|
||||
config: EditorConfig;
|
||||
utils: Utils;
|
||||
}
|
||||
|
||||
export interface SkeletonState {
|
||||
initReady: boolean;
|
||||
skeletonKey: string;
|
||||
__hasError?: boolean;
|
||||
}
|
||||
|
||||
export default class Skeleton extends PureComponent<SkeletonProps, SkeletonState> {
|
||||
static displayName = 'LowcodeEditorSkeleton';
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
return {
|
||||
__hasError: true,
|
||||
__hasError: true
|
||||
};
|
||||
}
|
||||
|
||||
private editor: Editor;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
initReady: false,
|
||||
skeletonKey: `skeleton${renderIdx}`,
|
||||
skeletonKey: `skeleton${renderIdx}`
|
||||
};
|
||||
|
||||
this.init();
|
||||
@ -37,31 +55,28 @@ export default class Skeleton extends PureComponent {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.editor && this.editor.destroy();
|
||||
this.editor = null;
|
||||
}
|
||||
|
||||
componentDidCatch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
init = (isReset = false) => {
|
||||
init = (isReset: boolean = false): void => {
|
||||
if (this.editor) {
|
||||
this.editor.destroy();
|
||||
this.editor = null;
|
||||
}
|
||||
const { utils, config, components } = this.props;
|
||||
const editor = (this.editor = new Editor(
|
||||
comboEditorConfig(defaultConfig, config),
|
||||
{ ...skeletonUtils, ...utils },
|
||||
components,
|
||||
));
|
||||
const editor = (this.editor = new Editor(comboEditorConfig(defaultConfig, config), components, {
|
||||
...skeletonUtils,
|
||||
...utils
|
||||
}));
|
||||
window.__ctx = {
|
||||
editor,
|
||||
appHelper: editor
|
||||
};
|
||||
editor.once('editor.reset', () => {
|
||||
this.setState({
|
||||
initReady: false,
|
||||
initReady: false
|
||||
});
|
||||
editor.emit('editor.beforeReset');
|
||||
this.init(true);
|
||||
@ -72,9 +87,7 @@ export default class Skeleton extends PureComponent {
|
||||
{
|
||||
initReady: true,
|
||||
//刷新IDE时生成新的skeletonKey保证插件生命周期重新执行
|
||||
skeletonKey: isReset
|
||||
? `skeleton${++renderIdx}`
|
||||
: this.state.skeletonKey,
|
||||
skeletonKey: isReset ? `skeleton${++renderIdx}` : this.state.skeletonKey
|
||||
},
|
||||
() => {
|
||||
editor.emit('editor.ready');
|
||||
@ -86,7 +99,7 @@ export default class Skeleton extends PureComponent {
|
||||
|
||||
render() {
|
||||
const { initReady, skeletonKey, __hasError } = this.state;
|
||||
if (__hasError) {
|
||||
if (__hasError || !this.editor) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
@ -102,13 +115,7 @@ export default class Skeleton extends PureComponent {
|
||||
this.editor.set('match', match);
|
||||
return (
|
||||
<ConfigProvider>
|
||||
<Loading
|
||||
tip="Loading"
|
||||
size="large"
|
||||
visible={!initReady}
|
||||
shape="fusion-reactor"
|
||||
fullScreen
|
||||
>
|
||||
<Loading tip="Loading" size="large" visible={!initReady} shape="fusion-reactor" fullScreen>
|
||||
<div className="lowcode-editor" key={skeletonKey}>
|
||||
<TopArea editor={this.editor} />
|
||||
<div className="lowcode-main-content">
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import Editor from '../../../framework/editor';
|
||||
import { PluginConfig } from '../../../framework/definitions';
|
||||
import './index.scss';
|
||||
|
||||
export default class CenterArea extends PureComponent {
|
||||
static displayName = 'lowcodeCenterArea';
|
||||
export interface CenterAreaProps {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
export default class CenterArea extends PureComponent<CenterAreaProps> {
|
||||
static displayName = 'LowcodeCenterArea';
|
||||
|
||||
private editor: Editor;
|
||||
private config: Array<PluginConfig>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editor = props.editor;
|
||||
this.config = this.editor.config && this.editor.config.plugins && this.editor.config.plugins.centerArea || [];
|
||||
this.config = (this.editor.config && this.editor.config.plugins && this.editor.config.plugins.centerArea) || [];
|
||||
}
|
||||
|
||||
render() {
|
||||
const list = this.config.filter(item => {
|
||||
return true;
|
||||
});
|
||||
return (
|
||||
<div className="lowcode-center-area">
|
||||
{list.map(item => {
|
||||
{this.config.map(item => {
|
||||
const Comp = this.editor.components[item.pluginKey];
|
||||
return (
|
||||
<Comp
|
||||
editor={this.editor}
|
||||
config={item}
|
||||
{...item.pluginProps}
|
||||
/>
|
||||
)
|
||||
return <Comp editor={this.editor} config={item} {...item.pluginProps} />;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -3,5 +3,5 @@ import Panel from './panel';
|
||||
|
||||
export default {
|
||||
Nav,
|
||||
Panel,
|
||||
Panel
|
||||
};
|
||||
|
||||
@ -1,20 +1,28 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import LeftPlugin from '../../components/LeftPlugin';
|
||||
import './index.scss';
|
||||
import Editor from '../../../framework/editor';
|
||||
import { PluginConfig } from '../../../framework/definitions';
|
||||
|
||||
export default class LeftAreaPanel extends PureComponent {
|
||||
static displayName = 'lowcodeLeftAreaNav';
|
||||
export interface LeftAreaNavProps {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
export default class LeftAreaNav extends PureComponent<LeftAreaNavProps> {
|
||||
static displayName = 'LowcodeLeftAreaNav';
|
||||
|
||||
private editor: Editor;
|
||||
private config: Array<PluginConfig>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editor = props.editor;
|
||||
this.config =
|
||||
this.editor.config.plugins && this.editor.config.plugins.leftArea;
|
||||
this.config = (this.editor.config.plugins && this.editor.config.plugins.leftArea) || [];
|
||||
}
|
||||
|
||||
handlePluginClick = item => {};
|
||||
|
||||
renderPluginList = (list = []) => {
|
||||
renderPluginList = (list: Array<PluginConfig> = []): Array<React.ReactElement> => {
|
||||
return list.map((item, idx) => {
|
||||
return (
|
||||
<LeftPlugin
|
||||
@ -29,11 +37,10 @@ export default class LeftAreaPanel extends PureComponent {
|
||||
};
|
||||
|
||||
render() {
|
||||
const topList = [];
|
||||
const bottomList = [];
|
||||
const topList: Array<PluginConfig> = [];
|
||||
const bottomList: Array<PluginConfig> = [];
|
||||
this.config.forEach(item => {
|
||||
const align =
|
||||
item.props && item.props.align === 'bottom' ? 'bottom' : 'top';
|
||||
const align = item.props && item.props.align === 'bottom' ? 'bottom' : 'top';
|
||||
if (align === 'bottom') {
|
||||
bottomList.push(item);
|
||||
} else {
|
||||
|
||||
@ -1,18 +1,30 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
import Panel from '../../components/Panel';
|
||||
import './index.scss';
|
||||
import Editor from '../../../framework/editor';
|
||||
import { PluginConfig } from '../../../framework/definitions';
|
||||
|
||||
export default class LeftAreaPanel extends PureComponent {
|
||||
static displayName = 'lowcodeLeftAreaPanel';
|
||||
export interface LeftAreaPanelProps {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
export interface LeftAreaPanelState {
|
||||
activeKey: string;
|
||||
}
|
||||
|
||||
export default class LeftAreaPanel extends PureComponent<LeftAreaPanelProps, LeftAreaPanelState> {
|
||||
static displayName = 'LowcodeLeftAreaPanel';
|
||||
|
||||
private editor: Editor;
|
||||
private config: Array<PluginConfig>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editor = props.editor;
|
||||
this.config =
|
||||
this.editor.config.plugins && this.editor.config.plugins.leftArea;
|
||||
this.config = (this.editor.config.plugins && this.editor.config.plugins.leftArea) || [];
|
||||
|
||||
this.state = {
|
||||
activeKey: 'leftPanelIcon',
|
||||
activeKey: 'leftPanelIcon'
|
||||
};
|
||||
}
|
||||
|
||||
@ -25,10 +37,7 @@ export default class LeftAreaPanel extends PureComponent {
|
||||
{list.map((item, idx) => {
|
||||
const Comp = this.editor.components[item.pluginKey];
|
||||
return (
|
||||
<Panel
|
||||
key={item.pluginKey}
|
||||
visible={item.pluginKey === this.state.activeKey}
|
||||
>
|
||||
<Panel key={item.pluginKey} visible={item.pluginKey === this.state.activeKey}>
|
||||
<Comp editor={this.editor} config={item} />
|
||||
</Panel>
|
||||
);
|
||||
|
||||
@ -1,44 +1,52 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Tab } from '@alifd/next';
|
||||
import './index.scss';
|
||||
import Editor from '../../../framework/editor';
|
||||
import { PluginConfig } from '../../../framework/definitions';
|
||||
|
||||
export default class RightArea extends PureComponent {
|
||||
static displayName = 'lowcodeRightArea';
|
||||
export interface RightAreaProps {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
export interface RightAreaState {
|
||||
activeKey: string;
|
||||
}
|
||||
|
||||
export default class RightArea extends PureComponent<RightAreaProps, RightAreaState> {
|
||||
static displayName = 'LowcodeRightArea';
|
||||
|
||||
private editor: Editor;
|
||||
private config: Array<PluginConfig>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editor = props.editor;
|
||||
this.config = (this.editor.config.plugins && this.editor.config.plugins.rightArea) || [];
|
||||
this.state = {
|
||||
activeKey: 'rightPanel1',
|
||||
activeKey: 'rightPanel1'
|
||||
};
|
||||
}
|
||||
|
||||
handleTabChange = key => {
|
||||
handleTabChange = (key: string): void => {
|
||||
this.setState({
|
||||
activeKey: key,
|
||||
activeKey: key
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const list =
|
||||
(this.editor &&
|
||||
this.editor.config &&
|
||||
this.editor.config.plugins &&
|
||||
this.editor.config.plugins.rightArea) ||
|
||||
[];
|
||||
return (
|
||||
<div className="lowcode-right-area">
|
||||
<Tab
|
||||
shape="wrapped"
|
||||
className="right-tabs"
|
||||
style={{
|
||||
height: '100%',
|
||||
height: '100%'
|
||||
}}
|
||||
activeKey={this.state.activeKey}
|
||||
lazyLoad={false}
|
||||
onChange={this.handleTabChange}
|
||||
>
|
||||
{list.map((item, idx) => {
|
||||
{this.config.map((item, idx) => {
|
||||
const Comp = this.editor.components[item.pluginKey];
|
||||
return (
|
||||
<Tab.Item key={item.pluginKey} title={item.props.title}>
|
||||
|
||||
@ -2,17 +2,25 @@ import React, { PureComponent } from 'react';
|
||||
import { Grid } from '@alifd/next';
|
||||
import TopPlugin from '../../components/TopPlugin';
|
||||
import './index.scss';
|
||||
import Editor from '../../../framework/index';
|
||||
import { PluginConfig } from '../../../framework/definitions';
|
||||
|
||||
const { Row, Col } = Grid;
|
||||
|
||||
export default class TopArea extends PureComponent {
|
||||
static displayName = 'lowcodeTopArea';
|
||||
export interface TopAreaProps {
|
||||
editor: Editor;
|
||||
}
|
||||
|
||||
export default class TopArea extends PureComponent<TopAreaProps> {
|
||||
static displayName = 'LowcodeTopArea';
|
||||
|
||||
private editor: Editor;
|
||||
private config: Array<PluginConfig>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editor = props.editor;
|
||||
this.config =
|
||||
this.editor.config.plugins && this.editor.config.plugins.topArea;
|
||||
this.config = (this.editor.config.plugins && this.editor.config.plugins.topArea) || [];
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
@ -20,7 +28,7 @@ export default class TopArea extends PureComponent {
|
||||
|
||||
handlePluginStatusChange = () => {};
|
||||
|
||||
renderPluginList = (list = []) => {
|
||||
renderPluginList = (list: Array<PluginConfig> = []): Array<React.ReactElement> => {
|
||||
return list.map((item, idx) => {
|
||||
const isDivider = item.type === 'Divider';
|
||||
return (
|
||||
@ -29,15 +37,11 @@ export default class TopArea extends PureComponent {
|
||||
key={isDivider ? idx : item.pluginKey}
|
||||
style={{
|
||||
width: (item.props && item.props.width) || 40,
|
||||
flex: 'none',
|
||||
flex: 'none'
|
||||
}}
|
||||
>
|
||||
{!isDivider && (
|
||||
<TopPlugin
|
||||
config={item}
|
||||
pluginClass={this.editor.components[item.pluginKey]}
|
||||
editor={this.editor}
|
||||
/>
|
||||
<TopPlugin config={item} pluginClass={this.editor.components[item.pluginKey]} editor={this.editor} />
|
||||
)}
|
||||
</Col>
|
||||
);
|
||||
@ -46,19 +50,14 @@ export default class TopArea extends PureComponent {
|
||||
|
||||
render() {
|
||||
if (!this.config) return null;
|
||||
const leftList = [];
|
||||
const rightList = [];
|
||||
const leftList: Array<PluginConfig> = [];
|
||||
const rightList: Array<PluginConfig> = [];
|
||||
this.config.forEach(item => {
|
||||
const align =
|
||||
item.props && item.props.align === 'right' ? 'right' : 'left';
|
||||
const align = item.props && item.props.align === 'right' ? 'right' : 'left';
|
||||
// 分隔符不允许相邻
|
||||
if (item.type === 'Divider') {
|
||||
const currList = align === 'right' ? rightList : leftList;
|
||||
if (
|
||||
currList.length === 0 ||
|
||||
currList[currList.length - 1].type === 'Divider'
|
||||
)
|
||||
return;
|
||||
if (currList.length === 0 || currList[currList.length - 1].type === 'Divider') return;
|
||||
}
|
||||
if (align === 'right') {
|
||||
rightList.push(item);
|
||||
|
||||
@ -6,5 +6,5 @@ export default {
|
||||
pageNotExist: 'The current Page not exist',
|
||||
enterFromAppCenter: 'Please enter from the app center',
|
||||
noPermission: 'Sorry, you do not have the develop permission',
|
||||
getPermission: 'Please connect the app owners {owners} to get the permission',
|
||||
getPermission: 'Please connect the app owners {owners} to get the permission'
|
||||
};
|
||||
|
||||
@ -6,5 +6,5 @@ export default {
|
||||
pageNotExist: '当前访问地址不存在',
|
||||
enterFromAppCenter: '请从应用中心入口重新进入',
|
||||
noPermission: '抱歉,您暂无开发权限',
|
||||
getPermission: '请移步应用中心申请开发权限, 或联系 {owners} 开通权限',
|
||||
getPermission: '请移步应用中心申请开发权限, 或联系 {owners} 开通权限'
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user