fix outline backup mode

This commit is contained in:
kangwei 2020-05-10 03:57:38 +08:00
parent e1d3f1e5a6
commit f75a51e77e
17 changed files with 185 additions and 170 deletions

View File

@ -331,6 +331,12 @@ body {
display: none;
flex-shrink: 0;
margin-left: 2px;
position: relative;
>.lc-panel {
position: absolute;
left: 0;
top: 0;
}
&.lc-area-visible {
display: block;
}

View File

@ -110,7 +110,7 @@ export class Skeleton {
}
return this.createPanel(config);
},
true,
false,
true,
);
this.mainArea = new Area(

View File

@ -1,5 +1,6 @@
import { ReactElement, ComponentType } from 'react';
import { TitleContent, IconType, I18nData, TipContent } from '@ali/lowcode-types';
import { IWidget } from './widget/widget';
export interface IWidgetBaseConfig {
type: string;
@ -16,6 +17,7 @@ export interface WidgetConfig extends IWidgetBaseConfig {
type: "Widget";
props?: {
align?: "left" | "right" | "bottom" | "center" | "top";
onInit?: (widget: IWidget) => void;
};
content?: string | ReactElement | ComponentType<any>; // children
}
@ -47,6 +49,7 @@ export function isDividerConfig(obj: any): obj is DividerConfig {
export interface IDockBaseConfig extends IWidgetBaseConfig {
props?: DockProps & {
align?: "left" | "right" | "bottom" | "center" | "top";
onInit?: (widget: IWidget) => void;
};
}
@ -95,7 +98,8 @@ export interface PanelProps {
height?: number; // panel.props
maxWidth?: number; // panel.props
maxHeight?: number; // panel.props
onInit?: () => any;
condition?: (widget: IWidget) => any;
onInit?: (widget: IWidget) => any;
onDestroy?: () => any;
shortcut?: string; // 只有在特定位置,可触发 toggle show
}

View File

@ -46,7 +46,7 @@ export default class Dock implements IWidget {
this._body = createElement(DockView, props);
}
this.inited = true;
return this._body;
}
@ -54,6 +54,9 @@ export default class Dock implements IWidget {
const { props = {}, name } = config;
this.name = name;
this.align = props.align;
if (props.onInit) {
props.onInit.call(this, this);
}
}
setVisible(flag: boolean) {

View File

@ -83,6 +83,9 @@ export default class PanelDock implements IWidget {
area: panelProps?.area,
}) as Panel;
}
if (props?.onInit) {
props.onInit.call(this, this);
}
}
setVisible(flag: boolean) {

View File

@ -1,6 +1,6 @@
import { EventEmitter } from 'events';
import { createElement, ReactNode } from 'react';
import { obx } from '@ali/lowcode-editor-core';
import { obx, computed } from '@ali/lowcode-editor-core';
import { uniqueId, createContent } from '@ali/lowcode-utils';
import { TitleContent } from '@ali/lowcode-types';
import WidgetContainer from './widget-container';
@ -16,14 +16,18 @@ export default class Panel implements IWidget {
readonly name: string;
readonly id: string;
@obx.ref inited = false;
@obx.ref private _actived = false;
@obx.ref private _actived: boolean = false;
private emitter = new EventEmitter();
get actived(): boolean {
return this._actived;
}
get visible(): boolean {
if (this.parent?.visible) {
@computed get visible(): boolean {
if (!this.parent || this.parent.visible) {
const { props } = this.config;
if (props?.condition) {
return props.condition(this);
}
return this._actived;
}
return false;
@ -80,6 +84,9 @@ export default class Panel implements IWidget {
);
content.forEach((item) => this.add(item));
}
if (props.onInit) {
props.onInit.call(this, this);
}
// todo: process shortcut
}

View File

@ -60,6 +60,9 @@ export default class Widget implements IWidget {
const { props = {}, name } = config;
this.name = name;
this.align = props.align;
if (props.onInit) {
props.onInit.call(this, this);
}
}
getId() {

View File

@ -1,6 +1,8 @@
import Pane from './views/pane';
import { OutlinePane } from './views/pane';
import { OutlineBackupPane } from './views/backup-pane';
import { IconOutline } from './icons/outline';
import { intlNode } from './locale';
import { getTreeMaster } from './tree-master';
export default {
name: 'outline-pane',
@ -8,9 +10,7 @@ export default {
icon: IconOutline,
description: intlNode('Outline Tree'),
},
content: Pane,
content: OutlinePane,
};
export { getTreeMaster } from './main';
export { Pane };
export { OutlinePane, OutlineBackupPane, getTreeMaster };

View File

@ -1,5 +1,4 @@
import { EventEmitter } from 'events';
import { computed, obx, Editor } from '@ali/lowcode-editor-core';
import { computed, obx } from '@ali/lowcode-editor-core';
import {
Designer,
ISensor,
@ -18,108 +17,15 @@ import {
contains,
Node,
} from '@ali/lowcode-designer';
import { Tree } from './tree';
import TreeNode from './tree-node';
import { IndentTrack } from './helper/indent-track';
import DwellTimer from './helper/dwell-timer';
import { uniqueId } from '@ali/lowcode-utils';
import { Backup } from './views/backup-pane';
import { IEditor } from '@ali/lowcode-types';
import { ITreeBoard, TreeMaster, getTreeMaster } from './tree-master';
export interface IScrollBoard {
scrollToNode(treeNode: TreeNode, detail?: any): void;
}
class TreeMaster {
private emitter = new EventEmitter();
private currentFixed?: OutlineMain;
constructor(readonly designer: Designer) {
designer.dragon.onDragstart((e) => {
const tree = this.currentTree;
if (tree) {
tree.document.selection.getTopNodes().forEach((node) => {
tree.getTreeNode(node).setExpanded(false);
});
}
if (!this.currentFixed) {
this.emitter.emit('enable-builtin');
}
});
designer.activeTracker.onChange(({ node, detail }) => {
const tree = this.currentTree;
if (!tree || node.document !== tree.document) {
return;
}
const treeNode = tree.getTreeNode(node);
if (detail && isLocationChildrenDetail(detail)) {
treeNode.expand(true);
} else {
treeNode.expandParents();
}
this.boards.forEach((board) => {
board.scrollToNode(treeNode, detail);
});
});
}
setFixed(entry: OutlineMain) {
this.currentFixed = entry;
}
unFixed(entry: OutlineMain) {
if (entry === this.currentFixed) {
this.currentFixed = undefined;
}
}
onceEnableBuiltin(fn: () => void): () => void {
this.emitter.once('enable-builtin', fn);
return () => {
this.emitter.removeListener('enable-builtin', fn);
}
}
private boards = new Set<IScrollBoard>();
addBoard(board: IScrollBoard) {
this.boards.add(board);
}
removeBoard(board: IScrollBoard) {
this.boards.delete(board);
}
purge() {
this.emitter.removeAllListeners();
// todo others purge
}
private treeMap = new Map<string, Tree>();
@computed get currentTree(): Tree | null {
const doc = this.designer?.currentDocument;
if (doc) {
const id = doc.id;
if (this.treeMap.has(id)) {
return this.treeMap.get(id)!;
}
const tree = new Tree(doc);
// TODO: listen purge event to remove
this.treeMap.set(id, tree);
return tree;
}
return null;
}
}
const mastersMap = new Map<Designer, TreeMaster>();
export function getTreeMaster(designer: Designer): TreeMaster {
let master = mastersMap.get(designer);
if (!master) {
master = new TreeMaster(designer);
mastersMap.set(designer, master);
}
return master;
}
export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
private _designer?: Designer;
@obx.ref private _master?: TreeMaster;
get master() {
@ -130,8 +36,11 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
}
readonly id = uniqueId('outline');
private fixed = false;
constructor(readonly editor: Editor, at?: string) {
@obx.ref _visible: boolean = false;
get visible() {
return this._visible;
}
constructor(readonly editor: IEditor, readonly at: string | Symbol) {
let inited = false;
const setup = async () => {
if (inited) {
@ -142,29 +51,18 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
this.setupDesigner(designer);
};
// FIXME: dirty connect to others
if (at === '__IN_SETTINGS__') {
if (at === Backup) {
setup();
} else {
editor.on('skeleton.panel.show', (key: string) => {
if (key === at) {
setup();
if (this.master) {
this.master.setFixed(this);
} else {
this.fixed = true;
}
document.documentElement.classList.add('lowcode-has-fixed-tree');
this._visible = true;
}
});
editor.on('skeleton.panel.hide', (key: string) => {
if (key === at) {
document.documentElement.classList.remove('lowcode-has-fixed-tree');
if (this.master) {
this.master.unFixed(this);
} else {
this.fixed = false;
}
this._visible = false;
}
});
}
@ -628,9 +526,6 @@ export class OutlineMain implements ISensor, IScrollBoard, IScrollable {
this._designer = designer;
this._master = getTreeMaster(designer);
this._master.addBoard(this);
if (this.fixed) {
this._master.setFixed(this);
}
designer.dragon.addSensor(this);
this.scroller = designer.createScroller(this);
}

View File

@ -0,0 +1,93 @@
import { computed, obx } from '@ali/lowcode-editor-core';
import { Designer, isLocationChildrenDetail } from '@ali/lowcode-designer';
import TreeNode from './tree-node';
import { Tree } from './tree';
import { Backup } from './views/backup-pane';
export interface ITreeBoard {
readonly visible: boolean;
readonly at: string | Symbol;
scrollToNode(treeNode: TreeNode, detail?: any): void;
}
export class TreeMaster {
constructor(readonly designer: Designer) {
designer.dragon.onDragstart(() => {
// needs?
this.toVision();
});
designer.activeTracker.onChange(({ node, detail }) => {
const tree = this.currentTree;
if (!tree || node.document !== tree.document) {
return;
}
const treeNode = tree.getTreeNode(node);
if (detail && isLocationChildrenDetail(detail)) {
treeNode.expand(true);
} else {
treeNode.expandParents();
}
this.boards.forEach((board) => {
board.scrollToNode(treeNode, detail);
});
});
}
private toVision() {
const tree = this.currentTree;
if (tree) {
tree.document.selection.getTopNodes().forEach((node) => {
tree.getTreeNode(node).setExpanded(false);
});
}
}
@obx.val private boards = new Set<ITreeBoard>();
addBoard(board: ITreeBoard) {
this.boards.add(board);
}
removeBoard(board: ITreeBoard) {
this.boards.delete(board);
}
@computed hasVisibleTreeBoard() {
for (const item of this.boards) {
if (item.visible && item.at !== Backup) {
return true;
}
}
return false;
}
purge() {
// todo others purge
}
private treeMap = new Map<string, Tree>();
@computed get currentTree(): Tree | null {
const doc = this.designer?.currentDocument;
if (doc) {
const id = doc.id;
if (this.treeMap.has(id)) {
return this.treeMap.get(id)!;
}
const tree = new Tree(doc);
// TODO: listen purge event to remove
this.treeMap.set(id, tree);
return tree;
}
return null;
}
}
const mastersMap = new Map<Designer, TreeMaster>();
export function getTreeMaster(designer: Designer): TreeMaster {
let master = mastersMap.get(designer);
if (!master) {
master = new TreeMaster(designer);
mastersMap.set(designer, master);
}
return master;
}

View File

@ -1,28 +1,16 @@
import { PureComponent } from 'react';
import { PluginProps } from '@ali/lowcode-types';
import OutlinePane from './pane';
import { OutlinePane } from './pane';
export const Backup = Symbol.for('backup-outline');
export class OutlineBackupPane extends PureComponent<PluginProps> {
state = {
outlineInited: false,
};
private dispose = this.props.main.onceOutlineVisible(() => {
this.setState({
outlineInited: true,
});
});
componentWillUnmount() {
this.dispose();
}
render() {
if (!this.state.outlineInited) {
return null;
}
return (
<OutlinePane
editor={this.props.main.editor}
editor={this.props.editor}
config={{
name: '__IN_SETTINGS__',
name: Backup,
}}
/>
);

View File

@ -4,13 +4,11 @@ import { intl } from '../locale';
import { OutlineMain } from '../main';
import TreeView from './tree';
import './style.less';
import { IEditor } from '@ali/lowcode-types';
@observer
export default class OutlinePane extends Component<{ config: any; editor: any; inSettings?: boolean }> {
private main = new OutlineMain(
this.props.editor,
this.props.config.name || this.props.config.pluginKey,
);
export class OutlinePane extends Component<{ config: any; editor: IEditor }> {
private main = new OutlineMain(this.props.editor, this.props.config.name || this.props.config.pluginKey);
shouldComponentUpdate() {
return false;

View File

@ -2,6 +2,8 @@
height: 100%;
width: 100%;
position: relative;
z-index: 20;
background-color: white;
> .lc-outline-tree-container {
top: 0;

View File

@ -139,8 +139,6 @@ export interface Utils {
export interface PluginProps {
editor: IEditor;
config: PluginConfig;
i18n?: I18nFunction;
ref?: RefObject<ReactElement>;
[key: string]: any;
}

View File

@ -732,11 +732,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
const supports: any = {};
if (canUseCondition != null) {
console.info('canUseCondition', componentName);
supports.condition = canUseCondition;
}
if (canLoop != null) {
console.info('canLoop', componentName);
supports.loop = canLoop;
}
meta.configure = { props, component, supports };

View File

@ -2,7 +2,7 @@ import { isJSBlock, isJSExpression, isJSSlot } from '@ali/lowcode-types';
import { isPlainObject } from '@ali/lowcode-utils';
import { globalContext, Editor } from '@ali/lowcode-editor-core';
import { Designer, TransformStage, addBuiltinComponentAction } from '@ali/lowcode-designer';
import Outline from '@ali/lowcode-plugin-outline-pane';
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
import { toCss } from '@ali/vu-css-style';
import DesignerPlugin from '@ali/lowcode-plugin-designer';
@ -16,9 +16,11 @@ globalContext.register(editor, Editor);
export const skeleton = new Skeleton(editor);
editor.set(Skeleton, skeleton);
editor.set('skeleton', skeleton);
export const designer = new Designer({ editor: editor });
editor.set(Designer, designer);
editor.set('designer', designer);
// 节点 props 初始化
designer.addPropsReducer((props, node) => {
@ -146,6 +148,17 @@ skeleton.add({
area: 'leftFixedArea',
},
});
skeleton.add({
area: 'rightArea',
name: 'backupOutline',
type: 'Panel',
props: {
condition: () => {
return designer.dragon.dragging && !getTreeMaster(designer).hasVisibleTreeBoard();
}
},
content: OutlineBackupPane,
});
// skeleton.add({
// name: 'sourceEditor',

View File

@ -59,8 +59,6 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
title,
description,
align: place,
onInit: init,
onDestroy: destroy,
},
contentProps: props,
index: index || props?.index,
@ -84,6 +82,8 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
maxWidth,
height,
maxHeight,
onInit: init,
onDestroy: destroy,
};
if (contents && Array.isArray(contents)) {
@ -100,18 +100,22 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
});
}
}
} else if (type === 'action') {
newConfig.area = 'top';
newConfig.type = 'Dock';
} else if (type === 'tab') {
newConfig.area = 'right';
newConfig.type = 'Panel';
} else if (type === 'stage') {
newConfig.area = 'stages';
newConfig.type = 'Widget';
} else {
newConfig.area = 'main';
newConfig.type = 'Widget';
newConfig.props.onInit = init;
newConfig.props.onDestroy = destroy;
if (type === 'action') {
newConfig.area = 'top';
newConfig.type = 'Dock';
} else if (type === 'tab') {
newConfig.area = 'right';
newConfig.type = 'Panel';
} else if (type === 'stage') {
newConfig.area = 'stages';
newConfig.type = 'Widget';
} else {
newConfig.area = 'main';
newConfig.type = 'Widget';
}
}
return newConfig;