Skip to content

Commit

Permalink
Track command execution to distinguish mutations from undo/redo
Browse files Browse the repository at this point in the history
  • Loading branch information
salmenf committed Oct 10, 2024
1 parent 979e918 commit c184af5
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 50 deletions.
95 changes: 54 additions & 41 deletions @webwriter/core/view/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 = {
Expand Down
13 changes: 4 additions & 9 deletions @webwriter/core/view/editor/nodeviews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -47,7 +47,7 @@ export class WidgetView implements NodeView {

// static existingWidgets = new Set()

constructor(node: Node, view: EditorViewController, getPos: () => number, readonly initializedElements: Set<string>) {
constructor(node: Node, view: EditorViewController, getPos: () => number, readonly editor: ExplorableEditor) {
this.node = node
this.view = view
this.getPos = getPos
Expand Down Expand Up @@ -117,7 +117,6 @@ export class WidgetView implements NodeView {
}

inTransaction = false
isMutating = false

get widgetIdPath() {
const ids = [this.dom.id]
Expand All @@ -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
}
Expand Down Expand Up @@ -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)]) {
Expand All @@ -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) {
Expand All @@ -211,7 +208,6 @@ export class WidgetView implements NodeView {
tr = tr.setNodeAttribute(this.getPos(), attr, final)
}
else {
this.isMutating = false
return true
}
}
Expand All @@ -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
Expand Down

0 comments on commit c184af5

Please sign in to comment.