in packages/designer/src/builtin-simulator/live-editing/live-editing.ts [54:166]
apply(target: EditingTarget) {
const { node, event, rootElement } = target;
const targetElement = event.target as HTMLElement;
const { liveTextEditing } = node.componentMeta;
const editor = node.document?.designer.editor;
const npm = node?.componentMeta?.npm;
const selected =
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
editor?.eventBus.emit('designer.builtinSimulator.liveEditing', {
selected,
});
let setterPropElement = getSetterPropElement(targetElement, rootElement);
let propTarget = setterPropElement?.dataset.setterProp;
let matched: (IPublicTypePluginConfig & { propElement?: HTMLElement }) | undefined | null;
if (liveTextEditing) {
if (propTarget) {
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置(mode|onSaveContent)
matched = liveTextEditing.find(config => config.propTarget == propTarget);
} else {
// 执行 embedTextEditing selector 规则,获得第一个节点 是否 contains e.target,若匹配,读取配置
matched = liveTextEditing.find(config => {
if (!config.selector) {
return false;
}
setterPropElement = queryPropElement(rootElement, targetElement, config.selector);
return !!setterPropElement;
});
propTarget = matched?.propTarget;
}
} else {
specificRules.some((rule) => {
matched = rule(target);
return !!matched;
});
if (matched) {
propTarget = matched.propTarget;
setterPropElement = matched.propElement || queryPropElement(rootElement, targetElement, matched.selector);
}
}
// 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)!;
if (this._editing === prop) {
return;
}
// 进入编辑
// 1. 设置 contentEditable="plaintext|..."
// 2. 添加类名
// 3. focus & cursor locate
// 4. 监听 blur 事件
// 5. 设置编辑锁定:disable hover | disable select | disable canvas drag
const onSaveContent = matched?.onSaveContent || saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;
setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only');
setterPropElement.classList.add('engine-live-editing');
// be sure
setterPropElement.focus();
setCaret(event);
this._save = () => {
onSaveContent(setterPropElement!.innerText, prop);
};
const keydown = (e: KeyboardEvent) => {
console.info(e.code);
switch (e.code) {
case 'Enter':
break;
// TODO: check is richtext?
case 'Escape':
break;
case 'Tab':
setterPropElement?.blur();
}
// esc
// enter
// tab
};
const focusout = (/* e: FocusEvent */) => {
this.saveAndDispose();
};
setterPropElement.addEventListener('focusout', focusout);
setterPropElement.addEventListener('keydown', keydown, true);
this._dispose = () => {
setterPropElement!.classList.remove('engine-live-editing');
setterPropElement!.removeAttribute('contenteditable');
setterPropElement!.removeEventListener('focusout', focusout);
setterPropElement!.removeEventListener('keydown', keydown, true);
};
this._editing = prop;
}
// TODO: process enter | esc events & joint the FocusTracker
// TODO: upward testing for b/i/a html elements
}