prosemirror-view 1.41.3 → 1.41.4
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 +10 -0
- package/dist/index.cjs +47 -12
- package/dist/index.js +37 -10
- package/package.json +1 -1
- package/src/dom.ts +1 -1
- package/src/domchange.ts +1 -1
- package/src/domcoords.ts +7 -4
- package/src/domobserver.ts +9 -0
- package/src/index.ts +1 -1
- package/src/input.ts +17 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 1.41.4 (2025-12-01)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
`EditorView.dragging` is now only cleared after the drop event has entirely been handled.
|
|
6
|
+
|
|
7
|
+
Add a workaround for an issue where Chrome and Safari will, if you backspace out the last text before an inline-flex node, insert a bogus hard break.
|
|
8
|
+
|
|
9
|
+
Fix a composition problem on Chrome Windows when starting a composition before an absolutely positioned widget.
|
|
10
|
+
|
|
1
11
|
## 1.41.3 (2025-10-09)
|
|
2
12
|
|
|
3
13
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -360,18 +360,23 @@ function findOffsetInNode(node, coords) {
|
|
|
360
360
|
}
|
|
361
361
|
function findOffsetInText(node, coords) {
|
|
362
362
|
var len = node.nodeValue.length;
|
|
363
|
-
var range = document.createRange()
|
|
363
|
+
var range = document.createRange(),
|
|
364
|
+
result;
|
|
364
365
|
for (var i = 0; i < len; i++) {
|
|
365
366
|
range.setEnd(node, i + 1);
|
|
366
367
|
range.setStart(node, i);
|
|
367
368
|
var rect = singleRect(range, 1);
|
|
368
369
|
if (rect.top == rect.bottom) continue;
|
|
369
|
-
if (inRect(coords, rect))
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
370
|
+
if (inRect(coords, rect)) {
|
|
371
|
+
result = {
|
|
372
|
+
node: node,
|
|
373
|
+
offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)
|
|
374
|
+
};
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
373
377
|
}
|
|
374
|
-
|
|
378
|
+
range.detach();
|
|
379
|
+
return result || {
|
|
375
380
|
node: node,
|
|
376
381
|
offset: 0
|
|
377
382
|
};
|
|
@@ -3272,7 +3277,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
|
|
|
3272
3277
|
$pos = state.selection.$to;
|
|
3273
3278
|
if (state.selection instanceof prosemirrorState.TextSelection && (state.storedMarks || !$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) {
|
|
3274
3279
|
return m.type.spec.inclusive === false;
|
|
3275
|
-
}))) {
|
|
3280
|
+
}) || chrome && windows && selectionBeforeUneditable(view))) {
|
|
3276
3281
|
view.markCursor = view.state.storedMarks || $pos.marks();
|
|
3277
3282
|
endComposition(view, true);
|
|
3278
3283
|
view.markCursor = null;
|
|
@@ -3298,6 +3303,14 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
|
|
|
3298
3303
|
}
|
|
3299
3304
|
scheduleComposeEnd(view, timeoutComposition);
|
|
3300
3305
|
};
|
|
3306
|
+
function selectionBeforeUneditable(view) {
|
|
3307
|
+
var _view$domSelectionRan4 = view.domSelectionRange(),
|
|
3308
|
+
focusNode = _view$domSelectionRan4.focusNode,
|
|
3309
|
+
focusOffset = _view$domSelectionRan4.focusOffset;
|
|
3310
|
+
if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length) return false;
|
|
3311
|
+
var next = focusNode.childNodes[focusOffset];
|
|
3312
|
+
return next.nodeType == 1 && next.contentEditable == "false";
|
|
3313
|
+
}
|
|
3301
3314
|
editHandlers.compositionend = function (view, event) {
|
|
3302
3315
|
if (view.composing) {
|
|
3303
3316
|
view.input.composing = false;
|
|
@@ -3485,10 +3498,14 @@ handlers.dragend = function (view) {
|
|
|
3485
3498
|
editHandlers.dragover = editHandlers.dragenter = function (_, e) {
|
|
3486
3499
|
return e.preventDefault();
|
|
3487
3500
|
};
|
|
3488
|
-
editHandlers.drop = function (view,
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3501
|
+
editHandlers.drop = function (view, event) {
|
|
3502
|
+
try {
|
|
3503
|
+
handleDrop(view, event, view.dragging);
|
|
3504
|
+
} finally {
|
|
3505
|
+
view.dragging = null;
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
function handleDrop(view, event, dragging) {
|
|
3492
3509
|
if (!event.dataTransfer) return;
|
|
3493
3510
|
var eventPos = view.posAtCoords(eventCoords(event));
|
|
3494
3511
|
if (!eventPos) return;
|
|
@@ -3534,7 +3551,7 @@ editHandlers.drop = function (view, _event) {
|
|
|
3534
3551
|
}
|
|
3535
3552
|
view.focus();
|
|
3536
3553
|
view.dispatch(tr.setMeta("uiEvent", "drop"));
|
|
3537
|
-
}
|
|
3554
|
+
}
|
|
3538
3555
|
handlers.focus = function (view) {
|
|
3539
3556
|
view.input.lastFocus = Date.now();
|
|
3540
3557
|
if (!view.focused) {
|
|
@@ -4399,6 +4416,24 @@ var DOMObserver = function () {
|
|
|
4399
4416
|
_iterator3.f();
|
|
4400
4417
|
}
|
|
4401
4418
|
}
|
|
4419
|
+
} else if ((chrome || safari) && added.some(function (n) {
|
|
4420
|
+
return n.nodeName == "BR";
|
|
4421
|
+
}) && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
|
|
4422
|
+
var _iterator4 = _createForOfIteratorHelper(added),
|
|
4423
|
+
_step4;
|
|
4424
|
+
try {
|
|
4425
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
4426
|
+
var node = _step4.value;
|
|
4427
|
+
if (node.nodeName == "BR" && node.parentNode) {
|
|
4428
|
+
var after = node.nextSibling;
|
|
4429
|
+
if (after && after.nodeType == 1 && after.contentEditable == "false") node.parentNode.removeChild(node);
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
} catch (err) {
|
|
4433
|
+
_iterator4.e(err);
|
|
4434
|
+
} finally {
|
|
4435
|
+
_iterator4.f();
|
|
4436
|
+
}
|
|
4402
4437
|
}
|
|
4403
4438
|
var readSel = null;
|
|
4404
4439
|
if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 && Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 && selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) && readSel.eq(prosemirrorState.Selection.near(view.state.doc.resolve(0), 1))) {
|
package/dist/index.js
CHANGED
|
@@ -367,17 +367,20 @@ function findOffsetInNode(node, coords) {
|
|
|
367
367
|
}
|
|
368
368
|
function findOffsetInText(node, coords) {
|
|
369
369
|
let len = node.nodeValue.length;
|
|
370
|
-
let range = document.createRange();
|
|
370
|
+
let range = document.createRange(), result;
|
|
371
371
|
for (let i = 0; i < len; i++) {
|
|
372
372
|
range.setEnd(node, i + 1);
|
|
373
373
|
range.setStart(node, i);
|
|
374
374
|
let rect = singleRect(range, 1);
|
|
375
375
|
if (rect.top == rect.bottom)
|
|
376
376
|
continue;
|
|
377
|
-
if (inRect(coords, rect))
|
|
378
|
-
|
|
377
|
+
if (inRect(coords, rect)) {
|
|
378
|
+
result = { node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0) };
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
379
381
|
}
|
|
380
|
-
|
|
382
|
+
range.detach();
|
|
383
|
+
return result || { node, offset: 0 };
|
|
381
384
|
}
|
|
382
385
|
function inRect(coords, rect) {
|
|
383
386
|
return coords.left >= rect.left - 1 && coords.left <= rect.right + 1 &&
|
|
@@ -3471,7 +3474,8 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3471
3474
|
let { state } = view, $pos = state.selection.$to;
|
|
3472
3475
|
if (state.selection instanceof TextSelection &&
|
|
3473
3476
|
(state.storedMarks ||
|
|
3474
|
-
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false))
|
|
3477
|
+
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
|
|
3478
|
+
chrome && windows && selectionBeforeUneditable(view))) { // Issue #1500
|
|
3475
3479
|
// Need to wrap the cursor in mark nodes different from the ones in the DOM context
|
|
3476
3480
|
view.markCursor = view.state.storedMarks || $pos.marks();
|
|
3477
3481
|
endComposition(view, true);
|
|
@@ -3505,6 +3509,13 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
3505
3509
|
}
|
|
3506
3510
|
scheduleComposeEnd(view, timeoutComposition);
|
|
3507
3511
|
};
|
|
3512
|
+
function selectionBeforeUneditable(view) {
|
|
3513
|
+
let { focusNode, focusOffset } = view.domSelectionRange();
|
|
3514
|
+
if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length)
|
|
3515
|
+
return false;
|
|
3516
|
+
let next = focusNode.childNodes[focusOffset];
|
|
3517
|
+
return next.nodeType == 1 && next.contentEditable == "false";
|
|
3518
|
+
}
|
|
3508
3519
|
editHandlers.compositionend = (view, event) => {
|
|
3509
3520
|
if (view.composing) {
|
|
3510
3521
|
view.input.composing = false;
|
|
@@ -3732,10 +3743,15 @@ handlers.dragend = view => {
|
|
|
3732
3743
|
}, 50);
|
|
3733
3744
|
};
|
|
3734
3745
|
editHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault();
|
|
3735
|
-
editHandlers.drop = (view,
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3746
|
+
editHandlers.drop = (view, event) => {
|
|
3747
|
+
try {
|
|
3748
|
+
handleDrop(view, event, view.dragging);
|
|
3749
|
+
}
|
|
3750
|
+
finally {
|
|
3751
|
+
view.dragging = null;
|
|
3752
|
+
}
|
|
3753
|
+
};
|
|
3754
|
+
function handleDrop(view, event, dragging) {
|
|
3739
3755
|
if (!event.dataTransfer)
|
|
3740
3756
|
return;
|
|
3741
3757
|
let eventPos = view.posAtCoords(eventCoords(event));
|
|
@@ -3789,7 +3805,7 @@ editHandlers.drop = (view, _event) => {
|
|
|
3789
3805
|
}
|
|
3790
3806
|
view.focus();
|
|
3791
3807
|
view.dispatch(tr.setMeta("uiEvent", "drop"));
|
|
3792
|
-
}
|
|
3808
|
+
}
|
|
3793
3809
|
handlers.focus = view => {
|
|
3794
3810
|
view.input.lastFocus = Date.now();
|
|
3795
3811
|
if (!view.focused) {
|
|
@@ -4715,6 +4731,17 @@ class DOMObserver {
|
|
|
4715
4731
|
}
|
|
4716
4732
|
}
|
|
4717
4733
|
}
|
|
4734
|
+
else if ((chrome || safari) && added.some(n => n.nodeName == "BR") &&
|
|
4735
|
+
(view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
|
|
4736
|
+
// Chrome/Safari sometimes insert a bogus break node if you
|
|
4737
|
+
// backspace out the last bit of text before an inline-flex node (#1552)
|
|
4738
|
+
for (let node of added)
|
|
4739
|
+
if (node.nodeName == "BR" && node.parentNode) {
|
|
4740
|
+
let after = node.nextSibling;
|
|
4741
|
+
if (after && after.nodeType == 1 && after.contentEditable == "false")
|
|
4742
|
+
node.parentNode.removeChild(node);
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4718
4745
|
let readSel = null;
|
|
4719
4746
|
// If it looks like the browser has reset the selection to the
|
|
4720
4747
|
// start of the document after focus, restore the selection from
|
package/package.json
CHANGED
package/src/dom.ts
CHANGED
package/src/domchange.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {Fragment, DOMParser, TagParseRule, Node, Mark, ResolvedPos} from "prosemirror-model"
|
|
2
|
-
import {
|
|
2
|
+
import {TextSelection, Transaction} from "prosemirror-state"
|
|
3
3
|
|
|
4
4
|
import {selectionBetween, selectionFromDOM, selectionToDOM} from "./selection"
|
|
5
5
|
import {selectionCollapsed, keyEvent, DOMNode} from "./dom"
|
package/src/domcoords.ts
CHANGED
|
@@ -184,16 +184,19 @@ function findOffsetInNode(node: HTMLElement, coords: {top: number, left: number}
|
|
|
184
184
|
|
|
185
185
|
function findOffsetInText(node: Text, coords: {top: number, left: number}) {
|
|
186
186
|
let len = node.nodeValue!.length
|
|
187
|
-
let range = document.createRange()
|
|
187
|
+
let range = document.createRange(), result: {node: Node, offset: number} | undefined
|
|
188
188
|
for (let i = 0; i < len; i++) {
|
|
189
189
|
range.setEnd(node, i + 1)
|
|
190
190
|
range.setStart(node, i)
|
|
191
191
|
let rect = singleRect(range, 1)
|
|
192
192
|
if (rect.top == rect.bottom) continue
|
|
193
|
-
if (inRect(coords, rect))
|
|
194
|
-
|
|
193
|
+
if (inRect(coords, rect)) {
|
|
194
|
+
result = {node, offset: i + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0)}
|
|
195
|
+
break
|
|
196
|
+
}
|
|
195
197
|
}
|
|
196
|
-
|
|
198
|
+
range.detach()
|
|
199
|
+
return result || {node, offset: 0}
|
|
197
200
|
}
|
|
198
201
|
|
|
199
202
|
function inRect(coords: {top: number, left: number}, rect: Rect) {
|
package/src/domobserver.ts
CHANGED
|
@@ -198,6 +198,15 @@ export class DOMObserver {
|
|
|
198
198
|
br.remove()
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
+
} else if ((browser.chrome || browser.safari) && added.some(n => n.nodeName == "BR") &&
|
|
202
|
+
(view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
|
|
203
|
+
// Chrome/Safari sometimes insert a bogus break node if you
|
|
204
|
+
// backspace out the last bit of text before an inline-flex node (#1552)
|
|
205
|
+
for (let node of added) if (node.nodeName == "BR" && node.parentNode) {
|
|
206
|
+
let after = node.nextSibling
|
|
207
|
+
if (after && after.nodeType == 1 && (after as HTMLElement).contentEditable == "false")
|
|
208
|
+
node.parentNode.removeChild(node)
|
|
209
|
+
}
|
|
201
210
|
}
|
|
202
211
|
|
|
203
212
|
let readSel: Selection | null = null
|
package/src/index.ts
CHANGED
package/src/input.ts
CHANGED
|
@@ -459,7 +459,8 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
459
459
|
let {state} = view, $pos = state.selection.$to
|
|
460
460
|
if (state.selection instanceof TextSelection &&
|
|
461
461
|
(state.storedMarks ||
|
|
462
|
-
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore!.marks.some(m => m.type.spec.inclusive === false))
|
|
462
|
+
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore!.marks.some(m => m.type.spec.inclusive === false)) ||
|
|
463
|
+
browser.chrome && browser.windows && selectionBeforeUneditable(view))) { // Issue #1500
|
|
463
464
|
// Need to wrap the cursor in mark nodes different from the ones in the DOM context
|
|
464
465
|
view.markCursor = view.state.storedMarks || $pos.marks()
|
|
465
466
|
endComposition(view, true)
|
|
@@ -490,6 +491,13 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
490
491
|
scheduleComposeEnd(view, timeoutComposition)
|
|
491
492
|
}
|
|
492
493
|
|
|
494
|
+
function selectionBeforeUneditable(view: EditorView) {
|
|
495
|
+
let {focusNode, focusOffset} = view.domSelectionRange()
|
|
496
|
+
if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length) return false
|
|
497
|
+
let next = focusNode.childNodes[focusOffset]
|
|
498
|
+
return next.nodeType == 1 && (next as HTMLElement).contentEditable == "false"
|
|
499
|
+
}
|
|
500
|
+
|
|
493
501
|
editHandlers.compositionend = (view, event) => {
|
|
494
502
|
if (view.composing) {
|
|
495
503
|
view.input.composing = false
|
|
@@ -706,11 +714,15 @@ handlers.dragend = view => {
|
|
|
706
714
|
|
|
707
715
|
editHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault()
|
|
708
716
|
|
|
709
|
-
editHandlers.drop = (view,
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
717
|
+
editHandlers.drop = (view, event) => {
|
|
718
|
+
try {
|
|
719
|
+
handleDrop(view, event as DragEvent, view.dragging)
|
|
720
|
+
} finally {
|
|
721
|
+
view.dragging = null
|
|
722
|
+
}
|
|
723
|
+
}
|
|
713
724
|
|
|
725
|
+
function handleDrop(view: EditorView, event: DragEvent, dragging: Dragging | null) {
|
|
714
726
|
if (!event.dataTransfer) return
|
|
715
727
|
|
|
716
728
|
let eventPos = view.posAtCoords(eventCoords(event))
|