home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / js / tinymce / plugins / lists / plugin.js next >
Encoding:
JavaScript  |  2017-09-26  |  48.0 KB  |  1,793 lines

  1. (function () {
  2.  
  3. var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
  4.  
  5. // Used when there is no 'main' module.
  6. // The name is probably (hopefully) unique so minification removes for releases.
  7. var register_3795 = function (id) {
  8.   var module = dem(id);
  9.   var fragments = id.split('.');
  10.   var target = Function('return this;')();
  11.   for (var i = 0; i < fragments.length - 1; ++i) {
  12.     if (target[fragments[i]] === undefined)
  13.       target[fragments[i]] = {};
  14.     target = target[fragments[i]];
  15.   }
  16.   target[fragments[fragments.length - 1]] = module;
  17. };
  18.  
  19. var instantiate = function (id) {
  20.   var actual = defs[id];
  21.   var dependencies = actual.deps;
  22.   var definition = actual.defn;
  23.   var len = dependencies.length;
  24.   var instances = new Array(len);
  25.   for (var i = 0; i < len; ++i)
  26.     instances[i] = dem(dependencies[i]);
  27.   var defResult = definition.apply(null, instances);
  28.   if (defResult === undefined)
  29.      throw 'module [' + id + '] returned undefined';
  30.   actual.instance = defResult;
  31. };
  32.  
  33. var def = function (id, dependencies, definition) {
  34.   if (typeof id !== 'string')
  35.     throw 'module id must be a string';
  36.   else if (dependencies === undefined)
  37.     throw 'no dependencies for ' + id;
  38.   else if (definition === undefined)
  39.     throw 'no definition function for ' + id;
  40.   defs[id] = {
  41.     deps: dependencies,
  42.     defn: definition,
  43.     instance: undefined
  44.   };
  45. };
  46.  
  47. var dem = function (id) {
  48.   var actual = defs[id];
  49.   if (actual === undefined)
  50.     throw 'module [' + id + '] was undefined';
  51.   else if (actual.instance === undefined)
  52.     instantiate(id);
  53.   return actual.instance;
  54. };
  55.  
  56. var req = function (ids, callback) {
  57.   var len = ids.length;
  58.   var instances = new Array(len);
  59.   for (var i = 0; i < len; ++i)
  60.     instances.push(dem(ids[i]));
  61.   callback.apply(null, callback);
  62. };
  63.  
  64. var ephox = {};
  65.  
  66. ephox.bolt = {
  67.   module: {
  68.     api: {
  69.       define: def,
  70.       require: req,
  71.       demand: dem
  72.     }
  73.   }
  74. };
  75.  
  76. var define = def;
  77. var require = req;
  78. var demand = dem;
  79. // this helps with minificiation when using a lot of global references
  80. var defineGlobal = function (id, ref) {
  81.   define(id, [], function () { return ref; });
  82. };
  83. /*jsc
  84. ["tinymce.plugins.lists.Plugin","tinymce.core.PluginManager","tinymce.core.util.Tools","tinymce.core.util.VK","tinymce.plugins.lists.actions.Indent","tinymce.plugins.lists.actions.Outdent","tinymce.plugins.lists.actions.ToggleList","tinymce.plugins.lists.core.Delete","tinymce.plugins.lists.core.NodeType","tinymce.plugins.lists.core.Selection","global!tinymce.util.Tools.resolve","tinymce.core.dom.DOMUtils","tinymce.plugins.lists.core.Bookmark","tinymce.core.dom.DomQuery","tinymce.plugins.lists.core.NormalizeLists","tinymce.plugins.lists.core.SplitList","tinymce.plugins.lists.core.TextBlock","tinymce.core.dom.BookmarkManager","tinymce.core.dom.RangeUtils","tinymce.core.dom.TreeWalker","tinymce.plugins.lists.core.Range","tinymce.core.Env"]
  85. jsc*/
  86. defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
  87. /**
  88.  * ResolveGlobal.js
  89.  *
  90.  * Released under LGPL License.
  91.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  92.  *
  93.  * License: http://www.tinymce.com/license
  94.  * Contributing: http://www.tinymce.com/contributing
  95.  */
  96.  
  97. define(
  98.   'tinymce.core.PluginManager',
  99.   [
  100.     'global!tinymce.util.Tools.resolve'
  101.   ],
  102.   function (resolve) {
  103.     return resolve('tinymce.PluginManager');
  104.   }
  105. );
  106.  
  107. /**
  108.  * ResolveGlobal.js
  109.  *
  110.  * Released under LGPL License.
  111.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  112.  *
  113.  * License: http://www.tinymce.com/license
  114.  * Contributing: http://www.tinymce.com/contributing
  115.  */
  116.  
  117. define(
  118.   'tinymce.core.util.Tools',
  119.   [
  120.     'global!tinymce.util.Tools.resolve'
  121.   ],
  122.   function (resolve) {
  123.     return resolve('tinymce.util.Tools');
  124.   }
  125. );
  126.  
  127. /**
  128.  * ResolveGlobal.js
  129.  *
  130.  * Released under LGPL License.
  131.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  132.  *
  133.  * License: http://www.tinymce.com/license
  134.  * Contributing: http://www.tinymce.com/contributing
  135.  */
  136.  
  137. define(
  138.   'tinymce.core.util.VK',
  139.   [
  140.     'global!tinymce.util.Tools.resolve'
  141.   ],
  142.   function (resolve) {
  143.     return resolve('tinymce.util.VK');
  144.   }
  145. );
  146.  
  147. /**
  148.  * ResolveGlobal.js
  149.  *
  150.  * Released under LGPL License.
  151.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  152.  *
  153.  * License: http://www.tinymce.com/license
  154.  * Contributing: http://www.tinymce.com/contributing
  155.  */
  156.  
  157. define(
  158.   'tinymce.core.dom.DOMUtils',
  159.   [
  160.     'global!tinymce.util.Tools.resolve'
  161.   ],
  162.   function (resolve) {
  163.     return resolve('tinymce.dom.DOMUtils');
  164.   }
  165. );
  166.  
  167. /**
  168.  * NodeType.js
  169.  *
  170.  * Released under LGPL License.
  171.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  172.  *
  173.  * License: http://www.tinymce.com/license
  174.  * Contributing: http://www.tinymce.com/contributing
  175.  */
  176.  
  177. define(
  178.   'tinymce.plugins.lists.core.NodeType',
  179.   [
  180.   ],
  181.   function () {
  182.     var isTextNode = function (node) {
  183.       return node && node.nodeType === 3;
  184.     };
  185.  
  186.     var isListNode = function (node) {
  187.       return node && (/^(OL|UL|DL)$/).test(node.nodeName);
  188.     };
  189.  
  190.     var isListItemNode = function (node) {
  191.       return node && /^(LI|DT|DD)$/.test(node.nodeName);
  192.     };
  193.  
  194.     var isBr = function (node) {
  195.       return node && node.nodeName === 'BR';
  196.     };
  197.  
  198.     var isFirstChild = function (node) {
  199.       return node.parentNode.firstChild === node;
  200.     };
  201.  
  202.     var isLastChild = function (node) {
  203.       return node.parentNode.lastChild === node;
  204.     };
  205.  
  206.     var isTextBlock = function (editor, node) {
  207.       return node && !!editor.schema.getTextBlockElements()[node.nodeName];
  208.     };
  209.  
  210.     var isBlock = function (node, blockElements) {
  211.       return node && node.nodeName in blockElements;
  212.     };
  213.  
  214.     var isBogusBr = function (dom, node) {
  215.       if (!isBr(node)) {
  216.         return false;
  217.       }
  218.  
  219.       if (dom.isBlock(node.nextSibling) && !isBr(node.previousSibling)) {
  220.         return true;
  221.       }
  222.  
  223.       return false;
  224.     };
  225.  
  226.     var isEmpty = function (dom, elm, keepBookmarks) {
  227.       var empty = dom.isEmpty(elm);
  228.  
  229.       if (keepBookmarks && dom.select('span[data-mce-type=bookmark]', elm).length > 0) {
  230.         return false;
  231.       }
  232.  
  233.       return empty;
  234.     };
  235.  
  236.     var isChildOfBody = function (dom, elm) {
  237.       return dom.isChildOf(elm, dom.getRoot());
  238.     };
  239.  
  240.     return {
  241.       isTextNode: isTextNode,
  242.       isListNode: isListNode,
  243.       isListItemNode: isListItemNode,
  244.       isBr: isBr,
  245.       isFirstChild: isFirstChild,
  246.       isLastChild: isLastChild,
  247.       isTextBlock: isTextBlock,
  248.       isBlock: isBlock,
  249.       isBogusBr: isBogusBr,
  250.       isEmpty: isEmpty,
  251.       isChildOfBody: isChildOfBody
  252.     };
  253.   }
  254. );
  255.  
  256.  
  257. /**
  258.  * ResolveGlobal.js
  259.  *
  260.  * Released under LGPL License.
  261.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  262.  *
  263.  * License: http://www.tinymce.com/license
  264.  * Contributing: http://www.tinymce.com/contributing
  265.  */
  266.  
  267. define(
  268.   'tinymce.core.dom.RangeUtils',
  269.   [
  270.     'global!tinymce.util.Tools.resolve'
  271.   ],
  272.   function (resolve) {
  273.     return resolve('tinymce.dom.RangeUtils');
  274.   }
  275. );
  276.  
  277. /**
  278.  * Range.js
  279.  *
  280.  * Released under LGPL License.
  281.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  282.  *
  283.  * License: http://www.tinymce.com/license
  284.  * Contributing: http://www.tinymce.com/contributing
  285.  */
  286.  
  287. define(
  288.   'tinymce.plugins.lists.core.Range',
  289.   [
  290.     'tinymce.core.dom.RangeUtils',
  291.     'tinymce.plugins.lists.core.NodeType'
  292.   ],
  293.   function (RangeUtils, NodeType) {
  294.     var getNormalizedEndPoint = function (container, offset) {
  295.       var node = RangeUtils.getNode(container, offset);
  296.  
  297.       if (NodeType.isListItemNode(container) && NodeType.isTextNode(node)) {
  298.         var textNodeOffset = offset >= container.childNodes.length ? node.data.length : 0;
  299.         return { container: node, offset: textNodeOffset };
  300.       }
  301.  
  302.       return { container: container, offset: offset };
  303.     };
  304.  
  305.     var normalizeRange = function (rng) {
  306.       var outRng = rng.cloneRange();
  307.  
  308.       var rangeStart = getNormalizedEndPoint(rng.startContainer, rng.startOffset);
  309.       outRng.setStart(rangeStart.container, rangeStart.offset);
  310.  
  311.       var rangeEnd = getNormalizedEndPoint(rng.endContainer, rng.endOffset);
  312.       outRng.setEnd(rangeEnd.container, rangeEnd.offset);
  313.  
  314.       return outRng;
  315.     };
  316.  
  317.     return {
  318.       getNormalizedEndPoint: getNormalizedEndPoint,
  319.       normalizeRange: normalizeRange
  320.     };
  321.   }
  322. );
  323.  
  324.  
  325. /**
  326.  * Bookmark.js
  327.  *
  328.  * Released under LGPL License.
  329.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  330.  *
  331.  * License: http://www.tinymce.com/license
  332.  * Contributing: http://www.tinymce.com/contributing
  333.  */
  334.  
  335. define(
  336.   'tinymce.plugins.lists.core.Bookmark',
  337.   [
  338.     'tinymce.core.dom.DOMUtils',
  339.     'tinymce.plugins.lists.core.NodeType',
  340.     'tinymce.plugins.lists.core.Range'
  341.   ],
  342.   function (DOMUtils, NodeType, Range) {
  343.     var DOM = DOMUtils.DOM;
  344.  
  345.     /**
  346.      * Returns a range bookmark. This will convert indexed bookmarks into temporary span elements with
  347.      * index 0 so that they can be restored properly after the DOM has been modified. Text bookmarks will not have spans
  348.      * added to them since they can be restored after a dom operation.
  349.      *
  350.      * So this: <p><b>|</b><b>|</b></p>
  351.      * becomes: <p><b><span data-mce-type="bookmark">|</span></b><b data-mce-type="bookmark">|</span></b></p>
  352.      *
  353.      * @param  {DOMRange} rng DOM Range to get bookmark on.
  354.      * @return {Object} Bookmark object.
  355.      */
  356.     var createBookmark = function (rng) {
  357.       var bookmark = {};
  358.  
  359.       var setupEndPoint = function (start) {
  360.         var offsetNode, container, offset;
  361.  
  362.         container = rng[start ? 'startContainer' : 'endContainer'];
  363.         offset = rng[start ? 'startOffset' : 'endOffset'];
  364.  
  365.         if (container.nodeType === 1) {
  366.           offsetNode = DOM.create('span', { 'data-mce-type': 'bookmark' });
  367.  
  368.           if (container.hasChildNodes()) {
  369.             offset = Math.min(offset, container.childNodes.length - 1);
  370.  
  371.             if (start) {
  372.               container.insertBefore(offsetNode, container.childNodes[offset]);
  373.             } else {
  374.               DOM.insertAfter(offsetNode, container.childNodes[offset]);
  375.             }
  376.           } else {
  377.             container.appendChild(offsetNode);
  378.           }
  379.  
  380.           container = offsetNode;
  381.           offset = 0;
  382.         }
  383.  
  384.         bookmark[start ? 'startContainer' : 'endContainer'] = container;
  385.         bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  386.       };
  387.  
  388.       setupEndPoint(true);
  389.  
  390.       if (!rng.collapsed) {
  391.         setupEndPoint();
  392.       }
  393.  
  394.       return bookmark;
  395.     };
  396.  
  397.     var resolveBookmark = function (bookmark) {
  398.       function restoreEndPoint(start) {
  399.         var container, offset, node;
  400.  
  401.         var nodeIndex = function (container) {
  402.           var node = container.parentNode.firstChild, idx = 0;
  403.  
  404.           while (node) {
  405.             if (node === container) {
  406.               return idx;
  407.             }
  408.  
  409.             // Skip data-mce-type=bookmark nodes
  410.             if (node.nodeType !== 1 || node.getAttribute('data-mce-type') !== 'bookmark') {
  411.               idx++;
  412.             }
  413.  
  414.             node = node.nextSibling;
  415.           }
  416.  
  417.           return -1;
  418.         };
  419.  
  420.         container = node = bookmark[start ? 'startContainer' : 'endContainer'];
  421.         offset = bookmark[start ? 'startOffset' : 'endOffset'];
  422.  
  423.         if (!container) {
  424.           return;
  425.         }
  426.  
  427.         if (container.nodeType === 1) {
  428.           offset = nodeIndex(container);
  429.           container = container.parentNode;
  430.           DOM.remove(node);
  431.         }
  432.  
  433.         bookmark[start ? 'startContainer' : 'endContainer'] = container;
  434.         bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  435.       }
  436.  
  437.       restoreEndPoint(true);
  438.       restoreEndPoint();
  439.  
  440.       var rng = DOM.createRng();
  441.  
  442.       rng.setStart(bookmark.startContainer, bookmark.startOffset);
  443.  
  444.       if (bookmark.endContainer) {
  445.         rng.setEnd(bookmark.endContainer, bookmark.endOffset);
  446.       }
  447.  
  448.       return Range.normalizeRange(rng);
  449.     };
  450.  
  451.     return {
  452.       createBookmark: createBookmark,
  453.       resolveBookmark: resolveBookmark
  454.     };
  455.   }
  456. );
  457.  
  458.  
  459. /**
  460.  * ResolveGlobal.js
  461.  *
  462.  * Released under LGPL License.
  463.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  464.  *
  465.  * License: http://www.tinymce.com/license
  466.  * Contributing: http://www.tinymce.com/contributing
  467.  */
  468.  
  469. define(
  470.   'tinymce.core.dom.DomQuery',
  471.   [
  472.     'global!tinymce.util.Tools.resolve'
  473.   ],
  474.   function (resolve) {
  475.     return resolve('tinymce.dom.DomQuery');
  476.   }
  477. );
  478.  
  479. /**
  480.  * Selection.js
  481.  *
  482.  * Released under LGPL License.
  483.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  484.  *
  485.  * License: http://www.tinymce.com/license
  486.  * Contributing: http://www.tinymce.com/contributing
  487.  */
  488.  
  489. define(
  490.   'tinymce.plugins.lists.core.Selection',
  491.   [
  492.     'tinymce.core.dom.DomQuery',
  493.     'tinymce.core.util.Tools',
  494.     'tinymce.plugins.lists.core.NodeType'
  495.   ],
  496.   function (DomQuery, Tools, NodeType) {
  497.     var getParentList = function (editor) {
  498.       return editor.dom.getParent(editor.selection.getStart(true), 'OL,UL,DL');
  499.     };
  500.  
  501.     var getSelectedSubLists = function (editor) {
  502.       var parentList = getParentList(editor);
  503.       return Tools.grep(editor.selection.getSelectedBlocks(), function (elm) {
  504.         return NodeType.isListNode(elm) && parentList !== elm;
  505.       });
  506.     };
  507.  
  508.     var findParentListItemsNodes = function (editor, elms) {
  509.       var listItemsElms = Tools.map(elms, function (elm) {
  510.         var parentLi = editor.dom.getParent(elm, 'li,dd,dt', editor.getBody());
  511.  
  512.         return parentLi ? parentLi : elm;
  513.       });
  514.  
  515.       return DomQuery.unique(listItemsElms);
  516.     };
  517.  
  518.     var getSelectedListItems = function (editor) {
  519.       var selectedBlocks = editor.selection.getSelectedBlocks();
  520.       return Tools.grep(findParentListItemsNodes(editor, selectedBlocks), function (block) {
  521.         return NodeType.isListItemNode(block);
  522.       });
  523.     };
  524.  
  525.     return {
  526.       getParentList: getParentList,
  527.       getSelectedSubLists: getSelectedSubLists,
  528.       getSelectedListItems: getSelectedListItems
  529.     };
  530.   }
  531. );
  532.  
  533.  
  534. /**
  535.  * Indent.js
  536.  *
  537.  * Released under LGPL License.
  538.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  539.  *
  540.  * License: http://www.tinymce.com/license
  541.  * Contributing: http://www.tinymce.com/contributing
  542.  */
  543.  
  544. define(
  545.   'tinymce.plugins.lists.actions.Indent',
  546.   [
  547.     'tinymce.core.dom.DOMUtils',
  548.     'tinymce.plugins.lists.core.Bookmark',
  549.     'tinymce.plugins.lists.core.NodeType',
  550.     'tinymce.plugins.lists.core.Selection'
  551.   ],
  552.   function (DOMUtils, Bookmark, NodeType, Selection) {
  553.     var DOM = DOMUtils.DOM;
  554.  
  555.     var mergeLists = function (from, to) {
  556.       var node;
  557.  
  558.       if (NodeType.isListNode(from)) {
  559.         while ((node = from.firstChild)) {
  560.           to.appendChild(node);
  561.         }
  562.  
  563.         DOM.remove(from);
  564.       }
  565.     };
  566.  
  567.     var indent = function (li) {
  568.       var sibling, newList, listStyle;
  569.  
  570.       if (li.nodeName === 'DT') {
  571.         DOM.rename(li, 'DD');
  572.         return true;
  573.       }
  574.  
  575.       sibling = li.previousSibling;
  576.  
  577.       if (sibling && NodeType.isListNode(sibling)) {
  578.         sibling.appendChild(li);
  579.         return true;
  580.       }
  581.  
  582.       if (sibling && sibling.nodeName === 'LI' && NodeType.isListNode(sibling.lastChild)) {
  583.         sibling.lastChild.appendChild(li);
  584.         mergeLists(li.lastChild, sibling.lastChild);
  585.         return true;
  586.       }
  587.  
  588.       sibling = li.nextSibling;
  589.  
  590.       if (sibling && NodeType.isListNode(sibling)) {
  591.         sibling.insertBefore(li, sibling.firstChild);
  592.         return true;
  593.       }
  594.  
  595.       /*if (sibling && sibling.nodeName === 'LI' && isListNode(li.lastChild)) {
  596.         return false;
  597.       }*/
  598.  
  599.       sibling = li.previousSibling;
  600.       if (sibling && sibling.nodeName === 'LI') {
  601.         newList = DOM.create(li.parentNode.nodeName);
  602.         listStyle = DOM.getStyle(li.parentNode, 'listStyleType');
  603.         if (listStyle) {
  604.           DOM.setStyle(newList, 'listStyleType', listStyle);
  605.         }
  606.         sibling.appendChild(newList);
  607.         newList.appendChild(li);
  608.         mergeLists(li.lastChild, newList);
  609.         return true;
  610.       }
  611.  
  612.       return false;
  613.     };
  614.  
  615.     var indentSelection = function (editor) {
  616.       var listElements = Selection.getSelectedListItems(editor);
  617.  
  618.       if (listElements.length) {
  619.         var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
  620.  
  621.         for (var i = 0; i < listElements.length; i++) {
  622.           if (!indent(listElements[i]) && i === 0) {
  623.             break;
  624.           }
  625.         }
  626.  
  627.         editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  628.         editor.nodeChanged();
  629.  
  630.         return true;
  631.       }
  632.     };
  633.  
  634.     return {
  635.       indentSelection: indentSelection
  636.     };
  637.   }
  638. );
  639.  
  640.  
  641. /**
  642.  * NormalizeLists.js
  643.  *
  644.  * Released under LGPL License.
  645.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  646.  *
  647.  * License: http://www.tinymce.com/license
  648.  * Contributing: http://www.tinymce.com/contributing
  649.  */
  650.  
  651. define(
  652.   'tinymce.plugins.lists.core.NormalizeLists',
  653.   [
  654.     'tinymce.core.dom.DOMUtils',
  655.     'tinymce.core.util.Tools',
  656.     'tinymce.plugins.lists.core.NodeType'
  657.   ],
  658.   function (DOMUtils, Tools, NodeType) {
  659.     var DOM = DOMUtils.DOM;
  660.  
  661.     var normalizeList = function (dom, ul) {
  662.       var sibling, parentNode = ul.parentNode;
  663.  
  664.       // Move UL/OL to previous LI if it's the only child of a LI
  665.       if (parentNode.nodeName === 'LI' && parentNode.firstChild === ul) {
  666.         sibling = parentNode.previousSibling;
  667.         if (sibling && sibling.nodeName === 'LI') {
  668.           sibling.appendChild(ul);
  669.  
  670.           if (NodeType.isEmpty(dom, parentNode)) {
  671.             DOM.remove(parentNode);
  672.           }
  673.         } else {
  674.           DOM.setStyle(parentNode, 'listStyleType', 'none');
  675.         }
  676.       }
  677.  
  678.       // Append OL/UL to previous LI if it's in a parent OL/UL i.e. old HTML4
  679.       if (NodeType.isListNode(parentNode)) {
  680.         sibling = parentNode.previousSibling;
  681.         if (sibling && sibling.nodeName === 'LI') {
  682.           sibling.appendChild(ul);
  683.         }
  684.       }
  685.     };
  686.  
  687.     var normalizeLists = function (dom, element) {
  688.       Tools.each(Tools.grep(dom.select('ol,ul', element)), function (ul) {
  689.         normalizeList(dom, ul);
  690.       });
  691.     };
  692.  
  693.     return {
  694.       normalizeList: normalizeList,
  695.       normalizeLists: normalizeLists
  696.     };
  697.   }
  698. );
  699.  
  700.  
  701. /**
  702.  * ResolveGlobal.js
  703.  *
  704.  * Released under LGPL License.
  705.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  706.  *
  707.  * License: http://www.tinymce.com/license
  708.  * Contributing: http://www.tinymce.com/contributing
  709.  */
  710.  
  711. define(
  712.   'tinymce.core.Env',
  713.   [
  714.     'global!tinymce.util.Tools.resolve'
  715.   ],
  716.   function (resolve) {
  717.     return resolve('tinymce.Env');
  718.   }
  719. );
  720.  
  721. /**
  722.  * TextBlock.js
  723.  *
  724.  * Released under LGPL License.
  725.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  726.  *
  727.  * License: http://www.tinymce.com/license
  728.  * Contributing: http://www.tinymce.com/contributing
  729.  */
  730.  
  731. define(
  732.   'tinymce.plugins.lists.core.TextBlock',
  733.   [
  734.     'tinymce.core.dom.DOMUtils',
  735.     'tinymce.core.Env',
  736.     'tinymce.plugins.lists.core.NodeType'
  737.   ],
  738.   function (DOMUtils, Env, NodeType) {
  739.     var DOM = DOMUtils.DOM;
  740.  
  741.     var createNewTextBlock = function (editor, contentNode, blockName) {
  742.       var node, textBlock, fragment = DOM.createFragment(), hasContentNode;
  743.       var blockElements = editor.schema.getBlockElements();
  744.  
  745.       if (editor.settings.forced_root_block) {
  746.         blockName = blockName || editor.settings.forced_root_block;
  747.       }
  748.  
  749.       if (blockName) {
  750.         textBlock = DOM.create(blockName);
  751.  
  752.         if (textBlock.tagName === editor.settings.forced_root_block) {
  753.           DOM.setAttribs(textBlock, editor.settings.forced_root_block_attrs);
  754.         }
  755.  
  756.         if (!NodeType.isBlock(contentNode.firstChild, blockElements)) {
  757.           fragment.appendChild(textBlock);
  758.         }
  759.       }
  760.  
  761.       if (contentNode) {
  762.         while ((node = contentNode.firstChild)) {
  763.           var nodeName = node.nodeName;
  764.  
  765.           if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
  766.             hasContentNode = true;
  767.           }
  768.  
  769.           if (NodeType.isBlock(node, blockElements)) {
  770.             fragment.appendChild(node);
  771.             textBlock = null;
  772.           } else {
  773.             if (blockName) {
  774.               if (!textBlock) {
  775.                 textBlock = DOM.create(blockName);
  776.                 fragment.appendChild(textBlock);
  777.               }
  778.  
  779.               textBlock.appendChild(node);
  780.             } else {
  781.               fragment.appendChild(node);
  782.             }
  783.           }
  784.         }
  785.       }
  786.  
  787.       if (!editor.settings.forced_root_block) {
  788.         fragment.appendChild(DOM.create('br'));
  789.       } else {
  790.         // BR is needed in empty blocks on non IE browsers
  791.         if (!hasContentNode && (!Env.ie || Env.ie > 10)) {
  792.           textBlock.appendChild(DOM.create('br', { 'data-mce-bogus': '1' }));
  793.         }
  794.       }
  795.  
  796.       return fragment;
  797.     };
  798.  
  799.     return {
  800.       createNewTextBlock: createNewTextBlock
  801.     };
  802.   }
  803. );
  804.  
  805. /**
  806.  * SplitList.js
  807.  *
  808.  * Released under LGPL License.
  809.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  810.  *
  811.  * License: http://www.tinymce.com/license
  812.  * Contributing: http://www.tinymce.com/contributing
  813.  */
  814.  
  815. define(
  816.   'tinymce.plugins.lists.core.SplitList',
  817.   [
  818.     'tinymce.core.dom.DOMUtils',
  819.     'tinymce.plugins.lists.core.NodeType',
  820.     'tinymce.plugins.lists.core.TextBlock',
  821.     'tinymce.core.util.Tools'
  822.   ],
  823.   function (DOMUtils, NodeType, TextBlock, Tools) {
  824.     var DOM = DOMUtils.DOM;
  825.  
  826.     var splitList = function (editor, ul, li, newBlock) {
  827.       var tmpRng, fragment, bookmarks, node;
  828.  
  829.       var removeAndKeepBookmarks = function (targetNode) {
  830.         Tools.each(bookmarks, function (node) {
  831.           targetNode.parentNode.insertBefore(node, li.parentNode);
  832.         });
  833.  
  834.         DOM.remove(targetNode);
  835.       };
  836.  
  837.       bookmarks = DOM.select('span[data-mce-type="bookmark"]', ul);
  838.       newBlock = newBlock || TextBlock.createNewTextBlock(editor, li);
  839.       tmpRng = DOM.createRng();
  840.       tmpRng.setStartAfter(li);
  841.       tmpRng.setEndAfter(ul);
  842.       fragment = tmpRng.extractContents();
  843.  
  844.       for (node = fragment.firstChild; node; node = node.firstChild) {
  845.         if (node.nodeName === 'LI' && editor.dom.isEmpty(node)) {
  846.           DOM.remove(node);
  847.           break;
  848.         }
  849.       }
  850.  
  851.       if (!editor.dom.isEmpty(fragment)) {
  852.         DOM.insertAfter(fragment, ul);
  853.       }
  854.  
  855.       DOM.insertAfter(newBlock, ul);
  856.  
  857.       if (NodeType.isEmpty(editor.dom, li.parentNode)) {
  858.         removeAndKeepBookmarks(li.parentNode);
  859.       }
  860.  
  861.       DOM.remove(li);
  862.  
  863.       if (NodeType.isEmpty(editor.dom, ul)) {
  864.         DOM.remove(ul);
  865.       }
  866.     };
  867.  
  868.     return {
  869.       splitList: splitList
  870.     };
  871.   }
  872. );
  873.  
  874.  
  875. /**
  876.  * Outdent.js
  877.  *
  878.  * Released under LGPL License.
  879.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  880.  *
  881.  * License: http://www.tinymce.com/license
  882.  * Contributing: http://www.tinymce.com/contributing
  883.  */
  884.  
  885. define(
  886.   'tinymce.plugins.lists.actions.Outdent',
  887.   [
  888.     'tinymce.core.dom.DOMUtils',
  889.     'tinymce.plugins.lists.core.Bookmark',
  890.     'tinymce.plugins.lists.core.NodeType',
  891.     'tinymce.plugins.lists.core.NormalizeLists',
  892.     'tinymce.plugins.lists.core.Selection',
  893.     'tinymce.plugins.lists.core.SplitList',
  894.     'tinymce.plugins.lists.core.TextBlock'
  895.   ],
  896.   function (DOMUtils, Bookmark, NodeType, NormalizeLists, Selection, SplitList, TextBlock) {
  897.     var DOM = DOMUtils.DOM;
  898.  
  899.     var removeEmptyLi = function (dom, li) {
  900.       if (NodeType.isEmpty(dom, li)) {
  901.         DOM.remove(li);
  902.       }
  903.     };
  904.  
  905.     var outdent = function (editor, li) {
  906.       var ul = li.parentNode, ulParent = ul.parentNode, newBlock;
  907.  
  908.       if (ul === editor.getBody()) {
  909.         return true;
  910.       }
  911.  
  912.       if (li.nodeName === 'DD') {
  913.         DOM.rename(li, 'DT');
  914.         return true;
  915.       }
  916.  
  917.       if (NodeType.isFirstChild(li) && NodeType.isLastChild(li)) {
  918.         if (ulParent.nodeName === "LI") {
  919.           DOM.insertAfter(li, ulParent);
  920.           removeEmptyLi(editor.dom, ulParent);
  921.           DOM.remove(ul);
  922.         } else if (NodeType.isListNode(ulParent)) {
  923.           DOM.remove(ul, true);
  924.         } else {
  925.           ulParent.insertBefore(TextBlock.createNewTextBlock(editor, li), ul);
  926.           DOM.remove(ul);
  927.         }
  928.  
  929.         return true;
  930.       } else if (NodeType.isFirstChild(li)) {
  931.         if (ulParent.nodeName === "LI") {
  932.           DOM.insertAfter(li, ulParent);
  933.           li.appendChild(ul);
  934.           removeEmptyLi(editor.dom, ulParent);
  935.         } else if (NodeType.isListNode(ulParent)) {
  936.           ulParent.insertBefore(li, ul);
  937.         } else {
  938.           ulParent.insertBefore(TextBlock.createNewTextBlock(editor, li), ul);
  939.           DOM.remove(li);
  940.         }
  941.  
  942.         return true;
  943.       } else if (NodeType.isLastChild(li)) {
  944.         if (ulParent.nodeName === "LI") {
  945.           DOM.insertAfter(li, ulParent);
  946.         } else if (NodeType.isListNode(ulParent)) {
  947.           DOM.insertAfter(li, ul);
  948.         } else {
  949.           DOM.insertAfter(TextBlock.createNewTextBlock(editor, li), ul);
  950.           DOM.remove(li);
  951.         }
  952.  
  953.         return true;
  954.       }
  955.  
  956.       if (ulParent.nodeName === 'LI') {
  957.         ul = ulParent;
  958.         newBlock = TextBlock.createNewTextBlock(editor, li, 'LI');
  959.       } else if (NodeType.isListNode(ulParent)) {
  960.         newBlock = TextBlock.createNewTextBlock(editor, li, 'LI');
  961.       } else {
  962.         newBlock = TextBlock.createNewTextBlock(editor, li);
  963.       }
  964.  
  965.       SplitList.splitList(editor, ul, li, newBlock);
  966.       NormalizeLists.normalizeLists(editor.dom, ul.parentNode);
  967.  
  968.       return true;
  969.     };
  970.  
  971.     var outdentSelection = function (editor) {
  972.       var listElements = Selection.getSelectedListItems(editor);
  973.  
  974.       if (listElements.length) {
  975.         var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
  976.         var i, y, root = editor.getBody();
  977.  
  978.         i = listElements.length;
  979.         while (i--) {
  980.           var node = listElements[i].parentNode;
  981.  
  982.           while (node && node !== root) {
  983.             y = listElements.length;
  984.             while (y--) {
  985.               if (listElements[y] === node) {
  986.                 listElements.splice(i, 1);
  987.                 break;
  988.               }
  989.             }
  990.  
  991.             node = node.parentNode;
  992.           }
  993.         }
  994.  
  995.         for (i = 0; i < listElements.length; i++) {
  996.           if (!outdent(editor, listElements[i]) && i === 0) {
  997.             break;
  998.           }
  999.         }
  1000.  
  1001.         editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1002.         editor.nodeChanged();
  1003.  
  1004.         return true;
  1005.       }
  1006.     };
  1007.  
  1008.     return {
  1009.       outdent: outdent,
  1010.       outdentSelection: outdentSelection
  1011.     };
  1012.   }
  1013. );
  1014.  
  1015.  
  1016. /**
  1017.  * ResolveGlobal.js
  1018.  *
  1019.  * Released under LGPL License.
  1020.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1021.  *
  1022.  * License: http://www.tinymce.com/license
  1023.  * Contributing: http://www.tinymce.com/contributing
  1024.  */
  1025.  
  1026. define(
  1027.   'tinymce.core.dom.BookmarkManager',
  1028.   [
  1029.     'global!tinymce.util.Tools.resolve'
  1030.   ],
  1031.   function (resolve) {
  1032.     return resolve('tinymce.dom.BookmarkManager');
  1033.   }
  1034. );
  1035.  
  1036. /**
  1037.  * ToggleList.js
  1038.  *
  1039.  * Released under LGPL License.
  1040.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1041.  *
  1042.  * License: http://www.tinymce.com/license
  1043.  * Contributing: http://www.tinymce.com/contributing
  1044.  */
  1045.  
  1046. define(
  1047.   'tinymce.plugins.lists.actions.ToggleList',
  1048.   [
  1049.     'tinymce.core.dom.BookmarkManager',
  1050.     'tinymce.core.util.Tools',
  1051.     'tinymce.plugins.lists.actions.Outdent',
  1052.     'tinymce.plugins.lists.core.Bookmark',
  1053.     'tinymce.plugins.lists.core.NodeType',
  1054.     'tinymce.plugins.lists.core.NormalizeLists',
  1055.     'tinymce.plugins.lists.core.Selection',
  1056.     'tinymce.plugins.lists.core.SplitList'
  1057.   ],
  1058.   function (BookmarkManager, Tools, Outdent, Bookmark, NodeType, NormalizeLists, Selection, SplitList) {
  1059.     var updateListStyle = function (dom, el, detail) {
  1060.       var type = detail['list-style-type'] ? detail['list-style-type'] : null;
  1061.       dom.setStyle(el, 'list-style-type', type);
  1062.     };
  1063.  
  1064.     var setAttribs = function (elm, attrs) {
  1065.       Tools.each(attrs, function (value, key) {
  1066.         elm.setAttribute(key, value);
  1067.       });
  1068.     };
  1069.  
  1070.     var updateListAttrs = function (dom, el, detail) {
  1071.       setAttribs(el, detail['list-attributes']);
  1072.       Tools.each(dom.select('li', el), function (li) {
  1073.         setAttribs(li, detail['list-item-attributes']);
  1074.       });
  1075.     };
  1076.  
  1077.     var updateListWithDetails = function (dom, el, detail) {
  1078.       updateListStyle(dom, el, detail);
  1079.       updateListAttrs(dom, el, detail);
  1080.     };
  1081.  
  1082.     var getEndPointNode = function (editor, rng, start) {
  1083.       var container, offset, root = editor.getBody();
  1084.  
  1085.       container = rng[start ? 'startContainer' : 'endContainer'];
  1086.       offset = rng[start ? 'startOffset' : 'endOffset'];
  1087.  
  1088.       // Resolve node index
  1089.       if (container.nodeType === 1) {
  1090.         container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
  1091.       }
  1092.  
  1093.       while (container.parentNode !== root) {
  1094.         if (NodeType.isTextBlock(editor, container)) {
  1095.           return container;
  1096.         }
  1097.  
  1098.         if (/^(TD|TH)$/.test(container.parentNode.nodeName)) {
  1099.           return container;
  1100.         }
  1101.  
  1102.         container = container.parentNode;
  1103.       }
  1104.  
  1105.       return container;
  1106.     };
  1107.  
  1108.     var getSelectedTextBlocks = function (editor, rng) {
  1109.       var textBlocks = [], root = editor.getBody(), dom = editor.dom;
  1110.  
  1111.       var startNode = getEndPointNode(editor, rng, true);
  1112.       var endNode = getEndPointNode(editor, rng, false);
  1113.       var block, siblings = [];
  1114.  
  1115.       for (var node = startNode; node; node = node.nextSibling) {
  1116.         siblings.push(node);
  1117.  
  1118.         if (node === endNode) {
  1119.           break;
  1120.         }
  1121.       }
  1122.  
  1123.       Tools.each(siblings, function (node) {
  1124.         if (NodeType.isTextBlock(editor, node)) {
  1125.           textBlocks.push(node);
  1126.           block = null;
  1127.           return;
  1128.         }
  1129.  
  1130.         if (dom.isBlock(node) || NodeType.isBr(node)) {
  1131.           if (NodeType.isBr(node)) {
  1132.             dom.remove(node);
  1133.           }
  1134.  
  1135.           block = null;
  1136.           return;
  1137.         }
  1138.  
  1139.         var nextSibling = node.nextSibling;
  1140.         if (BookmarkManager.isBookmarkNode(node)) {
  1141.           if (NodeType.isTextBlock(editor, nextSibling) || (!nextSibling && node.parentNode === root)) {
  1142.             block = null;
  1143.             return;
  1144.           }
  1145.         }
  1146.  
  1147.         if (!block) {
  1148.           block = dom.create('p');
  1149.           node.parentNode.insertBefore(block, node);
  1150.           textBlocks.push(block);
  1151.         }
  1152.  
  1153.         block.appendChild(node);
  1154.       });
  1155.  
  1156.       return textBlocks;
  1157.     };
  1158.  
  1159.     var applyList = function (editor, listName, detail) {
  1160.       var rng = editor.selection.getRng(true), bookmark, listItemName = 'LI';
  1161.       var dom = editor.dom;
  1162.  
  1163.       detail = detail ? detail : {};
  1164.  
  1165.       if (dom.getContentEditable(editor.selection.getNode()) === "false") {
  1166.         return;
  1167.       }
  1168.  
  1169.       listName = listName.toUpperCase();
  1170.  
  1171.       if (listName === 'DL') {
  1172.         listItemName = 'DT';
  1173.       }
  1174.  
  1175.       bookmark = Bookmark.createBookmark(rng);
  1176.  
  1177.       Tools.each(getSelectedTextBlocks(editor, rng), function (block) {
  1178.         var listBlock, sibling;
  1179.  
  1180.         var hasCompatibleStyle = function (sib) {
  1181.           var sibStyle = dom.getStyle(sib, 'list-style-type');
  1182.           var detailStyle = detail ? detail['list-style-type'] : '';
  1183.  
  1184.           detailStyle = detailStyle === null ? '' : detailStyle;
  1185.  
  1186.           return sibStyle === detailStyle;
  1187.         };
  1188.  
  1189.         sibling = block.previousSibling;
  1190.         if (sibling && NodeType.isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(sibling)) {
  1191.           listBlock = sibling;
  1192.           block = dom.rename(block, listItemName);
  1193.           sibling.appendChild(block);
  1194.         } else {
  1195.           listBlock = dom.create(listName);
  1196.           block.parentNode.insertBefore(listBlock, block);
  1197.           listBlock.appendChild(block);
  1198.           block = dom.rename(block, listItemName);
  1199.         }
  1200.  
  1201.         updateListWithDetails(dom, listBlock, detail);
  1202.         mergeWithAdjacentLists(editor.dom, listBlock);
  1203.       });
  1204.  
  1205.       editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1206.     };
  1207.  
  1208.     var removeList = function (editor) {
  1209.       var bookmark = Bookmark.createBookmark(editor.selection.getRng(true)), root = editor.getBody();
  1210.       var listItems = Selection.getSelectedListItems(editor);
  1211.       var emptyListItems = Tools.grep(listItems, function (li) {
  1212.         return editor.dom.isEmpty(li);
  1213.       });
  1214.  
  1215.       listItems = Tools.grep(listItems, function (li) {
  1216.         return !editor.dom.isEmpty(li);
  1217.       });
  1218.  
  1219.       Tools.each(emptyListItems, function (li) {
  1220.         if (NodeType.isEmpty(editor.dom, li)) {
  1221.           Outdent.outdent(editor, li);
  1222.           return;
  1223.         }
  1224.       });
  1225.  
  1226.       Tools.each(listItems, function (li) {
  1227.         var node, rootList;
  1228.  
  1229.         if (li.parentNode === editor.getBody()) {
  1230.           return;
  1231.         }
  1232.  
  1233.         for (node = li; node && node !== root; node = node.parentNode) {
  1234.           if (NodeType.isListNode(node)) {
  1235.             rootList = node;
  1236.           }
  1237.         }
  1238.  
  1239.         SplitList.splitList(editor, rootList, li);
  1240.         NormalizeLists.normalizeLists(editor.dom, rootList.parentNode);
  1241.       });
  1242.  
  1243.       editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1244.     };
  1245.  
  1246.     var isValidLists = function (list1, list2) {
  1247.       return list1 && list2 && NodeType.isListNode(list1) && list1.nodeName === list2.nodeName;
  1248.     };
  1249.  
  1250.     var hasSameListStyle = function (dom, list1, list2) {
  1251.       var targetStyle = dom.getStyle(list1, 'list-style-type', true);
  1252.       var style = dom.getStyle(list2, 'list-style-type', true);
  1253.       return targetStyle === style;
  1254.     };
  1255.  
  1256.     var hasSameClasses = function (elm1, elm2) {
  1257.       return elm1.className === elm2.className;
  1258.     };
  1259.  
  1260.     var shouldMerge = function (dom, list1, list2) {
  1261.       return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
  1262.     };
  1263.  
  1264.     var mergeWithAdjacentLists = function (dom, listBlock) {
  1265.       var sibling, node;
  1266.  
  1267.       sibling = listBlock.nextSibling;
  1268.       if (shouldMerge(dom, listBlock, sibling)) {
  1269.         while ((node = sibling.firstChild)) {
  1270.           listBlock.appendChild(node);
  1271.         }
  1272.  
  1273.         dom.remove(sibling);
  1274.       }
  1275.  
  1276.       sibling = listBlock.previousSibling;
  1277.       if (shouldMerge(dom, listBlock, sibling)) {
  1278.         while ((node = sibling.lastChild)) {
  1279.           listBlock.insertBefore(node, listBlock.firstChild);
  1280.         }
  1281.  
  1282.         dom.remove(sibling);
  1283.       }
  1284.     };
  1285.  
  1286.     var updateList = function (dom, list, listName, detail) {
  1287.       if (list.nodeName !== listName) {
  1288.         var newList = dom.rename(list, listName);
  1289.         updateListWithDetails(dom, newList, detail);
  1290.       } else {
  1291.         updateListWithDetails(dom, list, detail);
  1292.       }
  1293.     };
  1294.  
  1295.     var toggleMultipleLists = function (editor, parentList, lists, listName, detail) {
  1296.       if (parentList.nodeName === listName && !hasListStyleDetail(detail)) {
  1297.         removeList(editor, listName);
  1298.       } else {
  1299.         var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
  1300.  
  1301.         Tools.each([parentList].concat(lists), function (elm) {
  1302.           updateList(editor.dom, elm, listName, detail);
  1303.         });
  1304.  
  1305.         editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1306.       }
  1307.     };
  1308.  
  1309.     var hasListStyleDetail = function (detail) {
  1310.       return 'list-style-type' in detail;
  1311.     };
  1312.  
  1313.     var toggleSingleList = function (editor, parentList, listName, detail) {
  1314.       if (parentList === editor.getBody()) {
  1315.         return;
  1316.       }
  1317.  
  1318.       if (parentList) {
  1319.         if (parentList.nodeName === listName && !hasListStyleDetail(detail)) {
  1320.           removeList(editor, listName);
  1321.         } else {
  1322.           var bookmark = Bookmark.createBookmark(editor.selection.getRng(true));
  1323.           updateListWithDetails(editor.dom, parentList, detail);
  1324.           mergeWithAdjacentLists(editor.dom, editor.dom.rename(parentList, listName));
  1325.           editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1326.         }
  1327.       } else {
  1328.         applyList(editor, listName, detail);
  1329.       }
  1330.     };
  1331.  
  1332.     var toggleList = function (editor, listName, detail) {
  1333.       var parentList = Selection.getParentList(editor);
  1334.       var selectedSubLists = Selection.getSelectedSubLists(editor);
  1335.  
  1336.       detail = detail ? detail : {};
  1337.  
  1338.       if (parentList && selectedSubLists.length > 0) {
  1339.         toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
  1340.       } else {
  1341.         toggleSingleList(editor, parentList, listName, detail);
  1342.       }
  1343.     };
  1344.  
  1345.     return {
  1346.       toggleList: toggleList,
  1347.       removeList: removeList,
  1348.       mergeWithAdjacentLists: mergeWithAdjacentLists
  1349.     };
  1350.   }
  1351. );
  1352.  
  1353.  
  1354. /**
  1355.  * ResolveGlobal.js
  1356.  *
  1357.  * Released under LGPL License.
  1358.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1359.  *
  1360.  * License: http://www.tinymce.com/license
  1361.  * Contributing: http://www.tinymce.com/contributing
  1362.  */
  1363.  
  1364. define(
  1365.   'tinymce.core.dom.TreeWalker',
  1366.   [
  1367.     'global!tinymce.util.Tools.resolve'
  1368.   ],
  1369.   function (resolve) {
  1370.     return resolve('tinymce.dom.TreeWalker');
  1371.   }
  1372. );
  1373.  
  1374. /**
  1375.  * Delete.js
  1376.  *
  1377.  * Released under LGPL License.
  1378.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1379.  *
  1380.  * License: http://www.tinymce.com/license
  1381.  * Contributing: http://www.tinymce.com/contributing
  1382.  */
  1383.  
  1384. define(
  1385.   'tinymce.plugins.lists.core.Delete',
  1386.   [
  1387.     'tinymce.core.dom.RangeUtils',
  1388.     'tinymce.core.dom.TreeWalker',
  1389.     'tinymce.core.util.VK',
  1390.     'tinymce.plugins.lists.actions.ToggleList',
  1391.     'tinymce.plugins.lists.core.Bookmark',
  1392.     'tinymce.plugins.lists.core.NodeType',
  1393.     'tinymce.plugins.lists.core.NormalizeLists',
  1394.     'tinymce.plugins.lists.core.Range',
  1395.     'tinymce.plugins.lists.core.Selection'
  1396.   ],
  1397.   function (RangeUtils, TreeWalker, VK, ToggleList, Bookmark, NodeType, NormalizeLists, Range, Selection) {
  1398.     var findNextCaretContainer = function (editor, rng, isForward) {
  1399.       var node = rng.startContainer, offset = rng.startOffset;
  1400.       var nonEmptyBlocks, walker;
  1401.  
  1402.       if (node.nodeType === 3 && (isForward ? offset < node.data.length : offset > 0)) {
  1403.         return node;
  1404.       }
  1405.  
  1406.       nonEmptyBlocks = editor.schema.getNonEmptyElements();
  1407.       if (node.nodeType === 1) {
  1408.         node = RangeUtils.getNode(node, offset);
  1409.       }
  1410.  
  1411.       walker = new TreeWalker(node, editor.getBody());
  1412.  
  1413.       // Delete at <li>|<br></li> then jump over the bogus br
  1414.       if (isForward) {
  1415.         if (NodeType.isBogusBr(editor.dom, node)) {
  1416.           walker.next();
  1417.         }
  1418.       }
  1419.  
  1420.       while ((node = walker[isForward ? 'next' : 'prev2']())) {
  1421.         if (node.nodeName === 'LI' && !node.hasChildNodes()) {
  1422.           return node;
  1423.         }
  1424.  
  1425.         if (nonEmptyBlocks[node.nodeName]) {
  1426.           return node;
  1427.         }
  1428.  
  1429.         if (node.nodeType === 3 && node.data.length > 0) {
  1430.           return node;
  1431.         }
  1432.       }
  1433.     };
  1434.  
  1435.     var hasOnlyOneBlockChild = function (dom, elm) {
  1436.       var childNodes = elm.childNodes;
  1437.       return childNodes.length === 1 && !NodeType.isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
  1438.     };
  1439.  
  1440.     var unwrapSingleBlockChild = function (dom, elm) {
  1441.       if (hasOnlyOneBlockChild(dom, elm)) {
  1442.         dom.remove(elm.firstChild, true);
  1443.       }
  1444.     };
  1445.  
  1446.     var moveChildren = function (dom, fromElm, toElm) {
  1447.       var node, targetElm;
  1448.  
  1449.       targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
  1450.       unwrapSingleBlockChild(dom, fromElm);
  1451.  
  1452.       if (!NodeType.isEmpty(dom, fromElm, true)) {
  1453.         while ((node = fromElm.firstChild)) {
  1454.           targetElm.appendChild(node);
  1455.         }
  1456.       }
  1457.     };
  1458.  
  1459.     var mergeLiElements = function (dom, fromElm, toElm) {
  1460.       var node, listNode, ul = fromElm.parentNode;
  1461.  
  1462.       if (!NodeType.isChildOfBody(dom, fromElm) || !NodeType.isChildOfBody(dom, toElm)) {
  1463.         return;
  1464.       }
  1465.  
  1466.       if (NodeType.isListNode(toElm.lastChild)) {
  1467.         listNode = toElm.lastChild;
  1468.       }
  1469.  
  1470.       if (ul === toElm.lastChild) {
  1471.         if (NodeType.isBr(ul.previousSibling)) {
  1472.           dom.remove(ul.previousSibling);
  1473.         }
  1474.       }
  1475.  
  1476.       node = toElm.lastChild;
  1477.       if (node && NodeType.isBr(node) && fromElm.hasChildNodes()) {
  1478.         dom.remove(node);
  1479.       }
  1480.  
  1481.       if (NodeType.isEmpty(dom, toElm, true)) {
  1482.         dom.$(toElm).empty();
  1483.       }
  1484.  
  1485.       moveChildren(dom, fromElm, toElm);
  1486.  
  1487.       if (listNode) {
  1488.         toElm.appendChild(listNode);
  1489.       }
  1490.  
  1491.       dom.remove(fromElm);
  1492.  
  1493.       if (NodeType.isEmpty(dom, ul) && ul !== dom.getRoot()) {
  1494.         dom.remove(ul);
  1495.       }
  1496.     };
  1497.  
  1498.     var mergeIntoEmptyLi = function (editor, fromLi, toLi) {
  1499.       editor.dom.$(toLi).empty();
  1500.       mergeLiElements(editor.dom, fromLi, toLi);
  1501.       editor.selection.setCursorLocation(toLi);
  1502.     };
  1503.  
  1504.     var mergeForward = function (editor, rng, fromLi, toLi) {
  1505.       var dom = editor.dom;
  1506.  
  1507.       if (dom.isEmpty(toLi)) {
  1508.         mergeIntoEmptyLi(editor, fromLi, toLi);
  1509.       } else {
  1510.         var bookmark = Bookmark.createBookmark(rng);
  1511.         mergeLiElements(dom, fromLi, toLi);
  1512.         editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1513.       }
  1514.     };
  1515.  
  1516.     var mergeBackward = function (editor, rng, fromLi, toLi) {
  1517.       var bookmark = Bookmark.createBookmark(rng);
  1518.       mergeLiElements(editor.dom, fromLi, toLi);
  1519.       editor.selection.setRng(Bookmark.resolveBookmark(bookmark));
  1520.     };
  1521.  
  1522.     var backspaceDeleteFromListToListCaret = function (editor, isForward) {
  1523.       var dom = editor.dom, selection = editor.selection;
  1524.       var li = dom.getParent(selection.getStart(), 'LI'), ul, rng, otherLi;
  1525.  
  1526.       if (li) {
  1527.         ul = li.parentNode;
  1528.         if (ul === editor.getBody() && NodeType.isEmpty(dom, ul)) {
  1529.           return true;
  1530.         }
  1531.  
  1532.         rng = Range.normalizeRange(selection.getRng(true));
  1533.         otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward), 'LI');
  1534.  
  1535.         if (otherLi && otherLi !== li) {
  1536.           if (isForward) {
  1537.             mergeForward(editor, rng, otherLi, li);
  1538.           } else {
  1539.             mergeBackward(editor, rng, li, otherLi);
  1540.           }
  1541.  
  1542.           return true;
  1543.         } else if (!otherLi) {
  1544.           if (!isForward && ToggleList.removeList(editor, ul.nodeName)) {
  1545.             return true;
  1546.           }
  1547.         }
  1548.       }
  1549.  
  1550.       return false;
  1551.     };
  1552.  
  1553.     var removeBlock = function (dom, block) {
  1554.       var parentBlock = dom.getParent(block.parentNode, dom.isBlock);
  1555.  
  1556.       dom.remove(block);
  1557.       if (parentBlock && dom.isEmpty(parentBlock)) {
  1558.         dom.remove(parentBlock);
  1559.       }
  1560.     };
  1561.  
  1562.     var backspaceDeleteIntoListCaret = function (editor, isForward) {
  1563.       var dom = editor.dom;
  1564.       var block = dom.getParent(editor.selection.getStart(), dom.isBlock);
  1565.  
  1566.       if (block && dom.isEmpty(block)) {
  1567.         var rng = Range.normalizeRange(editor.selection.getRng(true));
  1568.         var otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward), 'LI');
  1569.  
  1570.         if (otherLi) {
  1571.           editor.undoManager.transact(function () {
  1572.             removeBlock(dom, block);
  1573.             ToggleList.mergeWithAdjacentLists(dom, otherLi.parentNode);
  1574.             editor.selection.select(otherLi, true);
  1575.             editor.selection.collapse(isForward);
  1576.           });
  1577.  
  1578.           return true;
  1579.         }
  1580.       }
  1581.  
  1582.       return false;
  1583.     };
  1584.  
  1585.     var backspaceDeleteCaret = function (editor, isForward) {
  1586.       return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
  1587.     };
  1588.  
  1589.     var backspaceDeleteRange = function (editor) {
  1590.       var startListParent = editor.dom.getParent(editor.selection.getStart(), 'LI,DT,DD');
  1591.  
  1592.       if (startListParent || Selection.getSelectedListItems(editor).length > 0) {
  1593.         editor.undoManager.transact(function () {
  1594.           editor.execCommand('Delete');
  1595.           NormalizeLists.normalizeLists(editor.dom, editor.getBody());
  1596.         });
  1597.  
  1598.         return true;
  1599.       }
  1600.  
  1601.       return false;
  1602.     };
  1603.  
  1604.     var backspaceDelete = function (editor, isForward) {
  1605.       return editor.selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor);
  1606.     };
  1607.  
  1608.     var setup = function (editor) {
  1609.       editor.on('keydown', function (e) {
  1610.         if (e.keyCode === VK.BACKSPACE) {
  1611.           if (backspaceDelete(editor, false)) {
  1612.             e.preventDefault();
  1613.           }
  1614.         } else if (e.keyCode === VK.DELETE) {
  1615.           if (backspaceDelete(editor, true)) {
  1616.             e.preventDefault();
  1617.           }
  1618.         }
  1619.       });
  1620.     };
  1621.  
  1622.     return {
  1623.       setup: setup,
  1624.       backspaceDelete: backspaceDelete
  1625.     };
  1626.   }
  1627. );
  1628.  
  1629.  
  1630. /**
  1631.  * plugin.js
  1632.  *
  1633.  * Released under LGPL License.
  1634.  * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1635.  *
  1636.  * License: http://www.tinymce.com/license
  1637.  * Contributing: http://www.tinymce.com/contributing
  1638.  */
  1639.  
  1640. define(
  1641.   'tinymce.plugins.lists.Plugin',
  1642.   [
  1643.     'tinymce.core.PluginManager',
  1644.     'tinymce.core.util.Tools',
  1645.     'tinymce.core.util.VK',
  1646.     'tinymce.plugins.lists.actions.Indent',
  1647.     'tinymce.plugins.lists.actions.Outdent',
  1648.     'tinymce.plugins.lists.actions.ToggleList',
  1649.     'tinymce.plugins.lists.core.Delete',
  1650.     'tinymce.plugins.lists.core.NodeType',
  1651.     'tinymce.plugins.lists.core.Selection'
  1652.   ],
  1653.   function (PluginManager, Tools, VK, Indent, Outdent, ToggleList, Delete, NodeType, Selection) {
  1654.     var queryListCommandState = function (editor, listName) {
  1655.       return function () {
  1656.         var parentList = editor.dom.getParent(editor.selection.getStart(), 'UL,OL,DL');
  1657.         return parentList && parentList.nodeName === listName;
  1658.       };
  1659.     };
  1660.  
  1661.     var setupCommands = function (editor) {
  1662.       editor.on('BeforeExecCommand', function (e) {
  1663.         var cmd = e.command.toLowerCase(), isHandled;
  1664.  
  1665.         if (cmd === "indent") {
  1666.           if (Indent.indentSelection(editor)) {
  1667.             isHandled = true;
  1668.           }
  1669.         } else if (cmd === "outdent") {
  1670.           if (Outdent.outdentSelection(editor)) {
  1671.             isHandled = true;
  1672.           }
  1673.         }
  1674.  
  1675.         if (isHandled) {
  1676.           editor.fire('ExecCommand', { command: e.command });
  1677.           e.preventDefault();
  1678.           return true;
  1679.         }
  1680.       });
  1681.  
  1682.       editor.addCommand('InsertUnorderedList', function (ui, detail) {
  1683.         ToggleList.toggleList(editor, 'UL', detail);
  1684.       });
  1685.  
  1686.       editor.addCommand('InsertOrderedList', function (ui, detail) {
  1687.         ToggleList.toggleList(editor, 'OL', detail);
  1688.       });
  1689.  
  1690.       editor.addCommand('InsertDefinitionList', function (ui, detail) {
  1691.         ToggleList.toggleList(editor, 'DL', detail);
  1692.       });
  1693.     };
  1694.  
  1695.     var setupStateHandlers = function (editor) {
  1696.       editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
  1697.       editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
  1698.       editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
  1699.     };
  1700.  
  1701.     var setupTabKey = function (editor) {
  1702.       editor.on('keydown', function (e) {
  1703.         // Check for tab but not ctrl/cmd+tab since it switches browser tabs
  1704.         if (e.keyCode !== 9 || VK.metaKeyPressed(e)) {
  1705.           return;
  1706.         }
  1707.  
  1708.         if (editor.dom.getParent(editor.selection.getStart(), 'LI,DT,DD')) {
  1709.           e.preventDefault();
  1710.  
  1711.           if (e.shiftKey) {
  1712.             Outdent.outdentSelection(editor);
  1713.           } else {
  1714.             Indent.indentSelection(editor);
  1715.           }
  1716.         }
  1717.       });
  1718.     };
  1719.  
  1720.     var setupUi = function (editor) {
  1721.       var listState = function (listName) {
  1722.         return function () {
  1723.           var self = this;
  1724.  
  1725.           editor.on('NodeChange', function (e) {
  1726.             var lists = Tools.grep(e.parents, NodeType.isListNode);
  1727.             self.active(lists.length > 0 && lists[0].nodeName === listName);
  1728.           });
  1729.         };
  1730.       };
  1731.  
  1732.       var hasPlugin = function (editor, plugin) {
  1733.         var plugins = editor.settings.plugins ? editor.settings.plugins : '';
  1734.         return Tools.inArray(plugins.split(/[ ,]/), plugin) !== -1;
  1735.       };
  1736.  
  1737.       if (!hasPlugin(editor, 'advlist')) {
  1738.         editor.addButton('numlist', {
  1739.           title: 'Numbered list',
  1740.           cmd: 'InsertOrderedList',
  1741.           onPostRender: listState('OL')
  1742.         });
  1743.  
  1744.         editor.addButton('bullist', {
  1745.           title: 'Bullet list',
  1746.           cmd: 'InsertUnorderedList',
  1747.           onPostRender: listState('UL')
  1748.         });
  1749.       }
  1750.  
  1751.       editor.addButton('indent', {
  1752.         icon: 'indent',
  1753.         title: 'Increase indent',
  1754.         cmd: 'Indent',
  1755.         onPostRender: function (e) {
  1756.           var ctrl = e.control;
  1757.  
  1758.           editor.on('nodechange', function () {
  1759.             var listItemBlocks = Selection.getSelectedListItems(editor);
  1760.             var disable = listItemBlocks.length > 0 && NodeType.isFirstChild(listItemBlocks[0]);
  1761.             ctrl.disabled(disable);
  1762.           });
  1763.         }
  1764.       });
  1765.     };
  1766.  
  1767.     PluginManager.add('lists', function (editor) {
  1768.       setupUi(editor);
  1769.       Delete.setup(editor);
  1770.  
  1771.       editor.on('init', function () {
  1772.         setupCommands(editor);
  1773.         setupStateHandlers(editor);
  1774.         if (editor.getParam('lists_indent_on_tab', true)) {
  1775.           setupTabKey(editor);
  1776.         }
  1777.       });
  1778.  
  1779.       return {
  1780.         backspaceDelete: function (isForward) {
  1781.           Delete.backspaceDelete(editor, isForward);
  1782.         }
  1783.       };
  1784.     });
  1785.  
  1786.     return function () { };
  1787.   }
  1788. );
  1789.  
  1790.  
  1791. dem('tinymce.plugins.lists.Plugin')();
  1792. })();
  1793.