jodit 4.14.2 → 4.14.3
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 +21 -0
- package/es2015/jodit.css +1 -1
- package/es2015/jodit.fat.min.js +7 -7
- package/es2015/jodit.js +469 -313
- package/es2015/jodit.min.js +5 -5
- package/es2015/plugins/debug/debug.css +1 -1
- package/es2015/plugins/debug/debug.js +1 -1
- package/es2015/plugins/debug/debug.min.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2018/jodit.fat.min.js +7 -7
- package/es2018/jodit.min.js +5 -5
- package/es2018/plugins/debug/debug.min.js +1 -1
- package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021/jodit.css +1 -1
- package/es2021/jodit.fat.min.js +9 -9
- package/es2021/jodit.js +456 -304
- package/es2021/jodit.min.js +6 -6
- package/es2021/plugins/debug/debug.css +1 -1
- package/es2021/plugins/debug/debug.js +1 -1
- package/es2021/plugins/debug/debug.min.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es2021.en/jodit.css +1 -1
- package/es2021.en/jodit.fat.min.js +5 -5
- package/es2021.en/jodit.js +395 -251
- package/es2021.en/jodit.min.js +5 -5
- package/es2021.en/plugins/debug/debug.css +1 -1
- package/es2021.en/plugins/debug/debug.js +1 -1
- package/es2021.en/plugins/debug/debug.min.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/jodit.css +2 -2
- package/es5/jodit.fat.min.js +2 -2
- package/es5/jodit.js +701 -381
- package/es5/jodit.min.css +2 -2
- package/es5/jodit.min.js +2 -2
- package/es5/plugins/debug/debug.css +1 -1
- package/es5/plugins/debug/debug.js +1 -1
- package/es5/plugins/debug/debug.min.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
- package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
- package/es5/polyfills.fat.min.js +1 -1
- package/es5/polyfills.js +1 -1
- package/es5/polyfills.min.js +1 -1
- package/esm/core/constants.js +1 -1
- package/esm/core/selection/helpers/index.js +5 -2
- package/esm/core/selection/selection.d.ts +8 -5
- package/esm/core/selection/selection.js +267 -159
- package/esm/core/selection/style/api/extract.js +1 -3
- package/esm/core/selection/style/api/is-same-attributes.js +5 -2
- package/esm/core/selection/style/api/toggle-attributes.js +27 -10
- package/esm/core/selection/style/api/unwrap-children.js +39 -33
- package/esm/core/selection/style/apply-style.js +23 -25
- package/esm/core/selection/style/commit-style.js +3 -0
- package/esm/core/selection/style/transactions.js +2 -1
- package/esm/langs/az.d.ts +223 -0
- package/esm/langs/az.js +240 -0
- package/esm/languages.js +2 -0
- package/esm/modules/history/snapshot.js +45 -20
- package/esm/types/style.d.ts +2 -2
- package/esm/types/types.d.ts +3 -0
- package/package.json +1 -1
- package/types/core/selection/selection.d.ts +8 -5
- package/types/langs/az.d.ts +223 -0
- package/types/types/style.d.ts +2 -2
- package/types/types/types.d.ts +3 -0
|
@@ -27,6 +27,7 @@ import { cursorInTheEdgeOfString, findCorrectCurrentNode } from "./helpers/index
|
|
|
27
27
|
export class Selection {
|
|
28
28
|
constructor(jodit) {
|
|
29
29
|
this.jodit = jodit;
|
|
30
|
+
this.__fakeSelections = new WeakMap();
|
|
30
31
|
jodit.e.on('removeMarkers', () => {
|
|
31
32
|
this.removeMarkers();
|
|
32
33
|
});
|
|
@@ -85,8 +86,15 @@ export class Selection {
|
|
|
85
86
|
*/
|
|
86
87
|
get isInsideArea() {
|
|
87
88
|
const { sel } = this;
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
if (!(sel === null || sel === void 0 ? void 0 : sel.rangeCount)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
for (let i = 0; i < sel.rangeCount; i += 1) {
|
|
93
|
+
if (!Dom.isOrContains(this.area, sel.getRangeAt(i).commonAncestorContainer)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
90
98
|
}
|
|
91
99
|
/**
|
|
92
100
|
* Return current selection object
|
|
@@ -106,8 +114,11 @@ export class Selection {
|
|
|
106
114
|
const sel = this.sel, current = this.current();
|
|
107
115
|
if (sel && current) {
|
|
108
116
|
for (let i = 0; i < sel.rangeCount; i += 1) {
|
|
109
|
-
sel.getRangeAt(i)
|
|
110
|
-
|
|
117
|
+
const range = sel.getRangeAt(i);
|
|
118
|
+
if (Dom.isOrContains(this.area, range.commonAncestorContainer)) {
|
|
119
|
+
range.deleteContents();
|
|
120
|
+
range.collapse(true);
|
|
121
|
+
}
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
}
|
|
@@ -138,28 +149,31 @@ export class Selection {
|
|
|
138
149
|
* @returns false - Something went wrong
|
|
139
150
|
*/
|
|
140
151
|
insertCursorAtPoint(x, y) {
|
|
141
|
-
|
|
152
|
+
var _a, _b, _c, _d;
|
|
142
153
|
try {
|
|
143
|
-
const
|
|
144
|
-
(()
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
154
|
+
const range = this.createRange();
|
|
155
|
+
const position = (_b = (_a = this.doc).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y);
|
|
156
|
+
const caret = position
|
|
157
|
+
? null
|
|
158
|
+
: (_d = (_c = this.doc).caretRangeFromPoint) === null || _d === void 0 ? void 0 : _d.call(_c, x, y);
|
|
159
|
+
if (position) {
|
|
160
|
+
range.setStart(position.offsetNode, position.offset);
|
|
161
|
+
}
|
|
162
|
+
else if (caret) {
|
|
163
|
+
range.setStart(caret.startContainer, caret.startOffset);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (!Dom.isOrContains(this.area, range.startContainer)) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
range.collapse(true);
|
|
172
|
+
this.removeMarkers();
|
|
173
|
+
this.selectRange(range);
|
|
160
174
|
return true;
|
|
161
175
|
}
|
|
162
|
-
catch (
|
|
176
|
+
catch (_e) { }
|
|
163
177
|
return false;
|
|
164
178
|
}
|
|
165
179
|
/**
|
|
@@ -217,89 +231,131 @@ export class Selection {
|
|
|
217
231
|
* Restores user selections using marker invisible elements in the DOM.
|
|
218
232
|
*/
|
|
219
233
|
restore() {
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
var _a, _b;
|
|
235
|
+
const markers = this.markers;
|
|
236
|
+
const byId = new Map(markers.map(marker => [marker.id, marker]));
|
|
237
|
+
const ranges = [];
|
|
238
|
+
let backward = false;
|
|
239
|
+
for (let i = 0; i < markers.length; i += 1) {
|
|
240
|
+
const start = markers[i];
|
|
241
|
+
if (attr(start, 'data-' + consts.MARKER_CLASS) !== 'start') {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
backward || (backward = attr(start, 'data-selection-backward') === 'true');
|
|
245
|
+
const endId = attr(start, 'data-selection-end');
|
|
246
|
+
let end = endId ? byId.get(endId) : undefined;
|
|
247
|
+
if (!endId &&
|
|
248
|
+
markers[i + 1] &&
|
|
249
|
+
attr(markers[i + 1], 'data-' + consts.MARKER_CLASS) === 'end') {
|
|
250
|
+
end = markers[i + 1];
|
|
251
|
+
}
|
|
252
|
+
const range = this.createRange();
|
|
253
|
+
if (end) {
|
|
254
|
+
range.setStartAfter(start);
|
|
255
|
+
range.setEndBefore(end);
|
|
234
256
|
}
|
|
235
257
|
else {
|
|
236
|
-
|
|
258
|
+
const previous = start.previousSibling;
|
|
259
|
+
if (Dom.isText(previous)) {
|
|
260
|
+
range.setStart(previous, (_b = (_a = previous.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
range.setStartBefore(start);
|
|
264
|
+
}
|
|
265
|
+
range.collapse(true);
|
|
237
266
|
}
|
|
238
|
-
|
|
239
|
-
range.collapse(true);
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
range.setStartAfter(start);
|
|
243
|
-
Dom.safeRemove(start);
|
|
244
|
-
range.setEndBefore(end);
|
|
245
|
-
Dom.safeRemove(end);
|
|
267
|
+
ranges.push(range);
|
|
246
268
|
}
|
|
247
|
-
|
|
248
|
-
|
|
269
|
+
Dom.safeRemove(...markers);
|
|
270
|
+
if (ranges.length) {
|
|
271
|
+
this.__selectRanges(ranges, backward);
|
|
249
272
|
}
|
|
250
273
|
}
|
|
274
|
+
__isBackward() {
|
|
275
|
+
const sel = this.sel;
|
|
276
|
+
return Boolean(sel &&
|
|
277
|
+
sel.rangeCount === 1 &&
|
|
278
|
+
!sel.isCollapsed &&
|
|
279
|
+
sel.anchorNode === sel.getRangeAt(0).endContainer &&
|
|
280
|
+
sel.anchorOffset === sel.getRangeAt(0).endOffset);
|
|
281
|
+
}
|
|
282
|
+
__ranges() {
|
|
283
|
+
const sel = this.sel;
|
|
284
|
+
return sel
|
|
285
|
+
? Array.from({ length: sel.rangeCount }, (_, i) => sel.getRangeAt(i).cloneRange())
|
|
286
|
+
: [];
|
|
287
|
+
}
|
|
251
288
|
/**
|
|
252
289
|
* Inserts invisible fake nodes on the boundaries of the current selection
|
|
253
|
-
* and returns
|
|
290
|
+
* and returns the first pair as a restoration handle for all ranges. Unlike [[Select.save]] the selection stays valid while
|
|
254
291
|
* the DOM around it is being modified. Restore it later with [[Select.restoreFakes]].
|
|
255
292
|
*/
|
|
256
293
|
fakes() {
|
|
257
|
-
|
|
258
|
-
if (!sel || !sel.rangeCount) {
|
|
294
|
+
if (!this.isInsideArea) {
|
|
259
295
|
return [];
|
|
260
296
|
}
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
297
|
+
const backward = this.__isBackward();
|
|
298
|
+
const ranges = this.__ranges();
|
|
299
|
+
const pairs = ranges.map(range => {
|
|
300
|
+
const collapsed = range.collapsed;
|
|
301
|
+
const left = range.cloneRange();
|
|
302
|
+
left.collapse(true);
|
|
303
|
+
const fakeLeft = this.j.createInside.fake();
|
|
304
|
+
Dom.safeInsertNode(left, fakeLeft);
|
|
305
|
+
range.setStartBefore(fakeLeft);
|
|
306
|
+
const pair = [fakeLeft];
|
|
307
|
+
if (!collapsed) {
|
|
308
|
+
const right = range.cloneRange();
|
|
309
|
+
right.collapse(false);
|
|
310
|
+
const fakeRight = this.j.createInside.fake();
|
|
311
|
+
Dom.safeInsertNode(right, fakeRight);
|
|
312
|
+
range.setEndAfter(fakeRight);
|
|
313
|
+
pair.push(fakeRight);
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
range.collapse(true);
|
|
317
|
+
}
|
|
318
|
+
return pair;
|
|
319
|
+
});
|
|
320
|
+
this.__fakeSelections.set(pairs[0][0], { pairs, backward });
|
|
321
|
+
this.__selectRanges(ranges, backward);
|
|
322
|
+
return pairs[0];
|
|
279
323
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Restores the selection previously saved with [[Select.fakes]]
|
|
282
|
-
* and removes the fake nodes (disconnected fakes are ignored).
|
|
283
|
-
*/
|
|
324
|
+
/** Restore all ranges associated with the returned fake pair. */
|
|
284
325
|
restoreFakes(fakes) {
|
|
285
|
-
var _a, _b, _c
|
|
286
|
-
|
|
287
|
-
if (!nodes.length) {
|
|
326
|
+
var _a, _b, _c;
|
|
327
|
+
if (!fakes.length) {
|
|
288
328
|
return;
|
|
289
329
|
}
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
range.setEndBefore(fakeRight);
|
|
330
|
+
const saved = this.__fakeSelections.get(fakes[0]);
|
|
331
|
+
this.__fakeSelections.delete(fakes[0]);
|
|
332
|
+
if (this.j.isInDestruct) {
|
|
333
|
+
return;
|
|
295
334
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
Dom.
|
|
335
|
+
const ranges = [];
|
|
336
|
+
for (const pair of (_a = saved === null || saved === void 0 ? void 0 : saved.pairs) !== null && _a !== void 0 ? _a : [fakes]) {
|
|
337
|
+
const nodes = pair.filter(n => n.isConnected && Dom.isOrContains(this.area, n, true));
|
|
338
|
+
if (!nodes.length) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const [left, right] = nodes;
|
|
342
|
+
const range = this.createRange();
|
|
343
|
+
range.setStartAfter(left);
|
|
344
|
+
if (right) {
|
|
345
|
+
range.setEndBefore(right);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
range.collapse(true);
|
|
349
|
+
}
|
|
350
|
+
for (const node of nodes) {
|
|
351
|
+
if (((_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.firstChild) !== ((_c = node.parentNode) === null || _c === void 0 ? void 0 : _c.lastChild)) {
|
|
352
|
+
Dom.safeRemove(node);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
ranges.push(range);
|
|
299
356
|
}
|
|
300
|
-
if (
|
|
301
|
-
(
|
|
302
|
-
Dom.safeRemove(fakeRight);
|
|
357
|
+
if (ranges.length) {
|
|
358
|
+
this.__selectRanges(ranges, saved === null || saved === void 0 ? void 0 : saved.backward);
|
|
303
359
|
}
|
|
304
360
|
}
|
|
305
361
|
/**
|
|
@@ -314,9 +370,15 @@ export class Selection {
|
|
|
314
370
|
if (!sel || !sel.rangeCount) {
|
|
315
371
|
return [];
|
|
316
372
|
}
|
|
373
|
+
const backward = this.__isBackward();
|
|
317
374
|
const info = [], length = sel.rangeCount, ranges = [];
|
|
318
375
|
for (let i = 0; i < length; i += 1) {
|
|
319
376
|
ranges[i] = sel.getRangeAt(i);
|
|
377
|
+
if (!Dom.isOrContains(this.area, ranges[i].commonAncestorContainer)) {
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
for (let i = 0; i < length; i += 1) {
|
|
320
382
|
if (ranges[i].collapsed) {
|
|
321
383
|
const start = this.marker(true, ranges[i]);
|
|
322
384
|
info[i] = {
|
|
@@ -328,6 +390,12 @@ export class Selection {
|
|
|
328
390
|
else {
|
|
329
391
|
const start = this.marker(true, ranges[i]);
|
|
330
392
|
const end = this.marker(false, ranges[i]);
|
|
393
|
+
if (length > 1) {
|
|
394
|
+
attr(start, 'data-selection-end', end.id);
|
|
395
|
+
}
|
|
396
|
+
if (backward) {
|
|
397
|
+
attr(start, 'data-selection-backward', 'true');
|
|
398
|
+
}
|
|
331
399
|
info[i] = {
|
|
332
400
|
startId: start.id,
|
|
333
401
|
endId: end.id,
|
|
@@ -340,7 +408,7 @@ export class Selection {
|
|
|
340
408
|
if (!silent) {
|
|
341
409
|
sel.removeAllRanges();
|
|
342
410
|
for (let i = length - 1; i >= 0; --i) {
|
|
343
|
-
const startElm = this.
|
|
411
|
+
const startElm = this.area.querySelector('#' + info[i].startId);
|
|
344
412
|
if (!startElm) {
|
|
345
413
|
continue;
|
|
346
414
|
}
|
|
@@ -351,7 +419,7 @@ export class Selection {
|
|
|
351
419
|
else {
|
|
352
420
|
ranges[i].setStartBefore(startElm);
|
|
353
421
|
if (info[i].endId) {
|
|
354
|
-
const endElm = this.
|
|
422
|
+
const endElm = this.area.querySelector('#' + info[i].endId);
|
|
355
423
|
if (endElm) {
|
|
356
424
|
ranges[i].setEndAfter(endElm);
|
|
357
425
|
}
|
|
@@ -433,6 +501,9 @@ export class Selection {
|
|
|
433
501
|
const range = sel.getRangeAt(0);
|
|
434
502
|
let node = range.startContainer;
|
|
435
503
|
let rightMode = false;
|
|
504
|
+
if (!Dom.isOrContains(this.area, node)) {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
436
507
|
const child = (nd) => rightMode ? nd.lastChild : nd.firstChild;
|
|
437
508
|
if (Dom.isTag(node, 'br') && sel.isCollapsed) {
|
|
438
509
|
return node;
|
|
@@ -457,8 +528,11 @@ export class Selection {
|
|
|
457
528
|
*/
|
|
458
529
|
insertNode(node, insertCursorAfter = true, fireChange = true) {
|
|
459
530
|
this.errorNode(node);
|
|
460
|
-
const child = Dom.isFragment(node) ? node.lastChild : node;
|
|
461
531
|
this.j.e.fire('safeHTML', node);
|
|
532
|
+
let child = Dom.isFragment(node) ? node.lastChild : node;
|
|
533
|
+
if (!child || this.j.isInDestruct) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
462
536
|
if (!this.isFocused() && this.j.isEditorMode()) {
|
|
463
537
|
this.focus();
|
|
464
538
|
this.restore();
|
|
@@ -469,6 +543,10 @@ export class Selection {
|
|
|
469
543
|
this.j.execCommand('Delete');
|
|
470
544
|
}
|
|
471
545
|
this.j.e.fire('beforeInsertNode', node);
|
|
546
|
+
child = Dom.isFragment(node) ? node.lastChild : node;
|
|
547
|
+
if (!child || this.j.isInDestruct) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
472
550
|
if (sel && sel.rangeCount) {
|
|
473
551
|
const range = sel.getRangeAt(0);
|
|
474
552
|
const { firstChild } = node;
|
|
@@ -614,14 +692,22 @@ export class Selection {
|
|
|
614
692
|
/**
|
|
615
693
|
* Call callback for all selection node
|
|
616
694
|
*/
|
|
617
|
-
// eslint-disable-next-line complexity
|
|
618
695
|
eachSelection(callback) {
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
696
|
+
const seen = new Set();
|
|
697
|
+
for (const range of this.__ranges()) {
|
|
698
|
+
if (!Dom.isOrContains(this.area, range.commonAncestorContainer)) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
this.__eachRange(range, node => {
|
|
702
|
+
if (!seen.has(node)) {
|
|
703
|
+
seen.add(node);
|
|
704
|
+
callback(node);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
623
707
|
}
|
|
624
|
-
|
|
708
|
+
}
|
|
709
|
+
__eachRange(range, callback) {
|
|
710
|
+
var _a;
|
|
625
711
|
let root = range.commonAncestorContainer;
|
|
626
712
|
if (!Dom.isHTMLElement(root)) {
|
|
627
713
|
root = root.parentElement;
|
|
@@ -706,12 +792,16 @@ export class Selection {
|
|
|
706
792
|
*/
|
|
707
793
|
cursorInTheEdge(start, parentBlock, fake = null) {
|
|
708
794
|
const end = !start, sel = this.sel, range = (sel === null || sel === void 0 ? void 0 : sel.rangeCount) ? sel.getRangeAt(0) : null;
|
|
709
|
-
|
|
710
|
-
if (!range || !fake || !Dom.isOrContains(parentBlock, fake, true)) {
|
|
795
|
+
if (!range) {
|
|
711
796
|
return null;
|
|
712
797
|
}
|
|
713
798
|
const container = start ? range.startContainer : range.endContainer;
|
|
714
799
|
const offset = start ? range.startOffset : range.endOffset;
|
|
800
|
+
fake !== null && fake !== void 0 ? fake : (fake = container);
|
|
801
|
+
if (!Dom.isOrContains(parentBlock, container) ||
|
|
802
|
+
!Dom.isOrContains(parentBlock, fake)) {
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
715
805
|
const isSignificant = (elm) => Boolean(elm &&
|
|
716
806
|
!Dom.isTag(elm, 'br') &&
|
|
717
807
|
!Dom.isEmptyTextNode(elm) &&
|
|
@@ -725,14 +815,10 @@ export class Selection {
|
|
|
725
815
|
}
|
|
726
816
|
}
|
|
727
817
|
else {
|
|
728
|
-
const children =
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
else {
|
|
735
|
-
if (children.slice(0, offset).some(isSignificant)) {
|
|
818
|
+
const children = container.childNodes;
|
|
819
|
+
const limit = end ? children.length : offset;
|
|
820
|
+
for (let i = end ? offset : 0; i < limit; i += 1) {
|
|
821
|
+
if (isSignificant(children[i])) {
|
|
736
822
|
return false;
|
|
737
823
|
}
|
|
738
824
|
}
|
|
@@ -745,7 +831,7 @@ export class Selection {
|
|
|
745
831
|
continue;
|
|
746
832
|
}
|
|
747
833
|
next = nextOne;
|
|
748
|
-
if (
|
|
834
|
+
if (isSignificant(next)) {
|
|
749
835
|
return false;
|
|
750
836
|
}
|
|
751
837
|
}
|
|
@@ -783,7 +869,7 @@ export class Selection {
|
|
|
783
869
|
setCursorNearWith(node, inStart) {
|
|
784
870
|
var _a, _b;
|
|
785
871
|
this.errorNode(node);
|
|
786
|
-
if (!Dom.
|
|
872
|
+
if (!Dom.isOrContains(this.area, node, true)) {
|
|
787
873
|
throw error('Node element must be in editor');
|
|
788
874
|
}
|
|
789
875
|
const range = this.createRange();
|
|
@@ -854,13 +940,20 @@ export class Selection {
|
|
|
854
940
|
* Set range selection
|
|
855
941
|
*/
|
|
856
942
|
selectRange(range, focus = true) {
|
|
943
|
+
return this.__selectRanges([range], false, focus);
|
|
944
|
+
}
|
|
945
|
+
__selectRanges(ranges, backward = false, focus = true) {
|
|
857
946
|
const sel = this.sel;
|
|
858
947
|
if (focus && !this.isFocused() && this.j.e.current !== 'focus') {
|
|
859
948
|
this.focus();
|
|
860
949
|
}
|
|
861
950
|
if (sel) {
|
|
862
951
|
sel.removeAllRanges();
|
|
863
|
-
sel.addRange(range);
|
|
952
|
+
ranges.forEach(range => sel.addRange(range));
|
|
953
|
+
if (backward && ranges.length === 1) {
|
|
954
|
+
const range = ranges[0];
|
|
955
|
+
sel.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
|
|
956
|
+
}
|
|
864
957
|
}
|
|
865
958
|
/**
|
|
866
959
|
* Fired after change selection
|
|
@@ -879,7 +972,7 @@ export class Selection {
|
|
|
879
972
|
throw error('Node element must be in editor');
|
|
880
973
|
}
|
|
881
974
|
const range = this.createRange();
|
|
882
|
-
range[inward ? 'selectNodeContents' : 'selectNode'](node);
|
|
975
|
+
range[inward || node === this.area ? 'selectNodeContents' : 'selectNode'](node);
|
|
883
976
|
return this.selectRange(range);
|
|
884
977
|
}
|
|
885
978
|
/**
|
|
@@ -894,10 +987,8 @@ export class Selection {
|
|
|
894
987
|
get html() {
|
|
895
988
|
const sel = this.sel;
|
|
896
989
|
if (sel && sel.rangeCount > 0) {
|
|
897
|
-
const range = sel.getRangeAt(0);
|
|
898
|
-
const clonedSelection = range.cloneContents();
|
|
899
990
|
const div = this.j.createInside.div();
|
|
900
|
-
Dom.append(div,
|
|
991
|
+
this.__ranges().forEach(range => Dom.append(div, range.cloneContents()));
|
|
901
992
|
return div.innerHTML;
|
|
902
993
|
}
|
|
903
994
|
return '';
|
|
@@ -911,8 +1002,7 @@ export class Selection {
|
|
|
911
1002
|
* `nativeExecCommand('fontsize', false, '7')` trick which relied on the
|
|
912
1003
|
* browser to split the selection into `<font size="7">` fragments.
|
|
913
1004
|
*/
|
|
914
|
-
__wrapSelectionFragments() {
|
|
915
|
-
const range = this.range;
|
|
1005
|
+
__wrapSelectionFragments(range) {
|
|
916
1006
|
this.__splitSelectionBoundaries(range);
|
|
917
1007
|
let root = range.commonAncestorContainer;
|
|
918
1008
|
if (Dom.isText(root)) {
|
|
@@ -929,30 +1019,22 @@ export class Selection {
|
|
|
929
1019
|
* fully (not partially) selected.
|
|
930
1020
|
*/
|
|
931
1021
|
__splitSelectionBoundaries(range) {
|
|
932
|
-
var _a, _b, _c, _d
|
|
933
|
-
|
|
934
|
-
let { startOffset, endOffset } = range;
|
|
1022
|
+
var _a, _b, _c, _d;
|
|
1023
|
+
const { endContainer, endOffset } = range;
|
|
935
1024
|
if (Dom.isText(endContainer) &&
|
|
936
1025
|
endOffset > 0 &&
|
|
937
1026
|
endOffset < ((_b = (_a = endContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0)) {
|
|
938
1027
|
endContainer.splitText(endOffset);
|
|
939
|
-
endOffset = (_d = (_c = endContainer.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : endOffset;
|
|
940
1028
|
}
|
|
1029
|
+
const { startContainer, startOffset } = range;
|
|
941
1030
|
if (Dom.isText(startContainer) &&
|
|
942
1031
|
startOffset > 0 &&
|
|
943
|
-
startOffset < ((
|
|
1032
|
+
startOffset < ((_d = (_c = startContainer.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0)) {
|
|
944
1033
|
const middle = startContainer.splitText(startOffset);
|
|
945
|
-
//
|
|
946
|
-
//
|
|
947
|
-
|
|
948
|
-
endContainer = middle;
|
|
949
|
-
endOffset = (_h = (_g = middle.nodeValue) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0;
|
|
950
|
-
}
|
|
951
|
-
startContainer = middle;
|
|
952
|
-
startOffset = 0;
|
|
1034
|
+
// splitText updates the live range, including element end offsets.
|
|
1035
|
+
// Only the start at the split point needs to move to the new node.
|
|
1036
|
+
range.setStart(middle, 0);
|
|
953
1037
|
}
|
|
954
|
-
range.setStart(startContainer, startOffset);
|
|
955
|
-
range.setEnd(endContainer, endOffset);
|
|
956
1038
|
// Normalize text-edge boundaries (e.g. `(text, 0)` or `(text, length)`)
|
|
957
1039
|
// to the element level so that containment checks based on
|
|
958
1040
|
// `selectNode()` treat a fully selected text node as contained.
|
|
@@ -982,20 +1064,19 @@ export class Selection {
|
|
|
982
1064
|
* Collects the highest-level nodes that are completely inside the range,
|
|
983
1065
|
* descending into nodes that are only partially selected.
|
|
984
1066
|
*/
|
|
985
|
-
__collectContainedNodes(root, range) {
|
|
1067
|
+
__collectContainedNodes(root, range, scratch = this.createRange()) {
|
|
986
1068
|
const result = [];
|
|
987
1069
|
toArray(root.childNodes).forEach(child => {
|
|
988
|
-
if (this.__isFullyContained(range, child)) {
|
|
1070
|
+
if (this.__isFullyContained(range, child, scratch)) {
|
|
989
1071
|
result.push(child);
|
|
990
1072
|
}
|
|
991
1073
|
else if (child.childNodes.length && range.intersectsNode(child)) {
|
|
992
|
-
result.push(...this.__collectContainedNodes(child, range));
|
|
1074
|
+
result.push(...this.__collectContainedNodes(child, range, scratch));
|
|
993
1075
|
}
|
|
994
1076
|
});
|
|
995
1077
|
return result;
|
|
996
1078
|
}
|
|
997
|
-
__isFullyContained(range, node) {
|
|
998
|
-
const nodeRange = this.createRange();
|
|
1079
|
+
__isFullyContained(range, node, nodeRange) {
|
|
999
1080
|
nodeRange.selectNode(node);
|
|
1000
1081
|
return (range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
|
|
1001
1082
|
range.compareBoundaryPoints(Range.END_TO_END, nodeRange) >= 0);
|
|
@@ -1047,33 +1128,52 @@ export class Selection {
|
|
|
1047
1128
|
* Wrap all selected fragments inside Tag or apply some callback
|
|
1048
1129
|
*/
|
|
1049
1130
|
*wrapInTagGen(fakes) {
|
|
1131
|
+
var _a;
|
|
1132
|
+
if (((_a = this.sel) === null || _a === void 0 ? void 0 : _a.rangeCount) && !this.isInsideArea) {
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1050
1135
|
if (this.isCollapsed()) {
|
|
1051
1136
|
const font = this.jodit.createInside.element('font', INVISIBLE_SPACE);
|
|
1052
1137
|
this.insertNode(font, false, false);
|
|
1053
1138
|
if (fakes && fakes[0]) {
|
|
1054
1139
|
Dom.append(font, fakes[0]);
|
|
1055
1140
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1141
|
+
try {
|
|
1142
|
+
yield font;
|
|
1143
|
+
}
|
|
1144
|
+
finally {
|
|
1145
|
+
Dom.unwrap(font);
|
|
1146
|
+
}
|
|
1058
1147
|
return;
|
|
1059
1148
|
}
|
|
1060
|
-
const elms = this.__wrapSelectionFragments();
|
|
1061
|
-
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1149
|
+
const elms = this.__ranges().flatMap(range => this.__wrapSelectionFragments(range));
|
|
1150
|
+
try {
|
|
1151
|
+
for (const font of elms) {
|
|
1152
|
+
if (this.j.isInDestruct ||
|
|
1153
|
+
!Dom.isOrContains(this.area, font, true)) {
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
const { firstChild, lastChild } = font;
|
|
1157
|
+
if (firstChild &&
|
|
1158
|
+
firstChild === lastChild &&
|
|
1159
|
+
isMarker(firstChild)) {
|
|
1160
|
+
Dom.unwrap(font);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
if (firstChild && isMarker(firstChild)) {
|
|
1164
|
+
Dom.before(font, firstChild);
|
|
1165
|
+
}
|
|
1166
|
+
if (lastChild && isMarker(lastChild)) {
|
|
1167
|
+
Dom.after(font, lastChild);
|
|
1168
|
+
}
|
|
1169
|
+
yield font;
|
|
1066
1170
|
Dom.unwrap(font);
|
|
1067
|
-
continue;
|
|
1068
|
-
}
|
|
1069
|
-
if (firstChild && isMarker(firstChild)) {
|
|
1070
|
-
Dom.before(font, firstChild);
|
|
1071
|
-
}
|
|
1072
|
-
if (lastChild && isMarker(lastChild)) {
|
|
1073
|
-
Dom.after(font, lastChild);
|
|
1074
1171
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1172
|
+
}
|
|
1173
|
+
finally {
|
|
1174
|
+
// A callback can throw or stop iteration before later wrappers
|
|
1175
|
+
// have been visited. None of the temporary fonts should survive.
|
|
1176
|
+
elms.forEach(font => Dom.unwrap(font));
|
|
1077
1177
|
}
|
|
1078
1178
|
return;
|
|
1079
1179
|
}
|
|
@@ -1133,7 +1233,11 @@ export class Selection {
|
|
|
1133
1233
|
* Split selection on two parts: left and right
|
|
1134
1234
|
*/
|
|
1135
1235
|
splitSelection(currentBox, edge) {
|
|
1136
|
-
if (!this.isCollapsed()
|
|
1236
|
+
if (!this.isCollapsed() ||
|
|
1237
|
+
!this.isInsideArea ||
|
|
1238
|
+
!Dom.isOrContains(this.area, currentBox, true) ||
|
|
1239
|
+
!Dom.isOrContains(currentBox, this.range.startContainer) ||
|
|
1240
|
+
(edge && !Dom.isOrContains(currentBox, edge, true))) {
|
|
1137
1241
|
return null;
|
|
1138
1242
|
}
|
|
1139
1243
|
const leftRange = this.createRange();
|
|
@@ -1220,13 +1324,18 @@ export class Selection {
|
|
|
1220
1324
|
* becomes `<p>|<b>test</b>|</p>`)
|
|
1221
1325
|
*/
|
|
1222
1326
|
expandSelection() {
|
|
1223
|
-
if (this.isCollapsed()) {
|
|
1327
|
+
if (this.isCollapsed() || !this.isInsideArea) {
|
|
1224
1328
|
return this;
|
|
1225
1329
|
}
|
|
1226
|
-
const
|
|
1330
|
+
const backward = this.__isBackward();
|
|
1331
|
+
const ranges = this.__ranges().map(range => this.__expandRange(range));
|
|
1332
|
+
this.__selectRanges(ranges, backward);
|
|
1333
|
+
return this;
|
|
1334
|
+
}
|
|
1335
|
+
__expandRange(range) {
|
|
1227
1336
|
const c = range.cloneRange();
|
|
1228
1337
|
if (!Dom.isOrContains(this.j.editor, range.commonAncestorContainer, true)) {
|
|
1229
|
-
return
|
|
1338
|
+
return range;
|
|
1230
1339
|
}
|
|
1231
1340
|
const moveMaxEdgeFake = (start) => {
|
|
1232
1341
|
const fake = this.j.createInside.fake();
|
|
@@ -1270,12 +1379,11 @@ export class Selection {
|
|
|
1270
1379
|
}
|
|
1271
1380
|
}
|
|
1272
1381
|
}
|
|
1273
|
-
this.selectRange(c);
|
|
1274
1382
|
Dom.safeRemove(leftFake, rightFake);
|
|
1275
|
-
if (
|
|
1383
|
+
if (c.collapsed) {
|
|
1276
1384
|
throw error('Selection is collapsed');
|
|
1277
1385
|
}
|
|
1278
|
-
return
|
|
1386
|
+
return c;
|
|
1279
1387
|
}
|
|
1280
1388
|
}
|
|
1281
1389
|
__decorate([
|