mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-20 15:38:32 +00:00
fix: panel visible time
This commit is contained in:
parent
ea62f12343
commit
18ac1fa4c4
@ -1,4 +1,5 @@
|
|||||||
import { obx } from '@ali/lowcode-editor-core';
|
import { obx } from '@ali/lowcode-editor-core';
|
||||||
|
import { LiveTextEditingConfig } from '@ali/lowcode-types';
|
||||||
import { Node, Prop } from '../../document';
|
import { Node, Prop } from '../../document';
|
||||||
|
|
||||||
const EDITOR_KEY = 'data-setter-prop';
|
const EDITOR_KEY = 'data-setter-prop';
|
||||||
@ -22,11 +23,45 @@ export class LiveEditing {
|
|||||||
const targetElement = event.target as HTMLElement;
|
const targetElement = event.target as HTMLElement;
|
||||||
const liveTextEditing = node.componentMeta.getMetadata().experimental?.liveTextEditing || [];
|
const liveTextEditing = node.componentMeta.getMetadata().experimental?.liveTextEditing || [];
|
||||||
|
|
||||||
const setterPropElement = getSetterPropElement(targetElement, rootElement);
|
let setterPropElement = getSetterPropElement(targetElement, rootElement);
|
||||||
const propTarget = setterPropElement?.dataset.setterProp;
|
let propTarget = setterPropElement?.dataset.setterProp;
|
||||||
if (setterPropElement && propTarget) {
|
let matched: LiveTextEditingConfig | undefined;
|
||||||
|
if (propTarget) {
|
||||||
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置(mode|onSaveContent)
|
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置(mode|onSaveContent)
|
||||||
const config = liveTextEditing.find(config => config.propTarget == propTarget);
|
matched = liveTextEditing.find(config => config.propTarget == propTarget);
|
||||||
|
} else {
|
||||||
|
// 执行 embedTextEditing selector 规则,获得第一个节点 是否 contains e.target,若匹配,读取配置
|
||||||
|
matched = liveTextEditing.find(config => {
|
||||||
|
if (!config.selector) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setterPropElement = config.selector === ':root' ? rootElement : rootElement.querySelector(config.selector);
|
||||||
|
if (!setterPropElement) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!setterPropElement.contains(targetElement)) {
|
||||||
|
// try selectorAll
|
||||||
|
setterPropElement = Array.from(rootElement.querySelectorAll(config.selector)).find(item => item.contains(targetElement)) as HTMLElement;
|
||||||
|
if (!setterPropElement) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
propTarget = matched?.propTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!propTarget) {
|
||||||
|
// 自动纯文本编辑满足一下情况:
|
||||||
|
// 1. children 内容都是 Leaf 且都是文本(一期)
|
||||||
|
// 2. DOM 节点是单层容器,子集都是文本节点 (已满足)
|
||||||
|
const isAllText = node.children?.every(item => {
|
||||||
|
return item.isLeaf() && item.getProp('children')?.type === 'literal';
|
||||||
|
});
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propTarget && setterPropElement) {
|
||||||
const prop = node.getProp(propTarget, true)!;
|
const prop = node.getProp(propTarget, true)!;
|
||||||
|
|
||||||
if (this._editing === prop) {
|
if (this._editing === prop) {
|
||||||
@ -40,21 +75,21 @@ export class LiveEditing {
|
|||||||
// 4. 监听 blur 事件
|
// 4. 监听 blur 事件
|
||||||
// 5. 设置编辑锁定:disable hover | disable select | disable canvas drag
|
// 5. 设置编辑锁定:disable hover | disable select | disable canvas drag
|
||||||
|
|
||||||
const onSaveContent = config?.onSaveContent || this.saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;
|
const onSaveContent = matched?.onSaveContent || this.saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;
|
||||||
|
|
||||||
setterPropElement.setAttribute('contenteditable', config?.mode && config.mode !== 'plaintext' ? 'true' : 'plaintext-only');
|
setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only');
|
||||||
setterPropElement.classList.add('engine-live-editing');
|
setterPropElement.classList.add('engine-live-editing');
|
||||||
// be sure
|
// be sure
|
||||||
setterPropElement.focus();
|
setterPropElement.focus();
|
||||||
setCaret(event);
|
setCaret(event);
|
||||||
|
|
||||||
this._save = () => {
|
this._save = () => {
|
||||||
onSaveContent(setterPropElement.innerText, prop);
|
onSaveContent(setterPropElement!.innerText, prop);
|
||||||
};
|
};
|
||||||
|
|
||||||
this._dispose = () => {
|
this._dispose = () => {
|
||||||
setterPropElement.removeAttribute('contenteditable');
|
setterPropElement!.removeAttribute('contenteditable');
|
||||||
setterPropElement.classList.remove('engine-live-editing');
|
setterPropElement!.classList.remove('engine-live-editing');
|
||||||
};
|
};
|
||||||
|
|
||||||
setterPropElement.addEventListener('focusout', (e) => {
|
setterPropElement.addEventListener('focusout', (e) => {
|
||||||
@ -62,32 +97,9 @@ export class LiveEditing {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this._editing = prop;
|
this._editing = prop;
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// 1) 自动纯文本编辑满足一下情况:
|
|
||||||
// 1. children 内容都是 Leaf 且都是文本(一期)
|
// TODO: upward testing for b/i/a html elements
|
||||||
// 2. DOM 节点是单层容器,子集都是文本节点
|
|
||||||
// 2) children 内容都是 Leaf 且都是文本(一期), 且 children 命中 embedTextEditing 配置(必须配置 selector)
|
|
||||||
// 3)
|
|
||||||
// 4) 执行 embedTextEditing selector 规则,或得第一个节点 是否 contains e.target,若匹配,读取配置,若不匹配,parentNode,closeat?
|
|
||||||
/*
|
|
||||||
embedTextEditing: Array<{
|
|
||||||
propTarget: string;
|
|
||||||
selector?: string;
|
|
||||||
// 编辑模式 纯文本|段落编辑|文章编辑(默认纯文本,无跟随工具条)
|
|
||||||
mode?: 'plaintext' | 'paragraph' | 'article';
|
|
||||||
// 从 contentEditable 获取内容并设置到属性
|
|
||||||
onSaveContent?: (content: string, prop: any) => any;
|
|
||||||
}>;
|
|
||||||
*/
|
|
||||||
// 进入编辑
|
|
||||||
// 1. 设置contentEditable="plaintext|..."
|
|
||||||
// 2. 添加类名
|
|
||||||
// 3. focus & cursor locate
|
|
||||||
// 4. 监听 blur 事件
|
|
||||||
// 5. 设置编辑锁定:disable hover | disable select | disable canvas drag
|
|
||||||
|
|
||||||
// 非文本编辑
|
// 非文本编辑
|
||||||
// 国际化数据,改变当前
|
// 国际化数据,改变当前
|
||||||
|
|||||||
@ -213,6 +213,10 @@ export class NodeChildren {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
every(fn: (item: Node, index: number) => any): boolean {
|
||||||
|
return this.children.every((child, index) => fn(child, index));
|
||||||
|
}
|
||||||
|
|
||||||
some(fn: (item: Node, index: number) => any): boolean {
|
some(fn: (item: Node, index: number) => any): boolean {
|
||||||
return this.children.some((child, index) => fn(child, index));
|
return this.children.some((child, index) => fn(child, index));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,10 +35,21 @@ export default class Panel implements IWidget {
|
|||||||
|
|
||||||
readonly isPanel = true;
|
readonly isPanel = true;
|
||||||
|
|
||||||
private _body?: ReactNode;
|
|
||||||
get body() {
|
get body() {
|
||||||
this.initBody();
|
if (this.container) {
|
||||||
return this._body;
|
return createElement(TabsPanelView, {
|
||||||
|
container: this.container,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { content, contentProps } = this.config;
|
||||||
|
return createContent(content, {
|
||||||
|
...contentProps,
|
||||||
|
editor: this.skeleton.editor,
|
||||||
|
config: this.config,
|
||||||
|
panel: this,
|
||||||
|
pane: this,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get content(): ReactNode {
|
get content(): ReactNode {
|
||||||
@ -90,27 +101,6 @@ export default class Panel implements IWidget {
|
|||||||
// todo: process shortcut
|
// todo: process shortcut
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBody() {
|
|
||||||
if (this.inited) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.inited = true;
|
|
||||||
if (this.container) {
|
|
||||||
this._body = createElement(TabsPanelView, {
|
|
||||||
container: this.container,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const { content, contentProps } = this.config;
|
|
||||||
this._body = createContent(content, {
|
|
||||||
...contentProps,
|
|
||||||
editor: this.skeleton.editor,
|
|
||||||
config: this.config,
|
|
||||||
panel: this,
|
|
||||||
pane: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setParent(parent: WidgetContainer) {
|
setParent(parent: WidgetContainer) {
|
||||||
if (parent === this.parent) {
|
if (parent === this.parent) {
|
||||||
return;
|
return;
|
||||||
@ -155,11 +145,11 @@ export default class Panel implements IWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (flag) {
|
if (flag) {
|
||||||
if (!this.inited) {
|
|
||||||
this.initBody();
|
|
||||||
}
|
|
||||||
this._actived = true;
|
this._actived = true;
|
||||||
this.parent?.active(this);
|
this.parent?.active(this);
|
||||||
|
if (!this.inited) {
|
||||||
|
this.inited = true;
|
||||||
|
}
|
||||||
this.emitter.emit('activechange', true);
|
this.emitter.emit('activechange', true);
|
||||||
} else if (this.inited) {
|
} else if (this.inited) {
|
||||||
this._actived = false;
|
this._actived = false;
|
||||||
|
|||||||
@ -77,14 +77,17 @@ export interface Experimental {
|
|||||||
|
|
||||||
// 纯文本编辑:如果 children 内容是
|
// 纯文本编辑:如果 children 内容是
|
||||||
// 文本编辑:配置
|
// 文本编辑:配置
|
||||||
liveTextEditing?: Array<{
|
liveTextEditing?: LiveTextEditingConfig[];
|
||||||
propTarget: string;
|
}
|
||||||
selector?: string;
|
|
||||||
// 编辑模式 纯文本|段落编辑|文章编辑(默认纯文本,无跟随工具条)
|
// thinkof Array
|
||||||
mode?: 'plaintext' | 'paragraph' | 'article';
|
export interface LiveTextEditingConfig {
|
||||||
// 从 contentEditable 获取内容并设置到属性
|
propTarget: string;
|
||||||
onSaveContent?: (content: string, prop: any) => any;
|
selector?: string;
|
||||||
}>;
|
// 编辑模式 纯文本|段落编辑|文章编辑(默认纯文本,无跟随工具条)
|
||||||
|
mode?: 'plaintext' | 'paragraph' | 'article';
|
||||||
|
// 从 contentEditable 获取内容并设置到属性
|
||||||
|
onSaveContent?: (content: string, prop: any) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Configure {
|
export interface Configure {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user