Subversion Repositories oidplus

Rev

Rev 1042 | Go to most recent revision | View as "text/javascript" | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /**
  2.  * Copyright (c) Tiny Technologies, Inc. All rights reserved.
  3.  * Licensed under the LGPL or a commercial license.
  4.  * For LGPL see License.txt in the project root for license information.
  5.  * For commercial licenses see https://www.tiny.cloud/
  6.  *
  7.  * Version: 5.10.8 (2023-10-19)
  8.  */
  9. (function () {
  10.     'use strict';
  11.  
  12.     var Cell = function (initial) {
  13.       var value = initial;
  14.       var get = function () {
  15.         return value;
  16.       };
  17.       var set = function (v) {
  18.         value = v;
  19.       };
  20.       return {
  21.         get: get,
  22.         set: set
  23.       };
  24.     };
  25.  
  26.     var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  27.  
  28.     var __assign = function () {
  29.       __assign = Object.assign || function __assign(t) {
  30.         for (var s, i = 1, n = arguments.length; i < n; i++) {
  31.           s = arguments[i];
  32.           for (var p in s)
  33.             if (Object.prototype.hasOwnProperty.call(s, p))
  34.               t[p] = s[p];
  35.         }
  36.         return t;
  37.       };
  38.       return __assign.apply(this, arguments);
  39.     };
  40.  
  41.     var typeOf = function (x) {
  42.       var t = typeof x;
  43.       if (x === null) {
  44.         return 'null';
  45.       } else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
  46.         return 'array';
  47.       } else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
  48.         return 'string';
  49.       } else {
  50.         return t;
  51.       }
  52.     };
  53.     var isType$1 = function (type) {
  54.       return function (value) {
  55.         return typeOf(value) === type;
  56.       };
  57.     };
  58.     var isSimpleType = function (type) {
  59.       return function (value) {
  60.         return typeof value === type;
  61.       };
  62.     };
  63.     var isString = isType$1('string');
  64.     var isArray = isType$1('array');
  65.     var isBoolean = isSimpleType('boolean');
  66.     var isNumber = isSimpleType('number');
  67.  
  68.     var noop = function () {
  69.     };
  70.     var constant = function (value) {
  71.       return function () {
  72.         return value;
  73.       };
  74.     };
  75.     var identity = function (x) {
  76.       return x;
  77.     };
  78.     var never = constant(false);
  79.     var always = constant(true);
  80.  
  81.     var punctuationStr = '[!-#%-*,-\\/:;?@\\[-\\]_{}\xA1\xAB\xB7\xBB\xBF;\xB7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uff3f\uFF5B\uFF5D\uFF5F-\uFF65]';
  82.  
  83.     var punctuation$1 = constant(punctuationStr);
  84.  
  85.     var none = function () {
  86.       return NONE;
  87.     };
  88.     var NONE = function () {
  89.       var call = function (thunk) {
  90.         return thunk();
  91.       };
  92.       var id = identity;
  93.       var me = {
  94.         fold: function (n, _s) {
  95.           return n();
  96.         },
  97.         isSome: never,
  98.         isNone: always,
  99.         getOr: id,
  100.         getOrThunk: call,
  101.         getOrDie: function (msg) {
  102.           throw new Error(msg || 'error: getOrDie called on none.');
  103.         },
  104.         getOrNull: constant(null),
  105.         getOrUndefined: constant(undefined),
  106.         or: id,
  107.         orThunk: call,
  108.         map: none,
  109.         each: noop,
  110.         bind: none,
  111.         exists: never,
  112.         forall: always,
  113.         filter: function () {
  114.           return none();
  115.         },
  116.         toArray: function () {
  117.           return [];
  118.         },
  119.         toString: constant('none()')
  120.       };
  121.       return me;
  122.     }();
  123.     var some = function (a) {
  124.       var constant_a = constant(a);
  125.       var self = function () {
  126.         return me;
  127.       };
  128.       var bind = function (f) {
  129.         return f(a);
  130.       };
  131.       var me = {
  132.         fold: function (n, s) {
  133.           return s(a);
  134.         },
  135.         isSome: always,
  136.         isNone: never,
  137.         getOr: constant_a,
  138.         getOrThunk: constant_a,
  139.         getOrDie: constant_a,
  140.         getOrNull: constant_a,
  141.         getOrUndefined: constant_a,
  142.         or: self,
  143.         orThunk: self,
  144.         map: function (f) {
  145.           return some(f(a));
  146.         },
  147.         each: function (f) {
  148.           f(a);
  149.         },
  150.         bind: bind,
  151.         exists: bind,
  152.         forall: bind,
  153.         filter: function (f) {
  154.           return f(a) ? me : NONE;
  155.         },
  156.         toArray: function () {
  157.           return [a];
  158.         },
  159.         toString: function () {
  160.           return 'some(' + a + ')';
  161.         }
  162.       };
  163.       return me;
  164.     };
  165.     var from = function (value) {
  166.       return value === null || value === undefined ? NONE : some(value);
  167.     };
  168.     var Optional = {
  169.       some: some,
  170.       none: none,
  171.       from: from
  172.     };
  173.  
  174.     var punctuation = punctuation$1;
  175.  
  176.     var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
  177.  
  178.     var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  179.  
  180.     var nativeSlice = Array.prototype.slice;
  181.     var nativePush = Array.prototype.push;
  182.     var map = function (xs, f) {
  183.       var len = xs.length;
  184.       var r = new Array(len);
  185.       for (var i = 0; i < len; i++) {
  186.         var x = xs[i];
  187.         r[i] = f(x, i);
  188.       }
  189.       return r;
  190.     };
  191.     var each = function (xs, f) {
  192.       for (var i = 0, len = xs.length; i < len; i++) {
  193.         var x = xs[i];
  194.         f(x, i);
  195.       }
  196.     };
  197.     var eachr = function (xs, f) {
  198.       for (var i = xs.length - 1; i >= 0; i--) {
  199.         var x = xs[i];
  200.         f(x, i);
  201.       }
  202.     };
  203.     var groupBy = function (xs, f) {
  204.       if (xs.length === 0) {
  205.         return [];
  206.       } else {
  207.         var wasType = f(xs[0]);
  208.         var r = [];
  209.         var group = [];
  210.         for (var i = 0, len = xs.length; i < len; i++) {
  211.           var x = xs[i];
  212.           var type = f(x);
  213.           if (type !== wasType) {
  214.             r.push(group);
  215.             group = [];
  216.           }
  217.           wasType = type;
  218.           group.push(x);
  219.         }
  220.         if (group.length !== 0) {
  221.           r.push(group);
  222.         }
  223.         return r;
  224.       }
  225.     };
  226.     var foldl = function (xs, f, acc) {
  227.       each(xs, function (x, i) {
  228.         acc = f(acc, x, i);
  229.       });
  230.       return acc;
  231.     };
  232.     var flatten = function (xs) {
  233.       var r = [];
  234.       for (var i = 0, len = xs.length; i < len; ++i) {
  235.         if (!isArray(xs[i])) {
  236.           throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  237.         }
  238.         nativePush.apply(r, xs[i]);
  239.       }
  240.       return r;
  241.     };
  242.     var bind = function (xs, f) {
  243.       return flatten(map(xs, f));
  244.     };
  245.     var sort = function (xs, comparator) {
  246.       var copy = nativeSlice.call(xs, 0);
  247.       copy.sort(comparator);
  248.       return copy;
  249.     };
  250.  
  251.     var hasOwnProperty = Object.hasOwnProperty;
  252.     var has = function (obj, key) {
  253.       return hasOwnProperty.call(obj, key);
  254.     };
  255.  
  256.     typeof window !== 'undefined' ? window : Function('return this;')();
  257.  
  258.     var DOCUMENT = 9;
  259.     var DOCUMENT_FRAGMENT = 11;
  260.     var ELEMENT = 1;
  261.     var TEXT = 3;
  262.  
  263.     var type = function (element) {
  264.       return element.dom.nodeType;
  265.     };
  266.     var isType = function (t) {
  267.       return function (element) {
  268.         return type(element) === t;
  269.       };
  270.     };
  271.     var isText$1 = isType(TEXT);
  272.  
  273.     var rawSet = function (dom, key, value) {
  274.       if (isString(value) || isBoolean(value) || isNumber(value)) {
  275.         dom.setAttribute(key, value + '');
  276.       } else {
  277.         console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  278.         throw new Error('Attribute value was not simple');
  279.       }
  280.     };
  281.     var set = function (element, key, value) {
  282.       rawSet(element.dom, key, value);
  283.     };
  284.  
  285.     var compareDocumentPosition = function (a, b, match) {
  286.       return (a.compareDocumentPosition(b) & match) !== 0;
  287.     };
  288.     var documentPositionPreceding = function (a, b) {
  289.       return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING);
  290.     };
  291.  
  292.     var fromHtml = function (html, scope) {
  293.       var doc = scope || document;
  294.       var div = doc.createElement('div');
  295.       div.innerHTML = html;
  296.       if (!div.hasChildNodes() || div.childNodes.length > 1) {
  297.         console.error('HTML does not have a single root node', html);
  298.         throw new Error('HTML must have a single root node');
  299.       }
  300.       return fromDom(div.childNodes[0]);
  301.     };
  302.     var fromTag = function (tag, scope) {
  303.       var doc = scope || document;
  304.       var node = doc.createElement(tag);
  305.       return fromDom(node);
  306.     };
  307.     var fromText = function (text, scope) {
  308.       var doc = scope || document;
  309.       var node = doc.createTextNode(text);
  310.       return fromDom(node);
  311.     };
  312.     var fromDom = function (node) {
  313.       if (node === null || node === undefined) {
  314.         throw new Error('Node cannot be null or undefined');
  315.       }
  316.       return { dom: node };
  317.     };
  318.     var fromPoint = function (docElm, x, y) {
  319.       return Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  320.     };
  321.     var SugarElement = {
  322.       fromHtml: fromHtml,
  323.       fromTag: fromTag,
  324.       fromText: fromText,
  325.       fromDom: fromDom,
  326.       fromPoint: fromPoint
  327.     };
  328.  
  329.     var bypassSelector = function (dom) {
  330.       return dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  331.     };
  332.     var all = function (selector, scope) {
  333.       var base = scope === undefined ? document : scope.dom;
  334.       return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  335.     };
  336.  
  337.     var parent = function (element) {
  338.       return Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  339.     };
  340.     var children = function (element) {
  341.       return map(element.dom.childNodes, SugarElement.fromDom);
  342.     };
  343.     var spot = function (element, offset) {
  344.       return {
  345.         element: element,
  346.         offset: offset
  347.       };
  348.     };
  349.     var leaf = function (element, offset) {
  350.       var cs = children(element);
  351.       return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
  352.     };
  353.  
  354.     var before = function (marker, element) {
  355.       var parent$1 = parent(marker);
  356.       parent$1.each(function (v) {
  357.         v.dom.insertBefore(element.dom, marker.dom);
  358.       });
  359.     };
  360.     var append = function (parent, element) {
  361.       parent.dom.appendChild(element.dom);
  362.     };
  363.     var wrap = function (element, wrapper) {
  364.       before(element, wrapper);
  365.       append(wrapper, element);
  366.     };
  367.  
  368.     var NodeValue = function (is, name) {
  369.       var get = function (element) {
  370.         if (!is(element)) {
  371.           throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
  372.         }
  373.         return getOption(element).getOr('');
  374.       };
  375.       var getOption = function (element) {
  376.         return is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
  377.       };
  378.       var set = function (element, value) {
  379.         if (!is(element)) {
  380.           throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
  381.         }
  382.         element.dom.nodeValue = value;
  383.       };
  384.       return {
  385.         get: get,
  386.         getOption: getOption,
  387.         set: set
  388.       };
  389.     };
  390.  
  391.     var api = NodeValue(isText$1, 'text');
  392.     var get$1 = function (element) {
  393.       return api.get(element);
  394.     };
  395.  
  396.     var descendants = function (scope, selector) {
  397.       return all(selector, scope);
  398.     };
  399.  
  400.     var global = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
  401.  
  402.     var isSimpleBoundary = function (dom, node) {
  403.       return dom.isBlock(node) || has(dom.schema.getShortEndedElements(), node.nodeName);
  404.     };
  405.     var isContentEditableFalse = function (dom, node) {
  406.       return dom.getContentEditable(node) === 'false';
  407.     };
  408.     var isContentEditableTrueInCef = function (dom, node) {
  409.       return dom.getContentEditable(node) === 'true' && dom.getContentEditableParent(node.parentNode) === 'false';
  410.     };
  411.     var isHidden = function (dom, node) {
  412.       return !dom.isBlock(node) && has(dom.schema.getWhiteSpaceElements(), node.nodeName);
  413.     };
  414.     var isBoundary = function (dom, node) {
  415.       return isSimpleBoundary(dom, node) || isContentEditableFalse(dom, node) || isHidden(dom, node) || isContentEditableTrueInCef(dom, node);
  416.     };
  417.     var isText = function (node) {
  418.       return node.nodeType === 3;
  419.     };
  420.     var nuSection = function () {
  421.       return {
  422.         sOffset: 0,
  423.         fOffset: 0,
  424.         elements: []
  425.       };
  426.     };
  427.     var toLeaf = function (node, offset) {
  428.       return leaf(SugarElement.fromDom(node), offset);
  429.     };
  430.     var walk = function (dom, walkerFn, startNode, callbacks, endNode, skipStart) {
  431.       if (skipStart === void 0) {
  432.         skipStart = true;
  433.       }
  434.       var next = skipStart ? walkerFn(false) : startNode;
  435.       while (next) {
  436.         var isCefNode = isContentEditableFalse(dom, next);
  437.         if (isCefNode || isHidden(dom, next)) {
  438.           var stopWalking = isCefNode ? callbacks.cef(next) : callbacks.boundary(next);
  439.           if (stopWalking) {
  440.             break;
  441.           } else {
  442.             next = walkerFn(true);
  443.             continue;
  444.           }
  445.         } else if (isSimpleBoundary(dom, next)) {
  446.           if (callbacks.boundary(next)) {
  447.             break;
  448.           }
  449.         } else if (isText(next)) {
  450.           callbacks.text(next);
  451.         }
  452.         if (next === endNode) {
  453.           break;
  454.         } else {
  455.           next = walkerFn(false);
  456.         }
  457.       }
  458.     };
  459.     var collectTextToBoundary = function (dom, section, node, rootNode, forwards) {
  460.       if (isBoundary(dom, node)) {
  461.         return;
  462.       }
  463.       var rootBlock = dom.getParent(rootNode, dom.isBlock);
  464.       var walker = new global(node, rootBlock);
  465.       var walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker);
  466.       walk(dom, walkerFn, node, {
  467.         boundary: always,
  468.         cef: always,
  469.         text: function (next) {
  470.           if (forwards) {
  471.             section.fOffset += next.length;
  472.           } else {
  473.             section.sOffset += next.length;
  474.           }
  475.           section.elements.push(SugarElement.fromDom(next));
  476.         }
  477.       });
  478.     };
  479.     var collect = function (dom, rootNode, startNode, endNode, callbacks, skipStart) {
  480.       if (skipStart === void 0) {
  481.         skipStart = true;
  482.       }
  483.       var walker = new global(startNode, rootNode);
  484.       var sections = [];
  485.       var current = nuSection();
  486.       collectTextToBoundary(dom, current, startNode, rootNode, false);
  487.       var finishSection = function () {
  488.         if (current.elements.length > 0) {
  489.           sections.push(current);
  490.           current = nuSection();
  491.         }
  492.         return false;
  493.       };
  494.       walk(dom, walker.next.bind(walker), startNode, {
  495.         boundary: finishSection,
  496.         cef: function (node) {
  497.           finishSection();
  498.           if (callbacks) {
  499.             sections.push.apply(sections, callbacks.cef(node));
  500.           }
  501.           return false;
  502.         },
  503.         text: function (next) {
  504.           current.elements.push(SugarElement.fromDom(next));
  505.           if (callbacks) {
  506.             callbacks.text(next, current);
  507.           }
  508.         }
  509.       }, endNode, skipStart);
  510.       if (endNode) {
  511.         collectTextToBoundary(dom, current, endNode, rootNode, true);
  512.       }
  513.       finishSection();
  514.       return sections;
  515.     };
  516.     var collectRangeSections = function (dom, rng) {
  517.       var start = toLeaf(rng.startContainer, rng.startOffset);
  518.       var startNode = start.element.dom;
  519.       var end = toLeaf(rng.endContainer, rng.endOffset);
  520.       var endNode = end.element.dom;
  521.       return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
  522.         text: function (node, section) {
  523.           if (node === endNode) {
  524.             section.fOffset += node.length - end.offset;
  525.           } else if (node === startNode) {
  526.             section.sOffset += start.offset;
  527.           }
  528.         },
  529.         cef: function (node) {
  530.           var sections = bind(descendants(SugarElement.fromDom(node), '*[contenteditable=true]'), function (e) {
  531.             var ceTrueNode = e.dom;
  532.             return collect(dom, ceTrueNode, ceTrueNode);
  533.           });
  534.           return sort(sections, function (a, b) {
  535.             return documentPositionPreceding(a.elements[0].dom, b.elements[0].dom) ? 1 : -1;
  536.           });
  537.         }
  538.       }, false);
  539.     };
  540.     var fromRng = function (dom, rng) {
  541.       return rng.collapsed ? [] : collectRangeSections(dom, rng);
  542.     };
  543.     var fromNode = function (dom, node) {
  544.       var rng = dom.createRng();
  545.       rng.selectNode(node);
  546.       return fromRng(dom, rng);
  547.     };
  548.     var fromNodes = function (dom, nodes) {
  549.       return bind(nodes, function (node) {
  550.         return fromNode(dom, node);
  551.       });
  552.     };
  553.  
  554.     var find$2 = function (text, pattern, start, finish) {
  555.       if (start === void 0) {
  556.         start = 0;
  557.       }
  558.       if (finish === void 0) {
  559.         finish = text.length;
  560.       }
  561.       var regex = pattern.regex;
  562.       regex.lastIndex = start;
  563.       var results = [];
  564.       var match;
  565.       while (match = regex.exec(text)) {
  566.         var matchedText = match[pattern.matchIndex];
  567.         var matchStart = match.index + match[0].indexOf(matchedText);
  568.         var matchFinish = matchStart + matchedText.length;
  569.         if (matchFinish > finish) {
  570.           break;
  571.         }
  572.         results.push({
  573.           start: matchStart,
  574.           finish: matchFinish
  575.         });
  576.         regex.lastIndex = matchFinish;
  577.       }
  578.       return results;
  579.     };
  580.     var extract = function (elements, matches) {
  581.       var nodePositions = foldl(elements, function (acc, element) {
  582.         var content = get$1(element);
  583.         var start = acc.last;
  584.         var finish = start + content.length;
  585.         var positions = bind(matches, function (match, matchIdx) {
  586.           if (match.start < finish && match.finish > start) {
  587.             return [{
  588.                 element: element,
  589.                 start: Math.max(start, match.start) - start,
  590.                 finish: Math.min(finish, match.finish) - start,
  591.                 matchId: matchIdx
  592.               }];
  593.           } else {
  594.             return [];
  595.           }
  596.         });
  597.         return {
  598.           results: acc.results.concat(positions),
  599.           last: finish
  600.         };
  601.       }, {
  602.         results: [],
  603.         last: 0
  604.       }).results;
  605.       return groupBy(nodePositions, function (position) {
  606.         return position.matchId;
  607.       });
  608.     };
  609.  
  610.     var find$1 = function (pattern, sections) {
  611.       return bind(sections, function (section) {
  612.         var elements = section.elements;
  613.         var content = map(elements, get$1).join('');
  614.         var positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset);
  615.         return extract(elements, positions);
  616.       });
  617.     };
  618.     var mark = function (matches, replacementNode) {
  619.       eachr(matches, function (match, idx) {
  620.         eachr(match, function (pos) {
  621.           var wrapper = SugarElement.fromDom(replacementNode.cloneNode(false));
  622.           set(wrapper, 'data-mce-index', idx);
  623.           var textNode = pos.element.dom;
  624.           if (textNode.length === pos.finish && pos.start === 0) {
  625.             wrap(pos.element, wrapper);
  626.           } else {
  627.             if (textNode.length !== pos.finish) {
  628.               textNode.splitText(pos.finish);
  629.             }
  630.             var matchNode = textNode.splitText(pos.start);
  631.             wrap(SugarElement.fromDom(matchNode), wrapper);
  632.           }
  633.         });
  634.       });
  635.     };
  636.     var findAndMark = function (dom, pattern, node, replacementNode) {
  637.       var textSections = fromNode(dom, node);
  638.       var matches = find$1(pattern, textSections);
  639.       mark(matches, replacementNode);
  640.       return matches.length;
  641.     };
  642.     var findAndMarkInSelection = function (dom, pattern, selection, replacementNode) {
  643.       var bookmark = selection.getBookmark();
  644.       var nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
  645.       var textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng());
  646.       var matches = find$1(pattern, textSections);
  647.       mark(matches, replacementNode);
  648.       selection.moveToBookmark(bookmark);
  649.       return matches.length;
  650.     };
  651.  
  652.     var getElmIndex = function (elm) {
  653.       var value = elm.getAttribute('data-mce-index');
  654.       if (typeof value === 'number') {
  655.         return '' + value;
  656.       }
  657.       return value;
  658.     };
  659.     var markAllMatches = function (editor, currentSearchState, pattern, inSelection) {
  660.       var marker = editor.dom.create('span', { 'data-mce-bogus': 1 });
  661.       marker.className = 'mce-match-marker';
  662.       var node = editor.getBody();
  663.       done(editor, currentSearchState, false);
  664.       if (inSelection) {
  665.         return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker);
  666.       } else {
  667.         return findAndMark(editor.dom, pattern, node, marker);
  668.       }
  669.     };
  670.     var unwrap = function (node) {
  671.       var parentNode = node.parentNode;
  672.       if (node.firstChild) {
  673.         parentNode.insertBefore(node.firstChild, node);
  674.       }
  675.       node.parentNode.removeChild(node);
  676.     };
  677.     var findSpansByIndex = function (editor, index) {
  678.       var spans = [];
  679.       var nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
  680.       if (nodes.length) {
  681.         for (var i = 0; i < nodes.length; i++) {
  682.           var nodeIndex = getElmIndex(nodes[i]);
  683.           if (nodeIndex === null || !nodeIndex.length) {
  684.             continue;
  685.           }
  686.           if (nodeIndex === index.toString()) {
  687.             spans.push(nodes[i]);
  688.           }
  689.         }
  690.       }
  691.       return spans;
  692.     };
  693.     var moveSelection = function (editor, currentSearchState, forward) {
  694.       var searchState = currentSearchState.get();
  695.       var testIndex = searchState.index;
  696.       var dom = editor.dom;
  697.       forward = forward !== false;
  698.       if (forward) {
  699.         if (testIndex + 1 === searchState.count) {
  700.           testIndex = 0;
  701.         } else {
  702.           testIndex++;
  703.         }
  704.       } else {
  705.         if (testIndex - 1 === -1) {
  706.           testIndex = searchState.count - 1;
  707.         } else {
  708.           testIndex--;
  709.         }
  710.       }
  711.       dom.removeClass(findSpansByIndex(editor, searchState.index), 'mce-match-marker-selected');
  712.       var spans = findSpansByIndex(editor, testIndex);
  713.       if (spans.length) {
  714.         dom.addClass(findSpansByIndex(editor, testIndex), 'mce-match-marker-selected');
  715.         editor.selection.scrollIntoView(spans[0]);
  716.         return testIndex;
  717.       }
  718.       return -1;
  719.     };
  720.     var removeNode = function (dom, node) {
  721.       var parent = node.parentNode;
  722.       dom.remove(node);
  723.       if (dom.isEmpty(parent)) {
  724.         dom.remove(parent);
  725.       }
  726.     };
  727.     var escapeSearchText = function (text, wholeWord) {
  728.       var escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&').replace(/\s/g, '[^\\S\\r\\n\\uFEFF]');
  729.       var wordRegex = '(' + escapedText + ')';
  730.       return wholeWord ? '(?:^|\\s|' + punctuation() + ')' + wordRegex + ('(?=$|\\s|' + punctuation() + ')') : wordRegex;
  731.     };
  732.     var find = function (editor, currentSearchState, text, matchCase, wholeWord, inSelection) {
  733.       var selection = editor.selection;
  734.       var escapedText = escapeSearchText(text, wholeWord);
  735.       var isForwardSelection = selection.isForward();
  736.       var pattern = {
  737.         regex: new RegExp(escapedText, matchCase ? 'g' : 'gi'),
  738.         matchIndex: 1
  739.       };
  740.       var count = markAllMatches(editor, currentSearchState, pattern, inSelection);
  741.       if (global$2.browser.isSafari()) {
  742.         selection.setRng(selection.getRng(), isForwardSelection);
  743.       }
  744.       if (count) {
  745.         var newIndex = moveSelection(editor, currentSearchState, true);
  746.         currentSearchState.set({
  747.           index: newIndex,
  748.           count: count,
  749.           text: text,
  750.           matchCase: matchCase,
  751.           wholeWord: wholeWord,
  752.           inSelection: inSelection
  753.         });
  754.       }
  755.       return count;
  756.     };
  757.     var next = function (editor, currentSearchState) {
  758.       var index = moveSelection(editor, currentSearchState, true);
  759.       currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }));
  760.     };
  761.     var prev = function (editor, currentSearchState) {
  762.       var index = moveSelection(editor, currentSearchState, false);
  763.       currentSearchState.set(__assign(__assign({}, currentSearchState.get()), { index: index }));
  764.     };
  765.     var isMatchSpan = function (node) {
  766.       var matchIndex = getElmIndex(node);
  767.       return matchIndex !== null && matchIndex.length > 0;
  768.     };
  769.     var replace = function (editor, currentSearchState, text, forward, all) {
  770.       var searchState = currentSearchState.get();
  771.       var currentIndex = searchState.index;
  772.       var currentMatchIndex, nextIndex = currentIndex;
  773.       forward = forward !== false;
  774.       var node = editor.getBody();
  775.       var nodes = global$1.grep(global$1.toArray(node.getElementsByTagName('span')), isMatchSpan);
  776.       for (var i = 0; i < nodes.length; i++) {
  777.         var nodeIndex = getElmIndex(nodes[i]);
  778.         var matchIndex = currentMatchIndex = parseInt(nodeIndex, 10);
  779.         if (all || matchIndex === searchState.index) {
  780.           if (text.length) {
  781.             nodes[i].firstChild.nodeValue = text;
  782.             unwrap(nodes[i]);
  783.           } else {
  784.             removeNode(editor.dom, nodes[i]);
  785.           }
  786.           while (nodes[++i]) {
  787.             matchIndex = parseInt(getElmIndex(nodes[i]), 10);
  788.             if (matchIndex === currentMatchIndex) {
  789.               removeNode(editor.dom, nodes[i]);
  790.             } else {
  791.               i--;
  792.               break;
  793.             }
  794.           }
  795.           if (forward) {
  796.             nextIndex--;
  797.           }
  798.         } else if (currentMatchIndex > currentIndex) {
  799.           nodes[i].setAttribute('data-mce-index', String(currentMatchIndex - 1));
  800.         }
  801.       }
  802.       currentSearchState.set(__assign(__assign({}, searchState), {
  803.         count: all ? 0 : searchState.count - 1,
  804.         index: nextIndex
  805.       }));
  806.       if (forward) {
  807.         next(editor, currentSearchState);
  808.       } else {
  809.         prev(editor, currentSearchState);
  810.       }
  811.       return !all && currentSearchState.get().count > 0;
  812.     };
  813.     var done = function (editor, currentSearchState, keepEditorSelection) {
  814.       var startContainer, endContainer;
  815.       var searchState = currentSearchState.get();
  816.       var nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
  817.       for (var i = 0; i < nodes.length; i++) {
  818.         var nodeIndex = getElmIndex(nodes[i]);
  819.         if (nodeIndex !== null && nodeIndex.length) {
  820.           if (nodeIndex === searchState.index.toString()) {
  821.             if (!startContainer) {
  822.               startContainer = nodes[i].firstChild;
  823.             }
  824.             endContainer = nodes[i].firstChild;
  825.           }
  826.           unwrap(nodes[i]);
  827.         }
  828.       }
  829.       currentSearchState.set(__assign(__assign({}, searchState), {
  830.         index: -1,
  831.         count: 0,
  832.         text: ''
  833.       }));
  834.       if (startContainer && endContainer) {
  835.         var rng = editor.dom.createRng();
  836.         rng.setStart(startContainer, 0);
  837.         rng.setEnd(endContainer, endContainer.data.length);
  838.         if (keepEditorSelection !== false) {
  839.           editor.selection.setRng(rng);
  840.         }
  841.         return rng;
  842.       }
  843.     };
  844.     var hasNext = function (editor, currentSearchState) {
  845.       return currentSearchState.get().count > 1;
  846.     };
  847.     var hasPrev = function (editor, currentSearchState) {
  848.       return currentSearchState.get().count > 1;
  849.     };
  850.  
  851.     var get = function (editor, currentState) {
  852.       var done$1 = function (keepEditorSelection) {
  853.         return done(editor, currentState, keepEditorSelection);
  854.       };
  855.       var find$1 = function (text, matchCase, wholeWord, inSelection) {
  856.         if (inSelection === void 0) {
  857.           inSelection = false;
  858.         }
  859.         return find(editor, currentState, text, matchCase, wholeWord, inSelection);
  860.       };
  861.       var next$1 = function () {
  862.         return next(editor, currentState);
  863.       };
  864.       var prev$1 = function () {
  865.         return prev(editor, currentState);
  866.       };
  867.       var replace$1 = function (text, forward, all) {
  868.         return replace(editor, currentState, text, forward, all);
  869.       };
  870.       return {
  871.         done: done$1,
  872.         find: find$1,
  873.         next: next$1,
  874.         prev: prev$1,
  875.         replace: replace$1
  876.       };
  877.     };
  878.  
  879.     var singleton = function (doRevoke) {
  880.       var subject = Cell(Optional.none());
  881.       var revoke = function () {
  882.         return subject.get().each(doRevoke);
  883.       };
  884.       var clear = function () {
  885.         revoke();
  886.         subject.set(Optional.none());
  887.       };
  888.       var isSet = function () {
  889.         return subject.get().isSome();
  890.       };
  891.       var get = function () {
  892.         return subject.get();
  893.       };
  894.       var set = function (s) {
  895.         revoke();
  896.         subject.set(Optional.some(s));
  897.       };
  898.       return {
  899.         clear: clear,
  900.         isSet: isSet,
  901.         get: get,
  902.         set: set
  903.       };
  904.     };
  905.     var value = function () {
  906.       var subject = singleton(noop);
  907.       var on = function (f) {
  908.         return subject.get().each(f);
  909.       };
  910.       return __assign(__assign({}, subject), { on: on });
  911.     };
  912.  
  913.     var open = function (editor, currentSearchState) {
  914.       var dialogApi = value();
  915.       editor.undoManager.add();
  916.       var selectedText = global$1.trim(editor.selection.getContent({ format: 'text' }));
  917.       var updateButtonStates = function (api) {
  918.         var updateNext = hasNext(editor, currentSearchState) ? api.enable : api.disable;
  919.         updateNext('next');
  920.         var updatePrev = hasPrev(editor, currentSearchState) ? api.enable : api.disable;
  921.         updatePrev('prev');
  922.       };
  923.       var updateSearchState = function (api) {
  924.         var data = api.getData();
  925.         var current = currentSearchState.get();
  926.         currentSearchState.set(__assign(__assign({}, current), {
  927.           matchCase: data.matchcase,
  928.           wholeWord: data.wholewords,
  929.           inSelection: data.inselection
  930.         }));
  931.       };
  932.       var disableAll = function (api, disable) {
  933.         var buttons = [
  934.           'replace',
  935.           'replaceall',
  936.           'prev',
  937.           'next'
  938.         ];
  939.         var toggle = disable ? api.disable : api.enable;
  940.         each(buttons, toggle);
  941.       };
  942.       var notFoundAlert = function (api) {
  943.         editor.windowManager.alert('Could not find the specified string.', function () {
  944.           api.focus('findtext');
  945.         });
  946.       };
  947.       var focusButtonIfRequired = function (api, name) {
  948.         if (global$2.browser.isSafari() && global$2.deviceType.isTouch() && (name === 'find' || name === 'replace' || name === 'replaceall')) {
  949.           api.focus(name);
  950.         }
  951.       };
  952.       var reset = function (api) {
  953.         done(editor, currentSearchState, false);
  954.         disableAll(api, true);
  955.         updateButtonStates(api);
  956.       };
  957.       var doFind = function (api) {
  958.         var data = api.getData();
  959.         var last = currentSearchState.get();
  960.         if (!data.findtext.length) {
  961.           reset(api);
  962.           return;
  963.         }
  964.         if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
  965.           next(editor, currentSearchState);
  966.         } else {
  967.           var count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection);
  968.           if (count <= 0) {
  969.             notFoundAlert(api);
  970.           }
  971.           disableAll(api, count === 0);
  972.         }
  973.         updateButtonStates(api);
  974.       };
  975.       var initialState = currentSearchState.get();
  976.       var initialData = {
  977.         findtext: selectedText,
  978.         replacetext: '',
  979.         wholewords: initialState.wholeWord,
  980.         matchcase: initialState.matchCase,
  981.         inselection: initialState.inSelection
  982.       };
  983.       var spec = {
  984.         title: 'Find and Replace',
  985.         size: 'normal',
  986.         body: {
  987.           type: 'panel',
  988.           items: [
  989.             {
  990.               type: 'bar',
  991.               items: [
  992.                 {
  993.                   type: 'input',
  994.                   name: 'findtext',
  995.                   placeholder: 'Find',
  996.                   maximized: true,
  997.                   inputMode: 'search'
  998.                 },
  999.                 {
  1000.                   type: 'button',
  1001.                   name: 'prev',
  1002.                   text: 'Previous',
  1003.                   icon: 'action-prev',
  1004.                   disabled: true,
  1005.                   borderless: true
  1006.                 },
  1007.                 {
  1008.                   type: 'button',
  1009.                   name: 'next',
  1010.                   text: 'Next',
  1011.                   icon: 'action-next',
  1012.                   disabled: true,
  1013.                   borderless: true
  1014.                 }
  1015.               ]
  1016.             },
  1017.             {
  1018.               type: 'input',
  1019.               name: 'replacetext',
  1020.               placeholder: 'Replace with',
  1021.               inputMode: 'search'
  1022.             }
  1023.           ]
  1024.         },
  1025.         buttons: [
  1026.           {
  1027.             type: 'menu',
  1028.             name: 'options',
  1029.             icon: 'preferences',
  1030.             tooltip: 'Preferences',
  1031.             align: 'start',
  1032.             items: [
  1033.               {
  1034.                 type: 'togglemenuitem',
  1035.                 name: 'matchcase',
  1036.                 text: 'Match case'
  1037.               },
  1038.               {
  1039.                 type: 'togglemenuitem',
  1040.                 name: 'wholewords',
  1041.                 text: 'Find whole words only'
  1042.               },
  1043.               {
  1044.                 type: 'togglemenuitem',
  1045.                 name: 'inselection',
  1046.                 text: 'Find in selection'
  1047.               }
  1048.             ]
  1049.           },
  1050.           {
  1051.             type: 'custom',
  1052.             name: 'find',
  1053.             text: 'Find',
  1054.             primary: true
  1055.           },
  1056.           {
  1057.             type: 'custom',
  1058.             name: 'replace',
  1059.             text: 'Replace',
  1060.             disabled: true
  1061.           },
  1062.           {
  1063.             type: 'custom',
  1064.             name: 'replaceall',
  1065.             text: 'Replace all',
  1066.             disabled: true
  1067.           }
  1068.         ],
  1069.         initialData: initialData,
  1070.         onChange: function (api, details) {
  1071.           if (details.name === 'findtext' && currentSearchState.get().count > 0) {
  1072.             reset(api);
  1073.           }
  1074.         },
  1075.         onAction: function (api, details) {
  1076.           var data = api.getData();
  1077.           switch (details.name) {
  1078.           case 'find':
  1079.             doFind(api);
  1080.             break;
  1081.           case 'replace':
  1082.             if (!replace(editor, currentSearchState, data.replacetext)) {
  1083.               reset(api);
  1084.             } else {
  1085.               updateButtonStates(api);
  1086.             }
  1087.             break;
  1088.           case 'replaceall':
  1089.             replace(editor, currentSearchState, data.replacetext, true, true);
  1090.             reset(api);
  1091.             break;
  1092.           case 'prev':
  1093.             prev(editor, currentSearchState);
  1094.             updateButtonStates(api);
  1095.             break;
  1096.           case 'next':
  1097.             next(editor, currentSearchState);
  1098.             updateButtonStates(api);
  1099.             break;
  1100.           case 'matchcase':
  1101.           case 'wholewords':
  1102.           case 'inselection':
  1103.             updateSearchState(api);
  1104.             reset(api);
  1105.             break;
  1106.           }
  1107.           focusButtonIfRequired(api, details.name);
  1108.         },
  1109.         onSubmit: function (api) {
  1110.           doFind(api);
  1111.           focusButtonIfRequired(api, 'find');
  1112.         },
  1113.         onClose: function () {
  1114.           editor.focus();
  1115.           done(editor, currentSearchState);
  1116.           editor.undoManager.add();
  1117.         }
  1118.       };
  1119.       dialogApi.set(editor.windowManager.open(spec, { inline: 'toolbar' }));
  1120.     };
  1121.  
  1122.     var register$1 = function (editor, currentSearchState) {
  1123.       editor.addCommand('SearchReplace', function () {
  1124.         open(editor, currentSearchState);
  1125.       });
  1126.     };
  1127.  
  1128.     var showDialog = function (editor, currentSearchState) {
  1129.       return function () {
  1130.         open(editor, currentSearchState);
  1131.       };
  1132.     };
  1133.     var register = function (editor, currentSearchState) {
  1134.       editor.ui.registry.addMenuItem('searchreplace', {
  1135.         text: 'Find and replace...',
  1136.         shortcut: 'Meta+F',
  1137.         onAction: showDialog(editor, currentSearchState),
  1138.         icon: 'search'
  1139.       });
  1140.       editor.ui.registry.addButton('searchreplace', {
  1141.         tooltip: 'Find and replace',
  1142.         onAction: showDialog(editor, currentSearchState),
  1143.         icon: 'search'
  1144.       });
  1145.       editor.shortcuts.add('Meta+F', '', showDialog(editor, currentSearchState));
  1146.     };
  1147.  
  1148.     function Plugin () {
  1149.       global$3.add('searchreplace', function (editor) {
  1150.         var currentSearchState = Cell({
  1151.           index: -1,
  1152.           count: 0,
  1153.           text: '',
  1154.           matchCase: false,
  1155.           wholeWord: false,
  1156.           inSelection: false
  1157.         });
  1158.         register$1(editor, currentSearchState);
  1159.         register(editor, currentSearchState);
  1160.         return get(editor, currentSearchState);
  1161.       });
  1162.     }
  1163.  
  1164.     Plugin();
  1165.  
  1166. }());
  1167.