polyfill panes

This commit is contained in:
kangwei 2020-04-15 01:47:16 +08:00
commit e49a02e37c
10 changed files with 685 additions and 1 deletions

View File

@ -157,7 +157,7 @@ export class Selection {
return nodes;
}
onSelectionChange(fn: () => void): () => void {
onSelectionChange(fn: (ids: string[]) => void): () => void {
this.emitter.on('selectionchange', fn);
return () => {
this.emitter.removeListener('selectionchange', fn);

View File

@ -0,0 +1,134 @@
import bus from '../bus';
import SchemaManager from './schemaManager';
import VisualDesigner from './visualDesigner';
import VisualManager from './visualManager';
import { findIndex, get, unionBy, uniqueId } from 'lodash';
export type removeEventListener = () => void;
export interface IEventNameMap {
[eventName: string]: string | symbol;
}
export interface ISchemaController {
getSchemaManager(): SchemaManager;
getSchemaManagerById(id?: string): SchemaManager;
getSchemaManagerByName(name?: string): SchemaManager[];
getSchemaManagerList(): SchemaManager[];
connectSchemaManager(manager: SchemaManager): this;
connectSchemaManagerList(managerList: SchemaManager[]): this;
notifyAllSchemaManagers(eventName: string | symbol, eventData: any): boolean;
}
export interface IManagerController {
getManager(): VisualManager;
getManagerById(id?: string): VisualManager;
getManagerByName(name?: string): VisualManager[];
getManagerList(name?: string): VisualManager[];
connectManager(manager: VisualManager): this;
connectManagerList(managerList: VisualManager[]): this;
notifyAllManagers(eventName: string | symbol, eventData: any): boolean;
}
export interface IDesignerController {
getDesigner(): VisualDesigner;
getDesignerById(id?: string): VisualDesigner;
getDesignerByName(name?: string): VisualDesigner[];
getDesignerList(): VisualDesigner[];
connectDesigner(designer: VisualDesigner): this;
connectDesignerList(designerList: VisualDesigner[]): this;
notifyAllDesigners(eventName: string | symbol, eventData: any): boolean;
}
export interface INameable {
getName(): string;
getId(): string;
setName(name?: string): this;
}
export interface IObservable {
getEventMap(): IEventNameMap;
on(eventName: string | symbol, callback: () => any): removeEventListener;
emit(eventName: string | symbol, eventData?: any[]): boolean;
}
export interface IManagerConfigs {
name?: string;
disableEvents?: boolean;
emitter?: IEmitter;
}
export interface IEmitter {
on(eventName: string | symbol, callback: () => any): removeEventListener;
emit(eventName: string | symbol, eventData?: any): boolean;
removeListener(eventName: string | symbol, callback: () => any): any;
}
export function connectGeneralManager(manager: any, managerList: any[]) {
const index = findIndex(managerList, (m) => m.getId() === manager.getId());
if (index > -1) {
managerList.push(manager);
} else {
managerList.splice(index, 1, manager);
}
return managerList;
}
export function connectGeneralManagerList(managerList: any[], sourceManagerList: any[]): any {
return unionBy(sourceManagerList, managerList, (manager) => manager.getId());
}
export class BaseManager implements INameable, IObservable {
static EVENTS: IEventNameMap = {};
static NAME = 'BaseManager';
private name: string;
private id: string;
private emitter: any;
constructor(managerConfigs: IManagerConfigs = {}) {
this.name = managerConfigs.name || get(this, 'constructor', 'NAME');
this.id = uniqueId(this.name);
if (!managerConfigs.disableEvents) {
if (managerConfigs.emitter) {
// 使用自定义的满足 EventEmitter 接口要求的自定义事件对象
this.emitter = managerConfigs.emitter;
} else {
// Bus 为单例模式
this.emitter = bus;
}
}
}
getId(): string {
return this.id;
}
setName(name: string): this {
this.name = name;
return this;
}
getName(): string {
return this.name;
}
getEventMap() {
/**
* Hack for get current constructor
* because if we write this.constructor.EVENTS
* ts compiler will show compiled error
*/
return get(this, 'constructor', BaseManager.EVENTS);
}
on(eventName: string | symbol, callback: () => any): removeEventListener {
this.emitter.on(eventName, callback);
return () => this.emitter.removeListener(eventName, callback);
}
emit(eventName: string | symbol, ...eventData: any[]): boolean {
return this.emitter.emit.call(this.emitter, eventName, ...eventData);
}
}

View File

@ -0,0 +1,44 @@
/**
* Storage the const variables
*/
/**
* Global
*/
export const VERSION = '5.3.0';
/**
* schema version defined in alibaba
*/
export const ALI_SCHEMA_VERSION = '1.0.0';
export const VE_EVENTS = {
/**
* node props to be dynamically replaced
* @event props the new props object been replaced
*/
VE_NODE_CREATED: 've.node.created',
VE_NODE_DESTROY: 've.node.destroyed',
VE_NODE_PROPS_REPLACE: 've.node.props.replaced',
// copy / clone node
VE_OVERLAY_ACTION_CLONE_NODE: 've.overlay.cloneElement',
// remove / delete node
VE_OVERLAY_ACTION_REMOVE_NODE: 've.overlay.removeElement',
// one page successfully mount on the DOM
VE_PAGE_PAGE_READY: 've.page.pageReady',
};
export const VE_HOOKS = {
// a decorator function
VE_NODE_PROPS_DECORATOR: 've.leaf.props.decorator',
// a remove callback function
VE_NODE_REMOVE_HELPER: 've.outline.actions.removeHelper',
/**
* provide customization field
*/
VE_SETTING_FIELD_PROVIDER: 've.settingField.provider',
/**
* VariableSetter for variable mode of a specified prop
*/
VE_SETTING_FIELD_VARIABLE_SETTER: 've.settingField.variableSetter',
};

View File

@ -0,0 +1,102 @@
import { cloneDeep, find } from 'lodash';
import {
BaseManager,
connectGeneralManager,
connectGeneralManagerList,
IManagerController,
ISchemaController,
} from './base';
import VisualManager from './visualManager';
export default class SchemaManager extends BaseManager implements IManagerController, ISchemaController {
private schemaData: object = {};
private visualManagerList: VisualManager[] = [];
private schemaManagerList: SchemaManager[] = [];
getManager(): VisualManager {
return this.visualManagerList[0];
}
getManagerByName(name?: string): VisualManager[] {
return this.visualManagerList.filter((m) => m.getName() === name);
}
getManagerById(id?: string): VisualManager {
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
}
getManagerList(): VisualManager[] {
return this.visualManagerList;
}
getSchemaManager(): SchemaManager {
return this.schemaManagerList[0];
}
getSchemaManagerById(id?: string): SchemaManager {
return find(this.schemaManagerList, (m) => m.getId() === id) as SchemaManager;
}
getSchemaManagerByName(name?: string): SchemaManager[] {
return this.schemaManagerList.filter((m) => m.getName() === name);
}
getSchemaManagerList() {
return this.schemaManagerList;
}
connectManager(manager: any) {
connectGeneralManager.call(this, manager, this.visualManagerList as any);
return this;
}
connectSchemaManager(manager: SchemaManager): this {
connectGeneralManager.call(this, manager, this.schemaManagerList);
return this;
}
connectManagerList(managerList: VisualManager[]): this {
this.visualManagerList = connectGeneralManagerList.call(this, managerList as any, this.visualManagerList as any);
return this;
}
connectSchemaManagerList(managerList: SchemaManager[]): this {
this.schemaManagerList = connectGeneralManagerList.call(this, managerList, this.schemaManagerList);
return this;
}
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
}
notifyAllSchemaManagers(eventName: string | symbol, ...eventData: any[]): boolean {
return this.schemaManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
}
exportSchema(): string {
try {
return JSON.stringify(this.schemaData);
} catch (e) {
throw new Error(e.message);
}
}
exportSchemaObject(): object {
return cloneDeep(this.schemaData);
}
importSchema(schemaString: string): this {
try {
this.schemaData = JSON.parse(schemaString);
return this;
} catch (e) {
throw new Error(e.message);
}
}
importSchemaObject(schema: object): this {
this.schemaData = schema;
return this;
}
}

View File

@ -0,0 +1,110 @@
import { assign, find, get } from 'lodash';
import { Component } from 'react';
import bus from '../bus';
import {
BaseManager,
connectGeneralManager,
connectGeneralManagerList,
IEmitter,
IEventNameMap,
IManagerController,
INameable,
IObservable,
} from './base';
import VisualManager from './visualManager';
interface IDesignerProps {
name?: string;
visualManagers?: VisualManager[];
emitter?: IEmitter;
}
export default class VisualDesigner extends Component implements IManagerController, IObservable, INameable {
static NAME = 'VisualDesigner';
static EVENTS: IEventNameMap = {};
props: IDesignerProps = {};
defaultProps: IDesignerProps = {
name: 'defaultDesigner',
visualManagers: [],
};
private visualManagerList: VisualManager[] = [];
private name = '';
private id = '';
private emitter: IEmitter;
constructor(props: IDesignerProps) {
super(props);
this.setName(props.name || get(this, 'constructor', 'NAME'));
this.connectManagerList(this.props.visualManagers as any);
if (props.emitter) {
// 使用自定义的满足 EventEmitter 接口要求的自定义事件对象
this.emitter = props.emitter;
} else {
this.emitter = bus;
}
}
getId(): string {
return this.id;
}
setName(name: string): this {
this.name = name;
return this;
}
getName() {
return this.name;
}
getManager(): VisualManager {
return this.visualManagerList[0];
}
getManagerByName(name?: string): VisualManager[] {
return this.visualManagerList.filter((m) => m.getName() === name);
}
getManagerById(id: string): VisualManager {
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
}
getManagerList(): VisualManager[] {
return this.visualManagerList;
}
connectManager(manager: VisualManager) {
connectGeneralManager.call(this, manager, this.visualManagerList);
return this;
}
connectManagerList(managerList: VisualManager[]): this {
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
return this;
}
getEventMap() {
/**
* Hack for get current constructor
* because if we write this.constructor.EVENTS
* ts compiler will show compiled error
*/
return get(this, 'constructor', BaseManager.EVENTS);
}
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
}
on(eventName: string | symbol, callback: () => any) {
this.emitter.on(eventName, callback);
return () => this.emitter.removeListener(eventName, callback);
}
emit(eventName: string | symbol, ...eventData: any[]): boolean {
return this.emitter.emit.call(this.emitter, eventName, ...eventData);
}
}

View File

@ -0,0 +1,79 @@
import { find } from 'lodash';
import {
BaseManager,
connectGeneralManager,
connectGeneralManagerList,
IDesignerController,
IManagerController,
} from './base';
import VisualDesigner from './visualDesigner';
export default class VisualManager extends BaseManager implements IManagerController, IDesignerController {
private visualManagerList: VisualManager[] = [];
private visualDesignerList: VisualDesigner[] = [];
getManager(): VisualManager {
return this.visualManagerList[0];
}
getManagerByName(name?: string): VisualManager[] {
return this.visualManagerList.filter((m) => m.getName() === name);
}
getManagerById(id?: string): VisualManager {
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
}
getManagerList(): VisualManager[] {
return this.visualManagerList;
}
getDesigner(): VisualDesigner {
return this.visualDesignerList[0];
}
getDesignerByName(name?: string): VisualDesigner[] {
return this.visualDesignerList.filter((m) => m.getName() === name);
}
getDesignerById(id?: string): VisualDesigner {
return find(this.visualDesignerList, (m) => m.getId() === id) as VisualDesigner;
}
getDesignerList() {
return this.visualDesignerList;
}
connectManager(manager: VisualManager) {
connectGeneralManager.call(this, manager, this.visualManagerList);
return this;
}
connectDesigner(manager: VisualDesigner): this {
connectGeneralManager.call(this, manager, this.visualDesignerList);
return this;
}
connectManagerList(managerList: VisualManager[]): this {
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
return this;
}
connectDesignerList(managerList: VisualDesigner[]): this {
this.visualDesignerList = connectGeneralManagerList.call(this, managerList, this.visualDesignerList);
return this;
}
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
return this.getManagerList()
.map((m) => m.emit(eventName, eventData))
.every((r) => r);
}
notifyAllDesigners(eventName: string | symbol, ...eventData: any[]): boolean {
return this.getDesignerList()
.map((m) => m.emit(eventName, eventData))
.every((r) => r);
}
}

