prosemirror-view 1.31.6 → 1.31.8
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 +20 -0
- package/dist/index.cjs +123 -45
- package/dist/index.d.cts +11 -9
- package/dist/index.d.ts +11 -9
- package/dist/index.js +108 -37
- package/package.json +1 -1
- package/src/capturekeys.ts +49 -9
- package/src/decoration.ts +13 -8
- package/src/dom.ts +1 -1
- package/src/domchange.ts +6 -3
- package/src/domcoords.ts +3 -1
- package/src/domobserver.ts +7 -5
- package/src/input.ts +4 -0
- package/src/viewdesc.ts +20 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 1.31.8 (2023-09-12)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a bug that broke arrow motion near uneditable nodes on Chrome in some situations.
|
|
6
|
+
|
|
7
|
+
Fix an issue that broke backspace at the end of a textblock that ended in a newline on Chrome.
|
|
8
|
+
|
|
9
|
+
Fix a crash in the way inline decorations that ended right after a node end position were drawn.
|
|
10
|
+
|
|
11
|
+
## 1.31.7 (2023-07-28)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Fix a bug where, when a compositionend event was received before the composition's final changes were processed, the resulting transaction didn't have its composition metadata set.
|
|
16
|
+
|
|
17
|
+
Fix an issue that caused cursor motion to stop at uneditable nodes that aren't widget decorations.
|
|
18
|
+
|
|
19
|
+
When scrolling an element higher than the viewport into view, make sure its top is visible.
|
|
20
|
+
|
|
1
21
|
## 1.31.6 (2023-07-14)
|
|
2
22
|
|
|
3
23
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -32,10 +32,6 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
|
|
|
32
32
|
|
|
33
33
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
34
34
|
|
|
35
|
-
Object.defineProperty(exports, '__esModule', {
|
|
36
|
-
value: true
|
|
37
|
-
});
|
|
38
|
-
|
|
39
35
|
var prosemirrorState = require('prosemirror-state');
|
|
40
36
|
|
|
41
37
|
var prosemirrorModel = require('prosemirror-model');
|
|
@@ -216,7 +212,7 @@ function scrollRectIntoView(view, rect, startDOM) {
|
|
|
216
212
|
var bounding = atTop ? windowRect(doc) : clientRect(elt);
|
|
217
213
|
var moveX = 0,
|
|
218
214
|
moveY = 0;
|
|
219
|
-
if (rect.top < bounding.top + getSide(scrollThreshold, "top")) moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top"));else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom")) moveY = rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom");
|
|
215
|
+
if (rect.top < bounding.top + getSide(scrollThreshold, "top")) moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top"));else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom")) moveY = rect.bottom - rect.top > bounding.bottom - bounding.top ? rect.top + getSide(scrollMargin, "top") - bounding.top : rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom");
|
|
220
216
|
if (rect.left < bounding.left + getSide(scrollThreshold, "left")) moveX = -(bounding.left - rect.left + getSide(scrollMargin, "left"));else if (rect.right > bounding.right - getSide(scrollThreshold, "right")) moveX = rect.right - bounding.right + getSide(scrollMargin, "right");
|
|
221
217
|
|
|
222
218
|
if (moveX || moveY) {
|
|
@@ -2190,9 +2186,13 @@ var ViewTreeUpdater = function () {
|
|
|
2190
2186
|
return true;
|
|
2191
2187
|
} else if (!locked && (updated = this.recreateWrapper(next, node, outerDeco, innerDeco, view, pos))) {
|
|
2192
2188
|
this.top.children[this.index] = updated;
|
|
2193
|
-
|
|
2194
|
-
updated.
|
|
2195
|
-
|
|
2189
|
+
|
|
2190
|
+
if (updated.contentDOM) {
|
|
2191
|
+
updated.dirty = CONTENT_DIRTY;
|
|
2192
|
+
updated.updateChildren(view, pos + 1);
|
|
2193
|
+
updated.dirty = NOT_DIRTY;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
2196
|
this.changed = true;
|
|
2197
2197
|
this.index++;
|
|
2198
2198
|
return true;
|
|
@@ -2209,25 +2209,27 @@ var ViewTreeUpdater = function () {
|
|
|
2209
2209
|
value: function recreateWrapper(next, node, outerDeco, innerDeco, view, pos) {
|
|
2210
2210
|
if (next.dirty || node.isAtom || !next.children.length || !next.node.content.eq(node.content)) return null;
|
|
2211
2211
|
var wrapper = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);
|
|
2212
|
-
if (!wrapper.contentDOM) return null;
|
|
2213
|
-
wrapper.children = next.children;
|
|
2214
|
-
next.children = [];
|
|
2215
|
-
next.destroy();
|
|
2216
2212
|
|
|
2217
|
-
|
|
2218
|
-
|
|
2213
|
+
if (wrapper.contentDOM) {
|
|
2214
|
+
wrapper.children = next.children;
|
|
2215
|
+
next.children = [];
|
|
2219
2216
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2217
|
+
var _iterator = _createForOfIteratorHelper(wrapper.children),
|
|
2218
|
+
_step;
|
|
2219
|
+
|
|
2220
|
+
try {
|
|
2221
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
2222
|
+
var ch = _step.value;
|
|
2223
|
+
ch.parent = wrapper;
|
|
2224
|
+
}
|
|
2225
|
+
} catch (err) {
|
|
2226
|
+
_iterator.e(err);
|
|
2227
|
+
} finally {
|
|
2228
|
+
_iterator.f();
|
|
2224
2229
|
}
|
|
2225
|
-
} catch (err) {
|
|
2226
|
-
_iterator.e(err);
|
|
2227
|
-
} finally {
|
|
2228
|
-
_iterator.f();
|
|
2229
2230
|
}
|
|
2230
2231
|
|
|
2232
|
+
next.destroy();
|
|
2231
2233
|
return wrapper;
|
|
2232
2234
|
}
|
|
2233
2235
|
}, {
|
|
@@ -2364,14 +2366,18 @@ function iterDeco(parent, deco, onWidget, onNode) {
|
|
|
2364
2366
|
restNode = null;
|
|
2365
2367
|
|
|
2366
2368
|
for (var parentIndex = 0;;) {
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2369
|
+
var widget = void 0,
|
|
2370
|
+
widgets = void 0;
|
|
2371
|
+
|
|
2372
|
+
while (decoIndex < locals.length && locals[decoIndex].to == offset) {
|
|
2373
|
+
var next = locals[decoIndex++];
|
|
2370
2374
|
|
|
2371
|
-
|
|
2372
|
-
(widgets || (widgets = [widget])).push(
|
|
2375
|
+
if (next.widget) {
|
|
2376
|
+
if (!widget) widget = next;else (widgets || (widgets = [widget])).push(next);
|
|
2373
2377
|
}
|
|
2378
|
+
}
|
|
2374
2379
|
|
|
2380
|
+
if (widget) {
|
|
2375
2381
|
if (widgets) {
|
|
2376
2382
|
widgets.sort(compareSide);
|
|
2377
2383
|
|
|
@@ -2773,9 +2779,10 @@ function nodeLen(node) {
|
|
|
2773
2779
|
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
2774
2780
|
}
|
|
2775
2781
|
|
|
2776
|
-
function isIgnorable(dom) {
|
|
2782
|
+
function isIgnorable(dom, dir) {
|
|
2783
|
+
if (dom.contentEditable == "false") return true;
|
|
2777
2784
|
var desc = dom.pmViewDesc;
|
|
2778
|
-
return desc && desc.size == 0 && (dom.nextSibling || dom.nodeName != "BR");
|
|
2785
|
+
return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
|
|
2779
2786
|
}
|
|
2780
2787
|
|
|
2781
2788
|
function skipIgnoredNodes(view, dir) {
|
|
@@ -2790,7 +2797,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2790
2797
|
var moveNode,
|
|
2791
2798
|
moveOffset,
|
|
2792
2799
|
force = false;
|
|
2793
|
-
if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset])) force = true;
|
|
2800
|
+
if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1)) force = true;
|
|
2794
2801
|
|
|
2795
2802
|
for (;;) {
|
|
2796
2803
|
if (offset > 0) {
|
|
@@ -2799,7 +2806,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2799
2806
|
} else {
|
|
2800
2807
|
var before = node.childNodes[offset - 1];
|
|
2801
2808
|
|
|
2802
|
-
if (isIgnorable(before)) {
|
|
2809
|
+
if (isIgnorable(before, -1)) {
|
|
2803
2810
|
moveNode = node;
|
|
2804
2811
|
moveOffset = --offset;
|
|
2805
2812
|
} else if (before.nodeType == 3) {
|
|
@@ -2812,7 +2819,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2812
2819
|
} else {
|
|
2813
2820
|
var prev = node.previousSibling;
|
|
2814
2821
|
|
|
2815
|
-
while (prev && isIgnorable(prev)) {
|
|
2822
|
+
while (prev && isIgnorable(prev, -1)) {
|
|
2816
2823
|
moveNode = node.parentNode;
|
|
2817
2824
|
moveOffset = domIndex(prev);
|
|
2818
2825
|
prev = prev.previousSibling;
|
|
@@ -2845,7 +2852,7 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2845
2852
|
if (node.nodeType != 1) break;
|
|
2846
2853
|
var after = node.childNodes[offset];
|
|
2847
2854
|
|
|
2848
|
-
if (isIgnorable(after)) {
|
|
2855
|
+
if (isIgnorable(after, 1)) {
|
|
2849
2856
|
moveNode = node;
|
|
2850
2857
|
moveOffset = ++offset;
|
|
2851
2858
|
} else break;
|
|
@@ -2854,7 +2861,7 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2854
2861
|
} else {
|
|
2855
2862
|
var next = node.nextSibling;
|
|
2856
2863
|
|
|
2857
|
-
while (next && isIgnorable(next)) {
|
|
2864
|
+
while (next && isIgnorable(next, 1)) {
|
|
2858
2865
|
moveNode = next.parentNode;
|
|
2859
2866
|
moveOffset = domIndex(next) + 1;
|
|
2860
2867
|
next = next.nextSibling;
|
|
@@ -2880,7 +2887,49 @@ function isBlockNode(dom) {
|
|
|
2880
2887
|
return desc && desc.node && desc.node.isBlock;
|
|
2881
2888
|
}
|
|
2882
2889
|
|
|
2890
|
+
function textNodeAfter(node, offset) {
|
|
2891
|
+
while (node && offset == node.childNodes.length && !hasBlockDesc(node)) {
|
|
2892
|
+
offset = domIndex(node) + 1;
|
|
2893
|
+
node = node.parentNode;
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
while (node && offset < node.childNodes.length) {
|
|
2897
|
+
var next = node.childNodes[offset];
|
|
2898
|
+
if (next.nodeType == 3) return next;
|
|
2899
|
+
if (next.nodeType == 1 && next.contentEditable == "false") break;
|
|
2900
|
+
node = next;
|
|
2901
|
+
offset = 0;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
function textNodeBefore(node, offset) {
|
|
2906
|
+
while (node && !offset && !hasBlockDesc(node)) {
|
|
2907
|
+
offset = domIndex(node);
|
|
2908
|
+
node = node.parentNode;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
while (node && offset) {
|
|
2912
|
+
var next = node.childNodes[offset - 1];
|
|
2913
|
+
if (next.nodeType == 3) return next;
|
|
2914
|
+
if (next.nodeType == 1 && next.contentEditable == "false") break;
|
|
2915
|
+
node = next;
|
|
2916
|
+
offset = node.childNodes.length;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2883
2920
|
function setSelFocus(view, node, offset) {
|
|
2921
|
+
if (node.nodeType != 3) {
|
|
2922
|
+
var before, after;
|
|
2923
|
+
|
|
2924
|
+
if (after = textNodeAfter(node, offset)) {
|
|
2925
|
+
node = after;
|
|
2926
|
+
offset = 0;
|
|
2927
|
+
} else if (before = textNodeBefore(node, offset)) {
|
|
2928
|
+
node = before;
|
|
2929
|
+
offset = before.nodeValue.length;
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2884
2933
|
var sel = view.domSelection();
|
|
2885
2934
|
|
|
2886
2935
|
if (selectionCollapsed(sel)) {
|
|
@@ -3020,7 +3069,7 @@ function captureKeyDown(view, event) {
|
|
|
3020
3069
|
} else if (code == 38 || mac && code == 80 && mods == "c") {
|
|
3021
3070
|
return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1);
|
|
3022
3071
|
} else if (code == 40 || mac && code == 78 && mods == "c") {
|
|
3023
|
-
return safariDownArrowBug(view) || selectVertically(view, 1, mods) ||
|
|
3072
|
+
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodes(view, 1);
|
|
3024
3073
|
} else if (mods == (mac ? "m" : "c") && (code == 66 || code == 73 || code == 89 || code == 90)) {
|
|
3025
3074
|
return true;
|
|
3026
3075
|
}
|
|
@@ -3349,6 +3398,7 @@ var InputState = _createClass(function InputState() {
|
|
|
3349
3398
|
this.compositionNodes = [];
|
|
3350
3399
|
this.compositionEndedAt = -2e8;
|
|
3351
3400
|
this.compositionID = 1;
|
|
3401
|
+
this.compositionPendingChanges = 0;
|
|
3352
3402
|
this.domChangeCount = 0;
|
|
3353
3403
|
this.eventHandlers = Object.create(null);
|
|
3354
3404
|
this.hideSelectionGuard = null;
|
|
@@ -3812,6 +3862,10 @@ editHandlers.compositionend = function (view, event) {
|
|
|
3812
3862
|
if (view.composing) {
|
|
3813
3863
|
view.input.composing = false;
|
|
3814
3864
|
view.input.compositionEndedAt = event.timeStamp;
|
|
3865
|
+
view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
|
|
3866
|
+
if (view.input.compositionPendingChanges) Promise.resolve().then(function () {
|
|
3867
|
+
return view.domObserver.flush();
|
|
3868
|
+
});
|
|
3815
3869
|
view.input.compositionID++;
|
|
3816
3870
|
scheduleComposeEnd(view, 20);
|
|
3817
3871
|
}
|
|
@@ -4252,6 +4306,11 @@ var Decoration = function () {
|
|
|
4252
4306
|
get: function get() {
|
|
4253
4307
|
return this.type instanceof InlineType;
|
|
4254
4308
|
}
|
|
4309
|
+
}, {
|
|
4310
|
+
key: "widget",
|
|
4311
|
+
get: function get() {
|
|
4312
|
+
return this.type instanceof WidgetType;
|
|
4313
|
+
}
|
|
4255
4314
|
}], [{
|
|
4256
4315
|
key: "widget",
|
|
4257
4316
|
value: function widget(pos, toDOM, spec) {
|
|
@@ -5018,18 +5077,34 @@ var DOMObserver = function () {
|
|
|
5018
5077
|
return true;
|
|
5019
5078
|
}
|
|
5020
5079
|
}
|
|
5080
|
+
}, {
|
|
5081
|
+
key: "pendingRecords",
|
|
5082
|
+
value: function pendingRecords() {
|
|
5083
|
+
if (this.observer) {
|
|
5084
|
+
var _iterator2 = _createForOfIteratorHelper(this.observer.takeRecords()),
|
|
5085
|
+
_step2;
|
|
5086
|
+
|
|
5087
|
+
try {
|
|
5088
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
5089
|
+
var mut = _step2.value;
|
|
5090
|
+
this.queue.push(mut);
|
|
5091
|
+
}
|
|
5092
|
+
} catch (err) {
|
|
5093
|
+
_iterator2.e(err);
|
|
5094
|
+
} finally {
|
|
5095
|
+
_iterator2.f();
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
|
|
5099
|
+
return this.queue;
|
|
5100
|
+
}
|
|
5021
5101
|
}, {
|
|
5022
5102
|
key: "flush",
|
|
5023
5103
|
value: function flush() {
|
|
5024
5104
|
var view = this.view;
|
|
5025
5105
|
if (!view.docView || this.flushingSoon > -1) return;
|
|
5026
|
-
var mutations = this.
|
|
5027
|
-
|
|
5028
|
-
if (this.queue.length) {
|
|
5029
|
-
mutations = this.queue.concat(mutations);
|
|
5030
|
-
this.queue.length = 0;
|
|
5031
|
-
}
|
|
5032
|
-
|
|
5106
|
+
var mutations = this.pendingRecords();
|
|
5107
|
+
if (mutations.length) this.queue = [];
|
|
5033
5108
|
var sel = view.domSelectionRange();
|
|
5034
5109
|
var newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
5035
5110
|
var from = -1,
|
|
@@ -5284,6 +5359,9 @@ function ruleFromNode(dom) {
|
|
|
5284
5359
|
var isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i;
|
|
5285
5360
|
|
|
5286
5361
|
function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
5362
|
+
var compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0);
|
|
5363
|
+
view.input.compositionPendingChanges = 0;
|
|
5364
|
+
|
|
5287
5365
|
if (from < 0) {
|
|
5288
5366
|
var origin = view.input.lastSelectionTime > Date.now() - 50 ? view.input.lastSelectionOrigin : null;
|
|
5289
5367
|
var newSel = selectionFromDOM(view, origin);
|
|
@@ -5296,7 +5374,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5296
5374
|
var _tr = view.state.tr.setSelection(newSel);
|
|
5297
5375
|
|
|
5298
5376
|
if (origin == "pointer") _tr.setMeta("pointer", true);else if (origin == "key") _tr.scrollIntoView();
|
|
5299
|
-
if (
|
|
5377
|
+
if (compositionID) _tr.setMeta("composition", compositionID);
|
|
5300
5378
|
view.dispatch(_tr);
|
|
5301
5379
|
}
|
|
5302
5380
|
|
|
@@ -5347,7 +5425,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5347
5425
|
if (_sel && !_sel.eq(view.state.selection)) {
|
|
5348
5426
|
var _tr2 = view.state.tr.setSelection(_sel);
|
|
5349
5427
|
|
|
5350
|
-
if (
|
|
5428
|
+
if (compositionID) _tr2.setMeta("composition", compositionID);
|
|
5351
5429
|
view.dispatch(_tr2);
|
|
5352
5430
|
}
|
|
5353
5431
|
}
|
|
@@ -5451,7 +5529,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5451
5529
|
}
|
|
5452
5530
|
|
|
5453
5531
|
if (storedMarks) tr.ensureMarks(storedMarks);
|
|
5454
|
-
if (
|
|
5532
|
+
if (compositionID) tr.setMeta("composition", compositionID);
|
|
5455
5533
|
view.dispatch(tr.scrollIntoView());
|
|
5456
5534
|
}
|
|
5457
5535
|
|
package/dist/index.d.cts
CHANGED
|
@@ -2,9 +2,9 @@ import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
|
|
|
2
2
|
import { Mark, Node, ParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
|
|
3
3
|
import { Mapping } from 'prosemirror-transform';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type DOMNode = InstanceType<typeof window.Node>;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
type WidgetConstructor = ((view: EditorView, getPos: () => number | undefined) => DOMNode) | DOMNode;
|
|
8
8
|
/**
|
|
9
9
|
Decoration objects can be provided to the view through the
|
|
10
10
|
[`decorations` prop](https://prosemirror.net/docs/ref/#view.EditorProps.decorations). They come in
|
|
@@ -125,7 +125,7 @@ A set of attributes to add to a decorated node. Most properties
|
|
|
125
125
|
simply directly correspond to DOM attributes of the same name,
|
|
126
126
|
which will be set to the property's value. These are exceptions:
|
|
127
127
|
*/
|
|
128
|
-
|
|
128
|
+
type DecorationAttrs = {
|
|
129
129
|
/**
|
|
130
130
|
When non-null, the target node is wrapped in a DOM element of
|
|
131
131
|
this type (and the other attributes are applied to this element).
|
|
@@ -166,7 +166,8 @@ updates create a new value.
|
|
|
166
166
|
declare class DecorationSet implements DecorationSource {
|
|
167
167
|
/**
|
|
168
168
|
Create a set of decorations, using the structure of the given
|
|
169
|
-
document.
|
|
169
|
+
document. This will consume (modify) the `decorations` array, so
|
|
170
|
+
you must make a copy if you want need to preserve that.
|
|
170
171
|
*/
|
|
171
172
|
static create(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
172
173
|
/**
|
|
@@ -193,8 +194,9 @@ declare class DecorationSet implements DecorationSource {
|
|
|
193
194
|
}): DecorationSet;
|
|
194
195
|
/**
|
|
195
196
|
Add the given array of decorations to the ones in the set,
|
|
196
|
-
producing a new set.
|
|
197
|
-
create the appropriate tree
|
|
197
|
+
producing a new set. Consumes the `decorations` array. Needs
|
|
198
|
+
access to the current document to create the appropriate tree
|
|
199
|
+
structure.
|
|
198
200
|
*/
|
|
199
201
|
add(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
200
202
|
private addInner;
|
|
@@ -356,7 +358,7 @@ declare class NodeViewDesc extends ViewDesc {
|
|
|
356
358
|
parseRule(): ParseRule | null;
|
|
357
359
|
matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
|
|
358
360
|
get size(): number;
|
|
359
|
-
get border():
|
|
361
|
+
get border(): 0 | 1;
|
|
360
362
|
updateChildren(view: EditorView, pos: number): void;
|
|
361
363
|
localCompositionInfo(view: EditorView, pos: number): {
|
|
362
364
|
node: Text;
|
|
@@ -604,12 +606,12 @@ declare class EditorView {
|
|
|
604
606
|
The type of function [provided](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) to
|
|
605
607
|
create [node views](https://prosemirror.net/docs/ref/#view.NodeView).
|
|
606
608
|
*/
|
|
607
|
-
|
|
609
|
+
type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number | undefined, decorations: readonly Decoration[], innerDecorations: DecorationSource) => NodeView;
|
|
608
610
|
/**
|
|
609
611
|
The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
|
|
610
612
|
mark views.
|
|
611
613
|
*/
|
|
612
|
-
|
|
614
|
+
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {
|
|
613
615
|
dom: HTMLElement;
|
|
614
616
|
contentDOM?: HTMLElement;
|
|
615
617
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
|
|
|
2
2
|
import { Mark, Node, ParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
|
|
3
3
|
import { Mapping } from 'prosemirror-transform';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type DOMNode = InstanceType<typeof window.Node>;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
type WidgetConstructor = ((view: EditorView, getPos: () => number | undefined) => DOMNode) | DOMNode;
|
|
8
8
|
/**
|
|
9
9
|
Decoration objects can be provided to the view through the
|
|
10
10
|
[`decorations` prop](https://prosemirror.net/docs/ref/#view.EditorProps.decorations). They come in
|
|
@@ -125,7 +125,7 @@ A set of attributes to add to a decorated node. Most properties
|
|
|
125
125
|
simply directly correspond to DOM attributes of the same name,
|
|
126
126
|
which will be set to the property's value. These are exceptions:
|
|
127
127
|
*/
|
|
128
|
-
|
|
128
|
+
type DecorationAttrs = {
|
|
129
129
|
/**
|
|
130
130
|
When non-null, the target node is wrapped in a DOM element of
|
|
131
131
|
this type (and the other attributes are applied to this element).
|
|
@@ -166,7 +166,8 @@ updates create a new value.
|
|
|
166
166
|
declare class DecorationSet implements DecorationSource {
|
|
167
167
|
/**
|
|
168
168
|
Create a set of decorations, using the structure of the given
|
|
169
|
-
document.
|
|
169
|
+
document. This will consume (modify) the `decorations` array, so
|
|
170
|
+
you must make a copy if you want need to preserve that.
|
|
170
171
|
*/
|
|
171
172
|
static create(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
172
173
|
/**
|
|
@@ -193,8 +194,9 @@ declare class DecorationSet implements DecorationSource {
|
|
|
193
194
|
}): DecorationSet;
|
|
194
195
|
/**
|
|
195
196
|
Add the given array of decorations to the ones in the set,
|
|
196
|
-
producing a new set.
|
|
197
|
-
create the appropriate tree
|
|
197
|
+
producing a new set. Consumes the `decorations` array. Needs
|
|
198
|
+
access to the current document to create the appropriate tree
|
|
199
|
+
structure.
|
|
198
200
|
*/
|
|
199
201
|
add(doc: Node, decorations: Decoration[]): DecorationSet;
|
|
200
202
|
private addInner;
|
|
@@ -356,7 +358,7 @@ declare class NodeViewDesc extends ViewDesc {
|
|
|
356
358
|
parseRule(): ParseRule | null;
|
|
357
359
|
matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
|
|
358
360
|
get size(): number;
|
|
359
|
-
get border():
|
|
361
|
+
get border(): 0 | 1;
|
|
360
362
|
updateChildren(view: EditorView, pos: number): void;
|
|
361
363
|
localCompositionInfo(view: EditorView, pos: number): {
|
|
362
364
|
node: Text;
|
|
@@ -604,12 +606,12 @@ declare class EditorView {
|
|
|
604
606
|
The type of function [provided](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) to
|
|
605
607
|
create [node views](https://prosemirror.net/docs/ref/#view.NodeView).
|
|
606
608
|
*/
|
|
607
|
-
|
|
609
|
+
type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number | undefined, decorations: readonly Decoration[], innerDecorations: DecorationSource) => NodeView;
|
|
608
610
|
/**
|
|
609
611
|
The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
|
|
610
612
|
mark views.
|
|
611
613
|
*/
|
|
612
|
-
|
|
614
|
+
type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {
|
|
613
615
|
dom: HTMLElement;
|
|
614
616
|
contentDOM?: HTMLElement;
|
|
615
617
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TextSelection, NodeSelection,
|
|
1
|
+
import { TextSelection, NodeSelection, AllSelection, Selection } from 'prosemirror-state';
|
|
2
2
|
import { DOMSerializer, Fragment, Mark, Slice, DOMParser } from 'prosemirror-model';
|
|
3
3
|
import { dropPoint } from 'prosemirror-transform';
|
|
4
4
|
|
|
@@ -163,7 +163,9 @@ function scrollRectIntoView(view, rect, startDOM) {
|
|
|
163
163
|
if (rect.top < bounding.top + getSide(scrollThreshold, "top"))
|
|
164
164
|
moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top"));
|
|
165
165
|
else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom"))
|
|
166
|
-
moveY = rect.bottom - bounding.bottom
|
|
166
|
+
moveY = rect.bottom - rect.top > bounding.bottom - bounding.top
|
|
167
|
+
? rect.top + getSide(scrollMargin, "top") - bounding.top
|
|
168
|
+
: rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom");
|
|
167
169
|
if (rect.left < bounding.left + getSide(scrollThreshold, "left"))
|
|
168
170
|
moveX = -(bounding.left - rect.left + getSide(scrollMargin, "left"));
|
|
169
171
|
else if (rect.right > bounding.right - getSide(scrollThreshold, "right"))
|
|
@@ -1808,9 +1810,11 @@ class ViewTreeUpdater {
|
|
|
1808
1810
|
}
|
|
1809
1811
|
else if (!locked && (updated = this.recreateWrapper(next, node, outerDeco, innerDeco, view, pos))) {
|
|
1810
1812
|
this.top.children[this.index] = updated;
|
|
1811
|
-
updated.
|
|
1812
|
-
|
|
1813
|
-
|
|
1813
|
+
if (updated.contentDOM) {
|
|
1814
|
+
updated.dirty = CONTENT_DIRTY;
|
|
1815
|
+
updated.updateChildren(view, pos + 1);
|
|
1816
|
+
updated.dirty = NOT_DIRTY;
|
|
1817
|
+
}
|
|
1814
1818
|
this.changed = true;
|
|
1815
1819
|
this.index++;
|
|
1816
1820
|
return true;
|
|
@@ -1827,13 +1831,13 @@ class ViewTreeUpdater {
|
|
|
1827
1831
|
!next.node.content.eq(node.content))
|
|
1828
1832
|
return null;
|
|
1829
1833
|
let wrapper = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos);
|
|
1830
|
-
if (
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
+
if (wrapper.contentDOM) {
|
|
1835
|
+
wrapper.children = next.children;
|
|
1836
|
+
next.children = [];
|
|
1837
|
+
for (let ch of wrapper.children)
|
|
1838
|
+
ch.parent = wrapper;
|
|
1839
|
+
}
|
|
1834
1840
|
next.destroy();
|
|
1835
|
-
for (let ch of wrapper.children)
|
|
1836
|
-
ch.parent = wrapper;
|
|
1837
1841
|
return wrapper;
|
|
1838
1842
|
}
|
|
1839
1843
|
// Insert the node as a newly created node desc.
|
|
@@ -1961,10 +1965,17 @@ function iterDeco(parent, deco, onWidget, onNode) {
|
|
|
1961
1965
|
}
|
|
1962
1966
|
let decoIndex = 0, active = [], restNode = null;
|
|
1963
1967
|
for (let parentIndex = 0;;) {
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
+
let widget, widgets;
|
|
1969
|
+
while (decoIndex < locals.length && locals[decoIndex].to == offset) {
|
|
1970
|
+
let next = locals[decoIndex++];
|
|
1971
|
+
if (next.widget) {
|
|
1972
|
+
if (!widget)
|
|
1973
|
+
widget = next;
|
|
1974
|
+
else
|
|
1975
|
+
(widgets || (widgets = [widget])).push(next);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
if (widget) {
|
|
1968
1979
|
if (widgets) {
|
|
1969
1980
|
widgets.sort(compareSide);
|
|
1970
1981
|
for (let i = 0; i < widgets.length; i++)
|
|
@@ -2353,9 +2364,11 @@ function selectHorizontally(view, dir, mods) {
|
|
|
2353
2364
|
function nodeLen(node) {
|
|
2354
2365
|
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
2355
2366
|
}
|
|
2356
|
-
function isIgnorable(dom) {
|
|
2367
|
+
function isIgnorable(dom, dir) {
|
|
2368
|
+
if (dom.contentEditable == "false")
|
|
2369
|
+
return true;
|
|
2357
2370
|
let desc = dom.pmViewDesc;
|
|
2358
|
-
return desc && desc.size == 0 && (dom.nextSibling || dom.nodeName != "BR");
|
|
2371
|
+
return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
|
|
2359
2372
|
}
|
|
2360
2373
|
function skipIgnoredNodes(view, dir) {
|
|
2361
2374
|
return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
|
|
@@ -2371,7 +2384,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2371
2384
|
// Gecko will do odd things when the selection is directly in front
|
|
2372
2385
|
// of a non-editable node, so in that case, move it into the next
|
|
2373
2386
|
// node if possible. Issue prosemirror/prosemirror#832.
|
|
2374
|
-
if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset]))
|
|
2387
|
+
if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
|
|
2375
2388
|
force = true;
|
|
2376
2389
|
for (;;) {
|
|
2377
2390
|
if (offset > 0) {
|
|
@@ -2380,7 +2393,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2380
2393
|
}
|
|
2381
2394
|
else {
|
|
2382
2395
|
let before = node.childNodes[offset - 1];
|
|
2383
|
-
if (isIgnorable(before)) {
|
|
2396
|
+
if (isIgnorable(before, -1)) {
|
|
2384
2397
|
moveNode = node;
|
|
2385
2398
|
moveOffset = --offset;
|
|
2386
2399
|
}
|
|
@@ -2397,7 +2410,7 @@ function skipIgnoredNodesBefore(view) {
|
|
|
2397
2410
|
}
|
|
2398
2411
|
else {
|
|
2399
2412
|
let prev = node.previousSibling;
|
|
2400
|
-
while (prev && isIgnorable(prev)) {
|
|
2413
|
+
while (prev && isIgnorable(prev, -1)) {
|
|
2401
2414
|
moveNode = node.parentNode;
|
|
2402
2415
|
moveOffset = domIndex(prev);
|
|
2403
2416
|
prev = prev.previousSibling;
|
|
@@ -2433,7 +2446,7 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2433
2446
|
if (node.nodeType != 1)
|
|
2434
2447
|
break;
|
|
2435
2448
|
let after = node.childNodes[offset];
|
|
2436
|
-
if (isIgnorable(after)) {
|
|
2449
|
+
if (isIgnorable(after, 1)) {
|
|
2437
2450
|
moveNode = node;
|
|
2438
2451
|
moveOffset = ++offset;
|
|
2439
2452
|
}
|
|
@@ -2445,7 +2458,7 @@ function skipIgnoredNodesAfter(view) {
|
|
|
2445
2458
|
}
|
|
2446
2459
|
else {
|
|
2447
2460
|
let next = node.nextSibling;
|
|
2448
|
-
while (next && isIgnorable(next)) {
|
|
2461
|
+
while (next && isIgnorable(next, 1)) {
|
|
2449
2462
|
moveNode = next.parentNode;
|
|
2450
2463
|
moveOffset = domIndex(next) + 1;
|
|
2451
2464
|
next = next.nextSibling;
|
|
@@ -2470,7 +2483,48 @@ function isBlockNode(dom) {
|
|
|
2470
2483
|
let desc = dom.pmViewDesc;
|
|
2471
2484
|
return desc && desc.node && desc.node.isBlock;
|
|
2472
2485
|
}
|
|
2486
|
+
function textNodeAfter(node, offset) {
|
|
2487
|
+
while (node && offset == node.childNodes.length && !hasBlockDesc(node)) {
|
|
2488
|
+
offset = domIndex(node) + 1;
|
|
2489
|
+
node = node.parentNode;
|
|
2490
|
+
}
|
|
2491
|
+
while (node && offset < node.childNodes.length) {
|
|
2492
|
+
let next = node.childNodes[offset];
|
|
2493
|
+
if (next.nodeType == 3)
|
|
2494
|
+
return next;
|
|
2495
|
+
if (next.nodeType == 1 && next.contentEditable == "false")
|
|
2496
|
+
break;
|
|
2497
|
+
node = next;
|
|
2498
|
+
offset = 0;
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
function textNodeBefore(node, offset) {
|
|
2502
|
+
while (node && !offset && !hasBlockDesc(node)) {
|
|
2503
|
+
offset = domIndex(node);
|
|
2504
|
+
node = node.parentNode;
|
|
2505
|
+
}
|
|
2506
|
+
while (node && offset) {
|
|
2507
|
+
let next = node.childNodes[offset - 1];
|
|
2508
|
+
if (next.nodeType == 3)
|
|
2509
|
+
return next;
|
|
2510
|
+
if (next.nodeType == 1 && next.contentEditable == "false")
|
|
2511
|
+
break;
|
|
2512
|
+
node = next;
|
|
2513
|
+
offset = node.childNodes.length;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2473
2516
|
function setSelFocus(view, node, offset) {
|
|
2517
|
+
if (node.nodeType != 3) {
|
|
2518
|
+
let before, after;
|
|
2519
|
+
if (after = textNodeAfter(node, offset)) {
|
|
2520
|
+
node = after;
|
|
2521
|
+
offset = 0;
|
|
2522
|
+
}
|
|
2523
|
+
else if (before = textNodeBefore(node, offset)) {
|
|
2524
|
+
node = before;
|
|
2525
|
+
offset = before.nodeValue.length;
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2474
2528
|
let sel = view.domSelection();
|
|
2475
2529
|
if (selectionCollapsed(sel)) {
|
|
2476
2530
|
let range = document.createRange();
|
|
@@ -2617,7 +2671,7 @@ function captureKeyDown(view, event) {
|
|
|
2617
2671
|
return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1);
|
|
2618
2672
|
}
|
|
2619
2673
|
else if (code == 40 || (mac && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac
|
|
2620
|
-
return safariDownArrowBug(view) || selectVertically(view, 1, mods) ||
|
|
2674
|
+
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodes(view, 1);
|
|
2621
2675
|
}
|
|
2622
2676
|
else if (mods == (mac ? "m" : "c") &&
|
|
2623
2677
|
(code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
|
|
@@ -2899,6 +2953,8 @@ class InputState {
|
|
|
2899
2953
|
this.compositionNodes = [];
|
|
2900
2954
|
this.compositionEndedAt = -2e8;
|
|
2901
2955
|
this.compositionID = 1;
|
|
2956
|
+
// Set to a composition ID when there are pending changes at compositionend
|
|
2957
|
+
this.compositionPendingChanges = 0;
|
|
2902
2958
|
this.domChangeCount = 0;
|
|
2903
2959
|
this.eventHandlers = Object.create(null);
|
|
2904
2960
|
this.hideSelectionGuard = null;
|
|
@@ -3328,6 +3384,9 @@ editHandlers.compositionend = (view, event) => {
|
|
|
3328
3384
|
if (view.composing) {
|
|
3329
3385
|
view.input.composing = false;
|
|
3330
3386
|
view.input.compositionEndedAt = event.timeStamp;
|
|
3387
|
+
view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
|
|
3388
|
+
if (view.input.compositionPendingChanges)
|
|
3389
|
+
Promise.resolve().then(() => view.domObserver.flush());
|
|
3331
3390
|
view.input.compositionID++;
|
|
3332
3391
|
scheduleComposeEnd(view, 20);
|
|
3333
3392
|
}
|
|
@@ -3770,6 +3829,10 @@ class Decoration {
|
|
|
3770
3829
|
@internal
|
|
3771
3830
|
*/
|
|
3772
3831
|
get inline() { return this.type instanceof InlineType; }
|
|
3832
|
+
/**
|
|
3833
|
+
@internal
|
|
3834
|
+
*/
|
|
3835
|
+
get widget() { return this.type instanceof WidgetType; }
|
|
3773
3836
|
}
|
|
3774
3837
|
const none = [], noSpec = {};
|
|
3775
3838
|
/**
|
|
@@ -3788,7 +3851,8 @@ class DecorationSet {
|
|
|
3788
3851
|
}
|
|
3789
3852
|
/**
|
|
3790
3853
|
Create a set of decorations, using the structure of the given
|
|
3791
|
-
document.
|
|
3854
|
+
document. This will consume (modify) the `decorations` array, so
|
|
3855
|
+
you must make a copy if you want need to preserve that.
|
|
3792
3856
|
*/
|
|
3793
3857
|
static create(doc, decorations) {
|
|
3794
3858
|
return decorations.length ? buildTree(decorations, doc, 0, noSpec) : empty;
|
|
@@ -3847,8 +3911,9 @@ class DecorationSet {
|
|
|
3847
3911
|
}
|
|
3848
3912
|
/**
|
|
3849
3913
|
Add the given array of decorations to the ones in the set,
|
|
3850
|
-
producing a new set.
|
|
3851
|
-
create the appropriate tree
|
|
3914
|
+
producing a new set. Consumes the `decorations` array. Needs
|
|
3915
|
+
access to the current document to create the appropriate tree
|
|
3916
|
+
structure.
|
|
3852
3917
|
*/
|
|
3853
3918
|
add(doc, decorations) {
|
|
3854
3919
|
if (!decorations.length)
|
|
@@ -4432,15 +4497,19 @@ class DOMObserver {
|
|
|
4432
4497
|
return true;
|
|
4433
4498
|
}
|
|
4434
4499
|
}
|
|
4500
|
+
pendingRecords() {
|
|
4501
|
+
if (this.observer)
|
|
4502
|
+
for (let mut of this.observer.takeRecords())
|
|
4503
|
+
this.queue.push(mut);
|
|
4504
|
+
return this.queue;
|
|
4505
|
+
}
|
|
4435
4506
|
flush() {
|
|
4436
4507
|
let { view } = this;
|
|
4437
4508
|
if (!view.docView || this.flushingSoon > -1)
|
|
4438
4509
|
return;
|
|
4439
|
-
let mutations = this.
|
|
4440
|
-
if (
|
|
4441
|
-
|
|
4442
|
-
this.queue.length = 0;
|
|
4443
|
-
}
|
|
4510
|
+
let mutations = this.pendingRecords();
|
|
4511
|
+
if (mutations.length)
|
|
4512
|
+
this.queue = [];
|
|
4444
4513
|
let sel = view.domSelectionRange();
|
|
4445
4514
|
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
|
|
4446
4515
|
let from = -1, to = -1, typeOver = false, added = [];
|
|
@@ -4661,6 +4730,8 @@ function ruleFromNode(dom) {
|
|
|
4661
4730
|
}
|
|
4662
4731
|
const isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i;
|
|
4663
4732
|
function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
4733
|
+
let compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0);
|
|
4734
|
+
view.input.compositionPendingChanges = 0;
|
|
4664
4735
|
if (from < 0) {
|
|
4665
4736
|
let origin = view.input.lastSelectionTime > Date.now() - 50 ? view.input.lastSelectionOrigin : null;
|
|
4666
4737
|
let newSel = selectionFromDOM(view, origin);
|
|
@@ -4674,8 +4745,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4674
4745
|
tr.setMeta("pointer", true);
|
|
4675
4746
|
else if (origin == "key")
|
|
4676
4747
|
tr.scrollIntoView();
|
|
4677
|
-
if (
|
|
4678
|
-
tr.setMeta("composition",
|
|
4748
|
+
if (compositionID)
|
|
4749
|
+
tr.setMeta("composition", compositionID);
|
|
4679
4750
|
view.dispatch(tr);
|
|
4680
4751
|
}
|
|
4681
4752
|
return;
|
|
@@ -4716,8 +4787,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4716
4787
|
let sel = resolveSelection(view, view.state.doc, parse.sel);
|
|
4717
4788
|
if (sel && !sel.eq(view.state.selection)) {
|
|
4718
4789
|
let tr = view.state.tr.setSelection(sel);
|
|
4719
|
-
if (
|
|
4720
|
-
tr.setMeta("composition",
|
|
4790
|
+
if (compositionID)
|
|
4791
|
+
tr.setMeta("composition", compositionID);
|
|
4721
4792
|
view.dispatch(tr);
|
|
4722
4793
|
}
|
|
4723
4794
|
}
|
|
@@ -4850,8 +4921,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4850
4921
|
}
|
|
4851
4922
|
if (storedMarks)
|
|
4852
4923
|
tr.ensureMarks(storedMarks);
|
|
4853
|
-
if (
|
|
4854
|
-
tr.setMeta("composition",
|
|
4924
|
+
if (compositionID)
|
|
4925
|
+
tr.setMeta("composition", compositionID);
|
|
4855
4926
|
view.dispatch(tr.scrollIntoView());
|
|
4856
4927
|
}
|
|
4857
4928
|
function resolveSelection(view, doc, parsedSel) {
|
package/package.json
CHANGED
package/src/capturekeys.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Selection, NodeSelection, TextSelection, AllSelection, EditorState} from "prosemirror-state"
|
|
2
2
|
import {EditorView} from "./index"
|
|
3
3
|
import * as browser from "./browser"
|
|
4
|
-
import {domIndex, selectionCollapsed} from "./dom"
|
|
4
|
+
import {domIndex, selectionCollapsed, hasBlockDesc} from "./dom"
|
|
5
5
|
import {selectionToDOM} from "./selection"
|
|
6
6
|
|
|
7
7
|
function moveSelectionBlock(state: EditorState, dir: number) {
|
|
@@ -54,9 +54,10 @@ function nodeLen(node: Node) {
|
|
|
54
54
|
return node.nodeType == 3 ? node.nodeValue!.length : node.childNodes.length
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function isIgnorable(dom: Node) {
|
|
57
|
+
function isIgnorable(dom: Node, dir: number) {
|
|
58
|
+
if ((dom as HTMLElement).contentEditable == "false") return true
|
|
58
59
|
let desc = dom.pmViewDesc
|
|
59
|
-
return desc && desc.size == 0 && (dom.nextSibling || dom.nodeName != "BR")
|
|
60
|
+
return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
function skipIgnoredNodes(view: EditorView, dir: number) {
|
|
@@ -73,14 +74,14 @@ function skipIgnoredNodesBefore(view: EditorView) {
|
|
|
73
74
|
// Gecko will do odd things when the selection is directly in front
|
|
74
75
|
// of a non-editable node, so in that case, move it into the next
|
|
75
76
|
// node if possible. Issue prosemirror/prosemirror#832.
|
|
76
|
-
if (browser.gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset])) force = true
|
|
77
|
+
if (browser.gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1)) force = true
|
|
77
78
|
for (;;) {
|
|
78
79
|
if (offset > 0) {
|
|
79
80
|
if (node.nodeType != 1) {
|
|
80
81
|
break
|
|
81
82
|
} else {
|
|
82
83
|
let before = node.childNodes[offset - 1]
|
|
83
|
-
if (isIgnorable(before)) {
|
|
84
|
+
if (isIgnorable(before, -1)) {
|
|
84
85
|
moveNode = node
|
|
85
86
|
moveOffset = --offset
|
|
86
87
|
} else if (before.nodeType == 3) {
|
|
@@ -92,7 +93,7 @@ function skipIgnoredNodesBefore(view: EditorView) {
|
|
|
92
93
|
break
|
|
93
94
|
} else {
|
|
94
95
|
let prev = node.previousSibling
|
|
95
|
-
while (prev && isIgnorable(prev)) {
|
|
96
|
+
while (prev && isIgnorable(prev, -1)) {
|
|
96
97
|
moveNode = node.parentNode
|
|
97
98
|
moveOffset = domIndex(prev)
|
|
98
99
|
prev = prev.previousSibling
|
|
@@ -123,7 +124,7 @@ function skipIgnoredNodesAfter(view: EditorView) {
|
|
|
123
124
|
if (offset < len) {
|
|
124
125
|
if (node.nodeType != 1) break
|
|
125
126
|
let after = node.childNodes[offset]
|
|
126
|
-
if (isIgnorable(after)) {
|
|
127
|
+
if (isIgnorable(after, 1)) {
|
|
127
128
|
moveNode = node
|
|
128
129
|
moveOffset = ++offset
|
|
129
130
|
}
|
|
@@ -132,7 +133,7 @@ function skipIgnoredNodesAfter(view: EditorView) {
|
|
|
132
133
|
break
|
|
133
134
|
} else {
|
|
134
135
|
let next = node.nextSibling
|
|
135
|
-
while (next && isIgnorable(next)) {
|
|
136
|
+
while (next && isIgnorable(next, 1)) {
|
|
136
137
|
moveNode = next.parentNode
|
|
137
138
|
moveOffset = domIndex(next) + 1
|
|
138
139
|
next = next.nextSibling
|
|
@@ -156,7 +157,46 @@ function isBlockNode(dom: Node) {
|
|
|
156
157
|
return desc && desc.node && desc.node.isBlock
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
function textNodeAfter(node: Node | null, offset: number): Text | undefined {
|
|
161
|
+
while (node && offset == node.childNodes.length && !hasBlockDesc(node)) {
|
|
162
|
+
offset = domIndex(node) + 1
|
|
163
|
+
node = node.parentNode
|
|
164
|
+
}
|
|
165
|
+
while (node && offset < node.childNodes.length) {
|
|
166
|
+
let next = node.childNodes[offset]
|
|
167
|
+
if (next.nodeType == 3) return next as Text
|
|
168
|
+
if (next.nodeType == 1 && (next as HTMLElement).contentEditable == "false") break
|
|
169
|
+
node = next
|
|
170
|
+
offset = 0
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function textNodeBefore(node: Node | null, offset: number): Text | undefined {
|
|
175
|
+
while (node && !offset && !hasBlockDesc(node)) {
|
|
176
|
+
offset = domIndex(node)
|
|
177
|
+
node = node.parentNode
|
|
178
|
+
}
|
|
179
|
+
while (node && offset) {
|
|
180
|
+
let next = node.childNodes[offset - 1]
|
|
181
|
+
if (next.nodeType == 3) return next as Text
|
|
182
|
+
if (next.nodeType == 1 && (next as HTMLElement).contentEditable == "false") break
|
|
183
|
+
node = next
|
|
184
|
+
offset = node.childNodes.length
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
159
188
|
function setSelFocus(view: EditorView, node: Node, offset: number) {
|
|
189
|
+
if (node.nodeType != 3) {
|
|
190
|
+
let before, after
|
|
191
|
+
if (after = textNodeAfter(node, offset)) {
|
|
192
|
+
node = after
|
|
193
|
+
offset = 0
|
|
194
|
+
} else if (before = textNodeBefore(node, offset)) {
|
|
195
|
+
node = before
|
|
196
|
+
offset = before.nodeValue!.length
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
160
200
|
let sel = view.domSelection()
|
|
161
201
|
if (selectionCollapsed(sel)) {
|
|
162
202
|
let range = document.createRange()
|
|
@@ -291,7 +331,7 @@ export function captureKeyDown(view: EditorView, event: KeyboardEvent) {
|
|
|
291
331
|
} else if (code == 38 || (browser.mac && code == 80 && mods == "c")) { // Up arrow, Ctrl-p on Mac
|
|
292
332
|
return selectVertically(view, -1, mods) || skipIgnoredNodes(view, -1)
|
|
293
333
|
} else if (code == 40 || (browser.mac && code == 78 && mods == "c")) { // Down arrow, Ctrl-n on Mac
|
|
294
|
-
return safariDownArrowBug(view) || selectVertically(view, 1, mods) ||
|
|
334
|
+
return safariDownArrowBug(view) || selectVertically(view, 1, mods) || skipIgnoredNodes(view, 1)
|
|
295
335
|
} else if (mods == (browser.mac ? "m" : "c") &&
|
|
296
336
|
(code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
|
|
297
337
|
return true
|
package/src/decoration.ts
CHANGED
|
@@ -223,6 +223,9 @@ export class Decoration {
|
|
|
223
223
|
|
|
224
224
|
/// @internal
|
|
225
225
|
get inline() { return this.type instanceof InlineType }
|
|
226
|
+
|
|
227
|
+
/// @internal
|
|
228
|
+
get widget() { return this.type instanceof WidgetType }
|
|
226
229
|
}
|
|
227
230
|
|
|
228
231
|
/// A set of attributes to add to a decorated node. Most properties
|
|
@@ -278,7 +281,8 @@ export class DecorationSet implements DecorationSource {
|
|
|
278
281
|
}
|
|
279
282
|
|
|
280
283
|
/// Create a set of decorations, using the structure of the given
|
|
281
|
-
/// document.
|
|
284
|
+
/// document. This will consume (modify) the `decorations` array, so
|
|
285
|
+
/// you must make a copy if you want need to preserve that.
|
|
282
286
|
static create(doc: Node, decorations: Decoration[]) {
|
|
283
287
|
return decorations.length ? buildTree(decorations, doc, 0, noSpec) : empty
|
|
284
288
|
}
|
|
@@ -302,7 +306,7 @@ export class DecorationSet implements DecorationSource {
|
|
|
302
306
|
result.push(span.copy(span.from + offset, span.to + offset))
|
|
303
307
|
}
|
|
304
308
|
for (let i = 0; i < this.children.length; i += 3) {
|
|
305
|
-
if (this.children[i] < end && this.children[i + 1] > start) {
|
|
309
|
+
if ((this.children[i] as number) < end && (this.children[i + 1] as number) > start) {
|
|
306
310
|
let childOff = (this.children[i] as number) + 1
|
|
307
311
|
;(this.children[i + 2] as DecorationSet).findInner(start - childOff, end - childOff,
|
|
308
312
|
result, offset + childOff, predicate)
|
|
@@ -340,8 +344,9 @@ export class DecorationSet implements DecorationSource {
|
|
|
340
344
|
}
|
|
341
345
|
|
|
342
346
|
/// Add the given array of decorations to the ones in the set,
|
|
343
|
-
/// producing a new set.
|
|
344
|
-
/// create the appropriate tree
|
|
347
|
+
/// producing a new set. Consumes the `decorations` array. Needs
|
|
348
|
+
/// access to the current document to create the appropriate tree
|
|
349
|
+
/// structure.
|
|
345
350
|
add(doc: Node, decorations: Decoration[]) {
|
|
346
351
|
if (!decorations.length) return this
|
|
347
352
|
if (this == empty) return DecorationSet.create(doc, decorations)
|
|
@@ -355,7 +360,7 @@ export class DecorationSet implements DecorationSource {
|
|
|
355
360
|
if (!(found = takeSpansForNode(decorations, childNode, baseOffset))) return
|
|
356
361
|
|
|
357
362
|
if (!children) children = this.children.slice()
|
|
358
|
-
while (childIndex < children.length && children[childIndex] < childOffset) childIndex += 3
|
|
363
|
+
while (childIndex < children.length && (children[childIndex] as number) < childOffset) childIndex += 3
|
|
359
364
|
if (children[childIndex] == childOffset)
|
|
360
365
|
children[childIndex + 2] = (children[childIndex + 2] as DecorationSet).addInner(childNode, found, baseOffset + 1)
|
|
361
366
|
else
|
|
@@ -414,7 +419,7 @@ export class DecorationSet implements DecorationSource {
|
|
|
414
419
|
if (node.isLeaf) return DecorationSet.empty
|
|
415
420
|
|
|
416
421
|
let child, local: Decoration[] | undefined
|
|
417
|
-
for (let i = 0; i < this.children.length; i += 3) if (this.children[i] >= offset) {
|
|
422
|
+
for (let i = 0; i < this.children.length; i += 3) if ((this.children[i] as number) >= offset) {
|
|
418
423
|
if (this.children[i] == offset) child = this.children[i + 2] as DecorationSet
|
|
419
424
|
break
|
|
420
425
|
}
|
|
@@ -576,7 +581,7 @@ function mapChildren(
|
|
|
576
581
|
// Find the child nodes that still correspond to a single node,
|
|
577
582
|
// recursively call mapInner on them and update their positions.
|
|
578
583
|
let mustRebuild = false
|
|
579
|
-
for (let i = 0; i < children.length; i += 3) if (children[i + 1] < 0) { // Touched nodes
|
|
584
|
+
for (let i = 0; i < children.length; i += 3) if ((children[i + 1] as number) < 0) { // Touched nodes
|
|
580
585
|
if (children[i + 1] == -2) {
|
|
581
586
|
mustRebuild = true
|
|
582
587
|
children[i + 1] = -1
|
|
@@ -613,7 +618,7 @@ function mapChildren(
|
|
|
613
618
|
offset, oldOffset, options)
|
|
614
619
|
let built = buildTree(decorations, node, 0, options)
|
|
615
620
|
newLocal = built.local as Decoration[]
|
|
616
|
-
for (let i = 0; i < children.length; i += 3) if (children[i + 1] < 0) {
|
|
621
|
+
for (let i = 0; i < children.length; i += 3) if ((children[i + 1] as number) < 0) {
|
|
617
622
|
children.splice(i, 3)
|
|
618
623
|
i -= 3
|
|
619
624
|
}
|
package/src/dom.ts
CHANGED
|
@@ -74,7 +74,7 @@ export function isOnEdge(node: Node, offset: number, parent: Node) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
function hasBlockDesc(dom: Node) {
|
|
77
|
+
export function hasBlockDesc(dom: Node) {
|
|
78
78
|
let desc
|
|
79
79
|
for (let cur: Node | null = dom; cur; cur = cur.parentNode) if (desc = cur.pmViewDesc) break
|
|
80
80
|
return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom)
|
package/src/domchange.ts
CHANGED
|
@@ -79,6 +79,9 @@ function ruleFromNode(dom: DOMNode): ParseRule | null {
|
|
|
79
79
|
const isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i
|
|
80
80
|
|
|
81
81
|
export function readDOMChange(view: EditorView, from: number, to: number, typeOver: boolean, addedNodes: readonly DOMNode[]) {
|
|
82
|
+
let compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0)
|
|
83
|
+
view.input.compositionPendingChanges = 0
|
|
84
|
+
|
|
82
85
|
if (from < 0) {
|
|
83
86
|
let origin = view.input.lastSelectionTime > Date.now() - 50 ? view.input.lastSelectionOrigin : null
|
|
84
87
|
let newSel = selectionFromDOM(view, origin)
|
|
@@ -90,7 +93,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
90
93
|
let tr = view.state.tr.setSelection(newSel)
|
|
91
94
|
if (origin == "pointer") tr.setMeta("pointer", true)
|
|
92
95
|
else if (origin == "key") tr.scrollIntoView()
|
|
93
|
-
if (
|
|
96
|
+
if (compositionID) tr.setMeta("composition", compositionID)
|
|
94
97
|
view.dispatch(tr)
|
|
95
98
|
}
|
|
96
99
|
return
|
|
@@ -133,7 +136,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
133
136
|
let sel = resolveSelection(view, view.state.doc, parse.sel)
|
|
134
137
|
if (sel && !sel.eq(view.state.selection)) {
|
|
135
138
|
let tr = view.state.tr.setSelection(sel)
|
|
136
|
-
if (
|
|
139
|
+
if (compositionID) tr.setMeta("composition", compositionID)
|
|
137
140
|
view.dispatch(tr)
|
|
138
141
|
}
|
|
139
142
|
}
|
|
@@ -268,7 +271,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
268
271
|
tr.setSelection(sel)
|
|
269
272
|
}
|
|
270
273
|
if (storedMarks) tr.ensureMarks(storedMarks)
|
|
271
|
-
if (
|
|
274
|
+
if (compositionID) tr.setMeta("composition", compositionID)
|
|
272
275
|
view.dispatch(tr.scrollIntoView())
|
|
273
276
|
}
|
|
274
277
|
|
package/src/domcoords.ts
CHANGED
|
@@ -37,7 +37,9 @@ export function scrollRectIntoView(view: EditorView, rect: Rect, startDOM: Node)
|
|
|
37
37
|
if (rect.top < bounding.top + getSide(scrollThreshold, "top"))
|
|
38
38
|
moveY = -(bounding.top - rect.top + getSide(scrollMargin, "top"))
|
|
39
39
|
else if (rect.bottom > bounding.bottom - getSide(scrollThreshold, "bottom"))
|
|
40
|
-
moveY = rect.bottom - bounding.bottom
|
|
40
|
+
moveY = rect.bottom - rect.top > bounding.bottom - bounding.top
|
|
41
|
+
? rect.top + getSide(scrollMargin, "top") - bounding.top
|
|
42
|
+
: rect.bottom - bounding.bottom + getSide(scrollMargin, "bottom")
|
|
41
43
|
if (rect.left < bounding.left + getSide(scrollThreshold, "left"))
|
|
42
44
|
moveX = -(bounding.left - rect.left + getSide(scrollMargin, "left"))
|
|
43
45
|
else if (rect.right > bounding.right - getSide(scrollThreshold, "right"))
|
package/src/domobserver.ts
CHANGED
|
@@ -157,14 +157,16 @@ export class DOMObserver {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
pendingRecords() {
|
|
161
|
+
if (this.observer) for (let mut of this.observer.takeRecords()) this.queue.push(mut)
|
|
162
|
+
return this.queue
|
|
163
|
+
}
|
|
164
|
+
|
|
160
165
|
flush() {
|
|
161
166
|
let {view} = this
|
|
162
167
|
if (!view.docView || this.flushingSoon > -1) return
|
|
163
|
-
let mutations = this.
|
|
164
|
-
if (
|
|
165
|
-
mutations = this.queue.concat(mutations)
|
|
166
|
-
this.queue.length = 0
|
|
167
|
-
}
|
|
168
|
+
let mutations = this.pendingRecords()
|
|
169
|
+
if (mutations.length) this.queue = []
|
|
168
170
|
|
|
169
171
|
let sel = view.domSelectionRange()
|
|
170
172
|
let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel)
|
package/src/input.ts
CHANGED
|
@@ -34,6 +34,8 @@ export class InputState {
|
|
|
34
34
|
compositionNodes: ViewDesc[] = []
|
|
35
35
|
compositionEndedAt = -2e8
|
|
36
36
|
compositionID = 1
|
|
37
|
+
// Set to a composition ID when there are pending changes at compositionend
|
|
38
|
+
compositionPendingChanges = 0
|
|
37
39
|
domChangeCount = 0
|
|
38
40
|
eventHandlers: {[event: string]: (event: Event) => void} = Object.create(null)
|
|
39
41
|
hideSelectionGuard: (() => void) | null = null
|
|
@@ -487,6 +489,8 @@ editHandlers.compositionend = (view, event) => {
|
|
|
487
489
|
if (view.composing) {
|
|
488
490
|
view.input.composing = false
|
|
489
491
|
view.input.compositionEndedAt = event.timeStamp
|
|
492
|
+
view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0
|
|
493
|
+
if (view.input.compositionPendingChanges) Promise.resolve().then(() => view.domObserver.flush())
|
|
490
494
|
view.input.compositionID++
|
|
491
495
|
scheduleComposeEnd(view, 20)
|
|
492
496
|
}
|
package/src/viewdesc.ts
CHANGED
|
@@ -387,7 +387,7 @@ export class ViewDesc {
|
|
|
387
387
|
brKludge = !!(offset && node.nodeValue![offset - 1] == "\n")
|
|
388
388
|
// Issue #1128
|
|
389
389
|
if (brKludge && offset == node.nodeValue!.length) {
|
|
390
|
-
|
|
390
|
+
for (let scan: DOMNode | null = node, after; scan; scan = scan.parentNode) {
|
|
391
391
|
if (after = scan.nextSibling) {
|
|
392
392
|
if (after.nodeName == "BR")
|
|
393
393
|
anchorDOM = headDOM = {node: after.parentNode!, offset: domIndex(after) + 1}
|
|
@@ -1244,9 +1244,11 @@ class ViewTreeUpdater {
|
|
|
1244
1244
|
return true
|
|
1245
1245
|
} else if (!locked && (updated = this.recreateWrapper(next, node, outerDeco, innerDeco, view, pos))) {
|
|
1246
1246
|
this.top.children[this.index] = updated
|
|
1247
|
-
updated.
|
|
1248
|
-
|
|
1249
|
-
|
|
1247
|
+
if (updated.contentDOM) {
|
|
1248
|
+
updated.dirty = CONTENT_DIRTY
|
|
1249
|
+
updated.updateChildren(view, pos + 1)
|
|
1250
|
+
updated.dirty = NOT_DIRTY
|
|
1251
|
+
}
|
|
1250
1252
|
this.changed = true
|
|
1251
1253
|
this.index++
|
|
1252
1254
|
return true
|
|
@@ -1264,12 +1266,12 @@ class ViewTreeUpdater {
|
|
|
1264
1266
|
if (next.dirty || node.isAtom || !next.children.length ||
|
|
1265
1267
|
!next.node.content.eq(node.content)) return null
|
|
1266
1268
|
let wrapper = NodeViewDesc.create(this.top, node, outerDeco, innerDeco, view, pos)
|
|
1267
|
-
if (
|
|
1268
|
-
|
|
1269
|
-
|
|
1269
|
+
if (wrapper.contentDOM) {
|
|
1270
|
+
wrapper.children = next.children
|
|
1271
|
+
next.children = []
|
|
1272
|
+
for (let ch of wrapper.children) ch.parent = wrapper
|
|
1273
|
+
}
|
|
1270
1274
|
next.destroy()
|
|
1271
|
-
for (let ch of wrapper.children) ch.parent = wrapper
|
|
1272
|
-
|
|
1273
1275
|
return wrapper
|
|
1274
1276
|
}
|
|
1275
1277
|
|
|
@@ -1403,10 +1405,15 @@ function iterDeco(
|
|
|
1403
1405
|
|
|
1404
1406
|
let decoIndex = 0, active = [], restNode = null
|
|
1405
1407
|
for (let parentIndex = 0;;) {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1408
|
+
let widget, widgets
|
|
1409
|
+
while (decoIndex < locals.length && locals[decoIndex].to == offset) {
|
|
1410
|
+
let next = locals[decoIndex++]
|
|
1411
|
+
if (next.widget) {
|
|
1412
|
+
if (!widget) widget = next
|
|
1413
|
+
else (widgets || (widgets = [widget])).push(next)
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
if (widget) {
|
|
1410
1417
|
if (widgets) {
|
|
1411
1418
|
widgets.sort(compareSide)
|
|
1412
1419
|
for (let i = 0; i < widgets.length; i++) onWidget(widgets[i], parentIndex, !!restNode)
|