prosemirror-view 1.41.9 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 1.42.0 (2026-07-01)
2
+
3
+ ### Bug fixes
4
+
5
+ The clipboard content parser now inlines simple styles defined in the pasted HTML before parsing it, since some applications output their styling that way.
6
+
7
+ ### New features
8
+
9
+ Mark views now also support an `update` method.
10
+
1
11
  ## 1.41.9 (2026-06-10)
2
12
 
3
13
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1272,7 +1272,7 @@ var MarkViewDesc = function (_ViewDesc3) {
1272
1272
  var NodeViewDesc = function (_ViewDesc4) {
1273
1273
  _inherits(NodeViewDesc, _ViewDesc4);
1274
1274
  var _super4 = _createSuper(NodeViewDesc);
1275
- function NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos) {
1275
+ function NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM) {
1276
1276
  var _this4;
1277
1277
  _classCallCheck(this, NodeViewDesc);
1278
1278
  _this4 = _super4.call(this, parent, [], dom, contentDOM);
@@ -1474,23 +1474,23 @@ var NodeViewDesc = function (_ViewDesc4) {
1474
1474
  }
1475
1475
  var nodeDOM = dom;
1476
1476
  dom = applyOuterDeco(dom, outerDeco, node);
1477
- if (spec) return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec, view, pos + 1);else if (node.isText) return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view);else return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, view, pos + 1);
1477
+ if (spec) return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec);else if (node.isText) return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM);else return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM);
1478
1478
  }
1479
1479
  }]);
1480
1480
  return NodeViewDesc;
1481
1481
  }(ViewDesc);
1482
1482
  function docViewDesc(doc, outerDeco, innerDeco, dom, view) {
1483
1483
  applyOuterDeco(dom, outerDeco, doc);
1484
- var docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom, view, 0);
1484
+ var docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom);
1485
1485
  if (docView.contentDOM) docView.updateChildren(view, 0);
1486
1486
  return docView;
1487
1487
  }