View File

@ -0,0 +1,48 @@
import { find } from 'lodash';
import { BaseManager, connectGeneralManager, connectGeneralManagerList, IManagerController } from './base';
import VisualManager from './visualManager';
export default class VisualRender extends BaseManager implements IManagerController {
private visualManagerList: VisualManager[] = [];
getManager(): VisualManager {
return this.visualManagerList[0];
}
getManagerByName(name?: string): VisualManager[] {
return this.visualManagerList.filter((m) => m.getName() === name);
}
getManagerById(id?: string): VisualManager {
return find(this.visualManagerList, (m) => m.getId() === id) as VisualManager;
}
getManagerList(): VisualManager[] {
return this.visualManagerList;
}
connectManager(manager: VisualManager) {
connectGeneralManager.call(this, manager, this.visualManagerList);
return this;
}
connectManagerList(managerList: VisualManager[]): this {
this.visualManagerList = connectGeneralManagerList.call(this, managerList, this.visualManagerList);
return this;
}
notifyAllManagers(eventName: string | symbol, ...eventData: any[]): boolean {
return this.visualManagerList.map((m) => m.emit(eventName, eventData)).every((r) => r);
}
/**
* Render function
* @override
*
* @memberof VisualRender
*/
render(): any {
return '';
}
}

View File

