Skip to content
Permalink
Browse files

Fix unneccessary redrawing of nodes when a widget before them is repl…

…aced

FIX: Avoid redrawing nodes when both their content and a widget in front of them is updated
in the same transaction.
  • Loading branch information
marijnh committed Mar 12, 2020
1 parent f5198a3 commit 6e03bf6b2358f7816fe65a653778f54b791bbca4
Showing with 30 additions and 18 deletions.
  1. +20 −17 src/viewdesc.js
  2. +10 −1 test/test-draw-decoration.js
@@ -1074,23 +1074,26 @@ class ViewTreeUpdater {
// Try to update the next node, if any, to the given data. Checks
// pre-matches to avoid overwriting nodes that could still be used.
updateNextNode(node, outerDeco, innerDeco, view, index) {
if (this.index == this.top.children.length) return false
let next = this.top.children[this.index]
if (next instanceof NodeViewDesc) {
let preMatch = this.preMatched.indexOf(next)
if (preMatch > -1 && preMatch + this.preMatchOffset != index) return false
let nextDOM = next.dom

// Can't update if nextDOM is or contains this.lock, except if
// it's a text node whose content already matches the new text
// and whose decorations match the new ones.
let locked = this.lock && (nextDOM == this.lock || nextDOM.nodeType == 1 && nextDOM.contains(this.lock.parentNode)) &&
!(node.isText && next.node && next.node.isText && next.nodeDOM.nodeValue == node.text &&
next.dirty != NODE_DIRTY && sameOuterDeco(outerDeco, next.outerDeco))
if (!locked && next.update(node, outerDeco, innerDeco, view)) {
if (next.dom != nextDOM) this.changed = true
this.index++
return true
for (let i = this.index; i < this.top.children.length; i++) {
let next = this.top.children[i]
if (next instanceof NodeViewDesc) {
let preMatch = this.preMatched.indexOf(next)
if (preMatch > -1 && preMatch + this.preMatchOffset != index) return false
let nextDOM = next.dom

// Can't update if nextDOM is or contains this.lock, except if
// it's a text node whose content already matches the new text
// and whose decorations match the new ones.
let locked = this.lock && (nextDOM == this.lock || nextDOM.nodeType == 1 && nextDOM.contains(this.lock.parentNode)) &&
!(node.isText && next.node && next.node.isText && next.nodeDOM.nodeValue == node.text &&
next.dirty != NODE_DIRTY && sameOuterDeco(outerDeco, next.outerDeco))
if (!locked && next.update(node, outerDeco, innerDeco, view)) {
this.destroyBetween(this.index, i)
if (next.dom != nextDOM) this.changed = true
this.index = i + 1
return true
}
break
}
}
return false
@@ -1,4 +1,4 @@
const {doc, p, hr, em, strong, img, blockquote, schema} = require("prosemirror-test-builder")
const {doc, p, h1, hr, em, strong, img, blockquote, schema} = require("prosemirror-test-builder")
const {Plugin, TextSelection} = require("prosemirror-state")
const {tempEditor} = require("./view")
const {DecorationSet, Decoration} = require("..")
@@ -305,6 +305,15 @@ describe("Decoration drawing", () => {
ist(lastP.style.color, "red")
})

it("doesn't redraw nodes when a widget before them is replaced", () => {
let w0 = make("3-widget")
let view = tempEditor({doc: doc(h1("a"), p("b")), plugins: [decoPlugin([w0])]})
let initialP = view.dom.querySelector("p")
view.dispatch(view.state.tr.setMeta("updateDecorations", {add: [make("3-widget")], remove: [w0]})
.insertText("c", 5))
ist(view.dom.querySelector("p"), initialP)
})

it("can add and remove inline style", () => {
let deco = Decoration.inline(1, 6, {style: "color: rgba(0,10,200,.4); text-decoration: underline"})
let view = tempEditor({doc: doc(p("al", img, "lo")),

0 comments on commit 6e03bf6

Please sign in to comment.
You can’t perform that action at this time.