2 * TinyMCE version 6.6.2 (2023-08-09)
8 var global$7 = tinymce.util.Tools.resolve('tinymce.PluginManager');
10 const hasProto = (v, constructor, predicate) => {
12 if (predicate(v, constructor.prototype)) {
15 return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
22 } else if (t === 'object' && Array.isArray(x)) {
24 } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
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');
43 const constant = value => {
48 const tripleEquals = (a, b) => {
51 const not = f => t => !f(t);
52 const never = constant(false);
55 constructor(tag, value) {
60 return new Optional(true, value);
63 return Optional.singletonNone;
65 fold(onNone, onSome) {
67 return onSome(this.value);
80 return Optional.some(mapper(this.value));
82 return Optional.none();
87 return binder(this.value);
89 return Optional.none();
93 return this.tag && predicate(this.value);
96 return !this.tag || predicate(this.value);
99 if (!this.tag || predicate(this.value)) {
102 return Optional.none();
106 return this.tag ? this.value : replacement;
109 return this.tag ? this : replacement;
112 return this.tag ? this.value : thunk();
115 return this.tag ? this : thunk();
119 throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
125 return isNonNullable(value) ? Optional.some(value) : Optional.none();
128 return this.tag ? this.value : null;
139 return this.tag ? [this.value] : [];
142 return this.tag ? `some(${ this.value })` : 'none()';
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++) {
161 const map = (xs, f) => {
162 const len = xs.length;
163 const r = new Array(len);
164 for (let i = 0; i < len; i++) {
170 const each$1 = (xs, f) => {
171 for (let i = 0, len = xs.length; i < len; i++) {
176 const filter$1 = (xs, pred) => {
178 for (let i = 0, len = xs.length; i < len; i++) {
186 const groupBy = (xs, f) => {
187 if (xs.length === 0) {
190 let wasType = f(xs[0]);
193 for (let i = 0, len = xs.length; i < len; i++) {
196 if (type !== wasType) {
203 if (group.length !== 0) {
209 const foldl = (xs, f, acc) => {
210 each$1(xs, (x, i) => {
215 const findUntil = (xs, pred, until) => {
216 for (let i = 0, len = xs.length; i < len; i++) {
219 return Optional.some(x);
220 } else if (until(x, i)) {
224 return Optional.none();
226 const find = (xs, pred) => {
227 return findUntil(xs, pred, never);
229 const flatten = xs => {
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);
235 nativePush.apply(r, xs[i]);
239 const bind = (xs, f) => flatten(map(xs, f));
240 const reverse = xs => {
241 const r = nativeSlice.call(xs, 0);
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) => {
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++) {
253 if (!isDuplicated(x)) {
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();
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);
275 return fromDom$1(div.childNodes[0]);
277 const fromTag = (tag, scope) => {
278 const doc = scope || document;
279 const node = doc.createElement(tag);
280 return fromDom$1(node);
282 const fromText = (text, scope) => {
283 const doc = scope || document;
284 const node = doc.createTextNode(text);
285 return fromDom$1(node);
287 const fromDom$1 = node => {
288 if (node === null || node === undefined) {
289 throw new Error('Node cannot be null or undefined');
291 return { dom: node };
293 const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
294 const SugarElement = {
302 const is$1 = (element, selector) => {
303 const dom = element.dom;
304 if (dom.nodeType !== ELEMENT) {
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);
317 throw new Error('Browser lacks native selectors');
322 const eq = (e1, e2) => e1.dom === e2.dom;
323 const contains = (e1, e2) => {
326 return d1 === d2 ? false : d1.contains(d2);
330 var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
332 return Optional.some(scope);
333 } else if (isFunction(isRoot) && isRoot(scope)) {
334 return Optional.none();
336 return ancestor(scope, a, isRoot);
340 typeof window !== 'undefined' ? window : Function('return this;')();
342 const name = element => {
343 const r = element.dom.nodeName;
344 return r.toLowerCase();
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);
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);
369 return Optional.some(el);
370 } else if (stop(el)) {
374 return Optional.none();
376 const closest = (scope, predicate, isRoot) => {
377 const is = (s, test) => test(s);
378 return ClosestOrAncestor(is, ancestor, scope, predicate, isRoot);
381 const before$1 = (marker, element) => {
382 const parent$1 = parent(marker);
384 v.dom.insertBefore(element.dom, marker.dom);
387 const after = (marker, element) => {
388 const sibling = nextSibling(marker);
390 const parent$1 = parent(marker);
392 append$1(v, element);
395 before$1(v, element);
398 const append$1 = (parent, element) => {
399 parent.dom.appendChild(element.dom);
402 const before = (marker, elements) => {
403 each$1(elements, x => {
407 const append = (parent, elements) => {
408 each$1(elements, x => {
413 const empty = element => {
414 element.dom.textContent = '';
415 each$1(children(element), rogue => {
419 const remove = element => {
420 const dom = element.dom;
421 if (dom.parentNode !== null) {
422 dom.parentNode.removeChild(dom);
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++) {
443 const objAcc = r => (x, i) => {
446 const internalFilter = (obj, pred, onTrue, onFalse) => {
447 each(obj, (x, i) => {
448 (pred(x, i) ? onTrue : onFalse)(x, i);
451 const filter = (obj, pred) => {
453 internalFilter(obj, pred, objAcc(t), noop);
457 const rawSet = (dom, key, value) => {
458 if (isString(value) || isBoolean(value) || isNumber(value)) {
459 dom.setAttribute(key, value + '');
461 console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
462 throw new Error('Attribute value was not simple');
465 const setAll = (element, attrs) => {
466 const dom = element.dom;
467 each(attrs, (v, k) => {
471 const clone$1 = element => foldl(element.dom.attributes, (acc, attr) => {
472 acc[attr.name] = attr.value;
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);
484 const mutate = (original, tag) => {
485 const nu = shallowAs(original, tag);
487 const children$1 = children(original);
488 append(nu, children$1);
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 => {
510 return ((_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === node;
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) => {
519 return dom.isBlock(node.nextSibling) && !isBr(node.previousSibling);
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) {
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',
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);
550 let hasContentNode = false;
551 textBlock = dom.create(blockName, blockAttrs);
552 if (!isBlock(contentNode.firstChild, blockElements)) {
553 fragment.appendChild(textBlock);
555 while (node = contentNode.firstChild) {
556 const nodeName = node.nodeName;
557 if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
558 hasContentNode = true;
560 if (isBlock(node, blockElements)) {
561 fragment.appendChild(node);
565 textBlock = dom.create(blockName, blockAttrs);
566 fragment.appendChild(textBlock);
568 textBlock.appendChild(node);
571 if (!hasContentNode && textBlock) {
572 textBlock.appendChild(dom.create('br', { 'data-mce-bogus': '1' }));
577 const DOM$2 = global$3.DOM;
578 const splitList = (editor, list, li) => {
579 const removeAndKeepBookmarks = targetNode => {
580 const parent = targetNode.parentNode;
582 global$2.each(bookmarks, node => {
583 parent.insertBefore(node, li.parentNode);
586 DOM$2.remove(targetNode);
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)) {
600 if (!editor.dom.isEmpty(fragment)) {
601 DOM$2.insertAfter(fragment, list);
603 DOM$2.insertAfter(newBlock, list);
604 const parent = li.parentElement;
605 if (parent && isEmpty$2(editor.dom, parent)) {
606 removeAndKeepBookmarks(parent);
609 if (isEmpty$2(editor.dom, list)) {
614 const isDescriptionDetail = isTag('dd');
615 const isDescriptionTerm = isTag('dt');
616 const outdentDlItem = (editor, item) => {
617 if (isDescriptionDetail(item)) {
619 } else if (isDescriptionTerm(item)) {
620 parentElement(item).each(dl => splitList(editor, dl.dom, item.dom));
623 const indentDlItem = item => {
624 if (isDescriptionTerm(item)) {
628 const dlIndentation = (editor, indentation, dlItems) => {
629 if (indentation === 'Indent') {
630 each$1(dlItems, indentDlItem);
632 each$1(dlItems, item => outdentDlItem(editor, item));
636 const getNormalizedPoint = (container, offset) => {
637 if (isTextNode$1(container)) {
643 const node = global$6.getNode(container, offset);
644 if (isTextNode$1(node)) {
647 offset: offset >= container.childNodes.length ? node.data.length : 0
649 } else if (node.previousSibling && isTextNode$1(node.previousSibling)) {
651 container: node.previousSibling,
652 offset: node.previousSibling.data.length
654 } else if (node.nextSibling && isTextNode$1(node.nextSibling)) {
656 container: node.nextSibling,
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);
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));
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);
692 return filter$1(selectedBlocks, elm => {
693 return isListNode(elm) && parentList !== elm;
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;
702 return unique(listItemsElms);
704 const getSelectedListItems = editor => {
705 const selectedBlocks = editor.selection.getSelectedBlocks();
706 return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
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();
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());
719 const findLastParentListNode = (editor, elm) => {
720 const parentLists = editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
721 return last(parentLists);
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);
728 const getSelectedListRoots = editor => {
729 const selectedLists = getSelectedLists(editor);
730 return getUniqueListRoots(editor, selectedLists);
732 const getUniqueListRoots = (editor, lists) => {
733 const listRoots = map(lists, list => findLastParentListNode(editor, list).getOr(list));
734 return unique(listRoots);
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);
744 const isWithinNonEditableList = (editor, element) => {
745 const parentList = editor.dom.getParent(element, 'ol,ul,dl');
746 return isWithinNonEditable(editor, parentList);
748 const setNodeChangeHandler = (editor, nodeChangeHandler) => {
749 const initialNode = editor.selection.getNode();
751 parents: editor.dom.getParents(initialNode),
754 editor.on('NodeChange', nodeChangeHandler);
755 return () => editor.off('NodeChange', nodeChangeHandler);
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);
764 return SugarElement.fromDom(fragment);
767 const fireListEvent = (editor, action, element) => editor.dispatch('ListMutation', {
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);
784 if (isSupported(dom)) {
785 dom.style.setProperty(property, value);
788 const set = (element, property, value) => {
789 const dom = element.dom;
790 internalSet(dom, property, value);
793 const joinSegment = (parent, child) => {
794 append$1(parent.item, child.list);
796 const joinSegments = segments => {
797 for (let i = 1; i < segments.length; i++) {
798 joinSegment(segments[i - 1], segments[i]);
801 const appendSegments = (head$1, tail) => {
802 lift2(last(head$1), head(tail), joinSegment);
804 const createSegment = (scope, listType) => {
806 list: SugarElement.fromTag(listType, scope),
807 item: SugarElement.fromTag('li', scope)
809 append$1(segment.list, segment.item);
812 const createSegments = (scope, entry, size) => {
814 for (let i = 0; i < size; i++) {
815 segments.push(createSegment(scope, entry.listType));
819 const populateSegments = (segments, entry) => {
820 for (let i = 0; i < segments.length - 1; i++) {
821 set(segments[i].item, 'list-style-type', 'none');
823 last(segments).each(segment => {
824 setAll(segment.list, entry.listAttributes);
825 setAll(segment.item, entry.itemAttributes);
826 append(segment.item, entry.content);
829 const normalizeSegment = (segment, entry) => {
830 if (name(segment.list) !== entry.listType) {
831 segment.list = mutate(segment.list, entry.listType);
833 setAll(segment.list, entry.listAttributes);
835 const createItem = (scope, attr, content) => {
836 const item = SugarElement.fromTag('li', scope);
838 append(item, content);
841 const appendItem = (segment, item) => {
842 append$1(segment.list, item);
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);
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);
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);
865 return head(cast).map(segment => segment.list);
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);
879 const createEntry = (li, depth, isSelected) => parent(li).filter(isElement$1).map(list => ({
883 content: cloneItemContent(li),
884 itemAttributes: clone$1(li),
885 listAttributes: clone$1(list),
889 const indentEntry = (indentation, entry) => {
890 switch (indentation) {
903 const cloneListProperties = (target, source) => {
904 target.listType = source.listType;
905 target.listAttributes = { ...source.listAttributes };
907 const cleanListProperties = entry => {
908 entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== 'start');
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));
916 const normalizeEntries = entries => {
917 each$1(entries, (entry, i) => {
918 closestSiblingEntry(entries, i).fold(() => {
920 cleanListProperties(entry);
922 }, matchingEntry => cloneListProperties(entry, matchingEntry));
927 const Cell = initial => {
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);
947 const currentItemEntry = createEntry(item, depth, selectionState.get());
948 itemSelection.each(selection => {
949 if (eq(selection.end, item)) {
950 selectionState.set(false);
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);
961 const parseLists = (lists, itemSelection) => {
962 const selectionState = Cell(false);
963 const initialDepth = 0;
964 return map(lists, list => ({
966 entries: parseList(initialDepth, itemSelection, selectionState, list)
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));
977 const indentedComposer = (editor, entries) => {
978 const normalizedEntries = normalizeEntries(entries);
979 return composeList(editor.contentDocument, normalizedEntries).toArray();
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);
985 const indentSelectedEntries = (entries, indentation) => {
986 each$1(filter$1(entries, isSelected), entry => indentEntry(indentation, entry));
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) => ({
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);
1003 before(entrySet.sourceList, composedLists);
1004 remove(entrySet.sourceList);
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();
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);
1044 container.insertBefore(offsetNode, container.childNodes[offset]);
1046 DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
1049 container.appendChild(offsetNode);
1051 container = offsetNode;
1054 bookmark[start ? 'startContainer' : 'endContainer'] = container;
1055 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
1057 setupEndPoint(true);
1058 if (!rng.collapsed) {
1063 const resolveBookmark = bookmark => {
1064 const restoreEndPoint = start => {
1065 const nodeIndex = container => {
1067 let node = (_a = container.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild;
1070 if (node === container) {
1073 if (!isElement(node) || node.getAttribute('data-mce-type') !== 'bookmark') {
1076 node = node.nextSibling;
1080 let container = bookmark[start ? 'startContainer' : 'endContainer'];
1081 let offset = bookmark[start ? 'startOffset' : 'endOffset'];
1085 if (isElement(container) && container.parentNode) {
1086 const node = container;
1087 offset = nodeIndex(container);
1088 container = container.parentNode;
1090 if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
1091 container.appendChild(DOM$1.create('br'));
1094 bookmark[start ? 'startContainer' : 'endContainer'] = container;
1095 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
1097 restoreEndPoint(true);
1099 const rng = DOM$1.createRng();
1100 rng.setStart(bookmark.startContainer, bookmark.startOffset);
1101 if (bookmark.endContainer) {
1102 rng.setEnd(bookmark.endContainer, bookmark.endOffset);
1104 return normalizeRange(rng);
1107 const listToggleActionFromListName = listName => {
1110 return 'ToggleUlList';
1112 return 'ToggleOlList';
1114 return 'ToggleDLList';
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);
1122 const setAttribs = (elm, attrs) => {
1123 global$2.each(attrs, (value, key) => {
1124 elm.setAttribute(key, value);
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']);
1133 const updateListWithDetails = (dom, el, detail) => {
1134 updateListStyle(dom, el, detail);
1135 updateListAttrs(dom, el, detail);
1137 const removeStyles = (dom, element, styles) => {
1138 global$2.each(styles, style => dom.setStyle(element, style, ''));
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;
1147 if (!start && isBr(container.nextSibling)) {
1148 container = container.nextSibling;
1150 const findBetterContainer = (container, forward) => {
1152 const walker = new global$5(container, root);
1153 const dir = forward ? 'next' : 'prev';
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);
1160 return Optional.none();
1162 if (start && isTextNode$1(container)) {
1163 if (isZwsp(container.textContent)) {
1164 container = findBetterContainer(container, false).getOr(container);
1166 if (container.parentNode !== null && isInline(editor, container.parentNode)) {
1167 container = container.parentNode;
1169 while (container.previousSibling !== null && (isInline(editor, container.previousSibling) || isTextNode$1(container.previousSibling))) {
1170 container = container.previousSibling;
1174 if (!start && isTextNode$1(container)) {
1175 if (isZwsp(container.textContent)) {
1176 container = findBetterContainer(container, true).getOr(container);
1178 if (container.parentNode !== null && isInline(editor, container.parentNode)) {
1179 container = container.parentNode;
1181 while (container.nextSibling !== null && (isInline(editor, container.nextSibling) || isTextNode$1(container.nextSibling))) {
1182 container = container.nextSibling;
1186 while (container.parentNode !== root) {
1187 const parent = container.parentNode;
1188 if (isTextBlock(editor, container)) {
1191 if (/^(TD|TH)$/.test(parent.nodeName)) {
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);
1204 const siblings = [];
1205 for (let node = startNode; node; node = node.nextSibling) {
1206 siblings.push(node);
1207 if (node === endNode) {
1211 global$2.each(siblings, node => {
1213 if (isTextBlock(editor, node)) {
1214 textBlocks.push(node);
1218 if (dom.isBlock(node) || isBr(node)) {
1225 const nextSibling = node.nextSibling;
1226 if (global$1.isBookmarkNode(node)) {
1227 if (isListNode(nextSibling) || isTextBlock(editor, nextSibling) || !nextSibling && node.parentNode === root) {
1233 block = dom.create('p');
1234 (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(block, node);
1235 textBlocks.push(block);
1237 block.appendChild(node);
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;
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') {
1255 listName = listName.toUpperCase();
1256 if (listName === 'DL') {
1257 listItemName = 'DT';
1259 const bookmark = createBookmark(rng);
1260 const selectedTextBlocks = filter$1(getSelectedTextBlocks(editor, rng, root), editor.dom.isEditable);
1261 global$2.each(selectedTextBlocks, block => {
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);
1271 listBlock = dom.create(listName);
1272 parent.insertBefore(listBlock, block);
1273 listBlock.appendChild(block);
1274 block = dom.rename(block, listItemName);
1276 removeStyles(dom, block, [
1288 updateListWithDetails(dom, listBlock, detail);
1289 mergeWithAdjacentLists(editor.dom, listBlock);
1292 editor.selection.setRng(resolveBookmark(bookmark));
1294 const isValidLists = (list1, list2) => {
1295 return isListNode(list1) && list1.nodeName === (list2 === null || list2 === void 0 ? void 0 : list2.nodeName);
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;
1302 const hasSameClasses = (elm1, elm2) => {
1303 return elm1.className === elm2.className;
1305 const shouldMerge = (dom, list1, list2) => {
1306 return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
1308 const mergeWithAdjacentLists = (dom, listBlock) => {
1310 let sibling = listBlock.nextSibling;
1311 if (shouldMerge(dom, listBlock, sibling)) {
1312 const liSibling = sibling;
1313 while (node = liSibling.firstChild) {
1314 listBlock.appendChild(node);
1316 dom.remove(liSibling);
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);
1324 dom.remove(liSibling);
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);
1333 updateListWithDetails(editor.dom, list, detail);
1334 fireListEvent(editor, listToggleActionFromListName(listName), list);
1337 const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
1338 const parentIsList = isListNode(parentList);
1339 if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail)) {
1340 flattenListSelection(editor);
1342 applyList(editor, listName, detail);
1343 const bookmark = createBookmark(editor.selection.getRng());
1344 const allLists = parentIsList ? [
1348 global$2.each(allLists, elm => {
1349 updateList$1(editor, elm, listName, detail);
1351 editor.selection.setRng(resolveBookmark(bookmark));
1354 const hasListStyleDetail = detail => {
1355 return 'list-style-type' in detail;
1357 const toggleSingleList = (editor, parentList, listName, detail) => {
1358 if (parentList === editor.getBody()) {
1362 if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
1363 flattenListSelection(editor);
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);
1374 applyList(editor, listName, detail);
1375 fireListEvent(editor, listToggleActionFromListName(listName), parentList);
1378 const toggleList = (editor, listName, _detail) => {
1379 const parentList = getParentList(editor);
1380 if (isWithinNonEditableList(editor, parentList)) {
1383 const selectedSubLists = getSelectedSubLists(editor);
1384 const detail = isObject(_detail) ? _detail : {};
1385 if (selectedSubLists.length > 0) {
1386 toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
1388 toggleSingleList(editor, parentList, listName, detail);
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);
1403 DOM.setStyle(parentNode, 'listStyleType', 'none');
1406 if (isListNode(parentNode)) {
1407 const sibling = parentNode.previousSibling;
1408 if (sibling && sibling.nodeName === 'LI') {
1409 sibling.appendChild(list);
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);
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)) {
1426 const nonEmptyBlocks = editor.schema.getNonEmptyElements();
1427 if (isElement(node)) {
1428 node = global$6.getNode(node, offset);
1430 const walker = new global$5(node, root);
1432 if (isBogusBr(editor.dom, node)) {
1436 const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
1437 while (node = walkFn()) {
1438 if (node.nodeName === 'LI' && !node.hasChildNodes()) {
1441 if (nonEmptyBlocks[node.nodeName]) {
1444 if (isTextNode$1(node) && node.data.length > 0) {
1450 const hasOnlyOneBlockChild = (dom, elm) => {
1451 const childNodes = elm.childNodes;
1452 return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
1454 const unwrapSingleBlockChild = (dom, elm) => {
1455 if (hasOnlyOneBlockChild(dom, elm)) {
1456 dom.remove(elm.firstChild, true);
1459 const moveChildren = (dom, fromElm, toElm) => {
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);
1469 const mergeLiElements = (dom, fromElm, toElm) => {
1471 const ul = fromElm.parentNode;
1472 if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
1475 if (isListNode(toElm.lastChild)) {
1476 listNode = toElm.lastChild;
1478 if (ul === toElm.lastChild) {
1479 if (isBr(ul.previousSibling)) {
1480 dom.remove(ul.previousSibling);
1483 const node = toElm.lastChild;
1484 if (node && isBr(node) && fromElm.hasChildNodes()) {
1487 if (isEmpty$2(dom, toElm, true)) {
1488 empty(SugarElement.fromDom(toElm));
1490 moveChildren(dom, fromElm, toElm);
1492 toElm.appendChild(listNode);
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()) {
1503 const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
1504 empty(SugarElement.fromDom(toLi));
1505 mergeLiElements(editor.dom, fromLi, toLi);
1506 editor.selection.setCursorLocation(toLi, 0);
1508 const mergeForward = (editor, rng, fromLi, toLi) => {
1509 const dom = editor.dom;
1510 if (dom.isEmpty(toLi)) {
1511 mergeIntoEmptyLi(editor, fromLi, toLi);
1513 const bookmark = createBookmark(rng);
1514 mergeLiElements(dom, fromLi, toLi);
1515 editor.selection.setRng(resolveBookmark(bookmark));
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);
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);
1530 const ul = li.parentElement;
1531 if (ul === editor.getBody() && isEmpty$2(dom, ul)) {
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(() => {
1539 mergeForward(editor, rng, otherLi, li);
1541 if (isFirstChild(li)) {
1542 outdentListSelection(editor);
1544 mergeBackward(editor, rng, li, otherLi);
1549 } else if (!otherLi) {
1550 if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
1551 editor.undoManager.transact(() => {
1552 flattenListSelection(editor);
1560 const removeBlock = (dom, block, root) => {
1561 const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
1563 if (parentBlock && dom.isEmpty(parentBlock)) {
1564 dom.remove(parentBlock);
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);
1576 const findValidElement = element => contains$1([
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)) {
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);
1598 const backspaceDeleteCaret = (editor, isForward) => {
1599 return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
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;
1607 const backspaceDeleteRange = editor => {
1608 if (hasListSelection(editor)) {
1609 editor.undoManager.transact(() => {
1610 editor.execCommand('Delete');
1611 normalizeLists(editor.dom, editor.getBody());
1617 const backspaceDelete = (editor, isForward) => {
1618 const selection = editor.selection;
1619 return !isWithinNonEditableList(editor, selection.getNode()) && (selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor));
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());
1628 editor.on('keydown', e => {
1629 if (e.keyCode === global$4.BACKSPACE) {
1630 if (backspaceDelete(editor, false)) {
1633 } else if (e.keyCode === global$4.DELETE) {
1634 if (backspaceDelete(editor, true)) {
1641 const get = editor => ({
1642 backspaceDelete: isForward => {
1643 backspaceDelete(editor, isForward);
1647 const updateList = (editor, update) => {
1648 const parentList = getParentList(editor);
1649 if (parentList === null || isWithinNonEditableList(editor, parentList)) {
1652 editor.undoManager.transact(() => {
1653 if (isObject(update.styles)) {
1654 editor.dom.setStyles(parentList, update.styles);
1656 if (isObject(update.attrs)) {
1657 each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
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;
1668 return foldl(values, (sum, v) => sum + v, 0);
1670 const composeAlphabeticBase26 = value => {
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);
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)) {
1688 } else if (isUppercase(start)) {
1690 } else if (isLowercase(start)) {
1692 } else if (isEmpty$1(start)) {
1698 const parseStartValue = start => {
1699 switch (deduceListType(start)) {
1701 return Optional.some({
1702 listStyleType: Optional.none(),
1706 return Optional.some({
1707 listStyleType: Optional.some('upper-alpha'),
1708 start: parseAlphabeticBase26(start).toString()
1711 return Optional.some({
1712 listStyleType: Optional.some('lower-alpha'),
1713 start: parseAlphabeticBase26(start).toString()
1716 return Optional.some({
1717 listStyleType: Optional.none(),
1721 return Optional.none();
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();
1731 return detail.start;
1735 const open = editor => {
1736 const currentList = getParentList(editor);
1737 if (!isOlNode(currentList) || isWithinNonEditableList(editor, currentList)) {
1740 editor.windowManager.open({
1741 title: 'List Properties',
1747 label: 'Start list at number',
1748 inputMode: 'numeric'
1752 start: parseDetail({
1753 start: editor.dom.getAttrib(currentList, 'start', '1'),
1754 listStyleType: Optional.from(editor.dom.getStyle(currentList, 'list-style-type'))
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('') }
1783 const queryListCommandState = (editor, listName) => () => {
1784 const parentList = getParentList(editor);
1785 return isNonNullable(parentList) && parentList.nodeName === listName;
1787 const registerDialog = editor => {
1788 editor.addCommand('mceListProps', () => {
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);
1801 editor.addCommand('InsertUnorderedList', (ui, detail) => {
1802 toggleList(editor, 'UL', detail);
1804 editor.addCommand('InsertOrderedList', (ui, detail) => {
1805 toggleList(editor, 'OL', detail);
1807 editor.addCommand('InsertDefinitionList', (ui, detail) => {
1808 toggleList(editor, 'DL', detail);
1810 editor.addCommand('RemoveList', () => {
1811 flattenListSelection(editor);
1813 registerDialog(editor);
1814 editor.addCommand('mceListUpdate', (ui, detail) => {
1815 if (isObject(detail)) {
1816 updateList(editor, detail);
1819 editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
1820 editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
1821 editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
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));
1833 list.insert(li, refNode, true);
1838 const reducer = (buffer, node) => {
1839 if (isTextNode(node)) {
1844 } else if (!isEmpty(buffer) && !isTextNode(node)) {
1845 insertListItem(buffer, node);
1851 const restBuffer = foldl(list.children(), reducer, []);
1852 if (!isEmpty(restBuffer)) {
1853 insertListItem(restBuffer);
1856 const setup$1 = editor => {
1857 editor.on('PreInit', () => {
1858 const {parser} = editor;
1859 parser.addNodeFilter('ul,ol', nodes => each$1(nodes, wrapInvalidChildren));
1863 const setupTabKey = editor => {
1864 editor.on('keydown', e => {
1865 if (e.keyCode !== global$4.TAB || global$4.metaKeyPressed(e)) {
1868 editor.undoManager.transact(() => {
1869 if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
1875 const setup = editor => {
1876 if (shouldIndentOnTab(editor)) {
1877 setupTabKey(editor);
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());
1887 api.setEnabled(editor.selection.isEditable());
1888 return setNodeChangeHandler(editor, toggleButtonHandler);
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',
1896 tooltip: 'Numbered list',
1897 onAction: exec('InsertOrderedList'),
1898 onSetup: setupToggleButtonHandler(editor, 'OL')
1900 editor.ui.registry.addToggleButton('bullist', {
1901 icon: 'unordered-list',
1903 tooltip: 'Bullet list',
1904 onAction: exec('InsertUnorderedList'),
1905 onSetup: setupToggleButtonHandler(editor, 'UL')
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);
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')
1921 editor.ui.registry.addMenuItem('listprops', listProperties);
1922 editor.ui.registry.addContextMenu('lists', {
1924 const parentList = getParentList(editor, node);
1925 return isOlNode(parentList) ? ['listprops'] : [];
1930 var Plugin = () => {
1931 global$7.add('lists', editor => {
1934 if (!editor.hasPlugin('rtc', true)) {
1938 registerDialog(editor);