@ -0,0 +1,104 @@
import { assign } from 'lodash';
import { Component, ReactElement } from 'react';
import VisualManager from './base/visualManager';
import Prototype from './bundle/prototype';
// TODO: Env 本地引入后需要兼容方法 getDesignerLocale
// import Env from './env';
let contextInstance: VisualEngineContext;
// prop is Prop object in Designer
export type SetterProvider = (prop: any, componentPrototype: Prototype) => Component | ReactElement<any>;
export default class VisualEngineContext {
private managerMap: { [name: string]: VisualManager } = {};
private moduleMap: { [name: string]: any } = {};
private pluginsMap: { [name: string]: any } = {};
constructor() {
if (!contextInstance) {
contextInstance = this;
} else {
return contextInstance;
}
}
use(pluginName: string, plugin: any) {
this.pluginsMap[pluginName || 'unknown'] = plugin;
}
getPlugin(name: string) {
if (!name) {
name = 'default';
}
if (this.pluginsMap[name]) {
return this.pluginsMap[name];
} else if (this.moduleMap[name]) {
return this.moduleMap[name];
}
return this.getManager(name);
}
registerManager(managerMap?: { [name: string]: VisualManager }): this;
registerManager(name: string, manager: VisualManager): this;
registerManager(name?: any, manager?: VisualManager): this {
if (name && typeof name === 'object') {
this.managerMap = assign(this.managerMap, name);
} else {
this.managerMap[name] = manager as VisualManager;
}
return this;
}
registerModule(moduleMap: { [name: string]: any }): this;
registerModule(name: string, module: any): this;
registerModule(name?: any, module?: any): this {
if (typeof name === 'object') {
this.moduleMap = Object.assign({}, this.moduleMap, name);
} else {
this.moduleMap[name] = module;
}
return this;
}
getManager(name: string): VisualManager {
return this.managerMap[name];
}
getModule(name: string): any {
return this.moduleMap[name];
}
// getDesignerLocale(): string {
// return Env.getLocale();
// }
/**
* Builtin APIs
*/
/**
* support dynamic setter replacement
*/
registerDynamicSetterProvider(setterProvider: SetterProvider) {
if (!setterProvider) {
console.error('ERROR: ', 'please set provider function.');
return;
}
this.use('ve.plugin.setterProvider', setterProvider);
}
/**
* support add treePane on the setting pane
* @param treePane see @ali/ve-tree-pane
* @param treeCore see @ali/ve-tree-pane
*/
registerTreePane(TreePane: Component, TreeCore: Component) {
if (TreePane && TreeCore) {
this.registerModule('TreePane', TreePane);
this.registerModule('TreeCore', TreeCore);
}
}
}

