@ntlab/ntjs-assets 2.83.0 → 2.84.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.
- package/assets/js/cdn.json +1 -1
- package/assets/js/tinymce/icons/default/icons.js +5 -0
- package/assets/js/tinymce/icons/default/icons.min.js +1 -1
- package/assets/js/tinymce/models/dom/model.js +5 -14
- package/assets/js/tinymce/models/dom/model.min.js +1 -1
- package/assets/js/tinymce/notices.txt +2 -2
- package/assets/js/tinymce/plugins/accordion/plugin.js +2 -5
- package/assets/js/tinymce/plugins/advlist/plugin.js +2 -2
- package/assets/js/tinymce/plugins/advlist/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/anchor/plugin.js +1 -1
- package/assets/js/tinymce/plugins/autolink/plugin.js +1 -2
- package/assets/js/tinymce/plugins/autoresize/plugin.js +1 -1
- package/assets/js/tinymce/plugins/autosave/plugin.js +1 -1
- package/assets/js/tinymce/plugins/charmap/plugin.js +1 -2
- package/assets/js/tinymce/plugins/code/plugin.js +3 -2
- package/assets/js/tinymce/plugins/code/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/codesample/plugin.js +3 -2
- package/assets/js/tinymce/plugins/codesample/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/directionality/plugin.js +2 -5
- package/assets/js/tinymce/plugins/emoticons/plugin.js +1 -3
- package/assets/js/tinymce/plugins/fullscreen/plugin.js +2 -5
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/bg-BG.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/fr-FR.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/he-IL.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/hu-HU.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/ko-KR.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/nb-NO.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/pt-BR.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/pt-PT.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/sl-SI.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/sv-SE.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/th-TH.js +93 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/zh-CN.js +87 -0
- package/assets/js/tinymce/plugins/help/js/i18n/keynav/zh-TW.js +93 -0
- package/assets/js/tinymce/plugins/help/plugin.js +3 -5
- package/assets/js/tinymce/plugins/help/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/image/plugin.js +14 -5
- package/assets/js/tinymce/plugins/image/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/importcss/plugin.js +1 -2
- package/assets/js/tinymce/plugins/insertdatetime/plugin.js +2 -1
- package/assets/js/tinymce/plugins/insertdatetime/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/link/plugin.js +1 -4
- package/assets/js/tinymce/plugins/lists/plugin.js +105 -2049
- package/assets/js/tinymce/plugins/lists/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/media/plugin.js +1 -3
- package/assets/js/tinymce/plugins/nonbreaking/plugin.js +1 -1
- package/assets/js/tinymce/plugins/pagebreak/plugin.js +1 -1
- package/assets/js/tinymce/plugins/preview/plugin.js +1 -1
- package/assets/js/tinymce/plugins/quickbars/plugin.js +1 -1
- package/assets/js/tinymce/plugins/save/plugin.js +1 -1
- package/assets/js/tinymce/plugins/searchreplace/plugin.js +1 -3
- package/assets/js/tinymce/plugins/table/plugin.js +2 -12
- package/assets/js/tinymce/plugins/table/plugin.min.js +1 -1
- package/assets/js/tinymce/plugins/visualblocks/plugin.js +1 -1
- package/assets/js/tinymce/plugins/visualchars/plugin.js +1 -2
- package/assets/js/tinymce/plugins/wordcount/plugin.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide/content.css +91 -0
- package/assets/js/tinymce/skins/ui/oxide/content.inline.css +91 -0
- package/assets/js/tinymce/skins/ui/oxide/content.inline.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide/content.inline.min.css +1 -1
- package/assets/js/tinymce/skins/ui/oxide/content.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide/content.min.css +1 -1
- package/assets/js/tinymce/skins/ui/oxide/skin.css +495 -70
- package/assets/js/tinymce/skins/ui/oxide/skin.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide/skin.min.css +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/content.css +91 -0
- package/assets/js/tinymce/skins/ui/oxide-dark/content.inline.css +91 -0
- package/assets/js/tinymce/skins/ui/oxide-dark/content.inline.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/content.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/content.min.css +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/skin.css +495 -70
- package/assets/js/tinymce/skins/ui/oxide-dark/skin.js +1 -1
- package/assets/js/tinymce/skins/ui/oxide-dark/skin.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/content.css +91 -0
- package/assets/js/tinymce/skins/ui/tinymce-5/content.inline.css +91 -0
- package/assets/js/tinymce/skins/ui/tinymce-5/content.inline.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/content.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/content.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/skin.css +495 -70
- package/assets/js/tinymce/skins/ui/tinymce-5/skin.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5/skin.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.css +91 -0
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.inline.css +91 -0
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/skin.css +495 -70
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/skin.js +1 -1
- package/assets/js/tinymce/skins/ui/tinymce-5-dark/skin.min.css +1 -1
- package/assets/js/tinymce/themes/silver/theme.js +483 -524
- package/assets/js/tinymce/themes/silver/theme.min.js +1 -1
- package/assets/js/tinymce/tinymce.js +5874 -3300
- package/assets/js/tinymce/tinymce.min.js +3 -4
- package/package.json +1 -1
|
@@ -1,52 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TinyMCE version
|
|
2
|
+
* TinyMCE version 8.0.0 (TBD)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
(function () {
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
var global
|
|
8
|
+
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (predicate(v, constructor.prototype)) {
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
// String-based fallback time
|
|
18
|
-
return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
const typeOf = (x) => {
|
|
22
|
-
const t = typeof x;
|
|
23
|
-
if (x === null) {
|
|
24
|
-
return 'null';
|
|
25
|
-
}
|
|
26
|
-
else if (t === 'object' && Array.isArray(x)) {
|
|
27
|
-
return 'array';
|
|
28
|
-
}
|
|
29
|
-
else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
|
|
30
|
-
return 'string';
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
return t;
|
|
10
|
+
const get = (editor) => ({
|
|
11
|
+
backspaceDelete: (isForward) => {
|
|
12
|
+
editor.execCommand('mceListBackspaceDelete', false, isForward);
|
|
34
13
|
}
|
|
35
|
-
};
|
|
36
|
-
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-wrapper-object-types */
|
|
37
17
|
const isSimpleType = (type) => (value) => typeof value === type;
|
|
38
|
-
const isString = isType$1('string');
|
|
39
|
-
const isObject = isType$1('object');
|
|
40
|
-
const isArray = isType$1('array');
|
|
41
|
-
const isBoolean = isSimpleType('boolean');
|
|
42
18
|
const isNullable = (a) => a === null || a === undefined;
|
|
43
19
|
const isNonNullable = (a) => !isNullable(a);
|
|
44
20
|
const isFunction = isSimpleType('function');
|
|
45
|
-
const isNumber = isSimpleType('number');
|
|
46
21
|
|
|
47
|
-
const noop = () => { };
|
|
48
|
-
/** Compose two unary functions. Similar to compose, but avoids using Function.prototype.apply. */
|
|
49
|
-
const compose1 = (fbc, fab) => (a) => fbc(fab(a));
|
|
50
22
|
const constant = (value) => {
|
|
51
23
|
return () => {
|
|
52
24
|
return value;
|
|
@@ -55,14 +27,6 @@
|
|
|
55
27
|
const tripleEquals = (a, b) => {
|
|
56
28
|
return a === b;
|
|
57
29
|
};
|
|
58
|
-
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
|
59
|
-
function curry(fn, ...initialArgs) {
|
|
60
|
-
return (...restArgs) => {
|
|
61
|
-
const all = initialArgs.concat(restArgs);
|
|
62
|
-
return fn.apply(null, all);
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const not = (f) => (t) => !f(t);
|
|
66
30
|
const never = constant(false);
|
|
67
31
|
|
|
68
32
|
/**
|
|
@@ -316,13 +280,7 @@
|
|
|
316
280
|
// reuse the same object
|
|
317
281
|
Optional.singletonNone = new Optional(false);
|
|
318
282
|
|
|
319
|
-
/* eslint-disable @typescript-eslint/unbound-method */
|
|
320
283
|
const nativeSlice = Array.prototype.slice;
|
|
321
|
-
const nativeIndexOf = Array.prototype.indexOf;
|
|
322
|
-
const nativePush = Array.prototype.push;
|
|
323
|
-
/* eslint-enable */
|
|
324
|
-
const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
|
|
325
|
-
const contains$1 = (xs, x) => rawIndexOf(xs, x) > -1;
|
|
326
284
|
const exists = (xs, pred) => {
|
|
327
285
|
for (let i = 0, len = xs.length; i < len; i++) {
|
|
328
286
|
const x = xs[i];
|
|
@@ -346,59 +304,14 @@
|
|
|
346
304
|
// Unwound implementing other functions in terms of each.
|
|
347
305
|
// The code size is roughly the same, and it should allow for better optimisation.
|
|
348
306
|
// const each = function<T, U>(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void {
|
|
349
|
-
const each
|
|
307
|
+
const each = (xs, f) => {
|
|
350
308
|
for (let i = 0, len = xs.length; i < len; i++) {
|
|
351
309
|
const x = xs[i];
|
|
352
310
|
f(x, i);
|
|
353
311
|
}
|
|
354
312
|
};
|
|
355
|
-
const filter$1 = (xs, pred) => {
|
|
356
|
-
const r = [];
|
|
357
|
-
for (let i = 0, len = xs.length; i < len; i++) {
|
|
358
|
-
const x = xs[i];
|
|
359
|
-
if (pred(x, i)) {
|
|
360
|
-
r.push(x);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
return r;
|
|
364
|
-
};
|
|
365
|
-
/*
|
|
366
|
-
* Groups an array into contiguous arrays of like elements. Whether an element is like or not depends on f.
|
|
367
|
-
*
|
|
368
|
-
* f is a function that derives a value from an element - e.g. true or false, or a string.
|
|
369
|
-
* Elements are like if this function generates the same value for them (according to ===).
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* Order of the elements is preserved. Arr.flatten() on the result will return the original list, as with Haskell groupBy function.
|
|
373
|
-
* For a good explanation, see the group function (which is a special case of groupBy)
|
|
374
|
-
* http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-List.html#v:group
|
|
375
|
-
*/
|
|
376
|
-
const groupBy = (xs, f) => {
|
|
377
|
-
if (xs.length === 0) {
|
|
378
|
-
return [];
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
let wasType = f(xs[0]); // initial case for matching
|
|
382
|
-
const r = [];
|
|
383
|
-
let group = [];
|
|
384
|
-
for (let i = 0, len = xs.length; i < len; i++) {
|
|
385
|
-
const x = xs[i];
|
|
386
|
-
const type = f(x);
|
|
387
|
-
if (type !== wasType) {
|
|
388
|
-
r.push(group);
|
|
389
|
-
group = [];
|
|
390
|
-
}
|
|
391
|
-
wasType = type;
|
|
392
|
-
group.push(x);
|
|
393
|
-
}
|
|
394
|
-
if (group.length !== 0) {
|
|
395
|
-
r.push(group);
|
|
396
|
-
}
|
|
397
|
-
return r;
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
313
|
const foldl = (xs, f, acc) => {
|
|
401
|
-
each
|
|
314
|
+
each(xs, (x, i) => {
|
|
402
315
|
acc = f(acc, x, i);
|
|
403
316
|
});
|
|
404
317
|
return acc;
|
|
@@ -418,1900 +331,146 @@
|
|
|
418
331
|
const find = (xs, pred) => {
|
|
419
332
|
return findUntil(xs, pred, never);
|
|
420
333
|
};
|
|
421
|
-
const flatten = (xs) => {
|
|
422
|
-
// Note, this is possible because push supports multiple arguments:
|
|
423
|
-
// http://jsperf.com/concat-push/6
|
|
424
|
-
// Note that in the past, concat() would silently work (very slowly) for array-like objects.
|
|
425
|
-
// With this change it will throw an error.
|
|
426
|
-
const r = [];
|
|
427
|
-
for (let i = 0, len = xs.length; i < len; ++i) {
|
|
428
|
-
// Ensure that each value is an array itself
|
|
429
|
-
if (!isArray(xs[i])) {
|
|
430
|
-
throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
|
|
431
|
-
}
|
|
432
|
-
nativePush.apply(r, xs[i]);
|
|
433
|
-
}
|
|
434
|
-
return r;
|
|
435
|
-
};
|
|
436
|
-
const bind = (xs, f) => flatten(map(xs, f));
|
|
437
334
|
const reverse = (xs) => {
|
|
438
335
|
const r = nativeSlice.call(xs, 0);
|
|
439
336
|
r.reverse();
|
|
440
337
|
return r;
|
|
441
338
|
};
|
|
442
|
-
|
|
443
|
-
const head = (xs) => get$1(xs, 0);
|
|
444
|
-
const last = (xs) => get$1(xs, xs.length - 1);
|
|
445
|
-
const unique = (xs, comparator) => {
|
|
446
|
-
const r = [];
|
|
447
|
-
const isDuplicated = isFunction(comparator) ?
|
|
448
|
-
(x) => exists(r, (i) => comparator(i, x)) :
|
|
449
|
-
(x) => contains$1(r, x);
|
|
450
|
-
for (let i = 0, len = xs.length; i < len; i++) {
|
|
451
|
-
const x = xs[i];
|
|
452
|
-
if (!isDuplicated(x)) {
|
|
453
|
-
r.push(x);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
return r;
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// There are many variations of Object iteration that are faster than the 'for-in' style:
|
|
460
|
-
// http://jsperf.com/object-keys-iteration/107
|
|
461
|
-
//
|
|
462
|
-
// Use the native keys if it is available (IE9+), otherwise fall back to manually filtering
|
|
463
|
-
const keys = Object.keys;
|
|
464
|
-
const each = (obj, f) => {
|
|
465
|
-
const props = keys(obj);
|
|
466
|
-
for (let k = 0, len = props.length; k < len; k++) {
|
|
467
|
-
const i = props[k];
|
|
468
|
-
const x = obj[i];
|
|
469
|
-
f(x, i);
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
const objAcc = (r) => (x, i) => {
|
|
473
|
-
r[i] = x;
|
|
474
|
-
};
|
|
475
|
-
const internalFilter = (obj, pred, onTrue, onFalse) => {
|
|
476
|
-
each(obj, (x, i) => {
|
|
477
|
-
(pred(x, i) ? onTrue : onFalse)(x, i);
|
|
478
|
-
});
|
|
479
|
-
};
|
|
480
|
-
const filter = (obj, pred) => {
|
|
481
|
-
const t = {};
|
|
482
|
-
internalFilter(obj, pred, objAcc(t), noop);
|
|
483
|
-
return t;
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
const Cell = (initial) => {
|
|
487
|
-
let value = initial;
|
|
488
|
-
const get = () => {
|
|
489
|
-
return value;
|
|
490
|
-
};
|
|
491
|
-
const set = (v) => {
|
|
492
|
-
value = v;
|
|
493
|
-
};
|
|
494
|
-
return {
|
|
495
|
-
get,
|
|
496
|
-
set
|
|
497
|
-
};
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
// Use window object as the global if it's available since CSP will block script evals
|
|
501
|
-
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
502
|
-
const Global = typeof window !== 'undefined' ? window : Function('return this;')();
|
|
339
|
+
isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x);
|
|
503
340
|
|
|
504
341
|
/**
|
|
505
342
|
* **Is** the value stored inside this Optional object equal to `rhs`?
|
|
506
343
|
*/
|
|
507
|
-
const is
|
|
508
|
-
/**
|
|
509
|
-
* Are these two Optional objects equal? Equality here means either they're both
|
|
510
|
-
* `Some` (and the values are equal under the comparator) or they're both `None`.
|
|
511
|
-
*/
|
|
512
|
-
const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
|
|
513
|
-
/*
|
|
514
|
-
Notes on the lift functions:
|
|
515
|
-
- We used to have a generic liftN, but we were concerned about its type-safety, and the below variants were faster in microbenchmarks.
|
|
516
|
-
- The getOrDie calls are partial functions, but are checked beforehand. This is faster and more convenient (but less safe) than folds.
|
|
517
|
-
- && is used instead of a loop for simplicity and performance.
|
|
518
|
-
*/
|
|
519
|
-
const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
|
|
520
|
-
|
|
521
|
-
/** path :: ([String], JsObj?) -> JsObj */
|
|
522
|
-
const path = (parts, scope) => {
|
|
523
|
-
let o = scope !== undefined && scope !== null ? scope : Global;
|
|
524
|
-
for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
|
|
525
|
-
o = o[parts[i]];
|
|
526
|
-
}
|
|
527
|
-
return o;
|
|
528
|
-
};
|
|
529
|
-
/** resolve :: (String, JsObj?) -> JsObj */
|
|
530
|
-
const resolve = (p, scope) => {
|
|
531
|
-
const parts = p.split('.');
|
|
532
|
-
return path(parts, scope);
|
|
533
|
-
};
|
|
344
|
+
const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
|
|
534
345
|
|
|
535
346
|
const blank = (r) => (s) => s.replace(r, '');
|
|
536
347
|
/** removes all leading and trailing spaces */
|
|
537
348
|
const trim = blank(/^\s+|\s+$/g);
|
|
538
349
|
const isNotEmpty = (s) => s.length > 0;
|
|
539
|
-
const isEmpty
|
|
540
|
-
|
|
541
|
-
const zeroWidth = '\uFEFF';
|
|
542
|
-
const isZwsp = (char) => char === zeroWidth;
|
|
543
|
-
|
|
544
|
-
const fromHtml = (html, scope) => {
|
|
545
|
-
const doc = scope || document;
|
|
546
|
-
const div = doc.createElement('div');
|
|
547
|
-
div.innerHTML = html;
|
|
548
|
-
if (!div.hasChildNodes() || div.childNodes.length > 1) {
|
|
549
|
-
const message = 'HTML does not have a single root node';
|
|
550
|
-
// eslint-disable-next-line no-console
|
|
551
|
-
console.error(message, html);
|
|
552
|
-
throw new Error(message);
|
|
553
|
-
}
|
|
554
|
-
return fromDom$1(div.childNodes[0]);
|
|
555
|
-
};
|
|
556
|
-
const fromTag = (tag, scope) => {
|
|
557
|
-
const doc = scope || document;
|
|
558
|
-
const node = doc.createElement(tag);
|
|
559
|
-
return fromDom$1(node);
|
|
560
|
-
};
|
|
561
|
-
const fromText = (text, scope) => {
|
|
562
|
-
const doc = scope || document;
|
|
563
|
-
const node = doc.createTextNode(text);
|
|
564
|
-
return fromDom$1(node);
|
|
565
|
-
};
|
|
566
|
-
const fromDom$1 = (node) => {
|
|
567
|
-
// TODO: Consider removing this check, but left atm for safety
|
|
568
|
-
if (node === null || node === undefined) {
|
|
569
|
-
throw new Error('Node cannot be null or undefined');
|
|
570
|
-
}
|
|
571
|
-
return {
|
|
572
|
-
dom: node
|
|
573
|
-
};
|
|
574
|
-
};
|
|
575
|
-
const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
|
|
576
|
-
// tslint:disable-next-line:variable-name
|
|
577
|
-
const SugarElement = {
|
|
578
|
-
fromHtml,
|
|
579
|
-
fromTag,
|
|
580
|
-
fromText,
|
|
581
|
-
fromDom: fromDom$1,
|
|
582
|
-
fromPoint
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
const COMMENT = 8;
|
|
586
|
-
const DOCUMENT_FRAGMENT = 11;
|
|
587
|
-
const ELEMENT = 1;
|
|
588
|
-
const TEXT = 3;
|
|
589
|
-
|
|
590
|
-
const is$1 = (element, selector) => {
|
|
591
|
-
const dom = element.dom;
|
|
592
|
-
if (dom.nodeType !== ELEMENT) {
|
|
593
|
-
return false;
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
const elem = dom;
|
|
597
|
-
if (elem.matches !== undefined) {
|
|
598
|
-
return elem.matches(selector);
|
|
599
|
-
}
|
|
600
|
-
else if (elem.msMatchesSelector !== undefined) {
|
|
601
|
-
return elem.msMatchesSelector(selector);
|
|
602
|
-
}
|
|
603
|
-
else if (elem.webkitMatchesSelector !== undefined) {
|
|
604
|
-
return elem.webkitMatchesSelector(selector);
|
|
605
|
-
}
|
|
606
|
-
else if (elem.mozMatchesSelector !== undefined) {
|
|
607
|
-
// cast to any as mozMatchesSelector doesn't exist in TS DOM lib
|
|
608
|
-
return elem.mozMatchesSelector(selector);
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
throw new Error('Browser lacks native selectors');
|
|
612
|
-
} // unfortunately we can't throw this on startup :(
|
|
613
|
-
}
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
const eq = (e1, e2) => e1.dom === e2.dom;
|
|
617
|
-
// Returns: true if node e1 contains e2, otherwise false.
|
|
618
|
-
// (returns false if e1===e2: A node does not contain itself).
|
|
619
|
-
const contains = (e1, e2) => {
|
|
620
|
-
const d1 = e1.dom;
|
|
621
|
-
const d2 = e2.dom;
|
|
622
|
-
return d1 === d2 ? false : d1.contains(d2);
|
|
623
|
-
};
|
|
624
|
-
const is = is$1;
|
|
625
|
-
|
|
626
|
-
const unsafe = (name, scope) => {
|
|
627
|
-
return resolve(name, scope);
|
|
628
|
-
};
|
|
629
|
-
const getOrDie = (name, scope) => {
|
|
630
|
-
const actual = unsafe(name, scope);
|
|
631
|
-
if (actual === undefined || actual === null) {
|
|
632
|
-
throw new Error(name + ' not available on this browser');
|
|
633
|
-
}
|
|
634
|
-
return actual;
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
const getPrototypeOf = Object.getPrototypeOf;
|
|
638
|
-
/*
|
|
639
|
-
* IE9 and above
|
|
640
|
-
*
|
|
641
|
-
* MDN no use on this one, but here's the link anyway:
|
|
642
|
-
* https://developer.mozilla.org/en/docs/Web/API/HTMLElement
|
|
643
|
-
*/
|
|
644
|
-
const sandHTMLElement = (scope) => {
|
|
645
|
-
return getOrDie('HTMLElement', scope);
|
|
646
|
-
};
|
|
647
|
-
const isPrototypeOf = (x) => {
|
|
648
|
-
// use Resolve to get the window object for x and just return undefined if it can't find it.
|
|
649
|
-
// undefined scope later triggers using the global window.
|
|
650
|
-
const scope = resolve('ownerDocument.defaultView', x);
|
|
651
|
-
// TINY-7374: We can't rely on looking at the owner window HTMLElement as the element may have
|
|
652
|
-
// been constructed in a different window and then appended to the current window document.
|
|
653
|
-
return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf(x).constructor.name));
|
|
654
|
-
};
|
|
655
|
-
|
|
656
|
-
const name = (element) => {
|
|
657
|
-
const r = element.dom.nodeName;
|
|
658
|
-
return r.toLowerCase();
|
|
659
|
-
};
|
|
660
|
-
const type = (element) => element.dom.nodeType;
|
|
661
|
-
const isType = (t) => (element) => type(element) === t;
|
|
662
|
-
const isComment = (element) => type(element) === COMMENT || name(element) === '#comment';
|
|
663
|
-
const isHTMLElement = (element) => isElement$1(element) && isPrototypeOf(element.dom);
|
|
664
|
-
const isElement$1 = isType(ELEMENT);
|
|
665
|
-
const isText = isType(TEXT);
|
|
666
|
-
const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
|
|
667
|
-
const isTag = (tag) => (e) => isElement$1(e) && name(e) === tag;
|
|
668
|
-
|
|
669
|
-
const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
|
|
670
|
-
const parentElement = (element) => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
|
|
671
|
-
const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
|
|
672
|
-
const children = (element) => map(element.dom.childNodes, SugarElement.fromDom);
|
|
673
|
-
const child = (element, index) => {
|
|
674
|
-
const cs = element.dom.childNodes;
|
|
675
|
-
return Optional.from(cs[index]).map(SugarElement.fromDom);
|
|
676
|
-
};
|
|
677
|
-
const firstChild = (element) => child(element, 0);
|
|
678
|
-
const lastChild = (element) => child(element, element.dom.childNodes.length - 1);
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Is the element a ShadowRoot?
|
|
682
|
-
*
|
|
683
|
-
* Note: this is insufficient to test if any element is a shadow root, but it is sufficient to differentiate between
|
|
684
|
-
* a Document and a ShadowRoot.
|
|
685
|
-
*/
|
|
686
|
-
const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
|
|
687
|
-
const getRootNode = (e) => SugarElement.fromDom(e.dom.getRootNode());
|
|
688
|
-
/** If this element is in a ShadowRoot, return it. */
|
|
689
|
-
const getShadowRoot = (e) => {
|
|
690
|
-
const r = getRootNode(e);
|
|
691
|
-
return isShadowRoot(r) ? Optional.some(r) : Optional.none();
|
|
692
|
-
};
|
|
693
|
-
/** Return the host of a ShadowRoot.
|
|
694
|
-
*
|
|
695
|
-
* This function will throw if Shadow DOM is unsupported in the browser, or if the host is null.
|
|
696
|
-
* If you actually have a ShadowRoot, this shouldn't happen.
|
|
697
|
-
*/
|
|
698
|
-
const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
|
|
699
|
-
|
|
700
|
-
const before$1 = (marker, element) => {
|
|
701
|
-
const parent$1 = parent(marker);
|
|
702
|
-
parent$1.each((v) => {
|
|
703
|
-
v.dom.insertBefore(element.dom, marker.dom);
|
|
704
|
-
});
|
|
705
|
-
};
|
|
706
|
-
const after = (marker, element) => {
|
|
707
|
-
const sibling = nextSibling(marker);
|
|
708
|
-
sibling.fold(() => {
|
|
709
|
-
const parent$1 = parent(marker);
|
|
710
|
-
parent$1.each((v) => {
|
|
711
|
-
append$1(v, element);
|
|
712
|
-
});
|
|
713
|
-
}, (v) => {
|
|
714
|
-
before$1(v, element);
|
|
715
|
-
});
|
|
716
|
-
};
|
|
717
|
-
const prepend = (parent, element) => {
|
|
718
|
-
const firstChild$1 = firstChild(parent);
|
|
719
|
-
firstChild$1.fold(() => {
|
|
720
|
-
append$1(parent, element);
|
|
721
|
-
}, (v) => {
|
|
722
|
-
parent.dom.insertBefore(element.dom, v.dom);
|
|
723
|
-
});
|
|
724
|
-
};
|
|
725
|
-
const append$1 = (parent, element) => {
|
|
726
|
-
parent.dom.appendChild(element.dom);
|
|
727
|
-
};
|
|
350
|
+
const isEmpty = (s) => !isNotEmpty(s);
|
|
728
351
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
each$1(elements, (x) => {
|
|
736
|
-
append$1(parent, x);
|
|
352
|
+
// Example: 'AB' -> 28
|
|
353
|
+
const parseAlphabeticBase26 = (str) => {
|
|
354
|
+
const chars = reverse(trim(str).split(''));
|
|
355
|
+
const values = map(chars, (char, i) => {
|
|
356
|
+
const charValue = char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 1;
|
|
357
|
+
return Math.pow(26, i) * charValue;
|
|
737
358
|
});
|
|
359
|
+
return foldl(values, (sum, v) => sum + v, 0);
|
|
738
360
|
};
|
|
739
|
-
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
* We fail on those invalid cases, only allowing numbers and booleans.
|
|
745
|
-
*/
|
|
746
|
-
if (isString(value) || isBoolean(value) || isNumber(value)) {
|
|
747
|
-
dom.setAttribute(key, value + '');
|
|
361
|
+
// Example: 28 -> 'AB'
|
|
362
|
+
const composeAlphabeticBase26 = (value) => {
|
|
363
|
+
value--;
|
|
364
|
+
if (value < 0) {
|
|
365
|
+
return '';
|
|
748
366
|
}
|
|
749
367
|
else {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const setAll = (element, attrs) => {
|
|
756
|
-
const dom = element.dom;
|
|
757
|
-
each(attrs, (v, k) => {
|
|
758
|
-
rawSet(dom, k, v);
|
|
759
|
-
});
|
|
760
|
-
};
|
|
761
|
-
const clone$1 = (element) => foldl(element.dom.attributes, (acc, attr) => {
|
|
762
|
-
acc[attr.name] = attr.value;
|
|
763
|
-
return acc;
|
|
764
|
-
}, {});
|
|
765
|
-
|
|
766
|
-
const empty = (element) => {
|
|
767
|
-
// shortcut "empty node" trick. Requires IE 9.
|
|
768
|
-
element.dom.textContent = '';
|
|
769
|
-
// If the contents was a single empty text node, the above doesn't remove it. But, it's still faster in general
|
|
770
|
-
// than removing every child node manually.
|
|
771
|
-
// The following is (probably) safe for performance as 99.9% of the time the trick works and
|
|
772
|
-
// Traverse.children will return an empty array.
|
|
773
|
-
each$1(children(element), (rogue) => {
|
|
774
|
-
remove(rogue);
|
|
775
|
-
});
|
|
776
|
-
};
|
|
777
|
-
const remove = (element) => {
|
|
778
|
-
const dom = element.dom;
|
|
779
|
-
if (dom.parentNode !== null) {
|
|
780
|
-
dom.parentNode.removeChild(dom);
|
|
781
|
-
}
|
|
782
|
-
};
|
|
783
|
-
|
|
784
|
-
const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
|
|
785
|
-
/** Deep clone - everything copied including children */
|
|
786
|
-
const deep = (original) => clone(original, true);
|
|
787
|
-
/** Shallow clone, with a new tag */
|
|
788
|
-
const shallowAs = (original, tag) => {
|
|
789
|
-
const nu = SugarElement.fromTag(tag);
|
|
790
|
-
const attributes = clone$1(original);
|
|
791
|
-
setAll(nu, attributes);
|
|
792
|
-
return nu;
|
|
793
|
-
};
|
|
794
|
-
/** Change the tag name, but keep all children */
|
|
795
|
-
const mutate = (original, tag) => {
|
|
796
|
-
const nu = shallowAs(original, tag);
|
|
797
|
-
after(original, nu);
|
|
798
|
-
const children$1 = children(original);
|
|
799
|
-
append(nu, children$1);
|
|
800
|
-
remove(original);
|
|
801
|
-
return nu;
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
const fromDom = (nodes) => map(nodes, SugarElement.fromDom);
|
|
805
|
-
|
|
806
|
-
// some elements, such as mathml, don't have style attributes
|
|
807
|
-
// others, such as angular elements, have style attributes that aren't a CSSStyleDeclaration
|
|
808
|
-
const isSupported = (dom) =>
|
|
809
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
810
|
-
dom.style !== undefined && isFunction(dom.style.getPropertyValue);
|
|
811
|
-
|
|
812
|
-
// Node.contains() is very, very, very good performance
|
|
813
|
-
// http://jsperf.com/closest-vs-contains/5
|
|
814
|
-
const inBody = (element) => {
|
|
815
|
-
// Technically this is only required on IE, where contains() returns false for text nodes.
|
|
816
|
-
// But it's cheap enough to run everywhere and Sugar doesn't have platform detection (yet).
|
|
817
|
-
const dom = isText(element) ? element.dom.parentNode : element.dom;
|
|
818
|
-
// use ownerDocument.body to ensure this works inside iframes.
|
|
819
|
-
// Normally contains is bad because an element "contains" itself, but here we want that.
|
|
820
|
-
if (dom === undefined || dom === null || dom.ownerDocument === null) {
|
|
821
|
-
return false;
|
|
368
|
+
const remainder = value % 26;
|
|
369
|
+
const quotient = Math.floor(value / 26);
|
|
370
|
+
const rest = composeAlphabeticBase26(quotient);
|
|
371
|
+
const char = String.fromCharCode('A'.charCodeAt(0) + remainder);
|
|
372
|
+
return rest + char;
|
|
822
373
|
}
|
|
823
|
-
const doc = dom.ownerDocument;
|
|
824
|
-
return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
|
|
825
374
|
};
|
|
826
|
-
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
// eslint-disable-next-line no-console
|
|
833
|
-
console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
|
|
834
|
-
throw new Error('CSS value must be a string: ' + value);
|
|
375
|
+
const isUppercase = (str) => /^[A-Z]+$/.test(str);
|
|
376
|
+
const isLowercase = (str) => /^[a-z]+$/.test(str);
|
|
377
|
+
const isNumeric = (str) => /^[0-9]+$/.test(str);
|
|
378
|
+
const deduceListType = (start) => {
|
|
379
|
+
if (isNumeric(start)) {
|
|
380
|
+
return 2 /* ListType.Numeric */;
|
|
835
381
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
dom.style.setProperty(property, value);
|
|
382
|
+
else if (isUppercase(start)) {
|
|
383
|
+
return 0 /* ListType.UpperAlpha */;
|
|
839
384
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const dom = element.dom;
|
|
843
|
-
internalSet(dom, property, value);
|
|
844
|
-
};
|
|
845
|
-
|
|
846
|
-
const fromElements = (elements, scope) => {
|
|
847
|
-
const doc = scope || document;
|
|
848
|
-
const fragment = doc.createDocumentFragment();
|
|
849
|
-
each$1(elements, (element) => {
|
|
850
|
-
fragment.appendChild(element.dom);
|
|
851
|
-
});
|
|
852
|
-
return SugarElement.fromDom(fragment);
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
|
|
856
|
-
if (is(scope, a)) {
|
|
857
|
-
return Optional.some(scope);
|
|
385
|
+
else if (isLowercase(start)) {
|
|
386
|
+
return 1 /* ListType.LowerAlpha */;
|
|
858
387
|
}
|
|
859
|
-
else if (
|
|
860
|
-
return
|
|
388
|
+
else if (isEmpty(start)) {
|
|
389
|
+
return 3 /* ListType.None */;
|
|
861
390
|
}
|
|
862
391
|
else {
|
|
863
|
-
return
|
|
392
|
+
return 4 /* ListType.Unknown */;
|
|
864
393
|
}
|
|
865
394
|
};
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
return Optional.some(
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
395
|
+
const parseStartValue = (start) => {
|
|
396
|
+
switch (deduceListType(start)) {
|
|
397
|
+
case 2 /* ListType.Numeric */:
|
|
398
|
+
return Optional.some({
|
|
399
|
+
listStyleType: Optional.none(),
|
|
400
|
+
start
|
|
401
|
+
});
|
|
402
|
+
case 0 /* ListType.UpperAlpha */:
|
|
403
|
+
return Optional.some({
|
|
404
|
+
listStyleType: Optional.some('upper-alpha'),
|
|
405
|
+
start: parseAlphabeticBase26(start).toString()
|
|
406
|
+
});
|
|
407
|
+
case 1 /* ListType.LowerAlpha */:
|
|
408
|
+
return Optional.some({
|
|
409
|
+
listStyleType: Optional.some('lower-alpha'),
|
|
410
|
+
start: parseAlphabeticBase26(start).toString()
|
|
411
|
+
});
|
|
412
|
+
case 3 /* ListType.None */:
|
|
413
|
+
return Optional.some({
|
|
414
|
+
listStyleType: Optional.none(),
|
|
415
|
+
start: ''
|
|
416
|
+
});
|
|
417
|
+
case 4 /* ListType.Unknown */:
|
|
418
|
+
return Optional.none();
|
|
879
419
|
}
|
|
880
|
-
return Optional.none();
|
|
881
420
|
};
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
// Returns Some(closest ancestor element (sugared)) matching 'selector' up to isRoot, or None() otherwise
|
|
890
|
-
const closest$1 = (scope, selector, isRoot) => {
|
|
891
|
-
const is = (element, selector) => is$1(element, selector);
|
|
892
|
-
return ClosestOrAncestor(is, ancestor$2, scope, selector, isRoot);
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
const closest = (target) => closest$1(target, '[contenteditable]');
|
|
896
|
-
const isEditable = (element, assumeEditable = false) => {
|
|
897
|
-
if (inBody(element)) {
|
|
898
|
-
return element.dom.isContentEditable;
|
|
421
|
+
const parseDetail = (detail) => {
|
|
422
|
+
const start = parseInt(detail.start, 10);
|
|
423
|
+
if (is(detail.listStyleType, 'upper-alpha')) {
|
|
424
|
+
return composeAlphabeticBase26(start);
|
|
425
|
+
}
|
|
426
|
+
else if (is(detail.listStyleType, 'lower-alpha')) {
|
|
427
|
+
return composeAlphabeticBase26(start).toLowerCase();
|
|
899
428
|
}
|
|
900
429
|
else {
|
|
901
|
-
|
|
902
|
-
return closest(element).fold(constant(assumeEditable), (editable) => getRaw(editable) === 'true');
|
|
430
|
+
return detail.start;
|
|
903
431
|
}
|
|
904
432
|
};
|
|
905
|
-
const getRaw = (element) => element.dom.contentEditable;
|
|
906
|
-
|
|
907
|
-
const ancestor$1 = (scope, predicate, isRoot) => ancestor$3(scope, predicate, isRoot).isSome();
|
|
908
|
-
|
|
909
|
-
const ancestor = (element, target) => ancestor$1(element, curry(eq, target));
|
|
910
433
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
var global$5 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
|
|
914
|
-
|
|
915
|
-
var global$4 = tinymce.util.Tools.resolve('tinymce.util.VK');
|
|
916
|
-
|
|
917
|
-
var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
|
|
918
|
-
|
|
919
|
-
var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
|
|
434
|
+
const option = (name) => (editor) => editor.options.get(name);
|
|
435
|
+
const getForcedRootBlock = option('forced_root_block');
|
|
920
436
|
|
|
921
|
-
const
|
|
437
|
+
const isCustomList = (list) => /\btox\-/.test(list.className);
|
|
922
438
|
const matchNodeNames = (regex) => (node) => isNonNullable(node) && regex.test(node.nodeName);
|
|
923
|
-
const
|
|
924
|
-
const isElement = (node) => isNonNullable(node) && node.nodeType === 1;
|
|
439
|
+
const matchNodeName = (name) => (node) => isNonNullable(node) && node.nodeName.toLowerCase() === name;
|
|
925
440
|
const isListNode = matchNodeNames(/^(OL|UL|DL)$/);
|
|
926
|
-
const isOlUlNode = matchNodeNames(/^(OL|UL)$/);
|
|
927
|
-
const isOlNode = matchNodeName('ol');
|
|
928
|
-
const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
|
|
929
|
-
const isDlItemNode = matchNodeNames(/^(DT|DD)$/);
|
|
930
441
|
const isTableCellNode = matchNodeNames(/^(TH|TD)$/);
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
442
|
+
const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
|
|
443
|
+
const inList = (parents, listName) => findUntil(parents, isListNode, isTableCellNode)
|
|
444
|
+
.exists((list) => list.nodeName === listName && !isCustomList(list));
|
|
445
|
+
const setNodeChangeHandler = (editor, nodeChangeHandler) => {
|
|
446
|
+
const initialNode = editor.selection.getNode();
|
|
447
|
+
// Set the initial state
|
|
448
|
+
nodeChangeHandler({
|
|
449
|
+
parents: editor.dom.getParents(initialNode),
|
|
450
|
+
element: initialNode
|
|
451
|
+
});
|
|
452
|
+
editor.on('NodeChange', nodeChangeHandler);
|
|
453
|
+
return () => editor.off('NodeChange', nodeChangeHandler);
|
|
941
454
|
};
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
}
|
|
947
|
-
return empty;
|
|
455
|
+
const isWithinNonEditable = (editor, element) => element !== null && !editor.dom.isEditable(element);
|
|
456
|
+
const isWithinNonEditableList = (editor, element) => {
|
|
457
|
+
const parentList = editor.dom.getParent(element, 'ol,ul,dl');
|
|
458
|
+
return isWithinNonEditable(editor, parentList) || !editor.selection.isEditable();
|
|
948
459
|
};
|
|
949
|
-
const
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
const
|
|
953
|
-
const
|
|
954
|
-
|
|
955
|
-
processor: 'boolean',
|
|
956
|
-
default: true
|
|
957
|
-
});
|
|
460
|
+
const isOlNode = matchNodeName('ol');
|
|
461
|
+
const listNames = ['OL', 'UL', 'DL'];
|
|
462
|
+
const listSelector = listNames.join(',');
|
|
463
|
+
const getParentList = (editor, node) => {
|
|
464
|
+
const selectionStart = node || editor.selection.getStart(true);
|
|
465
|
+
return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
|
|
958
466
|
};
|
|
959
|
-
const shouldIndentOnTab = option('lists_indent_on_tab');
|
|
960
|
-
const getForcedRootBlock = option('forced_root_block');
|
|
961
|
-
const getForcedRootBlockAttrs = option('forced_root_block_attrs');
|
|
962
|
-
|
|
963
|
-
const createTextBlock = (editor, contentNode, attrs = {}) => {
|
|
964
|
-
const dom = editor.dom;
|
|
965
|
-
const blockElements = editor.schema.getBlockElements();
|
|
966
|
-
const fragment = dom.createFragment();
|
|
967
|
-
const blockName = getForcedRootBlock(editor);
|
|
968
|
-
const blockAttrs = getForcedRootBlockAttrs(editor);
|
|
969
|
-
let node;
|
|
970
|
-
let textBlock;
|
|
971
|
-
let hasContentNode = false;
|
|
972
|
-
textBlock = dom.create(blockName, {
|
|
973
|
-
...blockAttrs,
|
|
974
|
-
...(attrs.style ? { style: attrs.style } : {})
|
|
975
|
-
});
|
|
976
|
-
if (!isBlock(contentNode.firstChild, blockElements)) {
|
|
977
|
-
fragment.appendChild(textBlock);
|
|
978
|
-
}
|
|
979
|
-
while ((node = contentNode.firstChild)) {
|
|
980
|
-
const nodeName = node.nodeName;
|
|
981
|
-
if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
|
|
982
|
-
hasContentNode = true;
|
|
983
|
-
}
|
|
984
|
-
if (isBlock(node, blockElements)) {
|
|
985
|
-
fragment.appendChild(node);
|
|
986
|
-
textBlock = null;
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
if (!textBlock) {
|
|
990
|
-
textBlock = dom.create(blockName, blockAttrs);
|
|
991
|
-
fragment.appendChild(textBlock);
|
|
992
|
-
}
|
|
993
|
-
textBlock.appendChild(node);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
// BR is needed in empty blocks
|
|
997
|
-
if (!hasContentNode && textBlock) {
|
|
998
|
-
textBlock.appendChild(dom.create('br', { 'data-mce-bogus': '1' }));
|
|
999
|
-
}
|
|
1000
|
-
return fragment;
|
|
1001
|
-
};
|
|
1002
|
-
|
|
1003
|
-
const DOM$2 = global$3.DOM;
|
|
1004
|
-
const splitList = (editor, list, li) => {
|
|
1005
|
-
const removeAndKeepBookmarks = (targetNode) => {
|
|
1006
|
-
const parent = targetNode.parentNode;
|
|
1007
|
-
if (parent) {
|
|
1008
|
-
global$2.each(bookmarks, (node) => {
|
|
1009
|
-
parent.insertBefore(node, li.parentNode);
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
DOM$2.remove(targetNode);
|
|
1013
|
-
};
|
|
1014
|
-
const bookmarks = DOM$2.select('span[data-mce-type="bookmark"]', list);
|
|
1015
|
-
const newBlock = createTextBlock(editor, li);
|
|
1016
|
-
const tmpRng = DOM$2.createRng();
|
|
1017
|
-
tmpRng.setStartAfter(li);
|
|
1018
|
-
tmpRng.setEndAfter(list);
|
|
1019
|
-
const fragment = tmpRng.extractContents();
|
|
1020
|
-
for (let node = fragment.firstChild; node; node = node.firstChild) {
|
|
1021
|
-
if (node.nodeName === 'LI' && editor.dom.isEmpty(node)) {
|
|
1022
|
-
DOM$2.remove(node);
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
if (!editor.dom.isEmpty(fragment)) {
|
|
1027
|
-
DOM$2.insertAfter(fragment, list);
|
|
1028
|
-
}
|
|
1029
|
-
DOM$2.insertAfter(newBlock, list);
|
|
1030
|
-
const parent = li.parentElement;
|
|
1031
|
-
if (parent && isEmpty$1(editor.dom, parent)) {
|
|
1032
|
-
removeAndKeepBookmarks(parent);
|
|
1033
|
-
}
|
|
1034
|
-
DOM$2.remove(li);
|
|
1035
|
-
if (isEmpty$1(editor.dom, list)) {
|
|
1036
|
-
DOM$2.remove(list);
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
|
|
1040
|
-
const isDescriptionDetail = isTag('dd');
|
|
1041
|
-
const isDescriptionTerm = isTag('dt');
|
|
1042
|
-
const outdentDlItem = (editor, item) => {
|
|
1043
|
-
if (isDescriptionDetail(item)) {
|
|
1044
|
-
mutate(item, 'dt');
|
|
1045
|
-
}
|
|
1046
|
-
else if (isDescriptionTerm(item)) {
|
|
1047
|
-
parentElement(item).each((dl) => splitList(editor, dl.dom, item.dom));
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
const indentDlItem = (item) => {
|
|
1051
|
-
if (isDescriptionTerm(item)) {
|
|
1052
|
-
mutate(item, 'dd');
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
const dlIndentation = (editor, indentation, dlItems) => {
|
|
1056
|
-
if (indentation === "Indent" /* Indentation.Indent */) {
|
|
1057
|
-
each$1(dlItems, indentDlItem);
|
|
1058
|
-
}
|
|
1059
|
-
else {
|
|
1060
|
-
each$1(dlItems, (item) => outdentDlItem(editor, item));
|
|
1061
|
-
}
|
|
1062
|
-
};
|
|
1063
|
-
|
|
1064
|
-
const getNormalizedPoint = (container, offset) => {
|
|
1065
|
-
if (isTextNode$1(container)) {
|
|
1066
|
-
return { container, offset };
|
|
1067
|
-
}
|
|
1068
|
-
const node = global$6.getNode(container, offset);
|
|
1069
|
-
if (isTextNode$1(node)) {
|
|
1070
|
-
return {
|
|
1071
|
-
container: node,
|
|
1072
|
-
offset: offset >= container.childNodes.length ? node.data.length : 0
|
|
1073
|
-
};
|
|
1074
|
-
}
|
|
1075
|
-
else if (node.previousSibling && isTextNode$1(node.previousSibling)) {
|
|
1076
|
-
return {
|
|
1077
|
-
container: node.previousSibling,
|
|
1078
|
-
offset: node.previousSibling.data.length
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
else if (node.nextSibling && isTextNode$1(node.nextSibling)) {
|
|
1082
|
-
return {
|
|
1083
|
-
container: node.nextSibling,
|
|
1084
|
-
offset: 0
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
return { container, offset };
|
|
1088
|
-
};
|
|
1089
|
-
const normalizeRange = (rng) => {
|
|
1090
|
-
const outRng = rng.cloneRange();
|
|
1091
|
-
const rangeStart = getNormalizedPoint(rng.startContainer, rng.startOffset);
|
|
1092
|
-
outRng.setStart(rangeStart.container, rangeStart.offset);
|
|
1093
|
-
const rangeEnd = getNormalizedPoint(rng.endContainer, rng.endOffset);
|
|
1094
|
-
outRng.setEnd(rangeEnd.container, rangeEnd.offset);
|
|
1095
|
-
return outRng;
|
|
1096
|
-
};
|
|
1097
|
-
|
|
1098
|
-
const listNames = ['OL', 'UL', 'DL'];
|
|
1099
|
-
const listSelector = listNames.join(',');
|
|
1100
|
-
const getParentList = (editor, node) => {
|
|
1101
|
-
const selectionStart = node || editor.selection.getStart(true);
|
|
1102
|
-
return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
|
|
1103
|
-
};
|
|
1104
|
-
const isParentListSelected = (parentList, selectedBlocks) => isNonNullable(parentList) && selectedBlocks.length === 1 && selectedBlocks[0] === parentList;
|
|
1105
|
-
const findSubLists = (parentList) => filter$1(parentList.querySelectorAll(listSelector), isListNode);
|
|
1106
|
-
const getSelectedSubLists = (editor) => {
|
|
1107
|
-
const parentList = getParentList(editor);
|
|
1108
|
-
const selectedBlocks = editor.selection.getSelectedBlocks();
|
|
1109
|
-
if (isParentListSelected(parentList, selectedBlocks)) {
|
|
1110
|
-
return findSubLists(parentList);
|
|
1111
|
-
}
|
|
1112
|
-
else {
|
|
1113
|
-
return filter$1(selectedBlocks, (elm) => {
|
|
1114
|
-
return isListNode(elm) && parentList !== elm;
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
};
|
|
1118
|
-
const findParentListItemsNodes = (editor, elms) => {
|
|
1119
|
-
const listItemsElms = global$2.map(elms, (elm) => {
|
|
1120
|
-
const parentLi = editor.dom.getParent(elm, 'li,dd,dt', getClosestListHost(editor, elm));
|
|
1121
|
-
return parentLi ? parentLi : elm;
|
|
1122
|
-
});
|
|
1123
|
-
return unique(listItemsElms);
|
|
1124
|
-
};
|
|
1125
|
-
const getSelectedListItems = (editor) => {
|
|
1126
|
-
const selectedBlocks = editor.selection.getSelectedBlocks();
|
|
1127
|
-
return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
|
|
1128
|
-
};
|
|
1129
|
-
const getSelectedDlItems = (editor) => filter$1(getSelectedListItems(editor), isDlItemNode);
|
|
1130
|
-
const getClosestEditingHost = (editor, elm) => {
|
|
1131
|
-
const parentTableCell = editor.dom.getParents(elm, 'TD,TH');
|
|
1132
|
-
return parentTableCell.length > 0 ? parentTableCell[0] : editor.getBody();
|
|
1133
|
-
};
|
|
1134
|
-
const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, (listName) => schema.isValidChild(node.nodeName, listName));
|
|
1135
467
|
const getClosestListHost = (editor, elm) => {
|
|
1136
468
|
const parentBlocks = editor.dom.getParents(elm, editor.dom.isBlock);
|
|
1137
469
|
const isNotForcedRootBlock = (elm) => elm.nodeName.toLowerCase() !== getForcedRootBlock(editor);
|
|
1138
470
|
const parentBlock = find(parentBlocks, (elm) => isNotForcedRootBlock(elm) && isListHost(editor.schema, elm));
|
|
1139
471
|
return parentBlock.getOr(editor.getBody());
|
|
1140
472
|
};
|
|
1141
|
-
const
|
|
1142
|
-
&& firstChild(parent).exists((firstChild) => !isListNode(firstChild.dom))
|
|
1143
|
-
&& lastChild(parent).exists((lastChild) => !isListNode(lastChild.dom)));
|
|
1144
|
-
const findLastParentListNode = (editor, elm) => {
|
|
1145
|
-
const parentLists = editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
|
|
1146
|
-
return last(parentLists);
|
|
1147
|
-
};
|
|
1148
|
-
const getSelectedLists = (editor) => {
|
|
1149
|
-
const firstList = findLastParentListNode(editor, editor.selection.getStart());
|
|
1150
|
-
const subsequentLists = filter$1(editor.selection.getSelectedBlocks(), isOlUlNode);
|
|
1151
|
-
return firstList.toArray().concat(subsequentLists);
|
|
1152
|
-
};
|
|
1153
|
-
const getParentLists = (editor) => {
|
|
1154
|
-
const elm = editor.selection.getStart();
|
|
1155
|
-
return editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
|
|
1156
|
-
};
|
|
1157
|
-
const getSelectedListRoots = (editor) => {
|
|
1158
|
-
const selectedLists = getSelectedLists(editor);
|
|
1159
|
-
const parentLists = getParentLists(editor);
|
|
1160
|
-
return find(parentLists, (p) => isListInsideAnLiWithFirstAndLastNotListElement(SugarElement.fromDom(p))).fold(() => getUniqueListRoots(editor, selectedLists), (l) => [l]);
|
|
1161
|
-
};
|
|
1162
|
-
const getUniqueListRoots = (editor, lists) => {
|
|
1163
|
-
const listRoots = map(lists, (list) => findLastParentListNode(editor, list).getOr(list));
|
|
1164
|
-
return unique(listRoots);
|
|
1165
|
-
};
|
|
1166
|
-
|
|
1167
|
-
const isCustomList = (list) => /\btox\-/.test(list.className);
|
|
1168
|
-
const inList = (parents, listName) => findUntil(parents, isListNode, isTableCellNode)
|
|
1169
|
-
.exists((list) => list.nodeName === listName && !isCustomList(list));
|
|
1170
|
-
// Advlist/core/ListUtils.ts - Duplicated in Advlist plugin
|
|
1171
|
-
const isWithinNonEditable = (editor, element) => element !== null && !editor.dom.isEditable(element);
|
|
1172
|
-
const selectionIsWithinNonEditableList = (editor) => {
|
|
1173
|
-
const parentList = getParentList(editor);
|
|
1174
|
-
return isWithinNonEditable(editor, parentList) || !editor.selection.isEditable();
|
|
1175
|
-
};
|
|
1176
|
-
const isWithinNonEditableList = (editor, element) => {
|
|
1177
|
-
const parentList = editor.dom.getParent(element, 'ol,ul,dl');
|
|
1178
|
-
return isWithinNonEditable(editor, parentList) || !editor.selection.isEditable();
|
|
1179
|
-
};
|
|
1180
|
-
const setNodeChangeHandler = (editor, nodeChangeHandler) => {
|
|
1181
|
-
const initialNode = editor.selection.getNode();
|
|
1182
|
-
// Set the initial state
|
|
1183
|
-
nodeChangeHandler({
|
|
1184
|
-
parents: editor.dom.getParents(initialNode),
|
|
1185
|
-
element: initialNode
|
|
1186
|
-
});
|
|
1187
|
-
editor.on('NodeChange', nodeChangeHandler);
|
|
1188
|
-
return () => editor.off('NodeChange', nodeChangeHandler);
|
|
1189
|
-
};
|
|
1190
|
-
|
|
1191
|
-
const fireListEvent = (editor, action, element) => editor.dispatch('ListMutation', { action, element });
|
|
1192
|
-
|
|
1193
|
-
const isList = (el) => is(el, 'OL,UL');
|
|
1194
|
-
const isListItem = (el) => is(el, 'LI');
|
|
1195
|
-
const hasFirstChildList = (el) => firstChild(el).exists(isList);
|
|
1196
|
-
const hasLastChildList = (el) => lastChild(el).exists(isList);
|
|
1197
|
-
|
|
1198
|
-
const isEntryList = (entry) => 'listAttributes' in entry;
|
|
1199
|
-
const isEntryComment = (entry) => 'isComment' in entry;
|
|
1200
|
-
const isEntryFragment = (entry) => 'isFragment' in entry;
|
|
1201
|
-
const isIndented = (entry) => entry.depth > 0;
|
|
1202
|
-
const isSelected = (entry) => entry.isSelected;
|
|
1203
|
-
const cloneItemContent = (li) => {
|
|
1204
|
-
const children$1 = children(li);
|
|
1205
|
-
const content = hasLastChildList(li) ? children$1.slice(0, -1) : children$1;
|
|
1206
|
-
return map(content, deep);
|
|
1207
|
-
};
|
|
1208
|
-
const createEntry = (li, depth, isSelected) => parent(li).filter(isElement$1).map((list) => ({
|
|
1209
|
-
depth,
|
|
1210
|
-
dirty: false,
|
|
1211
|
-
isSelected,
|
|
1212
|
-
content: cloneItemContent(li),
|
|
1213
|
-
itemAttributes: clone$1(li),
|
|
1214
|
-
listAttributes: clone$1(list),
|
|
1215
|
-
listType: name(list),
|
|
1216
|
-
isInPreviousLi: false
|
|
1217
|
-
}));
|
|
1218
|
-
|
|
1219
|
-
const joinSegment = (parent, child) => {
|
|
1220
|
-
append$1(parent.item, child.list);
|
|
1221
|
-
};
|
|
1222
|
-
const joinSegments = (segments) => {
|
|
1223
|
-
for (let i = 1; i < segments.length; i++) {
|
|
1224
|
-
joinSegment(segments[i - 1], segments[i]);
|
|
1225
|
-
}
|
|
1226
|
-
};
|
|
1227
|
-
const appendSegments = (head$1, tail) => {
|
|
1228
|
-
lift2(last(head$1), head(tail), joinSegment);
|
|
1229
|
-
};
|
|
1230
|
-
const createSegment = (scope, listType) => {
|
|
1231
|
-
const segment = {
|
|
1232
|
-
list: SugarElement.fromTag(listType, scope),
|
|
1233
|
-
item: SugarElement.fromTag('li', scope)
|
|
1234
|
-
};
|
|
1235
|
-
append$1(segment.list, segment.item);
|
|
1236
|
-
return segment;
|
|
1237
|
-
};
|
|
1238
|
-
const createSegments = (scope, entry, size) => {
|
|
1239
|
-
const segments = [];
|
|
1240
|
-
for (let i = 0; i < size; i++) {
|
|
1241
|
-
segments.push(createSegment(scope, isEntryList(entry) ? entry.listType : entry.parentListType));
|
|
1242
|
-
}
|
|
1243
|
-
return segments;
|
|
1244
|
-
};
|
|
1245
|
-
const populateSegments = (segments, entry) => {
|
|
1246
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
1247
|
-
set(segments[i].item, 'list-style-type', 'none');
|
|
1248
|
-
}
|
|
1249
|
-
last(segments).each((segment) => {
|
|
1250
|
-
if (isEntryList(entry)) {
|
|
1251
|
-
setAll(segment.list, entry.listAttributes);
|
|
1252
|
-
setAll(segment.item, entry.itemAttributes);
|
|
1253
|
-
}
|
|
1254
|
-
append(segment.item, entry.content);
|
|
1255
|
-
});
|
|
1256
|
-
};
|
|
1257
|
-
const normalizeSegment = (segment, entry) => {
|
|
1258
|
-
if (name(segment.list) !== entry.listType) {
|
|
1259
|
-
segment.list = mutate(segment.list, entry.listType);
|
|
1260
|
-
}
|
|
1261
|
-
setAll(segment.list, entry.listAttributes);
|
|
1262
|
-
};
|
|
1263
|
-
const createItem = (scope, attr, content) => {
|
|
1264
|
-
const item = SugarElement.fromTag('li', scope);
|
|
1265
|
-
setAll(item, attr);
|
|
1266
|
-
append(item, content);
|
|
1267
|
-
return item;
|
|
1268
|
-
};
|
|
1269
|
-
const appendItem = (segment, item) => {
|
|
1270
|
-
append$1(segment.list, item);
|
|
1271
|
-
segment.item = item;
|
|
1272
|
-
};
|
|
1273
|
-
const writeShallow = (scope, cast, entry) => {
|
|
1274
|
-
const newCast = cast.slice(0, entry.depth);
|
|
1275
|
-
last(newCast).each((segment) => {
|
|
1276
|
-
if (isEntryList(entry)) {
|
|
1277
|
-
const item = createItem(scope, entry.itemAttributes, entry.content);
|
|
1278
|
-
appendItem(segment, item);
|
|
1279
|
-
normalizeSegment(segment, entry);
|
|
1280
|
-
}
|
|
1281
|
-
else if (isEntryFragment(entry)) {
|
|
1282
|
-
append(segment.item, entry.content);
|
|
1283
|
-
}
|
|
1284
|
-
else {
|
|
1285
|
-
const item = SugarElement.fromHtml(`<!--${entry.content}-->`);
|
|
1286
|
-
append$1(segment.list, item);
|
|
1287
|
-
}
|
|
1288
|
-
});
|
|
1289
|
-
return newCast;
|
|
1290
|
-
};
|
|
1291
|
-
const writeDeep = (scope, cast, entry) => {
|
|
1292
|
-
const segments = createSegments(scope, entry, entry.depth - cast.length);
|
|
1293
|
-
joinSegments(segments);
|
|
1294
|
-
populateSegments(segments, entry);
|
|
1295
|
-
appendSegments(cast, segments);
|
|
1296
|
-
return cast.concat(segments);
|
|
1297
|
-
};
|
|
1298
|
-
const composeList = (scope, entries) => {
|
|
1299
|
-
let firstCommentEntryOpt = Optional.none();
|
|
1300
|
-
const cast = foldl(entries, (cast, entry, i) => {
|
|
1301
|
-
if (!isEntryComment(entry)) {
|
|
1302
|
-
return entry.depth > cast.length ? writeDeep(scope, cast, entry) : writeShallow(scope, cast, entry);
|
|
1303
|
-
}
|
|
1304
|
-
else {
|
|
1305
|
-
// this is needed becuase if the first element of the list is a comment we would not have the data to create the new list
|
|
1306
|
-
if (i === 0) {
|
|
1307
|
-
firstCommentEntryOpt = Optional.some(entry);
|
|
1308
|
-
return cast;
|
|
1309
|
-
}
|
|
1310
|
-
return writeShallow(scope, cast, entry);
|
|
1311
|
-
}
|
|
1312
|
-
}, []);
|
|
1313
|
-
firstCommentEntryOpt.each((firstCommentEntry) => {
|
|
1314
|
-
const item = SugarElement.fromHtml(`<!--${firstCommentEntry.content}-->`);
|
|
1315
|
-
head(cast).each((fistCast) => {
|
|
1316
|
-
prepend(fistCast.list, item);
|
|
1317
|
-
});
|
|
1318
|
-
});
|
|
1319
|
-
return head(cast).map((segment) => segment.list);
|
|
1320
|
-
};
|
|
1321
|
-
|
|
1322
|
-
const indentEntry = (indentation, entry) => {
|
|
1323
|
-
switch (indentation) {
|
|
1324
|
-
case "Indent" /* Indentation.Indent */:
|
|
1325
|
-
entry.depth++;
|
|
1326
|
-
break;
|
|
1327
|
-
case "Outdent" /* Indentation.Outdent */:
|
|
1328
|
-
entry.depth--;
|
|
1329
|
-
break;
|
|
1330
|
-
case "Flatten" /* Indentation.Flatten */:
|
|
1331
|
-
entry.depth = 0;
|
|
1332
|
-
}
|
|
1333
|
-
entry.dirty = true;
|
|
1334
|
-
};
|
|
1335
|
-
|
|
1336
|
-
const cloneListProperties = (target, source) => {
|
|
1337
|
-
if (isEntryList(target) && isEntryList(source)) {
|
|
1338
|
-
target.listType = source.listType;
|
|
1339
|
-
target.listAttributes = { ...source.listAttributes };
|
|
1340
|
-
}
|
|
1341
|
-
};
|
|
1342
|
-
const cleanListProperties = (entry) => {
|
|
1343
|
-
// Remove the start attribute if generating a new list
|
|
1344
|
-
entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== 'start');
|
|
1345
|
-
};
|
|
1346
|
-
// Closest entry above/below in the same list
|
|
1347
|
-
const closestSiblingEntry = (entries, start) => {
|
|
1348
|
-
const depth = entries[start].depth;
|
|
1349
|
-
// Ignore dirty items as they've been moved and won't have the right list data yet
|
|
1350
|
-
const matches = (entry) => entry.depth === depth && !entry.dirty;
|
|
1351
|
-
const until = (entry) => entry.depth < depth;
|
|
1352
|
-
// Check in reverse to see if there's an entry as the same depth before the current entry
|
|
1353
|
-
// but if not, then try to walk forwards as well
|
|
1354
|
-
return findUntil(reverse(entries.slice(0, start)), matches, until)
|
|
1355
|
-
.orThunk(() => findUntil(entries.slice(start + 1), matches, until));
|
|
1356
|
-
};
|
|
1357
|
-
const normalizeEntries = (entries) => {
|
|
1358
|
-
each$1(entries, (entry, i) => {
|
|
1359
|
-
closestSiblingEntry(entries, i).fold(() => {
|
|
1360
|
-
if (entry.dirty && isEntryList(entry)) {
|
|
1361
|
-
cleanListProperties(entry);
|
|
1362
|
-
}
|
|
1363
|
-
}, (matchingEntry) => cloneListProperties(entry, matchingEntry));
|
|
1364
|
-
});
|
|
1365
|
-
return entries;
|
|
1366
|
-
};
|
|
1367
|
-
|
|
1368
|
-
const parseSingleItem = (depth, itemSelection, selectionState, item) => {
|
|
1369
|
-
var _a;
|
|
1370
|
-
if (isComment(item)) {
|
|
1371
|
-
return [{
|
|
1372
|
-
depth: depth + 1,
|
|
1373
|
-
content: (_a = item.dom.nodeValue) !== null && _a !== void 0 ? _a : '',
|
|
1374
|
-
dirty: false,
|
|
1375
|
-
isSelected: false,
|
|
1376
|
-
isComment: true
|
|
1377
|
-
}];
|
|
1378
|
-
}
|
|
1379
|
-
itemSelection.each((selection) => {
|
|
1380
|
-
if (eq(selection.start, item)) {
|
|
1381
|
-
selectionState.set(true);
|
|
1382
|
-
}
|
|
1383
|
-
});
|
|
1384
|
-
const currentItemEntry = createEntry(item, depth, selectionState.get());
|
|
1385
|
-
// Update selectionState (end)
|
|
1386
|
-
itemSelection.each((selection) => {
|
|
1387
|
-
if (eq(selection.end, item)) {
|
|
1388
|
-
selectionState.set(false);
|
|
1389
|
-
}
|
|
1390
|
-
});
|
|
1391
|
-
const childListEntries = lastChild(item)
|
|
1392
|
-
.filter(isList)
|
|
1393
|
-
.map((list) => parseList(depth, itemSelection, selectionState, list))
|
|
1394
|
-
.getOr([]);
|
|
1395
|
-
return currentItemEntry.toArray().concat(childListEntries);
|
|
1396
|
-
};
|
|
1397
|
-
const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => parseSingleItem(depth, itemSelection, selectionState, item), (list) => {
|
|
1398
|
-
const parsedSiblings = foldl(children(item), (acc, liChild, i) => {
|
|
1399
|
-
if (i === 0) {
|
|
1400
|
-
return acc;
|
|
1401
|
-
}
|
|
1402
|
-
else {
|
|
1403
|
-
if (isListItem(liChild)) {
|
|
1404
|
-
return acc.concat(parseSingleItem(depth, itemSelection, selectionState, liChild));
|
|
1405
|
-
}
|
|
1406
|
-
else {
|
|
1407
|
-
const fragment = {
|
|
1408
|
-
isFragment: true,
|
|
1409
|
-
depth,
|
|
1410
|
-
content: [liChild],
|
|
1411
|
-
isSelected: false,
|
|
1412
|
-
dirty: false,
|
|
1413
|
-
parentListType: name(list)
|
|
1414
|
-
};
|
|
1415
|
-
return acc.concat(fragment);
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
}, []);
|
|
1419
|
-
return parseList(depth, itemSelection, selectionState, list).concat(parsedSiblings);
|
|
1420
|
-
});
|
|
1421
|
-
const parseList = (depth, itemSelection, selectionState, list) => bind(children(list), (element) => {
|
|
1422
|
-
const parser = isList(element) ? parseList : parseItem;
|
|
1423
|
-
const newDepth = depth + 1;
|
|
1424
|
-
return parser(newDepth, itemSelection, selectionState, element);
|
|
1425
|
-
});
|
|
1426
|
-
const parseLists = (lists, itemSelection) => {
|
|
1427
|
-
const selectionState = Cell(false);
|
|
1428
|
-
const initialDepth = 0;
|
|
1429
|
-
return map(lists, (list) => ({
|
|
1430
|
-
sourceList: list,
|
|
1431
|
-
entries: parseList(initialDepth, itemSelection, selectionState, list)
|
|
1432
|
-
}));
|
|
1433
|
-
};
|
|
1434
|
-
|
|
1435
|
-
const outdentedComposer = (editor, entries) => {
|
|
1436
|
-
const normalizedEntries = normalizeEntries(entries);
|
|
1437
|
-
return map(normalizedEntries, (entry) => {
|
|
1438
|
-
const content = !isEntryComment(entry)
|
|
1439
|
-
? fromElements(entry.content)
|
|
1440
|
-
: fromElements([SugarElement.fromHtml(`<!--${entry.content}-->`)]);
|
|
1441
|
-
const listItemAttrs = isEntryList(entry) ? entry.itemAttributes : {};
|
|
1442
|
-
return SugarElement.fromDom(createTextBlock(editor, content.dom, listItemAttrs));
|
|
1443
|
-
});
|
|
1444
|
-
};
|
|
1445
|
-
const indentedComposer = (editor, entries) => {
|
|
1446
|
-
const normalizedEntries = normalizeEntries(entries);
|
|
1447
|
-
return composeList(editor.contentDocument, normalizedEntries).toArray();
|
|
1448
|
-
};
|
|
1449
|
-
const composeEntries = (editor, entries) => bind(groupBy(entries, isIndented), (entries) => {
|
|
1450
|
-
const groupIsIndented = head(entries).exists(isIndented);
|
|
1451
|
-
return groupIsIndented ? indentedComposer(editor, entries) : outdentedComposer(editor, entries);
|
|
1452
|
-
});
|
|
1453
|
-
const indentSelectedEntries = (entries, indentation) => {
|
|
1454
|
-
each$1(filter$1(entries, isSelected), (entry) => indentEntry(indentation, entry));
|
|
1455
|
-
};
|
|
1456
|
-
const getItemSelection = (editor) => {
|
|
1457
|
-
const selectedListItems = map(getSelectedListItems(editor), SugarElement.fromDom);
|
|
1458
|
-
return lift2(find(selectedListItems, not(hasFirstChildList)), find(reverse(selectedListItems), not(hasFirstChildList)), (start, end) => ({ start, end }));
|
|
1459
|
-
};
|
|
1460
|
-
const listIndentation = (editor, lists, indentation) => {
|
|
1461
|
-
const entrySets = parseLists(lists, getItemSelection(editor));
|
|
1462
|
-
each$1(entrySets, (entrySet) => {
|
|
1463
|
-
indentSelectedEntries(entrySet.entries, indentation);
|
|
1464
|
-
const composedLists = composeEntries(editor, entrySet.entries);
|
|
1465
|
-
each$1(composedLists, (composedList) => {
|
|
1466
|
-
fireListEvent(editor, indentation === "Indent" /* Indentation.Indent */ ? "IndentList" /* ListAction.IndentList */ : "OutdentList" /* ListAction.OutdentList */, composedList.dom);
|
|
1467
|
-
});
|
|
1468
|
-
before(entrySet.sourceList, composedLists);
|
|
1469
|
-
remove(entrySet.sourceList);
|
|
1470
|
-
});
|
|
1471
|
-
};
|
|
1472
|
-
|
|
1473
|
-
const selectionIndentation = (editor, indentation) => {
|
|
1474
|
-
const lists = fromDom(getSelectedListRoots(editor));
|
|
1475
|
-
const dlItems = fromDom(getSelectedDlItems(editor));
|
|
1476
|
-
let isHandled = false;
|
|
1477
|
-
if (lists.length || dlItems.length) {
|
|
1478
|
-
const bookmark = editor.selection.getBookmark();
|
|
1479
|
-
listIndentation(editor, lists, indentation);
|
|
1480
|
-
dlIndentation(editor, indentation, dlItems);
|
|
1481
|
-
editor.selection.moveToBookmark(bookmark);
|
|
1482
|
-
editor.selection.setRng(normalizeRange(editor.selection.getRng()));
|
|
1483
|
-
editor.nodeChanged();
|
|
1484
|
-
isHandled = true;
|
|
1485
|
-
}
|
|
1486
|
-
return isHandled;
|
|
1487
|
-
};
|
|
1488
|
-
const handleIndentation = (editor, indentation) => !selectionIsWithinNonEditableList(editor) && selectionIndentation(editor, indentation);
|
|
1489
|
-
const indentListSelection = (editor) => handleIndentation(editor, "Indent" /* Indentation.Indent */);
|
|
1490
|
-
const outdentListSelection = (editor) => handleIndentation(editor, "Outdent" /* Indentation.Outdent */);
|
|
1491
|
-
const flattenListSelection = (editor) => handleIndentation(editor, "Flatten" /* Indentation.Flatten */);
|
|
1492
|
-
|
|
1493
|
-
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.BookmarkManager');
|
|
1494
|
-
|
|
1495
|
-
const DOM$1 = global$3.DOM;
|
|
1496
|
-
/**
|
|
1497
|
-
* Returns a range bookmark. This will convert indexed bookmarks into temporary span elements with
|
|
1498
|
-
* index 0 so that they can be restored properly after the DOM has been modified. Text bookmarks will not have spans
|
|
1499
|
-
* added to them since they can be restored after a dom operation.
|
|
1500
|
-
*
|
|
1501
|
-
* So this: <p><b>|</b><b>|</b></p>
|
|
1502
|
-
* becomes: <p><b><span data-mce-type="bookmark">|</span></b><b data-mce-type="bookmark">|</span></b></p>
|
|
1503
|
-
*
|
|
1504
|
-
* @param {DOMRange} rng DOM Range to get bookmark on.
|
|
1505
|
-
* @return {Object} Bookmark object.
|
|
1506
|
-
*/
|
|
1507
|
-
const createBookmark = (rng) => {
|
|
1508
|
-
const bookmark = {};
|
|
1509
|
-
const setupEndPoint = (start) => {
|
|
1510
|
-
let container = rng[start ? 'startContainer' : 'endContainer'];
|
|
1511
|
-
let offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
1512
|
-
if (isElement(container)) {
|
|
1513
|
-
const offsetNode = DOM$1.create('span', { 'data-mce-type': 'bookmark' });
|
|
1514
|
-
if (container.hasChildNodes()) {
|
|
1515
|
-
offset = Math.min(offset, container.childNodes.length - 1);
|
|
1516
|
-
if (start) {
|
|
1517
|
-
container.insertBefore(offsetNode, container.childNodes[offset]);
|
|
1518
|
-
}
|
|
1519
|
-
else {
|
|
1520
|
-
DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
else {
|
|
1524
|
-
container.appendChild(offsetNode);
|
|
1525
|
-
}
|
|
1526
|
-
container = offsetNode;
|
|
1527
|
-
offset = 0;
|
|
1528
|
-
}
|
|
1529
|
-
bookmark[start ? 'startContainer' : 'endContainer'] = container;
|
|
1530
|
-
bookmark[start ? 'startOffset' : 'endOffset'] = offset;
|
|
1531
|
-
};
|
|
1532
|
-
setupEndPoint(true);
|
|
1533
|
-
if (!rng.collapsed) {
|
|
1534
|
-
setupEndPoint();
|
|
1535
|
-
}
|
|
1536
|
-
return bookmark;
|
|
1537
|
-
};
|
|
1538
|
-
const resolveBookmark = (bookmark) => {
|
|
1539
|
-
const restoreEndPoint = (start) => {
|
|
1540
|
-
const nodeIndex = (container) => {
|
|
1541
|
-
var _a;
|
|
1542
|
-
let node = (_a = container.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild;
|
|
1543
|
-
let idx = 0;
|
|
1544
|
-
while (node) {
|
|
1545
|
-
if (node === container) {
|
|
1546
|
-
return idx;
|
|
1547
|
-
}
|
|
1548
|
-
// Skip data-mce-type=bookmark nodes
|
|
1549
|
-
if (!isElement(node) || node.getAttribute('data-mce-type') !== 'bookmark') {
|
|
1550
|
-
idx++;
|
|
1551
|
-
}
|
|
1552
|
-
node = node.nextSibling;
|
|
1553
|
-
}
|
|
1554
|
-
return -1;
|
|
1555
|
-
};
|
|
1556
|
-
let container = bookmark[start ? 'startContainer' : 'endContainer'];
|
|
1557
|
-
let offset = bookmark[start ? 'startOffset' : 'endOffset'];
|
|
1558
|
-
if (!container) {
|
|
1559
|
-
return;
|
|
1560
|
-
}
|
|
1561
|
-
if (isElement(container) && container.parentNode) {
|
|
1562
|
-
const node = container;
|
|
1563
|
-
offset = nodeIndex(container);
|
|
1564
|
-
container = container.parentNode;
|
|
1565
|
-
DOM$1.remove(node);
|
|
1566
|
-
if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
|
|
1567
|
-
container.appendChild(DOM$1.create('br'));
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
bookmark[start ? 'startContainer' : 'endContainer'] = container;
|
|
1571
|
-
bookmark[start ? 'startOffset' : 'endOffset'] = offset;
|
|
1572
|
-
};
|
|
1573
|
-
restoreEndPoint(true);
|
|
1574
|
-
restoreEndPoint();
|
|
1575
|
-
const rng = DOM$1.createRng();
|
|
1576
|
-
rng.setStart(bookmark.startContainer, bookmark.startOffset);
|
|
1577
|
-
if (bookmark.endContainer) {
|
|
1578
|
-
rng.setEnd(bookmark.endContainer, bookmark.endOffset);
|
|
1579
|
-
}
|
|
1580
|
-
return normalizeRange(rng);
|
|
1581
|
-
};
|
|
1582
|
-
|
|
1583
|
-
const listToggleActionFromListName = (listName) => {
|
|
1584
|
-
switch (listName) {
|
|
1585
|
-
case 'UL': return "ToggleUlList" /* ListAction.ToggleUlList */;
|
|
1586
|
-
case 'OL': return "ToggleOlList" /* ListAction.ToggleOlList */;
|
|
1587
|
-
case 'DL': return "ToggleDLList" /* ListAction.ToggleDLList */;
|
|
1588
|
-
}
|
|
1589
|
-
};
|
|
1590
|
-
|
|
1591
|
-
const updateListStyle = (dom, el, detail) => {
|
|
1592
|
-
const type = detail['list-style-type'] ? detail['list-style-type'] : null;
|
|
1593
|
-
dom.setStyle(el, 'list-style-type', type);
|
|
1594
|
-
};
|
|
1595
|
-
const setAttribs = (elm, attrs) => {
|
|
1596
|
-
global$2.each(attrs, (value, key) => {
|
|
1597
|
-
elm.setAttribute(key, value);
|
|
1598
|
-
});
|
|
1599
|
-
};
|
|
1600
|
-
const updateListAttrs = (dom, el, detail) => {
|
|
1601
|
-
setAttribs(el, detail['list-attributes']);
|
|
1602
|
-
global$2.each(dom.select('li', el), (li) => {
|
|
1603
|
-
setAttribs(li, detail['list-item-attributes']);
|
|
1604
|
-
});
|
|
1605
|
-
};
|
|
1606
|
-
const updateListWithDetails = (dom, el, detail) => {
|
|
1607
|
-
updateListStyle(dom, el, detail);
|
|
1608
|
-
updateListAttrs(dom, el, detail);
|
|
1609
|
-
};
|
|
1610
|
-
const removeStyles = (dom, element, styles) => {
|
|
1611
|
-
global$2.each(styles, (style) => dom.setStyle(element, style, ''));
|
|
1612
|
-
};
|
|
1613
|
-
const isInline = (editor, node) => isNonNullable(node) && !isBlock(node, editor.schema.getBlockElements());
|
|
1614
|
-
const getEndPointNode = (editor, rng, start, root) => {
|
|
1615
|
-
let container = rng[start ? 'startContainer' : 'endContainer'];
|
|
1616
|
-
const offset = rng[start ? 'startOffset' : 'endOffset'];
|
|
1617
|
-
// Resolve node index
|
|
1618
|
-
if (isElement(container)) {
|
|
1619
|
-
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
|
1620
|
-
}
|
|
1621
|
-
if (!start && isBr(container.nextSibling)) {
|
|
1622
|
-
container = container.nextSibling;
|
|
1623
|
-
}
|
|
1624
|
-
const findBlockAncestor = (node) => {
|
|
1625
|
-
while (!editor.dom.isBlock(node) && node.parentNode && root !== node) {
|
|
1626
|
-
node = node.parentNode;
|
|
1627
|
-
}
|
|
1628
|
-
return node;
|
|
1629
|
-
};
|
|
1630
|
-
// The reason why the next two if statements exist is because when the root node is a table cell (possibly some other node types)
|
|
1631
|
-
// then the highest we can go up the dom hierarchy is one level below the table cell.
|
|
1632
|
-
// So what happens when we have a bunch of inline nodes and text nodes in the table cell
|
|
1633
|
-
// and when the selection is collapsed inside one of the inline nodes then only that inline node (or text node) will be included
|
|
1634
|
-
// in the created list because that would be one level below td node and the other inline nodes won't be included.
|
|
1635
|
-
// So the fix proposed is to traverse left when looking for start node (and traverse right when looking for end node)
|
|
1636
|
-
// and keep traversing as long as we have an inline or text node (same for traversing right).
|
|
1637
|
-
// This way we end up including all the inline elements in the created list.
|
|
1638
|
-
// For more info look at #TINY-6853
|
|
1639
|
-
const findBetterContainer = (container, forward) => {
|
|
1640
|
-
var _a;
|
|
1641
|
-
const walker = new global$5(container, findBlockAncestor(container));
|
|
1642
|
-
const dir = forward ? 'next' : 'prev';
|
|
1643
|
-
let node;
|
|
1644
|
-
while ((node = walker[dir]())) {
|
|
1645
|
-
if (!(isVoid(editor, node) || isZwsp(node.textContent) || ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length) === 0)) {
|
|
1646
|
-
return Optional.some(node);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
return Optional.none();
|
|
1650
|
-
};
|
|
1651
|
-
// Traverse left to include inline/text nodes
|
|
1652
|
-
if (start && isTextNode$1(container)) {
|
|
1653
|
-
if (isZwsp(container.textContent)) {
|
|
1654
|
-
container = findBetterContainer(container, false).getOr(container);
|
|
1655
|
-
}
|
|
1656
|
-
else {
|
|
1657
|
-
if (container.parentNode !== null && isInline(editor, container.parentNode)) {
|
|
1658
|
-
container = container.parentNode;
|
|
1659
|
-
}
|
|
1660
|
-
while (container.previousSibling !== null && (isInline(editor, container.previousSibling) || isTextNode$1(container.previousSibling))) {
|
|
1661
|
-
container = container.previousSibling;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
// Traverse right to include inline/text nodes
|
|
1666
|
-
if (!start && isTextNode$1(container)) {
|
|
1667
|
-
if (isZwsp(container.textContent)) {
|
|
1668
|
-
container = findBetterContainer(container, true).getOr(container);
|
|
1669
|
-
}
|
|
1670
|
-
else {
|
|
1671
|
-
if (container.parentNode !== null && isInline(editor, container.parentNode)) {
|
|
1672
|
-
container = container.parentNode;
|
|
1673
|
-
}
|
|
1674
|
-
while (container.nextSibling !== null && (isInline(editor, container.nextSibling) || isTextNode$1(container.nextSibling))) {
|
|
1675
|
-
container = container.nextSibling;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
while (container.parentNode !== root) {
|
|
1680
|
-
const parent = container.parentNode;
|
|
1681
|
-
if (isTextBlock(editor, container)) {
|
|
1682
|
-
return container;
|
|
1683
|
-
}
|
|
1684
|
-
if (/^(TD|TH)$/.test(parent.nodeName)) {
|
|
1685
|
-
return container;
|
|
1686
|
-
}
|
|
1687
|
-
container = parent;
|
|
1688
|
-
}
|
|
1689
|
-
return container;
|
|
1690
|
-
};
|
|
1691
|
-
const getSelectedTextBlocks = (editor, rng, root) => {
|
|
1692
|
-
const textBlocks = [];
|
|
1693
|
-
const dom = editor.dom;
|
|
1694
|
-
const startNode = getEndPointNode(editor, rng, true, root);
|
|
1695
|
-
const endNode = getEndPointNode(editor, rng, false, root);
|
|
1696
|
-
let block;
|
|
1697
|
-
const siblings = [];
|
|
1698
|
-
for (let node = startNode; node; node = node.nextSibling) {
|
|
1699
|
-
siblings.push(node);
|
|
1700
|
-
if (node === endNode) {
|
|
1701
|
-
break;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
global$2.each(siblings, (node) => {
|
|
1705
|
-
var _a;
|
|
1706
|
-
if (isTextBlock(editor, node)) {
|
|
1707
|
-
textBlocks.push(node);
|
|
1708
|
-
block = null;
|
|
1709
|
-
return;
|
|
1710
|
-
}
|
|
1711
|
-
if (dom.isBlock(node) || isBr(node)) {
|
|
1712
|
-
if (isBr(node)) {
|
|
1713
|
-
dom.remove(node);
|
|
1714
|
-
}
|
|
1715
|
-
block = null;
|
|
1716
|
-
return;
|
|
1717
|
-
}
|
|
1718
|
-
const nextSibling = node.nextSibling;
|
|
1719
|
-
if (global$1.isBookmarkNode(node)) {
|
|
1720
|
-
if (isListNode(nextSibling) || isTextBlock(editor, nextSibling) || (!nextSibling && node.parentNode === root)) {
|
|
1721
|
-
block = null;
|
|
1722
|
-
return;
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
if (!block) {
|
|
1726
|
-
block = dom.create('p');
|
|
1727
|
-
(_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(block, node);
|
|
1728
|
-
textBlocks.push(block);
|
|
1729
|
-
}
|
|
1730
|
-
block.appendChild(node);
|
|
1731
|
-
});
|
|
1732
|
-
return textBlocks;
|
|
1733
|
-
};
|
|
1734
|
-
const hasCompatibleStyle = (dom, sib, detail) => {
|
|
1735
|
-
const sibStyle = dom.getStyle(sib, 'list-style-type');
|
|
1736
|
-
let detailStyle = detail ? detail['list-style-type'] : '';
|
|
1737
|
-
detailStyle = detailStyle === null ? '' : detailStyle;
|
|
1738
|
-
return sibStyle === detailStyle;
|
|
1739
|
-
};
|
|
1740
|
-
/*
|
|
1741
|
-
Find the first element we would transform into a li-element if given no constraints.
|
|
1742
|
-
If the common ancestor is higher up than that provide it as the starting-point for the search for the root instead of the first selected element.
|
|
1743
|
-
This helps avoid issues with divs that should become li-elements are detected as the root when they should not be.
|
|
1744
|
-
*/
|
|
1745
|
-
const getRootSearchStart = (editor, range) => {
|
|
1746
|
-
const start = editor.selection.getStart(true);
|
|
1747
|
-
const startPoint = getEndPointNode(editor, range, true, editor.getBody());
|
|
1748
|
-
if (ancestor(SugarElement.fromDom(startPoint), SugarElement.fromDom(range.commonAncestorContainer))) {
|
|
1749
|
-
return range.commonAncestorContainer;
|
|
1750
|
-
}
|
|
1751
|
-
else {
|
|
1752
|
-
return start;
|
|
1753
|
-
}
|
|
1754
|
-
};
|
|
1755
|
-
const applyList = (editor, listName, detail) => {
|
|
1756
|
-
const rng = editor.selection.getRng();
|
|
1757
|
-
let listItemName = 'LI';
|
|
1758
|
-
const root = getClosestListHost(editor, getRootSearchStart(editor, rng));
|
|
1759
|
-
const dom = editor.dom;
|
|
1760
|
-
if (dom.getContentEditable(editor.selection.getNode()) === 'false') {
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
|
-
listName = listName.toUpperCase();
|
|
1764
|
-
if (listName === 'DL') {
|
|
1765
|
-
listItemName = 'DT';
|
|
1766
|
-
}
|
|
1767
|
-
const bookmark = createBookmark(rng);
|
|
1768
|
-
const selectedTextBlocks = filter$1(getSelectedTextBlocks(editor, rng, root), editor.dom.isEditable);
|
|
1769
|
-
global$2.each(selectedTextBlocks, (block) => {
|
|
1770
|
-
let listBlock;
|
|
1771
|
-
const sibling = block.previousSibling;
|
|
1772
|
-
const parent = block.parentNode;
|
|
1773
|
-
if (!isListItemNode(parent)) {
|
|
1774
|
-
if (sibling && isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(dom, sibling, detail)) {
|
|
1775
|
-
listBlock = sibling;
|
|
1776
|
-
block = dom.rename(block, listItemName);
|
|
1777
|
-
sibling.appendChild(block);
|
|
1778
|
-
}
|
|
1779
|
-
else {
|
|
1780
|
-
listBlock = dom.create(listName);
|
|
1781
|
-
parent.insertBefore(listBlock, block);
|
|
1782
|
-
listBlock.appendChild(block);
|
|
1783
|
-
block = dom.rename(block, listItemName);
|
|
1784
|
-
}
|
|
1785
|
-
removeStyles(dom, block, [
|
|
1786
|
-
'margin', 'margin-right', 'margin-bottom', 'margin-left', 'margin-top',
|
|
1787
|
-
'padding', 'padding-right', 'padding-bottom', 'padding-left', 'padding-top'
|
|
1788
|
-
]);
|
|
1789
|
-
updateListWithDetails(dom, listBlock, detail);
|
|
1790
|
-
mergeWithAdjacentLists(editor.dom, listBlock);
|
|
1791
|
-
}
|
|
1792
|
-
});
|
|
1793
|
-
editor.selection.setRng(resolveBookmark(bookmark));
|
|
1794
|
-
};
|
|
1795
|
-
const isValidLists = (list1, list2) => {
|
|
1796
|
-
return isListNode(list1) && list1.nodeName === (list2 === null || list2 === void 0 ? void 0 : list2.nodeName);
|
|
1797
|
-
};
|
|
1798
|
-
const hasSameListStyle = (dom, list1, list2) => {
|
|
1799
|
-
const targetStyle = dom.getStyle(list1, 'list-style-type', true);
|
|
1800
|
-
const style = dom.getStyle(list2, 'list-style-type', true);
|
|
1801
|
-
return targetStyle === style;
|
|
1802
|
-
};
|
|
1803
|
-
const hasSameClasses = (elm1, elm2) => {
|
|
1804
|
-
return elm1.className === elm2.className;
|
|
1805
|
-
};
|
|
1806
|
-
const shouldMerge = (dom, list1, list2) => {
|
|
1807
|
-
return isValidLists(list1, list2) &&
|
|
1808
|
-
// Note: isValidLists will ensure list1 and list2 are a HTMLElement. Unfortunately TypeScript doesn't
|
|
1809
|
-
// support type guards on multiple variables. See https://github.com/microsoft/TypeScript/issues/26916
|
|
1810
|
-
hasSameListStyle(dom, list1, list2) &&
|
|
1811
|
-
hasSameClasses(list1, list2);
|
|
1812
|
-
};
|
|
1813
|
-
const mergeWithAdjacentLists = (dom, listBlock) => {
|
|
1814
|
-
let node;
|
|
1815
|
-
let sibling = listBlock.nextSibling;
|
|
1816
|
-
if (shouldMerge(dom, listBlock, sibling)) {
|
|
1817
|
-
const liSibling = sibling;
|
|
1818
|
-
while ((node = liSibling.firstChild)) {
|
|
1819
|
-
listBlock.appendChild(node);
|
|
1820
|
-
}
|
|
1821
|
-
dom.remove(liSibling);
|
|
1822
|
-
}
|
|
1823
|
-
sibling = listBlock.previousSibling;
|
|
1824
|
-
if (shouldMerge(dom, listBlock, sibling)) {
|
|
1825
|
-
const liSibling = sibling;
|
|
1826
|
-
while ((node = liSibling.lastChild)) {
|
|
1827
|
-
listBlock.insertBefore(node, listBlock.firstChild);
|
|
1828
|
-
}
|
|
1829
|
-
dom.remove(liSibling);
|
|
1830
|
-
}
|
|
1831
|
-
};
|
|
1832
|
-
const updateList$1 = (editor, list, listName, detail) => {
|
|
1833
|
-
if (list.nodeName !== listName) {
|
|
1834
|
-
const newList = editor.dom.rename(list, listName);
|
|
1835
|
-
updateListWithDetails(editor.dom, newList, detail);
|
|
1836
|
-
fireListEvent(editor, listToggleActionFromListName(listName), newList);
|
|
1837
|
-
}
|
|
1838
|
-
else {
|
|
1839
|
-
updateListWithDetails(editor.dom, list, detail);
|
|
1840
|
-
fireListEvent(editor, listToggleActionFromListName(listName), list);
|
|
1841
|
-
}
|
|
1842
|
-
};
|
|
1843
|
-
const updateCustomList = (editor, list, listName, detail) => {
|
|
1844
|
-
list.classList.forEach((cls, _, classList) => {
|
|
1845
|
-
if (cls.startsWith('tox-')) {
|
|
1846
|
-
classList.remove(cls);
|
|
1847
|
-
if (classList.length === 0) {
|
|
1848
|
-
list.removeAttribute('class');
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
});
|
|
1852
|
-
if (list.nodeName !== listName) {
|
|
1853
|
-
const newList = editor.dom.rename(list, listName);
|
|
1854
|
-
updateListWithDetails(editor.dom, newList, detail);
|
|
1855
|
-
fireListEvent(editor, listToggleActionFromListName(listName), newList);
|
|
1856
|
-
}
|
|
1857
|
-
else {
|
|
1858
|
-
updateListWithDetails(editor.dom, list, detail);
|
|
1859
|
-
fireListEvent(editor, listToggleActionFromListName(listName), list);
|
|
1860
|
-
}
|
|
1861
|
-
};
|
|
1862
|
-
const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
|
|
1863
|
-
const parentIsList = isListNode(parentList);
|
|
1864
|
-
if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
|
|
1865
|
-
flattenListSelection(editor);
|
|
1866
|
-
}
|
|
1867
|
-
else {
|
|
1868
|
-
applyList(editor, listName, detail);
|
|
1869
|
-
const bookmark = createBookmark(editor.selection.getRng());
|
|
1870
|
-
const allLists = parentIsList ? [parentList, ...lists] : lists;
|
|
1871
|
-
const updateFunction = (parentIsList && isCustomList(parentList)) ? updateCustomList : updateList$1;
|
|
1872
|
-
global$2.each(allLists, (elm) => {
|
|
1873
|
-
updateFunction(editor, elm, listName, detail);
|
|
1874
|
-
});
|
|
1875
|
-
editor.selection.setRng(resolveBookmark(bookmark));
|
|
1876
|
-
}
|
|
1877
|
-
};
|
|
1878
|
-
const hasListStyleDetail = (detail) => {
|
|
1879
|
-
return 'list-style-type' in detail;
|
|
1880
|
-
};
|
|
1881
|
-
const toggleSingleList = (editor, parentList, listName, detail) => {
|
|
1882
|
-
if (parentList === editor.getBody()) {
|
|
1883
|
-
return;
|
|
1884
|
-
}
|
|
1885
|
-
if (parentList) {
|
|
1886
|
-
if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
|
|
1887
|
-
flattenListSelection(editor);
|
|
1888
|
-
}
|
|
1889
|
-
else {
|
|
1890
|
-
const bookmark = createBookmark(editor.selection.getRng());
|
|
1891
|
-
if (isCustomList(parentList)) {
|
|
1892
|
-
parentList.classList.forEach((cls, _, classList) => {
|
|
1893
|
-
if (cls.startsWith('tox-')) {
|
|
1894
|
-
classList.remove(cls);
|
|
1895
|
-
if (classList.length === 0) {
|
|
1896
|
-
parentList.removeAttribute('class');
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
|
-
});
|
|
1900
|
-
}
|
|
1901
|
-
updateListWithDetails(editor.dom, parentList, detail);
|
|
1902
|
-
const newList = editor.dom.rename(parentList, listName);
|
|
1903
|
-
mergeWithAdjacentLists(editor.dom, newList);
|
|
1904
|
-
editor.selection.setRng(resolveBookmark(bookmark));
|
|
1905
|
-
applyList(editor, listName, detail);
|
|
1906
|
-
fireListEvent(editor, listToggleActionFromListName(listName), newList);
|
|
1907
|
-
}
|
|
1908
|
-
}
|
|
1909
|
-
else {
|
|
1910
|
-
applyList(editor, listName, detail);
|
|
1911
|
-
fireListEvent(editor, listToggleActionFromListName(listName), parentList);
|
|
1912
|
-
}
|
|
1913
|
-
};
|
|
1914
|
-
const toggleList = (editor, listName, _detail) => {
|
|
1915
|
-
const parentList = getParentList(editor);
|
|
1916
|
-
if (isWithinNonEditableList(editor, parentList)) {
|
|
1917
|
-
return;
|
|
1918
|
-
}
|
|
1919
|
-
const selectedSubLists = getSelectedSubLists(editor);
|
|
1920
|
-
const detail = isObject(_detail) ? _detail : {};
|
|
1921
|
-
if (selectedSubLists.length > 0) {
|
|
1922
|
-
toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
|
|
1923
|
-
}
|
|
1924
|
-
else {
|
|
1925
|
-
toggleSingleList(editor, parentList, listName, detail);
|
|
1926
|
-
}
|
|
1927
|
-
};
|
|
1928
|
-
|
|
1929
|
-
const DOM = global$3.DOM;
|
|
1930
|
-
const normalizeList = (dom, list) => {
|
|
1931
|
-
const parentNode = list.parentElement;
|
|
1932
|
-
// Move UL/OL to previous LI if it's the only child of a LI
|
|
1933
|
-
if (parentNode && parentNode.nodeName === 'LI' && parentNode.firstChild === list) {
|
|
1934
|
-
const sibling = parentNode.previousSibling;
|
|
1935
|
-
if (sibling && sibling.nodeName === 'LI') {
|
|
1936
|
-
sibling.appendChild(list);
|
|
1937
|
-
if (isEmpty$1(dom, parentNode)) {
|
|
1938
|
-
DOM.remove(parentNode);
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
else {
|
|
1942
|
-
DOM.setStyle(parentNode, 'listStyleType', 'none');
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
// Append OL/UL to previous LI if it's in a parent OL/UL i.e. old HTML4
|
|
1946
|
-
if (isListNode(parentNode)) {
|
|
1947
|
-
const sibling = parentNode.previousSibling;
|
|
1948
|
-
if (sibling && sibling.nodeName === 'LI') {
|
|
1949
|
-
sibling.appendChild(list);
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
};
|
|
1953
|
-
const normalizeLists = (dom, element) => {
|
|
1954
|
-
const lists = global$2.grep(dom.select('ol,ul', element));
|
|
1955
|
-
global$2.each(lists, (list) => {
|
|
1956
|
-
normalizeList(dom, list);
|
|
1957
|
-
});
|
|
1958
|
-
};
|
|
1959
|
-
|
|
1960
|
-
const findNextCaretContainer = (editor, rng, isForward, root) => {
|
|
1961
|
-
let node = rng.startContainer;
|
|
1962
|
-
const offset = rng.startOffset;
|
|
1963
|
-
if (isTextNode$1(node) && (isForward ? offset < node.data.length : offset > 0)) {
|
|
1964
|
-
return node;
|
|
1965
|
-
}
|
|
1966
|
-
const nonEmptyBlocks = editor.schema.getNonEmptyElements();
|
|
1967
|
-
if (isElement(node)) {
|
|
1968
|
-
node = global$6.getNode(node, offset);
|
|
1969
|
-
}
|
|
1970
|
-
const walker = new global$5(node, root);
|
|
1971
|
-
// Delete at <li>|<br></li> then jump over the bogus br
|
|
1972
|
-
if (isForward) {
|
|
1973
|
-
if (isBogusBr(editor.dom, node)) {
|
|
1974
|
-
walker.next();
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
|
|
1978
|
-
while ((node = walkFn())) {
|
|
1979
|
-
if (node.nodeName === 'LI' && !node.hasChildNodes()) {
|
|
1980
|
-
return node;
|
|
1981
|
-
}
|
|
1982
|
-
if (nonEmptyBlocks[node.nodeName]) {
|
|
1983
|
-
return node;
|
|
1984
|
-
}
|
|
1985
|
-
if (isTextNode$1(node) && node.data.length > 0) {
|
|
1986
|
-
return node;
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
|
-
return null;
|
|
1990
|
-
};
|
|
1991
|
-
const hasOnlyOneBlockChild = (dom, elm) => {
|
|
1992
|
-
const childNodes = elm.childNodes;
|
|
1993
|
-
return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
|
|
1994
|
-
};
|
|
1995
|
-
const isUnwrappable = (node) => Optional.from(node)
|
|
1996
|
-
.map(SugarElement.fromDom)
|
|
1997
|
-
.filter(isHTMLElement)
|
|
1998
|
-
.exists((el) => isEditable(el) && !contains$1(['details'], name(el)));
|
|
1999
|
-
const unwrapSingleBlockChild = (dom, elm) => {
|
|
2000
|
-
if (hasOnlyOneBlockChild(dom, elm) && isUnwrappable(elm.firstChild)) {
|
|
2001
|
-
dom.remove(elm.firstChild, true);
|
|
2002
|
-
}
|
|
2003
|
-
};
|
|
2004
|
-
const moveChildren = (dom, fromElm, toElm) => {
|
|
2005
|
-
let node;
|
|
2006
|
-
const targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
|
|
2007
|
-
unwrapSingleBlockChild(dom, fromElm);
|
|
2008
|
-
if (!isEmpty$1(dom, fromElm, true)) {
|
|
2009
|
-
while ((node = fromElm.firstChild)) {
|
|
2010
|
-
targetElm.appendChild(node);
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
};
|
|
2014
|
-
const mergeLiElements = (dom, fromElm, toElm) => {
|
|
2015
|
-
let listNode;
|
|
2016
|
-
const ul = fromElm.parentNode;
|
|
2017
|
-
if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
|
|
2018
|
-
return;
|
|
2019
|
-
}
|
|
2020
|
-
if (isListNode(toElm.lastChild)) {
|
|
2021
|
-
listNode = toElm.lastChild;
|
|
2022
|
-
}
|
|
2023
|
-
if (ul === toElm.lastChild) {
|
|
2024
|
-
if (isBr(ul.previousSibling)) {
|
|
2025
|
-
dom.remove(ul.previousSibling);
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
const node = toElm.lastChild;
|
|
2029
|
-
if (node && isBr(node) && fromElm.hasChildNodes()) {
|
|
2030
|
-
dom.remove(node);
|
|
2031
|
-
}
|
|
2032
|
-
if (isEmpty$1(dom, toElm, true)) {
|
|
2033
|
-
empty(SugarElement.fromDom(toElm));
|
|
2034
|
-
}
|
|
2035
|
-
moveChildren(dom, fromElm, toElm);
|
|
2036
|
-
if (listNode) {
|
|
2037
|
-
toElm.appendChild(listNode);
|
|
2038
|
-
}
|
|
2039
|
-
const contains$1 = contains(SugarElement.fromDom(toElm), SugarElement.fromDom(fromElm));
|
|
2040
|
-
const nestedLists = contains$1 ? dom.getParents(fromElm, isListNode, toElm) : [];
|
|
2041
|
-
dom.remove(fromElm);
|
|
2042
|
-
each$1(nestedLists, (list) => {
|
|
2043
|
-
if (isEmpty$1(dom, list) && list !== dom.getRoot()) {
|
|
2044
|
-
dom.remove(list);
|
|
2045
|
-
}
|
|
2046
|
-
});
|
|
2047
|
-
};
|
|
2048
|
-
const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
|
|
2049
|
-
empty(SugarElement.fromDom(toLi));
|
|
2050
|
-
mergeLiElements(editor.dom, fromLi, toLi);
|
|
2051
|
-
editor.selection.setCursorLocation(toLi, 0);
|
|
2052
|
-
};
|
|
2053
|
-
const mergeForward = (editor, rng, fromLi, toLi) => {
|
|
2054
|
-
const dom = editor.dom;
|
|
2055
|
-
if (dom.isEmpty(toLi)) {
|
|
2056
|
-
mergeIntoEmptyLi(editor, fromLi, toLi);
|
|
2057
|
-
}
|
|
2058
|
-
else {
|
|
2059
|
-
const bookmark = createBookmark(rng);
|
|
2060
|
-
mergeLiElements(dom, fromLi, toLi);
|
|
2061
|
-
editor.selection.setRng(resolveBookmark(bookmark));
|
|
2062
|
-
}
|
|
2063
|
-
};
|
|
2064
|
-
const mergeBackward = (editor, rng, fromLi, toLi) => {
|
|
2065
|
-
const bookmark = createBookmark(rng);
|
|
2066
|
-
mergeLiElements(editor.dom, fromLi, toLi);
|
|
2067
|
-
const resolvedBookmark = resolveBookmark(bookmark);
|
|
2068
|
-
editor.selection.setRng(resolvedBookmark);
|
|
2069
|
-
};
|
|
2070
|
-
const backspaceDeleteFromListToListCaret = (editor, isForward) => {
|
|
2071
|
-
const dom = editor.dom, selection = editor.selection;
|
|
2072
|
-
const selectionStartElm = selection.getStart();
|
|
2073
|
-
const root = getClosestEditingHost(editor, selectionStartElm);
|
|
2074
|
-
const li = dom.getParent(selection.getStart(), 'LI', root);
|
|
2075
|
-
if (li) {
|
|
2076
|
-
const ul = li.parentElement;
|
|
2077
|
-
if (ul === editor.getBody() && isEmpty$1(dom, ul)) {
|
|
2078
|
-
return true;
|
|
2079
|
-
}
|
|
2080
|
-
const rng = normalizeRange(selection.getRng());
|
|
2081
|
-
const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
|
|
2082
|
-
const willMergeParentIntoChild = otherLi && (isForward ? dom.isChildOf(li, otherLi) : dom.isChildOf(otherLi, li));
|
|
2083
|
-
if (otherLi && otherLi !== li && !willMergeParentIntoChild) {
|
|
2084
|
-
editor.undoManager.transact(() => {
|
|
2085
|
-
if (isForward) {
|
|
2086
|
-
mergeForward(editor, rng, otherLi, li);
|
|
2087
|
-
}
|
|
2088
|
-
else {
|
|
2089
|
-
if (isFirstChild(li)) {
|
|
2090
|
-
outdentListSelection(editor);
|
|
2091
|
-
}
|
|
2092
|
-
else {
|
|
2093
|
-
mergeBackward(editor, rng, li, otherLi);
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
});
|
|
2097
|
-
return true;
|
|
2098
|
-
}
|
|
2099
|
-
else if (willMergeParentIntoChild && !isForward && otherLi !== li) {
|
|
2100
|
-
const commonAncestorParent = rng.commonAncestorContainer.parentElement;
|
|
2101
|
-
if (!commonAncestorParent || dom.isChildOf(otherLi, commonAncestorParent)) {
|
|
2102
|
-
return false;
|
|
2103
|
-
}
|
|
2104
|
-
editor.undoManager.transact(() => {
|
|
2105
|
-
const bookmark = createBookmark(rng);
|
|
2106
|
-
moveChildren(dom, commonAncestorParent, otherLi);
|
|
2107
|
-
commonAncestorParent.remove();
|
|
2108
|
-
const resolvedBookmark = resolveBookmark(bookmark);
|
|
2109
|
-
editor.selection.setRng(resolvedBookmark);
|
|
2110
|
-
});
|
|
2111
|
-
return true;
|
|
2112
|
-
}
|
|
2113
|
-
else if (!otherLi) {
|
|
2114
|
-
if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
|
|
2115
|
-
editor.undoManager.transact(() => {
|
|
2116
|
-
flattenListSelection(editor);
|
|
2117
|
-
});
|
|
2118
|
-
return true;
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
return false;
|
|
2123
|
-
};
|
|
2124
|
-
const removeBlock = (dom, block, root) => {
|
|
2125
|
-
const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
|
|
2126
|
-
dom.remove(block);
|
|
2127
|
-
if (parentBlock && dom.isEmpty(parentBlock)) {
|
|
2128
|
-
dom.remove(parentBlock);
|
|
2129
|
-
}
|
|
2130
|
-
};
|
|
2131
|
-
const backspaceDeleteIntoListCaret = (editor, isForward) => {
|
|
2132
|
-
const dom = editor.dom;
|
|
2133
|
-
const selectionStartElm = editor.selection.getStart();
|
|
2134
|
-
const root = getClosestEditingHost(editor, selectionStartElm);
|
|
2135
|
-
const block = dom.getParent(selectionStartElm, dom.isBlock, root);
|
|
2136
|
-
if (block && dom.isEmpty(block, undefined, { checkRootAsContent: true })) {
|
|
2137
|
-
const rng = normalizeRange(editor.selection.getRng());
|
|
2138
|
-
const nextCaretContainer = findNextCaretContainer(editor, rng, isForward, root);
|
|
2139
|
-
const otherLi = dom.getParent(nextCaretContainer, 'LI', root);
|
|
2140
|
-
if (nextCaretContainer && otherLi) {
|
|
2141
|
-
const findValidElement = (element) => contains$1(['td', 'th', 'caption'], name(element));
|
|
2142
|
-
const findRoot = (node) => node.dom === root;
|
|
2143
|
-
const otherLiCell = closest$2(SugarElement.fromDom(otherLi), findValidElement, findRoot);
|
|
2144
|
-
const caretCell = closest$2(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
|
|
2145
|
-
if (!equals(otherLiCell, caretCell, eq)) {
|
|
2146
|
-
return false;
|
|
2147
|
-
}
|
|
2148
|
-
editor.undoManager.transact(() => {
|
|
2149
|
-
const parentNode = otherLi.parentNode;
|
|
2150
|
-
removeBlock(dom, block, root);
|
|
2151
|
-
mergeWithAdjacentLists(dom, parentNode);
|
|
2152
|
-
editor.selection.select(nextCaretContainer, true);
|
|
2153
|
-
editor.selection.collapse(isForward);
|
|
2154
|
-
});
|
|
2155
|
-
return true;
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
return false;
|
|
2159
|
-
};
|
|
2160
|
-
const backspaceDeleteCaret = (editor, isForward) => {
|
|
2161
|
-
return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
|
|
2162
|
-
};
|
|
2163
|
-
const hasListSelection = (editor) => {
|
|
2164
|
-
const selectionStartElm = editor.selection.getStart();
|
|
2165
|
-
const root = getClosestEditingHost(editor, selectionStartElm);
|
|
2166
|
-
const startListParent = editor.dom.getParent(selectionStartElm, 'LI,DT,DD', root);
|
|
2167
|
-
return startListParent || getSelectedListItems(editor).length > 0;
|
|
2168
|
-
};
|
|
2169
|
-
const backspaceDeleteRange = (editor) => {
|
|
2170
|
-
if (hasListSelection(editor)) {
|
|
2171
|
-
editor.undoManager.transact(() => {
|
|
2172
|
-
// Some delete actions may prevent the input event from being fired. If we do not detect it, we fire it ourselves.
|
|
2173
|
-
let shouldFireInput = true;
|
|
2174
|
-
const inputHandler = () => shouldFireInput = false;
|
|
2175
|
-
editor.on('input', inputHandler);
|
|
2176
|
-
editor.execCommand('Delete');
|
|
2177
|
-
editor.off('input', inputHandler);
|
|
2178
|
-
if (shouldFireInput) {
|
|
2179
|
-
editor.dispatch('input');
|
|
2180
|
-
}
|
|
2181
|
-
normalizeLists(editor.dom, editor.getBody());
|
|
2182
|
-
});
|
|
2183
|
-
return true;
|
|
2184
|
-
}
|
|
2185
|
-
return false;
|
|
2186
|
-
};
|
|
2187
|
-
const backspaceDelete = (editor, isForward) => {
|
|
2188
|
-
const selection = editor.selection;
|
|
2189
|
-
return !isWithinNonEditableList(editor, selection.getNode()) && (selection.isCollapsed() ?
|
|
2190
|
-
backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor));
|
|
2191
|
-
};
|
|
2192
|
-
const setup$2 = (editor) => {
|
|
2193
|
-
editor.on('ExecCommand', (e) => {
|
|
2194
|
-
const cmd = e.command.toLowerCase();
|
|
2195
|
-
if ((cmd === 'delete' || cmd === 'forwarddelete') && hasListSelection(editor)) {
|
|
2196
|
-
normalizeLists(editor.dom, editor.getBody());
|
|
2197
|
-
}
|
|
2198
|
-
});
|
|
2199
|
-
editor.on('keydown', (e) => {
|
|
2200
|
-
if (e.keyCode === global$4.BACKSPACE) {
|
|
2201
|
-
if (backspaceDelete(editor, false)) {
|
|
2202
|
-
e.preventDefault();
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
else if (e.keyCode === global$4.DELETE) {
|
|
2206
|
-
if (backspaceDelete(editor, true)) {
|
|
2207
|
-
e.preventDefault();
|
|
2208
|
-
}
|
|
2209
|
-
}
|
|
2210
|
-
});
|
|
2211
|
-
};
|
|
2212
|
-
|
|
2213
|
-
const get = (editor) => ({
|
|
2214
|
-
backspaceDelete: (isForward) => {
|
|
2215
|
-
backspaceDelete(editor, isForward);
|
|
2216
|
-
}
|
|
2217
|
-
});
|
|
2218
|
-
|
|
2219
|
-
const updateList = (editor, update) => {
|
|
2220
|
-
const parentList = getParentList(editor);
|
|
2221
|
-
if (parentList === null || isWithinNonEditableList(editor, parentList)) {
|
|
2222
|
-
return;
|
|
2223
|
-
}
|
|
2224
|
-
editor.undoManager.transact(() => {
|
|
2225
|
-
if (isObject(update.styles)) {
|
|
2226
|
-
editor.dom.setStyles(parentList, update.styles);
|
|
2227
|
-
}
|
|
2228
|
-
if (isObject(update.attrs)) {
|
|
2229
|
-
each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
};
|
|
2233
|
-
|
|
2234
|
-
// Example: 'AB' -> 28
|
|
2235
|
-
const parseAlphabeticBase26 = (str) => {
|
|
2236
|
-
const chars = reverse(trim(str).split(''));
|
|
2237
|
-
const values = map(chars, (char, i) => {
|
|
2238
|
-
const charValue = char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 1;
|
|
2239
|
-
return Math.pow(26, i) * charValue;
|
|
2240
|
-
});
|
|
2241
|
-
return foldl(values, (sum, v) => sum + v, 0);
|
|
2242
|
-
};
|
|
2243
|
-
// Example: 28 -> 'AB'
|
|
2244
|
-
const composeAlphabeticBase26 = (value) => {
|
|
2245
|
-
value--;
|
|
2246
|
-
if (value < 0) {
|
|
2247
|
-
return '';
|
|
2248
|
-
}
|
|
2249
|
-
else {
|
|
2250
|
-
const remainder = value % 26;
|
|
2251
|
-
const quotient = Math.floor(value / 26);
|
|
2252
|
-
const rest = composeAlphabeticBase26(quotient);
|
|
2253
|
-
const char = String.fromCharCode('A'.charCodeAt(0) + remainder);
|
|
2254
|
-
return rest + char;
|
|
2255
|
-
}
|
|
2256
|
-
};
|
|
2257
|
-
const isUppercase = (str) => /^[A-Z]+$/.test(str);
|
|
2258
|
-
const isLowercase = (str) => /^[a-z]+$/.test(str);
|
|
2259
|
-
const isNumeric = (str) => /^[0-9]+$/.test(str);
|
|
2260
|
-
const deduceListType = (start) => {
|
|
2261
|
-
if (isNumeric(start)) {
|
|
2262
|
-
return 2 /* ListType.Numeric */;
|
|
2263
|
-
}
|
|
2264
|
-
else if (isUppercase(start)) {
|
|
2265
|
-
return 0 /* ListType.UpperAlpha */;
|
|
2266
|
-
}
|
|
2267
|
-
else if (isLowercase(start)) {
|
|
2268
|
-
return 1 /* ListType.LowerAlpha */;
|
|
2269
|
-
}
|
|
2270
|
-
else if (isEmpty$2(start)) {
|
|
2271
|
-
return 3 /* ListType.None */;
|
|
2272
|
-
}
|
|
2273
|
-
else {
|
|
2274
|
-
return 4 /* ListType.Unknown */;
|
|
2275
|
-
}
|
|
2276
|
-
};
|
|
2277
|
-
const parseStartValue = (start) => {
|
|
2278
|
-
switch (deduceListType(start)) {
|
|
2279
|
-
case 2 /* ListType.Numeric */:
|
|
2280
|
-
return Optional.some({
|
|
2281
|
-
listStyleType: Optional.none(),
|
|
2282
|
-
start
|
|
2283
|
-
});
|
|
2284
|
-
case 0 /* ListType.UpperAlpha */:
|
|
2285
|
-
return Optional.some({
|
|
2286
|
-
listStyleType: Optional.some('upper-alpha'),
|
|
2287
|
-
start: parseAlphabeticBase26(start).toString()
|
|
2288
|
-
});
|
|
2289
|
-
case 1 /* ListType.LowerAlpha */:
|
|
2290
|
-
return Optional.some({
|
|
2291
|
-
listStyleType: Optional.some('lower-alpha'),
|
|
2292
|
-
start: parseAlphabeticBase26(start).toString()
|
|
2293
|
-
});
|
|
2294
|
-
case 3 /* ListType.None */:
|
|
2295
|
-
return Optional.some({
|
|
2296
|
-
listStyleType: Optional.none(),
|
|
2297
|
-
start: ''
|
|
2298
|
-
});
|
|
2299
|
-
case 4 /* ListType.Unknown */:
|
|
2300
|
-
return Optional.none();
|
|
2301
|
-
}
|
|
2302
|
-
};
|
|
2303
|
-
const parseDetail = (detail) => {
|
|
2304
|
-
const start = parseInt(detail.start, 10);
|
|
2305
|
-
if (is$2(detail.listStyleType, 'upper-alpha')) {
|
|
2306
|
-
return composeAlphabeticBase26(start);
|
|
2307
|
-
}
|
|
2308
|
-
else if (is$2(detail.listStyleType, 'lower-alpha')) {
|
|
2309
|
-
return composeAlphabeticBase26(start).toLowerCase();
|
|
2310
|
-
}
|
|
2311
|
-
else {
|
|
2312
|
-
return detail.start;
|
|
2313
|
-
}
|
|
2314
|
-
};
|
|
473
|
+
const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, (listName) => schema.isValidChild(node.nodeName, listName));
|
|
2315
474
|
|
|
2316
475
|
const open = (editor) => {
|
|
2317
476
|
// Find the current list and skip opening if the selection isn't in an ordered list
|
|
@@ -2368,106 +527,11 @@
|
|
|
2368
527
|
});
|
|
2369
528
|
};
|
|
2370
529
|
|
|
2371
|
-
const
|
|
2372
|
-
const parentList = getParentList(editor);
|
|
2373
|
-
return isNonNullable(parentList) && parentList.nodeName === listName;
|
|
2374
|
-
};
|
|
2375
|
-
const registerDialog = (editor) => {
|
|
530
|
+
const register$2 = (editor) => {
|
|
2376
531
|
editor.addCommand('mceListProps', () => {
|
|
2377
532
|
open(editor);
|
|
2378
533
|
});
|
|
2379
534
|
};
|
|
2380
|
-
const register$2 = (editor) => {
|
|
2381
|
-
editor.on('BeforeExecCommand', (e) => {
|
|
2382
|
-
const cmd = e.command.toLowerCase();
|
|
2383
|
-
if (cmd === 'indent') {
|
|
2384
|
-
indentListSelection(editor);
|
|
2385
|
-
}
|
|
2386
|
-
else if (cmd === 'outdent') {
|
|
2387
|
-
outdentListSelection(editor);
|
|
2388
|
-
}
|
|
2389
|
-
});
|
|
2390
|
-
editor.addCommand('InsertUnorderedList', (ui, detail) => {
|
|
2391
|
-
toggleList(editor, 'UL', detail);
|
|
2392
|
-
});
|
|
2393
|
-
editor.addCommand('InsertOrderedList', (ui, detail) => {
|
|
2394
|
-
toggleList(editor, 'OL', detail);
|
|
2395
|
-
});
|
|
2396
|
-
editor.addCommand('InsertDefinitionList', (ui, detail) => {
|
|
2397
|
-
toggleList(editor, 'DL', detail);
|
|
2398
|
-
});
|
|
2399
|
-
editor.addCommand('RemoveList', () => {
|
|
2400
|
-
flattenListSelection(editor);
|
|
2401
|
-
});
|
|
2402
|
-
registerDialog(editor);
|
|
2403
|
-
editor.addCommand('mceListUpdate', (ui, detail) => {
|
|
2404
|
-
if (isObject(detail)) {
|
|
2405
|
-
updateList(editor, detail);
|
|
2406
|
-
}
|
|
2407
|
-
});
|
|
2408
|
-
editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
|
|
2409
|
-
editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
|
|
2410
|
-
editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
|
|
2411
|
-
};
|
|
2412
|
-
|
|
2413
|
-
var global = tinymce.util.Tools.resolve('tinymce.html.Node');
|
|
2414
|
-
|
|
2415
|
-
const isTextNode = (node) => node.type === 3;
|
|
2416
|
-
const isEmpty = (nodeBuffer) => nodeBuffer.length === 0;
|
|
2417
|
-
const wrapInvalidChildren = (list) => {
|
|
2418
|
-
const insertListItem = (buffer, refNode) => {
|
|
2419
|
-
const li = global.create('li');
|
|
2420
|
-
each$1(buffer, (node) => li.append(node));
|
|
2421
|
-
if (refNode) {
|
|
2422
|
-
list.insert(li, refNode, true);
|
|
2423
|
-
}
|
|
2424
|
-
else {
|
|
2425
|
-
list.append(li);
|
|
2426
|
-
}
|
|
2427
|
-
};
|
|
2428
|
-
const reducer = (buffer, node) => {
|
|
2429
|
-
if (isTextNode(node)) {
|
|
2430
|
-
return [...buffer, node];
|
|
2431
|
-
}
|
|
2432
|
-
else if (!isEmpty(buffer) && !isTextNode(node)) {
|
|
2433
|
-
insertListItem(buffer, node);
|
|
2434
|
-
return [];
|
|
2435
|
-
}
|
|
2436
|
-
else {
|
|
2437
|
-
return buffer;
|
|
2438
|
-
}
|
|
2439
|
-
};
|
|
2440
|
-
const restBuffer = foldl(list.children(), reducer, []);
|
|
2441
|
-
if (!isEmpty(restBuffer)) {
|
|
2442
|
-
insertListItem(restBuffer);
|
|
2443
|
-
}
|
|
2444
|
-
};
|
|
2445
|
-
const setup$1 = (editor) => {
|
|
2446
|
-
editor.on('PreInit', () => {
|
|
2447
|
-
const { parser } = editor;
|
|
2448
|
-
parser.addNodeFilter('ul,ol', (nodes) => each$1(nodes, wrapInvalidChildren));
|
|
2449
|
-
});
|
|
2450
|
-
};
|
|
2451
|
-
|
|
2452
|
-
const setupTabKey = (editor) => {
|
|
2453
|
-
editor.on('keydown', (e) => {
|
|
2454
|
-
// Check for tab but not ctrl/cmd+tab since it switches browser tabs
|
|
2455
|
-
if (e.keyCode !== global$4.TAB || global$4.metaKeyPressed(e)) {
|
|
2456
|
-
return;
|
|
2457
|
-
}
|
|
2458
|
-
editor.undoManager.transact(() => {
|
|
2459
|
-
if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
|
|
2460
|
-
e.preventDefault();
|
|
2461
|
-
}
|
|
2462
|
-
});
|
|
2463
|
-
});
|
|
2464
|
-
};
|
|
2465
|
-
const setup = (editor) => {
|
|
2466
|
-
if (shouldIndentOnTab(editor)) {
|
|
2467
|
-
setupTabKey(editor);
|
|
2468
|
-
}
|
|
2469
|
-
setup$2(editor);
|
|
2470
|
-
};
|
|
2471
535
|
|
|
2472
536
|
const setupToggleButtonHandler = (editor, listName) => (api) => {
|
|
2473
537
|
const toggleButtonHandler = (e) => {
|
|
@@ -2518,16 +582,8 @@
|
|
|
2518
582
|
};
|
|
2519
583
|
|
|
2520
584
|
var Plugin = () => {
|
|
2521
|
-
global
|
|
2522
|
-
register$
|
|
2523
|
-
setup$1(editor);
|
|
2524
|
-
if (!editor.hasPlugin('rtc', true)) {
|
|
2525
|
-
setup(editor);
|
|
2526
|
-
register$2(editor);
|
|
2527
|
-
}
|
|
2528
|
-
else {
|
|
2529
|
-
registerDialog(editor);
|
|
2530
|
-
}
|
|
585
|
+
global.add('lists', (editor) => {
|
|
586
|
+
register$2(editor);
|
|
2531
587
|
register$1(editor);
|
|
2532
588
|
register(editor);
|
|
2533
589
|
return get(editor);
|