MDL-78251 editor_tiny: Update TinyMCE to 6.6.2
[moodle.git] / lib / editor / tiny / js / tinymce / plugins / lists / plugin.js
blob7c053dc12cd6904d9ff36c584b44aec1dd95f922
1 /**
2  * TinyMCE version 6.6.2 (2023-08-09)
3  */
5 (function () {
6     'use strict';
8     var global$7 = tinymce.util.Tools.resolve('tinymce.PluginManager');
10     const hasProto = (v, constructor, predicate) => {
11       var _a;
12       if (predicate(v, constructor.prototype)) {
13         return true;
14       } else {
15         return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
16       }
17     };
18     const typeOf = x => {
19       const t = typeof x;
20       if (x === null) {
21         return 'null';
22       } else if (t === 'object' && Array.isArray(x)) {
23         return 'array';
24       } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
25         return 'string';
26       } else {
27         return t;
28       }
29     };
30     const isType$1 = type => value => typeOf(value) === type;
31     const isSimpleType = type => value => typeof value === type;
32     const isString = isType$1('string');
33     const isObject = isType$1('object');
34     const isArray = isType$1('array');
35     const isBoolean = isSimpleType('boolean');
36     const isNullable = a => a === null || a === undefined;
37     const isNonNullable = a => !isNullable(a);
38     const isFunction = isSimpleType('function');
39     const isNumber = isSimpleType('number');
41     const noop = () => {
42     };
43     const constant = value => {
44       return () => {
45         return value;
46       };
47     };
48     const tripleEquals = (a, b) => {
49       return a === b;
50     };
51     const not = f => t => !f(t);
52     const never = constant(false);
54     class Optional {
55       constructor(tag, value) {
56         this.tag = tag;
57         this.value = value;
58       }
59       static some(value) {
60         return new Optional(true, value);
61       }
62       static none() {
63         return Optional.singletonNone;
64       }
65       fold(onNone, onSome) {
66         if (this.tag) {
67           return onSome(this.value);
68         } else {
69           return onNone();
70         }
71       }
72       isSome() {
73         return this.tag;
74       }
75       isNone() {
76         return !this.tag;
77       }
78       map(mapper) {
79         if (this.tag) {
80           return Optional.some(mapper(this.value));
81         } else {
82           return Optional.none();
83         }
84       }
85       bind(binder) {
86         if (this.tag) {
87           return binder(this.value);
88         } else {
89           return Optional.none();
90         }
91       }
92       exists(predicate) {
93         return this.tag && predicate(this.value);
94       }
95       forall(predicate) {
96         return !this.tag || predicate(this.value);
97       }
98       filter(predicate) {
99         if (!this.tag || predicate(this.value)) {
100           return this;
101         } else {
102           return Optional.none();
103         }
104       }
105       getOr(replacement) {
106         return this.tag ? this.value : replacement;
107       }
108       or(replacement) {
109         return this.tag ? this : replacement;
110       }
111       getOrThunk(thunk) {
112         return this.tag ? this.value : thunk();
113       }
114       orThunk(thunk) {
115         return this.tag ? this : thunk();
116       }
117       getOrDie(message) {
118         if (!this.tag) {
119           throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
120         } else {
121           return this.value;
122         }
123       }
124       static from(value) {
125         return isNonNullable(value) ? Optional.some(value) : Optional.none();
126       }
127       getOrNull() {
128         return this.tag ? this.value : null;
129       }
130       getOrUndefined() {
131         return this.value;
132       }
133       each(worker) {
134         if (this.tag) {
135           worker(this.value);
136         }
137       }
138       toArray() {
139         return this.tag ? [this.value] : [];
140       }
141       toString() {
142         return this.tag ? `some(${ this.value })` : 'none()';
143       }
144     }
145     Optional.singletonNone = new Optional(false);
147     const nativeSlice = Array.prototype.slice;
148     const nativeIndexOf = Array.prototype.indexOf;
149     const nativePush = Array.prototype.push;
150     const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
151     const contains$1 = (xs, x) => rawIndexOf(xs, x) > -1;
152     const exists = (xs, pred) => {
153       for (let i = 0, len = xs.length; i < len; i++) {
154         const x = xs[i];
155         if (pred(x, i)) {
156           return true;
157         }
158       }
159       return false;
160     };
161     const map = (xs, f) => {
162       const len = xs.length;
163       const r = new Array(len);
164       for (let i = 0; i < len; i++) {
165         const x = xs[i];
166         r[i] = f(x, i);
167       }
168       return r;
169     };
170     const each$1 = (xs, f) => {
171       for (let i = 0, len = xs.length; i < len; i++) {
172         const x = xs[i];
173         f(x, i);
174       }
175     };
176     const filter$1 = (xs, pred) => {
177       const r = [];
178       for (let i = 0, len = xs.length; i < len; i++) {
179         const x = xs[i];
180         if (pred(x, i)) {
181           r.push(x);
182         }
183       }
184       return r;
185     };
186     const groupBy = (xs, f) => {
187       if (xs.length === 0) {
188         return [];
189       } else {
190         let wasType = f(xs[0]);
191         const r = [];
192         let group = [];
193         for (let i = 0, len = xs.length; i < len; i++) {
194           const x = xs[i];
195           const type = f(x);
196           if (type !== wasType) {
197             r.push(group);
198             group = [];
199           }
200           wasType = type;
201           group.push(x);
202         }
203         if (group.length !== 0) {
204           r.push(group);
205         }
206         return r;
207       }
208     };
209     const foldl = (xs, f, acc) => {
210       each$1(xs, (x, i) => {
211         acc = f(acc, x, i);
212       });
213       return acc;
214     };
215     const findUntil = (xs, pred, until) => {
216       for (let i = 0, len = xs.length; i < len; i++) {
217         const x = xs[i];
218         if (pred(x, i)) {
219           return Optional.some(x);
220         } else if (until(x, i)) {
221           break;
222         }
223       }
224       return Optional.none();
225     };
226     const find = (xs, pred) => {
227       return findUntil(xs, pred, never);
228     };
229     const flatten = xs => {
230       const r = [];
231       for (let i = 0, len = xs.length; i < len; ++i) {
232         if (!isArray(xs[i])) {
233           throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
234         }
235         nativePush.apply(r, xs[i]);
236       }
237       return r;
238     };
239     const bind = (xs, f) => flatten(map(xs, f));
240     const reverse = xs => {
241       const r = nativeSlice.call(xs, 0);
242       r.reverse();
243       return r;
244     };
245     const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
246     const head = xs => get$1(xs, 0);
247     const last = xs => get$1(xs, xs.length - 1);
248     const unique = (xs, comparator) => {
249       const r = [];
250       const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$1(r, x);
251       for (let i = 0, len = xs.length; i < len; i++) {
252         const x = xs[i];
253         if (!isDuplicated(x)) {
254           r.push(x);
255         }
256       }
257       return r;
258     };
260     const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
261     const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
262     const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
264     const ELEMENT = 1;
266     const fromHtml = (html, scope) => {
267       const doc = scope || document;
268       const div = doc.createElement('div');
269       div.innerHTML = html;
270       if (!div.hasChildNodes() || div.childNodes.length > 1) {
271         const message = 'HTML does not have a single root node';
272         console.error(message, html);
273         throw new Error(message);
274       }
275       return fromDom$1(div.childNodes[0]);
276     };
277     const fromTag = (tag, scope) => {
278       const doc = scope || document;
279       const node = doc.createElement(tag);
280       return fromDom$1(node);
281     };
282     const fromText = (text, scope) => {
283       const doc = scope || document;
284       const node = doc.createTextNode(text);
285       return fromDom$1(node);
286     };
287     const fromDom$1 = node => {
288       if (node === null || node === undefined) {
289         throw new Error('Node cannot be null or undefined');
290       }
291       return { dom: node };
292     };
293     const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
294     const SugarElement = {
295       fromHtml,
296       fromTag,
297       fromText,
298       fromDom: fromDom$1,
299       fromPoint
300     };
302     const is$1 = (element, selector) => {
303       const dom = element.dom;
304       if (dom.nodeType !== ELEMENT) {
305         return false;
306       } else {
307         const elem = dom;
308         if (elem.matches !== undefined) {
309           return elem.matches(selector);
310         } else if (elem.msMatchesSelector !== undefined) {
311           return elem.msMatchesSelector(selector);
312         } else if (elem.webkitMatchesSelector !== undefined) {
313           return elem.webkitMatchesSelector(selector);
314         } else if (elem.mozMatchesSelector !== undefined) {
315           return elem.mozMatchesSelector(selector);
316         } else {
317           throw new Error('Browser lacks native selectors');
318         }
319       }
320     };
322     const eq = (e1, e2) => e1.dom === e2.dom;
323     const contains = (e1, e2) => {
324       const d1 = e1.dom;
325       const d2 = e2.dom;
326       return d1 === d2 ? false : d1.contains(d2);
327     };
328     const is = is$1;
330     var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
331       if (is(scope, a)) {
332         return Optional.some(scope);
333       } else if (isFunction(isRoot) && isRoot(scope)) {
334         return Optional.none();
335       } else {
336         return ancestor(scope, a, isRoot);
337       }
338     };
340     typeof window !== 'undefined' ? window : Function('return this;')();
342     const name = element => {
343       const r = element.dom.nodeName;
344       return r.toLowerCase();
345     };
346     const type = element => element.dom.nodeType;
347     const isType = t => element => type(element) === t;
348     const isElement$1 = isType(ELEMENT);
349     const isTag = tag => e => isElement$1(e) && name(e) === tag;
351     const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
352     const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
353     const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
354     const children = element => map(element.dom.childNodes, SugarElement.fromDom);
355     const child = (element, index) => {
356       const cs = element.dom.childNodes;
357       return Optional.from(cs[index]).map(SugarElement.fromDom);
358     };
359     const firstChild = element => child(element, 0);
360     const lastChild = element => child(element, element.dom.childNodes.length - 1);
362     const ancestor = (scope, predicate, isRoot) => {
363       let element = scope.dom;
364       const stop = isFunction(isRoot) ? isRoot : never;
365       while (element.parentNode) {
366         element = element.parentNode;
367         const el = SugarElement.fromDom(element);
368         if (predicate(el)) {
369           return Optional.some(el);
370         } else if (stop(el)) {
371           break;
372         }
373       }
374       return Optional.none();
375     };
376     const closest = (scope, predicate, isRoot) => {
377       const is = (s, test) => test(s);
378       return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
379     };
381     const before$1 = (marker, element) => {
382       const parent$1 = parent(marker);
383       parent$1.each(v => {
384         v.dom.insertBefore(element.dom, marker.dom);
385       });
386     };
387     const after = (marker, element) => {
388       const sibling = nextSibling(marker);
389       sibling.fold(() => {
390         const parent$1 = parent(marker);
391         parent$1.each(v => {
392           append$1(v, element);
393         });
394       }, v => {
395         before$1(v, element);
396       });
397     };
398     const append$1 = (parent, element) => {
399       parent.dom.appendChild(element.dom);
400     };
402     const before = (marker, elements) => {
403       each$1(elements, x => {
404         before$1(marker, x);
405       });
406     };
407     const append = (parent, elements) => {
408       each$1(elements, x => {
409         append$1(parent, x);
410       });
411     };
413     const empty = element => {
414       element.dom.textContent = '';
415       each$1(children(element), rogue => {
416         remove(rogue);
417       });
418     };
419     const remove = element => {
420       const dom = element.dom;
421       if (dom.parentNode !== null) {
422         dom.parentNode.removeChild(dom);
423       }
424     };
426     var global$6 = tinymce.util.Tools.resolve('tinymce.dom.RangeUtils');
428     var global$5 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
430     var global$4 = tinymce.util.Tools.resolve('tinymce.util.VK');
432     const fromDom = nodes => map(nodes, SugarElement.fromDom);
434     const keys = Object.keys;
435     const each = (obj, f) => {
436       const props = keys(obj);
437       for (let k = 0, len = props.length; k < len; k++) {
438         const i = props[k];
439         const x = obj[i];
440         f(x, i);
441       }
442     };
443     const objAcc = r => (x, i) => {
444       r[i] = x;
445     };
446     const internalFilter = (obj, pred, onTrue, onFalse) => {
447       each(obj, (x, i) => {
448         (pred(x, i) ? onTrue : onFalse)(x, i);
449       });
450     };
451     const filter = (obj, pred) => {
452       const t = {};
453       internalFilter(obj, pred, objAcc(t), noop);
454       return t;
455     };
457     const rawSet = (dom, key, value) => {
458       if (isString(value) || isBoolean(value) || isNumber(value)) {
459         dom.setAttribute(key, value + '');
460       } else {
461         console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
462         throw new Error('Attribute value was not simple');
463       }
464     };
465     const setAll = (element, attrs) => {
466       const dom = element.dom;
467       each(attrs, (v, k) => {
468         rawSet(dom, k, v);
469       });
470     };
471     const clone$1 = element => foldl(element.dom.attributes, (acc, attr) => {
472       acc[attr.name] = attr.value;
473       return acc;
474     }, {});
476     const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
477     const deep = original => clone(original, true);
478     const shallowAs = (original, tag) => {
479       const nu = SugarElement.fromTag(tag);
480       const attributes = clone$1(original);
481       setAll(nu, attributes);
482       return nu;
483     };
484     const mutate = (original, tag) => {
485       const nu = shallowAs(original, tag);
486       after(original, nu);
487       const children$1 = children(original);
488       append(nu, children$1);
489       remove(original);
490       return nu;
491     };
493     var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
495     var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
497     const matchNodeName = name => node => isNonNullable(node) && node.nodeName.toLowerCase() === name;
498     const matchNodeNames = regex => node => isNonNullable(node) && regex.test(node.nodeName);
499     const isTextNode$1 = node => isNonNullable(node) && node.nodeType === 3;
500     const isElement = node => isNonNullable(node) && node.nodeType === 1;
501     const isListNode = matchNodeNames(/^(OL|UL|DL)$/);
502     const isOlUlNode = matchNodeNames(/^(OL|UL)$/);
503     const isOlNode = matchNodeName('ol');
504     const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
505     const isDlItemNode = matchNodeNames(/^(DT|DD)$/);
506     const isTableCellNode = matchNodeNames(/^(TH|TD)$/);
507     const isBr = matchNodeName('br');
508     const isFirstChild = node => {
509       var _a;
510       return ((_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === node;
511     };
512     const isTextBlock = (editor, node) => isNonNullable(node) && node.nodeName in editor.schema.getTextBlockElements();
513     const isBlock = (node, blockElements) => isNonNullable(node) && node.nodeName in blockElements;
514     const isVoid = (editor, node) => isNonNullable(node) && node.nodeName in editor.schema.getVoidElements();
515     const isBogusBr = (dom, node) => {
516       if (!isBr(node)) {
517         return false;
518       }
519       return dom.isBlock(node.nextSibling) && !isBr(node.previousSibling);
520     };
521     const isEmpty$2 = (dom, elm, keepBookmarks) => {
522       const empty = dom.isEmpty(elm);
523       if (keepBookmarks && dom.select('span[data-mce-type=bookmark]', elm).length > 0) {
524         return false;
525       }
526       return empty;
527     };
528     const isChildOfBody = (dom, elm) => dom.isChildOf(elm, dom.getRoot());
530     const option = name => editor => editor.options.get(name);
531     const register$3 = editor => {
532       const registerOption = editor.options.register;
533       registerOption('lists_indent_on_tab', {
534         processor: 'boolean',
535         default: true
536       });
537     };
538     const shouldIndentOnTab = option('lists_indent_on_tab');
539     const getForcedRootBlock = option('forced_root_block');
540     const getForcedRootBlockAttrs = option('forced_root_block_attrs');
542     const createTextBlock = (editor, contentNode) => {
543       const dom = editor.dom;
544       const blockElements = editor.schema.getBlockElements();
545       const fragment = dom.createFragment();
546       const blockName = getForcedRootBlock(editor);
547       const blockAttrs = getForcedRootBlockAttrs(editor);
548       let node;
549       let textBlock;
550       let hasContentNode = false;
551       textBlock = dom.create(blockName, blockAttrs);
552       if (!isBlock(contentNode.firstChild, blockElements)) {
553         fragment.appendChild(textBlock);
554       }
555       while (node = contentNode.firstChild) {
556         const nodeName = node.nodeName;
557         if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
558           hasContentNode = true;
559         }
560         if (isBlock(node, blockElements)) {
561           fragment.appendChild(node);
562           textBlock = null;
563         } else {
564           if (!textBlock) {
565             textBlock = dom.create(blockName, blockAttrs);
566             fragment.appendChild(textBlock);
567           }
568           textBlock.appendChild(node);
569         }
570       }
571       if (!hasContentNode && textBlock) {
572         textBlock.appendChild(dom.create('br', { 'data-mce-bogus': '1' }));
573       }
574       return fragment;
575     };
577     const DOM$2 = global$3.DOM;
578     const splitList = (editor, list, li) => {
579       const removeAndKeepBookmarks = targetNode => {
580         const parent = targetNode.parentNode;
581         if (parent) {
582           global$2.each(bookmarks, node => {
583             parent.insertBefore(node, li.parentNode);
584           });
585         }
586         DOM$2.remove(targetNode);
587       };
588       const bookmarks = DOM$2.select('span[data-mce-type="bookmark"]', list);
589       const newBlock = createTextBlock(editor, li);
590       const tmpRng = DOM$2.createRng();
591       tmpRng.setStartAfter(li);
592       tmpRng.setEndAfter(list);
593       const fragment = tmpRng.extractContents();
594       for (let node = fragment.firstChild; node; node = node.firstChild) {
595         if (node.nodeName === 'LI' && editor.dom.isEmpty(node)) {
596           DOM$2.remove(node);
597           break;
598         }
599       }
600       if (!editor.dom.isEmpty(fragment)) {
601         DOM$2.insertAfter(fragment, list);
602       }
603       DOM$2.insertAfter(newBlock, list);
604       const parent = li.parentElement;
605       if (parent && isEmpty$2(editor.dom, parent)) {
606         removeAndKeepBookmarks(parent);
607       }
608       DOM$2.remove(li);
609       if (isEmpty$2(editor.dom, list)) {
610         DOM$2.remove(list);
611       }
612     };
614     const isDescriptionDetail = isTag('dd');
615     const isDescriptionTerm = isTag('dt');
616     const outdentDlItem = (editor, item) => {
617       if (isDescriptionDetail(item)) {
618         mutate(item, 'dt');
619       } else if (isDescriptionTerm(item)) {
620         parentElement(item).each(dl => splitList(editor, dl.dom, item.dom));
621       }
622     };
623     const indentDlItem = item => {
624       if (isDescriptionTerm(item)) {
625         mutate(item, 'dd');
626       }
627     };
628     const dlIndentation = (editor, indentation, dlItems) => {
629       if (indentation === 'Indent') {
630         each$1(dlItems, indentDlItem);
631       } else {
632         each$1(dlItems, item => outdentDlItem(editor, item));
633       }
634     };
636     const getNormalizedPoint = (container, offset) => {
637       if (isTextNode$1(container)) {
638         return {
639           container,
640           offset
641         };
642       }
643       const node = global$6.getNode(container, offset);
644       if (isTextNode$1(node)) {
645         return {
646           container: node,
647           offset: offset >= container.childNodes.length ? node.data.length : 0
648         };
649       } else if (node.previousSibling && isTextNode$1(node.previousSibling)) {
650         return {
651           container: node.previousSibling,
652           offset: node.previousSibling.data.length
653         };
654       } else if (node.nextSibling && isTextNode$1(node.nextSibling)) {
655         return {
656           container: node.nextSibling,
657           offset: 0
658         };
659       }
660       return {
661         container,
662         offset
663       };
664     };
665     const normalizeRange = rng => {
666       const outRng = rng.cloneRange();
667       const rangeStart = getNormalizedPoint(rng.startContainer, rng.startOffset);
668       outRng.setStart(rangeStart.container, rangeStart.offset);
669       const rangeEnd = getNormalizedPoint(rng.endContainer, rng.endOffset);
670       outRng.setEnd(rangeEnd.container, rangeEnd.offset);
671       return outRng;
672     };
674     const listNames = [
675       'OL',
676       'UL',
677       'DL'
678     ];
679     const listSelector = listNames.join(',');
680     const getParentList = (editor, node) => {
681       const selectionStart = node || editor.selection.getStart(true);
682       return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
683     };
684     const isParentListSelected = (parentList, selectedBlocks) => isNonNullable(parentList) && selectedBlocks.length === 1 && selectedBlocks[0] === parentList;
685     const findSubLists = parentList => filter$1(parentList.querySelectorAll(listSelector), isListNode);
686     const getSelectedSubLists = editor => {
687       const parentList = getParentList(editor);
688       const selectedBlocks = editor.selection.getSelectedBlocks();
689       if (isParentListSelected(parentList, selectedBlocks)) {
690         return findSubLists(parentList);
691       } else {
692         return filter$1(selectedBlocks, elm => {
693           return isListNode(elm) && parentList !== elm;
694         });
695       }
696     };
697     const findParentListItemsNodes = (editor, elms) => {
698       const listItemsElms = global$2.map(elms, elm => {
699         const parentLi = editor.dom.getParent(elm, 'li,dd,dt', getClosestListHost(editor, elm));
700         return parentLi ? parentLi : elm;
701       });
702       return unique(listItemsElms);
703     };
704     const getSelectedListItems = editor => {
705       const selectedBlocks = editor.selection.getSelectedBlocks();
706       return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
707     };
708     const getSelectedDlItems = editor => filter$1(getSelectedListItems(editor), isDlItemNode);
709     const getClosestEditingHost = (editor, elm) => {
710       const parentTableCell = editor.dom.getParents(elm, 'TD,TH');
711       return parentTableCell.length > 0 ? parentTableCell[0] : editor.getBody();
712     };
713     const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, listName => schema.isValidChild(node.nodeName, listName));
714     const getClosestListHost = (editor, elm) => {
715       const parentBlocks = editor.dom.getParents(elm, editor.dom.isBlock);
716       const parentBlock = find(parentBlocks, elm => isListHost(editor.schema, elm));
717       return parentBlock.getOr(editor.getBody());
718     };
719     const findLastParentListNode = (editor, elm) => {
720       const parentLists = editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
721       return last(parentLists);
722     };
723     const getSelectedLists = editor => {
724       const firstList = findLastParentListNode(editor, editor.selection.getStart());
725       const subsequentLists = filter$1(editor.selection.getSelectedBlocks(), isOlUlNode);
726       return firstList.toArray().concat(subsequentLists);
727     };
728     const getSelectedListRoots = editor => {
729       const selectedLists = getSelectedLists(editor);
730       return getUniqueListRoots(editor, selectedLists);
731     };
732     const getUniqueListRoots = (editor, lists) => {
733       const listRoots = map(lists, list => findLastParentListNode(editor, list).getOr(list));
734       return unique(listRoots);
735     };
737     const isCustomList = list => /\btox\-/.test(list.className);
738     const inList = (parents, listName) => findUntil(parents, isListNode, isTableCellNode).exists(list => list.nodeName === listName && !isCustomList(list));
739     const isWithinNonEditable = (editor, element) => element !== null && !editor.dom.isEditable(element);
740     const selectionIsWithinNonEditableList = editor => {
741       const parentList = getParentList(editor);
742       return isWithinNonEditable(editor, parentList);
743     };
744     const isWithinNonEditableList = (editor, element) => {
745       const parentList = editor.dom.getParent(element, 'ol,ul,dl');
746       return isWithinNonEditable(editor, parentList);
747     };
748     const setNodeChangeHandler = (editor, nodeChangeHandler) => {
749       const initialNode = editor.selection.getNode();
750       nodeChangeHandler({
751         parents: editor.dom.getParents(initialNode),
752         element: initialNode
753       });
754       editor.on('NodeChange', nodeChangeHandler);
755       return () => editor.off('NodeChange', nodeChangeHandler);
756     };
758     const fromElements = (elements, scope) => {
759       const doc = scope || document;
760       const fragment = doc.createDocumentFragment();
761       each$1(elements, element => {
762         fragment.appendChild(element.dom);
763       });
764       return SugarElement.fromDom(fragment);
765     };
767     const fireListEvent = (editor, action, element) => editor.dispatch('ListMutation', {
768       action,
769       element
770     });
772     const blank = r => s => s.replace(r, '');
773     const trim = blank(/^\s+|\s+$/g);
774     const isNotEmpty = s => s.length > 0;
775     const isEmpty$1 = s => !isNotEmpty(s);
777     const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
779     const internalSet = (dom, property, value) => {
780       if (!isString(value)) {
781         console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
782         throw new Error('CSS value must be a string: ' + value);
783       }
784       if (isSupported(dom)) {
785         dom.style.setProperty(property, value);
786       }
787     };
788     const set = (element, property, value) => {
789       const dom = element.dom;
790       internalSet(dom, property, value);
791     };
793     const joinSegment = (parent, child) => {
794       append$1(parent.item, child.list);
795     };
796     const joinSegments = segments => {
797       for (let i = 1; i < segments.length; i++) {
798         joinSegment(segments[i - 1], segments[i]);
799       }
800     };
801     const appendSegments = (head$1, tail) => {
802       lift2(last(head$1), head(tail), joinSegment);
803     };
804     const createSegment = (scope, listType) => {
805       const segment = {
806         list: SugarElement.fromTag(listType, scope),
807         item: SugarElement.fromTag('li', scope)
808       };
809       append$1(segment.list, segment.item);
810       return segment;
811     };
812     const createSegments = (scope, entry, size) => {
813       const segments = [];
814       for (let i = 0; i < size; i++) {
815         segments.push(createSegment(scope, entry.listType));
816       }
817       return segments;
818     };
819     const populateSegments = (segments, entry) => {
820       for (let i = 0; i < segments.length - 1; i++) {
821         set(segments[i].item, 'list-style-type', 'none');
822       }
823       last(segments).each(segment => {
824         setAll(segment.list, entry.listAttributes);
825         setAll(segment.item, entry.itemAttributes);
826         append(segment.item, entry.content);
827       });
828     };
829     const normalizeSegment = (segment, entry) => {
830       if (name(segment.list) !== entry.listType) {
831         segment.list = mutate(segment.list, entry.listType);
832       }
833       setAll(segment.list, entry.listAttributes);
834     };
835     const createItem = (scope, attr, content) => {
836       const item = SugarElement.fromTag('li', scope);
837       setAll(item, attr);
838       append(item, content);
839       return item;
840     };
841     const appendItem = (segment, item) => {
842       append$1(segment.list, item);
843       segment.item = item;
844     };
845     const writeShallow = (scope, cast, entry) => {
846       const newCast = cast.slice(0, entry.depth);
847       last(newCast).each(segment => {
848         const item = createItem(scope, entry.itemAttributes, entry.content);
849         appendItem(segment, item);
850         normalizeSegment(segment, entry);
851       });
852       return newCast;
853     };
854     const writeDeep = (scope, cast, entry) => {
855       const segments = createSegments(scope, entry, entry.depth - cast.length);
856       joinSegments(segments);
857       populateSegments(segments, entry);
858       appendSegments(cast, segments);
859       return cast.concat(segments);
860     };
861     const composeList = (scope, entries) => {
862       const cast = foldl(entries, (cast, entry) => {
863         return entry.depth > cast.length ? writeDeep(scope, cast, entry) : writeShallow(scope, cast, entry);
864       }, []);
865       return head(cast).map(segment => segment.list);
866     };
868     const isList = el => is(el, 'OL,UL');
869     const hasFirstChildList = el => firstChild(el).exists(isList);
870     const hasLastChildList = el => lastChild(el).exists(isList);
872     const isIndented = entry => entry.depth > 0;
873     const isSelected = entry => entry.isSelected;
874     const cloneItemContent = li => {
875       const children$1 = children(li);
876       const content = hasLastChildList(li) ? children$1.slice(0, -1) : children$1;
877       return map(content, deep);
878     };
879     const createEntry = (li, depth, isSelected) => parent(li).filter(isElement$1).map(list => ({
880       depth,
881       dirty: false,
882       isSelected,
883       content: cloneItemContent(li),
884       itemAttributes: clone$1(li),
885       listAttributes: clone$1(list),
886       listType: name(list)
887     }));
889     const indentEntry = (indentation, entry) => {
890       switch (indentation) {
891       case 'Indent':
892         entry.depth++;
893         break;
894       case 'Outdent':
895         entry.depth--;
896         break;
897       case 'Flatten':
898         entry.depth = 0;
899       }
900       entry.dirty = true;
901     };
903     const cloneListProperties = (target, source) => {
904       target.listType = source.listType;
905       target.listAttributes = { ...source.listAttributes };
906     };
907     const cleanListProperties = entry => {
908       entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== 'start');
909     };
910     const closestSiblingEntry = (entries, start) => {
911       const depth = entries[start].depth;
912       const matches = entry => entry.depth === depth && !entry.dirty;
913       const until = entry => entry.depth < depth;
914       return findUntil(reverse(entries.slice(0, start)), matches, until).orThunk(() => findUntil(entries.slice(start + 1), matches, until));
915     };
916     const normalizeEntries = entries => {
917       each$1(entries, (entry, i) => {
918         closestSiblingEntry(entries, i).fold(() => {
919           if (entry.dirty) {
920             cleanListProperties(entry);
921           }
922         }, matchingEntry => cloneListProperties(entry, matchingEntry));
923       });
924       return entries;
925     };
927     const Cell = initial => {
928       let value = initial;
929       const get = () => {
930         return value;
931       };
932       const set = v => {
933         value = v;
934       };
935       return {
936         get,
937         set
938       };
939     };
941     const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => {
942       itemSelection.each(selection => {
943         if (eq(selection.start, item)) {
944           selectionState.set(true);
945         }
946       });
947       const currentItemEntry = createEntry(item, depth, selectionState.get());
948       itemSelection.each(selection => {
949         if (eq(selection.end, item)) {
950           selectionState.set(false);
951         }
952       });
953       const childListEntries = lastChild(item).filter(isList).map(list => parseList(depth, itemSelection, selectionState, list)).getOr([]);
954       return currentItemEntry.toArray().concat(childListEntries);
955     }, list => parseList(depth, itemSelection, selectionState, list));
956     const parseList = (depth, itemSelection, selectionState, list) => bind(children(list), element => {
957       const parser = isList(element) ? parseList : parseItem;
958       const newDepth = depth + 1;
959       return parser(newDepth, itemSelection, selectionState, element);
960     });
961     const parseLists = (lists, itemSelection) => {
962       const selectionState = Cell(false);
963       const initialDepth = 0;
964       return map(lists, list => ({
965         sourceList: list,
966         entries: parseList(initialDepth, itemSelection, selectionState, list)
967       }));
968     };
970     const outdentedComposer = (editor, entries) => {
971       const normalizedEntries = normalizeEntries(entries);
972       return map(normalizedEntries, entry => {
973         const content = fromElements(entry.content);
974         return SugarElement.fromDom(createTextBlock(editor, content.dom));
975       });
976     };
977     const indentedComposer = (editor, entries) => {
978       const normalizedEntries = normalizeEntries(entries);
979       return composeList(editor.contentDocument, normalizedEntries).toArray();
980     };
981     const composeEntries = (editor, entries) => bind(groupBy(entries, isIndented), entries => {
982       const groupIsIndented = head(entries).exists(isIndented);
983       return groupIsIndented ? indentedComposer(editor, entries) : outdentedComposer(editor, entries);
984     });
985     const indentSelectedEntries = (entries, indentation) => {
986       each$1(filter$1(entries, isSelected), entry => indentEntry(indentation, entry));
987     };
988     const getItemSelection = editor => {
989       const selectedListItems = map(getSelectedListItems(editor), SugarElement.fromDom);
990       return lift2(find(selectedListItems, not(hasFirstChildList)), find(reverse(selectedListItems), not(hasFirstChildList)), (start, end) => ({
991         start,
992         end
993       }));
994     };
995     const listIndentation = (editor, lists, indentation) => {
996       const entrySets = parseLists(lists, getItemSelection(editor));
997       each$1(entrySets, entrySet => {
998         indentSelectedEntries(entrySet.entries, indentation);
999         const composedLists = composeEntries(editor, entrySet.entries);
1000         each$1(composedLists, composedList => {
1001           fireListEvent(editor, indentation === 'Indent' ? 'IndentList' : 'OutdentList', composedList.dom);
1002         });
1003         before(entrySet.sourceList, composedLists);
1004         remove(entrySet.sourceList);
1005       });
1006     };
1008     const selectionIndentation = (editor, indentation) => {
1009       const lists = fromDom(getSelectedListRoots(editor));
1010       const dlItems = fromDom(getSelectedDlItems(editor));
1011       let isHandled = false;
1012       if (lists.length || dlItems.length) {
1013         const bookmark = editor.selection.getBookmark();
1014         listIndentation(editor, lists, indentation);
1015         dlIndentation(editor, indentation, dlItems);
1016         editor.selection.moveToBookmark(bookmark);
1017         editor.selection.setRng(normalizeRange(editor.selection.getRng()));
1018         editor.nodeChanged();
1019         isHandled = true;
1020       }
1021       return isHandled;
1022     };
1023     const handleIndentation = (editor, indentation) => !selectionIsWithinNonEditableList(editor) && selectionIndentation(editor, indentation);
1024     const indentListSelection = editor => handleIndentation(editor, 'Indent');
1025     const outdentListSelection = editor => handleIndentation(editor, 'Outdent');
1026     const flattenListSelection = editor => handleIndentation(editor, 'Flatten');
1028     const zeroWidth = '\uFEFF';
1029     const isZwsp = char => char === zeroWidth;
1031     var global$1 = tinymce.util.Tools.resolve('tinymce.dom.BookmarkManager');
1033     const DOM$1 = global$3.DOM;
1034     const createBookmark = rng => {
1035       const bookmark = {};
1036       const setupEndPoint = start => {
1037         let container = rng[start ? 'startContainer' : 'endContainer'];
1038         let offset = rng[start ? 'startOffset' : 'endOffset'];
1039         if (isElement(container)) {
1040           const offsetNode = DOM$1.create('span', { 'data-mce-type': 'bookmark' });
1041           if (container.hasChildNodes()) {
1042             offset = Math.min(offset, container.childNodes.length - 1);
1043             if (start) {
1044               container.insertBefore(offsetNode, container.childNodes[offset]);
1045             } else {
1046               DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
1047             }
1048           } else {
1049             container.appendChild(offsetNode);
1050           }
1051           container = offsetNode;
1052           offset = 0;
1053         }
1054         bookmark[start ? 'startContainer' : 'endContainer'] = container;
1055         bookmark[start ? 'startOffset' : 'endOffset'] = offset;
1056       };
1057       setupEndPoint(true);
1058       if (!rng.collapsed) {
1059         setupEndPoint();
1060       }
1061       return bookmark;
1062     };
1063     const resolveBookmark = bookmark => {
1064       const restoreEndPoint = start => {
1065         const nodeIndex = container => {
1066           var _a;
1067           let node = (_a = container.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild;
1068           let idx = 0;
1069           while (node) {
1070             if (node === container) {
1071               return idx;
1072             }
1073             if (!isElement(node) || node.getAttribute('data-mce-type') !== 'bookmark') {
1074               idx++;
1075             }
1076             node = node.nextSibling;
1077           }
1078           return -1;
1079         };
1080         let container = bookmark[start ? 'startContainer' : 'endContainer'];
1081         let offset = bookmark[start ? 'startOffset' : 'endOffset'];
1082         if (!container) {
1083           return;
1084         }
1085         if (isElement(container) && container.parentNode) {
1086           const node = container;
1087           offset = nodeIndex(container);
1088           container = container.parentNode;
1089           DOM$1.remove(node);
1090           if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
1091             container.appendChild(DOM$1.create('br'));
1092           }
1093         }
1094         bookmark[start ? 'startContainer' : 'endContainer'] = container;
1095         bookmark[start ? 'startOffset' : 'endOffset'] = offset;
1096       };
1097       restoreEndPoint(true);
1098       restoreEndPoint();
1099       const rng = DOM$1.createRng();
1100       rng.setStart(bookmark.startContainer, bookmark.startOffset);
1101       if (bookmark.endContainer) {
1102         rng.setEnd(bookmark.endContainer, bookmark.endOffset);
1103       }
1104       return normalizeRange(rng);
1105     };
1107     const listToggleActionFromListName = listName => {
1108       switch (listName) {
1109       case 'UL':
1110         return 'ToggleUlList';
1111       case 'OL':
1112         return 'ToggleOlList';
1113       case 'DL':
1114         return 'ToggleDLList';
1115       }
1116     };
1118     const updateListStyle = (dom, el, detail) => {
1119       const type = detail['list-style-type'] ? detail['list-style-type'] : null;
1120       dom.setStyle(el, 'list-style-type', type);
1121     };
1122     const setAttribs = (elm, attrs) => {
1123       global$2.each(attrs, (value, key) => {
1124         elm.setAttribute(key, value);
1125       });
1126     };
1127     const updateListAttrs = (dom, el, detail) => {
1128       setAttribs(el, detail['list-attributes']);
1129       global$2.each(dom.select('li', el), li => {
1130         setAttribs(li, detail['list-item-attributes']);
1131       });
1132     };
1133     const updateListWithDetails = (dom, el, detail) => {
1134       updateListStyle(dom, el, detail);
1135       updateListAttrs(dom, el, detail);
1136     };
1137     const removeStyles = (dom, element, styles) => {
1138       global$2.each(styles, style => dom.setStyle(element, style, ''));
1139     };
1140     const isInline = (editor, node) => isNonNullable(node) && !isBlock(node, editor.schema.getBlockElements());
1141     const getEndPointNode = (editor, rng, start, root) => {
1142       let container = rng[start ? 'startContainer' : 'endContainer'];
1143       const offset = rng[start ? 'startOffset' : 'endOffset'];
1144       if (isElement(container)) {
1145         container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
1146       }
1147       if (!start && isBr(container.nextSibling)) {
1148         container = container.nextSibling;
1149       }
1150       const findBetterContainer = (container, forward) => {
1151         var _a;
1152         const walker = new global$5(container, root);
1153         const dir = forward ? 'next' : 'prev';
1154         let node;
1155         while (node = walker[dir]()) {
1156           if (!(isVoid(editor, node) || isZwsp(node.textContent) || ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length) === 0)) {
1157             return Optional.some(node);
1158           }
1159         }
1160         return Optional.none();
1161       };
1162       if (start && isTextNode$1(container)) {
1163         if (isZwsp(container.textContent)) {
1164           container = findBetterContainer(container, false).getOr(container);
1165         } else {
1166           if (container.parentNode !== null && isInline(editor, container.parentNode)) {
1167             container = container.parentNode;
1168           }
1169           while (container.previousSibling !== null && (isInline(editor, container.previousSibling) || isTextNode$1(container.previousSibling))) {
1170             container = container.previousSibling;
1171           }
1172         }
1173       }
1174       if (!start && isTextNode$1(container)) {
1175         if (isZwsp(container.textContent)) {
1176           container = findBetterContainer(container, true).getOr(container);
1177         } else {
1178           if (container.parentNode !== null && isInline(editor, container.parentNode)) {
1179             container = container.parentNode;
1180           }
1181           while (container.nextSibling !== null && (isInline(editor, container.nextSibling) || isTextNode$1(container.nextSibling))) {
1182             container = container.nextSibling;
1183           }
1184         }
1185       }
1186       while (container.parentNode !== root) {
1187         const parent = container.parentNode;
1188         if (isTextBlock(editor, container)) {
1189           return container;
1190         }
1191         if (/^(TD|TH)$/.test(parent.nodeName)) {
1192           return container;
1193         }
1194         container = parent;
1195       }
1196       return container;
1197     };
1198     const getSelectedTextBlocks = (editor, rng, root) => {
1199       const textBlocks = [];
1200       const dom = editor.dom;
1201       const startNode = getEndPointNode(editor, rng, true, root);
1202       const endNode = getEndPointNode(editor, rng, false, root);
1203       let block;
1204       const siblings = [];
1205       for (let node = startNode; node; node = node.nextSibling) {
1206         siblings.push(node);
1207         if (node === endNode) {
1208           break;
1209         }
1210       }
1211       global$2.each(siblings, node => {
1212         var _a;
1213         if (isTextBlock(editor, node)) {
1214           textBlocks.push(node);
1215           block = null;
1216           return;
1217         }
1218         if (dom.isBlock(node) || isBr(node)) {
1219           if (isBr(node)) {
1220             dom.remove(node);
1221           }
1222           block = null;
1223           return;
1224         }
1225         const nextSibling = node.nextSibling;
1226         if (global$1.isBookmarkNode(node)) {
1227           if (isListNode(nextSibling) || isTextBlock(editor, nextSibling) || !nextSibling && node.parentNode === root) {
1228             block = null;
1229             return;
1230           }
1231         }
1232         if (!block) {
1233           block = dom.create('p');
1234           (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(block, node);
1235           textBlocks.push(block);
1236         }
1237         block.appendChild(node);
1238       });
1239       return textBlocks;
1240     };
1241     const hasCompatibleStyle = (dom, sib, detail) => {
1242       const sibStyle = dom.getStyle(sib, 'list-style-type');
1243       let detailStyle = detail ? detail['list-style-type'] : '';
1244       detailStyle = detailStyle === null ? '' : detailStyle;
1245       return sibStyle === detailStyle;
1246     };
1247     const applyList = (editor, listName, detail) => {
1248       const rng = editor.selection.getRng();
1249       let listItemName = 'LI';
1250       const root = getClosestListHost(editor, editor.selection.getStart(true));
1251       const dom = editor.dom;
1252       if (dom.getContentEditable(editor.selection.getNode()) === 'false') {
1253         return;
1254       }
1255       listName = listName.toUpperCase();
1256       if (listName === 'DL') {
1257         listItemName = 'DT';
1258       }
1259       const bookmark = createBookmark(rng);
1260       const selectedTextBlocks = filter$1(getSelectedTextBlocks(editor, rng, root), editor.dom.isEditable);
1261       global$2.each(selectedTextBlocks, block => {
1262         let listBlock;
1263         const sibling = block.previousSibling;
1264         const parent = block.parentNode;
1265         if (!isListItemNode(parent)) {
1266           if (sibling && isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(dom, sibling, detail)) {
1267             listBlock = sibling;
1268             block = dom.rename(block, listItemName);
1269             sibling.appendChild(block);
1270           } else {
1271             listBlock = dom.create(listName);
1272             parent.insertBefore(listBlock, block);
1273             listBlock.appendChild(block);
1274             block = dom.rename(block, listItemName);
1275           }
1276           removeStyles(dom, block, [
1277             'margin',
1278             'margin-right',
1279             'margin-bottom',
1280             'margin-left',
1281             'margin-top',
1282             'padding',
1283             'padding-right',
1284             'padding-bottom',
1285             'padding-left',
1286             'padding-top'
1287           ]);
1288           updateListWithDetails(dom, listBlock, detail);
1289           mergeWithAdjacentLists(editor.dom, listBlock);
1290         }
1291       });
1292       editor.selection.setRng(resolveBookmark(bookmark));
1293     };
1294     const isValidLists = (list1, list2) => {
1295       return isListNode(list1) && list1.nodeName === (list2 === null || list2 === void 0 ? void 0 : list2.nodeName);
1296     };
1297     const hasSameListStyle = (dom, list1, list2) => {
1298       const targetStyle = dom.getStyle(list1, 'list-style-type', true);
1299       const style = dom.getStyle(list2, 'list-style-type', true);
1300       return targetStyle === style;
1301     };
1302     const hasSameClasses = (elm1, elm2) => {
1303       return elm1.className === elm2.className;
1304     };
1305     const shouldMerge = (dom, list1, list2) => {
1306       return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
1307     };
1308     const mergeWithAdjacentLists = (dom, listBlock) => {
1309       let node;
1310       let sibling = listBlock.nextSibling;
1311       if (shouldMerge(dom, listBlock, sibling)) {
1312         const liSibling = sibling;
1313         while (node = liSibling.firstChild) {
1314           listBlock.appendChild(node);
1315         }
1316         dom.remove(liSibling);
1317       }
1318       sibling = listBlock.previousSibling;
1319       if (shouldMerge(dom, listBlock, sibling)) {
1320         const liSibling = sibling;
1321         while (node = liSibling.lastChild) {
1322           listBlock.insertBefore(node, listBlock.firstChild);
1323         }
1324         dom.remove(liSibling);
1325       }
1326     };
1327     const updateList$1 = (editor, list, listName, detail) => {
1328       if (list.nodeName !== listName) {
1329         const newList = editor.dom.rename(list, listName);
1330         updateListWithDetails(editor.dom, newList, detail);
1331         fireListEvent(editor, listToggleActionFromListName(listName), newList);
1332       } else {
1333         updateListWithDetails(editor.dom, list, detail);
1334         fireListEvent(editor, listToggleActionFromListName(listName), list);
1335       }
1336     };
1337     const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
1338       const parentIsList = isListNode(parentList);
1339       if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail)) {
1340         flattenListSelection(editor);
1341       } else {
1342         applyList(editor, listName, detail);
1343         const bookmark = createBookmark(editor.selection.getRng());
1344         const allLists = parentIsList ? [
1345           parentList,
1346           ...lists
1347         ] : lists;
1348         global$2.each(allLists, elm => {
1349           updateList$1(editor, elm, listName, detail);
1350         });
1351         editor.selection.setRng(resolveBookmark(bookmark));
1352       }
1353     };
1354     const hasListStyleDetail = detail => {
1355       return 'list-style-type' in detail;
1356     };
1357     const toggleSingleList = (editor, parentList, listName, detail) => {
1358       if (parentList === editor.getBody()) {
1359         return;
1360       }
1361       if (parentList) {
1362         if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
1363           flattenListSelection(editor);
1364         } else {
1365           const bookmark = createBookmark(editor.selection.getRng());
1366           updateListWithDetails(editor.dom, parentList, detail);
1367           const newList = editor.dom.rename(parentList, listName);
1368           mergeWithAdjacentLists(editor.dom, newList);
1369           editor.selection.setRng(resolveBookmark(bookmark));
1370           applyList(editor, listName, detail);
1371           fireListEvent(editor, listToggleActionFromListName(listName), newList);
1372         }
1373       } else {
1374         applyList(editor, listName, detail);
1375         fireListEvent(editor, listToggleActionFromListName(listName), parentList);
1376       }
1377     };
1378     const toggleList = (editor, listName, _detail) => {
1379       const parentList = getParentList(editor);
1380       if (isWithinNonEditableList(editor, parentList)) {
1381         return;
1382       }
1383       const selectedSubLists = getSelectedSubLists(editor);
1384       const detail = isObject(_detail) ? _detail : {};
1385       if (selectedSubLists.length > 0) {
1386         toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
1387       } else {
1388         toggleSingleList(editor, parentList, listName, detail);
1389       }
1390     };
1392     const DOM = global$3.DOM;
1393     const normalizeList = (dom, list) => {
1394       const parentNode = list.parentElement;
1395       if (parentNode && parentNode.nodeName === 'LI' && parentNode.firstChild === list) {
1396         const sibling = parentNode.previousSibling;
1397         if (sibling && sibling.nodeName === 'LI') {
1398           sibling.appendChild(list);
1399           if (isEmpty$2(dom, parentNode)) {
1400             DOM.remove(parentNode);
1401           }
1402         } else {
1403           DOM.setStyle(parentNode, 'listStyleType', 'none');
1404         }
1405       }
1406       if (isListNode(parentNode)) {
1407         const sibling = parentNode.previousSibling;
1408         if (sibling && sibling.nodeName === 'LI') {
1409           sibling.appendChild(list);
1410         }
1411       }
1412     };
1413     const normalizeLists = (dom, element) => {
1414       const lists = global$2.grep(dom.select('ol,ul', element));
1415       global$2.each(lists, list => {
1416         normalizeList(dom, list);
1417       });
1418     };
1420     const findNextCaretContainer = (editor, rng, isForward, root) => {
1421       let node = rng.startContainer;
1422       const offset = rng.startOffset;
1423       if (isTextNode$1(node) && (isForward ? offset < node.data.length : offset > 0)) {
1424         return node;
1425       }
1426       const nonEmptyBlocks = editor.schema.getNonEmptyElements();
1427       if (isElement(node)) {
1428         node = global$6.getNode(node, offset);
1429       }
1430       const walker = new global$5(node, root);
1431       if (isForward) {
1432         if (isBogusBr(editor.dom, node)) {
1433           walker.next();
1434         }
1435       }
1436       const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
1437       while (node = walkFn()) {
1438         if (node.nodeName === 'LI' && !node.hasChildNodes()) {
1439           return node;
1440         }
1441         if (nonEmptyBlocks[node.nodeName]) {
1442           return node;
1443         }
1444         if (isTextNode$1(node) && node.data.length > 0) {
1445           return node;
1446         }
1447       }
1448       return null;
1449     };
1450     const hasOnlyOneBlockChild = (dom, elm) => {
1451       const childNodes = elm.childNodes;
1452       return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
1453     };
1454     const unwrapSingleBlockChild = (dom, elm) => {
1455       if (hasOnlyOneBlockChild(dom, elm)) {
1456         dom.remove(elm.firstChild, true);
1457       }
1458     };
1459     const moveChildren = (dom, fromElm, toElm) => {
1460       let node;
1461       const targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
1462       unwrapSingleBlockChild(dom, fromElm);
1463       if (!isEmpty$2(dom, fromElm, true)) {
1464         while (node = fromElm.firstChild) {
1465           targetElm.appendChild(node);
1466         }
1467       }
1468     };
1469     const mergeLiElements = (dom, fromElm, toElm) => {
1470       let listNode;
1471       const ul = fromElm.parentNode;
1472       if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
1473         return;
1474       }
1475       if (isListNode(toElm.lastChild)) {
1476         listNode = toElm.lastChild;
1477       }
1478       if (ul === toElm.lastChild) {
1479         if (isBr(ul.previousSibling)) {
1480           dom.remove(ul.previousSibling);
1481         }
1482       }
1483       const node = toElm.lastChild;
1484       if (node && isBr(node) && fromElm.hasChildNodes()) {
1485         dom.remove(node);
1486       }
1487       if (isEmpty$2(dom, toElm, true)) {
1488         empty(SugarElement.fromDom(toElm));
1489       }
1490       moveChildren(dom, fromElm, toElm);
1491       if (listNode) {
1492         toElm.appendChild(listNode);
1493       }
1494       const contains$1 = contains(SugarElement.fromDom(toElm), SugarElement.fromDom(fromElm));
1495       const nestedLists = contains$1 ? dom.getParents(fromElm, isListNode, toElm) : [];
1496       dom.remove(fromElm);
1497       each$1(nestedLists, list => {
1498         if (isEmpty$2(dom, list) && list !== dom.getRoot()) {
1499           dom.remove(list);
1500         }
1501       });
1502     };
1503     const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
1504       empty(SugarElement.fromDom(toLi));
1505       mergeLiElements(editor.dom, fromLi, toLi);
1506       editor.selection.setCursorLocation(toLi, 0);
1507     };
1508     const mergeForward = (editor, rng, fromLi, toLi) => {
1509       const dom = editor.dom;
1510       if (dom.isEmpty(toLi)) {
1511         mergeIntoEmptyLi(editor, fromLi, toLi);
1512       } else {
1513         const bookmark = createBookmark(rng);
1514         mergeLiElements(dom, fromLi, toLi);
1515         editor.selection.setRng(resolveBookmark(bookmark));
1516       }
1517     };
1518     const mergeBackward = (editor, rng, fromLi, toLi) => {
1519       const bookmark = createBookmark(rng);
1520       mergeLiElements(editor.dom, fromLi, toLi);
1521       const resolvedBookmark = resolveBookmark(bookmark);
1522       editor.selection.setRng(resolvedBookmark);
1523     };
1524     const backspaceDeleteFromListToListCaret = (editor, isForward) => {
1525       const dom = editor.dom, selection = editor.selection;
1526       const selectionStartElm = selection.getStart();
1527       const root = getClosestEditingHost(editor, selectionStartElm);
1528       const li = dom.getParent(selection.getStart(), 'LI', root);
1529       if (li) {
1530         const ul = li.parentElement;
1531         if (ul === editor.getBody() && isEmpty$2(dom, ul)) {
1532           return true;
1533         }
1534         const rng = normalizeRange(selection.getRng());
1535         const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
1536         if (otherLi && otherLi !== li) {
1537           editor.undoManager.transact(() => {
1538             if (isForward) {
1539               mergeForward(editor, rng, otherLi, li);
1540             } else {
1541               if (isFirstChild(li)) {
1542                 outdentListSelection(editor);
1543               } else {
1544                 mergeBackward(editor, rng, li, otherLi);
1545               }
1546             }
1547           });
1548           return true;
1549         } else if (!otherLi) {
1550           if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
1551             editor.undoManager.transact(() => {
1552               flattenListSelection(editor);
1553             });
1554             return true;
1555           }
1556         }
1557       }
1558       return false;
1559     };
1560     const removeBlock = (dom, block, root) => {
1561       const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
1562       dom.remove(block);
1563       if (parentBlock && dom.isEmpty(parentBlock)) {
1564         dom.remove(parentBlock);
1565       }
1566     };
1567     const backspaceDeleteIntoListCaret = (editor, isForward) => {
1568       const dom = editor.dom;
1569       const selectionStartElm = editor.selection.getStart();
1570       const root = getClosestEditingHost(editor, selectionStartElm);
1571       const block = dom.getParent(selectionStartElm, dom.isBlock, root);
1572       if (block && dom.isEmpty(block)) {
1573         const rng = normalizeRange(editor.selection.getRng());
1574         const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
1575         if (otherLi) {
1576           const findValidElement = element => contains$1([
1577             'td',
1578             'th',
1579             'caption'
1580           ], name(element));
1581           const findRoot = node => node.dom === root;
1582           const otherLiCell = closest(SugarElement.fromDom(otherLi), findValidElement, findRoot);
1583           const caretCell = closest(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
1584           if (!equals(otherLiCell, caretCell, eq)) {
1585             return false;
1586           }
1587           editor.undoManager.transact(() => {
1588             removeBlock(dom, block, root);
1589             mergeWithAdjacentLists(dom, otherLi.parentNode);
1590             editor.selection.select(otherLi, true);
1591             editor.selection.collapse(isForward);
1592           });
1593           return true;
1594         }
1595       }
1596       return false;
1597     };
1598     const backspaceDeleteCaret = (editor, isForward) => {
1599       return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
1600     };
1601     const hasListSelection = editor => {
1602       const selectionStartElm = editor.selection.getStart();
1603       const root = getClosestEditingHost(editor, selectionStartElm);
1604       const startListParent = editor.dom.getParent(selectionStartElm, 'LI,DT,DD', root);
1605       return startListParent || getSelectedListItems(editor).length > 0;
1606     };
1607     const backspaceDeleteRange = editor => {
1608       if (hasListSelection(editor)) {
1609         editor.undoManager.transact(() => {
1610           editor.execCommand('Delete');
1611           normalizeLists(editor.dom, editor.getBody());
1612         });
1613         return true;
1614       }
1615       return false;
1616     };
1617     const backspaceDelete = (editor, isForward) => {
1618       const selection = editor.selection;
1619       return !isWithinNonEditableList(editor, selection.getNode()) && (selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor));
1620     };
1621     const setup$2 = editor => {
1622       editor.on('ExecCommand', e => {
1623         const cmd = e.command.toLowerCase();
1624         if ((cmd === 'delete' || cmd === 'forwarddelete') && hasListSelection(editor)) {
1625           normalizeLists(editor.dom, editor.getBody());
1626         }
1627       });
1628       editor.on('keydown', e => {
1629         if (e.keyCode === global$4.BACKSPACE) {
1630           if (backspaceDelete(editor, false)) {
1631             e.preventDefault();
1632           }
1633         } else if (e.keyCode === global$4.DELETE) {
1634           if (backspaceDelete(editor, true)) {
1635             e.preventDefault();
1636           }
1637         }
1638       });
1639     };
1641     const get = editor => ({
1642       backspaceDelete: isForward => {
1643         backspaceDelete(editor, isForward);
1644       }
1645     });
1647     const updateList = (editor, update) => {
1648       const parentList = getParentList(editor);
1649       if (parentList === null || isWithinNonEditableList(editor, parentList)) {
1650         return;
1651       }
1652       editor.undoManager.transact(() => {
1653         if (isObject(update.styles)) {
1654           editor.dom.setStyles(parentList, update.styles);
1655         }
1656         if (isObject(update.attrs)) {
1657           each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
1658         }
1659       });
1660     };
1662     const parseAlphabeticBase26 = str => {
1663       const chars = reverse(trim(str).split(''));
1664       const values = map(chars, (char, i) => {
1665         const charValue = char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 1;
1666         return Math.pow(26, i) * charValue;
1667       });
1668       return foldl(values, (sum, v) => sum + v, 0);
1669     };
1670     const composeAlphabeticBase26 = value => {
1671       value--;
1672       if (value < 0) {
1673         return '';
1674       } else {
1675         const remainder = value % 26;
1676         const quotient = Math.floor(value / 26);
1677         const rest = composeAlphabeticBase26(quotient);
1678         const char = String.fromCharCode('A'.charCodeAt(0) + remainder);
1679         return rest + char;
1680       }
1681     };
1682     const isUppercase = str => /^[A-Z]+$/.test(str);
1683     const isLowercase = str => /^[a-z]+$/.test(str);
1684     const isNumeric = str => /^[0-9]+$/.test(str);
1685     const deduceListType = start => {
1686       if (isNumeric(start)) {
1687         return 2;
1688       } else if (isUppercase(start)) {
1689         return 0;
1690       } else if (isLowercase(start)) {
1691         return 1;
1692       } else if (isEmpty$1(start)) {
1693         return 3;
1694       } else {
1695         return 4;
1696       }
1697     };
1698     const parseStartValue = start => {
1699       switch (deduceListType(start)) {
1700       case 2:
1701         return Optional.some({
1702           listStyleType: Optional.none(),
1703           start
1704         });
1705       case 0:
1706         return Optional.some({
1707           listStyleType: Optional.some('upper-alpha'),
1708           start: parseAlphabeticBase26(start).toString()
1709         });
1710       case 1:
1711         return Optional.some({
1712           listStyleType: Optional.some('lower-alpha'),
1713           start: parseAlphabeticBase26(start).toString()
1714         });
1715       case 3:
1716         return Optional.some({
1717           listStyleType: Optional.none(),
1718           start: ''
1719         });
1720       case 4:
1721         return Optional.none();
1722       }
1723     };
1724     const parseDetail = detail => {
1725       const start = parseInt(detail.start, 10);
1726       if (is$2(detail.listStyleType, 'upper-alpha')) {
1727         return composeAlphabeticBase26(start);
1728       } else if (is$2(detail.listStyleType, 'lower-alpha')) {
1729         return composeAlphabeticBase26(start).toLowerCase();
1730       } else {
1731         return detail.start;
1732       }
1733     };
1735     const open = editor => {
1736       const currentList = getParentList(editor);
1737       if (!isOlNode(currentList) || isWithinNonEditableList(editor, currentList)) {
1738         return;
1739       }
1740       editor.windowManager.open({
1741         title: 'List Properties',
1742         body: {
1743           type: 'panel',
1744           items: [{
1745               type: 'input',
1746               name: 'start',
1747               label: 'Start list at number',
1748               inputMode: 'numeric'
1749             }]
1750         },
1751         initialData: {
1752           start: parseDetail({
1753             start: editor.dom.getAttrib(currentList, 'start', '1'),
1754             listStyleType: Optional.from(editor.dom.getStyle(currentList, 'list-style-type'))
1755           })
1756         },
1757         buttons: [
1758           {
1759             type: 'cancel',
1760             name: 'cancel',
1761             text: 'Cancel'
1762           },
1763           {
1764             type: 'submit',
1765             name: 'save',
1766             text: 'Save',
1767             primary: true
1768           }
1769         ],
1770         onSubmit: api => {
1771           const data = api.getData();
1772           parseStartValue(data.start).each(detail => {
1773             editor.execCommand('mceListUpdate', false, {
1774               attrs: { start: detail.start === '1' ? '' : detail.start },
1775               styles: { 'list-style-type': detail.listStyleType.getOr('') }
1776             });
1777           });
1778           api.close();
1779         }
1780       });
1781     };
1783     const queryListCommandState = (editor, listName) => () => {
1784       const parentList = getParentList(editor);
1785       return isNonNullable(parentList) && parentList.nodeName === listName;
1786     };
1787     const registerDialog = editor => {
1788       editor.addCommand('mceListProps', () => {
1789         open(editor);
1790       });
1791     };
1792     const register$2 = editor => {
1793       editor.on('BeforeExecCommand', e => {
1794         const cmd = e.command.toLowerCase();
1795         if (cmd === 'indent') {
1796           indentListSelection(editor);
1797         } else if (cmd === 'outdent') {
1798           outdentListSelection(editor);
1799         }
1800       });
1801       editor.addCommand('InsertUnorderedList', (ui, detail) => {
1802         toggleList(editor, 'UL', detail);
1803       });
1804       editor.addCommand('InsertOrderedList', (ui, detail) => {
1805         toggleList(editor, 'OL', detail);
1806       });
1807       editor.addCommand('InsertDefinitionList', (ui, detail) => {
1808         toggleList(editor, 'DL', detail);
1809       });
1810       editor.addCommand('RemoveList', () => {
1811         flattenListSelection(editor);
1812       });
1813       registerDialog(editor);
1814       editor.addCommand('mceListUpdate', (ui, detail) => {
1815         if (isObject(detail)) {
1816           updateList(editor, detail);
1817         }
1818       });
1819       editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
1820       editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
1821       editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
1822     };
1824     var global = tinymce.util.Tools.resolve('tinymce.html.Node');
1826     const isTextNode = node => node.type === 3;
1827     const isEmpty = nodeBuffer => nodeBuffer.length === 0;
1828     const wrapInvalidChildren = list => {
1829       const insertListItem = (buffer, refNode) => {
1830         const li = global.create('li');
1831         each$1(buffer, node => li.append(node));
1832         if (refNode) {
1833           list.insert(li, refNode, true);
1834         } else {
1835           list.append(li);
1836         }
1837       };
1838       const reducer = (buffer, node) => {
1839         if (isTextNode(node)) {
1840           return [
1841             ...buffer,
1842             node
1843           ];
1844         } else if (!isEmpty(buffer) && !isTextNode(node)) {
1845           insertListItem(buffer, node);
1846           return [];
1847         } else {
1848           return buffer;
1849         }
1850       };
1851       const restBuffer = foldl(list.children(), reducer, []);
1852       if (!isEmpty(restBuffer)) {
1853         insertListItem(restBuffer);
1854       }
1855     };
1856     const setup$1 = editor => {
1857       editor.on('PreInit', () => {
1858         const {parser} = editor;
1859         parser.addNodeFilter('ul,ol', nodes => each$1(nodes, wrapInvalidChildren));
1860       });
1861     };
1863     const setupTabKey = editor => {
1864       editor.on('keydown', e => {
1865         if (e.keyCode !== global$4.TAB || global$4.metaKeyPressed(e)) {
1866           return;
1867         }
1868         editor.undoManager.transact(() => {
1869           if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
1870             e.preventDefault();
1871           }
1872         });
1873       });
1874     };
1875     const setup = editor => {
1876       if (shouldIndentOnTab(editor)) {
1877         setupTabKey(editor);
1878       }
1879       setup$2(editor);
1880     };
1882     const setupToggleButtonHandler = (editor, listName) => api => {
1883       const toggleButtonHandler = e => {
1884         api.setActive(inList(e.parents, listName));
1885         api.setEnabled(!isWithinNonEditableList(editor, e.element) && editor.selection.isEditable());
1886       };
1887       api.setEnabled(editor.selection.isEditable());
1888       return setNodeChangeHandler(editor, toggleButtonHandler);
1889     };
1890     const register$1 = editor => {
1891       const exec = command => () => editor.execCommand(command);
1892       if (!editor.hasPlugin('advlist')) {
1893         editor.ui.registry.addToggleButton('numlist', {
1894           icon: 'ordered-list',
1895           active: false,
1896           tooltip: 'Numbered list',
1897           onAction: exec('InsertOrderedList'),
1898           onSetup: setupToggleButtonHandler(editor, 'OL')
1899         });
1900         editor.ui.registry.addToggleButton('bullist', {
1901           icon: 'unordered-list',
1902           active: false,
1903           tooltip: 'Bullet list',
1904           onAction: exec('InsertUnorderedList'),
1905           onSetup: setupToggleButtonHandler(editor, 'UL')
1906         });
1907       }
1908     };
1910     const setupMenuButtonHandler = (editor, listName) => api => {
1911       const menuButtonHandler = e => api.setEnabled(inList(e.parents, listName) && !isWithinNonEditableList(editor, e.element));
1912       return setNodeChangeHandler(editor, menuButtonHandler);
1913     };
1914     const register = editor => {
1915       const listProperties = {
1916         text: 'List properties...',
1917         icon: 'ordered-list',
1918         onAction: () => editor.execCommand('mceListProps'),
1919         onSetup: setupMenuButtonHandler(editor, 'OL')
1920       };
1921       editor.ui.registry.addMenuItem('listprops', listProperties);
1922       editor.ui.registry.addContextMenu('lists', {
1923         update: node => {
1924           const parentList = getParentList(editor, node);
1925           return isOlNode(parentList) ? ['listprops'] : [];
1926         }
1927       });
1928     };
1930     var Plugin = () => {
1931       global$7.add('lists', editor => {
1932         register$3(editor);
1933         setup$1(editor);
1934         if (!editor.hasPlugin('rtc', true)) {
1935           setup(editor);
1936           register$2(editor);
1937         } else {
1938           registerDialog(editor);
1939         }
1940         register$1(editor);
1941         register(editor);
1942         return get(editor);
1943       });
1944     };
1946     Plugin();
1948 })();