From 91e0a7d1e2c0fc1f7c57a9a29233128b617f1c1a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 26 Jan 2023 14:50:52 +0100 Subject: [PATCH] Pass editor view to updateDOM widget method. FEATURE: `WidgetType.updateDOM` is now passed the editor view object. See https://discuss.codemirror.net/t/is-view-requestmeasure-required-when-a-block-widget-changes-height/5604 --- src/blockview.ts | 11 ++++++----- src/contentview.ts | 11 +++-------- src/decoration.ts | 2 +- src/docview.ts | 4 +--- src/inlineview.ts | 17 +++++++++-------- 5 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/blockview.ts b/src/blockview.ts index 4967d70..853b056 100644 --- a/src/blockview.ts +++ b/src/blockview.ts @@ -5,6 +5,7 @@ import {clientRectsFor, Rect, clearAttributes} from "./dom" import {LineDecoration, WidgetType, BlockType} from "./decoration" import {Attrs, combineAttrs, attrsEq, updateAttrs} from "./attributes" import browser from "./browser" +import {EditorView} from "./editorview" import {Text} from "@codemirror/state" export interface BlockView extends ContentView { @@ -90,7 +91,7 @@ export class LineView extends ContentView implements BlockView { } } - sync(track?: {node: Node, written: boolean}) { + sync(view: EditorView, track?: {node: Node, written: boolean}) { if (!this.dom) { this.setDOM(document.createElement("div")) this.dom!.className = "cm-line" @@ -105,7 +106,7 @@ export class LineView extends ContentView implements BlockView { this.dom!.classList.add("cm-line") this.prevAttrs = undefined } - super.sync(track) + super.sync(view, track) let last = this.dom!.lastChild while (last && ContentView.get(last) instanceof MarkView) last = last.lastChild @@ -186,11 +187,11 @@ export class BlockWidgetView extends ContentView implements BlockView { get children() { return noChildren } - sync() { - if (!this.dom || !this.widget.updateDOM(this.dom)) { + sync(view: EditorView) { + if (!this.dom || !this.widget.updateDOM(this.dom, view)) { if (this.dom && this.prevWidget) this.prevWidget.destroy(this.dom) this.prevWidget = null - this.setDOM(this.widget.toDOM(this.editorView)) + this.setDOM(this.widget.toDOM(view)) this.dom!.contentEditable = "false" } } diff --git a/src/contentview.ts b/src/contentview.ts index 93678d4..d71c69b 100644 --- a/src/contentview.ts +++ b/src/contentview.ts @@ -31,11 +31,6 @@ export abstract class ContentView { abstract children: ContentView[] breakAfter!: number - get editorView(): EditorView { - if (!this.parent) throw new Error("Accessing view in orphan content view") - return this.parent.editorView - } - get overrideDOMText(): Text | null { return null } get posAtStart(): number { @@ -64,7 +59,7 @@ export abstract class ContentView { // given position. coordsAt(_pos: number, _side: number): Rect | null { return null } - sync(track?: {node: Node, written: boolean}) { + sync(view: EditorView, track?: {node: Node, written: boolean}) { if (this.dirty & Dirty.Node) { let parent = this.dom as HTMLElement let prev: Node | null = null, next @@ -75,7 +70,7 @@ export abstract class ContentView { if (!contentView || !contentView.parent && contentView.canReuseDOM(child)) child.reuseDOM(next) } - child.sync(track) + child.sync(view, track) child.dirty = Dirty.Not } next = prev ? prev.nextSibling : parent.firstChild @@ -92,7 +87,7 @@ export abstract class ContentView { while (next) next = rm(next) } else if (this.dirty & Dirty.Child) { for (let child of this.children) if (child.dirty) { - child.sync(track) + child.sync(view, track) child.dirty = Dirty.Not } } diff --git a/src/decoration.ts b/src/decoration.ts index 0f299ec..bd83424 100644 --- a/src/decoration.ts +++ b/src/decoration.ts @@ -105,7 +105,7 @@ export abstract class WidgetType { /// true to indicate that it could update, false to indicate it /// couldn't (in which case the widget will be redrawn). The default /// implementation just returns false. - updateDOM(dom: HTMLElement): boolean { return false } + updateDOM(dom: HTMLElement, view: EditorView): boolean { return false } /// @internal compare(other: WidgetType): boolean { diff --git a/src/docview.ts b/src/docview.ts index 0e8acd8..9bff727 100644 --- a/src/docview.ts +++ b/src/docview.ts @@ -43,8 +43,6 @@ export class DocView extends ContentView { // ourselves lastUpdate = Date.now() - get editorView() { return this.view } - get length() { return this.view.state.doc.length } constructor(readonly view: EditorView) { @@ -117,7 +115,7 @@ export class DocView extends ContentView { // selection from the one it displays (issue #218). This tries // to detect that situation. let track = browser.chrome || browser.ios ? {node: observer.selectionRange.focusNode!, written: false} : undefined - this.sync(track) + this.sync(this.view, track) this.dirty = Dirty.Not if (track && (track.written || observer.selectionRange.focusNode != track.node)) this.forceSelection = true this.dom.style.height = "" diff --git a/src/inlineview.ts b/src/inlineview.ts index af8223c..0670430 100644 --- a/src/inlineview.ts +++ b/src/inlineview.ts @@ -2,8 +2,9 @@ import {Text as DocText} from "@codemirror/state" import {ContentView, DOMPos, Dirty, mergeChildrenInto, noChildren} from "./contentview" import {WidgetType, MarkDecoration} from "./decoration" import {Rect, Rect0, flattenRect, textRange, clientRectsFor, clearAttributes, contains} from "./dom" -import {CompositionWidget} from "./docview" +import {CompositionWidget, DocView} from "./docview" import browser from "./browser" +import {EditorView} from "./editorview" const MaxJoinLen = 256 @@ -21,7 +22,7 @@ export class TextView extends ContentView { this.setDOM(textDOM || document.createTextNode(this.text)) } - sync(track?: {node: Node, written: boolean}) { + sync(view: EditorView, track?: {node: Node, written: boolean}) { if (!this.dom) this.createDOM() if (this.dom!.nodeValue != this.text) { if (track && track.node == this.dom) track.written = true @@ -87,10 +88,10 @@ export class MarkView extends ContentView { } } - sync(track?: {node: Node, written: boolean}) { + sync(view: EditorView, track?: {node: Node, written: boolean}) { if (!this.dom) this.setDOM(this.setAttrs(document.createElement(this.mark.tagName))) else if (this.dirty & Dirty.Attrs) this.setAttrs(this.dom) - super.sync(track) + super.sync(view, track) } merge(from: number, to: number, source: ContentView | null, _hasStart: boolean, openStart: number, openEnd: number): boolean { @@ -168,11 +169,11 @@ export class WidgetView extends ContentView { return result } - sync() { - if (!this.dom || !this.widget.updateDOM(this.dom)) { + sync(view: EditorView) { + if (!this.dom || !this.widget.updateDOM(this.dom, view)) { if (this.dom && this.prevWidget) this.prevWidget.destroy(this.dom) this.prevWidget = null - this.setDOM(this.widget.toDOM(this.editorView)) + this.setDOM(this.widget.toDOM(view)) this.dom!.contentEditable = "false" } } @@ -206,7 +207,7 @@ export class WidgetView extends ContentView { if (this.length == 0) return DocText.empty let top: ContentView = this while (top.parent) top = top.parent - let view = (top as any).editorView, text: DocText | undefined = view && view.state.doc, start = this.posAtStart + let {view} = top as DocView, text: DocText | undefined = view && view.state.doc, start = this.posAtStart return text ? text.slice(start, start + this.length) : DocText.empty }