text: /**
   * Copyright (c) Tiny Technologies, Inc. All rights reserved.
   * Licensed under the LGPL or a commercial license.
   * For LGPL see License.txt in the project root for license information.
   * For commercial licenses see https://www.tiny.cloud/
   *
   * Version: 5.0.16 (2019-09-24)
   */
  (function (domGlobals) {
      'use strict';
  
      var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
  
      var noop = function () {
      };
      var constant = function (value) {
        return function () {
          return value;
        };
      };
      var never = constant(false);
      var always = constant(true);
  
      var none = function () {
        return NONE;
      };
      var NONE = function () {
        var eq = function (o) {
          return o.isNone();
        };
        var call = function (thunk) {
          return thunk();
        };
        var id = function (n) {
          return n;
        };
        var me = {
          fold: function (n, s) {
            return n();
          },
          is: never,
          isSome: never,
          isNone: always,
          getOr: id,
          getOrThunk: call,
          getOrDie: function (msg) {
            throw new Error(msg || 'error: getOrDie called on none.');
          },
          getOrNull: constant(null),
          getOrUndefined: constant(undefined),
          or: id,
          orThunk: call,
          map: none,
          each: noop,
          bind: none,
          exists: never,
          forall: always,
          filter: none,
          equals: eq,
          equals_: eq,
          toArray: function () {
            return [];
          },
          toString: constant('none()')
        };
        if (Object.freeze) {
          Object.freeze(me);
        }
        return me;
      }();
      var some = function (a) {
        var constant_a = constant(a);
        var self = function () {
          return me;
        };
        var bind = function (f) {
          return f(a);
        };
        var me = {
          fold: function (n, s) {
            return s(a);
          },
          is: function (v) {
            return a === v;
          },
          isSome: always,
          isNone: never,
          getOr: constant_a,
          getOrThunk: constant_a,
          getOrDie: constant_a,
          getOrNull: constant_a,
          getOrUndefined: constant_a,
          or: self,
          orThunk: self,
          map: function (f) {
            return some(f(a));
          },
          each: function (f) {
            f(a);
          },
          bind: bind,
          exists: bind,
          forall: bind,
          filter: function (f) {
            return f(a) ? me : NONE;
          },
          toArray: function () {
            return [a];
          },
          toString: function () {
            return 'some(' + a + ')';
          },
          equals: function (o) {
            return o.is(a);
          },
          equals_: function (o, elementEq) {
            return o.fold(never, function (b) {
              return elementEq(a, b);
            });
          }
        };
        return me;
      };
      var from = function (value) {
        return value === null || value === undefined ? NONE : some(value);
      };
      var Option = {
        some: some,
        none: none,
        from: from
      };
  
      var typeOf = function (x) {
        if (x === null) {
          return 'null';
        }
        var t = typeof x;
        if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
          return 'array';
        }
        if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
          return 'string';
        }
        return t;
      };
      var isType = function (type) {
        return function (value) {
          return typeOf(value) === type;
        };
      };
      var isFunction = isType('function');
  
      var nativeSlice = Array.prototype.slice;
      var exists = function (xs, pred) {
        for (var i = 0, len = xs.length; i < len; i++) {
          var x = xs[i];
          if (pred(x, i)) {
            return true;
          }
        }
        return false;
      };
      var map = function (xs, f) {
        var len = xs.length;
        var r = new Array(len);
        for (var i = 0; i < len; i++) {
          var x = xs[i];
          r[i] = f(x, i);
        }
        return r;
      };
      var from$1 = isFunction(Array.from) ? Array.from : function (x) {
        return nativeSlice.call(x);
      };
  
      var contains = function (str, substr) {
        return str.indexOf(substr) !== -1;
      };
  
      var emojiMatches = function (emoji, lowerCasePattern) {
        return contains(emoji.title.toLowerCase(), lowerCasePattern) || exists(emoji.keywords, function (k) {
          return contains(k.toLowerCase(), lowerCasePattern);
        });
      };
      var emojisFrom = function (list, pattern, maxResults) {
        var matches = [];
        var lowerCasePattern = pattern.toLowerCase();
        var reachedLimit = maxResults.fold(function () {
          return never;
        }, function (max) {
          return function (size) {
            return size >= max;
          };
        });
        for (var i = 0; i < list.length; i++) {
          if (pattern.length === 0 || emojiMatches(list[i], lowerCasePattern)) {
            matches.push({
              value: list[i].char,
              text: list[i].title,
              icon: list[i].char
            });
            if (reachedLimit(matches.length)) {
              break;
            }
          }
        }
        return matches;
      };
  
      var init = function (editor, database) {
        editor.ui.registry.addAutocompleter('emoticons', {
          ch: ':',
          columns: 'auto',
          minChars: 2,
          fetch: function (pattern, maxResults) {
            return database.waitForLoad().then(function () {
              var candidates = database.listAll();
              return emojisFrom(candidates, pattern, Option.some(maxResults));
            });
          },
          onAction: function (autocompleteApi, rng, value) {
            editor.selection.setRng(rng);
            editor.insertContent(value);
            autocompleteApi.hide();
          }
        });
      };
  
      var Cell = function (initial) {
        var value = initial;
        var get = function () {
          return value;
        };
        var set = function (v) {
          value = v;
        };
        var clone = function () {
          return Cell(get());
        };
        return {
          get: get,
          set: set,
          clone: clone
        };
      };
  
      var last = function (fn, rate) {
        var timer = null;
        var cancel = function () {
          if (timer !== null) {
            domGlobals.clearTimeout(timer);
            timer = null;
          }
        };
        var throttle = function () {
          var args = [];
          for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
          }
          if (timer !== null) {
            domGlobals.clearTimeout(timer);
          }
          timer = domGlobals.setTimeout(function () {
            fn.apply(null, args);
            timer = null;
          }, rate);
        };
        return {
          cancel: cancel,
          throttle: throttle
        };
      };
  
      var insertEmoticon = function (editor, ch) {
        editor.insertContent(ch);
      };
  
      var hasOwnProperty = Object.prototype.hasOwnProperty;
      var shallow = function (old, nu) {
        return nu;
      };
      var baseMerge = function (merger) {
        return function () {
          var objects = new Array(arguments.length);
          for (var i = 0; i < objects.length; i++) {
            objects[i] = arguments[i];
          }
          if (objects.length === 0) {
            throw new Error('Can\'t merge zero objects');
          }
          var ret = {};
          for (var j = 0; j < objects.length; j++) {
            var curObject = objects[j];
            for (var key in curObject) {
              if (hasOwnProperty.call(curObject, key)) {
                ret[key] = merger(ret[key], curObject[key]);
              }
            }
          }
          return ret;
        };
      };
      var merge = baseMerge(shallow);
  
      var keys = Object.keys;
      var hasOwnProperty$1 = Object.hasOwnProperty;
      var each = function (obj, f) {
        var props = keys(obj);
        for (var k = 0, len = props.length; k < len; k++) {
          var i = props[k];
          var x = obj[i];
          f(x, i);
        }
      };
      var map$1 = function (obj, f) {
        return tupleMap(obj, function (x, i) {
          return {
            k: i,
            v: f(x, i)
          };
        });
      };
      var tupleMap = function (obj, f) {
        var r = {};
        each(obj, function (x, i) {
          var tuple = f(x, i);
          r[tuple.k] = tuple.v;
        });
        return r;
      };
      var has = function (obj, key) {
        return hasOwnProperty$1.call(obj, key);
      };
  
      var global$1 = tinymce.util.Tools.resolve('tinymce.Resource');
  
      var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  
      var global$3 = tinymce.util.Tools.resolve('tinymce.util.Promise');
  
      var DEFAULT_ID = 'tinymce.plugins.emoticons';
      var getEmoticonDatabaseUrl = function (editor, pluginUrl) {
        return editor.getParam('emoticons_database_url', pluginUrl + '/js/emojis' + editor.suffix + '.js');
      };
      var getEmoticonDatabaseId = function (editor) {
        return editor.getParam('emoticons_database_id', DEFAULT_ID, 'string');
      };
      var getAppendedEmoticons = function (editor) {
        return editor.getParam('emoticons_append', {}, 'object');
      };
      var Settings = {
        getEmoticonDatabaseUrl: getEmoticonDatabaseUrl,
        getEmoticonDatabaseId: getEmoticonDatabaseId,
        getAppendedEmoticons: getAppendedEmoticons
      };
  
      var ALL_CATEGORY = 'All';
      var categoryNameMap = {
        symbols: 'Symbols',
        people: 'People',
        animals_and_nature: 'Animals and Nature',
        food_and_drink: 'Food and Drink',
        activity: 'Activity',
        travel_and_places: 'Travel and Places',
        objects: 'Objects',
        flags: 'Flags',
        user: 'User Defined'
      };
      var translateCategory = function (categories, name) {
        return has(categories, name) ? categories[name] : name;
      };
      var getUserDefinedEmoticons = function (editor) {
        var userDefinedEmoticons = Settings.getAppendedEmoticons(editor);
        return map$1(userDefinedEmoticons, function (value) {
          return merge({
            keywords: [],
            category: 'user'
          }, value);
        });
      };
      var initDatabase = function (editor, databaseUrl, databaseId) {
        var categories = Cell(Option.none());
        var all = Cell(Option.none());
        var processEmojis = function (emojis) {
          var cats = {};
          var everything = [];
          each(emojis, function (lib, title) {
            var entry = {
              title: title,
              keywords: lib.keywords,
              char: lib.char,
              category: translateCategory(categoryNameMap, lib.category)
            };
            var current = cats[entry.category] !== undefined ? cats[entry.category] : [];
            cats[entry.category] = current.concat([entry]);
            everything.push(entry);
          });
          categories.set(Option.some(cats));
          all.set(Option.some(everything));
        };
        editor.on('init', function () {
          global$1.load(databaseId, databaseUrl).then(function (emojis) {
            var userEmojis = getUserDefinedEmoticons(editor);
            processEmojis(merge(emojis, userEmojis));
          }, function (err) {
            domGlobals.console.log('Failed to load emoticons: ' + err);
            categories.set(Option.some({}));
            all.set(Option.some([]));
          });
        });
        var listCategory = function (category) {
          if (category === ALL_CATEGORY) {
            return listAll();
          }
          return categories.get().bind(function (cats) {
            return Option.from(cats[category]);
          }).getOr([]);
        };
        var listAll = function () {
          return all.get().getOr([]);
        };
        var listCategories = function () {
          return [ALL_CATEGORY].concat(keys(categories.get().getOr({})));
        };
        var waitForLoad = function () {
          if (hasLoaded()) {
            return global$3.resolve(true);
          } else {
            return new global$3(function (resolve, reject) {
              var numRetries = 15;
              var interval = global$2.setInterval(function () {
                if (hasLoaded()) {
                  global$2.clearInterval(interval);
                  resolve(true);
                } else {
                  numRetries--;
                  if (numRetries < 0) {
                    domGlobals.console.log('Could not load emojis from url: ' + databaseUrl);
                    global$2.clearInterval(interval);
                    reject(false);
                  }
                }
              }, 100);
            });
          }
        };
        var hasLoaded = function () {
          return categories.get().isSome() && all.get().isSome();
        };
        return {
          listCategories: listCategories,
          hasLoaded: hasLoaded,
          waitForLoad: waitForLoad,
          listAll: listAll,
          listCategory: listCategory
        };
      };
  
      var patternName = 'pattern';
      var open = function (editor, database) {
        var initialState = {
          pattern: '',
          results: emojisFrom(database.listAll(), '', Option.some(300))
        };
        var currentTab = Cell(ALL_CATEGORY);
        var scan = function (dialogApi) {
          var dialogData = dialogApi.getData();
          var category = currentTab.get();
          var candidates = database.listCategory(category);
          var results = emojisFrom(candidates, dialogData[patternName], category === ALL_CATEGORY ? Option.some(300) : Option.none());
          dialogApi.setData({ results: results });
        };
        var updateFilter = last(function (dialogApi) {
          scan(dialogApi);
        }, 200);
        var searchField = {
          label: 'Search',
          type: 'input',
          name: patternName
        };
        var resultsField = {
          type: 'collection',
          name: 'results'
        };
        var getInitialState = function () {
          var body = {
            type: 'tabpanel',
            tabs: map(database.listCategories(), function (cat) {
              return {
                title: cat,
                name: cat,
                items: [
                  searchField,
                  resultsField
                ]
              };
            })
          };
          return {
            title: 'Emoticons',
            size: 'normal',
            body: body,
            initialData: initialState,
            onTabChange: function (dialogApi, details) {
              currentTab.set(details.newTabName);
              updateFilter.throttle(dialogApi);
            },
            onChange: updateFilter.throttle,
            onAction: function (dialogApi, actionData) {
              if (actionData.name === 'results') {
                insertEmoticon(editor, actionData.value);
                dialogApi.close();
              }
            },
            buttons: [{
                type: 'cancel',
                text: 'Close',
                primary: true
              }]
          };
        };
        var dialogApi = editor.windowManager.open(getInitialState());
        dialogApi.focus(patternName);
        if (!database.hasLoaded()) {
          dialogApi.block('Loading emoticons...');
          database.waitForLoad().then(function () {
            dialogApi.redial(getInitialState());
            updateFilter.throttle(dialogApi);
            dialogApi.focus(patternName);
            dialogApi.unblock();
          }).catch(function (err) {
            dialogApi.redial({
              title: 'Emoticons',
              body: {
                type: 'panel',
                items: [{
                    type: 'alertbanner',
                    level: 'error',
                    icon: 'warning',
                    text: '<p>Could not load emoticons</p>'
                  }]
              },
              buttons: [{
                  type: 'cancel',
                  text: 'Close',
                  primary: true
                }],
              initialData: {
                pattern: '',
                results: []
              }
            });
            dialogApi.focus(patternName);
            dialogApi.unblock();
          });
        }
      };
      var Dialog = { open: open };
  
      var register = function (editor, database) {
        var onAction = function () {
          return Dialog.open(editor, database);
        };
        editor.ui.registry.addButton('emoticons', {
          tooltip: 'Emoticons',
          icon: 'emoji',
          onAction: onAction
        });
        editor.ui.registry.addMenuItem('emoticons', {
          text: 'Emoticons...',
          icon: 'emoji',
          onAction: onAction
        });
      };
      var Buttons = { register: register };
  
      function Plugin () {
        global.add('emoticons', function (editor, pluginUrl) {
          var databaseUrl = Settings.getEmoticonDatabaseUrl(editor, pluginUrl);
          var databaseId = Settings.getEmoticonDatabaseId(editor);
          var database = initDatabase(editor, databaseUrl, databaseId);
          Buttons.register(editor, database);
          init(editor, database);
        });
      }
  
      Plugin();
  
  }(window));
  