@atlaskit/editor-plugin-find-replace 0.1.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.
Files changed (121) hide show
  1. package/.eslintrc.js +26 -0
  2. package/CHANGELOG.md +11 -0
  3. package/LICENSE.md +13 -0
  4. package/README.md +30 -0
  5. package/dist/cjs/FindReplaceToolbarButtonWithState.js +166 -0
  6. package/dist/cjs/actions.js +19 -0
  7. package/dist/cjs/commands-with-analytics.js +101 -0
  8. package/dist/cjs/commands.js +255 -0
  9. package/dist/cjs/index.js +12 -0
  10. package/dist/cjs/plugin.js +93 -0
  11. package/dist/cjs/pm-plugins/keymap.js +24 -0
  12. package/dist/cjs/pm-plugins/main.js +39 -0
  13. package/dist/cjs/pm-plugins/plugin-factory.js +109 -0
  14. package/dist/cjs/pm-plugins/plugin-key.js +8 -0
  15. package/dist/cjs/reducer.js +61 -0
  16. package/dist/cjs/styles.js +17 -0
  17. package/dist/cjs/types.js +5 -0
  18. package/dist/cjs/ui/Find.js +309 -0
  19. package/dist/cjs/ui/FindReplace.js +104 -0
  20. package/dist/cjs/ui/FindReplaceToolbarButton.js +133 -0
  21. package/dist/cjs/ui/FindReplaceTooltipButton.js +77 -0
  22. package/dist/cjs/ui/Replace.js +176 -0
  23. package/dist/cjs/ui/styles.js +46 -0
  24. package/dist/cjs/utils/array.js +13 -0
  25. package/dist/cjs/utils/batch-decorations.js +310 -0
  26. package/dist/cjs/utils/commands.js +16 -0
  27. package/dist/cjs/utils/index.js +290 -0
  28. package/dist/es2019/FindReplaceToolbarButtonWithState.js +153 -0
  29. package/dist/es2019/actions.js +13 -0
  30. package/dist/es2019/commands-with-analytics.js +72 -0
  31. package/dist/es2019/commands.js +240 -0
  32. package/dist/es2019/index.js +1 -0
  33. package/dist/es2019/plugin.js +88 -0
  34. package/dist/es2019/pm-plugins/keymap.js +16 -0
  35. package/dist/es2019/pm-plugins/main.js +30 -0
  36. package/dist/es2019/pm-plugins/plugin-factory.js +91 -0
  37. package/dist/es2019/pm-plugins/plugin-key.js +2 -0
  38. package/dist/es2019/reducer.js +56 -0
  39. package/dist/es2019/styles.js +18 -0
  40. package/dist/es2019/types.js +1 -0
  41. package/dist/es2019/ui/Find.js +286 -0
  42. package/dist/es2019/ui/FindReplace.js +81 -0
  43. package/dist/es2019/ui/FindReplaceToolbarButton.js +122 -0
  44. package/dist/es2019/ui/FindReplaceTooltipButton.js +51 -0
  45. package/dist/es2019/ui/Replace.js +155 -0
  46. package/dist/es2019/ui/styles.js +50 -0
  47. package/dist/es2019/utils/array.js +3 -0
  48. package/dist/es2019/utils/batch-decorations.js +189 -0
  49. package/dist/es2019/utils/commands.js +6 -0
  50. package/dist/es2019/utils/index.js +249 -0
  51. package/dist/esm/FindReplaceToolbarButtonWithState.js +157 -0
  52. package/dist/esm/actions.js +13 -0
  53. package/dist/esm/commands-with-analytics.js +95 -0
  54. package/dist/esm/commands.js +248 -0
  55. package/dist/esm/index.js +1 -0
  56. package/dist/esm/plugin.js +86 -0
  57. package/dist/esm/pm-plugins/keymap.js +18 -0
  58. package/dist/esm/pm-plugins/main.js +33 -0
  59. package/dist/esm/pm-plugins/plugin-factory.js +104 -0
  60. package/dist/esm/pm-plugins/plugin-key.js +2 -0
  61. package/dist/esm/reducer.js +54 -0
  62. package/dist/esm/styles.js +11 -0
  63. package/dist/esm/types.js +1 -0
  64. package/dist/esm/ui/Find.js +304 -0
  65. package/dist/esm/ui/FindReplace.js +100 -0
  66. package/dist/esm/ui/FindReplaceToolbarButton.js +126 -0
  67. package/dist/esm/ui/FindReplaceTooltipButton.js +70 -0
  68. package/dist/esm/ui/Replace.js +171 -0
  69. package/dist/esm/ui/styles.js +39 -0
  70. package/dist/esm/utils/array.js +7 -0
  71. package/dist/esm/utils/batch-decorations.js +304 -0
  72. package/dist/esm/utils/commands.js +10 -0
  73. package/dist/esm/utils/index.js +280 -0
  74. package/dist/types/FindReplaceToolbarButtonWithState.d.ts +4 -0
  75. package/dist/types/actions.d.ts +64 -0
  76. package/dist/types/commands-with-analytics.d.ts +27 -0
  77. package/dist/types/commands.d.ts +12 -0
  78. package/dist/types/index.d.ts +2 -0
  79. package/dist/types/plugin.d.ts +2 -0
  80. package/dist/types/pm-plugins/keymap.d.ts +4 -0
  81. package/dist/types/pm-plugins/main.d.ts +5 -0
  82. package/dist/types/pm-plugins/plugin-factory.d.ts +2 -0
  83. package/dist/types/pm-plugins/plugin-key.d.ts +3 -0
  84. package/dist/types/reducer.d.ts +4 -0
  85. package/dist/types/styles.d.ts +3 -0
  86. package/dist/types/types.d.ts +76 -0
  87. package/dist/types/ui/Find.d.ts +71 -0
  88. package/dist/types/ui/FindReplace.d.ts +43 -0
  89. package/dist/types/ui/FindReplaceToolbarButton.d.ts +21 -0
  90. package/dist/types/ui/FindReplaceTooltipButton.d.ts +18 -0
  91. package/dist/types/ui/Replace.d.ts +27 -0
  92. package/dist/types/ui/styles.d.ts +6 -0
  93. package/dist/types/utils/array.d.ts +1 -0
  94. package/dist/types/utils/batch-decorations.d.ts +36 -0
  95. package/dist/types/utils/commands.d.ts +2 -0
  96. package/dist/types/utils/index.d.ts +49 -0
  97. package/dist/types-ts4.5/FindReplaceToolbarButtonWithState.d.ts +4 -0
  98. package/dist/types-ts4.5/actions.d.ts +64 -0
  99. package/dist/types-ts4.5/commands-with-analytics.d.ts +27 -0
  100. package/dist/types-ts4.5/commands.d.ts +12 -0
  101. package/dist/types-ts4.5/index.d.ts +2 -0
  102. package/dist/types-ts4.5/plugin.d.ts +2 -0
  103. package/dist/types-ts4.5/pm-plugins/keymap.d.ts +4 -0
  104. package/dist/types-ts4.5/pm-plugins/main.d.ts +5 -0
  105. package/dist/types-ts4.5/pm-plugins/plugin-factory.d.ts +2 -0
  106. package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +3 -0
  107. package/dist/types-ts4.5/reducer.d.ts +4 -0
  108. package/dist/types-ts4.5/styles.d.ts +3 -0
  109. package/dist/types-ts4.5/types.d.ts +76 -0
  110. package/dist/types-ts4.5/ui/Find.d.ts +71 -0
  111. package/dist/types-ts4.5/ui/FindReplace.d.ts +43 -0
  112. package/dist/types-ts4.5/ui/FindReplaceToolbarButton.d.ts +21 -0
  113. package/dist/types-ts4.5/ui/FindReplaceTooltipButton.d.ts +18 -0
  114. package/dist/types-ts4.5/ui/Replace.d.ts +27 -0
  115. package/dist/types-ts4.5/ui/styles.d.ts +6 -0
  116. package/dist/types-ts4.5/utils/array.d.ts +1 -0
  117. package/dist/types-ts4.5/utils/batch-decorations.d.ts +36 -0
  118. package/dist/types-ts4.5/utils/commands.d.ts +2 -0
  119. package/dist/types-ts4.5/utils/index.d.ts +49 -0
  120. package/package.json +117 -0
  121. package/styles/package.json +17 -0
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
+ var _pluginFactory = require("../pm-plugins/plugin-factory");
13
+ var _index = require("./index");
14
+ // max number of decorations to apply at once
15
+ var batchIncrement = 100;
16
+ // position range to apply decorations between before alternating above or below viewport
17
+ var posIncrement = 2000;
18
+ /**
19
+ * Provides support for applying search match highlight decorations in batches
20
+ */
21
+ var BatchDecorations = /*#__PURE__*/function () {
22
+ function BatchDecorations() {
23
+ (0, _classCallCheck2.default)(this, BatchDecorations);
24
+ }
25
+ (0, _createClass2.default)(BatchDecorations, [{
26
+ key: "stop",
27
+ value: function stop() {
28
+ if (this.rafId) {
29
+ cancelAnimationFrame(this.rafId);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Applies the decorations needed for the current search results
35
+ * It does so async, splitting them up into batches to help with performance
36
+ */
37
+ }, {
38
+ key: "applyAllSearchDecorations",
39
+ value: function () {
40
+ var _applyAllSearchDecorations = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(editorView, containerElement, addDecorations, removeDecorations) {
41
+ var pmElement, positions, startPos, endPos, viewportStartPos, viewportEndPos, dir, before, after, diff;
42
+ return _regenerator.default.wrap(function _callee$(_context) {
43
+ while (1) switch (_context.prev = _context.next) {
44
+ case 0:
45
+ this.stop();
46
+ this.addDecorations = addDecorations;
47
+ this.removeDecorations = removeDecorations;
48
+ if (containerElement) {
49
+ _context.next = 5;
50
+ break;
51
+ }
52
+ return _context.abrupt("return");
53
+ case 5:
54
+ pmElement = containerElement.querySelector('.ProseMirror');
55
+ if (pmElement) {
56
+ _context.next = 8;
57
+ break;
58
+ }
59
+ return _context.abrupt("return");
60
+ case 8:
61
+ positions = this.calcDecorationPositions(editorView, containerElement, pmElement);
62
+ startPos = positions.startPos, endPos = positions.endPos, viewportStartPos = positions.viewportStartPos, viewportEndPos = positions.viewportEndPos;
63
+ dir = 0;
64
+ before = viewportStartPos;
65
+ after = viewportEndPos - posIncrement;
66
+ _context.next = 15;
67
+ return this.updateDecorationsBetween(editorView, viewportStartPos, viewportEndPos);
68
+ case 15:
69
+ if (!(before > startPos || after < endPos)) {
70
+ _context.next = 28;
71
+ break;
72
+ }
73
+ if (!(dir++ % 2 === 0 && before > startPos || after >= endPos)) {
74
+ _context.next = 23;
75
+ break;
76
+ }
77
+ diff = before - startPos;
78
+ before = Math.max(before - posIncrement, startPos);
79
+ _context.next = 21;
80
+ return this.updateDecorationsBetween(editorView, before, before + Math.min(diff, posIncrement));
81
+ case 21:
82
+ _context.next = 26;
83
+ break;
84
+ case 23:
85
+ after = Math.min(after + posIncrement, endPos);
86
+ _context.next = 26;
87
+ return this.updateDecorationsBetween(editorView, after, Math.min(after + posIncrement, endPos));
88
+ case 26:
89
+ _context.next = 15;
90
+ break;
91
+ case 28:
92
+ case "end":
93
+ return _context.stop();
94
+ }
95
+ }, _callee, this);
96
+ }));
97
+ function applyAllSearchDecorations(_x, _x2, _x3, _x4) {
98
+ return _applyAllSearchDecorations.apply(this, arguments);
99
+ }
100
+ return applyAllSearchDecorations;
101
+ }()
102
+ }, {
103
+ key: "updateDecorationsBetween",
104
+ value: function () {
105
+ var _updateDecorationsBetween = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(editorView, startPos, endPos) {
106
+ return _regenerator.default.wrap(function _callee2$(_context2) {
107
+ while (1) switch (_context2.prev = _context2.next) {
108
+ case 0:
109
+ _context2.next = 2;
110
+ return this.removeDecorationsBetween(editorView, startPos, endPos);
111
+ case 2:
112
+ _context2.next = 4;
113
+ return this.addDecorationsBetween(editorView, startPos, endPos);
114
+ case 4:
115
+ case "end":
116
+ return _context2.stop();
117
+ }
118
+ }, _callee2, this);
119
+ }));
120
+ function updateDecorationsBetween(_x5, _x6, _x7) {
121
+ return _updateDecorationsBetween.apply(this, arguments);
122
+ }
123
+ return updateDecorationsBetween;
124
+ }()
125
+ }, {
126
+ key: "addDecorationsBetween",
127
+ value: function () {
128
+ var _addDecorationsBetween = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(editorView, startPos, endPos) {
129
+ var _this = this;
130
+ var selection, _getPluginState, matches, decorationSet, matchesBetween, selectionMatch, selectionIndex;
131
+ return _regenerator.default.wrap(function _callee3$(_context3) {
132
+ while (1) switch (_context3.prev = _context3.next) {
133
+ case 0:
134
+ selection = editorView.state.selection;
135
+ _getPluginState = (0, _pluginFactory.getPluginState)(editorView.state), matches = _getPluginState.matches, decorationSet = _getPluginState.decorationSet;
136
+ if (!(matches.length === 0)) {
137
+ _context3.next = 4;
138
+ break;
139
+ }
140
+ return _context3.abrupt("return");
141
+ case 4:
142
+ matchesBetween = matches.filter(function (m) {
143
+ return m.start >= startPos && (endPos === undefined || m.start < endPos);
144
+ });
145
+ selectionMatch = matches.find(function (match) {
146
+ return match.start >= selection.from;
147
+ });
148
+ selectionIndex = matchesBetween.findIndex(function (match) {
149
+ return match === selectionMatch;
150
+ });
151
+ _context3.next = 9;
152
+ return this.batchRequests(function (counter) {
153
+ var matchesToDecorate = matchesBetween.slice(counter, counter + batchIncrement);
154
+ if (matchesToDecorate.length === 0) {
155
+ return false;
156
+ }
157
+ var useSelectionIndex = selectionIndex >= counter && selectionIndex < counter + batchIncrement;
158
+ if (selectionMatch && useSelectionIndex) {
159
+ var selectionMatchDecoration = (0, _index.findDecorationFromMatch)(decorationSet, selectionMatch);
160
+ if (selectionMatchDecoration) {
161
+ matchesToDecorate.splice(selectionIndex % batchIncrement, 1);
162
+ useSelectionIndex = false;
163
+ }
164
+ }
165
+ if (_this.addDecorations) {
166
+ _this.addDecorations((0, _index.createDecorations)(useSelectionIndex ? selectionIndex % batchIncrement : -1, matchesToDecorate));
167
+ }
168
+ }, {
169
+ increment: batchIncrement,
170
+ until: matchesBetween.length
171
+ });
172
+ case 9:
173
+ return _context3.abrupt("return", _context3.sent);
174
+ case 10:
175
+ case "end":
176
+ return _context3.stop();
177
+ }
178
+ }, _callee3, this);
179
+ }));
180
+ function addDecorationsBetween(_x8, _x9, _x10) {
181
+ return _addDecorationsBetween.apply(this, arguments);
182
+ }
183
+ return addDecorationsBetween;
184
+ }()
185
+ }, {
186
+ key: "removeDecorationsBetween",
187
+ value: function () {
188
+ var _removeDecorationsBetween = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(editorView, startPos, endPos) {
189
+ var _this2 = this;
190
+ var _getPluginState2, decorationSet, decorations;
191
+ return _regenerator.default.wrap(function _callee4$(_context4) {
192
+ while (1) switch (_context4.prev = _context4.next) {
193
+ case 0:
194
+ _getPluginState2 = (0, _pluginFactory.getPluginState)(editorView.state), decorationSet = _getPluginState2.decorationSet;
195
+ decorations = decorationSet.find(startPos, endPos);
196
+ if (!(decorations.length === 0)) {
197
+ _context4.next = 4;
198
+ break;
199
+ }
200
+ return _context4.abrupt("return");
201
+ case 4:
202
+ _context4.next = 6;
203
+ return this.batchRequests(function (counter) {
204
+ var decorationsToRemove = decorations.slice(counter, counter + batchIncrement);
205
+ if (decorationsToRemove.length === 0) {
206
+ return false;
207
+ }
208
+ // only get those decorations whose from >= startPos
209
+ for (var i = 0; i < decorationsToRemove.length; i++) {
210
+ if (decorationsToRemove[i].from >= startPos) {
211
+ break;
212
+ }
213
+ decorationsToRemove = decorationsToRemove.slice(1);
214
+ }
215
+ if (_this2.removeDecorations) {
216
+ _this2.removeDecorations(decorationsToRemove);
217
+ }
218
+ }, {
219
+ increment: batchIncrement,
220
+ until: decorations.length
221
+ });
222
+ case 6:
223
+ return _context4.abrupt("return", _context4.sent);
224
+ case 7:
225
+ case "end":
226
+ return _context4.stop();
227
+ }
228
+ }, _callee4, this);
229
+ }));
230
+ function removeDecorationsBetween(_x11, _x12, _x13) {
231
+ return _removeDecorationsBetween.apply(this, arguments);
232
+ }
233
+ return removeDecorationsBetween;
234
+ }()
235
+ /**
236
+ * Calculates Prosemirror start and end positions we want to apply the decorations
237
+ * between
238
+ * Also calculates the positions the are the start and end of the user's viewport
239
+ * so we can apply decorations there first and work outwards
240
+ */
241
+ }, {
242
+ key: "calcDecorationPositions",
243
+ value: function calcDecorationPositions(editorView, containerElement, pmElement) {
244
+ var containerRect = containerElement.getBoundingClientRect();
245
+ var pmRect = pmElement.getBoundingClientRect();
246
+ var viewportStartPos = this.getStartPos(editorView, 0, pmRect.left);
247
+ var viewportEndPos = this.getEndPos(editorView, containerRect.top + containerRect.height, pmRect.left);
248
+ return {
249
+ viewportStartPos: viewportStartPos,
250
+ viewportEndPos: viewportEndPos,
251
+ startPos: 1,
252
+ endPos: editorView.state.doc.nodeSize
253
+ };
254
+ }
255
+ }, {
256
+ key: "getStartPos",
257
+ value: function getStartPos(editorView, y, x) {
258
+ var startPos = editorView.posAtCoords({
259
+ top: y,
260
+ left: x
261
+ });
262
+ return startPos ? startPos.pos : 1;
263
+ }
264
+ }, {
265
+ key: "getEndPos",
266
+ value: function getEndPos(editorView, y, x) {
267
+ var maxPos = editorView.state.doc.nodeSize;
268
+ var endPos = editorView.posAtCoords({
269
+ top: y,
270
+ left: x
271
+ });
272
+ return endPos ? endPos.pos : maxPos;
273
+ }
274
+
275
+ /**
276
+ * Util to batch function calls by animation frames
277
+ * A counter will start at 0 and increment by provided value until reaches limit
278
+ * Passed in fn receives the counter as a param, return false to skip waiting
279
+ * for the animation frame for the next call
280
+ */
281
+ }, {
282
+ key: "batchRequests",
283
+ value: function batchRequests(fn, opts) {
284
+ var _this3 = this;
285
+ var counter = 0;
286
+ var increment = opts.increment,
287
+ until = opts.until;
288
+ return new Promise(function (resolve) {
289
+ var batchedFn = function batchedFn() {
290
+ var result = fn(counter);
291
+ while (result === false && counter < until) {
292
+ counter += increment;
293
+ result = fn(counter);
294
+ }
295
+ if (counter < until) {
296
+ counter += increment;
297
+ _this3.rafId = requestAnimationFrame(batchedFn);
298
+ } else {
299
+ _this3.rafId = undefined;
300
+ resolve();
301
+ }
302
+ };
303
+ _this3.rafId = requestAnimationFrame(batchedFn);
304
+ });
305
+ }
306
+ }]);
307
+ return BatchDecorations;
308
+ }();
309
+ var batchDecorations = new BatchDecorations();
310
+ var _default = exports.default = batchDecorations;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.withScrollIntoView = void 0;
7
+ var withScrollIntoView = exports.withScrollIntoView = function withScrollIntoView(command) {
8
+ return function (state, dispatch, view) {
9
+ return command(state, function (tr) {
10
+ tr.scrollIntoView();
11
+ if (dispatch) {
12
+ dispatch(tr);
13
+ }
14
+ }, view);
15
+ };
16
+ };
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.findLostAdjacentDecorations = exports.findIndexBeforePosition = exports.findDecorationFromMatch = exports.createDecorations = exports.createDecoration = void 0;
7
+ exports.findMatches = findMatches;
8
+ exports.findSearchIndex = findSearchIndex;
9
+ exports.getSelectedText = getSelectedText;
10
+ exports.removeMatchesFromSet = exports.removeDecorationsFromSet = exports.prevIndex = exports.nextIndex = exports.isMatchAffectedByStep = exports.getSelectionForMatch = void 0;
11
+ var _state = require("@atlaskit/editor-prosemirror/state");
12
+ var _view = require("@atlaskit/editor-prosemirror/view");
13
+ var _styles = require("../styles");
14
+ function getSelectedText(selection) {
15
+ var text = '';
16
+ var selectedContent = selection.content().content;
17
+ for (var i = 0; i < selectedContent.childCount; i++) {
18
+ text += selectedContent.child(i).textContent;
19
+ }
20
+ return text;
21
+ }
22
+ var createDecorations = exports.createDecorations = function createDecorations(selectedIndex, matches) {
23
+ return matches.map(function (_ref, i) {
24
+ var start = _ref.start,
25
+ end = _ref.end;
26
+ return createDecoration(start, end, i === selectedIndex);
27
+ });
28
+ };
29
+ var createDecoration = exports.createDecoration = function createDecoration(start, end, isSelected) {
30
+ var className = _styles.searchMatchClass;
31
+ if (isSelected) {
32
+ className += " ".concat(_styles.selectedSearchMatchClass);
33
+ }
34
+ return _view.Decoration.inline(start, end, {
35
+ class: className
36
+ });
37
+ };
38
+ function findMatches(content, searchText, shouldMatchCase) {
39
+ var contentIndex = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
40
+ var matches = [];
41
+ var searchTextLength = searchText.length;
42
+ var textGrouping = null;
43
+ var collectMatch = function collectMatch(textGrouping) {
44
+ if (!textGrouping) {
45
+ return;
46
+ }
47
+ var text = textGrouping.text,
48
+ relativePos = textGrouping.pos;
49
+ var pos = contentIndex + relativePos;
50
+ if (!shouldMatchCase) {
51
+ searchText = searchText.toLowerCase();
52
+ text = text.toLowerCase();
53
+ }
54
+ var index = text.indexOf(searchText);
55
+ while (index !== -1) {
56
+ // Find the next substring from the end of the first, so that they don't overlap
57
+ var end = index + searchTextLength;
58
+ // Add the substring index to the position of the node
59
+ matches.push({
60
+ start: pos + index,
61
+ end: pos + end
62
+ });
63
+ index = text.indexOf(searchText, end);
64
+ }
65
+ };
66
+ if (searchTextLength > 0) {
67
+ content.descendants(function (node, pos) {
68
+ if (node.isText) {
69
+ if (textGrouping === null) {
70
+ textGrouping = {
71
+ text: node.text,
72
+ pos: pos
73
+ };
74
+ } else {
75
+ textGrouping.text = textGrouping.text + node.text;
76
+ }
77
+ } else {
78
+ collectMatch(textGrouping);
79
+ textGrouping = null;
80
+ }
81
+ });
82
+ // if there's a dangling text grouping and no non-text node to trigger collectMatch, manually collectMatch
83
+ if (textGrouping) {
84
+ collectMatch(textGrouping);
85
+ }
86
+ }
87
+ return matches;
88
+ }
89
+
90
+ /**
91
+ * Finds index of first item in matches array that comes after user's cursor pos.
92
+ * If `backward` is `true`, finds index of first item that comes before instead.
93
+ */
94
+ function findSearchIndex(selectionPos, matches) {
95
+ var backward = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
96
+ if (backward) {
97
+ var matchIndex = matches.findIndex(function (match) {
98
+ return match.start >= selectionPos;
99
+ }) - 1;
100
+ if (matchIndex < 0) {
101
+ matchIndex = matches.length - 1; // wrap around from the end
102
+ }
103
+
104
+ return matchIndex;
105
+ }
106
+ return Math.max(matches.findIndex(function (match) {
107
+ return match.start >= selectionPos;
108
+ }), 0);
109
+ }
110
+ var nextIndex = exports.nextIndex = function nextIndex(currentIndex, total) {
111
+ return (currentIndex + 1) % total;
112
+ };
113
+ var prevIndex = exports.prevIndex = function prevIndex(currentIndex, total) {
114
+ return (currentIndex - 1 + total) % total;
115
+ };
116
+ var getSelectionForMatch = exports.getSelectionForMatch = function getSelectionForMatch(selection, doc, index, matches) {
117
+ var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
118
+ if (matches[index]) {
119
+ return _state.TextSelection.create(doc, matches[index].start + offset);
120
+ }
121
+ return selection;
122
+ };
123
+ var findDecorationFromMatch = exports.findDecorationFromMatch = function findDecorationFromMatch(decorationSet, match) {
124
+ if (!match) {
125
+ return;
126
+ }
127
+ var decorations = decorationSet.find(match.start, match.end);
128
+ return decorations.length ? decorations.find(
129
+ // decorationSet.find() returns any decorations that touch the specifided
130
+ // positions, but we want to be stricter
131
+ function (decoration) {
132
+ return decoration.from === match.start && decoration.to === match.end;
133
+ }) : undefined;
134
+ };
135
+ var removeDecorationsFromSet = exports.removeDecorationsFromSet = function removeDecorationsFromSet(decorationSet, decorationsToRemove, doc) {
136
+ var prevDecorations = decorationSet.find();
137
+
138
+ // it is essential that we copy the decorations otherwise in some rare cases
139
+ // prosemirror-view will update our decorationsToRemove array to contain nulls
140
+ // instead of Decorations which ruins our check for lost decorations below
141
+ decorationSet = decorationSet.remove(decorationsToRemove.map(function (decoration) {
142
+ return (
143
+ // copy exists but isn't on the type definition
144
+ decoration.copy(decoration.from, decoration.to)
145
+ );
146
+ }));
147
+ var newDecorations = decorationSet.find();
148
+
149
+ // there is a bug in prosemirror-view where it can't cope with deleting inline
150
+ // decorations from a set in some cases (where there are multiple levels of nested
151
+ // children arrays), and it deletes more decorations than it should
152
+ // todo: ticket link
153
+ var lostDecorations = findLostAdjacentDecorations(decorationsToRemove, prevDecorations, newDecorations);
154
+ if (lostDecorations.length > 0) {
155
+ decorationSet = decorationSet.add(doc, lostDecorations);
156
+ }
157
+ return decorationSet;
158
+ };
159
+ var removeMatchesFromSet = exports.removeMatchesFromSet = function removeMatchesFromSet(decorationSet, matches, doc) {
160
+ var decorationsToRemove = matches.filter(function (match) {
161
+ return !!match;
162
+ }).map(function (match) {
163
+ return findDecorationFromMatch(decorationSet, match);
164
+ });
165
+ decorationsToRemove.forEach(function (decoration) {
166
+ if (decoration) {
167
+ decorationSet = removeDecorationsFromSet(decorationSet, [decoration], doc);
168
+ }
169
+ });
170
+ return decorationSet;
171
+ };
172
+
173
+ /**
174
+ * Finds decorations in prevDecorations that are not in newDecorations or decorationsToRemove
175
+ * These decorations have been lost by Prosemirror during an over eager decoration removal
176
+ * We need to be smart to cope with thousands of decorations without crashing everything
177
+ */
178
+ var findLostAdjacentDecorations = exports.findLostAdjacentDecorations = function findLostAdjacentDecorations(decorationsToRemove, prevDecorations, newDecorations) {
179
+ var lostDecorations = [];
180
+ if (prevDecorations.length - decorationsToRemove.length > newDecorations.length) {
181
+ var position = decorationsToRemove.length > 0 ? decorationsToRemove[0].from : 0;
182
+ var prevDecorationsStartIdx = findIndexBeforePosition(prevDecorations, position);
183
+ var newDecorationsStartIdx = findIndexBeforePosition(newDecorations, position);
184
+ var startIdx = Math.min(prevDecorationsStartIdx, newDecorationsStartIdx);
185
+ var prevDecorationsToCheck = prevDecorations.slice(startIdx);
186
+ var newDecorationsToCheck = newDecorations.slice(startIdx);
187
+ var uniqueInPrev = [];
188
+ var numToFind = prevDecorationsToCheck.length - newDecorationsToCheck.length;
189
+ var foundAll = false;
190
+ var newDecorationsIdxOffset = 0;
191
+ var _loop = function _loop() {
192
+ var prevDecoration = prevDecorationsToCheck[i];
193
+ // this was a legit removal, skip and continue
194
+ if (decorationsToRemove.find(function (decoration) {
195
+ return decoration.from === prevDecoration.from;
196
+ })) {
197
+ newDecorationsIdxOffset -= 1;
198
+ return 0; // continue
199
+ }
200
+ var j = i + newDecorationsIdxOffset;
201
+
202
+ // this is a lost decoration
203
+ if (j >= newDecorationsToCheck.length) {
204
+ uniqueInPrev.push(prevDecoration);
205
+ if (uniqueInPrev.length === numToFind) {
206
+ foundAll = true;
207
+ }
208
+ }
209
+ for (; j < newDecorationsToCheck.length; j++) {
210
+ var newDecoration = newDecorationsToCheck[j];
211
+
212
+ // decoration found in both arrays, skip and continue
213
+ if (prevDecoration.from === newDecoration.from) {
214
+ break;
215
+ }
216
+
217
+ // this is a lost decoration
218
+ if (newDecoration.from > prevDecoration.from || j === newDecorationsToCheck.length - 1) {
219
+ uniqueInPrev.push(prevDecoration);
220
+ newDecorationsIdxOffset -= 1;
221
+ if (uniqueInPrev.length === numToFind) {
222
+ foundAll = true;
223
+ }
224
+ break;
225
+ }
226
+ }
227
+ if (foundAll) {
228
+ return 1; // break
229
+ }
230
+ },
231
+ _ret;
232
+ for (var i = 0; i < prevDecorationsToCheck.length; i++) {
233
+ _ret = _loop();
234
+ if (_ret === 0) continue;
235
+ if (_ret === 1) break;
236
+ }
237
+
238
+ // make sure we ignore any that we wanted to delete
239
+ lostDecorations = uniqueInPrev.filter(function (decoration) {
240
+ return !decorationsToRemove.find(function (decorationToRemove) {
241
+ return decoration.from === decorationToRemove.from;
242
+ });
243
+ });
244
+ }
245
+ return lostDecorations;
246
+ };
247
+
248
+ /**
249
+ * Searches through array in bumps of 100 to return the index of the first
250
+ * decoration whose 'from' value is before or equal to the position
251
+ */
252
+ var findIndexBeforePosition = exports.findIndexBeforePosition = function findIndexBeforePosition(items, position) {
253
+ // jump in batches to cope with arrays with thousands of decorations
254
+ var increment = 100;
255
+ var index = 0;
256
+ for (var i = items.length - 1; i >= 0; i -= increment) {
257
+ if (items[i].from < position) {
258
+ // now we have found the 100 range, we can narrow it down to exact index
259
+ index = i;
260
+ for (var j = i; j <= items.length - 1; j++) {
261
+ if (items[j].from <= position) {
262
+ index = j;
263
+ } else {
264
+ break;
265
+ }
266
+ }
267
+ break;
268
+ }
269
+ if (i < 100 && i > 0) {
270
+ i = 100;
271
+ }
272
+ }
273
+ return index;
274
+ };
275
+
276
+ /**
277
+ * Determines whether a find/replace text Match will be changed as a result
278
+ * of a Step modification to the document. This is evaluated by checking
279
+ * both mapped and unmapped versions of the Step as in different cases the
280
+ * matches will match.
281
+ *
282
+ * **Note:** Match state received here is after step has been applied.
283
+ */
284
+ var isMatchAffectedByStep = exports.isMatchAffectedByStep = function isMatchAffectedByStep(match, step, tr) {
285
+ var from = step.from,
286
+ to = step.to,
287
+ slice = step.slice;
288
+ var sliceSize = slice.content.size;
289
+ return from + sliceSize >= match.start && to - sliceSize <= match.end || tr.mapping.map(from) + sliceSize >= match.start && tr.mapping.map(to) - sliceSize <= match.end;
290
+ };