View File

@ -0,0 +1,51 @@
import { Selection, DocumentModel, Node } from '@ali/lowcode-designer';
import editor from './editor';
let currentSelection: Selection;
// let currentDocument: DocumentModel;
// get selection async
editor.once('designer.ready', () => {
const getSelection = () => {
if (editor.designer.currentSelection) {
currentSelection = editor.designer.currentSelection;
// currentDocument = editor.designer.currentDocument;
currentSelection.onSelectionChange((ids: string[]) => {
// console.log(ids);
// const nodes = ids.map((id: string) => currentDocument.getNode(id));
// console.log(nodes);
});
} else {
console.log('waiting ...');
requestAnimationFrame(getSelection);
}
};
getSelection();
});
export default {
select: (node: Node) => {
if (!node) {
return currentSelection.clear();
}
currentSelection.select(node.id);
},
getSelected: () => {
const nodes = currentSelection.getNodes();
return nodes;
},
// 以下废弃
// hover: (node: Node) => {
// hovering.hover(node);
// },
// getDropping: () => {
// return null;
// },
// onIntoView: (func: (node: any, insertion: Insertion) => any) => {
// currentSelection.onSelectionChange((ids) => {
// console.log(ids);
// });
// return null;
// },
}

View File

@ -9,6 +9,9 @@ import Symbols from './symbols';
import { editor, skeleton } from './editor';
import { VisionWorkbench } from './skeleton/workbench';
import Panes from './panes';
import Exchange from './exchange';
import VisualEngineContext from './context';
import VisualManager from './base/visualManager';
function init(container?: Element) {
if (!container) {
@ -31,6 +34,12 @@ const ui = {
Popup,
};
const modules = {
VisualManager,
};
const context = new VisualEngineContext();
export {
/**
* VE.Popup
@ -48,6 +57,8 @@ export {
HOOKS,
/* Symbol 管理类 */
Symbols,
Exchange,
context,
/**
* VE.init
*
@ -56,4 +67,5 @@ export {
init,
ui,
Panes,
modules,
};