prosemirror-view 1.41.8 → 1.41.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.41.9 (2026-06-10)
2
+
3
+ ### Bug fixes
4
+
5
+ Allow triple-click drag selection.
6
+
7
+ Adjust an existing workaround to work around the fact that Chrome no longer fires key events for backspace during composition.
8
+
1
9
  ## 1.41.8 (2026-04-02)
2
10
 
3
11
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2201,11 +2201,11 @@ function selectionToDOM(view) {
2201
2201
  var sel = view.state.selection;
2202
2202
  syncNodeSelection(view, sel);
2203
2203
  if (!editorOwnsSelection(view)) return;
2204
- if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
2204
+ var mouseDown = view.input.mouseDown;
2205
+ if (!force && chrome && mouseDown) {
2205
2206
  var domSel = view.domSelectionRange(),
2206
2207
  curSel = view.domObserver.currentSelection;
2207
- if (domSel.anchorNode && curSel.anchorNode && isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
2208
- view.input.mouseDown.delayedSelectionSync = true;
2208
+ if (domSel.anchorNode && curSel.anchorNode && isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset) && mouseDown.delaySelUpdate()) {
2209
2209
  view.domObserver.setCurSelection();
2210
2210
  return;
2211
2211
  }
@@ -2949,6 +2949,7 @@ function setSelectionOrigin(view, origin) {
2949
2949
  view.input.lastSelectionTime = Date.now();
2950
2950
  }
2951
2951
  function destroyInput(view) {
2952
+ if (view.input.mouseDown) view.input.mouseDown.done();
2952
2953
  view.domObserver.stop();
2953
2954
  for (var type in view.input.eventHandlers) view.dom.removeEventListener(type, view.input.eventHandlers[type]);
2954
2955
  clearTimeout(view.input.composingTimeout);
@@ -2979,7 +2980,7 @@ function _dispatchEvent(view, event) {
2979
2980
  editHandlers.keydown = function (view, _event) {
2980
2981
  var event = _event;
2981
2982
  view.input.shiftKey = event.keyCode == 16 || event.shiftKey;
2982
- if (inOrNearComposition(view, event)) return;
2983
+ if (inOrNearComposition(view)) return;
2983
2984
  view.input.lastKeyCode = event.keyCode;
2984
2985
  view.input.lastKeyCodeTime = Date.now();
2985
2986
  if (android && chrome && event.keyCode == 13) return;
@@ -3008,7 +3009,7 @@ editHandlers.keyup = function (view, event) {
3008
3009
  };
3009
3010
  editHandlers.keypress = function (view, _event) {
3010
3011
  var event = _event;
3011
- if (inOrNearComposition(view, event) || !event.charCode || event.ctrlKey && !event.altKey || mac && event.metaKey) return;
3012
+ if (inOrNearComposition(view) || !event.charCode || event.ctrlKey && !event.altKey || mac && event.metaKey) return;
3012
3013
  if (view.someProp("handleKeyPress", function (f) {
3013
3014
  return f(view, event);
3014
3015
  })) {
@@ -3110,21 +3111,23 @@ function handleTripleClick(view, pos, inside, event) {
3110
3111
  }
3111
3112
  function defaultTripleClick(view, inside, event) {
3112
3113
  if (event.button != 0) return false;
3114
+ var selection = selectionForTripleClick(view, inside, true),
3115
+ doc = view.state.doc;
3116
+ if (!selection) return false;
3117
+ updateSelection(view, selection, "pointer");
3118
+ if (selection instanceof prosemirrorState.TextSelection && doc.eq(view.state.doc)) view.input.mouseDown = new TripleClickDrag(view, selection);
3119
+ return true;
3120
+ }
3121
+ function selectionForTripleClick(view, inside, selectNodes) {
3113
3122
  var doc = view.state.doc;
3114
- if (inside == -1) {
3115
- if (doc.inlineContent) {
3116
- updateSelection(view, prosemirrorState.TextSelection.create(doc, 0, doc.content.size), "pointer");
3117
- return true;
3118
- }
3119
- return false;
3120
- }
3123
+ if (inside == -1) return doc.inlineContent ? prosemirrorState.TextSelection.create(doc, 0, doc.content.size) : null;
3121
3124
  var $pos = doc.resolve(inside);
3122
3125
  for (var i = $pos.depth + 1; i > 0; i--) {
3123
3126
  var node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
3124
3127
  var nodePos = $pos.before(i);
3125
- if (node.inlineContent) updateSelection(view, prosemirrorState.TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer");else if (prosemirrorState.NodeSelection.isSelectable(node)) updateSelection(view, prosemirrorState.NodeSelection.create(doc, nodePos), "pointer");else continue;
3126
- return true;
3128
+ if (node.inlineContent) return prosemirrorState.TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size);else if (selectNodes && prosemirrorState.NodeSelection.isSelectable(node)) return prosemirrorState.NodeSelection.create(doc, nodePos);
3127
3129
  }
3130
+ return null;
3128
3131
  }
3129
3132
  function forceDOMFlush(view) {
3130
3133
  return endComposition(view);
@@ -3146,11 +3149,11 @@ handlers.mousedown = function (view, _event) {
3146
3149
  type: type,
3147
3150
  button: event.button
3148
3151
  };
3152
+ if (view.input.mouseDown) view.input.mouseDown.done();
3149
3153
  var pos = view.posAtCoords(eventCoords(event));
3150
3154
  if (!pos) return;
3151
3155
  if (type == "singleClick") {
3152
- if (view.input.mouseDown) view.input.mouseDown.done();
3153
- view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);
3156
+ view.input.mouseDown = new LeftMouseDown(view, pos, event, !!flushed);
3154
3157
  } else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
3155
3158
  event.preventDefault();
3156
3159
  } else {
@@ -3158,18 +3161,52 @@ handlers.mousedown = function (view, _event) {
3158
3161
  }
3159
3162
  };
3160
3163
  var MouseDown = function () {
3161
- function MouseDown(view, pos, event, flushed) {
3162
- var _this8 = this;
3164
+ function MouseDown(view) {
3163
3165
  _classCallCheck(this, MouseDown);
3164
3166
  this.view = view;
3165
- this.pos = pos;
3166
- this.event = event;
3167
- this.flushed = flushed;
3168
- this.delayedSelectionSync = false;
3169
3167
  this.mightDrag = null;
3170
- this.startDoc = view.state.doc;
3171
- this.selectNode = !!event[selectNodeModifier];
3172
- this.allowDefault = event.shiftKey;
3168
+ view.root.addEventListener("mouseup", this.up = this.up.bind(this));
3169
+ view.root.addEventListener("mousemove", this.move = this.move.bind(this));
3170
+ }
3171
+ _createClass(MouseDown, [{
3172
+ key: "up",
3173
+ value: function up(event) {
3174
+ this.done();
3175
+ }
3176
+ }, {
3177
+ key: "move",
3178
+ value: function move(event) {
3179
+ if (event.buttons == 0) this.done();
3180
+ }
3181
+ }, {
3182
+ key: "done",
3183
+ value: function done() {
3184
+ this.view.root.removeEventListener("mouseup", this.up);
3185
+ this.view.root.removeEventListener("mousemove", this.move);
3186
+ if (this.view.input.mouseDown == this) this.view.input.mouseDown = null;
3187
+ }
3188
+ }, {
3189
+ key: "delaySelUpdate",
3190
+ value: function delaySelUpdate() {
3191
+ return false;
3192
+ }
3193
+ }]);
3194
+ return MouseDown;
3195
+ }();
3196
+ var LeftMouseDown = function (_MouseDown) {
3197
+ _inherits(LeftMouseDown, _MouseDown);
3198
+ var _super8 = _createSuper(LeftMouseDown);
3199
+ function LeftMouseDown(view, pos, event, flushed) {
3200
+ var _this8;
3201
+ _classCallCheck(this, LeftMouseDown);
3202
+ _this8 = _super8.call(this, view);
3203
+ _this8.pos = pos;
3204
+ _this8.event = event;
3205
+ _this8.flushed = flushed;
3206
+ _this8.delayedSelectionSync = false;
3207
+ _this8.startDoc = view.state.doc;
3208
+ _this8.selectNode = !!event[selectNodeModifier];
3209
+ _this8.allowDefault = event.shiftKey;
3173
3210
  var targetNode, targetPos;
3174
3211
  if (pos.inside > -1) {
3175
3212
  targetNode = view.state.doc.nodeAt(pos.inside);
@@ -3181,32 +3218,30 @@ var MouseDown = function () {
3181
3218
  }
3182
3219
  var target = flushed ? null : event.target;
3183
3220
  var targetDesc = target ? view.docView.nearestDesc(target, true) : null;
3184
- this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
3221
+ _this8.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
3185
3222
  var selection = view.state.selection;
3186
- if (event.button == 0 && (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false || selection instanceof prosemirrorState.NodeSelection && selection.from <= targetPos && selection.to > targetPos)) this.mightDrag = {
3223
+ if (event.button == 0 && (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false || selection instanceof prosemirrorState.NodeSelection && selection.from <= targetPos && selection.to > targetPos)) _this8.mightDrag = {
3187
3224
  node: targetNode,
3188
3225
  pos: targetPos,
3189
- addAttr: !!(this.target && !this.target.draggable),
3190
- setUneditable: !!(this.target && gecko && !this.target.hasAttribute("contentEditable"))
3226
+ addAttr: !!(_this8.target && !_this8.target.draggable),
3227
+ setUneditable: !!(_this8.target && gecko && !_this8.target.hasAttribute("contentEditable"))
3191
3228
  };
3192
- if (this.target && this.mightDrag && (this.mightDrag.addAttr || this.mightDrag.setUneditable)) {
3193
- this.view.domObserver.stop();
3194
- if (this.mightDrag.addAttr) this.target.draggable = true;
3195
- if (this.mightDrag.setUneditable) setTimeout(function () {
3196
- if (_this8.view.input.mouseDown == _this8) _this8.target.setAttribute("contentEditable", "false");
3229
+ if (_this8.target && _this8.mightDrag && (_this8.mightDrag.addAttr || _this8.mightDrag.setUneditable)) {
3230
+ _this8.view.domObserver.stop();
3231
+ if (_this8.mightDrag.addAttr) _this8.target.draggable = true;
3232
+ if (_this8.mightDrag.setUneditable) setTimeout(function () {
3233
+ if (_this8.view.input.mouseDown == _assertThisInitialized(_this8)) _this8.target.setAttribute("contentEditable", "false");
3197
3234
  }, 20);
3198
- this.view.domObserver.start();
3235
+ _this8.view.domObserver.start();
3199
3236
  }
3200
- view.root.addEventListener("mouseup", this.up = this.up.bind(this));
3201
- view.root.addEventListener("mousemove", this.move = this.move.bind(this));
3202
3237
  setSelectionOrigin(view, "pointer");
3238
+ return _this8;
3203
3239
  }
3204
- _createClass(MouseDown, [{
3240
+ _createClass(LeftMouseDown, [{
3205
3241
  key: "done",
3206
3242
  value: function done() {
3207
3243
  var _this9 = this;
3208
- this.view.root.removeEventListener("mouseup", this.up);
3209
- this.view.root.removeEventListener("mousemove", this.move);
3244
+ _get(_getPrototypeOf(LeftMouseDown.prototype), "done", this).call(this);
3210
3245
  if (this.mightDrag && this.target) {
3211
3246
  this.view.domObserver.stop();
3212
3247
  if (this.mightDrag.addAttr) this.target.removeAttribute("draggable");
@@ -3214,9 +3249,8 @@ var MouseDown = function () {
3214
3249
  this.view.domObserver.start();
3215
3250
  }
3216
3251
  if (this.delayedSelectionSync) setTimeout(function () {
3217
- return selectionToDOM(_this9.view);
3252
+ if (!_this9.view.isDestroyed) selectionToDOM(_this9.view);
3218
3253
  });
3219
- this.view.input.mouseDown = null;
3220
3254
  }
3221
3255
  }, {
3222
3256
  key: "up",
@@ -3242,16 +3276,57 @@ var MouseDown = function () {
3242
3276
  value: function move(event) {
3243
3277
  this.updateAllowDefault(event);
3244
3278
  setSelectionOrigin(this.view, "pointer");
3245
- if (event.buttons == 0) this.done();
3279
+ _get(_getPrototypeOf(LeftMouseDown.prototype), "move", this).call(this, event);
3246
3280
  }
3247
3281
  }, {
3248
3282
  key: "updateAllowDefault",
3249
3283
  value: function updateAllowDefault(event) {
3250
3284
  if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 || Math.abs(this.event.y - event.clientY) > 4)) this.allowDefault = true;
3251
3285
  }
3286
+ }, {
3287
+ key: "delaySelUpdate",
3288
+ value: function delaySelUpdate() {
3289
+ if (!this.allowDefault) return false;
3290
+ this.delayedSelectionSync = true;
3291
+ return true;
3292
+ }
3252
3293
  }]);
3253
- return MouseDown;
3254
- }();
3294
+ return LeftMouseDown;
3295
+ }(MouseDown);
3296
+ var TripleClickDrag = function (_MouseDown2) {
3297
+ _inherits(TripleClickDrag, _MouseDown2);
3298
+ var _super9 = _createSuper(TripleClickDrag);
3299
+ function TripleClickDrag(view, startSelection) {
3300
+ var _this10;
3301
+ _classCallCheck(this, TripleClickDrag);
3302
+ _this10 = _super9.call(this, view);
3303
+ _this10.startSelection = startSelection;
3304
+ _this10.startDoc = view.state.doc;
3305
+ return _this10;
3306
+ }
3307
+ _createClass(TripleClickDrag, [{
3308
+ key: "move",
3309
+ value: function move(event) {
3310
+ if (event.buttons == 0 || this.view.isDestroyed || !this.view.state.doc.eq(this.startDoc)) {
3311
+ this.done();
3312
+ return;
3313
+ }
3314
+ event.preventDefault();
3315
+ setSelectionOrigin(this.view, "pointer");
3316
+ var pos = this.view.posAtCoords(eventCoords(event));
3317
+ var target = pos && selectionForTripleClick(this.view, pos.inside, false);
3318
+ if (!target) return;
3319
+ var doc = this.view.state.doc,
3320
+ start = this.startSelection;
3321
+ var _ref5 = target.from < start.from ? [start.to, target.from] : [start.from, target.to],
3322
+ _ref6 = _slicedToArray(_ref5, 2),
3323
+ anchor = _ref6[0],
3324
+ head = _ref6[1];
3325
+ updateSelection(this.view, prosemirrorState.TextSelection.create(doc, anchor, head), "pointer");
3326
+ }
3327
+ }]);
3328
+ return TripleClickDrag;
3329
+ }(MouseDown);
3255
3330
  handlers.touchstart = function (view) {
3256
3331
  view.input.lastTouch = Date.now();
3257
3332
  forceDOMFlush(view);
@@ -3266,7 +3341,7 @@ handlers.contextmenu = function (view) {
3266
3341
  };
3267
3342
  function inOrNearComposition(view, event) {
3268
3343
  if (view.composing) return true;
3269
- if (safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
3344
+ if (safari && Math.abs(Date.now() - view.input.compositionEndedAt) < 500) {
3270
3345
  view.input.compositionEndedAt = -2e8;
3271
3346
  return true;
3272
3347
  }
@@ -3317,7 +3392,7 @@ function selectionBeforeUneditable(view) {
3317
3392
  editHandlers.compositionend = function (view, event) {
3318
3393
  if (view.composing) {
3319
3394
  view.input.composing = false;
3320
- view.input.compositionEndedAt = event.timeStamp;
3395
+ view.input.compositionEndedAt = Date.now();
3321
3396
  view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
3322
3397
  view.input.compositionNode = null;
3323
3398
  if (view.input.badSafariComposition) view.domObserver.forceFlush();else if (view.input.compositionPendingChanges) Promise.resolve().then(function () {
@@ -3336,7 +3411,7 @@ function scheduleComposeEnd(view, delay) {
3336
3411
  function clearComposition(view) {
3337
3412
  if (view.composing) {
3338
3413
  view.input.composing = false;
3339
- view.input.compositionEndedAt = timestampFromCustomEvent();
3414
+ view.input.compositionEndedAt = Date.now();
3340
3415
  }
3341
3416
  while (view.input.compositionNodes.length > 0) view.input.compositionNodes.pop().markParentsDirty();
3342
3417
  }
@@ -3358,11 +3433,6 @@ function findCompositionNode(view) {
3358
3433
  }
3359
3434
  return textBefore || textAfter;
3360
3435
  }
3361
- function timestampFromCustomEvent() {
3362
- var event = document.createEvent("Event");
3363
- event.initEvent("event", true, true);
3364
- return event.timeStamp;
3365
- }
3366
3436
  function endComposition(view) {
3367
3437
  var restarting = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3368
3438
  if (android && view.domObserver.flushingSoon >= 0) return;
@@ -3815,14 +3885,14 @@ var DecorationSet = function () {
3815
3885
  }, {
3816
3886
  key: "addInner",
3817
3887
  value: function addInner(doc, decorations, offset) {
3818
- var _this10 = this;
3888
+ var _this11 = this;
3819
3889
  var children,
3820
3890
  childIndex = 0;
3821
3891
  doc.forEach(function (childNode, childOffset) {
3822
3892
  var baseOffset = childOffset + offset,
3823
3893
  found;
3824
3894
  if (!(found = takeSpansForNode(decorations, childNode, baseOffset))) return;
3825
- if (!children) children = _this10.children.slice();
3895
+ if (!children) children = _this11.children.slice();
3826
3896
  while (childIndex < children.length && children[childIndex] < childOffset) childIndex += 3;
3827
3897
  if (children[childIndex] == childOffset) children[childIndex + 2] = children[childIndex + 2].addInner(childNode, found, baseOffset + 1);else children.splice(childIndex, 0, childOffset, childOffset + childNode.nodeSize, buildTree(found, childNode, baseOffset + 1, noSpec));
3828
3898
  childIndex += 3;
@@ -4224,7 +4294,7 @@ var SelectionState = function () {
4224
4294
  }();
4225
4295
  var DOMObserver = function () {
4226
4296
  function DOMObserver(view, handleDOMChange) {
4227
- var _this11 = this;
4297
+ var _this12 = this;
4228
4298
  _classCallCheck(this, DOMObserver);
4229
4299
  this.view = view;
4230
4300
  this.handleDOMChange = handleDOMChange;
@@ -4236,28 +4306,28 @@ var DOMObserver = function () {
4236
4306
  this.suppressingSelectionUpdates = false;
4237
4307
  this.lastChangedTextNode = null;
4238
4308
  this.observer = window.MutationObserver && new window.MutationObserver(function (mutations) {
4239
- for (var i = 0; i < mutations.length; i++) _this11.queue.push(mutations[i]);
4309
+ for (var i = 0; i < mutations.length; i++) _this12.queue.push(mutations[i]);
4240
4310
  if (ie && ie_version <= 11 && mutations.some(function (m) {
4241
4311
  return m.type == "childList" && m.removedNodes.length || m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length;
4242
4312
  })) {
4243
- _this11.flushSoon();
4313
+ _this12.flushSoon();
4244
4314
  } else if (safari && view.composing && mutations.some(function (m) {
4245
4315
  return m.type == "childList" && m.target.nodeName == "TR";
4246
4316
  })) {
4247
4317
  view.input.badSafariComposition = true;
4248
- _this11.flushSoon();
4318
+ _this12.flushSoon();
4249
4319
  } else {
4250
- _this11.flush();
4320
+ _this12.flush();
4251
4321
  }
4252
4322
  });
4253
4323
  if (useCharData) {
4254
4324
  this.onCharData = function (e) {
4255
- _this11.queue.push({
4325
+ _this12.queue.push({
4256
4326
  target: e.target,
4257
4327
  type: "characterData",
4258
4328
  oldValue: e.prevValue
4259
4329
  });
4260
- _this11.flushSoon();
4330
+ _this12.flushSoon();
4261
4331
  };
4262
4332
  }
4263
4333
  this.onSelectionChange = this.onSelectionChange.bind(this);
@@ -4265,10 +4335,10 @@ var DOMObserver = function () {
4265
4335
  _createClass(DOMObserver, [{
4266
4336
  key: "flushSoon",
4267
4337
  value: function flushSoon() {
4268
- var _this12 = this;
4338
+ var _this13 = this;
4269
4339
  if (this.flushingSoon < 0) this.flushingSoon = window.setTimeout(function () {
4270
- _this12.flushingSoon = -1;
4271
- _this12.flush();
4340
+ _this13.flushingSoon = -1;
4341
+ _this13.flush();
4272
4342
  }, 20);
4273
4343
  }
4274
4344
  }, {
@@ -4293,13 +4363,13 @@ var DOMObserver = function () {
4293
4363
  }, {
4294
4364
  key: "stop",
4295
4365
  value: function stop() {
4296
- var _this13 = this;
4366
+ var _this14 = this;
4297
4367
  if (this.observer) {
4298
4368
  var take = this.observer.takeRecords();
4299
4369
  if (take.length) {
4300
4370
  for (var i = 0; i < take.length; i++) this.queue.push(take[i]);
4301
4371
  window.setTimeout(function () {
4302
- return _this13.flush();
4372
+ return _this14.flush();
4303
4373
  }, 20);
4304
4374
  }
4305
4375
  this.observer.disconnect();
@@ -4320,10 +4390,10 @@ var DOMObserver = function () {
4320
4390
  }, {
4321
4391
  key: "suppressSelectionUpdates",
4322
4392
  value: function suppressSelectionUpdates() {
4323
- var _this14 = this;
4393
+ var _this15 = this;
4324
4394
  this.suppressingSelectionUpdates = true;
4325
4395
  setTimeout(function () {
4326
- return _this14.suppressingSelectionUpdates = false;
4396
+ return _this15.suppressingSelectionUpdates = false;
4327
4397
  }, 50);
4328
4398
  }
4329
4399
  }, {
@@ -4406,7 +4476,9 @@ var DOMObserver = function () {
4406
4476
  }
4407
4477
  if (added.some(function (n) {
4408
4478
  return n.nodeName == "BR";
4409
- }) && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
4479
+ }) && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46 || chrome && (view.composing || view.input.compositionEndedAt > Date.now() - 50) && mutations.some(function (m) {
4480
+ return m.type == "childList" && m.removedNodes.length;
4481
+ }))) {
4410
4482
  var _iterator3 = _createForOfIteratorHelper(added),
4411
4483
  _step3;
4412
4484
  try {
@@ -4546,11 +4618,11 @@ function rangeToSelectionRange(view, range) {
4546
4618
  focusOffset = range.endOffset;
4547
4619
  var currentAnchor = view.domAtPos(view.state.selection.anchor);
4548
4620
  if (isEquivalentPosition(currentAnchor.node, currentAnchor.offset, focusNode, focusOffset)) {
4549
- var _ref5 = [focusNode, focusOffset, anchorNode, anchorOffset];
4550
- anchorNode = _ref5[0];
4551
- anchorOffset = _ref5[1];
4552
- focusNode = _ref5[2];
4553
- focusOffset = _ref5[3];
4621
+ var _ref7 = [focusNode, focusOffset, anchorNode, anchorOffset];
4622
+ anchorNode = _ref7[0];
4623
+ anchorOffset = _ref7[1];
4624
+ focusNode = _ref7[2];
4625
+ focusOffset = _ref7[3];
4554
4626
  }
4555
4627
  return {
4556
4628
  anchorNode: anchorNode,
@@ -4914,25 +4986,25 @@ function skipClosingAndOpening($pos, fromEnd, mayOpen) {
4914
4986
  return end;
4915
4987
  }
4916
4988
  function findDiff(a, b, pos, preferredPos, preferredSide) {
4917
- var start = a.findDiffStart(b, pos);
4989
+ var start = a.findDiffStart(b, pos),
4990
+ lenA = pos + a.size,
4991
+ lenB = pos + b.size;
4918
4992
  if (start == null) return null;
4919
- var _a$findDiffEnd = a.findDiffEnd(b, pos + a.size, pos + b.size),
4993
+ var _a$findDiffEnd = a.findDiffEnd(b, lenA, lenB),
4920
4994
  endA = _a$findDiffEnd.a,
4921
4995
  endB = _a$findDiffEnd.b;
4922
4996
  if (preferredSide == "end") {
4923
4997
  var adjust = Math.max(0, start - Math.min(endA, endB));
4924
4998
  preferredPos -= endA + adjust - start;
4925
4999
  }
4926
- if (endA < start && a.size < b.size) {
5000
+ if (endA < start && lenA < lenB) {
4927
5001
  var move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
4928
5002
  start -= move;
4929
- if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1))) start += move ? 1 : -1;
4930
5003
  endB = start + (endB - endA);
4931
5004
  endA = start;
4932
5005
  } else if (endB < start) {
4933
5006
  var _move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
4934
5007
  start -= _move;
4935
- if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1))) start += _move ? 1 : -1;
4936
5008
  endA = start + (endA - endB);
4937
5009
  endB = start;
4938
5010
  }
@@ -4942,17 +5014,11 @@ function findDiff(a, b, pos, preferredPos, preferredSide) {
4942
5014
  endB: endB
4943
5015
  };
4944
5016
  }
4945
- function isSurrogatePair(str) {
4946
- if (str.length != 2) return false;
4947
- var a = str.charCodeAt(0),
4948
- b = str.charCodeAt(1);
4949
- return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
4950
- }
4951
5017
  var __parseFromClipboard = parseFromClipboard;
4952
5018
  var __endComposition = endComposition;
4953
5019
  var EditorView = function () {
4954
5020
  function EditorView(place, props) {
4955
- var _this15 = this;
5021
+ var _this16 = this;
4956
5022
  _classCallCheck(this, EditorView);
4957
5023
  this._root = null;
4958
5024
  this.focused = false;
@@ -4980,7 +5046,7 @@ var EditorView = function () {
4980
5046
  this.nodeViews = buildNodeViews(this);
4981
5047
  this.docView = docViewDesc(this.state.doc, computeDocDeco(this), viewDecorations(this), this.dom, this);
4982
5048
  this.domObserver = new DOMObserver(this, function (from, to, typeOver, added) {
4983
- return readDOMChange(_this15, from, to, typeOver, added);
5049
+ return readDOMChange(_this16, from, to, typeOver, added);
4984
5050
  });
4985
5051
  this.domObserver.start();
4986
5052
  initInput(this);
@@ -5072,7 +5138,8 @@ var EditorView = function () {
5072
5138
  }
5073
5139
  if (chromeKludge && (!this.trackWrites || !this.dom.contains(this.trackWrites))) forceSelUpdate = true;
5074
5140
  }
5075
- if (forceSelUpdate || !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) && anchorInRightPlace(this))) {
5141
+ var mouseDown = this.input.mouseDown;
5142
+ if (forceSelUpdate || !(mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) && anchorInRightPlace(this) && mouseDown.delaySelUpdate())) {
5076
5143
  selectionToDOM(this, forceSelUpdate);
5077
5144
  } else {
5078
5145
  syncNodeSelection(this, state.selection);
@@ -5093,10 +5160,10 @@ var EditorView = function () {
5093
5160
  }, {
5094
5161
  key: "scrollToSelection",
5095
5162
  value: function scrollToSelection() {
5096
- var _this16 = this;
5163
+ var _this17 = this;
5097
5164
  var startDOM = this.domSelectionRange().focusNode;
5098
5165
  if (!startDOM || !this.dom.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;else if (this.someProp("handleScrollToSelection", function (f) {
5099
- return f(_this16);
5166
+ return f(_this17);
5100
5167
  })) ;else if (this.state.selection instanceof prosemirrorState.NodeSelection) {
5101
5168
  var target = this.docView.domAfterPos(this.state.selection.from);
5102
5169
  if (target.nodeType == 1) scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);
@@ -5187,7 +5254,7 @@ var EditorView = function () {
5187
5254
  }, {
5188
5255
  key: "root",
5189
5256
  get: function get() {
5190
- var _this17 = this;
5257
+ var _this18 = this;
5191
5258
  var cached = this._root;
5192
5259
  if (cached == null) {
5193
5260
  var _loop5 = function _loop5(search) {
@@ -5196,7 +5263,7 @@ var EditorView = function () {
5196
5263
  return search.ownerDocument.getSelection();
5197
5264
  };
5198
5265
  return {
5199
- v: _this17._root = search
5266
+ v: _this18._root = search
5200
5267
  };
5201
5268
  }
5202
5269
  },
package/dist/index.js CHANGED
@@ -2244,14 +2244,14 @@ function selectionToDOM(view, force = false) {
2244
2244
  syncNodeSelection(view, sel);
2245
2245
  if (!editorOwnsSelection(view))
2246
2246
  return;
2247
- // The delayed drag selection causes issues with Cell Selections
2248
- // in Safari. And the drag selection delay is to workarond issues
2249
- // which only present in Chrome.
2250
- if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
2247
+ // Need to delay selection normalization during a native selection
2248
+ // drag on Chrome, or it will cause further dragging to glitch.
2249
+ let mouseDown = view.input.mouseDown;
2250
+ if (!force && chrome && mouseDown) {
2251
2251
  let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
2252
2252
  if (domSel.anchorNode && curSel.anchorNode &&
2253
- isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
2254
- view.input.mouseDown.delayedSelectionSync = true;
2253
+ isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset) &&
2254
+ mouseDown.delaySelUpdate()) {
2255
2255
  view.domObserver.setCurSelection();
2256
2256
  return;
2257
2257
  }
@@ -3103,6 +3103,8 @@ function setSelectionOrigin(view, origin) {
3103
3103
  view.input.lastSelectionTime = Date.now();
3104
3104
  }
3105
3105
  function destroyInput(view) {
3106
+ if (view.input.mouseDown)
3107
+ view.input.mouseDown.done();
3106
3108
  view.domObserver.stop();
3107
3109
  for (let type in view.input.eventHandlers)
3108
3110
  view.dom.removeEventListener(type, view.input.eventHandlers[type]);
@@ -3141,7 +3143,7 @@ function dispatchEvent(view, event) {
3141
3143
  editHandlers.keydown = (view, _event) => {
3142
3144
  let event = _event;
3143
3145
  view.input.shiftKey = event.keyCode == 16 || event.shiftKey;
3144
- if (inOrNearComposition(view, event))
3146
+ if (inOrNearComposition(view))
3145
3147
  return;
3146
3148
  view.input.lastKeyCode = event.keyCode;
3147
3149
  view.input.lastKeyCodeTime = Date.now();
@@ -3179,7 +3181,7 @@ editHandlers.keyup = (view, event) => {
3179
3181
  };
3180
3182
  editHandlers.keypress = (view, _event) => {
3181
3183
  let event = _event;
3182
- if (inOrNearComposition(view, event) || !event.charCode ||
3184
+ if (inOrNearComposition(view) || !event.charCode ||
3183
3185
  event.ctrlKey && !event.altKey || mac && event.metaKey)
3184
3186
  return;
3185
3187
  if (view.someProp("handleKeyPress", f => f(view, event))) {
@@ -3274,26 +3276,28 @@ function handleTripleClick(view, pos, inside, event) {
3274
3276
  function defaultTripleClick(view, inside, event) {
3275
3277
  if (event.button != 0)
3276
3278
  return false;
3277
- let doc = view.state.doc;
3278
- if (inside == -1) {
3279
- if (doc.inlineContent) {
3280
- updateSelection(view, TextSelection.create(doc, 0, doc.content.size), "pointer");
3281
- return true;
3282
- }
3279
+ let selection = selectionForTripleClick(view, inside, true), doc = view.state.doc;
3280
+ if (!selection)
3283
3281
  return false;
3284
- }
3282
+ updateSelection(view, selection, "pointer");
3283
+ if (selection instanceof TextSelection && doc.eq(view.state.doc))
3284
+ view.input.mouseDown = new TripleClickDrag(view, selection);
3285
+ return true;
3286
+ }
3287
+ function selectionForTripleClick(view, inside, selectNodes) {
3288
+ let doc = view.state.doc;
3289
+ if (inside == -1)
3290
+ return doc.inlineContent ? TextSelection.create(doc, 0, doc.content.size) : null;
3285
3291
  let $pos = doc.resolve(inside);
3286
3292
  for (let i = $pos.depth + 1; i > 0; i--) {
3287
3293
  let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
3288
3294
  let nodePos = $pos.before(i);
3289
3295
  if (node.inlineContent)
3290
- updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer");
3291
- else if (NodeSelection.isSelectable(node))
3292
- updateSelection(view, NodeSelection.create(doc, nodePos), "pointer");
3293
- else
3294
- continue;
3295
- return true;
3296
+ return TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size);
3297
+ else if (selectNodes && NodeSelection.isSelectable(node))
3298
+ return NodeSelection.create(doc, nodePos);
3296
3299
  }
3300
+ return null;
3297
3301
  }
3298
3302
  function forceDOMFlush(view) {
3299
3303
  return endComposition(view);
@@ -3312,13 +3316,13 @@ handlers.mousedown = (view, _event) => {
3312
3316
  type = "tripleClick";
3313
3317
  }
3314
3318
  view.input.lastClick = { time: now, x: event.clientX, y: event.clientY, type, button: event.button };
3319
+ if (view.input.mouseDown)
3320
+ view.input.mouseDown.done();
3315
3321
  let pos = view.posAtCoords(eventCoords(event));
3316
3322
  if (!pos)
3317
3323
  return;
3318
3324
  if (type == "singleClick") {
3319
- if (view.input.mouseDown)
3320
- view.input.mouseDown.done();
3321
- view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);
3325
+ view.input.mouseDown = new LeftMouseDown(view, pos, event, !!flushed);
3322
3326
  }
3323
3327
  else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
3324
3328
  event.preventDefault();
@@ -3328,13 +3332,34 @@ handlers.mousedown = (view, _event) => {
3328
3332
  }
3329
3333
  };
3330
3334
  class MouseDown {
3331
- constructor(view, pos, event, flushed) {
3335
+ constructor(view) {
3332
3336
  this.view = view;
3337
+ this.mightDrag = null;
3338
+ view.root.addEventListener("mouseup", this.up = this.up.bind(this));
3339
+ view.root.addEventListener("mousemove", this.move = this.move.bind(this));
3340
+ }
3341
+ up(event) {
3342
+ this.done();
3343
+ }
3344
+ move(event) {
3345
+ if (event.buttons == 0)
3346
+ this.done();
3347
+ }
3348
+ done() {
3349
+ this.view.root.removeEventListener("mouseup", this.up);
3350
+ this.view.root.removeEventListener("mousemove", this.move);
3351
+ if (this.view.input.mouseDown == this)
3352
+ this.view.input.mouseDown = null;
3353
+ }
3354
+ delaySelUpdate() { return false; }
3355
+ }
3356
+ class LeftMouseDown extends MouseDown {
3357
+ constructor(view, pos, event, flushed) {
3358
+ super(view);
3333
3359
  this.pos = pos;
3334
3360
  this.event = event;
3335
3361
  this.flushed = flushed;
3336
3362
  this.delayedSelectionSync = false;
3337
- this.mightDrag = null;
3338
3363
  this.startDoc = view.state.doc;
3339
3364
  this.selectNode = !!event[selectNodeModifier];
3340
3365
  this.allowDefault = event.shiftKey;
@@ -3372,13 +3397,10 @@ class MouseDown {
3372
3397
  }, 20);
3373
3398
  this.view.domObserver.start();
3374
3399
  }
3375
- view.root.addEventListener("mouseup", this.up = this.up.bind(this));
3376
- view.root.addEventListener("mousemove", this.move = this.move.bind(this));
3377
3400
  setSelectionOrigin(view, "pointer");
3378
3401
  }
3379
3402
  done() {
3380
- this.view.root.removeEventListener("mouseup", this.up);
3381
- this.view.root.removeEventListener("mousemove", this.move);
3403
+ super.done();
3382
3404
  if (this.mightDrag && this.target) {
3383
3405
  this.view.domObserver.stop();
3384
3406
  if (this.mightDrag.addAttr)
@@ -3388,8 +3410,10 @@ class MouseDown {
3388
3410
  this.view.domObserver.start();
3389
3411
  }
3390
3412
  if (this.delayedSelectionSync)
3391
- setTimeout(() => selectionToDOM(this.view));
3392
- this.view.input.mouseDown = null;
3413
+ setTimeout(() => {
3414
+ if (!this.view.isDestroyed)
3415
+ selectionToDOM(this.view);
3416
+ });
3393
3417
  }
3394
3418
  up(event) {
3395
3419
  this.done();
@@ -3428,14 +3452,41 @@ class MouseDown {
3428
3452
  move(event) {
3429
3453
  this.updateAllowDefault(event);
3430
3454
  setSelectionOrigin(this.view, "pointer");
3431
- if (event.buttons == 0)
3432
- this.done();
3455
+ super.move(event);
3433
3456
  }
3434
3457
  updateAllowDefault(event) {
3435
3458
  if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
3436
3459
  Math.abs(this.event.y - event.clientY) > 4))
3437
3460
  this.allowDefault = true;
3438
3461
  }
3462
+ delaySelUpdate() {
3463
+ if (!this.allowDefault)
3464
+ return false;
3465
+ this.delayedSelectionSync = true;
3466
+ return true;
3467
+ }
3468
+ }
3469
+ class TripleClickDrag extends MouseDown {
3470
+ constructor(view, startSelection) {
3471
+ super(view);
3472
+ this.startSelection = startSelection;
3473
+ this.startDoc = view.state.doc;
3474
+ }
3475
+ move(event) {
3476
+ if (event.buttons == 0 || this.view.isDestroyed || !this.view.state.doc.eq(this.startDoc)) {
3477
+ this.done();
3478
+ return;
3479
+ }
3480
+ event.preventDefault();
3481
+ setSelectionOrigin(this.view, "pointer");
3482
+ let pos = this.view.posAtCoords(eventCoords(event));
3483
+ let target = pos && selectionForTripleClick(this.view, pos.inside, false);
3484
+ if (!target)
3485
+ return;
3486
+ let { doc } = this.view.state, start = this.startSelection;
3487
+ let [anchor, head] = target.from < start.from ? [start.to, target.from] : [start.from, target.to];
3488
+ updateSelection(this.view, TextSelection.create(doc, anchor, head), "pointer");
3489
+ }
3439
3490
  }
3440
3491
  handlers.touchstart = view => {
3441
3492
  view.input.lastTouch = Date.now();
@@ -3460,7 +3511,7 @@ function inOrNearComposition(view, event) {
3460
3511
  // This guards against the case where compositionend is triggered without the keyboard
3461
3512
  // (e.g. character confirmation may be done with the mouse), and keydown is triggered
3462
3513
  // afterwards- we wouldn't want to ignore the keydown event in this case.
3463
- if (safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
3514
+ if (safari && Math.abs(Date.now() - view.input.compositionEndedAt) < 500) {
3464
3515
  view.input.compositionEndedAt = -2e8;
3465
3516
  return true;
3466
3517
  }
@@ -3519,7 +3570,7 @@ function selectionBeforeUneditable(view) {
3519
3570
  editHandlers.compositionend = (view, event) => {
3520
3571
  if (view.composing) {
3521
3572
  view.input.composing = false;
3522
- view.input.compositionEndedAt = event.timeStamp;
3573
+ view.input.compositionEndedAt = Date.now();
3523
3574
  view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
3524
3575
  view.input.compositionNode = null;
3525
3576
  if (view.input.badSafariComposition)
@@ -3538,7 +3589,7 @@ function scheduleComposeEnd(view, delay) {
3538
3589
  function clearComposition(view) {
3539
3590
  if (view.composing) {
3540
3591
  view.input.composing = false;
3541
- view.input.compositionEndedAt = timestampFromCustomEvent();
3592
+ view.input.compositionEndedAt = Date.now();
3542
3593
  }
3543
3594
  while (view.input.compositionNodes.length > 0)
3544
3595
  view.input.compositionNodes.pop().markParentsDirty();
@@ -3564,11 +3615,6 @@ function findCompositionNode(view) {
3564
3615
  }
3565
3616
  return textBefore || textAfter;
3566
3617
  }
3567
- function timestampFromCustomEvent() {
3568
- let event = document.createEvent("Event");
3569
- event.initEvent("event", true, true);
3570
- return event.timeStamp;
3571
- }
3572
3618
  /**
3573
3619
  @internal
3574
3620
  */
@@ -4725,7 +4771,10 @@ class DOMObserver {
4725
4771
  }
4726
4772
  }
4727
4773
  }
4728
- if (added.some(n => n.nodeName == "BR") && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
4774
+ if (added.some(n => n.nodeName == "BR") &&
4775
+ (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46 ||
4776
+ chrome && (view.composing || view.input.compositionEndedAt > Date.now() - 50) &&
4777
+ mutations.some(m => m.type == "childList" && m.removedNodes.length))) {
4729
4778
  // Browsers sometimes insert a bogus break node if you
4730
4779
  // backspace out the last bit of text before an inline-flex node (#1552)
4731
4780
  for (let node of added)
@@ -5281,38 +5330,28 @@ function skipClosingAndOpening($pos, fromEnd, mayOpen) {
5281
5330
  return end;
5282
5331
  }
5283
5332
  function findDiff(a, b, pos, preferredPos, preferredSide) {
5284
- let start = a.findDiffStart(b, pos);
5333
+ let start = a.findDiffStart(b, pos), lenA = pos + a.size, lenB = pos + b.size;
5285
5334
  if (start == null)
5286
5335
  return null;
5287
- let { a: endA, b: endB } = a.findDiffEnd(b, pos + a.size, pos + b.size);
5336
+ let { a: endA, b: endB } = a.findDiffEnd(b, lenA, lenB);
5288
5337
  if (preferredSide == "end") {
5289
5338
  let adjust = Math.max(0, start - Math.min(endA, endB));
5290
5339
  preferredPos -= endA + adjust - start;
5291
5340
  }
5292
- if (endA < start && a.size < b.size) {
5341
+ if (endA < start && lenA < lenB) {
5293
5342
  let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
5294
5343
  start -= move;
5295
- if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
5296
- start += move ? 1 : -1;
5297
5344
  endB = start + (endB - endA);
5298
5345
  endA = start;
5299
5346
  }
5300
5347
  else if (endB < start) {
5301
5348
  let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
5302
5349
  start -= move;
5303
- if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
5304
- start += move ? 1 : -1;
5305
5350
  endA = start + (endA - endB);
5306
5351
  endB = start;
5307
5352
  }
5308
5353
  return { start, endA, endB };
5309
5354
  }
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
5355
 
5317
5356
  /**
5318
5357
  @internal
@@ -5513,9 +5552,10 @@ class EditorView {
5513
5552
  // a DOM selection change and the "selectionchange" event for it
5514
5553
  // can cause a spurious DOM selection update, disrupting mouse
5515
5554
  // drag selection.
5555
+ let mouseDown = this.input.mouseDown;
5516
5556
  if (forceSelUpdate ||
5517
- !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
5518
- anchorInRightPlace(this))) {
5557
+ !(mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
5558
+ anchorInRightPlace(this) && mouseDown.delaySelUpdate())) {
5519
5559
  selectionToDOM(this, forceSelUpdate);
5520
5560
  }
5521
5561
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.41.8",
3
+ "version": "1.41.9",
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.20.0",
31
+ "prosemirror-model": "^1.25.8",
32
32
  "prosemirror-state": "^1.0.0",
33
33
  "prosemirror-transform": "^1.1.0"
34
34
  },
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, pos + a.size, pos + b.size)!
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 && a.size < b.size) {
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
- }
@@ -192,7 +192,10 @@ export class DOMObserver {
192
192
  }
193
193
  }
194
194
 
195
- if (added.some(n => n.nodeName == "BR") && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
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
- !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
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)
package/src/input.ts CHANGED
@@ -66,6 +66,7 @@ function setSelectionOrigin(view: EditorView, origin: string) {
66
66
  }
67
67
 
68
68
  export function destroyInput(view: EditorView) {
69
+ if (view.input.mouseDown) view.input.mouseDown.done()
69
70
  view.domObserver.stop()
70
71
  for (let type in view.input.eventHandlers)
71
72
  view.dom.removeEventListener(type, view.input.eventHandlers[type])
@@ -246,27 +247,28 @@ function handleTripleClick(view: EditorView, pos: number, inside: number, event:
246
247
 
247
248
  function defaultTripleClick(view: EditorView, inside: number, event: MouseEvent) {
248
249
  if (event.button != 0) return false
250
+ let selection = selectionForTripleClick(view, inside, true), doc = view.state.doc
251
+ if (!selection) return false
252
+ updateSelection(view, selection, "pointer")
253
+ if (selection instanceof TextSelection && doc.eq(view.state.doc))
254
+ view.input.mouseDown = new TripleClickDrag(view, selection)
255
+ return true
256
+ }
257
+
258
+ function selectionForTripleClick(view: EditorView, inside: number, selectNodes: boolean): Selection | null {
249
259
  let doc = view.state.doc
250
- if (inside == -1) {
251
- if (doc.inlineContent) {
252
- updateSelection(view, TextSelection.create(doc, 0, doc.content.size), "pointer")
253
- return true
254
- }
255
- return false
256
- }
260
+ if (inside == -1) return doc.inlineContent ? TextSelection.create(doc, 0, doc.content.size) : null
257
261
 
258
262
  let $pos = doc.resolve(inside)
259
263
  for (let i = $pos.depth + 1; i > 0; i--) {
260
264
  let node = i > $pos.depth ? $pos.nodeAfter! : $pos.node(i)
261
265
  let nodePos = $pos.before(i)
262
266
  if (node.inlineContent)
263
- updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer")
264
- else if (NodeSelection.isSelectable(node))
265
- updateSelection(view, NodeSelection.create(doc, nodePos), "pointer")
266
- else
267
- continue
268
- return true
267
+ return TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size)
268
+ else if (selectNodes && NodeSelection.isSelectable(node))
269
+ return NodeSelection.create(doc, nodePos)
269
270
  }
271
+ return null
270
272
  }
271
273
 
272
274
  function forceDOMFlush(view: EditorView) {
@@ -287,12 +289,13 @@ handlers.mousedown = (view, _event) => {
287
289
  }
288
290
  view.input.lastClick = {time: now, x: event.clientX, y: event.clientY, type, button: event.button}
289
291
 
292
+ if (view.input.mouseDown) view.input.mouseDown.done()
293
+
290
294
  let pos = view.posAtCoords(eventCoords(event))
291
295
  if (!pos) return
292
296
 
293
297
  if (type == "singleClick") {
294
- if (view.input.mouseDown) view.input.mouseDown.done()
295
- view.input.mouseDown = new MouseDown(view, pos, event, !!flushed)
298
+ view.input.mouseDown = new LeftMouseDown(view, pos, event, !!flushed)
296
299
  } else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
297
300
  event.preventDefault()
298
301
  } else {
@@ -300,20 +303,46 @@ handlers.mousedown = (view, _event) => {
300
303
  }
301
304
  }
302
305
 
303
- class MouseDown {
306
+
307
+ abstract class MouseDown {
308
+ mightDrag: {node: Node, pos: number, addAttr: boolean, setUneditable: boolean} | null = null
309
+
310
+ constructor(readonly view: EditorView) {
311
+ view.root.addEventListener("mouseup", this.up = this.up.bind(this) as any)
312
+ view.root.addEventListener("mousemove", this.move = this.move.bind(this) as any)
313
+ }
314
+
315
+ up(event: MouseEvent) {
316
+ this.done()
317
+ }
318
+
319
+ move(event: MouseEvent) {
320
+ if (event.buttons == 0) this.done()
321
+ }
322
+
323
+ done() {
324
+ this.view.root.removeEventListener("mouseup", this.up as any)
325
+ this.view.root.removeEventListener("mousemove", this.move as any)
326
+ if (this.view.input.mouseDown == this) this.view.input.mouseDown = null
327
+ }
328
+
329
+ delaySelUpdate() { return false }
330
+ }
331
+
332
+ class LeftMouseDown extends MouseDown {
304
333
  startDoc: Node
305
334
  selectNode: boolean
306
335
  allowDefault: boolean
307
336
  delayedSelectionSync = false
308
- mightDrag: {node: Node, pos: number, addAttr: boolean, setUneditable: boolean} | null = null
309
337
  target: HTMLElement | null
310
338
 
311
339
  constructor(
312
- readonly view: EditorView,
340
+ view: EditorView,
313
341
  readonly pos: {pos: number, inside: number},
314
342
  readonly event: MouseEvent,
315
343
  readonly flushed: boolean
316
344
  ) {
345
+ super(view)
317
346
  this.startDoc = view.state.doc
318
347
  this.selectNode = !!event[selectNodeModifier]
319
348
  this.allowDefault = event.shiftKey
@@ -353,22 +382,20 @@ class MouseDown {
353
382
  this.view.domObserver.start()
354
383
  }
355
384
 
356
- view.root.addEventListener("mouseup", this.up = this.up.bind(this) as any)
357
- view.root.addEventListener("mousemove", this.move = this.move.bind(this) as any)
358
385
  setSelectionOrigin(view, "pointer")
359
386
  }
360
387
 
361
388
  done() {
362
- this.view.root.removeEventListener("mouseup", this.up as any)
363
- this.view.root.removeEventListener("mousemove", this.move as any)
389
+ super.done()
364
390
  if (this.mightDrag && this.target) {
365
391
  this.view.domObserver.stop()
366
392
  if (this.mightDrag.addAttr) this.target.removeAttribute("draggable")
367
393
  if (this.mightDrag.setUneditable) this.target.removeAttribute("contentEditable")
368
394
  this.view.domObserver.start()
369
395
  }
370
- if (this.delayedSelectionSync) setTimeout(() => selectionToDOM(this.view))
371
- this.view.input.mouseDown = null
396
+ if (this.delayedSelectionSync) setTimeout(() => {
397
+ if (!this.view.isDestroyed) selectionToDOM(this.view)
398
+ })
372
399
  }
373
400
 
374
401
  up(event: MouseEvent) {
@@ -409,7 +436,7 @@ class MouseDown {
409
436
  move(event: MouseEvent) {
410
437
  this.updateAllowDefault(event)
411
438
  setSelectionOrigin(this.view, "pointer")
412
- if (event.buttons == 0) this.done()
439
+ super.move(event)
413
440
  }
414
441
 
415
442
  updateAllowDefault(event: MouseEvent) {
@@ -417,6 +444,39 @@ class MouseDown {
417
444
  Math.abs(this.event.y - event.clientY) > 4))
418
445
  this.allowDefault = true
419
446
  }
447
+
448
+ delaySelUpdate() {
449
+ if (!this.allowDefault) return false
450
+ this.delayedSelectionSync = true
451
+ return true
452
+ }
453
+ }
454
+
455
+ class TripleClickDrag extends MouseDown {
456
+ startDoc: Node
457
+
458
+ constructor(view: EditorView, readonly startSelection: TextSelection) {
459
+ super(view)
460
+ this.startDoc = view.state.doc
461
+ }
462
+
463
+ move(event: MouseEvent) {
464
+ if (event.buttons == 0 || this.view.isDestroyed || !this.view.state.doc.eq(this.startDoc)) {
465
+ this.done()
466
+ return
467
+ }
468
+
469
+ event.preventDefault()
470
+ setSelectionOrigin(this.view, "pointer")
471
+
472
+ let pos = this.view.posAtCoords(eventCoords(event))
473
+ let target = pos && selectionForTripleClick(this.view, pos.inside, false)
474
+ if (!target) return
475
+
476
+ let {doc} = this.view.state, start = this.startSelection
477
+ let [anchor, head] = target.from < start.from ? [start.to, target.from] : [start.from, target.to]
478
+ updateSelection(this.view, TextSelection.create(doc, anchor, head), "pointer")
479
+ }
420
480
  }
421
481
 
422
482
  handlers.touchstart = view => {
@@ -444,7 +504,7 @@ function inOrNearComposition(view: EditorView, event: Event) {
444
504
  // This guards against the case where compositionend is triggered without the keyboard
445
505
  // (e.g. character confirmation may be done with the mouse), and keydown is triggered
446
506
  // afterwards- we wouldn't want to ignore the keydown event in this case.
447
- if (browser.safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
507
+ if (browser.safari && Math.abs(Date.now() - view.input.compositionEndedAt) < 500) {
448
508
  view.input.compositionEndedAt = -2e8
449
509
  return true
450
510
  }
@@ -502,7 +562,7 @@ function selectionBeforeUneditable(view: EditorView) {
502
562
  editHandlers.compositionend = (view, event) => {
503
563
  if (view.composing) {
504
564
  view.input.composing = false
505
- view.input.compositionEndedAt = event.timeStamp
565
+ view.input.compositionEndedAt = Date.now()
506
566
  view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0
507
567
  view.input.compositionNode = null
508
568
  if (view.input.badSafariComposition) view.domObserver.forceFlush()
@@ -520,7 +580,7 @@ function scheduleComposeEnd(view: EditorView, delay: number) {
520
580
  export function clearComposition(view: EditorView) {
521
581
  if (view.composing) {
522
582
  view.input.composing = false
523
- view.input.compositionEndedAt = timestampFromCustomEvent()
583
+ view.input.compositionEndedAt = Date.now()
524
584
  }
525
585
  while (view.input.compositionNodes.length > 0) view.input.compositionNodes.pop()!.markParentsDirty()
526
586
  }
@@ -544,12 +604,6 @@ export function findCompositionNode(view: EditorView) {
544
604
  return textBefore || textAfter
545
605
  }
546
606
 
547
- function timestampFromCustomEvent() {
548
- let event = document.createEvent("Event")
549
- event.initEvent("event", true, true)
550
- return event.timeStamp
551
- }
552
-
553
607
  /// @internal
554
608
  export function endComposition(view: EditorView, restarting = false) {
555
609
  if (browser.android && view.domObserver.flushingSoon >= 0) return
package/src/selection.ts CHANGED
@@ -58,15 +58,15 @@ export function selectionToDOM(view: EditorView, force = false) {
58
58
 
59
59
  if (!editorOwnsSelection(view)) return
60
60
 
61
- // The delayed drag selection causes issues with Cell Selections
62
- // in Safari. And the drag selection delay is to workarond issues
63
- // which only present in Chrome.
64
- if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && browser.chrome) {
61
+ // Need to delay selection normalization during a native selection
62
+ // drag on Chrome, or it will cause further dragging to glitch.
63
+ let mouseDown = view.input.mouseDown
64
+ if (!force && browser.chrome && mouseDown) {
65
65
  let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection
66
66
  if (domSel.anchorNode && curSel.anchorNode &&
67
67
  isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset,
68
- curSel.anchorNode, curSel.anchorOffset)) {
69
- view.input.mouseDown.delayedSelectionSync = true
68
+ curSel.anchorNode, curSel.anchorOffset) &&
69
+ mouseDown.delaySelUpdate()) {
70
70
  view.domObserver.setCurSelection()
71
71
  return
72
72
  }