prosemirror-view 1.41.8 → 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 +18 -0
- package/dist/index.cjs +231 -146
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +136 -72
- package/package.json +2 -2
- package/src/clipboard.ts +14 -3
- package/src/domchange.ts +3 -13
- package/src/domobserver.ts +4 -1
- package/src/index.ts +3 -2
- package/src/input.ts +88 -34
- package/src/selection.ts +6 -6
- package/src/viewdesc.ts +31 -14
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1517
|
-
super(parent, node, outerDeco, innerDeco, dom, null, nodeDOM
|
|
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,
|
|
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
|
|
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
|
|
1582
|
-
super(parent, node, outerDeco, innerDeco, dom, contentDOM, nodeDOM
|
|
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;
|
|
@@ -2244,14 +2257,14 @@ function selectionToDOM(view, force = false) {
|
|
|
2244
2257
|
syncNodeSelection(view, sel);
|
|
2245
2258
|
if (!editorOwnsSelection(view))
|
|
2246
2259
|
return;
|
|
2247
|
-
//
|
|
2248
|
-
//
|
|
2249
|
-
|
|
2250
|
-
if (!force &&
|
|
2260
|
+
// Need to delay selection normalization during a native selection
|
|
2261
|
+
// drag on Chrome, or it will cause further dragging to glitch.
|
|
2262
|
+
let mouseDown = view.input.mouseDown;
|
|
2263
|
+
if (!force && chrome && mouseDown) {
|
|
2251
2264
|
let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
|
|
2252
2265
|
if (domSel.anchorNode && curSel.anchorNode &&
|
|
2253
|
-
isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)
|
|
2254
|
-
|
|
2266
|
+
isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset) &&
|
|
2267
|
+
mouseDown.delaySelUpdate()) {
|
|
2255
2268
|
view.domObserver.setCurSelection();
|
|
2256
2269
|
return;
|
|
2257
2270
|
}
|
|
@@ -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
|
|
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
|
|
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
|
|
@@ -3103,6 +3127,8 @@ function setSelectionOrigin(view, origin) {
|
|
|
3103
3127
|
view.input.lastSelectionTime = Date.now();
|
|
3104
3128
|
}
|
|
3105
3129
|
function destroyInput(view) {
|
|
3130
|
+
if (view.input.mouseDown)
|
|
3131
|
+
view.input.mouseDown.done();
|
|
3106
3132
|
view.domObserver.stop();
|
|
3107
3133
|
for (let type in view.input.eventHandlers)
|
|
3108
3134
|
view.dom.removeEventListener(type, view.input.eventHandlers[type]);
|
|
@@ -3141,7 +3167,7 @@ function dispatchEvent(view, event) {
|
|
|
3141
3167
|
editHandlers.keydown = (view, _event) => {
|
|
3142
3168
|
let event = _event;
|
|
3143
3169
|
view.input.shiftKey = event.keyCode == 16 || event.shiftKey;
|
|
3144
|
-
if (inOrNearComposition(view
|
|
3170
|
+
if (inOrNearComposition(view))
|
|
3145
3171
|
return;
|
|
3146
3172
|
view.input.lastKeyCode = event.keyCode;
|
|
3147
3173
|
view.input.lastKeyCodeTime = Date.now();
|
|
@@ -3179,7 +3205,7 @@ editHandlers.keyup = (view, event) => {
|
|
|
3179
3205
|
};
|
|
3180
3206
|
editHandlers.keypress = (view, _event) => {
|
|
3181
3207
|
let event = _event;
|
|
3182
|
-
if (inOrNearComposition(view
|
|
3208
|
+
if (inOrNearComposition(view) || !event.charCode ||
|
|
3183
3209
|
event.ctrlKey && !event.altKey || mac && event.metaKey)
|
|
3184
3210
|
return;
|
|
3185
3211
|
if (view.someProp("handleKeyPress", f => f(view, event))) {
|
|
@@ -3274,26 +3300,28 @@ function handleTripleClick(view, pos, inside, event) {
|
|
|
3274
3300
|
function defaultTripleClick(view, inside, event) {
|
|
3275
3301
|
if (event.button != 0)
|
|
3276
3302
|
return false;
|
|
3277
|
-
let doc = view.state.doc;
|
|
3278
|
-
if (
|
|
3279
|
-
if (doc.inlineContent) {
|
|
3280
|
-
updateSelection(view, TextSelection.create(doc, 0, doc.content.size), "pointer");
|
|
3281
|
-
return true;
|
|
3282
|
-
}
|
|
3303
|
+
let selection = selectionForTripleClick(view, inside, true), doc = view.state.doc;
|
|
3304
|
+
if (!selection)
|
|
3283
3305
|
return false;
|
|
3284
|
-
|
|
3306
|
+
updateSelection(view, selection, "pointer");
|
|
3307
|
+
if (selection instanceof TextSelection && doc.eq(view.state.doc))
|
|
3308
|
+
view.input.mouseDown = new TripleClickDrag(view, selection);
|
|
3309
|
+
return true;
|
|
3310
|
+
}
|
|
3311
|
+
function selectionForTripleClick(view, inside, selectNodes) {
|
|
3312
|
+
let doc = view.state.doc;
|
|
3313
|
+
if (inside == -1)
|
|
3314
|
+
return doc.inlineContent ? TextSelection.create(doc, 0, doc.content.size) : null;
|
|
3285
3315
|
let $pos = doc.resolve(inside);
|
|
3286
3316
|
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
3287
3317
|
let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
|
|
3288
3318
|
let nodePos = $pos.before(i);
|
|
3289
3319
|
if (node.inlineContent)
|
|
3290
|
-
|
|
3291
|
-
else if (NodeSelection.isSelectable(node))
|
|
3292
|
-
|
|
3293
|
-
else
|
|
3294
|
-
continue;
|
|
3295
|
-
return true;
|
|
3320
|
+
return TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size);
|
|
3321
|
+
else if (selectNodes && NodeSelection.isSelectable(node))
|
|
3322
|
+
return NodeSelection.create(doc, nodePos);
|
|
3296
3323
|
}
|
|
3324
|
+
return null;
|
|
3297
3325
|
}
|
|
3298
3326
|
function forceDOMFlush(view) {
|
|
3299
3327
|
return endComposition(view);
|
|
@@ -3312,13 +3340,13 @@ handlers.mousedown = (view, _event) => {
|
|
|
3312
3340
|
type = "tripleClick";
|
|
3313
3341
|
}
|
|
3314
3342
|
view.input.lastClick = { time: now, x: event.clientX, y: event.clientY, type, button: event.button };
|
|
3343
|
+
if (view.input.mouseDown)
|
|
3344
|
+
view.input.mouseDown.done();
|
|
3315
3345
|
let pos = view.posAtCoords(eventCoords(event));
|
|
3316
3346
|
if (!pos)
|
|
3317
3347
|
return;
|
|
3318
3348
|
if (type == "singleClick") {
|
|
3319
|
-
|
|
3320
|
-
view.input.mouseDown.done();
|
|
3321
|
-
view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);
|
|
3349
|
+
view.input.mouseDown = new LeftMouseDown(view, pos, event, !!flushed);
|
|
3322
3350
|
}
|
|
3323
3351
|
else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
|
|
3324
3352
|
event.preventDefault();
|
|
@@ -3328,13 +3356,34 @@ handlers.mousedown = (view, _event) => {
|
|
|
3328
3356
|
}
|
|
3329
3357
|
};
|
|
3330
3358
|
class MouseDown {
|
|
3331
|
-
constructor(view
|
|
3359
|
+
constructor(view) {
|
|
3332
3360
|
this.view = view;
|
|
3361
|
+
this.mightDrag = null;
|
|
3362
|
+
view.root.addEventListener("mouseup", this.up = this.up.bind(this));
|
|
3363
|
+
view.root.addEventListener("mousemove", this.move = this.move.bind(this));
|
|
3364
|
+
}
|
|
3365
|
+
up(event) {
|
|
3366
|
+
this.done();
|
|
3367
|
+
}
|
|
3368
|
+
move(event) {
|
|
3369
|
+
if (event.buttons == 0)
|
|
3370
|
+
this.done();
|
|
3371
|
+
}
|
|
3372
|
+
done() {
|
|
3373
|
+
this.view.root.removeEventListener("mouseup", this.up);
|
|
3374
|
+
this.view.root.removeEventListener("mousemove", this.move);
|
|
3375
|
+
if (this.view.input.mouseDown == this)
|
|
3376
|
+
this.view.input.mouseDown = null;
|
|
3377
|
+
}
|
|
3378
|
+
delaySelUpdate() { return false; }
|
|
3379
|
+
}
|
|
3380
|
+
class LeftMouseDown extends MouseDown {
|
|
3381
|
+
constructor(view, pos, event, flushed) {
|
|
3382
|
+
super(view);
|
|
3333
3383
|
this.pos = pos;
|
|
3334
3384
|
this.event = event;
|
|
3335
3385
|
this.flushed = flushed;
|
|
3336
3386
|
this.delayedSelectionSync = false;
|
|
3337
|
-
this.mightDrag = null;
|
|
3338
3387
|
this.startDoc = view.state.doc;
|
|
3339
3388
|
this.selectNode = !!event[selectNodeModifier];
|
|
3340
3389
|
this.allowDefault = event.shiftKey;
|
|
@@ -3372,13 +3421,10 @@ class MouseDown {
|
|
|
3372
3421
|
}, 20);
|
|
3373
3422
|
this.view.domObserver.start();
|
|
3374
3423
|
}
|
|
3375
|
-
view.root.addEventListener("mouseup", this.up = this.up.bind(this));
|
|
3376
|
-
view.root.addEventListener("mousemove", this.move = this.move.bind(this));
|
|
3377
3424
|
setSelectionOrigin(view, "pointer");
|
|
3378
3425
|
}
|
|
3379
3426
|
done() {
|
|
3380
|
-
|
|
3381
|
-
this.view.root.removeEventListener("mousemove", this.move);
|
|
3427
|
+
super.done();
|
|
3382
3428
|
if (this.mightDrag && this.target) {
|
|
3383
3429
|
this.view.domObserver.stop();
|
|
3384
3430
|
if (this.mightDrag.addAttr)
|
|
@@ -3388,8 +3434,10 @@ class MouseDown {
|
|
|
3388
3434
|
this.view.domObserver.start();
|
|
3389
3435
|
}
|
|
3390
3436
|
if (this.delayedSelectionSync)
|
|
3391
|
-
setTimeout(() =>
|
|
3392
|
-
|
|
3437
|
+
setTimeout(() => {
|
|
3438
|
+
if (!this.view.isDestroyed)
|
|
3439
|
+
selectionToDOM(this.view);
|
|
3440
|
+
});
|
|
3393
3441
|
}
|
|
3394
3442
|
up(event) {
|
|
3395
3443
|
this.done();
|
|
@@ -3428,14 +3476,41 @@ class MouseDown {
|
|
|
3428
3476
|
move(event) {
|
|
3429
3477
|
this.updateAllowDefault(event);
|
|
3430
3478
|
setSelectionOrigin(this.view, "pointer");
|
|
3431
|
-
|
|
3432
|
-
this.done();
|
|
3479
|
+
super.move(event);
|
|
3433
3480
|
}
|
|
3434
3481
|
updateAllowDefault(event) {
|
|
3435
3482
|
if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
|
|
3436
3483
|
Math.abs(this.event.y - event.clientY) > 4))
|
|
3437
3484
|
this.allowDefault = true;
|
|
3438
3485
|
}
|
|
3486
|
+
delaySelUpdate() {
|
|
3487
|
+
if (!this.allowDefault)
|
|
3488
|
+
return false;
|
|
3489
|
+
this.delayedSelectionSync = true;
|
|
3490
|
+
return true;
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
class TripleClickDrag extends MouseDown {
|
|
3494
|
+
constructor(view, startSelection) {
|
|
3495
|
+
super(view);
|
|
3496
|
+
this.startSelection = startSelection;
|
|
3497
|
+
this.startDoc = view.state.doc;
|
|
3498
|
+
}
|
|
3499
|
+
move(event) {
|
|
3500
|
+
if (event.buttons == 0 || this.view.isDestroyed || !this.view.state.doc.eq(this.startDoc)) {
|
|
3501
|
+
this.done();
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
event.preventDefault();
|
|
3505
|
+
setSelectionOrigin(this.view, "pointer");
|
|
3506
|
+
let pos = this.view.posAtCoords(eventCoords(event));
|
|
3507
|
+
let target = pos && selectionForTripleClick(this.view, pos.inside, false);
|
|
3508
|
+
if (!target)
|
|
3509
|
+
return;
|
|
3510
|
+
let { doc } = this.view.state, start = this.startSelection;
|
|
3511
|
+
let [anchor, head] = target.from < start.from ? [start.to, target.from] : [start.from, target.to];
|
|
3512
|
+
updateSelection(this.view, TextSelection.create(doc, anchor, head), "pointer");
|
|
3513
|
+
}
|
|
3439
3514
|
}
|
|
3440
3515
|
handlers.touchstart = view => {
|
|
3441
3516
|
view.input.lastTouch = Date.now();
|
|
@@ -3460,7 +3535,7 @@ function inOrNearComposition(view, event) {
|
|
|
3460
3535
|
// This guards against the case where compositionend is triggered without the keyboard
|
|
3461
3536
|
// (e.g. character confirmation may be done with the mouse), and keydown is triggered
|
|
3462
3537
|
// afterwards- we wouldn't want to ignore the keydown event in this case.
|
|
3463
|
-
if (safari && Math.abs(
|
|
3538
|
+
if (safari && Math.abs(Date.now() - view.input.compositionEndedAt) < 500) {
|
|
3464
3539
|
view.input.compositionEndedAt = -2e8;
|
|
3465
3540
|
return true;
|
|
3466
3541
|
}
|
|
@@ -3519,7 +3594,7 @@ function selectionBeforeUneditable(view) {
|
|
|
3519
3594
|
editHandlers.compositionend = (view, event) => {
|
|
3520
3595
|
if (view.composing) {
|
|
3521
3596
|
view.input.composing = false;
|
|
3522
|
-
view.input.compositionEndedAt =
|
|
3597
|
+
view.input.compositionEndedAt = Date.now();
|
|
3523
3598
|
view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
|
|
3524
3599
|
view.input.compositionNode = null;
|
|
3525
3600
|
if (view.input.badSafariComposition)
|
|
@@ -3538,7 +3613,7 @@ function scheduleComposeEnd(view, delay) {
|
|
|
3538
3613
|
function clearComposition(view) {
|
|
3539
3614
|
if (view.composing) {
|
|
3540
3615
|
view.input.composing = false;
|
|
3541
|
-
view.input.compositionEndedAt =
|
|
3616
|
+
view.input.compositionEndedAt = Date.now();
|
|
3542
3617
|
}
|
|
3543
3618
|
while (view.input.compositionNodes.length > 0)
|
|
3544
3619
|
view.input.compositionNodes.pop().markParentsDirty();
|
|
@@ -3564,11 +3639,6 @@ function findCompositionNode(view) {
|
|
|
3564
3639
|
}
|
|
3565
3640
|
return textBefore || textAfter;
|
|
3566
3641
|
}
|
|
3567
|
-
function timestampFromCustomEvent() {
|
|
3568
|
-
let event = document.createEvent("Event");
|
|
3569
|
-
event.initEvent("event", true, true);
|
|
3570
|
-
return event.timeStamp;
|
|
3571
|
-
}
|
|
3572
3642
|
/**
|
|
3573
3643
|
@internal
|
|
3574
3644
|
*/
|
|
@@ -4725,7 +4795,10 @@ class DOMObserver {
|
|
|
4725
4795
|
}
|
|
4726
4796
|
}
|
|
4727
4797
|
}
|
|
4728
|
-
if (added.some(n => n.nodeName == "BR") &&
|
|
4798
|
+
if (added.some(n => n.nodeName == "BR") &&
|
|
4799
|
+
(view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46 ||
|
|
4800
|
+
chrome && (view.composing || view.input.compositionEndedAt > Date.now() - 50) &&
|
|
4801
|
+
mutations.some(m => m.type == "childList" && m.removedNodes.length))) {
|
|
4729
4802
|
// Browsers sometimes insert a bogus break node if you
|
|
4730
4803
|
// backspace out the last bit of text before an inline-flex node (#1552)
|
|
4731
4804
|
for (let node of added)
|
|
@@ -5281,38 +5354,28 @@ function skipClosingAndOpening($pos, fromEnd, mayOpen) {
|
|
|
5281
5354
|
return end;
|
|
5282
5355
|
}
|
|
5283
5356
|
function findDiff(a, b, pos, preferredPos, preferredSide) {
|
|
5284
|
-
let start = a.findDiffStart(b, pos);
|
|
5357
|
+
let start = a.findDiffStart(b, pos), lenA = pos + a.size, lenB = pos + b.size;
|
|
5285
5358
|
if (start == null)
|
|
5286
5359
|
return null;
|
|
5287
|
-
let { a: endA, b: endB } = a.findDiffEnd(b,
|
|
5360
|
+
let { a: endA, b: endB } = a.findDiffEnd(b, lenA, lenB);
|
|
5288
5361
|
if (preferredSide == "end") {
|
|
5289
5362
|
let adjust = Math.max(0, start - Math.min(endA, endB));
|
|
5290
5363
|
preferredPos -= endA + adjust - start;
|
|
5291
5364
|
}
|
|
5292
|
-
if (endA < start &&
|
|
5365
|
+
if (endA < start && lenA < lenB) {
|
|
5293
5366
|
let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
|
|
5294
5367
|
start -= move;
|
|
5295
|
-
if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
|
|
5296
|
-
start += move ? 1 : -1;
|
|
5297
5368
|
endB = start + (endB - endA);
|
|
5298
5369
|
endA = start;
|
|
5299
5370
|
}
|
|
5300
5371
|
else if (endB < start) {
|
|
5301
5372
|
let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
|
|
5302
5373
|
start -= move;
|
|
5303
|
-
if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
|
|
5304
|
-
start += move ? 1 : -1;
|
|
5305
5374
|
endA = start + (endA - endB);
|
|
5306
5375
|
endB = start;
|
|
5307
5376
|
}
|
|
5308
5377
|
return { start, endA, endB };
|
|
5309
5378
|
}
|
|
5310
|
-
function isSurrogatePair(str) {
|
|
5311
|
-
if (str.length != 2)
|
|
5312
|
-
return false;
|
|
5313
|
-
let a = str.charCodeAt(0), b = str.charCodeAt(1);
|
|
5314
|
-
return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
|
|
5315
|
-
}
|
|
5316
5379
|
|
|
5317
5380
|
/**
|
|
5318
5381
|
@internal
|
|
@@ -5513,9 +5576,10 @@ class EditorView {
|
|
|
5513
5576
|
// a DOM selection change and the "selectionchange" event for it
|
|
5514
5577
|
// can cause a spurious DOM selection update, disrupting mouse
|
|
5515
5578
|
// drag selection.
|
|
5579
|
+
let mouseDown = this.input.mouseDown;
|
|
5516
5580
|
if (forceSelUpdate ||
|
|
5517
|
-
!(
|
|
5518
|
-
anchorInRightPlace(this))) {
|
|
5581
|
+
!(mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
|
|
5582
|
+
anchorInRightPlace(this) && mouseDown.delaySelUpdate())) {
|
|
5519
5583
|
selectionToDOM(this, forceSelUpdate);
|
|
5520
5584
|
}
|
|
5521
5585
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prosemirror-view",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.42.0",
|
|
4
4
|
"description": "ProseMirror's view component",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"url": "git+https://code.haverbeke.berlin/prosemirror/prosemirror-view.git"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"prosemirror-model": "^1.
|
|
31
|
+
"prosemirror-model": "^1.25.8",
|
|
32
32
|
"prosemirror-state": "^1.0.0",
|
|
33
33
|
"prosemirror-transform": "^1.1.0"
|
|
34
34
|
},
|
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
|
|
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
|
|
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/domchange.ts
CHANGED
|
@@ -351,33 +351,23 @@ function skipClosingAndOpening($pos: ResolvedPos, fromEnd: boolean, mayOpen: boo
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
function findDiff(a: Fragment, b: Fragment, pos: number, preferredPos: number, preferredSide: "start" | "end") {
|
|
354
|
-
let start = a.findDiffStart(b, pos)
|
|
354
|
+
let start = a.findDiffStart(b, pos), lenA = pos + a.size, lenB = pos + b.size
|
|
355
355
|
if (start == null) return null
|
|
356
|
-
let {a: endA, b: endB} = a.findDiffEnd(b,
|
|
356
|
+
let {a: endA, b: endB} = a.findDiffEnd(b, lenA, lenB)!
|
|
357
357
|
if (preferredSide == "end") {
|
|
358
358
|
let adjust = Math.max(0, start - Math.min(endA, endB))
|
|
359
359
|
preferredPos -= endA + adjust - start
|
|
360
360
|
}
|
|
361
|
-
if (endA < start &&
|
|
361
|
+
if (endA < start && lenA < lenB) {
|
|
362
362
|
let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0
|
|
363
363
|
start -= move
|
|
364
|
-
if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
|
|
365
|
-
start += move ? 1 : -1
|
|
366
364
|
endB = start + (endB - endA)
|
|
367
365
|
endA = start
|
|
368
366
|
} else if (endB < start) {
|
|
369
367
|
let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0
|
|
370
368
|
start -= move
|
|
371
|
-
if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
|
|
372
|
-
start += move ? 1 : -1
|
|
373
369
|
endA = start + (endA - endB)
|
|
374
370
|
endB = start
|
|
375
371
|
}
|
|
376
372
|
return {start, endA, endB}
|
|
377
373
|
}
|
|
378
|
-
|
|
379
|
-
function isSurrogatePair(str: string) {
|
|
380
|
-
if (str.length != 2) return false
|
|
381
|
-
let a = str.charCodeAt(0), b = str.charCodeAt(1)
|
|
382
|
-
return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF
|
|
383
|
-
}
|
package/src/domobserver.ts
CHANGED
|
@@ -192,7 +192,10 @@ export class DOMObserver {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
if (added.some(n => n.nodeName == "BR") &&
|
|
195
|
+
if (added.some(n => n.nodeName == "BR") &&
|
|
196
|
+
(view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46 ||
|
|
197
|
+
browser.chrome && (view.composing || view.input.compositionEndedAt > Date.now() - 50) &&
|
|
198
|
+
mutations.some(m => m.type == "childList" && m.removedNodes.length))) {
|
|
196
199
|
// Browsers sometimes insert a bogus break node if you
|
|
197
200
|
// backspace out the last bit of text before an inline-flex node (#1552)
|
|
198
201
|
for (let node of added) if (node.nodeName == "BR" && node.parentNode) {
|
package/src/index.ts
CHANGED
|
@@ -208,9 +208,10 @@ export class EditorView {
|
|
|
208
208
|
// a DOM selection change and the "selectionchange" event for it
|
|
209
209
|
// can cause a spurious DOM selection update, disrupting mouse
|
|
210
210
|
// drag selection.
|
|
211
|
+
let mouseDown = this.input.mouseDown
|
|
211
212
|
if (forceSelUpdate ||
|
|
212
|
-
!(
|
|
213
|
-
anchorInRightPlace(this))) {
|
|
213
|
+
!(mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
|
|
214
|
+
anchorInRightPlace(this) && mouseDown.delaySelUpdate())) {
|
|
214
215
|
selectionToDOM(this, forceSelUpdate)
|
|
215
216
|
} else {
|
|
216
217
|
syncNodeSelection(this, state.selection)
|