slate 0.47.4 → 0.47.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/slate.js CHANGED
@@ -615,7 +615,7 @@ function transform(path, operation) {
615
615
  p = operation.path;
616
616
 
617
617
 
618
- if (type === 'add_mark' || type === 'insert_text' || type === 'remove_mark' || type === 'remove_text' || type === 'set_mark' || type === 'set_node' || type === 'set_selection' || type === 'set_value' || path.size === 0) {
618
+ if (type === 'add_mark' || type === 'insert_text' || type === 'remove_mark' || type === 'remove_text' || type === 'set_mark' || type === 'set_node' || type === 'set_selection' || type === 'set_value' || type === 'add_annotation' || type === 'remove_annotation' || type === 'set_annotation' || path.size === 0) {
619
619
  return immutable.List([path]);
620
620
  }
621
621
 
@@ -2763,7 +2763,7 @@ var Text = function (_Record) {
2763
2763
  }
2764
2764
 
2765
2765
  // If the range starts after the leaf, or ends before it, continue.
2766
- if (start.offset > offset + length || end.offset <= offset) {
2766
+ if (start.offset > offset + length || end.offset < offset || end.offset === offset && offset !== 0) {
2767
2767
  next.push(leaf);
2768
2768
  continue;
2769
2769
  }
@@ -3479,10 +3479,14 @@ var Value = function (_Record) {
3479
3479
  annotation = Annotation.create(annotation);
3480
3480
  var value = this;
3481
3481
  var _value = value,
3482
- annotations = _value.annotations;
3482
+ annotations = _value.annotations,
3483
+ document = _value.document;
3483
3484
  var _annotation = annotation,
3484
3485
  key = _annotation.key;
3485
3486
 
3487
+ annotation = annotation.updatePoints(function (point) {
3488
+ return point.normalize(document);
3489
+ });
3486
3490
  annotations = annotations.set(key, annotation);
3487
3491
  value = value.set('annotations', annotations);
3488
3492
  return value;
@@ -3715,16 +3719,16 @@ var Value = function (_Record) {
3715
3719
 
3716
3720
  value = value.mapRanges(function (range) {
3717
3721
  var _range = range,
3718
- start = _range.start,
3719
- end = _range.end;
3722
+ anchor = _range.anchor,
3723
+ focus = _range.focus;
3720
3724
 
3721
3725
 
3722
- if (node.hasNode(start.key)) {
3723
- range = prev ? range.moveStartTo(prev.key, prev.text.length) : next ? range.moveStartTo(next.key, 0) : range.unset();
3726
+ if (node.hasNode(anchor.key)) {
3727
+ range = prev ? range.moveAnchorTo(prev.key, prev.text.length) : next ? range.moveAnchorTo(next.key, 0) : range.unset();
3724
3728
  }
3725
3729
 
3726
- if (node.hasNode(end.key)) {
3727
- range = prev ? range.moveEndTo(prev.key, prev.text.length) : next ? range.moveEndTo(next.key, 0) : range.unset();
3730
+ if (node.hasNode(focus.key)) {
3731
+ range = prev ? range.moveFocusTo(prev.key, prev.text.length) : next ? range.moveFocusTo(next.key, 0) : range.unset();
3728
3732
  }
3729
3733
 
3730
3734
  range = range.updatePoints(function (point) {
@@ -3924,18 +3928,18 @@ var Value = function (_Record) {
3924
3928
  value = value.mapRanges(function (range) {
3925
3929
  var next = newDocument.getNextText(node.key);
3926
3930
  var _range2 = range,
3927
- start = _range2.start,
3928
- end = _range2.end;
3931
+ anchor = _range2.anchor,
3932
+ focus = _range2.focus;
3929
3933
 
3930
- // If the start was after the split, move it to the next node.
3934
+ // If the anchor was after the split, move it to the next node.
3931
3935
 
3932
- if (node.key === start.key && position <= start.offset) {
3933
- range = range.moveStartTo(next.key, start.offset - position);
3936
+ if (node.key === anchor.key && position <= anchor.offset) {
3937
+ range = range.moveAnchorTo(next.key, anchor.offset - position);
3934
3938
  }
3935
3939
 
3936
- // If the end was after the split, move it to the next node.
3937
- if (node.key === end.key && position <= end.offset) {
3938
- range = range.moveEndTo(next.key, end.offset - position);
3940
+ // If the focus was after the split, move it to the next node.
3941
+ if (node.key === focus.key && position <= focus.offset) {
3942
+ range = range.moveFocusTo(next.key, focus.offset - position);
3939
3943
  }
3940
3944
 
3941
3945
  range = range.updatePoints(function (point) {
@@ -4374,7 +4378,7 @@ var Value = function (_Record) {
4374
4378
 
4375
4379
  if (isPlainObject(a)) {
4376
4380
  var p = {};
4377
- if ('annotations' in a) p.annotations = Annotation.createList(a.annotations);
4381
+ if ('annotations' in a) p.annotations = Annotation.createMap(a.annotations);
4378
4382
  if ('data' in a) p.data = Data.create(a.data);
4379
4383
  return p;
4380
4384
  }
@@ -5835,7 +5839,7 @@ Commands$1.deleteBackwardAtRange = function (editor, range) {
5835
5839
 
5836
5840
  // If the focus offset is farther than the number of characters to delete,
5837
5841
  // just remove the characters backwards inside the current node.
5838
- if (n < focus.offset) {
5842
+ if (n <= focus.offset) {
5839
5843
  range = range.moveFocusBackward(n);
5840
5844
  editor.deleteAtRange(range);
5841
5845
  return;
@@ -6211,7 +6215,7 @@ Commands$1.insertFragmentAtRange = function (editor, range, fragment) {
6211
6215
 
6212
6216
  // Regenerate the keys for all of the fragments nodes, so that they're
6213
6217
  // guaranteed not to collide with the existing keys in the document. Otherwise
6214
- // they will be rengerated automatically and we won't have an easy way to
6218
+ // they will be regenerated automatically and we won't have an easy way to
6215
6219
  // reference them.
6216
6220
  fragment = fragment.mapDescendants(function (child) {
6217
6221
  return child.regenerateKey();
@@ -7020,6 +7024,63 @@ Commands$2.addMarksByPath = function (editor, path, offset, length, marks) {
7020
7024
  });
7021
7025
  };
7022
7026
 
7027
+ /**
7028
+ * Sets specific set of marks on the path
7029
+ * @param {Editor} editor
7030
+ * @param {Array} path
7031
+ * @param {Number} offset
7032
+ * @param {Number} length
7033
+ * @param {Array<Object|Mark>} marks
7034
+ */
7035
+
7036
+ Commands$2.replaceMarksByPath = function (editor, path, offset, length, marks) {
7037
+ var marksSet = Mark.createSet(marks);
7038
+
7039
+ var value = editor.value;
7040
+ var document = value.document;
7041
+
7042
+ var node = document.assertNode(path);
7043
+
7044
+ if (node.marks.equals(marksSet)) {
7045
+ return;
7046
+ }
7047
+
7048
+ editor.withoutNormalizing(function () {
7049
+ // If it ends before the end of the node, we'll need to split to create a new
7050
+ // text with different marks.
7051
+ if (offset + length < node.text.length) {
7052
+ editor.splitNodeByPath(path, offset + length);
7053
+ }
7054
+
7055
+ // Same thing if it starts after the start. But in that case, we need to
7056
+ // update our path and offset to point to the new start.
7057
+ if (offset > 0) {
7058
+ editor.splitNodeByPath(path, offset);
7059
+ path = PathUtils.increment(path);
7060
+ offset = 0;
7061
+ }
7062
+
7063
+ var marksToApply = marksSet.subtract(node.marks);
7064
+ var marksToRemove = node.marks.subtract(marksSet);
7065
+
7066
+ marksToRemove.forEach(function (mark) {
7067
+ editor.applyOperation({
7068
+ type: 'remove_mark',
7069
+ path: path,
7070
+ mark: Mark.create(mark)
7071
+ });
7072
+ });
7073
+
7074
+ marksToApply.forEach(function (mark) {
7075
+ editor.applyOperation({
7076
+ type: 'add_mark',
7077
+ path: path,
7078
+ mark: Mark.create(mark)
7079
+ });
7080
+ });
7081
+ });
7082
+ };
7083
+
7023
7084
  /**
7024
7085
  * Insert a `fragment` at `index` in a node by `path`.
7025
7086
  *
@@ -7063,7 +7124,6 @@ Commands$2.insertNodeByPath = function (editor, path, index, node) {
7063
7124
  */
7064
7125
 
7065
7126
  Commands$2.insertTextByPath = function (editor, path, offset, text, marks) {
7066
- marks = Mark.createSet(marks);
7067
7127
  var value = editor.value;
7068
7128
  var annotations = value.annotations,
7069
7129
  document = value.document;
@@ -7117,8 +7177,8 @@ Commands$2.insertTextByPath = function (editor, path, offset, text, marks) {
7117
7177
  text: text
7118
7178
  });
7119
7179
 
7120
- if (marks.size) {
7121
- editor.addMarksByPath(path, offset, text.length, marks);
7180
+ if (marks) {
7181
+ editor.replaceMarksByPath(path, offset, text.length, marks);
7122
7182
  }
7123
7183
  });
7124
7184
  };
@@ -7213,6 +7273,10 @@ Commands$2.removeMarksByPath = function (editor, path, offset, length, marks) {
7213
7273
 
7214
7274
  var node = document.assertNode(path);
7215
7275
 
7276
+ if (marks.intersect(node.marks).isEmpty()) {
7277
+ return;
7278
+ }
7279
+
7216
7280
  editor.withoutNormalizing(function () {
7217
7281
  // If it ends before the end of the node, we'll need to split to create a new
7218
7282
  // text with different marks.
@@ -7769,7 +7833,7 @@ Commands$2.wrapNodeByPath = function (editor, path, node) {
7769
7833
  * Mix in `*ByKey` variants.
7770
7834
  */
7771
7835
 
7772
- var COMMANDS = ['addMark', 'insertFragment', 'insertNode', 'insertText', 'mergeNode', 'removeAllMarks', 'removeMark', 'removeNode', 'removeText', 'replaceNode', 'replaceText', 'setMark', 'setNode', 'setText', 'splitNode', 'unwrapBlock', 'unwrapChildren', 'unwrapInline', 'unwrapNode', 'wrapBlock', 'wrapInline', 'wrapNode'];
7836
+ var COMMANDS = ['addMark', 'insertFragment', 'insertNode', 'insertText', 'mergeNode', 'removeAllMarks', 'removeMark', 'removeNode', 'removeText', 'replaceMarks', 'replaceNode', 'replaceText', 'setMark', 'setNode', 'setText', 'splitNode', 'unwrapBlock', 'unwrapChildren', 'unwrapInline', 'unwrapNode', 'wrapBlock', 'wrapInline', 'wrapNode'];
7773
7837
 
7774
7838
  var _loop = function _loop(method) {
7775
7839
  Commands$2[method + 'ByKey'] = function (editor, key) {
@@ -7862,7 +7926,7 @@ Commands$3.save = function (editor, operation) {
7862
7926
  save = _editor$tmp.save,
7863
7927
  merge = _editor$tmp.merge;
7864
7928
 
7865
- if (save === false) return;
7929
+ if (save === false || !isValidOperation(operation)) return;
7866
7930
 
7867
7931
  var undos = data.get('undos') || immutable.List();
7868
7932
  var lastBatch = undos.last();
@@ -7923,13 +7987,13 @@ Commands$3.redo = function (editor) {
7923
7987
  batch.forEach(function (op) {
7924
7988
  var _op = op,
7925
7989
  type = _op.type,
7926
- properties = _op.properties;
7990
+ newProperties = _op.newProperties;
7927
7991
 
7928
7992
  // When the operation mutates the selection, omit its `isFocused` value to
7929
7993
  // prevent the editor focus from changing during redoing.
7930
7994
 
7931
7995
  if (type === 'set_selection') {
7932
- op = op.set('properties', omit(properties, 'isFocused'));
7996
+ op = op.set('newProperties', omit(newProperties, 'isFocused'));
7933
7997
  }
7934
7998
 
7935
7999
  editor.applyOperation(op);
@@ -7967,13 +8031,13 @@ Commands$3.undo = function (editor) {
7967
8031
  }).forEach(function (inverse) {
7968
8032
  var _inverse = inverse,
7969
8033
  type = _inverse.type,
7970
- properties = _inverse.properties;
8034
+ newProperties = _inverse.newProperties;
7971
8035
 
7972
8036
  // When the operation mutates the selection, omit its `isFocused` value to
7973
8037
  // prevent the editor focus from changing during undoing.
7974
8038
 
7975
8039
  if (type === 'set_selection') {
7976
- inverse = inverse.set('properties', omit(properties, 'isFocused'));
8040
+ inverse = inverse.set('newProperties', omit(newProperties, 'isFocused'));
7977
8041
  }
7978
8042
 
7979
8043
  editor.applyOperation(inverse);
@@ -8034,6 +8098,28 @@ function shouldMerge(o, p) {
8034
8098
  return merge;
8035
8099
  }
8036
8100
 
8101
+ /**
8102
+ * Check weather an operation needs to be saved to the history
8103
+ * @param {Object} o - operation
8104
+ * @returns {Boolean}
8105
+ */
8106
+
8107
+ function isValidOperation(o) {
8108
+ if (o.type === 'set_selection') {
8109
+ var _o$newProperties = o.newProperties,
8110
+ isFocused = _o$newProperties.isFocused,
8111
+ anchor = _o$newProperties.anchor,
8112
+ focus = _o$newProperties.focus;
8113
+
8114
+ // this is blur/focus operation, dont need to store it into the history
8115
+
8116
+ if (isFocused !== undefined && !anchor && !focus) {
8117
+ return false;
8118
+ }
8119
+ }
8120
+ return true;
8121
+ }
8122
+
8037
8123
  var Commands$4 = {};
8038
8124
 
8039
8125
  Commands$4.blur = function (editor) {
@@ -9065,6 +9151,20 @@ Commands$5.setAnnotation = function (editor, annotation, newProperties) {
9065
9151
  });
9066
9152
  };
9067
9153
 
9154
+ Commands$5.setAnnotations = function (editor) {
9155
+ var annotations = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
9156
+ var value = editor.value;
9157
+
9158
+ var newProperties = Value.createProperties({ annotations: annotations });
9159
+ var prevProperties = pick(value, Object.keys(newProperties));
9160
+
9161
+ editor.applyOperation({
9162
+ type: 'set_value',
9163
+ properties: prevProperties,
9164
+ newProperties: newProperties
9165
+ });
9166
+ };
9167
+
9068
9168
  /**
9069
9169
  * A plugin that adds a set of queries to the editor.
9070
9170
  *
@@ -10154,27 +10254,14 @@ Commands$6.insertFragment = function (editor, fragment) {
10154
10254
  var _value = value,
10155
10255
  document = _value.document,
10156
10256
  selection = _value.selection;
10157
- var start = selection.start,
10158
- end = selection.end;
10159
- var _value2 = value,
10160
- startText = _value2.startText,
10161
- endText = _value2.endText,
10162
- startInline = _value2.startInline;
10163
-
10164
- var lastText = fragment.getLastText();
10165
- var lastInline = fragment.getClosestInline(lastText.key);
10166
- var lastBlock = fragment.getClosestBlock(lastText.key);
10167
- var firstChild = fragment.nodes.first();
10168
- var lastChild = fragment.nodes.last();
10257
+ var start = selection.start;
10258
+
10169
10259
  var keys = Array.from(document.texts(), function (_ref) {
10170
10260
  var _ref2 = slicedToArray(_ref, 1),
10171
10261
  text = _ref2[0];
10172
10262
 
10173
10263
  return text.key;
10174
10264
  });
10175
- var isAppending = !startInline || start.isAtStartOfNode(startText) || end.isAtStartOfNode(startText) || start.isAtEndOfNode(endText) || end.isAtEndOfNode(endText);
10176
-
10177
- var isInserting = firstChild.hasBlockChildren() || lastChild.hasBlockChildren();
10178
10265
 
10179
10266
  editor.insertFragmentAtRange(selection, fragment);
10180
10267
  value = editor.value;
@@ -10183,25 +10270,28 @@ Commands$6.insertFragment = function (editor, fragment) {
10183
10270
  var newTexts = document.getTexts().filter(function (n) {
10184
10271
  return !keys.includes(n.key);
10185
10272
  });
10186
- var newText = isAppending ? newTexts.last() : newTexts.takeLast(2).first();
10187
-
10188
- if (newText && (lastInline || isInserting)) {
10189
- editor.moveToEndOfNode(newText);
10190
- } else if (newText) {
10191
- // The position within the last text node needs to be calculated. This is the length
10192
- // of all text nodes within the last block, but if the last block contains inline nodes,
10193
- // these have to be skipped.
10194
- var nodes = lastBlock.nodes;
10195
-
10196
- var lastIndex = nodes.findLastIndex(function (node) {
10197
- return node && node.object === 'inline';
10198
- });
10199
- var remainingTexts = nodes.takeLast(nodes.size - lastIndex - 1);
10200
- var remainingTextLength = remainingTexts.reduce(function (acc, val) {
10201
- return acc + val.text.length;
10202
- }, 0);
10203
- editor.moveToStartOfNode(newText).moveForward(remainingTextLength);
10273
+ if (newTexts.size === 0) return;
10274
+ var fragmentLength = fragment.text.length;
10275
+
10276
+ // Either startText is still here, or we want the first un-previously known text
10277
+ var startText = document.getNode(start.key) || newTexts.first();
10278
+ // We want the last un-previously known text
10279
+ var endText = newTexts.last() || startText;
10280
+
10281
+ if (startText === endText) {
10282
+ editor.moveTo(endText.key, fragmentLength);
10283
+ return;
10204
10284
  }
10285
+
10286
+ // Everything will be calculated relative to the first common ancestor to optimize speed
10287
+ var parent = document.getCommonAncestor(startText.key, endText.key);
10288
+
10289
+ var startOffset = parent.getOffset(startText.key) + (start.key === startText.key ? start.offset : 0);
10290
+
10291
+ // endText might not be the last un-previously known text node, so we precisely pick it by offset
10292
+ endText = parent.getTextAtOffset(startOffset + fragmentLength - 1) || endText;
10293
+
10294
+ editor.moveTo(endText.key, startOffset + fragmentLength - parent.getOffset(endText.key));
10205
10295
  };
10206
10296
 
10207
10297
  /**
@@ -10764,14 +10854,27 @@ var Editor = function () {
10764
10854
 
10765
10855
  // Get the paths of the affected nodes, and mark them as dirty.
10766
10856
  var newDirtyPaths = getDirtyPaths(operation);
10767
- var dirty = this.tmp.dirty.reduce(function (memo, path) {
10857
+
10858
+ var dirty = this.tmp.dirty.map(function (path) {
10768
10859
  path = PathUtils.create(path);
10769
10860
  var transformed = PathUtils.transform(path, operation);
10770
- memo = memo.concat(transformed.toArray());
10771
- return memo;
10772
- }, newDirtyPaths);
10861
+ return transformed.toArray();
10862
+ });
10773
10863
 
10774
- this.tmp.dirty = dirty;
10864
+ var pathIndex = {};
10865
+ var dirtyPaths = Array.prototype.concat.apply(newDirtyPaths, dirty);
10866
+ this.tmp.dirty = [];
10867
+
10868
+ // PERF: De-dupe the paths so we don't do extra normalization.
10869
+ dirtyPaths.forEach(function (dirtyPath) {
10870
+ var key = dirtyPath.join(',');
10871
+
10872
+ if (!pathIndex[key]) {
10873
+ _this.tmp.dirty.push(dirtyPath);
10874
+ }
10875
+
10876
+ pathIndex[key] = true;
10877
+ });
10775
10878
 
10776
10879
  // If we're not already, queue the flushing process on the next tick.
10777
10880
  if (!this.tmp.flushing) {