1488
1488
  var TextViewDesc = function (_NodeViewDesc) {
1489
1489
  _inherits(TextViewDesc, _NodeViewDesc);
1490
1490
  var _super5 = _createSuper(TextViewDesc);
1491
- function TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {
1491
+ function TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM) {
1492
1492
  _classCallCheck(this, TextViewDesc);
1493
- return _super5.call(this, parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view, 0);
1493
+ return _super5.call(this, parent, node, outerDeco, innerDeco, dom, null, nodeDOM);
1494
1494
  }
1495
1495
  _createClass(TextViewDesc, [{
1496
1496
  key: "parseRule",
@@ -1542,10 +1542,10 @@ var TextViewDesc = function (_NodeViewDesc) {
1542
1542
  }
1543
1543
  }, {
1544
1544
  key: "slice",
1545
- value: function slice(from, to, view) {
1545
+ value: function slice(from, to, _view) {
1546
1546
  var node = this.node.cut(from, to),
1547
1547
  dom = document.createTextNode(node.text);
1548
- return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom, view);
1548
+ return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom);
1549
1549
  }
1550
1550
  }, {
1551
1551
  key: "markDirty",
@@ -1601,10 +1601,10 @@ var TrailingHackViewDesc = function (_ViewDesc5) {
1601
1601
  var CustomNodeViewDesc = function (_NodeViewDesc2) {
1602
1602
  _inherits(CustomNodeViewDesc, _NodeViewDesc2);
1603
1603
  var _super7 = _createSuper(CustomNodeViewDesc);
1604
- function CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view, pos) {
1604
+ function CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec) {
1605
1605
  var _this7;
1606
1606
  _classCallCheck(this, CustomNodeViewDesc);
1607
- _this7 = _super7.call(this, parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos);
1607
+ _this7 = _super7.call(this, parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM);
1608
1608
  _this7.spec = spec;
1609
1609
  return _this7;
1610
1610
  }
@@ -1810,6 +1810,14 @@ var ViewTreeUpdater = function () {
1810
1810
  break;
1811
1811
  }
1812
1812
  }
1813
+ if (found < 0 && this.index < this.top.children.length) {
1814
+ var cur = this.top.children[this.index];
1815
+ if (cur instanceof MarkViewDesc && cur.dirty != NODE_DIRTY && cur.mark.type == marks[depth].type && cur.spec.update && !this.isLocked(cur.dom) && cur.spec.update(marks[depth])) {
1816
+ cur.mark = marks[depth];
1817
+ found = this.index;
1818
+ this.changed = true;
1819
+ }
1820
+ }
1813
1821
  if (found > -1) {
1814
1822
  if (found > this.index) {
1815
1823
  this.changed = true;
@@ -2831,9 +2839,8 @@ var wrapMap = {
2831
2839
  td: ["table", "tbody", "tr"],
2832
2840
  th: ["table", "tbody", "tr"]
2833
2841
  };
2834
- var _detachedDoc = null;
2835
2842
  function detachedDoc() {
2836
- return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
2843
+ return document.implementation.createHTMLDocument("title");
2837
2844
  }
2838
2845
  var _policy = null;
2839
2846
  function maybeWrapTrusted(html) {
@@ -2849,7 +2856,8 @@ function maybeWrapTrusted(html) {
2849
2856
  function readHTML(html) {
2850
2857
  var metas = /^(\s*<meta [^>]*>)*/.exec(html);
2851
2858
  if (metas) html = html.slice(metas[0].length);
2852
- var elt = detachedDoc().createElement("div");
2859
+ var doc = detachedDoc(),
2860
+ elt = doc.body;
2853
2861
  var firstTag = /<([a-z][^>\s]+)/i.exec(html),
2854
2862
  wrap;
2855
2863
  if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()]) html = wrap.map(function (n) {
@@ -2859,6 +2867,16 @@ function readHTML(html) {
2859
2867
  }).reverse().join("");
2860
2868
  elt.innerHTML = maybeWrapTrusted(html);
2861
2869
  if (wrap) for (var i = 0; i < wrap.length; i++) elt = elt.querySelector(wrap[i]) || elt;
2870
+ for (var _i6 = 0; _i6 < doc.styleSheets.length; _i6++) {
2871
+ var style = doc.styleSheets[_i6];
2872
+ for (var j = 0; j < style.rules.length; j++) {
2873
+ var rule = style.rules[j];
2874
+ if (rule instanceof CSSStyleRule) {
2875
+ var matches = elt.querySelectorAll(rule.selectorText);
2876
+ for (var k = 0; k < matches.length; k++) matches[k].style.cssText += rule.style.cssText;
2877
+ }
2878
+ }
2879
+ }
2862
2880
  return elt;
2863
2881
  }
2864
2882
  function restoreReplacedSpaces(dom) {
@@ -3852,10 +3870,10 @@ var DecorationSet = function () {
3852
3870
  var span = this.local[i];
3853
3871
  if (span.from <= end && span.to >= start && (!predicate || predicate(span.spec))) result.push(span.copy(span.from + offset, span.to + offset));
3854
3872
  }
3855
- for (var _i6 = 0; _i6 < this.children.length; _i6 += 3) {
3856
- if (this.children[_i6] < end && this.children[_i6 + 1] > start) {
3857
- var childOff = this.children[_i6] + 1;
3858
- this.children[_i6 + 2].findInner(start - childOff, end - childOff, result, offset + childOff, predicate);
3873
+ for (var _i7 = 0; _i7 < this.children.length; _i7 += 3) {
3874
+ if (this.children[_i7] < end && this.children[_i7 + 1] > start) {
3875
+ var childOff = this.children[_i7] + 1;
3876
+ this.children[_i7 + 2].findInner(start - childOff, end - childOff, result, offset + childOff, predicate);
3859
3877
  }
3860
3878
  }
3861
3879
  }
@@ -3932,7 +3950,7 @@ var DecorationSet = function () {
3932
3950
  i -= 3;
3933
3951
  }
3934
3952
  }
3935
- if (local.length) for (var _i7 = 0, _span; _i7 < decorations.length; _i7++) if (_span = decorations[_i7]) {
3953
+ if (local.length) for (var _i8 = 0, _span; _i8 < decorations.length; _i8++) if (_span = decorations[_i8]) {
3936
3954
  for (var _j2 = 0; _j2 < local.length; _j2++) if (local[_j2].eq(_span, offset)) {
3937
3955
  if (local == this.local) local = this.local.slice();
3938
3956
  local.splice(_j2--, 1);
@@ -3953,8 +3971,8 @@ var DecorationSet = function () {
3953
3971
  }
3954
3972
  var start = offset + 1,
3955
3973
  end = start + node.content.size;
3956
- for (var _i8 = 0; _i8 < this.local.length; _i8++) {
3957
- var dec = this.local[_i8];
3974
+ for (var _i9 = 0; _i9 < this.local.length; _i9++) {
3975
+ var dec = this.local[_i9];
3958
3976
  if (dec.from < end && dec.to > start && dec.type instanceof InlineType) {
3959
3977
  var from = Math.max(start, dec.from) - start,
3960
3978
  to = Math.min(end, dec.to) - start;
@@ -3973,7 +3991,7 @@ var DecorationSet = function () {
3973
3991
  if (this == other) return true;
3974
3992
  if (!(other instanceof DecorationSet) || this.local.length != other.local.length || this.children.length != other.children.length) return false;
3975
3993
  for (var i = 0; i < this.local.length; i++) if (!this.local[i].eq(other.local[i])) return false;
3976
- for (var _i9 = 0; _i9 < this.children.length; _i9 += 3) if (this.children[_i9] != other.children[_i9] || this.children[_i9 + 1] != other.children[_i9 + 1] || !this.children[_i9 + 2].eq(other.children[_i9 + 2])) return false;
3994
+ for (var _i10 = 0; _i10 < this.children.length; _i10 += 3) if (this.children[_i10] != other.children[_i10] || this.children[_i10 + 1] != other.children[_i10 + 1] || !this.children[_i10 + 2].eq(other.children[_i10 + 2])) return false;
3977
3995
  return true;
3978
3996
  }
3979
3997
  }, {
@@ -4090,15 +4108,15 @@ function mapChildren(oldChildren, newLocal, mapping, node, offset, oldOffset, op
4090
4108
  var moved = 0;
4091
4109
  mapping.maps[i].forEach(function (oldStart, oldEnd, newStart, newEnd) {
4092
4110
  var dSize = newEnd - newStart - (oldEnd - oldStart);
4093
- for (var _i13 = 0; _i13 < children.length; _i13 += 3) {
4094
- var end = children[_i13 + 1];
4111
+ for (var _i14 = 0; _i14 < children.length; _i14 += 3) {
4112
+ var end = children[_i14 + 1];
4095
4113
  if (end < 0 || oldStart > end + _baseOffset - moved) continue;
4096
- var start = children[_i13] + _baseOffset - moved;
4114
+ var start = children[_i14] + _baseOffset - moved;
4097
4115
  if (oldEnd >= start) {
4098
- children[_i13 + 1] = oldStart <= start ? -2 : -1;
4116
+ children[_i14 + 1] = oldStart <= start ? -2 : -1;
4099
4117
  } else if (oldStart >= _baseOffset && dSize) {
4100
- children[_i13] += dSize;
4101
- children[_i13 + 1] += dSize;
4118
+ children[_i14] += dSize;
4119
+ children[_i14 + 1] += dSize;
4102
4120
  }
4103
4121
  }
4104
4122
  moved += dSize;
@@ -4110,32 +4128,32 @@ function mapChildren(oldChildren, newLocal, mapping, node, offset, oldOffset, op
4110
4128
  _loop4(baseOffset);
4111
4129
  }
4112
4130
  var mustRebuild = false;
4113
- for (var _i10 = 0; _i10 < children.length; _i10 += 3) if (children[_i10 + 1] < 0) {
4114
- if (children[_i10 + 1] == -2) {
4131
+ for (var _i11 = 0; _i11 < children.length; _i11 += 3) if (children[_i11 + 1] < 0) {
4132
+ if (children[_i11 + 1] == -2) {
4115
4133
  mustRebuild = true;
4116
- children[_i10 + 1] = -1;
4134
+ children[_i11 + 1] = -1;
4117
4135
  continue;
4118
4136
  }
4119
- var from = mapping.map(oldChildren[_i10] + oldOffset),
4137
+ var from = mapping.map(oldChildren[_i11] + oldOffset),
4120
4138
  fromLocal = from - offset;
4121
4139
  if (fromLocal < 0 || fromLocal >= node.content.size) {
4122
4140
  mustRebuild = true;
4123
4141
  continue;
4124
4142
  }
4125
- var to = mapping.map(oldChildren[_i10 + 1] + oldOffset, -1),
4143
+ var to = mapping.map(oldChildren[_i11 + 1] + oldOffset, -1),
4126
4144
  toLocal = to - offset;
4127
4145
  var _node$content$findInd2 = node.content.findIndex(fromLocal),
4128
4146
  index = _node$content$findInd2.index,
4129
4147
  childOffset = _node$content$findInd2.offset;
4130
4148
  var childNode = node.maybeChild(index);
4131
4149
  if (childNode && childOffset == fromLocal && childOffset + childNode.nodeSize == toLocal) {
4132
- var mapped = children[_i10 + 2].mapInner(mapping, childNode, from + 1, oldChildren[_i10] + oldOffset + 1, options);
4150
+ var mapped = children[_i11 + 2].mapInner(mapping, childNode, from + 1, oldChildren[_i11] + oldOffset + 1, options);
4133
4151
  if (mapped != empty) {
4134
- children[_i10] = fromLocal;
4135
- children[_i10 + 1] = toLocal;
4136
- children[_i10 + 2] = mapped;
4152
+ children[_i11] = fromLocal;
4153
+ children[_i11 + 1] = toLocal;
4154
+ children[_i11 + 2] = mapped;
4137
4155
  } else {
4138
- children[_i10 + 1] = -2;
4156
+ children[_i11 + 1] = -2;
4139
4157
  mustRebuild = true;
4140
4158
  }
4141
4159
  } else {
@@ -4146,14 +4164,14 @@ function mapChildren(oldChildren, newLocal, mapping, node, offset, oldOffset, op
4146
4164
  var decorations = mapAndGatherRemainingDecorations(children, oldChildren, newLocal, mapping, offset, oldOffset, options);
4147
4165
  var built = buildTree(decorations, node, 0, options);
4148
4166
  newLocal = built.local;
4149
- for (var _i11 = 0; _i11 < children.length; _i11 += 3) if (children[_i11 + 1] < 0) {
4150
- children.splice(_i11, 3);
4151
- _i11 -= 3;
4167
+ for (var _i12 = 0; _i12 < children.length; _i12 += 3) if (children[_i12 + 1] < 0) {
4168
+ children.splice(_i12, 3);
4169
+ _i12 -= 3;
4152
4170
  }
4153
- for (var _i12 = 0, j = 0; _i12 < built.children.length; _i12 += 3) {
4154
- var _from2 = built.children[_i12];
4171
+ for (var _i13 = 0, j = 0; _i13 < built.children.length; _i13 += 3) {
4172
+ var _from2 = built.children[_i13];
4155
4173
  while (j < children.length && children[j] < _from2) j += 3;
4156
- children.splice(j, 0, built.children[_i12], built.children[_i12 + 1], built.children[_i12 + 2]);
4174
+ children.splice(j, 0, built.children[_i13], built.children[_i13 + 1], built.children[_i13 + 2]);
4157
4175
  }
4158
4176
  }
4159
4177
  return new DecorationSet(newLocal.sort(byPos), children);
@@ -4173,7 +4191,7 @@ function mapAndGatherRemainingDecorations(children, oldChildren, decorations, ma
4173
4191
  var mapped = set.local[i].map(mapping, offset, oldOffset);
4174
4192
  if (mapped) decorations.push(mapped);else if (options.onRemove) options.onRemove(set.local[i].spec);
4175
4193
  }
4176
- for (var _i14 = 0; _i14 < set.children.length; _i14 += 3) gather(set.children[_i14 + 2], set.children[_i14] + oldOffset + 1);
4194
+ for (var _i15 = 0; _i15 < set.children.length; _i15 += 3) gather(set.children[_i15 + 2], set.children[_i15] + oldOffset + 1);
4177
4195
  }
4178
4196
  for (var i = 0; i < children.length; i += 3) if (children[i + 1] == -1) gather(children[i + 2], oldChildren[i] + oldOffset + 1);
4179
4197
  return decorations;
@@ -4566,8 +4584,8 @@ var DOMObserver = function () {
4566
4584
  var prev = mut.previousSibling,
4567
4585
  next = mut.nextSibling;
4568
4586
  if (ie && ie_version <= 11 && mut.addedNodes.length) {
4569
- for (var _i15 = 0; _i15 < mut.addedNodes.length; _i15++) {
4570
- var _mut$addedNodes$_i = mut.addedNodes[_i15],
4587
+ for (var _i16 = 0; _i16 < mut.addedNodes.length; _i16++) {
4588
+ var _mut$addedNodes$_i = mut.addedNodes[_i16],
4571
4589
  previousSibling = _mut$addedNodes$_i.previousSibling,
4572
4590
  nextSibling = _mut$addedNodes$_i.nextSibling;
4573
4591
  if (!previousSibling || Array.prototype.indexOf.call(mut.addedNodes, previousSibling) < 0) prev = previousSibling;
@@ -4933,7 +4951,7 @@ function isMarkChange(cur, prev) {
4933
4951
  mark,
4934
4952
  update;
4935
4953
  for (var i = 0; i < prevMarks.length; i++) added = prevMarks[i].removeFromSet(added);
4936
- for (var _i16 = 0; _i16 < curMarks.length; _i16++) removed = curMarks[_i16].removeFromSet(removed);
4954
+ for (var _i17 = 0; _i17 < curMarks.length; _i17++) removed = curMarks[_i17].removeFromSet(removed);
4937
4955
  if (added.length == 1 && removed.length == 0) {
4938
4956
  mark = added[0];
4939
4957
  type = "add";
@@ -4950,7 +4968,7 @@ function isMarkChange(cur, prev) {
4950
4968
  return null;
4951
4969
  }
4952
4970
  var updated = [];
4953
- for (var _i17 = 0; _i17 < prev.childCount; _i17++) updated.push(update(prev.child(_i17)));
4971
+ for (var _i18 = 0; _i18 < prev.childCount; _i18++) updated.push(update(prev.child(_i18)));
4954
4972
  if (prosemirrorModel.Fragment.from(updated).eq(cur)) return {
4955
4973
  mark: mark,
4956
4974
  type: type
@@ -5187,13 +5205,13 @@ var EditorView = function () {
5187
5205
  var plugin = this.directPlugins[i];
5188
5206
  if (plugin.spec.view) this.pluginViews.push(plugin.spec.view(this));
5189
5207
  }
5190
- for (var _i18 = 0; _i18 < this.state.plugins.length; _i18++) {
5191
- var _plugin = this.state.plugins[_i18];
5208
+ for (var _i19 = 0; _i19 < this.state.plugins.length; _i19++) {
5209
+ var _plugin = this.state.plugins[_i19];
5192
5210
  if (_plugin.spec.view) this.pluginViews.push(_plugin.spec.view(this));
5193
5211
  }
5194
5212
  } else {
5195
- for (var _i19 = 0; _i19 < this.pluginViews.length; _i19++) {
5196
- var pluginView = this.pluginViews[_i19];
5213
+ for (var _i20 = 0; _i20 < this.pluginViews.length; _i20++) {
5214
+ var pluginView = this.pluginViews[_i20];
5197
5215
  if (pluginView.update) pluginView.update(this, prevState);
5198
5216
  }
5199
5217
  }
@@ -5223,8 +5241,8 @@ var EditorView = function () {
5223
5241
  if (_prop != null && (value = f ? f(_prop) : _prop)) return value;
5224
5242
  }
5225
5243
  var plugins = this.state.plugins;
5226
- if (plugins) for (var _i20 = 0; _i20 < plugins.length; _i20++) {
5227
- var _prop2 = plugins[_i20].props[propName];
5244
+ if (plugins) for (var _i21 = 0; _i21 < plugins.length; _i21++) {
5245
+ var _prop2 = plugins[_i21].props[propName];
5228
5246
  if (_prop2 != null && (value = f ? f(_prop2) : _prop2)) return value;
5229
5247
  }
5230
5248
  }
package/dist/index.d.cts CHANGED
@@ -363,6 +363,14 @@ interface MarkView {
363
363
  */
364
364
  contentDOM?: HTMLElement | null;
365
365
  /**
366
+ When given, this is called when the view is updating itself. It
367
+ will be given a mark (of the same type as the current one). When it
368
+ returns true, the existing DOM is kept and reused (its content is
369
+ still managed by ProseMirror); when it returns false, the mark view
370
+ is rebuilt.
371
+ */
372
+ update?: (mark: Mark) => boolean;
373
+ /**
366
374
  Called when a [mutation](https://prosemirror.net/docs/ref/#view.ViewMutationRecord) happens within the
367
375
  view. Return false if the editor should re-read the selection or re-parse
368
376
  the range around the mutation, true if it can safely be ignored.
package/dist/index.d.ts CHANGED
@@ -363,6 +363,14 @@ interface MarkView {
363
363
  */
364
364
  contentDOM?: HTMLElement | null;
365
365
  /**
366
+ When given, this is called when the view is updating itself. It
367
+ will be given a mark (of the same type as the current one). When it
368
+ returns true, the existing DOM is kept and reused (its content is
369
+ still managed by ProseMirror); when it returns false, the mark view
370
+ is rebuilt.
371
+ */
372
+ update?: (mark: Mark) => boolean;
373
+ /**
366
374
  Called when a [mutation](https://prosemirror.net/docs/ref/#view.ViewMutationRecord) happens within the
367
375
  view. Return false if the editor should re-read the selection or re-parse
368
376
  the range around the mutation, true if it can safely be ignored.
package/dist/index.js CHANGED
@@ -1273,7 +1273,7 @@ class MarkViewDesc extends ViewDesc {
1273
1273
  // correspond to an actual node in the document. Unlike mark descs,
1274
1274
  // they populate their child array themselves.
1275
1275
  class NodeViewDesc extends ViewDesc {
1276
- constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos) {
1276
+ constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM) {
1277
1277
  super(parent, [], dom, contentDOM);
1278
1278
  this.node = node;
1279
1279
  this.outerDeco = outerDeco;
@@ -1319,11 +1319,11 @@ class NodeViewDesc extends ViewDesc {
1319
1319
  let nodeDOM = dom;
1320
1320
  dom = applyOuterDeco(dom, outerDeco, node);
1321
1321
  if (spec)
1322
- return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec, view, pos + 1);
1322
+ return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, spec);
1323
1323
  else if (node.isText)
1324
- return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view);
1324
+ return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM);
1325
1325
  else
1326
- return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, view, pos + 1);
1326
+ return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM);
1327
1327
  }
1328
1328
  parseRule() {
1329
1329
  // Experimental kludge to allow opt-in re-parsing of nodes
@@ -1507,14 +1507,14 @@ class NodeViewDesc extends ViewDesc {
1507
1507
  // and used by the view class.
1508
1508
  function docViewDesc(doc, outerDeco, innerDeco, dom, view) {
1509
1509
  applyOuterDeco(dom, outerDeco, doc);
1510
- let docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom, view, 0);
1510
+ let docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom);
1511
1511
  if (docView.contentDOM)
1512
1512
  docView.updateChildren(view, 0);
1513
1513
  return docView;
1514
1514
  }
1515
1515
  class TextViewDesc extends NodeViewDesc {
1516
- constructor(parent, node, outerDeco, innerDeco, dom, nodeDOM, view) {
1517
- super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view, 0);
1516
+ constructor(parent, node, outerDeco, innerDeco, dom, nodeDOM) {
1517
+ super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM);
1518
1518
  }
1519
1519
  parseRule() {
1520
1520
  let skip = this.nodeDOM.parentNode;
@@ -1554,9 +1554,9 @@ class TextViewDesc extends NodeViewDesc {
1554
1554
  ignoreMutation(mutation) {
1555
1555
  return mutation.type != "characterData" && mutation.type != "selection";
1556
1556
  }
1557
- slice(from, to, view) {
1557
+ slice(from, to, _view) {
1558
1558
  let node = this.node.cut(from, to), dom = document.createTextNode(node.text);
1559
- return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom, view);
1559
+ return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom);
1560
1560
  }
1561
1561
  markDirty(from, to) {
1562
1562
  super.markDirty(from, to);
@@ -1578,8 +1578,8 @@ class TrailingHackViewDesc extends ViewDesc {
1578
1578
  // extra checks only have to be made for nodes that are actually
1579
1579
  // customized.
1580
1580
  class CustomNodeViewDesc extends NodeViewDesc {
1581
- constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec, view, pos) {
1582
- super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos);
1581
+ constructor(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, spec) {
1582
+ super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM);
1583
1583
  this.spec = spec;
1584
1584
  }
1585
1585
  // A custom `update` method gets to decide whether the update goes
@@ -1816,6 +1816,19 @@ class ViewTreeUpdater {
1816
1816
  break;
1817
1817
  }
1818
1818
  }
1819
+ // When nothing matches, try to update the mark view at this position
1820
+ // in place, so a custom mark view can adapt to a changed mark without
1821
+ // re-creating its DOM.
1822
+ if (found < 0 && this.index < this.top.children.length) {
1823
+ let cur = this.top.children[this.index];
1824
+ if (cur instanceof MarkViewDesc && cur.dirty != NODE_DIRTY &&
1825
+ cur.mark.type == marks[depth].type && cur.spec.update &&
1826
+ !this.isLocked(cur.dom) && cur.spec.update(marks[depth])) {
1827
+ cur.mark = marks[depth];
1828
+ found = this.index;
1829
+ this.changed = true;
1830
+ }
1831
+ }
1819
1832
  if (found > -1) {
1820
1833
  if (found > this.index) {
1821
1834
  this.changed = true;
@@ -2984,9 +2997,8 @@ const wrapMap = {
2984
2997
  td: ["table", "tbody", "tr"],
2985
2998
  th: ["table", "tbody", "tr"]
2986
2999
  };
2987
- let _detachedDoc = null;
2988
3000
  function detachedDoc() {
2989
- return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
3001
+ return document.implementation.createHTMLDocument("title");
2990
3002
  }
2991
3003
  let _policy = null;
2992
3004
  function maybeWrapTrusted(html) {
@@ -3004,7 +3016,7 @@ function readHTML(html) {
3004
3016
  let metas = /^(\s*<meta [^>]*>)*/.exec(html);
3005
3017
  if (metas)
3006
3018
  html = html.slice(metas[0].length);
3007
- let elt = detachedDoc().createElement("div");
3019
+ let doc = detachedDoc(), elt = doc.body;
3008
3020
  let firstTag = /<([a-z][^>\s]+)/i.exec(html), wrap;
3009
3021
  if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])
3010
3022
  html = wrap.map(n => "<" + n + ">").join("") + html + wrap.map(n => "</" + n + ">").reverse().join("");
@@ -3012,6 +3024,18 @@ function readHTML(html) {
3012
3024
  if (wrap)
3013
3025
  for (let i = 0; i < wrap.length; i++)
3014
3026
  elt = elt.querySelector(wrap[i]) || elt;
3027
+ // Inline styles defined in the pasted content, so that parse rules pick them up
3028
+ for (let i = 0; i < doc.styleSheets.length; i++) {
3029
+ let style = doc.styleSheets[i];
3030
+ for (let j = 0; j < style.rules.length; j++) {
3031
+ let rule = style.rules[j];
3032
+ if (rule instanceof CSSStyleRule) {
3033
+ let matches = elt.querySelectorAll(rule.selectorText);
3034
+ for (let k = 0; k < matches.length; k++)
3035
+ matches[k].style.cssText += rule.style.cssText;
3036
+ }
3037
+ }
3038
+ }
3015
3039
  return elt;
3016
3040
  }
3017
3041
  // Webkit browsers do some hard-to-predict replacement of regular
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.41.9",
3
+ "version": "1.42.0",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -203,9 +203,8 @@ const wrapMap: {[node: string]: string[]} = {
203
203
  th: ["table", "tbody", "tr"]
204
204
  }
205
205
 
206
- let _detachedDoc: Document | null = null
207
206
  function detachedDoc() {
208
- return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
207
+ return document.implementation.createHTMLDocument("title")
209
208
  }
210
209
 
211
210
  let _policy: any = null
@@ -224,12 +223,24 @@ function maybeWrapTrusted(html: string): string {
224
223
  function readHTML(html: string) {
225
224
  let metas = /^(\s*<meta [^>]*>)*/.exec(html)
226
225
  if (metas) html = html.slice(metas[0].length)
227
- let elt = detachedDoc().createElement("div")
226
+ let doc = detachedDoc(), elt = doc.body
228
227
  let firstTag = /<([a-z][^>\s]+)/i.exec(html), wrap
229
228
  if (wrap = firstTag && wrapMap[firstTag[1].toLowerCase()])
230
229
  html = wrap.map(n => "<" + n + ">").join("") + html + wrap.map(n => "</" + n + ">").reverse().join("")
231
230
  elt.innerHTML = maybeWrapTrusted(html)
232
231
  if (wrap) for (let i = 0; i < wrap.length; i++) elt = elt.querySelector(wrap[i]) || elt
232
+ // Inline styles defined in the pasted content, so that parse rules pick them up
233
+ for (let i = 0; i < doc.styleSheets.length; i++) {
234
+ let style = doc.styleSheets[i]
235
+ for (let j = 0; j < style.rules.length; j++) {
236
+ let rule = style.rules[j]
237
+ if (rule instanceof CSSStyleRule) {
238
+ let matches = elt.querySelectorAll(rule.selectorText)
239
+ for (let k = 0; k < matches.length; k++)
240
+ (matches[k] as HTMLElement).style.cssText += rule.style.cssText
241
+ }
242
+ }
243
+ }
233
244
  return elt
234
245
  }
235
246
 
package/src/viewdesc.ts CHANGED
@@ -105,6 +105,13 @@ export interface MarkView {
105
105
  /// present, the `dom` property is used as the content DOM.
106
106
  contentDOM?: HTMLElement | null
107
107
 
108
+ /// When given, this is called when the view is updating itself. It
109
+ /// will be given a mark (of the same type as the current one). When it
110
+ /// returns true, the existing DOM is kept and reused (its content is
111
+ /// still managed by ProseMirror); when it returns false, the mark view
112
+ /// is rebuilt.
113
+ update?: (mark: Mark) => boolean
114
+
108
115
  /// Called when a [mutation](#view.ViewMutationRecord) happens within the
109
116
  /// view. Return false if the editor should re-read the selection or re-parse
110
117
  /// the range around the mutation, true if it can safely be ignored.
@@ -610,7 +617,7 @@ class CompositionViewDesc extends ViewDesc {
610
617
  // some cases they will be split more often than would appear
611
618
  // necessary.
612
619
  class MarkViewDesc extends ViewDesc {
613
- constructor(parent: ViewDesc, readonly mark: Mark, dom: HTMLElement, contentDOM: HTMLElement, readonly spec: MarkView) {
620
+ constructor(parent: ViewDesc, public mark: Mark, dom: HTMLElement, contentDOM: HTMLElement, readonly spec: MarkView) {
614
621
  super(parent, [], dom, contentDOM)
615
622
  }
616
623
 
@@ -672,8 +679,6 @@ export class NodeViewDesc extends ViewDesc {
672
679
  dom: DOMNode,
673
680
  contentDOM: HTMLElement | null,
674
681
  readonly nodeDOM: DOMNode,
675
- view: EditorView,
676
- pos: number
677
682
  ) {
678
683
  super(parent, [], dom, contentDOM)
679
684
  }
@@ -715,11 +720,11 @@ export class NodeViewDesc extends ViewDesc {
715
720
 
716
721
  if (spec)
717
722
  return descObj = new CustomNodeViewDesc(parent, node, outerDeco, innerDeco, dom as HTMLElement, contentDOM || null,
718
- nodeDOM as HTMLElement, spec, view, pos + 1)
723
+ nodeDOM as HTMLElement, spec)
719
724
  else if (node.isText)
720
- return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM, view)
725
+ return new TextViewDesc(parent, node, outerDeco, innerDeco, dom, nodeDOM)
721
726
  else
722
- return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM, view, pos + 1)
727
+ return new NodeViewDesc(parent, node, outerDeco, innerDeco, dom, contentDOM || null, nodeDOM)
723
728
  }
724
729
 
725
730
  parseRule() {
@@ -906,15 +911,15 @@ export class NodeViewDesc extends ViewDesc {
906
911
  export function docViewDesc(doc: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource,
907
912
  dom: HTMLElement, view: EditorView): NodeViewDesc {
908
913
  applyOuterDeco(dom, outerDeco, doc)
909
- let docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom, view, 0)
914
+ let docView = new NodeViewDesc(undefined, doc, outerDeco, innerDeco, dom, dom, dom)
910
915
  if (docView.contentDOM) docView.updateChildren(view, 0)
911
916
  return docView
912
917
  }
913
918
 
914
919
  class TextViewDesc extends NodeViewDesc {
915
920
  constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[],
916
- innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode, view: EditorView) {
917
- super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM, view, 0)
921
+ innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode) {
922
+ super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM)
918
923
  }
919
924
 
920
925
  parseRule() {
@@ -955,9 +960,9 @@ class TextViewDesc extends NodeViewDesc {
955
960
  return mutation.type != "characterData" && mutation.type != "selection"
956
961
  }
957
962
 
958
- slice(from: number, to: number, view: EditorView) {
963
+ slice(from: number, to: number, _view?: EditorView) {
959
964
  let node = this.node.cut(from, to), dom = document.createTextNode(node.text!)
960
- return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom, view)
965
+ return new TextViewDesc(this.parent, node, this.outerDeco, this.innerDeco, dom, dom)
961
966
  }
962
967
 
963
968
  markDirty(from: number, to: number) {
@@ -985,9 +990,8 @@ class TrailingHackViewDesc extends ViewDesc {
985
990
  // customized.
986
991
  class CustomNodeViewDesc extends NodeViewDesc {
987
992
  constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource,
988
- dom: HTMLElement, contentDOM: HTMLElement | null, nodeDOM: HTMLElement, readonly spec: NodeView,
989
- view: EditorView, pos: number) {
990
- super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM, view, pos)
993
+ dom: HTMLElement, contentDOM: HTMLElement | null, nodeDOM: HTMLElement, readonly spec: NodeView) {
994
+ super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM)
991
995
  }
992
996
 
993
997
  // A custom `update` method gets to decide whether the update goes
@@ -1220,6 +1224,19 @@ class ViewTreeUpdater {
1220
1224
  let next = this.top.children[i]
1221
1225
  if (next.matchesMark(marks[depth]) && !this.isLocked(next.dom)) { found = i; break }
1222
1226
  }
1227
+ // When nothing matches, try to update the mark view at this position
1228
+ // in place, so a custom mark view can adapt to a changed mark without
1229
+ // re-creating its DOM.
1230
+ if (found < 0 && this.index < this.top.children.length) {
1231
+ let cur = this.top.children[this.index]
1232
+ if (cur instanceof MarkViewDesc && cur.dirty != NODE_DIRTY &&
1233
+ cur.mark.type == marks[depth].type && cur.spec.update &&
1234
+ !this.isLocked(cur.dom) && cur.spec.update(marks[depth])) {
1235
+ cur.mark = marks[depth]
1236
+ found = this.index
1237
+ this.changed = true
1238
+ }
1239
+ }
1223
1240
  if (found > -1) {
1224
1241
  if (found > this.index) {
1225
1242
  this.changed = true