diff --git a/@webwriter/core/view/editor/editor.ts b/@webwriter/core/view/editor/editor.ts index 7d1eaff..4bc8ccd 100644 --- a/@webwriter/core/view/editor/editor.ts +++ b/@webwriter/core/view/editor/editor.ts @@ -58,9 +58,20 @@ export class ExplorableEditor extends LitElement { @property({attribute: false}) app: App + executingCommand = false + exec = (command: PmCommand) => { - command(this.pmEditor.state, this.pmEditor.dispatch, this.pmEditor as any) - this.pmEditor.focus() + this.executingCommand = true + try { + command(this.pmEditor.state, this.pmEditor.dispatch, this.pmEditor as any) + this.pmEditor.focus() + } + catch(err) { + throw err + } + finally { + this.executingCommand = false + } } execInCodeEditor = (command: CmCommand) => command({state: this.cmEditor.state, dispatch: this.cmEditor.dispatch}) @@ -353,7 +364,7 @@ export class ExplorableEditor extends LitElement { (node: Node, view: EditorViewController, getPos: () => number) => new (nodeViews as any)[k](node, view, getPos), ]) const widgetViewEntries = widgetKeys - .map(key => [key, (node: Node, view: EditorViewController, getPos: () => number) => new WidgetView(node, view, getPos, this.initializedElements)]) + .map(key => [key, (node: Node, view: EditorViewController, getPos: () => number) => new WidgetView(node, view, getPos, this)]) this.cachedNodeViews = Object.fromEntries([...elementViewEntries, ...nodeViewEntries, ...widgetViewEntries]) return this.cachedNodeViews } @@ -862,44 +873,46 @@ export class ExplorableEditor extends LitElement { shouldBeEditable = (state: EditorState) => !this.ownerDocument.fullscreenElement setNodeAttribute(el: HTMLElement, key: string, value?: string | boolean, tag?: string) { - - const pos = this.pmEditor.posAtDOM(el, 0, 1) - 1 - const resolved = this.editorState.doc.resolve(pos) - const node = resolved.nodeAfter ?? resolved.nodeBefore - const builtinAttr = key in (this.editorState.schema.nodes[node!.type.name].spec.attrs ?? {}) - const dataAttr = key.startsWith("data-") - let v = value - if(value === true) { - v = "" - } - else if(value === false) { - v = undefined - } - let tr = this.editorState.tr - if(builtinAttr) { - tr = tr.setNodeMarkup( - pos, - tag? this.editorState.schema.nodes[tag]: undefined, - {...node!.attrs, [key]: v} - ) - // tr.setNodeAttribute(pos, key, v) - } - else if(dataAttr) { - tr = tr.setNodeMarkup( - pos, - tag? this.editorState.schema.nodes[tag]: undefined, - {...node!.attrs, data: {...node!.attrs.data, [key]: v}} - ) - } - else { - tr = tr.setNodeMarkup( - pos, - tag? this.editorState.schema.nodes[tag]: undefined, - {...node!.attrs, _: {...node!.attrs._, [key]: v}} - ) - } - this.pmEditor.dispatch(tr) - this.pmEditor.focus() + this.exec((state, dispatch, view) => { + const pos = this.pmEditor.posAtDOM(el, 0, 1) - 1 + const resolved = state.doc.resolve(pos) + const node = resolved.nodeAfter ?? resolved.nodeBefore + const builtinAttr = key in (state.schema.nodes[node!.type.name].spec.attrs ?? {}) + const dataAttr = key.startsWith("data-") + let v = value + if(value === true) { + v = "" + } + else if(value === false) { + v = undefined + } + let tr = state.tr + if(builtinAttr) { + tr = tr.setNodeMarkup( + pos, + tag? state.schema.nodes[tag]: undefined, + {...node!.attrs, [key]: v} + ) + // tr.setNodeAttribute(pos, key, v) + } + else if(dataAttr) { + tr = tr.setNodeMarkup( + pos, + tag? state.schema.nodes[tag]: undefined, + {...node!.attrs, data: {...node!.attrs.data, [key]: v}} + ) + } + else { + tr = tr.setNodeMarkup( + pos, + tag? state.schema.nodes[tag]: undefined, + {...node!.attrs, _: {...node!.attrs._, [key]: v}} + ) + } + this.pmEditor.dispatch(tr) + this.pmEditor.focus() + return true + }) } handleDOMEvents = { diff --git a/@webwriter/core/view/editor/nodeviews.ts b/@webwriter/core/view/editor/nodeviews.ts index 317a2e6..7647d3c 100644 --- a/@webwriter/core/view/editor/nodeviews.ts +++ b/@webwriter/core/view/editor/nodeviews.ts @@ -4,7 +4,7 @@ import { DOMParser, DOMSerializer, Fragment, Node, ResolvedPos, Slice, TagParseR import {LitElement, html, render} from "lit" import { EditorStateWithHead, getAttrs, globalHTMLAttributes, toAttributes } from "../../model" -import {EditorViewController} from "." +import {EditorViewController, ExplorableEditor} from "." import { selectParentNode } from "prosemirror-commands" import { filterObject, sameMembers, shallowCompare, browser } from "../../utility" import { readDOMChange } from "./prosemirror-view/domchange" @@ -47,7 +47,7 @@ export class WidgetView implements NodeView { // static existingWidgets = new Set() - constructor(node: Node, view: EditorViewController, getPos: () => number, readonly initializedElements: Set) { + constructor(node: Node, view: EditorViewController, getPos: () => number, readonly editor: ExplorableEditor) { this.node = node this.view = view this.getPos = getPos @@ -117,7 +117,6 @@ export class WidgetView implements NodeView { } inTransaction = false - isMutating = false get widgetIdPath() { const ids = [this.dom.id] @@ -137,7 +136,7 @@ export class WidgetView implements NodeView { if(oldName !== name) { return false } - if(this.isMutating) { + if(!this.editor.executingCommand) { this.node = node return true } @@ -184,7 +183,6 @@ export class WidgetView implements NodeView { if((type as any) === "selection") { return false } - this.isMutating = true if(type === "childList") { (this.view as any).domObserver.stop() for(const node of [...Array.from(addedNodes), ...Array.from(removedNodes)]) { @@ -194,7 +192,6 @@ export class WidgetView implements NodeView { } readDOMChange(this.view as any, this.getPos(), this.getPos() + this.node.nodeSize, true, Array.from(addedNodes)); (this.view as any).domObserver.start() - setTimeout(() => this.isMutating = false) return true } else if(attr && !attrUnchanged) { @@ -211,7 +208,6 @@ export class WidgetView implements NodeView { tr = tr.setNodeAttribute(this.getPos(), attr, final) } else { - this.isMutating = false return true } } @@ -226,11 +222,10 @@ export class WidgetView implements NodeView { const _ = {...this.node.attrs._, [attr]: value} tr = tr.setNodeAttribute(this.getPos(), "_", _) } - if(this.widgetIdPath.some(id => !this.initializedElements.has(id))) { + if(this.widgetIdPath.some(id => !this.editor.initializedElements.has(id))) { tr = tr.setMeta("addToHistory", false) } this.view.dispatch(tr) - setTimeout(() => this.isMutating = false) return true } return attrUnchanged