PageSourceSearch

https://www.homeschoolinginidaho.com/lib/summernote/summernote-bs4.js

js homeschoolinginidaho.com collected 2026-10-04 14:06:40 UTC 309,282 bytes, 7,768 lines download raw bytes

1/**
2 * Super simple wysiwyg editor v0.8.12
3 * https://summernote.org
4 *
5 * Copyright 2013- Alan Hong. and other contributors
6 * summernote may be freely distributed under the MIT license.
7 *
8 * Date: 2019-05-16T08:16Z
9 */
10(function (global, factory) {
11  typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
12  typeof define === 'function' && define.amd ? define(['jquery'], factory) :
13  (global = global || self, factory(global.jQuery));
14}(this, function ($$1) { 'use strict';
15
16  $$1 = $$1 && $$1.hasOwnProperty('default') ? $$1['default'] : $$1;
17
18  var Renderer = /** @class */ (function () {
19      function Renderer(markup, children, options, callback) {
20          this.markup = markup;
21          this.children = children;
22          this.options = options;
23          this.callback = callback;
24      }
25      Renderer.prototype.render = function ($parent) {
26          var $node = $$1(this.markup);
27          if (this.options && this.options.contents) {
28              $node.html(this.options.contents);
29          }
30          if (this.options && this.options.className) {
31              $node.addClass(this.options.className);
32          }
33          if (this.options && this.options.data) {
34              $$1.each(this.options.data, function (k, v) {
35                  $node.attr('data-' + k, v);
36              });
37          }
38          if (this.options && this.options.click) {
39              $node.on('click', this.options.click);
40          }
41          if (this.children) {
42              var $container_1 = $node.find('.note-children-container');
43              this.children.forEach(function (child) {
44                  child.render($container_1.length ? $container_1 : $node);
45              });
46          }
47          if (this.callback) {
48              this.callback($node, this.options);
49          }
50          if (this.options && this.options.callback) {
51              this.options.callback($node);
52          }
53          if ($parent) {
54              $parent.append($node);
55          }
56          return $node;
57      };
58      return Renderer;
59  }());
60  var renderer = {
61      create: function (markup, callback) {
62          return function () {
63              var options = typeof arguments[1] === 'object' ? arguments[1] : arguments[0];
64              var children = Array.isArray(arguments[0]) ? arguments[0] : [];
65              if (options && options.children) {
66                  children = options.children;
67              }
68              return new Renderer(markup, children, options, callback);
69          };
70      }
71  };
72
73  var editor = renderer.create('<div class="note-editor note-frame card"/>');
74  var toolbar = renderer.create('<div class="note-toolbar card-header" role="toolbar"></div>');
75  var editingArea = renderer.create('<div class="note-editing-area"/>');
76  var codable = renderer.create('<textarea class="note-codable" role="textbox" aria-multiline="true"/>');
77  var editable = renderer.create('<div class="note-editable card-block" contentEditable="true" role="textbox" aria-multiline="true"/>');
78  var statusbar = renderer.create([
79      '<output class="note-status-output" aria-live="polite"/>',
80      '<div class="note-statusbar" role="status">',
81      '  <output class="note-status-output" aria-live="polite"></output>',
82      '  <div class="note-resizebar" role="seperator" aria-orientation="horizontal" aria-label="Resize">',
83      '    <div class="note-icon-bar"/>',
84      '    <div class="note-icon-bar"/>',
85      '    <div class="note-icon-bar"/>',
86      '  </div>',
87      '</div>',
88  ].join(''));
89  var airEditor = renderer.create('<div class="note-editor"/>');
90  var airEditable = renderer.create([
91      '<div class="note-editable" contentEditable="true" role="textbox" aria-multiline="true"/>',
92      '<output class="note-status-output" aria-live="polite"/>',
93  ].join(''));
94  var buttonGroup = renderer.create('<div class="note-btn-group btn-group">');
95  var dropdown = renderer.create('<div class="dropdown-menu" role="list">', function ($node, options) {
96      var markup = Array.isArray(options.items) ? options.items.map(function (item) {
97          var value = (typeof item === 'string') ? item : (item.value || '');
98          var content = options.template ? options.template(item) : item;
99          var option = (typeof item === 'object') ? item.option : undefined;
100          var dataValue = 'data-value="' + value + '"';
101          var dataOption = (option !== undefined) ? ' data-option="' + option + '"' : '';
102          return '<a class="dropdown-item" href="#" ' + (dataValue + dataOption) + ' role="listitem" aria-label="' + value + '">' + content + '</a>';
103      }).join('') : options.items;
104      $node.html(markup).attr({ 'aria-label': options.title });
105  });
106  var dropdownButtonContents = function (contents) {
107      return contents;
108  };
109  var dropdownCheck = renderer.create('<div class="dropdown-menu note-check" role="list">', function ($node, options) {
110      var markup = Array.isArray(options.items) ? options.items.map(function (item) {
111          var value = (typeof item === 'string') ? item : (item.value || '');
112          var content = options.template ? options.template(item) : item;
113          return '<a class="dropdown-item" href="#" data-value="' + value + '" role="listitem" aria-label="' + item + '">' + icon(options.checkClassName) + ' ' + content + '</a>';
114      }).join('') : options.items;
115      $node.html(markup).attr({ 'aria-label': options.title });
116  });
117  var palette = renderer.create('<div class="note-color-palette"/>', function ($node, options) {
118      var contents = [];
119      for (var row = 0, rowSize = options.colors.length; row < rowSize; row++) {
120          var eventName = options.eventName;
121          var colors = options.colors[row];
122          var colorsName = options.colorsName[row];
123          var buttons = [];
124          for (var col = 0, colSize = colors.length; col < colSize; col++) {
125              var color = colors[col];
126              var colorName = colorsName[col];
127              buttons.push([
128                  '<button type="button" class="note-color-btn"',
129                  'style="background-color:', color, '" ',
130                  'data-event="', eventName, '" ',
131                  'data-value="', color, '" ',
132                  'title="', colorName, '" ',
133                  'aria-label="', colorName, '" ',
134                  'data-toggle="button" tabindex="-1"></button>',
135              ].join(''));
136          }
137          contents.push('<div class="note-color-row">' + buttons.join('') + '</div>');
138      }
139      $node.html(contents.join(''));
140      if (options.tooltip) {
141          $node.find('.note-color-btn').tooltip({
142              container: options.container,
143              trigger: 'hover',
144              placement: 'bottom'
145          });
146      }
147  });
148  var dialog = renderer.create('<div class="modal" aria-hidden="false" tabindex="-1" role="dialog"/>', function ($node, options) {
149      if (options.fade) {
150          $node.addClass('fade');
151      }
152      $node.attr({
153          'aria-label': options.title
154      });
155      $node.html([
156          '<div class="modal-dialog">',
157          '  <div class="modal-content">',
158          (options.title
159              ? '    <div class="modal-header">' +
160                  '      <h4 class="modal-title">' + options.title + '</h4>' +
161                  '      <button type="button" class="close" data-dismiss="modal" aria-label="Close" aria-hidden="true">&times;</button>' +
162                  '    </div>' : ''),
163          '    <div class="modal-body">' + options.body + '</div>',
164          (options.footer
165              ? '    <div class="modal-footer">' + options.footer + '</div>' : ''),
166          '  </div>',
167          '</div>',
168      ].join(''));
169  });
170  var popover = renderer.create([
171      '<div class="note-popover popover in">',
172      '  <div class="arrow"/>',
173      '  <div class="popover-content note-children-container"/>',
174      '</div>',
175  ].join(''), function ($node, options) {
176      var direction = typeof options.direction !== 'undefined' ? options.direction : 'bottom';
177      $node.addClass(direction);
178      if (options.hideArrow) {
179          $node.find('.arrow').hide();
180      }
181  });
182  var checkbox = renderer.create('<div class="form-check"></div>', function ($node, options) {
183      $node.html([
184          '<label class="form-check-label"' + (options.id ? ' for="' + options.id + '"' : '') + '>',
185          ' <input role="checkbox" type="checkbox" class="form-check-input"' + (options.id ? ' id="' + options.id + '"' : ''),
186          (options.checked ? ' checked' : ''),
187          ' aria-label="' + (options.text ? options.text : '') + '"',
188          ' aria-checked="' + (options.checked ? 'true' : 'false') + '"/>',
189          ' ' + (options.text ? options.text : '') + '</label>',
190      ].join(''));
191  });
192  var icon = function (iconClassName, tagName) {
193      tagName = tagName || 'i';
194      return '<' + tagName + ' class="' + iconClassName + '"/>';
195  };
196  var ui = {
197      editor: editor,
198      toolbar: toolbar,
199      editingArea: editingArea,
200      codable: codable,
201      editable: editable,
202      statusbar: statusbar,
203      airEditor: airEditor,
204      airEditable: airEditable,
205      buttonGroup: buttonGroup,
206      dropdown: dropdown,
207      dropdownButtonContents: dropdownButtonContents,
208      dropdownCheck: dropdownCheck,
209      palette: palette,
210      dialog: dialog,
211      popover: popover,
212      icon: icon,
213      checkbox: checkbox,
214      options: {},
215      button: function ($node, options) {
216          return renderer.create('<button type="button" class="note-btn btn btn-light btn-sm" role="button" tabindex="-1">', function ($node, options) {
217              if (options && options.tooltip) {
218                  $node.attr({
219                      title: options.tooltip,
220                      'aria-label': options.tooltip
221                  }).tooltip({
222                      container: (options.container !== undefined) ? options.container : 'body',
223                      trigger: 'hover',
224                      placement: 'bottom'
225                  }).on('click', function (e) {
226                      $$1(e.currentTarget).tooltip('hide');
227                  });
228              }
229          })($node, options);
230      },
231      toggleBtn: function ($btn, isEnable) {
232          $btn.toggleClass('disabled', !isEnable);
233          $btn.attr('disabled', !isEnable);
234      },
235      toggleBtnActive: function ($btn, isActive) {
236          $btn.toggleClass('active', isActive);
237      },
238      onDialogShown: function ($dialog, handler) {
239          $dialog.one('shown.bs.modal', handler);
240      },
241      onDialogHidden: function ($dialog, handler) {
242          $dialog.one('hidden.bs.modal', handler);
243      },
244      showDialog: function ($dialog) {
245          $dialog.modal('show');
246      },
247      hideDialog: function ($dialog) {
248          $dialog.modal('hide');
249      },
250      createLayout: function ($note, options) {
251          var $editor = (options.airMode ? ui.airEditor([
252              ui.editingArea([
253                  ui.airEditable(),
254              ]),
255          ]) : ui.editor([
256              ui.toolbar(),
257              ui.editingArea([
258                  ui.codable(),
259                  ui.editable(),
260              ]),
261              ui.statusbar(),
262          ])).render();
263          $editor.insertAfter($note);
264          return {
265              note: $note,
266              editor: $editor,
267              toolbar: $editor.find('.note-toolbar'),
268              editingArea: $editor.find('.note-editing-area'),
269              editable: $editor.find('.note-editable'),
270              codable: $editor.find('.note-codable'),
271              statusbar: $editor.find('.note-statusbar')
272          };
273      },
274      removeLayout: function ($note, layoutInfo) {
275          $note.html(layoutInfo.editable.html());
276          layoutInfo.editor.remove();
277          $note.show();
278      }
279  };
280
281  $$1.summernote = $$1.summernote || {
282      lang: {}
283  };
284  $$1.extend($$1.summernote.lang, {
285      'en-US': {
286          font: {
287              bold: 'Bold',
288              italic: 'Italic',
289              underline: 'Underline',
290              clear: 'Remove Font Style',
291              height: 'Line Height',
292              name: 'Font Family',
293              strikethrough: 'Strikethrough',
294              subscript: 'Subscript',
295              superscript: 'Superscript',
296              size: 'Font Size'
297          },
298          image: {
299              image: 'Picture',
300              insert: 'Insert Image',
301              resizeFull: 'Resize full',
302              resizeHalf: 'Resize half',
303              resizeQuarter: 'Resize quarter',
304              resizeNone: 'Original size',
305              floatLeft: 'Float Left',
306              floatRight: 'Float Right',
307              floatNone: 'Remove float',
308              shapeRounded: 'Shape: Rounded',
309              shapeCircle: 'Shape: Circle',
310              shapeThumbnail: 'Shape: Thumbnail',
311              shapeNone: 'Shape: None',
312              dragImageHere: 'Drag image or text here',
313              dropImage: 'Drop image or Text',
314              selectFromFiles: 'Select from files',
315              maximumFileSize: 'Maximum file size',
316              maximumFileSizeError: 'Maximum file size exceeded.',
317              url: 'Image URL',
318              remove: 'Remove Image',
319              original: 'Original'
320          },
321          video: {
322              video: 'Video',
323              videoLink: 'Video Link',
324              insert: 'Insert Video',
325              url: 'Video URL',
326              providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)'
327          },
328          link: {
329              link: 'Link',
330              insert: 'Insert Link',
331              unlink: 'Unlink',
332              edit: 'Edit',
333              textToDisplay: 'Text to display',
334              url: 'To what URL should this link go?',
335              openInNewWindow: 'Open in new window'
336          },
337          table: {
338              table: 'Table',
339              addRowAbove: 'Add row above',
340              addRowBelow: 'Add row below',
341              addColLeft: 'Add column left',
342              addColRight: 'Add column right',
343              delRow: 'Delete row',
344              delCol: 'Delete column',
345              delTable: 'Delete table'
346          },
347          hr: {
348              insert: 'Insert Horizontal Rule'
349          },
350          style: {
351              style: 'Style',
352              p: 'Normal',
353              blockquote: 'Quote',
354              pre: 'Code',
355              h1: 'Header 1',
356              h2: 'Header 2',
357              h3: 'Header 3',
358              h4: 'Header 4',
359              h5: 'Header 5',
360              h6: 'Header 6'
361          },
362          lists: {
363              unordered: 'Unordered list',
364              ordered: 'Ordered list'
365          },
366          options: {
367              help: 'Help',
368              fullscreen: 'Full Screen',
369              codeview: 'Code View'
370          },
371          paragraph: {
372              paragraph: 'Paragraph',
373              outdent: 'Outdent',
374              indent: 'Indent',
375              left: 'Align left',
376              center: 'Align center',
377              right: 'Align right',
378              justify: 'Justify full'
379          },
380          color: {
381              recent: 'Recent Color',
382              more: 'More Color',
383              background: 'Background Color',
384              foreground: 'Foreground Color',
385              transparent: 'Transparent',
386              setTransparent: 'Set transparent',
387              reset: 'Reset',
388              resetToDefault: 'Reset to default',
389              cpSelect: 'Select'
390          },
391          shortcut: {
392              shortcuts: 'Keyboard shortcuts',
393              close: 'Close',
394              textFormatting: 'Text formatting',
395              action: 'Action',
396              paragraphFormatting: 'Paragraph formatting',
397              documentStyle: 'Document Style',
398              extraKeys: 'Extra keys'
399          },
400          help: {
401              'insertParagraph': 'Insert Paragraph',
402              'undo': 'Undoes the last command',
403              'redo': 'Redoes the last command',
404              'tab': 'Tab',
405              'untab': 'Untab',
406              'bold': 'Set a bold style',
407              'italic': 'Set a italic style',
408              'underline': 'Set a underline style',
409              'strikethrough': 'Set a strikethrough style',
410              'removeFormat': 'Clean a style',
411              'justifyLeft': 'Set left align',
412              'justifyCenter': 'Set center align',
413              'justifyRight': 'Set right align',
414              'justifyFull': 'Set full align',
415              'insertUnorderedList': 'Toggle unordered list',
416              'insertOrderedList': 'Toggle ordered list',
417              'outdent': 'Outdent on current paragraph',
418              'indent': 'Indent on current paragraph',
419              'formatPara': 'Change current block\'s format as a paragraph(P tag)',
420              'formatH1': 'Change current block\'s format as H1',
421              'formatH2': 'Change current block\'s format as H2',
422              'formatH3': 'Change current block\'s format as H3',
423              'formatH4': 'Change current block\'s format as H4',
424              'formatH5': 'Change current block\'s format as H5',
425              'formatH6': 'Change current block\'s format as H6',
426              'insertHorizontalRule': 'Insert horizontal rule',
427              'linkDialog.show': 'Show Link Dialog'
428          },
429          history: {
430              undo: 'Undo',
431              redo: 'Redo'
432          },
433          specialChar: {
434              specialChar: 'SPECIAL CHARACTERS',
435              select: 'Select Special characters'
436          }
437      }
438  });
439
440  var isSupportAmd = typeof define === 'function' && define.amd; // eslint-disable-line
441  /**
442   * returns whether font is installed or not.
443   *
444   * @param {String} fontName
445   * @return {Boolean}
446   */
447  function isFontInstalled(fontName) {
448      var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
449      var testText = 'mmmmmmmmmmwwwww';
450      var testSize = '200px';
451      var canvas = document.createElement('canvas');
452      var context = canvas.getContext('2d');
453      context.font = testSize + " '" + testFontName + "'";
454      var originalWidth = context.measureText(testText).width;
455      context.font = testSize + " '" + fontName + "', '" + testFontName + "'";
456      var width = context.measureText(testText).width;
457      return originalWidth !== width;
458  }
459  var userAgent = navigator.userAgent;
460  var isMSIE = /MSIE|Trident/i.test(userAgent);
461  var browserVersion;
462  if (isMSIE) {
463      var matches = /MSIE (\d+[.]\d+)/.exec(userAgent);
464      if (matches) {
465          browserVersion = parseFloat(matches[1]);
466      }
467      matches = /Trident\/.*rv:([0-9]{1,}[.0-9]{0,})/.exec(userAgent);
468      if (matches) {
469          browserVersion = parseFloat(matches[1]);
470      }
471  }
472  var isEdge = /Edge\/\d+/.test(userAgent);
473  var hasCodeMirror = !!window.CodeMirror;
474  var isSupportTouch = (('ontouchstart' in window) ||
475      (navigator.MaxTouchPoints > 0) ||
476      (navigator.msMaxTouchPoints > 0));
477  // [workaround] IE doesn't have input events for contentEditable
478  // - see: https://goo.gl/4bfIvA
479  var inputEventName = (isMSIE || isEdge) ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';
480  /**
481   * @class core.env
482   *
483   * Object which check platform and agent
484   *
485   * @singleton
486   * @alternateClassName env
487   */
488  var env = {
489      isMac: navigator.appVersion.indexOf('Mac') > -1,
490      isMSIE: isMSIE,
491      isEdge: isEdge,
492      isFF: !isEdge && /firefox/i.test(userAgent),
493      isPhantom: /PhantomJS/i.test(userAgent),
494      isWebkit: !isEdge && /webkit/i.test(userAgent),
495      isChrome: !isEdge && /chrome/i.test(userAgent),
496      isSafari: !isEdge && /safari/i.test(userAgent),
497      browserVersion: browserVersion,
498      jqueryVersion: parseFloat($$1.fn.jquery),
499      isSupportAmd: isSupportAmd,
500      isSupportTouch: isSupportTouch,
501      hasCodeMirror: hasCodeMirror,
502      isFontInstalled: isFontInstalled,
503      isW3CRangeSupport: !!document.createRange,
504      inputEventName: inputEventName
505  };
506
507  /**
508   * @class core.func
509   *
510   * func utils (for high-order func's arg)
511   *
512   * @singleton
513   * @alternateClassName func
514   */
515  function eq(itemA) {
516      return function (itemB) {
517          return itemA === itemB;
518      };
519  }
520  function eq2(itemA, itemB) {
521      return itemA === itemB;
522  }
523  function peq2(propName) {
524      return function (itemA, itemB) {
525          return itemA[propName] === itemB[propName];
526      };
527  }
528  function ok() {
529      return true;
530  }
531  function fail() {
532      return false;
533  }
534  function not(f) {
535      return function () {
536          return !f.apply(f, arguments);
537      };
538  }
539  function and(fA, fB) {
540      return function (item) {
541          return fA(item) && fB(item);
542      };
543  }
544  function self(a) {
545      return a;
546  }
547  function invoke(obj, method) {
548      return function () {
549          return obj[method].apply(obj, arguments);
550      };
551  }
552  var idCounter = 0;
553  /**
554   * generate a globally-unique id
555   *
556   * @param {String} [prefix]
557   */
558  function uniqueId(prefix) {
559      var id = ++idCounter + '';
560      return prefix ? prefix + id : id;
561  }
562  /**
563   * returns bnd (bounds) from rect
564   *
565   * - IE Compatibility Issue: http://goo.gl/sRLOAo
566   * - Scroll Issue: http://goo.gl/sNjUc
567   *
568   * @param {Rect} rect
569   * @return {Object} bounds
570   * @return {Number} bounds.top
571   * @return {Number} bounds.left
572   * @return {Number} bounds.width
573   * @return {Number} bounds.height
574   */
575  function rect2bnd(rect) {
576      var $document = $(document);
577      return {
578          top: rect.top + $document.scrollTop(),
579          left: rect.left + $document.scrollLeft(),
580          width: rect.right - rect.left,
581          height: rect.bottom - rect.top
582      };
583  }
584  /**
585   * returns a copy of the object where the keys have become the values and the values the keys.
586   * @param {Object} obj
587   * @return {Object}
588   */
589  function invertObject(obj) {
590      var inverted = {};
591      for (var key in obj) {
592          if (obj.hasOwnProperty(key)) {
593              inverted[obj[key]] = key;
594          }
595      }
596      return inverted;
597  }
598  /**
599   * @param {String} namespace
600   * @param {String} [prefix]
601   * @return {String}
602   */
603  function namespaceToCamel(namespace, prefix) {
604      prefix = prefix || '';
605      return prefix + namespace.split('.').map(function (name) {
606          return name.substring(0, 1).toUpperCase() + name.substring(1);
607      }).join('');
608  }
609  /**
610   * Returns a function, that, as long as it continues to be invoked, will not
611   * be triggered. The function will be called after it stops being called for
612   * N milliseconds. If `immediate` is passed, trigger the function on the
613   * leading edge, instead of the trailing.
614   * @param {Function} func
615   * @param {Number} wait
616   * @param {Boolean} immediate
617   * @return {Function}
618   */
619  function debounce(func, wait, immediate) {
620      var timeout;
621      return function () {
622          var context = this;
623          var args = arguments;
624          var later = function () {
625              timeout = null;
626              if (!immediate) {
vendor: 20,277 bytes, lines 627-1403
627                  func.apply(context, args);
628              }
629          };
630          var callNow = immediate && !timeout;
631          clearTimeout(timeout);
632          timeout = setTimeout(later, wait);
633          if (callNow) {
634              func.apply(context, args);
635          }
636      };
637  }
638  /**
639   *
640   * @param {String} url
641   * @return {Boolean}
642   */
643  function isValidUrl(url) {
644      var expression = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi;
645      return expression.test(url);
646  }
647  var func = {
648      eq: eq,
649      eq2: eq2,
650      peq2: peq2,
651      ok: ok,
652      fail: fail,
653      self: self,
654      not: not,
655      and: and,
656      invoke: invoke,
657      uniqueId: uniqueId,
658      rect2bnd: rect2bnd,
659      invertObject: invertObject,
660      namespaceToCamel: namespaceToCamel,
661      debounce: debounce,
662      isValidUrl: isValidUrl
663  };
664
665  /**
666   * returns the first item of an array.
667   *
668   * @param {Array} array
669   */
670  function head(array) {
671      return array[0];
672  }
673  /**
674   * returns the last item of an array.
675   *
676   * @param {Array} array
677   */
678  function last(array) {
679      return array[array.length - 1];
680  }
681  /**
682   * returns everything but the last entry of the array.
683   *
684   * @param {Array} array
685   */
686  function initial(array) {
687      return array.slice(0, array.length - 1);
688  }
689  /**
690   * returns the rest of the items in an array.
691   *
692   * @param {Array} array
693   */
694  function tail(array) {
695      return array.slice(1);
696  }
697  /**
698   * returns item of array
699   */
700  function find(array, pred) {
701      for (var idx = 0, len = array.length; idx < len; idx++) {
702          var item = array[idx];
703          if (pred(item)) {
704              return item;
705          }
706      }
707  }
708  /**
709   * returns true if all of the values in the array pass the predicate truth test.
710   */
711  function all(array, pred) {
712      for (var idx = 0, len = array.length; idx < len; idx++) {
713          if (!pred(array[idx])) {
714              return false;
715          }
716      }
717      return true;
718  }
719  /**
720   * returns true if the value is present in the list.
721   */
722  function contains(array, item) {
723      if (array && array.length && item) {
724          return array.indexOf(item) !== -1;
725      }
726      return false;
727  }
728  /**
729   * get sum from a list
730   *
731   * @param {Array} array - array
732   * @param {Function} fn - iterator
733   */
734  function sum(array, fn) {
735      fn = fn || func.self;
736      return array.reduce(function (memo, v) {
737          return memo + fn(v);
738      }, 0);
739  }
740  /**
741   * returns a copy of the collection with array type.
742   * @param {Collection} collection - collection eg) node.childNodes, ...
743   */
744  function from(collection) {
745      var result = [];
746      var length = collection.length;
747      var idx = -1;
748      while (++idx < length) {
749          result[idx] = collection[idx];
750      }
751      return result;
752  }
753  /**
754   * returns whether list is empty or not
755   */
756  function isEmpty(array) {
757      return !array || !array.length;
758  }
759  /**
760   * cluster elements by predicate function.
761   *
762   * @param {Array} array - array
763   * @param {Function} fn - predicate function for cluster rule
764   * @param {Array[]}
765   */
766  function clusterBy(array, fn) {
767      if (!array.length) {
768          return [];
769      }
770      var aTail = tail(array);
771      return aTail.reduce(function (memo, v) {
772          var aLast = last(memo);
773          if (fn(last(aLast), v)) {
774              aLast[aLast.length] = v;
775          }
776          else {
777              memo[memo.length] = [v];
778          }
779          return memo;
780      }, [[head(array)]]);
781  }
782  /**
783   * returns a copy of the array with all false values removed
784   *
785   * @param {Array} array - array
786   * @param {Function} fn - predicate function for cluster rule
787   */
788  function compact(array) {
789      var aResult = [];
790      for (var idx = 0, len = array.length; idx < len; idx++) {
791          if (array[idx]) {
792              aResult.push(array[idx]);
793          }
794      }
795      return aResult;
796  }
797  /**
798   * produces a duplicate-free version of the array
799   *
800   * @param {Array} array
801   */
802  function unique(array) {
803      var results = [];
804      for (var idx = 0, len = array.length; idx < len; idx++) {
805          if (!contains(results, array[idx])) {
806              results.push(array[idx]);
807          }
808      }
809      return results;
810  }
811  /**
812   * returns next item.
813   * @param {Array} array
814   */
815  function next(array, item) {
816      if (array && array.length && item) {
817          var idx = array.indexOf(item);
818          return idx === -1 ? null : array[idx + 1];
819      }
820      return null;
821  }
822  /**
823   * returns prev item.
824   * @param {Array} array
825   */
826  function prev(array, item) {
827      if (array && array.length && item) {
828          var idx = array.indexOf(item);
829          return idx === -1 ? null : array[idx - 1];
830      }
831      return null;
832  }
833  /**
834   * @class core.list
835   *
836   * list utils
837   *
838   * @singleton
839   * @alternateClassName list
840   */
841  var lists = {
842      head: head,
843      last: last,
844      initial: initial,
845      tail: tail,
846      prev: prev,
847      next: next,
848      find: find,
849      contains: contains,
850      all: all,
851      sum: sum,
852      from: from,
853      isEmpty: isEmpty,
854      clusterBy: clusterBy,
855      compact: compact,
856      unique: unique
857  };
858
859  var NBSP_CHAR = String.fromCharCode(160);
860  var ZERO_WIDTH_NBSP_CHAR = '\ufeff';
861  /**
862   * @method isEditable
863   *
864   * returns whether node is `note-editable` or not.
865   *
866   * @param {Node} node
867   * @return {Boolean}
868   */
869  function isEditable(node) {
870      return node && $$1(node).hasClass('note-editable');
871  }
872  /**
873   * @method isControlSizing
874   *
875   * returns whether node is `note-control-sizing` or not.
876   *
877   * @param {Node} node
878   * @return {Boolean}
879   */
880  function isControlSizing(node) {
881      return node && $$1(node).hasClass('note-control-sizing');
882  }
883  /**
884   * @method makePredByNodeName
885   *
886   * returns predicate which judge whether nodeName is same
887   *
888   * @param {String} nodeName
889   * @return {Function}
890   */
891  function makePredByNodeName(nodeName) {
892      nodeName = nodeName.toUpperCase();
893      return function (node) {
894          return node && node.nodeName.toUpperCase() === nodeName;
895      };
896  }
897  /**
898   * @method isText
899   *
900   *
901   *
902   * @param {Node} node
903   * @return {Boolean} true if node's type is text(3)
904   */
905  function isText(node) {
906      return node && node.nodeType === 3;
907  }
908  /**
909   * @method isElement
910   *
911   *
912   *
913   * @param {Node} node
914   * @return {Boolean} true if node's type is element(1)
915   */
916  function isElement(node) {
917      return node && node.nodeType === 1;
918  }
919  /**
920   * ex) br, col, embed, hr, img, input, ...
921   * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
922   */
923  function isVoid(node) {
924      return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON|^INPUT|^AUDIO|^VIDEO|^EMBED/.test(node.nodeName.toUpperCase());
925  }
926  function isPara(node) {
927      if (isEditable(node)) {
928          return false;
929      }
930      // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
931      return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());
932  }
933  function isHeading(node) {
934      return node && /^H[1-7]/.test(node.nodeName.toUpperCase());
935  }
936  var isPre = makePredByNodeName('PRE');
937  var isLi = makePredByNodeName('LI');
938  function isPurePara(node) {
939      return isPara(node) && !isLi(node);
940  }
941  var isTable = makePredByNodeName('TABLE');
942  var isData = makePredByNodeName('DATA');
943  function isInline(node) {
944      return !isBodyContainer(node) &&
945          !isList(node) &&
946          !isHr(node) &&
947          !isPara(node) &&
948          !isTable(node) &&
949          !isBlockquote(node) &&
950          !isData(node);
951  }
952  function isList(node) {
953      return node && /^UL|^OL/.test(node.nodeName.toUpperCase());
954  }
955  var isHr = makePredByNodeName('HR');
956  function isCell(node) {
957      return node && /^TD|^TH/.test(node.nodeName.toUpperCase());
958  }
959  var isBlockquote = makePredByNodeName('BLOCKQUOTE');
960  function isBodyContainer(node) {
961      return isCell(node) || isBlockquote(node) || isEditable(node);
962  }
963  var isAnchor = makePredByNodeName('A');
964  function isParaInline(node) {
965      return isInline(node) && !!ancestor(node, isPara);
966  }
967  function isBodyInline(node) {
968      return isInline(node) && !ancestor(node, isPara);
969  }
970  var isBody = makePredByNodeName('BODY');
971  /**
972   * returns whether nodeB is closest sibling of nodeA
973   *
974   * @param {Node} nodeA
975   * @param {Node} nodeB
976   * @return {Boolean}
977   */
978  function isClosestSibling(nodeA, nodeB) {
979      return nodeA.nextSibling === nodeB ||
980          nodeA.previousSibling === nodeB;
981  }
982  /**
983   * returns array of closest siblings with node
984   *
985   * @param {Node} node
986   * @param {function} [pred] - predicate function
987   * @return {Node[]}
988   */
989  function withClosestSiblings(node, pred) {
990      pred = pred || func.ok;
991      var siblings = [];
992      if (node.previousSibling && pred(node.previousSibling)) {
993          siblings.push(node.previousSibling);
994      }
995      siblings.push(node);
996      if (node.nextSibling && pred(node.nextSibling)) {
997          siblings.push(node.nextSibling);
998      }
999      return siblings;
1000  }
1001  /**
1002   * blank HTML for cursor position
1003   * - [workaround] old IE only works with &nbsp;
1004   * - [workaround] IE11 and other browser works with bogus br
1005   */
1006  var blankHTML = env.isMSIE && env.browserVersion < 11 ? '&nbsp;' : '<br>';
1007  /**
1008   * @method nodeLength
1009   *
1010   * returns #text's text size or element's childNodes size
1011   *
1012   * @param {Node} node
1013   */
1014  function nodeLength(node) {
1015      if (isText(node)) {
1016          return node.nodeValue.length;
1017      }
1018      if (node) {
1019          return node.childNodes.length;
1020      }
1021      return 0;
1022  }
1023  /**
1024   * returns whether node is empty or not.
1025   *
1026   * @param {Node} node
1027   * @return {Boolean}
1028   */
1029  function isEmpty$1(node) {
1030      var len = nodeLength(node);
1031      if (len === 0) {
1032          return true;
1033      }
1034      else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {
1035          // ex) <p><br></p>, <span><br></span>
1036          return true;
1037      }
1038      else if (lists.all(node.childNodes, isText) && node.innerHTML === '') {
1039          // ex) <p></p>, <span></span>
1040          return true;
1041      }
1042      return false;
1043  }
1044  /**
1045   * padding blankHTML if node is empty (for cursor position)
1046   */
1047  function paddingBlankHTML(node) {
1048      if (!isVoid(node) && !nodeLength(node)) {
1049          node.innerHTML = blankHTML;
1050      }
1051  }
1052  /**
1053   * find nearest ancestor predicate hit
1054   *
1055   * @param {Node} node
1056   * @param {Function} pred - predicate function
1057   */
1058  function ancestor(node, pred) {
1059      while (node) {
1060          if (pred(node)) {
1061              return node;
1062          }
1063          if (isEditable(node)) {
1064              break;
1065          }
1066          node = node.parentNode;
1067      }
1068      return null;
1069  }
1070  /**
1071   * find nearest ancestor only single child blood line and predicate hit
1072   *
1073   * @param {Node} node
1074   * @param {Function} pred - predicate function
1075   */
1076  function singleChildAncestor(node, pred) {
1077      node = node.parentNode;
1078      while (node) {
1079          if (nodeLength(node) !== 1) {
1080              break;
1081          }
1082          if (pred(node)) {
1083              return node;
1084          }
1085          if (isEditable(node)) {
1086              break;
1087          }
1088          node = node.parentNode;
1089      }
1090      return null;
1091  }
1092  /**
1093   * returns new array of ancestor nodes (until predicate hit).
1094   *
1095   * @param {Node} node
1096   * @param {Function} [optional] pred - predicate function
1097   */
1098  function listAncestor(node, pred) {
1099      pred = pred || func.fail;
1100      var ancestors = [];
1101      ancestor(node, function (el) {
1102          if (!isEditable(el)) {
1103              ancestors.push(el);
1104          }
1105          return pred(el);
1106      });
1107      return ancestors;
1108  }
1109  /**
1110   * find farthest ancestor predicate hit
1111   */
1112  function lastAncestor(node, pred) {
1113      var ancestors = listAncestor(node);
1114      return lists.last(ancestors.filter(pred));
1115  }
1116  /**
1117   * returns common ancestor node between two nodes.
1118   *
1119   * @param {Node} nodeA
1120   * @param {Node} nodeB
1121   */
1122  function commonAncestor(nodeA, nodeB) {
1123      var ancestors = listAncestor(nodeA);
1124      for (var n = nodeB; n; n = n.parentNode) {
1125          if (ancestors.indexOf(n) > -1)
1126              return n;
1127      }
1128      return null; // difference document area
1129  }
1130  /**
1131   * listing all previous siblings (until predicate hit).
1132   *
1133   * @param {Node} node
1134   * @param {Function} [optional] pred - predicate function
1135   */
1136  function listPrev(node, pred) {
1137      pred = pred || func.fail;
1138      var nodes = [];
1139      while (node) {
1140          if (pred(node)) {
1141              break;
1142          }
1143          nodes.push(node);
1144          node = node.previousSibling;
1145      }
1146      return nodes;
1147  }
1148  /**
1149   * listing next siblings (until predicate hit).
1150   *
1151   * @param {Node} node
1152   * @param {Function} [pred] - predicate function
1153   */
1154  function listNext(node, pred) {
1155      pred = pred || func.fail;
1156      var nodes = [];
1157      while (node) {
1158          if (pred(node)) {
1159              break;
1160          }
1161          nodes.push(node);
1162          node = node.nextSibling;
1163      }
1164      return nodes;
1165  }
1166  /**
1167   * listing descendant nodes
1168   *
1169   * @param {Node} node
1170   * @param {Function} [pred] - predicate function
1171   */
1172  function listDescendant(node, pred) {
1173      var descendants = [];
1174      pred = pred || func.ok;
1175      // start DFS(depth first search) with node
1176      (function fnWalk(current) {
1177          if (node !== current && pred(current)) {
1178              descendants.push(current);
1179          }
1180          for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {
1181              fnWalk(current.childNodes[idx]);
1182          }
1183      })(node);
1184      return descendants;
1185  }
1186  /**
1187   * wrap node with new tag.
1188   *
1189   * @param {Node} node
1190   * @param {Node} tagName of wrapper
1191   * @return {Node} - wrapper
1192   */
1193  function wrap(node, wrapperName) {
1194      var parent = node.parentNode;
1195      var wrapper = $$1('<' + wrapperName + '>')[0];
1196      parent.insertBefore(wrapper, node);
1197      wrapper.appendChild(node);
1198      return wrapper;
1199  }
1200  /**
1201   * insert node after preceding
1202   *
1203   * @param {Node} node
1204   * @param {Node} preceding - predicate function
1205   */
1206  function insertAfter(node, preceding) {
1207      var next = preceding.nextSibling;
1208      var parent = preceding.parentNode;
1209      if (next) {
1210          parent.insertBefore(node, next);
1211      }
1212      else {
1213          parent.appendChild(node);
1214      }
1215      return node;
1216  }
1217  /**
1218   * append elements.
1219   *
1220   * @param {Node} node
1221   * @param {Collection} aChild
1222   */
1223  function appendChildNodes(node, aChild) {
1224      $$1.each(aChild, function (idx, child) {
1225          node.appendChild(child);
1226      });
1227      return node;
1228  }
1229  /**
1230   * returns whether boundaryPoint is left edge or not.
1231   *
1232   * @param {BoundaryPoint} point
1233   * @return {Boolean}
1234   */
1235  function isLeftEdgePoint(point) {
1236      return point.offset === 0;
1237  }
1238  /**
1239   * returns whether boundaryPoint is right edge or not.
1240   *
1241   * @param {BoundaryPoint} point
1242   * @return {Boolean}
1243   */
1244  function isRightEdgePoint(point) {
1245      return point.offset === nodeLength(point.node);
1246  }
1247  /**
1248   * returns whether boundaryPoint is edge or not.
1249   *
1250   * @param {BoundaryPoint} point
1251   * @return {Boolean}
1252   */
1253  function isEdgePoint(point) {
1254      return isLeftEdgePoint(point) || isRightEdgePoint(point);
1255  }
1256  /**
1257   * returns whether node is left edge of ancestor or not.
1258   *
1259   * @param {Node} node
1260   * @param {Node} ancestor
1261   * @return {Boolean}
1262   */
1263  function isLeftEdgeOf(node, ancestor) {
1264      while (node && node !== ancestor) {
1265          if (position(node) !== 0) {
1266              return false;
1267          }
1268          node = node.parentNode;
1269      }
1270      return true;
1271  }
1272  /**
1273   * returns whether node is right edge of ancestor or not.
1274   *
1275   * @param {Node} node
1276   * @param {Node} ancestor
1277   * @return {Boolean}
1278   */
1279  function isRightEdgeOf(node, ancestor) {
1280      if (!ancestor) {
1281          return false;
1282      }
1283      while (node && node !== ancestor) {
1284          if (position(node) !== nodeLength(node.parentNode) - 1) {
1285              return false;
1286          }
1287          node = node.parentNode;
1288      }
1289      return true;
1290  }
1291  /**
1292   * returns whether point is left edge of ancestor or not.
1293   * @param {BoundaryPoint} point
1294   * @param {Node} ancestor
1295   * @return {Boolean}
1296   */
1297  function isLeftEdgePointOf(point, ancestor) {
1298      return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);
1299  }
1300  /**
1301   * returns whether point is right edge of ancestor or not.
1302   * @param {BoundaryPoint} point
1303   * @param {Node} ancestor
1304   * @return {Boolean}
1305   */
1306  function isRightEdgePointOf(point, ancestor) {
1307      return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);
1308  }
1309  /**
1310   * returns offset from parent.
1311   *
1312   * @param {Node} node
1313   */
1314  function position(node) {
1315      var offset = 0;
1316      while ((node = node.previousSibling)) {
1317          offset += 1;
1318      }
1319      return offset;
1320  }
1321  function hasChildren(node) {
1322      return !!(node && node.childNodes && node.childNodes.length);
1323  }
1324  /**
1325   * returns previous boundaryPoint
1326   *
1327   * @param {BoundaryPoint} point
1328   * @param {Boolean} isSkipInnerOffset
1329   * @return {BoundaryPoint}
1330   */
1331  function prevPoint(point, isSkipInnerOffset) {
1332      var node;
1333      var offset;
1334      if (point.offset === 0) {
1335          if (isEditable(point.node)) {
1336              return null;
1337          }
1338          node = point.node.parentNode;
1339          offset = position(point.node);
1340      }
1341      else if (hasChildren(point.node)) {
1342          node = point.node.childNodes[point.offset - 1];
1343          offset = nodeLength(node);
1344      }
1345      else {
1346          node = point.node;
1347          offset = isSkipInnerOffset ? 0 : point.offset - 1;
1348      }
1349      return {
1350          node: node,
1351          offset: offset
1352      };
1353  }
1354  /**
1355   * returns next boundaryPoint
1356   *
1357   * @param {BoundaryPoint} point
1358   * @param {Boolean} isSkipInnerOffset
1359   * @return {BoundaryPoint}
1360   */
1361  function nextPoint(point, isSkipInnerOffset) {
1362      var node, offset;
1363      if (nodeLength(point.node) === point.offset) {
1364          if (isEditable(point.node)) {
1365              return null;
1366          }
1367          node = point.node.parentNode;
1368          offset = position(point.node) + 1;
1369      }
1370      else if (hasChildren(point.node)) {
1371          node = point.node.childNodes[point.offset];
1372          offset = 0;
1373      }
1374      else {
1375          node = point.node;
1376          offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
1377      }
1378      return {
1379          node: node,
1380          offset: offset
1381      };
1382  }
1383  /**
1384   * returns whether pointA and pointB is same or not.
1385   *
1386   * @param {BoundaryPoint} pointA
1387   * @param {BoundaryPoint} pointB
1388   * @return {Boolean}
1389   */
1390  function isSamePoint(pointA, pointB) {
1391      return pointA.node === pointB.node && pointA.offset === pointB.offset;
1392  }
1393  /**
1394   * returns whether point is visible (can set cursor) or not.
1395   *
1396   * @param {BoundaryPoint} point
1397   * @return {Boolean}
1398   */
1399  function isVisiblePoint(point) {
1400      if (isText(point.node) || !hasChildren(point.node) || isEmpty$1(point.node)) {
1401          return true;
1402      }
1403      var leftNode = point.node.childNodes[point.offset - 1];
vendor: 8,354 bytes, lines 1404-1683
1404      var rightNode = point.node.childNodes[point.offset];
1405      if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {
1406          return true;
1407      }
1408      return false;
1409  }
1410  /**
1411   * @method prevPointUtil
1412   *
1413   * @param {BoundaryPoint} point
1414   * @param {Function} pred
1415   * @return {BoundaryPoint}
1416   */
1417  function prevPointUntil(point, pred) {
1418      while (point) {
1419          if (pred(point)) {
1420              return point;
1421          }
1422          point = prevPoint(point);
1423      }
1424      return null;
1425  }
1426  /**
1427   * @method nextPointUntil
1428   *
1429   * @param {BoundaryPoint} point
1430   * @param {Function} pred
1431   * @return {BoundaryPoint}
1432   */
1433  function nextPointUntil(point, pred) {
1434      while (point) {
1435          if (pred(point)) {
1436              return point;
1437          }
1438          point = nextPoint(point);
1439      }
1440      return null;
1441  }
1442  /**
1443   * returns whether point has character or not.
1444   *
1445   * @param {Point} point
1446   * @return {Boolean}
1447   */
1448  function isCharPoint(point) {
1449      if (!isText(point.node)) {
1450          return false;
1451      }
1452      var ch = point.node.nodeValue.charAt(point.offset - 1);
1453      return ch && (ch !== ' ' && ch !== NBSP_CHAR);
1454  }
1455  /**
1456   * @method walkPoint
1457   *
1458   * @param {BoundaryPoint} startPoint
1459   * @param {BoundaryPoint} endPoint
1460   * @param {Function} handler
1461   * @param {Boolean} isSkipInnerOffset
1462   */
1463  function walkPoint(startPoint, endPoint, handler, isSkipInnerOffset) {
1464      var point = startPoint;
1465      while (point) {
1466          handler(point);
1467          if (isSamePoint(point, endPoint)) {
1468              break;
1469          }
1470          var isSkipOffset = isSkipInnerOffset &&
1471              startPoint.node !== point.node &&
1472              endPoint.node !== point.node;
1473          point = nextPoint(point, isSkipOffset);
1474      }
1475  }
1476  /**
1477   * @method makeOffsetPath
1478   *
1479   * return offsetPath(array of offset) from ancestor
1480   *
1481   * @param {Node} ancestor - ancestor node
1482   * @param {Node} node
1483   */
1484  function makeOffsetPath(ancestor, node) {
1485      var ancestors = listAncestor(node, func.eq(ancestor));
1486      return ancestors.map(position).reverse();
1487  }
1488  /**
1489   * @method fromOffsetPath
1490   *
1491   * return element from offsetPath(array of offset)
1492   *
1493   * @param {Node} ancestor - ancestor node
1494   * @param {array} offsets - offsetPath
1495   */
1496  function fromOffsetPath(ancestor, offsets) {
1497      var current = ancestor;
1498      for (var i = 0, len = offsets.length; i < len; i++) {
1499          if (current.childNodes.length <= offsets[i]) {
1500              current = current.childNodes[current.childNodes.length - 1];
1501          }
1502          else {
1503              current = current.childNodes[offsets[i]];
1504          }
1505      }
1506      return current;
1507  }
1508  /**
1509   * @method splitNode
1510   *
1511   * split element or #text
1512   *
1513   * @param {BoundaryPoint} point
1514   * @param {Object} [options]
1515   * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
1516   * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
1517   * @param {Boolean} [options.isDiscardEmptySplits] - default: false
1518   * @return {Node} right node of boundaryPoint
1519   */
1520  function splitNode(point, options) {
1521      var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
1522      var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
1523      var isDiscardEmptySplits = options && options.isDiscardEmptySplits;
1524      if (isDiscardEmptySplits) {
1525          isSkipPaddingBlankHTML = true;
1526      }
1527      // edge case
1528      if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
1529          if (isLeftEdgePoint(point)) {
1530              return point.node;
1531          }
1532          else if (isRightEdgePoint(point)) {
1533              return point.node.nextSibling;
1534          }
1535      }
1536      // split #text
1537      if (isText(point.node)) {
1538          return point.node.splitText(point.offset);
1539      }
1540      else {
1541          var childNode = point.node.childNodes[point.offset];
1542          var clone = insertAfter(point.node.cloneNode(false), point.node);
1543          appendChildNodes(clone, listNext(childNode));
1544          if (!isSkipPaddingBlankHTML) {
1545              paddingBlankHTML(point.node);
1546              paddingBlankHTML(clone);
1547          }
1548          if (isDiscardEmptySplits) {
1549              if (isEmpty$1(point.node)) {
1550                  remove(point.node);
1551              }
1552              if (isEmpty$1(clone)) {
1553                  remove(clone);
1554                  return point.node.nextSibling;
1555              }
1556          }
1557          return clone;
1558      }
1559  }
1560  /**
1561   * @method splitTree
1562   *
1563   * split tree by point
1564   *
1565   * @param {Node} root - split root
1566   * @param {BoundaryPoint} point
1567   * @param {Object} [options]
1568   * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
1569   * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
1570   * @return {Node} right node of boundaryPoint
1571   */
1572  function splitTree(root, point, options) {
1573      // ex) [#text, <span>, <p>]
1574      var ancestors = listAncestor(point.node, func.eq(root));
1575      if (!ancestors.length) {
1576          return null;
1577      }
1578      else if (ancestors.length === 1) {
1579          return splitNode(point, options);
1580      }
1581      return ancestors.reduce(function (node, parent) {
1582          if (node === point.node) {
1583              node = splitNode(point, options);
1584          }
1585          return splitNode({
1586              node: parent,
1587              offset: node ? position(node) : nodeLength(parent)
1588          }, options);
1589      });
1590  }
1591  /**
1592   * split point
1593   *
1594   * @param {Point} point
1595   * @param {Boolean} isInline
1596   * @return {Object}
1597   */
1598  function splitPoint(point, isInline) {
1599      // find splitRoot, container
1600      //  - inline: splitRoot is a child of paragraph
1601      //  - block: splitRoot is a child of bodyContainer
1602      var pred = isInline ? isPara : isBodyContainer;
1603      var ancestors = listAncestor(point.node, pred);
1604      var topAncestor = lists.last(ancestors) || point.node;
1605      var splitRoot, container;
1606      if (pred(topAncestor)) {
1607          splitRoot = ancestors[ancestors.length - 2];
1608          container = topAncestor;
1609      }
1610      else {
1611          splitRoot = topAncestor;
1612          container = splitRoot.parentNode;
1613      }
1614      // if splitRoot is exists, split with splitTree
1615      var pivot = splitRoot && splitTree(splitRoot, point, {
1616          isSkipPaddingBlankHTML: isInline,
1617          isNotSplitEdgePoint: isInline
1618      });
1619      // if container is point.node, find pivot with point.offset
1620      if (!pivot && container === point.node) {
1621          pivot = point.node.childNodes[point.offset];
1622      }
1623      return {
1624          rightNode: pivot,
1625          container: container
1626      };
1627  }
1628  function create(nodeName) {
1629      return document.createElement(nodeName);
1630  }
1631  function createText(text) {
1632      return document.createTextNode(text);
1633  }
1634  /**
1635   * @method remove
1636   *
1637   * remove node, (isRemoveChild: remove child or not)
1638   *
1639   * @param {Node} node
1640   * @param {Boolean} isRemoveChild
1641   */
1642  function remove(node, isRemoveChild) {
1643      if (!node || !node.parentNode) {
1644          return;
1645      }
1646      if (node.removeNode) {
1647          return node.removeNode(isRemoveChild);
1648      }
1649      var parent = node.parentNode;
1650      if (!isRemoveChild) {
1651          var nodes = [];
1652          for (var i = 0, len = node.childNodes.length; i < len; i++) {
1653              nodes.push(node.childNodes[i]);
1654          }
1655          for (var i = 0, len = nodes.length; i < len; i++) {
1656              parent.insertBefore(nodes[i], node);
1657          }
1658      }
1659      parent.removeChild(node);
1660  }
1661  /**
1662   * @method removeWhile
1663   *
1664   * @param {Node} node
1665   * @param {Function} pred
1666   */
1667  function removeWhile(node, pred) {
1668      while (node) {
1669          if (isEditable(node) || !pred(node)) {
1670              break;
1671          }
1672          var parent = node.parentNode;
1673          remove(node);
1674          node = parent;
1675      }
1676  }
1677  /**
1678   * @method replace
1679   *
1680   * replace node with provided nodeName
1681   *
1682   * @param {Node} node
1683   * @param {String}
1683 nodeName
1684   * @return {Node} - new node
1685   */
1686  function replace(node, nodeName) {
1687      if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
1688          return node;
1689      }
1690      var newNode = create(nodeName);
1691      if (node.style.cssText) {
1692          newNode.style.cssText = node.style.cssText;
1693      }
1694      appendChildNodes(newNode, lists.from(node.childNodes));
1695      insertAfter(newNode, node);
1696      remove(node);
1697      return newNode;
1698  }
1699  var isTextarea = makePredByNodeName('TEXTAREA');
1700  /**
1701   * @param {jQuery} $node
1702   * @param {Boolean} [stripLinebreaks] - default: false
1703   */
1704  function value($node, stripLinebreaks) {
1705      var val = isTextarea($node[0]) ? $node.val() : $node.html();
1706      if (stripLinebreaks) {
1707          return val.replace(/[\n\r]/g, '');
1708      }
1709      return val;
1710  }
1711  /**
1712   * @method html
1713   *
1714   * get the HTML contents of node
1715   *
1716   * @param {jQuery} $node
1717   * @param {Boolean} [isNewlineOnBlock]
1718   */
1719  function html($node, isNewlineOnBlock) {
1720      var markup = value($node);
1721      if (isNewlineOnBlock) {
1722          var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
1723          markup = markup.replace(regexTag, function (match, endSlash, name) {
1724              name = name.toUpperCase();
1725              var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&
1726                  !!endSlash;
1727              var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
1728              return match + ((isEndOfInlineContainer || isBlockNode) ? '\n' : '');
1729          });
1730          markup = markup.trim();
1731      }
1732      return markup;
1733  }
1734  function posFromPlaceholder(placeholder) {
1735      var $placeholder = $$1(placeholder);
1736      var pos = $placeholder.offset();
1737      var height = $placeholder.outerHeight(true); // include margin
1738      return {
1739          left: pos.left,
1740          top: pos.top + height
1741      };
1742  }
1743  function attachEvents($node, events) {
1744      Object.keys(events).forEach(function (key) {
1745          $node.on(key, events[key]);
1746      });
1747  }
1748  function detachEvents($node, events) {
1749      Object.keys(events).forEach(function (key) {
1750          $node.off(key, events[key]);
1751      });
1752  }
1753  /**
1754   * @method isCustomStyleTag
1755   *
1756   * assert if a node contains a "note-styletag" class,
1757   * which implies that's a custom-made style tag node
1758   *
1759   * @param {Node} an HTML DOM node
1760   */
1761  function isCustomStyleTag(node) {
1762      return node && !isText(node) && lists.contains(node.classList, 'note-styletag');
1763  }
1764  var dom = {
1765      /** @property {String} NBSP_CHAR */
1766      NBSP_CHAR: NBSP_CHAR,
1767      /** @property {String} ZERO_WIDTH_NBSP_CHAR */
1768      ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
1769      /** @property {String} blank */
1770      blank: blankHTML,
1771      /** @property {String} emptyPara */
1772      emptyPara: "<p>" + blankHTML + "</p>",
1773      makePredByNodeName: makePredByNodeName,
1774      isEditable: isEditable,
1775      isControlSizing: isControlSizing,
1776      isText: isText,
1777      isElement: isElement,
1778      isVoid: isVoid,
1779      isPara: isPara,
1780      isPurePara: isPurePara,
1781      isHeading: isHeading,
1782      isInline: isInline,
1783      isBlock: func.not(isInline),
1784      isBodyInline: isBodyInline,
1785      isBody: isBody,
1786      isParaInline: isParaInline,
1787      isPre: isPre,
1788      isList: isList,
1789      isTable: isTable,
1790      isData: isData,
1791      isCell: isCell,
1792      isBlockquote: isBlockquote,
1793      isBodyContainer: isBodyContainer,
1794      isAnchor: isAnchor,
1795      isDiv: makePredByNodeName('DIV'),
1796      isLi: isLi,
1797      isBR: makePredByNodeName('BR'),
1798      isSpan: makePredByNodeName('SPAN'),
1799      isB: makePredByNodeName('B'),
1800      isU: makePredByNodeName('U'),
1801      isS: makePredByNodeName('S'),
1802      isI: makePredByNodeName('I'),
1803      isImg: makePredByNodeName('IMG'),
1804      isTextarea: isTextarea,
1805      isEmpty: isEmpty$1,
1806      isEmptyAnchor: func.and(isAnchor, isEmpty$1),
1807      isClosestSibling: isClosestSibling,
1808      withClosestSiblings: withClosestSiblings,
1809      nodeLength: nodeLength,
1810      isLeftEdgePoint: isLeftEdgePoint,
1811      isRightEdgePoint: isRightEdgePoint,
1812      isEdgePoint: isEdgePoint,
1813      isLeftEdgeOf: isLeftEdgeOf,
1814      isRightEdgeOf: isRightEdgeOf,
1815      isLeftEdgePointOf: isLeftEdgePointOf,
1816      isRightEdgePointOf: isRightEdgePointOf,
1817      prevPoint: prevPoint,
1818      nextPoint: nextPoint,
1819      isSamePoint: isSamePoint,
1820      isVisiblePoint: isVisiblePoint,
1821      prevPointUntil: prevPointUntil,
1822      nextPointUntil: nextPointUntil,
1823      isCharPoint: isCharPoint,
1824      walkPoint: walkPoint,
1825      ancestor: ancestor,
1826      singleChildAncestor: singleChildAncestor,
1827      listAncestor: listAncestor,
1828      lastAncestor: lastAncestor,
1829      listNext: listNext,
1830      listPrev: listPrev,
1831      listDescendant: listDescendant,
1832      commonAncestor: commonAncestor,
1833      wrap: wrap,
1834      insertAfter: insertAfter,
1835      appendChildNodes: appendChildNodes,
1836      position: position,
1837      hasChildren: hasChildren,
1838      makeOffsetPath: makeOffsetPath,
1839      fromOffsetPath: fromOffsetPath,
1840      splitTree: splitTree,
1841      splitPoint: splitPoint,
1842      create: create,
1843      createText: createText,
1844      remove: remove,
1845      removeWhile: removeWhile,
1846      replace: replace,
1847      html: html,
1848      value: value,
1849      posFromPlaceholder: posFromPlaceholder,
1850      attachEvents: attachEvents,
1851      detachEvents: detachEvents,
1852      isCustomStyleTag: isCustomStyleTag
1853  };
1854
1855  var Context = /** @class */ (function () {
1856      /**
1857       * @param {jQuery} $note
1858       * @param {Object} options
1859       */
1860      function Context($note, options) {
1861          this.ui = $$1.summernote.ui;
1862          this.$note = $note;
1863          this.memos = {};
1864          this.modules = {};
1865          this.layoutInfo = {};
1866          this.options = options;
1867          this.initialize();
1868      }
1869      /**
1870       * create layout and initialize modules and other resources
1871       */
1872      Context.prototype.initialize = function () {
1873          this.layoutInfo = this.ui.createLayout(this.$note, this.options);
1874          this._initialize();
1875          this.$note.hide();
1876          return this;
1877      };
1878      /**
1879       * destroy modules and other resources and remove layout
1880       */
1881      Context.prototype.destroy = function () {
1882          this._destroy();
1883          this.$note.removeData('summernote');
1884          this.ui.removeLayout(this.$note, this.layoutInfo);
1885      };
1886      /**
1887       * destory modules and other resources and initialize it again
1888       */
1889      Context.prototype.reset = function () {
1890          var disabled = this.isDisabled();
1891          this.code(dom.emptyPara);
1892          this._destroy();
1893          this._initialize();
1894          if (disabled) {
1895              this.disable();
1896          }
1897      };
1898      Context.prototype._initialize = function () {
1899          var _this = this;
1900          // add optional buttons
1901          var buttons = $$1.extend({}, this.options.buttons);
1902          Object.keys(buttons).forEach(function (key) {
1903              _this.memo('button.' + key, buttons[key]);
1904          });
1905          var modules = $$1.extend({}, this.options.modules, $$1.summernote.plugins || {});
1906          // add and initialize modules
1907          Object.keys(modules).forEach(function (key) {
1908              _this.module(key, modules[key], true);
1909          });
1910          Object.keys(this.modules).forEach(function (key) {
1911              _this.initializeModule(key);
1912          });
1913      };
1914      Context.prototype._destroy = function () {
1915          var _this = this;
1916          // destroy modules with reversed order
1917          Object.keys(this.modules).reverse().forEach(function (key) {
1918              _this.removeModule(key);
1919          });
1920          Object.keys(this.memos).forEach(function (key) {
1921              _this.removeMemo(key);
1922          });
1923          // trigger custom onDestroy callback
1924          this.triggerEvent('destroy', this);
1925      };
1926      Context.prototype.code = function (html) {
1927          var isActivated = this.invoke('codeview.isActivated');
1928          if (html === undefined) {
1929              this.invoke('codeview.sync');
1930              return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();
1931          }
1932          else {
1933              if (isActivated) {
1934                  this.layoutInfo.codable.val(html);
1935              }
1936              else {
1937                  this.layoutInfo.editable.html(html);
1938              }
1939              this.$note.val(html);
1940              this.triggerEvent('change', html, this.layoutInfo.editable);
1941          }
1942      };
1943      Context.prototype.isDisabled = function () {
1944          return this.layoutInfo.editable.attr('contenteditable') === 'false';
1945      };
1946      Context.prototype.enable = function () {
1947          this.layoutInfo.editable.attr('contenteditable', true);
1948          this.invoke('toolbar.activate', true);
1949          this.triggerEvent('disable', false);
1950      };
1951      Context.prototype.disable = function () {
1952          // close codeview if codeview is opend
1953          if (this.invoke('codeview.isActivated')) {
1954              this.invoke('codeview.deactivate');
1955          }
1956          this.layoutInfo.editable.attr('contenteditable', false);
1957          this.invoke('toolbar.deactivate', true);
1958          this.triggerEvent('disable', true);
1959      };
1960      Context.prototype.triggerEvent = function () {
1961          var namespace = lists.head(arguments);
1962          var args = lists.tail(lists.from(arguments));
1963          var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];
1964          if (callback) {
1965              callback.apply(this.$note[0], args);
1966          }
1967          this.$note.trigger('summernote.' + namespace, args);
1968      };
1969      Context.prototype.initializeModule = function (key) {
1970          var module = this.modules[key];
1971          module.shouldInitialize = module.shouldInitialize || func.ok;
1972          if (!module.shouldInitialize()) {
1973              return;
1974          }
1975          // initialize module
1976          if (module.initialize) {
1977              module.initialize();
1978          }
1979          // attach events
1980          if (module.events) {
1981              dom.attachEvents(this.$note, module.events);
1982          }
1983      };
1984      Context.prototype.module = function (key, ModuleClass, withoutIntialize) {
1985          if (arguments.length === 1) {
1986              return this.modules[key];
1987          }
1988          this.modules[key] = new ModuleClass(this);
1989          if (!withoutIntialize) {
1990              this.initializeModule(key);
1991          }
1992      };
1993      Context.prototype.removeModule = function (key) {
1994          var module = this.modules[key];
1995          if (module.shouldInitialize()) {
1996              if (module.events) {
1997                  dom.detachEvents(this.$note, module.events);
1998              }
1999              if (module.destroy) {
2000                  module.destroy();
2001              }
2002          }
2003          delete this.modules[key];
2004      };
2005      Context.prototype.memo = function (key, obj) {
2006          if (arguments.length === 1) {
2007              return this.memos[key];
2008          }
2009          this.memos[key] = obj;
2010      };
2011      Context.prototype.removeMemo = function (key) {
2012          if (this.memos[key] && this.memos[key].destroy) {
2013              this.memos[key].destroy();
2014          }
2015          delete this.memos[key];
2016      };
2017      /**
2018       * Some buttons need to change their visual style immediately once they get pressed
2019       */
2020      Context.prototype.createInvokeHandlerAndUpdateState = function (namespace, value) {
2021          var _this = this;
2022          return function (event) {
2023              _this.createInvokeHandler(namespace, value)(event);
2024              _this.invoke('buttons.updateCurrentStyle');
2025          };
2026      };
2027      Context.prototype.createInvokeHandler = function (namespace, value) {
2028          var _this = this;
2029          return function (event) {
2030              event.preventDefault();
2031              var $target = $$1(event.target);
2032              _this.invoke(namespace, value || $target.closest('[data-value]').data('value'), $target);
2033          };
2034      };
2035      Context.prototype.invoke = function () {
2036          var namespace = lists.head(arguments);
2037          var args = lists.tail(lists.from(arguments));
2038          var splits = namespace.split('.');
2039          var hasSeparator = splits.length > 1;
2040          var moduleName = hasSeparator && lists.head(splits);
2041          var methodName = hasSeparator ? lists.last(splits) : lists.head(splits);
2042          var module = this.modules[moduleName || 'editor'];
2043          if (!moduleName && this[methodName]) {
2044              return this[methodName].apply(this, args);
2045          }
2046          else if (module && module[methodName] && module.shouldInitialize()) {
2047              return module[methodName].apply(module, args);
2048          }
2049      };
2050      return Context;
2051  }());
2052
2053  $$1.fn.extend({
2054      /**
2055       * Summernote API
2056       *
2057       * @param {Object|String}
2058       * @return {this}
2059       */
2060      summernote: function () {
2061          var type = $$1.type(lists.head(arguments));
2062          var isExternalAPICalled = type === 'string';
2063          var hasInitOptions = type === 'object';
2064          var options = $$1.extend({}, $$1.summernote.options, hasInitOptions ? lists.head(arguments) : {});
2065          // Update options
2066          options.langInfo = $$1.extend(true, {}, $$1.summernote.lang['en-US'], $$1.summernote.lang[options.lang]);
2067          options.icons = $$1.extend(true, {}, $$1.summernote.options.icons, options.icons);
2068          options.tooltip = options.tooltip === 'auto' ? !env.isSupportTouch : options.tooltip;
2069          this.each(function (idx, note) {
2070              var $note = $$1(note);
2071              if (!$note.data('summernote')) {
2072                  var context = new Context($note, options);
2073                  $note.data('summernote', context);
2074                  $note.data('summernote').triggerEvent('init', context.layoutInfo);
2075              }
2076          });
2077          var $note = this.first();
2078          if ($note.length) {
2079              var context = $note.data('summernote');
2080              if (isExternalAPICalled) {
2081                  return context.invoke.apply(context, lists.from(arguments));
2082              }
2083              else if (options.focus) {
2084                  context.invoke('editor.focus');
2085              }
2086          }
2087          return this;
2088      }
2089  });
2090
2091  /**
2092   * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
2093   *
2094   * @param {TextRange} textRange
2095   * @param {Boolean} isStart
2096   * @return {BoundaryPoint}
2097   *
2098   * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx
2099   */
2100  function textRangeToPoint(textRange, isStart) {
2101      var container = textRange.parentElement();
2102      var offset;
2103      var tester = document.body.createTextRange();
2104      var prevContainer;
2105      var childNodes = lists.from(container.childNodes);
2106      for (offset = 0; offset < childNodes.length; offset++) {
2107          if (dom.isText(childNodes[offset])) {
2108              continue;
2109          }
2110          tester.moveToElementText(childNodes[offset]);
2111          if (tester.compareEndPoints('StartToStart', textRange) >= 0) {
2112              break;
2113          }
2114          prevContainer = childNodes[offset];
2115      }
2116      if (offset !== 0 && dom.isText(childNodes[offset - 1])) {
2117          var textRangeStart = document.body.createTextRange();
2118          var curTextNode = null;
2119          textRangeStart.moveToElementText(prevContainer || container);
2120          textRangeStart.collapse(!prevContainer);
2121          curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;
2122          var pointTester = textRange.duplicate();
2123          pointTester.setEndPoint('StartToStart', textRangeStart);
2124          var textCount = pointTester.text.replace(/[\r\n]/g, '').length;
2125          while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {
2126              textCount -= curTextNode.nodeValue.length;
2127              curTextNode = curTextNode.nextSibling;
2128          }
2129          // [workaround] enforce IE to re-reference curTextNode, hack
2130          var dummy = curTextNode.nodeValue; // eslint-disable-line
2131          if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&
2132              textCount === curTextNode.nodeValue.length) {
2133              textCount -= curTextNode.nodeValue.length;
2134              curTextNode = curTextNode.nextSibling;
2135          }
2136          container = curTextNode;
2137          offset = textCount;
2138      }
2139      return {
2140          cont: container,
2141          offset: offset
2142      };
2143  }
2144  /**
2145   * return TextRange from boundary point (inspired by google closure-library)
2146   * @param {BoundaryPoint} point
2147   * @return {TextRange}
2148   */
2149  function pointToTextRange(point) {
2150      var textRangeInfo = function (container, offset) {
2151          var node, isCollapseToStart;
2152          if (dom.isText(container)) {
2153              var prevTextNodes = dom.listPrev(container, func.not(dom.isText));
2154              var prevContainer = lists.last(prevTextNodes).previousSibling;
2155              node = prevContainer || container.parentNode;
2156              offset += lists.sum(lists.tail(prevTextNodes), dom.nodeLength);
2157              isCollapseToStart = !prevContainer;
2158          }
2159          else {
2160              node = container.childNodes[offset] || container;
2161              if (dom.isText(node)) {
2162                  return textRangeInfo(node, 0);
2163              }
2164              offset = 0;
2165              isCollapseToStart = false;
2166          }
2167          return {
2168              node: node,
2169              collapseToStart: isCollapseToStart,
2170              offset: offset
2171          };
2172      };
2173      var textRange = document.body.createTextRange();
2174      var info = textRangeInfo(point.node, point.offset);
2175      textRange.moveToElementText(info.node);
2176      textRange.collapse(info.collapseToStart);
2177      textRange.moveStart('character', info.offset);
2178      return textRange;
2179  }
2180  /**
2181     * Wrapped Range
2182     *
2183     * @constructor
2184     * @param {Node} sc - start container
2185     * @param {Number} so - start offset
2186     * @param {Node} ec - end container
2187     * @param {Number} eo - end offset
2188     */
2189  var WrappedRange = /** @class */ (function () {
2190      function WrappedRange(sc, so, ec, eo) {
2191          this.sc = sc;
2192          this.so = so;
2193          this.ec = ec;
2194          this.eo = eo;
2195          // isOnEditable: judge whether range is on editable or not
2196          this.isOnEditable = this.makeIsOn(dom.isEditable);
2197          // isOnList: judge whether range is on list node or not
2198          this.isOnList = this.makeIsOn(dom.isList);
2199          // isOnAnchor: judge whether range is on anchor node or not
2200          this.isOnAnchor = this.makeIsOn(dom.isAnchor);
2201          // isOnCell: judge whether range is on cell node or not
2202          this.isOnCell = this.makeIsOn(dom.isCell);
2203          // isOnData: judge whether range is on data node or not
2204          this.isOnData = this.makeIsOn(dom.isData);
2205      }
2206      // nativeRange: get nativeRange from sc, so, ec, eo
2207      WrappedRange.prototype.nativeRange = function () {
2208          if (env.isW3CRangeSupport) {
2209              var w3cRange = document.createRange();
2210              w3cRange.setStart(this.sc, this.sc.data && this.so > this.sc.data.length ? 0 : this.so);
2211              w3cRange.setEnd(this.ec, this.sc.data ? Math.min(this.eo, this.sc.data.length) : this.eo);
2212              return w3cRange;
2213          }
2214          else {
2215              var textRange = pointToTextRange({
2216                  node: this.sc,
2217                  offset: this.so
2218              });
2219              textRange.setEndPoint('EndToEnd', pointToTextRange({
2220                  node: this.ec,
2221                  offset: this.eo
2222              }));
2223              return textRange;
2224          }
2225      };
2226      WrappedRange.prototype.getPoints = function () {
2227          return {
2228              sc: this.sc,
2229              so: this.so,
2230              ec: this.ec,
2231              eo: this.eo
2232          };
2233      };
2234      WrappedRange.prototype.getStartPoint = function () {
2235          return {
2236              node: this.sc,
2237              offset: this.so
2238          };
2239      };
2240      WrappedRange.prototype.getEndPoint = function () {
2241          return {
2242              node: this.ec,
2243              offset: this.eo
2244          };
2245      };
2246      /**
2247       * select update visible range
2248       */
2249      WrappedRange.prototype.select = function () {
2250          var nativeRng = this.nativeRange();
2251          if (env.isW3CRangeSupport) {
2252              var selection = document.getSelection();
2253              if (selection.rangeCount > 0) {
2254                  selection.removeAllRanges();
2255              }
2256              selection.addRange(nativeRng);
2257          }
2258          else {
2259              nativeRng.select();
2260          }
2261          return this;
2262      };
2263      /**
2264       * Moves the scrollbar to start container(sc) of current range
2265       *
2266       * @return {WrappedRange}
2267       */
2268      WrappedRange.prototype.scrollIntoView = function (container) {
2269          var height = $$1(container).height();
2270          if (container.scrollTop + height < this.sc.offsetTop) {
2271              container.scrollTop += Math.abs(container.scrollTop + height - this.sc.offsetTop);
2272          }
2273          return this;
2274      };
2275      /**
2276       * @return {WrappedRange}
2277       */
2278      WrappedRange.prototype.normalize = function () {
2279          /**
2280           * @param {BoundaryPoint} point
2281           * @param {Boolean} isLeftToRight - true: prefer to choose right node
2282           *                                - false: prefer to choose left node
2283           * @return {BoundaryPoint}
2284           */
2285          var getVisiblePoint = function (point, isLeftToRight) {
2286              // Just use the given point [XXX:Adhoc]
2287              //  - case 01. if the point is on the middle of the node
2288              //  - case 02. if the point is on the right edge and prefer to choose left node
2289              //  - case 03. if the point is on the left edge and prefer to choose right node
2290              //  - case 04. if the point is on the right edge and prefer to choose right node but the node is void
2291              //  - case 05. if the point is on the left edge and prefer to choose left node but the node is void
2292              //  - case 06. if the point is on the block node and there is no children
2293              if (dom.isVisiblePoint(point)) {
2294                  if (!dom.isEdgePoint(point) ||
2295                      (dom.isRightEdgePoint(point) && !isLeftToRight) ||
2296                      (dom.isLeftEdgePoint(point) && isLeftToRight) ||
2297                      (dom.isRightEdgePoint(point) && isLeftToRight && dom.isVoid(point.node.nextSibling)) ||
2298                      (dom.isLeftEdgePoint(point) && !isLeftToRight && dom.isVoid(point.node.previousSibling)) ||
2299                      (dom.isBlock(point.node) && dom.isEmpty(point.node))) {
2300                      return point;
2301                  }
2302              }
2303              // point on block's edge
2304              var block = dom.ancestor(point.node, dom.isBlock);
2305              if (((dom.isLeftEdgePointOf(point, block) || dom.isVoid(dom.prevPoint(point).node)) && !isLeftToRight) ||
2306                  ((dom.isRightEdgePointOf(point, block) || dom.isVoid(dom.nextPoint(point).node)) && isLeftToRight)) {
2307                  // returns point already on visible point
2308                  if (dom.isVisiblePoint(point)) {
2309                      return point;
2310                  }
2311                  // reverse direction
2312                  isLeftToRight = !isLeftToRight;
2313              }
2314              var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint)
2315                  : dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);
2316              return nextPoint || point;
2317          };
2318          var endPoint = getVisiblePoint(this.getEndPoint(), false);
2319          var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);
2320          return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
2321      };
2322      /**
2323       * returns matched nodes on range
2324       *
2325       * @param {Function} [pred] - predicate function
2326       * @param {Object} [options]
2327       * @param {Boolean} [options.includeAncestor]
2328       * @param {Boolean} [options.fullyContains]
2329       * @return {Node[]}
2330       */
2331      WrappedRange.prototype.nodes = function (pred, options) {
2332          pred = pred || func.ok;
2333          var includeAncestor = options && options.includeAncestor;
2334          var fullyContains = options && options.fullyContains;
vendor: 6,859 bytes, lines 2335-2513
2335          // TODO compare points and sort
2336          var startPoint = this.getStartPoint();
2337          var endPoint = this.getEndPoint();
2338          var nodes = [];
2339          var leftEdgeNodes = [];
2340          dom.walkPoint(startPoint, endPoint, function (point) {
2341              if (dom.isEditable(point.node)) {
2342                  return;
2343              }
2344              var node;
2345              if (fullyContains) {
2346                  if (dom.isLeftEdgePoint(point)) {
2347                      leftEdgeNodes.push(point.node);
2348                  }
2349                  if (dom.isRightEdgePoint(point) && lists.contains(leftEdgeNodes, point.node)) {
2350                      node = point.node;
2351                  }
2352              }
2353              else if (includeAncestor) {
2354                  node = dom.ancestor(point.node, pred);
2355              }
2356              else {
2357                  node = point.node;
2358              }
2359              if (node && pred(node)) {
2360                  nodes.push(node);
2361              }
2362          }, true);
2363          return lists.unique(nodes);
2364      };
2365      /**
2366       * returns commonAncestor of range
2367       * @return {Element} - commonAncestor
2368       */
2369      WrappedRange.prototype.commonAncestor = function () {
2370          return dom.commonAncestor(this.sc, this.ec);
2371      };
2372      /**
2373       * returns expanded range by pred
2374       *
2375       * @param {Function} pred - predicate function
2376       * @return {WrappedRange}
2377       */
2378      WrappedRange.prototype.expand = function (pred) {
2379          var startAncestor = dom.ancestor(this.sc, pred);
2380          var endAncestor = dom.ancestor(this.ec, pred);
2381          if (!startAncestor && !endAncestor) {
2382              return new WrappedRange(this.sc, this.so, this.ec, this.eo);
2383          }
2384          var boundaryPoints = this.getPoints();
2385          if (startAncestor) {
2386              boundaryPoints.sc = startAncestor;
2387              boundaryPoints.so = 0;
2388          }
2389          if (endAncestor) {
2390              boundaryPoints.ec = endAncestor;
2391              boundaryPoints.eo = dom.nodeLength(endAncestor);
2392          }
2393          return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
2394      };
2395      /**
2396       * @param {Boolean} isCollapseToStart
2397       * @return {WrappedRange}
2398       */
2399      WrappedRange.prototype.collapse = function (isCollapseToStart) {
2400          if (isCollapseToStart) {
2401              return new WrappedRange(this.sc, this.so, this.sc, this.so);
2402          }
2403          else {
2404              return new WrappedRange(this.ec, this.eo, this.ec, this.eo);
2405          }
2406      };
2407      /**
2408       * splitText on range
2409       */
2410      WrappedRange.prototype.splitText = function () {
2411          var isSameContainer = this.sc === this.ec;
2412          var boundaryPoints = this.getPoints();
2413          if (dom.isText(this.ec) && !dom.isEdgePoint(this.getEndPoint())) {
2414              this.ec.splitText(this.eo);
2415          }
2416          if (dom.isText(this.sc) && !dom.isEdgePoint(this.getStartPoint())) {
2417              boundaryPoints.sc = this.sc.splitText(this.so);
2418              boundaryPoints.so = 0;
2419              if (isSameContainer) {
2420                  boundaryPoints.ec = boundaryPoints.sc;
2421                  boundaryPoints.eo = this.eo - this.so;
2422              }
2423          }
2424          return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
2425      };
2426      /**
2427       * delete contents on range
2428       * @return {WrappedRange}
2429       */
2430      WrappedRange.prototype.deleteContents = function () {
2431          if (this.isCollapsed()) {
2432              return this;
2433          }
2434          var rng = this.splitText();
2435          var nodes = rng.nodes(null, {
2436              fullyContains: true
2437          });
2438          // find new cursor point
2439          var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {
2440              return !lists.contains(nodes, point.node);
2441          });
2442          var emptyParents = [];
2443          $$1.each(nodes, function (idx, node) {
2444              // find empty parents
2445              var parent = node.parentNode;
2446              if (point.node !== parent && dom.nodeLength(parent) === 1) {
2447                  emptyParents.push(parent);
2448              }
2449              dom.remove(node, false);
2450          });
2451          // remove empty parents
2452          $$1.each(emptyParents, function (idx, node) {
2453              dom.remove(node, false);
2454          });
2455          return new WrappedRange(point.node, point.offset, point.node, point.offset).normalize();
2456      };
2457      /**
2458       * makeIsOn: return isOn(pred) function
2459       */
2460      WrappedRange.prototype.makeIsOn = function (pred) {
2461          return function () {
2462              var ancestor = dom.ancestor(this.sc, pred);
2463              return !!ancestor && (ancestor === dom.ancestor(this.ec, pred));
2464          };
2465      };
2466      /**
2467       * @param {Function} pred
2468       * @return {Boolean}
2469       */
2470      WrappedRange.prototype.isLeftEdgeOf = function (pred) {
2471          if (!dom.isLeftEdgePoint(this.getStartPoint())) {
2472              return false;
2473          }
2474          var node = dom.ancestor(this.sc, pred);
2475          return node && dom.isLeftEdgeOf(this.sc, node);
2476      };
2477      /**
2478       * returns whether range was collapsed or not
2479       */
2480      WrappedRange.prototype.isCollapsed = function () {
2481          return this.sc === this.ec && this.so === this.eo;
2482      };
2483      /**
2484       * wrap inline nodes which children of body with paragraph
2485       *
2486       * @return {WrappedRange}
2487       */
2488      WrappedRange.prototype.wrapBodyInlineWithPara = function () {
2489          if (dom.isBodyContainer(this.sc) && dom.isEmpty(this.sc)) {
2490              this.sc.innerHTML = dom.emptyPara;
2491              return new WrappedRange(this.sc.firstChild, 0, this.sc.firstChild, 0);
2492          }
2493          /**
2494           * [workaround] firefox often create range on not visible point. so normalize here.
2495           *  - firefox: |<p>text</p>|
2496           *  - chrome: <p>|text|</p>
2497           */
2498          var rng = this.normalize();
2499          if (dom.isParaInline(this.sc) || dom.isPara(this.sc)) {
2500              return rng;
2501          }
2502          // find inline top ancestor
2503          var topAncestor;
2504          if (dom.isInline(rng.sc)) {
2505              var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));
2506              topAncestor = lists.last(ancestors);
2507              if (!dom.isInline(topAncestor)) {
2508                  topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];
2509              }
2510          }
2511          else {
2512              topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];
2513          }
2514          // siblings not in paragraph
2515          var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();
2516          inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));
2517          // wrap with paragraph
2518          if (inlineSiblings.length) {
2519              var para = dom.wrap(lists.head(inlineSiblings), 'p');
2520              dom.appendChildNodes(para, lists.tail(inlineSiblings));
2521          }
2522          return this.normalize();
2523      };
2524      /**
2525       * insert node at current cursor
2526       *
2527       * @param {Node} node
2528       * @return {Node}
2529       */
2530      WrappedRange.prototype.insertNode = function (node) {
2531          var rng = this.wrapBodyInlineWithPara().deleteContents();
2532          var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));
2533          if (info.rightNode) {
2534              info.rightNode.parentNode.insertBefore(node, info.rightNode);
2535          }
2536          else {
2537              info.container.appendChild(node);
2538          }
2539          return node;
2540      };
2541      /**
2542       * insert html at current cursor
2543       */
2544      WrappedRange.prototype.pasteHTML = function (markup) {
2545          var contentsContainer = $$1('<div></div>').html(markup)[0];
2546          var childNodes = lists.from(contentsContainer.childNodes);
2547          var rng = this.wrapBodyInlineWithPara().deleteContents();
2548          if (rng.so > 0) {
2549              childNodes = childNodes.reverse();
2550          }
2551          childNodes = childNodes.map(function (childNode) {
2552              return rng.insertNode(childNode);
2553          });
2554          if (rng.so > 0) {
2555              childNodes = childNodes.reverse();
2556          }
2557          return childNodes;
2558      };
2559      /**
2560       * returns text in range
2561       *
2562       * @return {String}
2563       */
2564      WrappedRange.prototype.toString = function () {
2565          var nativeRng = this.nativeRange();
2566          return env.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
2567      };
2568      /**
2569       * returns range for word before cursor
2570       *
2571       * @param {Boolean} [findAfter] - find after cursor, default: false
2572       * @return {WrappedRange}
2573       */
2574      WrappedRange.prototype.getWordRange = function (findAfter) {
2575          var endPoint = this.getEndPoint();
2576          if (!dom.isCharPoint(endPoint)) {
2577              return this;
2578          }
2579          var startPoint = dom.prevPointUntil(endPoint, function (point) {
2580              return !dom.isCharPoint(point);
2581          });
2582          if (findAfter) {
2583              endPoint = dom.nextPointUntil(endPoint, function (point) {
2584                  return !dom.isCharPoint(point);
2585              });
2586          }
2587          return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
2588      };
2589      /**
2590       * create offsetPath bookmark
2591       *
2592       * @param {Node} editable
2593       */
2594      WrappedRange.prototype.bookmark = function (editable) {
2595          return {
2596              s: {
2597                  path: dom.makeOffsetPath(editable, this.sc),
2598                  offset: this.so
2599              },
2600              e: {
2601                  path: dom.makeOffsetPath(editable, this.ec),
2602                  offset: this.eo
2603              }
2604          };
2605      };
2606      /**
2607       * create offsetPath bookmark base on paragraph
2608       *
2609       * @param {Node[]} paras
2610       */
2611      WrappedRange.prototype.paraBookmark = function (paras) {
2612          return {
2613              s: {
2614                  path: lists.tail(dom.makeOffsetPath(lists.head(paras), this.sc)),
2615                  offset: this.so
2616              },
2617              e: {
2618                  path: lists.tail(dom.makeOffsetPath(lists.last(paras), this.ec)),
2619                  offset: this.eo
2620              }
2621          };
2622      };
2623      /**
2624       * getClientRects
2625       * @return {Rect[]}
2626       */
2627      WrappedRange.prototype.getClientRects = function () {
2628          var nativeRng = this.nativeRange();
2629          return nativeRng.getClientRects();
2630      };
2631      return WrappedRange;
2632  }());
2633  /**
2634   * Data structure
2635   *  * BoundaryPoint: a point of dom tree
2636   *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range
2637   *
2638   * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position
2639   */
2640  var range = {
2641      /**
2642       * create Range Object From arguments or Browser Selection
2643       *
2644       * @param {Node} sc - start container
2645       * @param {Number} so - start offset
2646       * @param {Node} ec - end container
2647       * @param {Number} eo - end offset
2648       * @return {WrappedRange}
2649       */
2650      create: function (sc, so, ec, eo) {
2651          if (arguments.length === 4) {
2652              return new WrappedRange(sc, so, ec, eo);
2653          }
2654          else if (arguments.length === 2) { // collapsed
2655              ec = sc;
2656              eo = so;
2657              return new WrappedRange(sc, so, ec, eo);
2658          }
2659          else {
2660              var wrappedRange = this.createFromSelection();
2661              if (!wrappedRange && arguments.length === 1) {
2662                  wrappedRange = this.createFromNode(arguments[0]);
2663                  return wrappedRange.collapse(dom.emptyPara === arguments[0].innerHTML);
2664              }
2665              return wrappedRange;
2666          }
2667      },
2668      createFromSelection: function () {
2669          var sc, so, ec, eo;
2670          if (env.isW3CRangeSupport) {
2671              var selection = document.getSelection();
2672              if (!selection || selection.rangeCount === 0) {
2673                  return null;
2674              }
2675              else if (dom.isBody(selection.anchorNode)) {
2676                  // Firefox: returns entire body as range on initialization.
2677                  // We won't never need it.
2678                  return null;
2679              }
2680              var nativeRng = selection.getRangeAt(0);
vendor: 4,839 bytes, lines 2681-2846
2681              sc = nativeRng.startContainer;
2682              so = nativeRng.startOffset;
2683              ec = nativeRng.endContainer;
2684              eo = nativeRng.endOffset;
2685          }
2686          else { // IE8: TextRange
2687              var textRange = document.selection.createRange();
2688              var textRangeEnd = textRange.duplicate();
2689              textRangeEnd.collapse(false);
2690              var textRangeStart = textRange;
2691              textRangeStart.collapse(true);
2692              var startPoint = textRangeToPoint(textRangeStart, true);
2693              var endPoint = textRangeToPoint(textRangeEnd, false);
2694              // same visible point case: range was collapsed.
2695              if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&
2696                  dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&
2697                  endPoint.node.nextSibling === startPoint.node) {
2698                  startPoint = endPoint;
2699              }
2700              sc = startPoint.cont;
2701              so = startPoint.offset;
2702              ec = endPoint.cont;
2703              eo = endPoint.offset;
2704          }
2705          return new WrappedRange(sc, so, ec, eo);
2706      },
2707      /**
2708       * @method
2709       *
2710       * create WrappedRange from node
2711       *
2712       * @param {Node} node
2713       * @return {WrappedRange}
2714       */
2715      createFromNode: function (node) {
2716          var sc = node;
2717          var so = 0;
2718          var ec = node;
2719          var eo = dom.nodeLength(ec);
2720          // browsers can't target a picture or void node
2721          if (dom.isVoid(sc)) {
2722              so = dom.listPrev(sc).length - 1;
2723              sc = sc.parentNode;
2724          }
2725          if (dom.isBR(ec)) {
2726              eo = dom.listPrev(ec).length - 1;
2727              ec = ec.parentNode;
2728          }
2729          else if (dom.isVoid(ec)) {
2730              eo = dom.listPrev(ec).length;
2731              ec = ec.parentNode;
2732          }
2733          return this.create(sc, so, ec, eo);
2734      },
2735      /**
2736       * create WrappedRange from node after position
2737       *
2738       * @param {Node} node
2739       * @return {WrappedRange}
2740       */
2741      createFromNodeBefore: function (node) {
2742          return this.createFromNode(node).collapse(true);
2743      },
2744      /**
2745       * create WrappedRange from node after position
2746       *
2747       * @param {Node} node
2748       * @return {WrappedRange}
2749       */
2750      createFromNodeAfter: function (node) {
2751          return this.createFromNode(node).collapse();
2752      },
2753      /**
2754       * @method
2755       *
2756       * create WrappedRange from bookmark
2757       *
2758       * @param {Node} editable
2759       * @param {Object} bookmark
2760       * @return {WrappedRange}
2761       */
2762      createFromBookmark: function (editable, bookmark) {
2763          var sc = dom.fromOffsetPath(editable, bookmark.s.path);
2764          var so = bookmark.s.offset;
2765          var ec = dom.fromOffsetPath(editable, bookmark.e.path);
2766          var eo = bookmark.e.offset;
2767          return new WrappedRange(sc, so, ec, eo);
2768      },
2769      /**
2770       * @method
2771       *
2772       * create WrappedRange from paraBookmark
2773       *
2774       * @param {Object} bookmark
2775       * @param {Node[]} paras
2776       * @return {WrappedRange}
2777       */
2778      createFromParaBookmark: function (bookmark, paras) {
2779          var so = bookmark.s.offset;
2780          var eo = bookmark.e.offset;
2781          var sc = dom.fromOffsetPath(lists.head(paras), bookmark.s.path);
2782          var ec = dom.fromOffsetPath(lists.last(paras), bookmark.e.path);
2783          return new WrappedRange(sc, so, ec, eo);
2784      }
2785  };
2786
2787  var KEY_MAP = {
2788      'BACKSPACE': 8,
2789      'TAB': 9,
2790      'ENTER': 13,
2791      'SPACE': 32,
2792      'DELETE': 46,
2793      // Arrow
2794      'LEFT': 37,
2795      'UP': 38,
2796      'RIGHT': 39,
2797      'DOWN': 40,
2798      // Number: 0-9
2799      'NUM0': 48,
2800      'NUM1': 49,
2801      'NUM2': 50,
2802      'NUM3': 51,
2803      'NUM4': 52,
2804      'NUM5': 53,
2805      'NUM6': 54,
2806      'NUM7': 55,
2807      'NUM8': 56,
2808      // Alphabet: a-z
2809      'B': 66,
2810      'E': 69,
2811      'I': 73,
2812      'J': 74,
2813      'K': 75,
2814      'L': 76,
2815      'R': 82,
2816      'S': 83,
2817      'U': 85,
2818      'V': 86,
2819      'Y': 89,
2820      'Z': 90,
2821      'SLASH': 191,
2822      'LEFTBRACKET': 219,
2823      'BACKSLASH': 220,
2824      'RIGHTBRACKET': 221
2825  };
2826  /**
2827   * @class core.key
2828   *
2829   * Object for keycodes.
2830   *
2831   * @singleton
2832   * @alternateClassName key
2833   */
2834  var key = {
2835      /**
2836       * @method isEdit
2837       *
2838       * @param {Number} keyCode
2839       * @return {Boolean}
2840       */
2841      isEdit: function (keyCode) {
2842          return lists.contains([
2843              KEY_MAP.BACKSPACE,
2844              KEY_MAP.TAB,
2845              KEY_MAP.ENTER,
2846              KEY_MAP.SPACE,
2847              KEY_MAP.DELETE,
2848          ], keyCode);
2849      },
2850      /**
2851       * @method isMove
2852       *
2853       * @param {Number} keyCode
2854       * @return {Boolean}
2855       */
2856      isMove: function (keyCode) {
2857          return lists.contains([
2858              KEY_MAP.LEFT,
2859              KEY_MAP.UP,
2860              KEY_MAP.RIGHT,
2861              KEY_MAP.DOWN,
2862          ], keyCode);
2863      },
2864      /**
2865       * @property {Object} nameFromCode
2866       * @property {String} nameFromCode.8 "BACKSPACE"
2867       */
2868      nameFromCode: func.invertObject(KEY_MAP),
2869      code: KEY_MAP
2870  };
2871
2872  /**
2873   * @method readFileAsDataURL
2874   *
2875   * read contents of file as representing URL
2876   *
2877   * @param {File} file
2878   * @return {Promise} - then: dataUrl
2879   */
2880  function readFileAsDataURL(file) {
2881      return $$1.Deferred(function (deferred) {
2882          $$1.extend(new FileReader(), {
2883              onload: function (e) {
2884                  var dataURL = e.target.result;
2885                  deferred.resolve(dataURL);
2886              },
2887              onerror: function (err) {
2888                  deferred.reject(err);
2889              }
2890          }).readAsDataURL(file);
2891      }).promise();
2892  }
2893  /**
2894   * @method createImage
2895   *
2896   * create `<image>` from url string
2897   *
2898   * @param {String} url
2899   * @return {Promise} - then: $image
2900   */
2901  function createImage(url) {
2902      return $$1.Deferred(function (deferred) {
2903          var $img = $$1('<img>');
2904          $img.one('load', function () {
2905              $img.off('error abort');
2906              deferred.resolve($img);
2907          }).one('error abort', function () {
2908              $img.off('load').detach();
2909              deferred.reject($img);
2910          }).css({
2911              display: 'none'
2912          }).appendTo(document.body).attr('src', url);
2913      }).promise();
2914  }
2915
2916  var History = /** @class */ (function () {
2917      function History($editable) {
2918          this.stack = [];
2919          this.stackOffset = -1;
2920          this.$editable = $editable;
2921          this.editable = $editable[0];
2922      }
2923      History.prototype.makeSnapshot = function () {
2924          var rng = range.create(this.editable);
2925          var emptyBookmark = { s: { path: [], offset: 0 }, e: { path: [], offset: 0 } };
2926          return {
2927              contents: this.$editable.html(),
2928              bookmark: ((rng && rng.isOnEditable()) ? rng.bookmark(this.editable) : emptyBookmark)
2929          };
2930      };
2931      History.prototype.applySnapshot = function (snapshot) {
2932          if (snapshot.contents !== null) {
2933              this.$editable.html(snapshot.contents);
2934          }
2935          if (snapshot.bookmark !== null) {
2936              range.createFromBookmark(this.editable, snapshot.bookmark).select();
2937          }
2938      };
2939      /**
2940      * @method rewind
2941      * Rewinds the history stack back to the first snapshot taken.
2942      * Leaves the stack intact, so that "Redo" can still be used.
2943      */
2944      History.prototype.rewind = function () {
2945          // Create snap shot if not yet recorded
2946          if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
2947              this.recordUndo();
2948          }
2949          // Return to the first available snapshot.
2950          this.stackOffset = 0;
2951          // Apply that snapshot.
2952          this.applySnapshot(this.stack[this.stackOffset]);
2953      };
2954      /**
2955      *  @method commit
2956      *  Resets history stack, but keeps current editor's content.
2957      */
2958      History.prototype.commit = function () {
2959          // Clear the stack.
2960          this.stack = [];
2961          // Restore stackOffset to its original value.
2962          this.stackOffset = -1;
2963          // Record our first snapshot (of nothing).
2964          this.recordUndo();
2965      };
2966      /**
2967      * @method reset
2968      * Resets the history stack completely; reverting to an empty editor.
2969      */
2970      History.prototype.reset = function () {
2971          // Clear the stack.
2972          this.stack = [];
2973          // Restore stackOffset to its original value.
2974          this.stackOffset = -1;
2975          // Clear the editable area.
2976          this.$editable.html('');
2977          // Record our first snapshot (of nothing).
2978          this.recordUndo();
2979      };
2980      /**
2981       * undo
2982       */
2983      History.prototype.undo = function () {
2984          // Create snap shot if not yet recorded
2985          if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
2986              this.recordUndo();
2987          }
2988          if (this.stackOffset > 0) {
2989              this.stackOffset--;
2990              this.applySnapshot(this.stack[this.stackOffset]);
2991          }
2992      };
2993      /**
2994       * redo
2995       */
2996      History.prototype.redo = function () {
2997          if (this.stack.length - 1 > this.stackOffset) {
2998              this.stackOffset++;
2999              this.applySnapshot(this.stack[this.stackOffset]);
3000          }
3001      };
3002      /**
3003       * recorded undo
3004       */
3005      History.prototype.recordUndo = function () {
3006          this.stackOffset++;
3007          // Wash out stack after stackOffset
3008          if (this.stack.length > this.stackOffset) {
3009              this.stack = this.stack.slice(0, this.stackOffset);
3010          }
3011          // Create new snapshot and push it to the end
3012          this.stack.push(this.makeSnapshot());
3013      };
3014      return History;
3015  }());
3016
3017  var Style = /** @class */ (function () {
3018      function Style() {
3019      }
3020      /**
3021       * @method jQueryCSS
3022       *
3023       * [workaround] for old jQuery
3024       * passing an array of style properties to .css()
3025       * will result in an object of property-value pairs.
3026       * (compability with version < 1.9)
3027       *
3028       * @private
3029       * @param  {jQuery} $obj
3030       * @param  {Array} propertyNames - An array of one or more CSS properties.
3031       * @return {Object}
3032       */
3033      Style.prototype.jQueryCSS = function ($obj, propertyNames) {
3034          if (env.jqueryVersion < 1.9) {
3035              var result_1 = {};
3036              $$1.each(propertyNames, function (idx, propertyName) {
3037                  result_1[propertyName] = $obj.css(propertyName);
3038              });
3039              return result_1;
3040          }
3041          return $obj.css(propertyNames);
3042      };
3043      /**
3044       * returns style object from node
3045       *
3046       * @param {jQuery} $node
3047       * @return {Object}
3048       */
3049      Style.prototype.fromNode = function ($node) {
3050          var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
3051          var styleInfo = this.jQueryCSS($node, properties) || {};
3052          styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);
3053          return styleInfo;
3054      };
3055      /**
3056       * paragraph level style
3057       *
3058       * @param {WrappedRange} rng
3059       * @param {Object} styleInfo
3060       */
3061      Style.prototype.stylePara = function (rng, styleInfo) {
vendor: 4,421 bytes, lines 3062-3154
3062          $$1.each(rng.nodes(dom.isPara, {
3063              includeAncestor: true
3064          }), function (idx, para) {
3065              $$1(para).css(styleInfo);
3066          });
3067      };
3068      /**
3069       * insert and returns styleNodes on range.
3070       *
3071       * @param {WrappedRange} rng
3072       * @param {Object} [options] - options for styleNodes
3073       * @param {String} [options.nodeName] - default: `SPAN`
3074       * @param {Boolean} [options.expandClosestSibling] - default: `false`
3075       * @param {Boolean} [options.onlyPartialContains] - default: `false`
3076       * @return {Node[]}
3077       */
3078      Style.prototype.styleNodes = function (rng, options) {
3079          rng = rng.splitText();
3080          var nodeName = (options && options.nodeName) || 'SPAN';
3081          var expandClosestSibling = !!(options && options.expandClosestSibling);
3082          var onlyPartialContains = !!(options && options.onlyPartialContains);
3083          if (rng.isCollapsed()) {
3084              return [rng.insertNode(dom.create(nodeName))];
3085          }
3086          var pred = dom.makePredByNodeName(nodeName);
3087          var nodes = rng.nodes(dom.isText, {
3088              fullyContains: true
3089          }).map(function (text) {
3090              return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);
3091          });
3092          if (expandClosestSibling) {
3093              if (onlyPartialContains) {
3094                  var nodesInRange_1 = rng.nodes();
3095                  // compose with partial contains predication
3096                  pred = func.and(pred, function (node) {
3097                      return lists.contains(nodesInRange_1, node);
3098                  });
3099              }
3100              return nodes.map(function (node) {
3101                  var siblings = dom.withClosestSiblings(node, pred);
3102                  var head = lists.head(siblings);
3103                  var tails = lists.tail(siblings);
3104                  $$1.each(tails, function (idx, elem) {
3105                      dom.appendChildNodes(head, elem.childNodes);
3106                      dom.remove(elem);
3107                  });
3108                  return lists.head(siblings);
3109              });
3110          }
3111          else {
3112              return nodes;
3113          }
3114      };
3115      /**
3116       * get current style on cursor
3117       *
3118       * @param {WrappedRange} rng
3119       * @return {Object} - object contains style properties.
3120       */
3121      Style.prototype.current = function (rng) {
3122          var $cont = $$1(!dom.isElement(rng.sc) ? rng.sc.parentNode : rng.sc);
3123          var styleInfo = this.fromNode($cont);
3124          // document.queryCommandState for toggle state
3125          // [workaround] prevent Firefox nsresult: "0x80004005 (NS_ERROR_FAILURE)"
3126          try {
3127              styleInfo = $$1.extend(styleInfo, {
3128                  'font-bold': document.queryCommandState('bold') ? 'bold' : 'normal',
3129                  'font-italic': document.queryCommandState('italic') ? 'italic' : 'normal',
3130                  'font-underline': document.queryCommandState('underline') ? 'underline' : 'normal',
3131                  'font-subscript': document.queryCommandState('subscript') ? 'subscript' : 'normal',
3132                  'font-superscript': document.queryCommandState('superscript') ? 'superscript' : 'normal',
3133                  'font-strikethrough': document.queryCommandState('strikethrough') ? 'strikethrough' : 'normal',
3134                  'font-family': document.queryCommandValue('fontname') || styleInfo['font-family']
3135              });
3136          }
3137          catch (e) { }
3138          // list-style-type to list-style(unordered, ordered)
3139          if (!rng.isOnList()) {
3140              styleInfo['list-style'] = 'none';
3141          }
3142          else {
3143              var orderedTypes = ['circle', 'disc', 'disc-leading-zero', 'square'];
3144              var isUnordered = orderedTypes.indexOf(styleInfo['list-style-type']) > -1;
3145              styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';
3146          }
3147          var para = dom.ancestor(rng.sc, dom.isPara);
3148          if (para && para.style['line-height']) {
3149              styleInfo['line-height'] = para.style.lineHeight;
3150          }
3151          else {
3152              var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);
3153              styleInfo['line-height'] = lineHeight.toFixed(1);
3154          }
3155          styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
3156          styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);
3157          styleInfo.range = rng;
3158          return styleInfo;
3159      };
3160      return Style;
3161  }());
3162
3163  var Bullet = /** @class */ (function () {
3164      function Bullet() {
3165      }
3166      /**
3167       * toggle ordered list
3168       */
3169      Bullet.prototype.insertOrderedList = function (editable) {
3170          this.toggleList('OL', editable);
3171      };
3172      /**
3173       * toggle unordered list
3174       */
3175      Bullet.prototype.insertUnorderedList = function (editable) {
3176          this.toggleList('UL', editable);
3177      };
3178      /**
3179       * indent
3180       */
3181      Bullet.prototype.indent = function (editable) {
3182          var _this = this;
3183          var rng = range.create(editable).wrapBodyInlineWithPara();
3184          var paras = rng.nodes(dom.isPara, { includeAncestor: true });
3185          var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
3186          $$1.each(clustereds, function (idx, paras) {
3187              var head = lists.head(paras);
3188              if (dom.isLi(head)) {
3189                  var previousList_1 = _this.findList(head.previousSibling);
3190                  if (previousList_1) {
3191                      paras
3192                          .map(function (para) { return previousList_1.appendChild(para); });
3193                  }
3194                  else {
3195                      _this.wrapList(paras, head.parentNode.nodeName);
3196                      paras
3197                          .map(function (para) { return para.parentNode; })
3198                          .map(function (para) { return _this.appendToPrevious(para); });
3199                  }
3200              }
3201              else {
3202                  $$1.each(paras, function (idx, para) {
3203                      $$1(para).css('marginLeft', function (idx, val) {
3204                          return (parseInt(val, 10) || 0) + 25;
3205                      });
3206                  });
3207              }
3208          });
3209          rng.select();
3210      };
3211      /**
3212       * outdent
3213       */
3214      Bullet.prototype.outdent = function (editable) {
3215          var _this = this;
3216          var rng = range.create(editable).wrapBodyInlineWithPara();
3217          var paras = rng.nodes(dom.isPara, { includeAncestor: true });
3218          var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
3219          $$1.each(clustereds, function (idx, paras) {
3220              var head = lists.head(paras);
3221              if (dom.isLi(head)) {
3222                  _this.releaseList([paras]);
3223              }
3224              else {
3225                  $$1.each(paras, function (idx, para) {
3226                      $$1(para).css('marginLeft', function (idx, val) {
3227                          val = (parseInt(val, 10) || 0);
3228                          return val > 25 ? val - 25 : '';
3229                      });
3230                  });
3231              }
3232          });
3233          rng.select();
3234      };
3235      /**
3236       * toggle list
3237       *
3238       * @param {String} listName - OL or UL
3239       */
3240      Bullet.prototype.toggleList = function (listName, editable) {
3241          var _this = this;
3242          var rng = range.create(editable).wrapBodyInlineWithPara();
3243          var paras = rng.nodes(dom.isPara, { includeAncestor: true });
3244          var bookmark = rng.paraBookmark(paras);
3245          var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
3246          // paragraph to list
3247          if (lists.find(paras, dom.isPurePara)) {
3248              var wrappedParas_1 = [];
3249              $$1.each(clustereds, function (idx, paras) {
3250                  wrappedParas_1 = wrappedParas_1.concat(_this.wrapList(paras, listName));
3251              });
3252              paras = wrappedParas_1;
3253              // list to paragraph or change list style
3254          }
3255          else {
3256              var diffLists = rng.nodes(dom.isList, {
3257                  includeAncestor: true
3258              }).filter(function (listNode) {
3259                  return !$$1.nodeName(listNode, listName);
3260              });
3261              if (diffLists.length) {
3262                  $$1.each(diffLists, function (idx, listNode) {
3263                      dom.replace(listNode, listName);
3264                  });
3265              }
3266              else {
3267                  paras = this.releaseList(clustereds, true);
3268              }
3269          }
3270          range.createFromParaBookmark(bookmark, paras).select();
3271      };
3272      /**
3273       * @param {Node[]} paras
3274       * @param {String} listName
3275       * @return {Node[]}
3276       */
3277      Bullet.prototype.wrapList = function (paras, listName) {
3278          var head = lists.head(paras);
3279          var last = lists.last(paras);
3280          var prevList = dom.isList(head.previousSibling) && head.previousSibling;
3281          var nextList = dom.isList(last.nextSibling) && last.nextSibling;
vendor: 4,381 bytes, lines 3282-3380
3282          var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);
3283          // P to LI
3284          paras = paras.map(function (para) {
3285              return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;
3286          });
3287          // append to list(<ul>, <ol>)
3288          dom.appendChildNodes(listNode, paras);
3289          if (nextList) {
3290              dom.appendChildNodes(listNode, lists.from(nextList.childNodes));
3291              dom.remove(nextList);
3292          }
3293          return paras;
3294      };
3295      /**
3296       * @method releaseList
3297       *
3298       * @param {Array[]} clustereds
3299       * @param {Boolean} isEscapseToBody
3300       * @return {Node[]}
3301       */
3302      Bullet.prototype.releaseList = function (clustereds, isEscapseToBody) {
3303          var _this = this;
3304          var releasedParas = [];
3305          $$1.each(clustereds, function (idx, paras) {
3306              var head = lists.head(paras);
3307              var last = lists.last(paras);
3308              var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) : head.parentNode;
3309              var parentItem = headList.parentNode;
3310              if (headList.parentNode.nodeName === 'LI') {
3311                  paras.map(function (para) {
3312                      var newList = _this.findNextSiblings(para);
3313                      if (parentItem.nextSibling) {
3314                          parentItem.parentNode.insertBefore(para, parentItem.nextSibling);
3315                      }
3316                      else {
3317                          parentItem.parentNode.appendChild(para);
3318                      }
3319                      if (newList.length) {
3320                          _this.wrapList(newList, headList.nodeName);
3321                          para.appendChild(newList[0].parentNode);
3322                      }
3323                  });
3324                  if (headList.children.length === 0) {
3325                      parentItem.removeChild(headList);
3326                  }
3327                  if (parentItem.childNodes.length === 0) {
3328                      parentItem.parentNode.removeChild(parentItem);
3329                  }
3330              }
3331              else {
3332                  var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
3333                      node: last.parentNode,
3334                      offset: dom.position(last) + 1
3335                  }, {
3336                      isSkipPaddingBlankHTML: true
3337                  }) : null;
3338                  var middleList = dom.splitTree(headList, {
3339                      node: head.parentNode,
3340                      offset: dom.position(head)
3341                  }, {
3342                      isSkipPaddingBlankHTML: true
3343                  });
3344                  paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi)
3345                      : lists.from(middleList.childNodes).filter(dom.isLi);
3346                  // LI to P
3347                  if (isEscapseToBody || !dom.isList(headList.parentNode)) {
3348                      paras = paras.map(function (para) {
3349                          return dom.replace(para, 'P');
3350                      });
3351                  }
3352                  $$1.each(lists.from(paras).reverse(), function (idx, para) {
3353                      dom.insertAfter(para, headList);
3354                  });
3355                  // remove empty lists
3356                  var rootLists = lists.compact([headList, middleList, lastList]);
3357                  $$1.each(rootLists, function (idx, rootList) {
3358                      var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));
3359                      $$1.each(listNodes.reverse(), function (idx, listNode) {
3360                          if (!dom.nodeLength(listNode)) {
3361                              dom.remove(listNode, true);
3362                          }
3363                      });
3364                  });
3365              }
3366              releasedParas = releasedParas.concat(paras);
3367          });
3368          return releasedParas;
3369      };
3370      /**
3371       * @method appendToPrevious
3372       *
3373       * Appends list to previous list item, if
3374       * none exist it wraps the list in a new list item.
3375       *
3376       * @param {HTMLNode} ListItem
3377       * @return {HTMLNode}
3378       */
3379      Bullet.prototype.appendToPrevious = function (node) {
3380          return node.previousSibling
3381              ? dom.appendChildNodes(node.previousSibling, [node])
3382              : this.wrapList([node], 'LI');
3383      };
3384      /**
3385       * @method findList
3386       *
3387       * Finds an existing list in list item
3388       *
3389       * @param {HTMLNode} ListItem
3390       * @return {Array[]}
3391       */
3392      Bullet.prototype.findList = function (node) {
3393          return node
3394              ? lists.find(node.children, function (child) { return ['OL', 'UL'].indexOf(child.nodeName) > -1; })
3395              : null;
3396      };
3397      /**
3398       * @method findNextSiblings
3399       *
3400       * Finds all list item siblings that follow it
3401       *
3402       * @param {HTMLNode} ListItem
3403       * @return {HTMLNode}
3404       */
3405      Bullet.prototype.findNextSiblings = function (node) {
3406          var siblings = [];
3407          while (node.nextSibling) {
3408              siblings.push(node.nextSibling);
3409              node = node.nextSibling;
3410          }
3411          return siblings;
3412      };
3413      return Bullet;
3414  }());
3415
3416  /**
3417   * @class editing.Typing
3418   *
3419   * Typing
3420   *
3421   */
3422  var Typing = /** @class */ (function () {
3423      function Typing(context) {
3424          // a Bullet instance to toggle lists off
3425          this.bullet = new Bullet();
3426          this.options = context.options;
3427      }
3428      /**
3429       * insert tab
3430       *
3431       * @param {WrappedRange} rng
3432       * @param {Number} tabsize
3433       */
3434      Typing.prototype.insertTab = function (rng, tabsize) {
3435          var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));
3436          rng = rng.deleteContents();
3437          rng.insertNode(tab, true);
3438          rng = range.create(tab, tabsize);
3439          rng.select();
3440      };
3441      /**
3442       * insert paragraph
3443       *
3444       * @param {jQuery} $editable
3445       * @param {WrappedRange} rng Can be used in unit tests to "mock" the range
3446       *
3447       * blockquoteBreakingLevel
3448       *   0 - No break, the new paragraph remains inside the quote
3449       *   1 - Break the first blockquote in the ancestors list
3450       *   2 - Break all blockquotes, so that the new paragraph is not quoted (this is the default)
3451       */
3452      Typing.prototype.insertParagraph = function (editable, rng) {
3453          rng = rng || range.create(editable);
3454          // deleteContents on range.
3455          rng = rng.deleteContents();
3456          // Wrap range if it needs to be wrapped by paragraph
3457          rng = rng.wrapBodyInlineWithPara();
3458          // finding paragraph
3459          var splitRoot = dom.ancestor(rng.sc, dom.isPara);
3460          var nextPara;
3461          // on paragraph: split paragraph
3462          if (splitRoot) {
3463              // if it is an empty line with li
3464              if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {
3465                  // toogle UL/OL and escape
3466                  this.bullet.toggleList(splitRoot.parentNode.nodeName);
3467                  return;
3468              }
3469              else {
3470                  var blockquote = null;
3471                  if (this.options.blockquoteBreakingLevel === 1) {
3472                      blockquote = dom.ancestor(splitRoot, dom.isBlockquote);
3473                  }
3474                  else if (this.options.blockquoteBreakingLevel === 2) {
3475                      blockquote = dom.lastAncestor(splitRoot, dom.isBlockquote);
3476                  }
3477                  if (blockquote) {
3478                      // We're inside a blockquote and options ask us to break it
3479                      nextPara = $$1(dom.emptyPara)[0];
3480                      // If the split is right before a <br>, remove it so that there's no "empty line"
3481                      // after the split in the new blockquote created
3482                      if (dom.isRightEdgePoint(rng.getStartPoint()) && dom.isBR(rng.sc.nextSibling)) {
3483                          $$1(rng.sc.nextSibling).remove();
3484                      }
3485                      var split = dom.splitTree(blockquote, rng.getStartPoint(), { isDiscardEmptySplits: true });
3486                      if (split) {
3487                          split.parentNode.insertBefore(nextPara, split);
3488                      }
3489                      else {
3490                          dom.insertAfter(nextPara, blockquote); // There's no split if we were at the end of the blockquote
3491                      }
3492                  }
3493                  else {
3494                      nextPara = dom.splitTree(splitRoot, rng.getStartPoint());
3495                      // not a blockquote, just insert the paragraph
3496                      var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);
3497                      emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));
3498                      $$1.each(emptyAnchors, function (idx, anchor) {
3499                          dom.remove(anchor);
3500                      });
3501                      // replace empty heading, pre or custom-made styleTag with P tag
3502                      if ((dom.isHeading(nextPara) || dom.isPre(nextPara) || dom.isCustomStyleTag(nextPara)) && dom.isEmpty(nextPara)) {
3503                          nextPara = dom.replace(nextPara, 'p');
3504                      }
3505                  }
3506              }
3507              // no paragraph: insert empty paragraph
3508          }
3509          else {
3510              var next = rng.sc.childNodes[rng.so];
3511              nextPara = $$1(dom.emptyPara)[0];
3512              if (next) {
3513                  rng.sc.insertBefore(nextPara, next);
3514              }
3515              else {
3516                  rng.sc.appendChild(nextPara);
3517              }
3518          }
3519          range.create(nextPara, 0).normalize().select().scrollIntoView(editable);
3520      };
3521      return Typing;
3522  }());
3523
3524  /**
3525   * @class Create a virtual table to create what actions to do in change.
3526   * @param {object} startPoint Cell selected to apply change.
3527   * @param {enum} where  Where change will be applied Row or Col. Use enum: TableResultAction.where
3528   * @param {enum} action Action to be applied. Use enum: TableResultAction.requestAction
3529   * @param {object} domTable Dom element of table to make changes.
3530   */
3531  var TableResultAction = function (startPoint, where, action, domTable) {
3532      var _startPoint = { 'colPos': 0, 'rowPos': 0 };
3533      var _virtualTable = [];
3534      var _actionCellList = [];
3535      /// ///////////////////////////////////////////
3536      // Private functions
3537      /// ///////////////////////////////////////////
3538      /**
3539       * Set the startPoint of action.
3540       */
3541      function setStartPoint() {
3542          if (!startPoint || !startPoint.tagName || (startPoint.tagName.toLowerCase() !== 'td' && startPoint.tagName.toLowerCase() !== 'th')) {
3543              console.error('Impossible to identify start Cell point.', startPoint);
3544              return;
3545          }
3546          _startPoint.colPos = startPoint.cellIndex;
3547          if (!startPoint.parentElement || !startPoint.parentElement.tagName || startPoint.parentElement.tagName.toLowerCase() !== 'tr') {
3548              console.error('Impossible to identify start Row point.', startPoint);
3549              return;
3550          }
3551          _startPoint.rowPos = startPoint.parentElement.rowIndex;
3552      }
3553      /**
3554       * Define virtual table position info object.
3555       *
3556       * @param {int} rowIndex Index position in line of virtual table.
3557       * @param {int} cellIndex Index position in column of virtual table.
3558       * @param {object} baseRow Row affected by this position.
3559       * @param {object} baseCell Cell affected by this position.
3560       * @param {bool} isSpan Inform if it is an span cell/row.
3561       */
3562      function setVirtualTablePosition(rowIndex, cellIndex, baseRow, baseCell, isRowSpan, isColSpan, isVirtualCell) {
3563          var objPosition = {
3564              'baseRow': baseRow,
3565              'baseCell': baseCell,
3566              'isRowSpan': isRowSpan,
3567              'isColSpan': isColSpan,
3568              'isVirtual': isVirtualCell
3569          };
3570          if (!_virtualTable[rowIndex]) {
3571              _virtualTable[rowIndex] = [];
3572          }
3573          _virtualTable[rowIndex][cellIndex] = objPosition;
3574      }
3575      /**
3576       * Create action cell object.
3577       *
3578       * @param {object} virtualTableCellObj Object of specific position on virtual table.
3579       * @param {enum} resultAction Action to be applied in that item.
3580       */
3581      function getActionCell(virtualTableCellObj, resultAction, virtualRowPosition, virtualColPosition) {
3582          return {
3583              'baseCell': virtualTableCellObj.baseCell,
3584              'action': resultAction,
3585              'virtualTable': {
3586                  'rowIndex': virtualRowPosition,
3587                  'cellIndex': virtualColPosition
3588              }
3589          };
3590      }
3591      /**
3592       * Recover free index of row to append Cell.
3593       *
3594       * @param {int} rowIndex Index of row to find free space.
3595       * @param {int} cellIndex Index of cell to find free space in table.
3596       */
3597      function recoverCellIndex(rowIndex, cellIndex) {
3598          if (!_virtualTable[rowIndex]) {
3599              return cellIndex;
3600          }
3601          if (!_virtualTable[rowIndex][cellIndex]) {
3602              return cellIndex;
3603          }
3604          var newCellIndex = cellIndex;
3605          while (_virtualTable[rowIndex][newCellIndex]) {
3606              newCellIndex++;
3607              if (!_virtualTable[rowIndex][newCellIndex]) {
3608                  return newCellIndex;
3609              }
3610          }
3611      }
3612      /**
3613       * Recover info about row and cell and add information to virtual table.
3614       *
3615       * @param {object} row Row to recover information.
3616       * @param {object}
vendor: 4,554 bytes, lines 3616-3716
3616 cell Cell to recover information.
3617       */
3618      function addCellInfoToVirtual(row, cell) {
3619          var cellIndex = recoverCellIndex(row.rowIndex, cell.cellIndex);
3620          var cellHasColspan = (cell.colSpan > 1);
3621          var cellHasRowspan = (cell.rowSpan > 1);
3622          var isThisSelectedCell = (row.rowIndex === _startPoint.rowPos && cell.cellIndex === _startPoint.colPos);
3623          setVirtualTablePosition(row.rowIndex, cellIndex, row, cell, cellHasRowspan, cellHasColspan, false);
3624          // Add span rows to virtual Table.
3625          var rowspanNumber = cell.attributes.rowSpan ? parseInt(cell.attributes.rowSpan.value, 10) : 0;
3626          if (rowspanNumber > 1) {
3627              for (var rp = 1; rp < rowspanNumber; rp++) {
3628                  var rowspanIndex = row.rowIndex + rp;
3629                  adjustStartPoint(rowspanIndex, cellIndex, cell, isThisSelectedCell);
3630                  setVirtualTablePosition(rowspanIndex, cellIndex, row, cell, true, cellHasColspan, true);
3631              }
3632          }
3633          // Add span cols to virtual table.
3634          var colspanNumber = cell.attributes.colSpan ? parseInt(cell.attributes.colSpan.value, 10) : 0;
3635          if (colspanNumber > 1) {
3636              for (var cp = 1; cp < colspanNumber; cp++) {
3637                  var cellspanIndex = recoverCellIndex(row.rowIndex, (cellIndex + cp));
3638                  adjustStartPoint(row.rowIndex, cellspanIndex, cell, isThisSelectedCell);
3639                  setVirtualTablePosition(row.rowIndex, cellspanIndex, row, cell, cellHasRowspan, true, true);
3640              }
3641          }
3642      }
3643      /**
3644       * Process validation and adjust of start point if needed
3645       *
3646       * @param {int} rowIndex
3647       * @param {int} cellIndex
3648       * @param {object} cell
3649       * @param {bool} isSelectedCell
3650       */
3651      function adjustStartPoint(rowIndex, cellIndex, cell, isSelectedCell) {
3652          if (rowIndex === _startPoint.rowPos && _startPoint.colPos >= cell.cellIndex && cell.cellIndex <= cellIndex && !isSelectedCell) {
3653              _startPoint.colPos++;
3654          }
3655      }
3656      /**
3657       * Create virtual table of cells with all cells, including span cells.
3658       */
3659      function createVirtualTable() {
3660          var rows = domTable.rows;
3661          for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) {
3662              var cells = rows[rowIndex].cells;
3663              for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {
3664                  addCellInfoToVirtual(rows[rowIndex], cells[cellIndex]);
3665              }
3666          }
3667      }
3668      /**
3669       * Get action to be applied on the cell.
3670       *
3671       * @param {object} cell virtual table cell to apply action
3672       */
3673      function getDeleteResultActionToCell(cell) {
3674          switch (where) {
3675              case TableResultAction.where.Column:
3676                  if (cell.isColSpan) {
3677                      return TableResultAction.resultAction.SubtractSpanCount;
3678                  }
3679                  break;
3680              case TableResultAction.where.Row:
3681                  if (!cell.isVirtual && cell.isRowSpan) {
3682                      return TableResultAction.resultAction.AddCell;
3683                  }
3684                  else if (cell.isRowSpan) {
3685                      return TableResultAction.resultAction.SubtractSpanCount;
3686                  }
3687                  break;
3688          }
3689          return TableResultAction.resultAction.RemoveCell;
3690      }
3691      /**
3692       * Get action to be applied on the cell.
3693       *
3694       * @param {object} cell virtual table cell to apply action
3695       */
3696      function getAddResultActionToCell(cell) {
3697          switch (where) {
3698              case TableResultAction.where.Column:
3699                  if (cell.isColSpan) {
3700                      return TableResultAction.resultAction.SumSpanCount;
3701                  }
3702                  else if (cell.isRowSpan && cell.isVirtual) {
3703                      return TableResultAction.resultAction.Ignore;
3704                  }
3705                  break;
3706              case TableResultAction.where.Row:
3707                  if (cell.isRowSpan) {
3708                      return TableResultAction.resultAction.SumSpanCount;
3709                  }
3710                  else if (cell.isColSpan && cell.isVirtual) {
3711                      return TableResultAction.resultAction.Ignore;
3712                  }
3713                  break;
3714          }
3715          return TableResultAction.resultAction.AddCell;
3716      }
3717      function init() {
3718          setStartPoint();
3719          createVirtualTable();
3720      }
3721      /// ///////////////////////////////////////////
3722      // Public functions
3723      /// ///////////////////////////////////////////
3724      /**
3725       * Recover array os what to do in table.
3726       */
3727      this.getActionList = function () {
3728          var fixedRow = (where === TableResultAction.where.Row) ? _startPoint.rowPos : -1;
3729          var fixedCol = (where === TableResultAction.where.Column) ? _startPoint.colPos : -1;
3730          var actualPosition = 0;
3731          var canContinue = true;
3732          while (canContinue) {
3733              var rowPosition = (fixedRow >= 0) ? fixedRow : actualPosition;
3734              var colPosition = (fixedCol >= 0) ? fixedCol : actualPosition;
3735              var row = _virtualTable[rowPosition];
3736              if (!row) {
3737                  canContinue = false;
3738                  return _actionCellList;
3739              }
3740              var cell = row[colPosition];
3741              if (!cell) {
3742                  canContinue = false;
3743                  return _actionCellList;
3744              }
3745              // Define action to be applied in this cell
3746              var resultAction = TableResultAction.resultAction.Ignore;
3747              switch (action) {
3748                  case TableResultAction.requestAction.Add:
3749                      resultAction = getAddResultActionToCell(cell);
3750                      break;
3751                  case TableResultAction.requestAction.Delete:
3752                      resultAction = getDeleteResultActionToCell(cell);
3753                      break;
3754              }
3755              _actionCellList.push(getActionCell(cell, resultAction, rowPosition, colPosition));
3756              actualPosition++;
3757          }
3758          return _actionCellList;
3759      };
3760      init();
3761  };
3762  /**
3763  *
3764  * Where action occours enum.
3765  */
3766  TableResultAction.where = { 'Row': 0, 'Column': 1 };
3767  /**
3768  *
3769  * Requested action to apply enum.
3770  */
3771  TableResultAction.requestAction = { 'Add': 0, 'Delete': 1 };
3772  /**
3773  *
3774  * Result action to be executed enum.
3775  */
3776  TableResultAction.resultAction = { 'Ignore': 0, 'SubtractSpanCount': 1, 'RemoveCell': 2, 'AddCell': 3, 'SumSpanCount': 4 };
3777  /**
3778   *
3779   * @class editing.Table
3780   *
3781   * Table
3782   *
3783   */
3784  var Table = /** @class */ (function () {
3785      function Table() {
3786      }
3787      /**
3788       * handle tab key
3789       *
3790       * @param {WrappedRange} rng
3791       * @param {Boolean} isShift
3792       */
3793      Table.prototype.tab = function (rng, isShift) {
3794          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
3795          var table = dom.ancestor(cell, dom.isTable);
3796          var cells = dom.listDescendant(table, dom.isCell);
3797          var nextCell = lists[isShift ? 'prev' : 'next'](cells, cell);
3798          if (nextCell) {
3799              range.create(nextCell, 0).select();
3800          }
3801      };
3802      /**
3803       * Add a new row
3804       *
3805       * @param {WrappedRange} rng
3806       * @param {String} position (top/bottom)
3807       * @return {Node}
3808       */
3809      Table.prototype.addRow = function (rng, position) {
3810          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
3811          var currentTr = $$1(cell).closest('tr');
3812          var trAttributes = this.recoverAttributes(currentTr);
3813          var html = $$1('<tr' + trAttributes + '></tr>');
3814          var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Add, $$1(currentTr).closest('table')[0]);
3815          var actions = vTable.getActionList();
3816          for (var idCell = 0; idCell < actions.length; idCell++) {
3817              var currentCell = actions[idCell];
3818              var tdAttributes = this.recoverAttributes(currentCell.baseCell);
3819              switch (currentCell.action) {
3820                  case TableResultAction.resultAction.AddCell:
3821                      html.append('<td' + tdAttributes + '>' + dom.blank + '</td>');
3822                      break;
3823                  case TableResultAction.resultAction.SumSpanCount:
3824                      if (position === 'top') {
3825                          var baseCellTr = currentCell.baseCell.parent;
3826                          var isTopFromRowSpan = (!baseCellTr ? 0 : currentCell.baseCell.closest('tr').rowIndex) <= currentTr[0].rowIndex;
3827                          if (isTopFromRowSpan) {
3828                              var newTd = $$1('<div></div>').append($$1('<td' + tdAttributes + '>' + dom.blank + '</td>').removeAttr('rowspan')).html();
3829                              html.append(newTd);
3830                              break;
3831                          }
3832                      }
3833                      var rowspanNumber = parseInt(currentCell.baseCell.rowSpan, 10);
3834                      rowspanNumber++;
3835                      currentCell.baseCell.setAttribute('rowSpan', rowspanNumber);
3836                      break;
3837              }
3838          }
3839          if (position === 'top') {
3840              currentTr.before(html);
3841          }
3842          else {
3843              var cellHasRowspan = (cell.rowSpan > 1);
3844              if (cellHasRowspan) {
3845                  var lastTrIndex = currentTr[0].rowIndex + (cell.rowSpan - 2);
3846                  $$1($$1(currentTr).parent().find('tr')[lastTrIndex]).after($$1(html));
3847                  return;
3848              }
3849              currentTr.after(html);
3850          }
3851      };
3852      /**
3853       * Add a new col
3854       *
3855       * @param {WrappedRange} rng
3856       * @param {String} position (left/right)
3857       * @return {Node}
3858       */
3859      Table.prototype.addCol = function (rng, position) {
3860          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
3861          var row = $$1(cell).closest('tr');
3862          var rowsGroup = $$1(row).siblings();
3863          rowsGroup.push(row);
3864          var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Add, $$1(row).closest('table')[0]);
3865          var actions = vTable.getActionList();
3866          for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
3867              var currentCell = actions[actionIndex];
3868              var tdAttributes = this.recoverAttributes(currentCell.baseCell);
3869              switch (currentCell.action) {
3870                  case TableResultAction.resultAction.AddCell:
3871                      if (position === 'right') {
3872                          $$1(currentCell.baseCell).after('<td' + tdAttributes + '>' + dom.blank + '</td>');
3873                      }
3874                      else {
3875                          $$1(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
3876                      }
3877                      break;
3878                  case TableResultAction.resultAction.SumSpanCount:
3879                      if (position === 'right') {
3880                          var colspanNumber = parseInt(currentCell.baseCell.colSpan, 10);
3881                          colspanNumber++;
3882                          currentCell.baseCell.setAttribute('colSpan', colspanNumber);
3883                      }
3884                      else {
3885                          $$1(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
3886                      }
3887                      break;
3888              }
3889          }
3890      };
3891      /*
3892      * Copy attributes from element.
3893      *
3894      * @param {object} Element to recover attributes.
3895      * @return {string} Copied string elements.
3896      */
3897      Table.prototype.recoverAttributes = function (el) {
3898          var resultStr = '';
3899          if (!el) {
3900              return resultStr;
3901          }
3902          var attrList = el.attributes || [];
3903          for (var i = 0; i < attrList.length; i++) {
3904              if (attrList[i].name.toLowerCase() === 'id') {
3905                  continue;
3906              }
3907              if (attrList[i].specified) {
3908                  resultStr += ' ' + attrList[i].name + '=\'' + attrList[i].value + '\'';
3909              }
3910          }
3911          return resultStr;
3912      };
3913      /**
3914       * Delete current row
3915       *
3916       * @param {WrappedRange} rng
3917       * @return {Node}
3918       */
3919      Table.prototype.deleteRow = function (rng) {
3920          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
3921          var row = $$1(cell).closest('tr');
3922          var cellPos = row.children('td, th').index($$1(cell));
3923          var rowPos = row[0].rowIndex;
3924          var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Delete, $$1(row).closest('table')[0]);
3925          var actions = vTable.getActionList();
3926          for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
3927              if (!actions[actionIndex]) {
3928                  continue;
3929              }
3930              var baseCell = actions[actionIndex].baseCell;
3931              var virtualPosition = actions[actionIndex].virtualTable;
3932              var hasRowspan = (baseCell.rowSpan && baseCell.rowSpan > 1);
3933              var rowspanNumber = (hasRowspan) ? parseInt(baseCell.rowSpan, 10) : 0;
3934              switch (actions[actionIndex].action) {
3935                  case TableResultAction.resultAction.Ignore:
3936                      continue;
3937                  case TableResultAction.resultAction.AddCell:
3938                      var nextRow = row.next('tr')[0];
3939                      if (!nextRow) {
3940                          continue;
3941                      }
3942                      var cloneRow = row[0].cells[cellPos];
3943                      if (hasRowspan) {
3944                          if (rowspanNumber > 2) {
3945                              rowspanNumber--;
3946                              nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
3947                              nextRow.cells[cellPos].setAttribute('rowSpan', rowspanNumber);
3948                              nextRow.cells[cellPos].innerHTML = '';
3949                          }
3950                          else if (rowspanNumber === 2) {
3951                              nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
3952                              nextRow.cells[cellPos].removeAttribute('rowSpan');
3953                              nextRow.cells[cellPos].innerHTML = '';
3954                          }
3955                      }
3956                      continue;
3957                  case TableResultAction.resultAction.SubtractSpanCount:
3958                      if (hasRowspan) {
3959                          if (rowspanNumber > 2) {
3960                              rowspanNumber--;
3961                              baseCell.setAttribute('rowSpan', rowspanNumber);
3962                              if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
3963                                  baseCell.innerHTML = '';
3964                              }
3965                          }
3966                          else if (rowspanNumber === 2) {
3967                              baseCell.removeAttribute('rowSpan');
3968                              if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
3969                                  baseCell.innerHTML = '';
3970                              }
3971                          }
3972                      }
3973                      continue;
3974                  case TableResultAction.resultAction.RemoveCell:
3975                      // Do not need remove cell because row will be deleted.
3976                      continue;
3977              }
3978          }
3979          row.remove();
3980      };
3981      /**
3982       * Delete current col
3983       *
3984       * @param {WrappedRange} rng
3985       * @return {Node}
3986       */
3987      Table.prototype.deleteCol = function (rng) {
3988          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
3989          var row = $$1(cell).closest('tr');
3990          var cellPos = row.children('td, th').index($$1(cell));
3991          var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Delete, $$1(row).closest('table')[0]);
3992          var actions = vTable.getActionList();
3993          for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
3994              if (!actions[actionIndex]) {
3995                  continue;
3996              }
3997              switch (actions[actionIndex].action) {
3998                  case TableResultAction.resultAction.Ignore:
3999                      continue;
4000                  case TableResultAction.resultAction.SubtractSpanCount:
4001                      var baseCell = actions[actionIndex].baseCell;
4002                      var hasColspan = (baseCell.colSpan && baseCell.colSpan > 1);
4003                      if (hasColspan) {
4004                          var colspanNumber = (baseCell.colSpan) ? parseInt(baseCell.colSpan, 10) : 0;
4005                          if (colspanNumber > 2) {
4006                              colspanNumber--;
4007                              baseCell.setAttribute('colSpan', colspanNumber);
4008                              if (baseCell.cellIndex === cellPos) {
4009                                  baseCell.innerHTML = '';
4010                              }
4011                          }
4012                          else if (colspanNumber === 2) {
4013                              baseCell.removeAttribute('colSpan');
4014                              if (baseCell.cellIndex === cellPos) {
4015                                  baseCell.innerHTML = '';
4016                              }
4017                          }
4018                      }
4019                      continue;
4020                  case TableResultAction.resultAction.RemoveCell:
4021                      dom.remove(actions[actionIndex].baseCell, true);
4022                      continue;
4023              }
4024          }
4025      };
4026      /**
4027       * create empty table element
4028       *
4029       * @param {Number} rowCount
4030       * @param {Number} colCount
4031       * @return {Node}
4032       */
4033      Table.prototype.createTable = function (colCount, rowCount, options) {
4034          var tds = [];
4035          var tdHTML;
4036          for (var idxCol = 0; idxCol < colCount; idxCol++) {
4037              tds.push('<td>' + dom.blank + '</td>');
4038          }
4039          tdHTML = tds.join('');
4040          var trs = [];
4041          var trHTML;
4042          for (var idxRow = 0; idxRow < rowCount; idxRow++) {
4043              trs.push('<tr>' + tdHTML + '</tr>');
4044          }
4045          trHTML = trs.join('');
4046          var $table = $$1('<table>' + trHTML + '</table>');
4047          if (options && options.tableClassName) {
4048              $table.addClass(options.tableClassName);
4049          }
4050          return $table[0];
4051      };
4052      /**
4053       * Delete current table
4054       *
4055       * @param {WrappedRange} rng
4056       * @return {Node}
4057       */
4058      Table.prototype.deleteTable = function (rng) {
4059          var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
4060          $$1(cell).closest('table').remove();
4061      };
4062      return Table;
4063  }());
4064
4065  var KEY_BOGUS = 'bogus';
4066  /**
4067   * @class Editor
4068   */
4069  var Editor = /** @class */ (function () {
4070      function Editor(context) {
4071          var _this = this;
4072          this.context = context;
4073          this.$note = context.layoutInfo.note;
4074          this.$editor = context.layoutInfo.editor;
4075          this.$editable = context.layoutInfo.editable;
4076          this.options = context.options;
4077          this.lang = this.options.langInfo;
4078          this.editable = this.$editable[0];
4079          this.lastRange = null;
4080          this.style = new Style();
4081          this.table = new Table();
4082          this.typing = new Typing(context);
4083          this.bullet = new Bullet();
4084          this.history = new History(this.$editable);
4085          this.context.memo('help.undo', this.lang.help.undo);
4086          this.context.memo('help.redo', this.lang.help.redo);
4087          this.context.memo('help.tab', this.lang.help.tab);
4088          this.context.memo('help.untab', this.lang.help.untab);
4089          this.context.memo('help.insertParagraph', this.lang.help.insertParagraph);
4090          this.context.memo('help.insertOrderedList', this.lang.help.insertOrderedList);
4091          this.context.memo('help.insertUnorderedList', this.lang.help.insertUnorderedList);
4092          this.context.memo('help.indent', this.lang.help.indent);
4093          this.context.memo('help.outdent', this.lang.help.outdent);
4094          this.context.memo('help.formatPara', this.lang.help.formatPara);
4095          this.context.memo('help.insertHorizontalRule', this.lang.help.insertHorizontalRule);
4096          this.context.memo('help.fontName', this.lang.help.fontName);
4097          // native commands(with execCommand), generate function for execCommand
4098          var commands = [
4099              'bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',
4100              'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',
4101              'formatBlock', 'removeFormat', 'backColor',
4102          ];
4103          for (var idx = 0, len = commands.length; idx < len; idx++) {
4104              this[commands[idx]] = (function (sCmd) {
4105                  return function (value) {
4106                      _this.beforeCommand();
4107                      document.execCommand(sCmd, false, value);
4108                      _this.afterCommand(true);
4109                  };
4110              })(commands[idx]);
4111              this.context.memo('help.' + commands[idx], this.lang.help[commands[idx]]);
4112          }
4113          this.fontName = this.wrapCommand(function (value) {
4114              return _this.fontStyling('font-family', "\'" + value + "\'");
4115          });
4116          this.fontSize = this.wrapCommand(function (value) {
4117              return _this.fontStyling('font-size', value + 'px');
4118          });
4119          for (var idx = 1; idx <= 6; idx++) {
4120              this['formatH' + idx] = (function (idx) {
4121                  return function () {
4122                      _this.formatBlock('H' + idx);
4123                  };
4124              })(idx);
4125              this.context.memo('help.formatH' + idx, this.lang.help['formatH' + idx]);
4126          }
4127          this.insertParagraph = this.wrapCommand(function () {
4128              _this.typing.insertParagraph(_this.editable);
4129          });
4130          this.insertOrderedList = this.wrapCommand(function () {
4131              _this.bullet.insertOrderedList(_this.editable);
4132          });
4133          this.insertUnorderedList = this.wrapCommand(function () {
4134              _this.bullet.insertUnorderedList(_this.editable);
4135          });
4136          this.indent = this.wrapCommand(function () {
4137              _this.bullet.indent(_this.editable);
4138          });
4139          this.outdent = this.wrapCommand(function () {
4140              _this.bullet.outdent(_this.editable);
4141          });
4142          /**
4143           * insertNode
4144           * insert node
4145           * @param {Node} node
4146           */
4147          this.insertNode = this.wrapCommand(function (node) {
4148              if (_this.isLimited($$1(node).text().length)) {
4149                  return;
4150              }
4151              var rng = _this.getLastRange();
4152              rng.insertNode(node);
4153              range.createFromNodeAfter(node).select();
4154              _this.setLastRange();
4155          });
4156          /**
4157           * insert text
4158           * @param {String} text
4159           */
4160          this.insertText = this.wrapCommand(function (text) {
4161              if (_this.isLimited(text.length)) {
4162                  return;
4163              }
4164              var rng = _this.getLastRange();
4165              var textNode = rng.insertNode(dom.createText(text));
4166              range.create(textNode, dom.nodeLength(textNode)).select();
4167              _this.setLastRange();
4168          });
4169          /**
4170           * paste HTML
4171           * @param {String} markup
4172           */
4173          this.pasteHTML = this.wrapCommand(function (markup) {
4174              if (_this.isLimited(markup.length)) {
4175                  return;
4176              }
4177              markup = _this.context.invoke('codeview.purify', markup);
4178              var contents = _this.getLastRange().pasteHTML(markup);
4179              range.createFromNodeAfter(lists.last(contents)).select();
4180              _this.setLastRange();
4181          });
4182          /**
4183           * formatBlock
4184           *
4185           * @param {String} tagName
4186           */
4187          this.formatBlock = this.wrapCommand(function (tagName, $target) {
4188              var onApplyCustomStyle = _this.options.callbacks.onApplyCustomStyle;
4189              if (onApplyCustomStyle) {
4190                  onApplyCustomStyle.call(_this, $target, _this.context, _this.onFormatBlock);
4191              }
4192              else {
4193                  _this.onFormatBlock(tagName, $target);
4194              }
4195          });
4196          /**
4197           * insert horizontal rule
4198           */
4199          this.insertHorizontalRule = this.wrapCommand(function () {
4200              var hrNode = _this.getLastRange().insertNode(dom.create('HR'));
4201              if (hrNode.nextSibling) {
4202                  range.create(hrNode.nextSibling, 0).normalize().select();
4203                  _this.setLastRange();
4204              }
4205          });
4206          /**
4207           * lineHeight
4208           * @param {String} value
4209           */
4210          this.lineHeight = this.wrapCommand(function (value) {
4211              _this.style.stylePara(_this.getLastRange(), {
4212                  lineHeight: value
4213              });
4214          });
4215          /**
4216           * create link (command)
4217           *
4218           * @param {Object} linkInfo
4219           */
4220          this.createLink = this.wrapCommand(function (linkInfo) {
4221              var linkUrl = linkInfo.url;
4222              var linkText = linkInfo.text;
4223              var isNewWindow = linkInfo.isNewWindow;
4224              var rng = linkInfo.range || _this.getLastRange();
4225              var additionalTextLength = linkText.length - rng.toString().length;
4226              if (additionalTextLength > 0 && _this.isLimited(additionalTextLength)) {
4227                  return;
4228              }
4229              var isTextChanged = rng.toString() !== linkText;
4230              // handle spaced urls from input
4231              if (typeof linkUrl === 'string') {
4232                  linkUrl = linkUrl.trim();
4233              }
4234              if (_this.options.onCreateLink) {
4235                  linkUrl = _this.options.onCreateLink(linkUrl);
4236              }
4237              else {
4238                  // if url doesn't have any protocol and not even a relative or a label, use http:// as default
4239                  linkUrl = /^([A-Za-z][A-Za-z0-9+-.]*\:|#|\/)/.test(linkUrl)
4240                      ? linkUrl : 'http://' + linkUrl;
4241              }
4242              var anchors = [];
4243              if (isTextChanged) {
4244                  rng = rng.deleteContents();
4245                  var anchor = rng.insertNode($$1('<A>' + linkText + '</A>')[0]);
4246                  anchors.push(anchor);
4247              }
4248              else {
4249                  anchors = _this.style.styleNodes(rng, {
4250                      nodeName: 'A',
4251                      expandClosestSibling: true,
4252                      onlyPartialContains: true
4253                  });
4254              }
4255              $$1.each(anchors, function (idx, anchor) {
4256                  $$1(anchor).attr('href', linkUrl);
4257                  if (isNewWindow) {
4258                      $$1(anchor).attr('target', '_blank');
4259                  }
4260                  else {
4261                      $$1(anchor).removeAttr('target');
4262                  }
4263              });
4264              var startRange = range.createFromNodeBefore(lists.head(anchors));
4265              var startPoint = startRange.getStartPoint();
4266              var endRange = range.createFromNodeAfter(lists.last(anchors));
4267              var endPoint = endRange.getEndPoint();
4268              range.create(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset).select();
4269              _this.setLastRange();
4270          });
4271          /**
4272           * setting color
4273           *
4274           * @param {Object} sObjColor  color code
4275           * @param {String} sObjColor.foreColor foreground color
4276           * @param {String} sObjColor.backColor background color
4277           */
4278          this.color = this.wrapCommand(function (colorInfo) {
4279              var foreColor = colorInfo.foreColor;
4280              var backColor = colorInfo.backColor;
4281              if (foreColor) {
4282                  document.execCommand('foreColor', false, foreColor);
4283              }
4284              if (backColor) {
4285                  document.execCommand('backColor', false, backColor);
4286              }
4287          });
4288          /**
4289           * Set foreground color
4290           *
4291           * @param {String} colorCode foreground color code
4292           */
4293          this.foreColor = this.wrapCommand(function (colorInfo) {
4294              document.execCommand('styleWithCSS', false, true);
4295              document.execCommand('foreColor', false, colorInfo);
4296          });
4297          /**
4298           * insert Table
4299           *
4300           * @param {String} dimension of table (ex : "5x5")
4301           */
4302          this.insertTable = this.wrapCommand(function (dim) {
4303              var dimension = dim.split('x');
4304              var rng = _this.getLastRange().deleteContents();
4305              rng.insertNode(_this.table.createTable(dimension[0], dimension[1], _this.options));
4306          });
4307          /**
4308           * remove media object and Figure Elements if media object is img with Figure.
4309           */
4310          this.removeMedia = this.wrapCommand(function () {
4311              var $target = $$1(_this.restoreTarget()).parent();
4312              if ($target.parent('figure').length) {
4313                  $target.parent('figure').remove();
4314              }
4315              else {
4316                  $target = $$1(_this.restoreTarget()).detach();
4317              }
4318              _this.context.triggerEvent('media.delete', $target, _this.$editable);
4319          });
4320          /**
4321           * float me
4322           *
4323           * @param {String} value
4324           */
4325          this.floatMe = this.wrapCommand(function (value) {
4326              var $target = $$1(_this.restoreTarget());
4327              $target.toggleClass('note-float-left', value === 'left');
4328              $target.toggleClass('note-float-right', value === 'right');
4329              $target.css('float', (value === 'none' ? '' : value));
4330          });
4331          /**
4332           * resize overlay element
4333           * @param {String} value
4334           */
4335          this.resize = this.wrapCommand(function (value) {
4336              var $target = $$1(_this.restoreTarget());
4337              value = parseFloat(value);
4338              if (value === 0) {
4339                  $target.css('width', '');
4340              }
4341              else {
4342                  $target.css({
4343                      width: value * 100 + '%',
4344                      height: ''
4345                  });
4346              }
4347          });
4348      }
4349      Editor.prototype.initialize = function () {
4350          var _this = this;
4351          // bind custom events
4352          this.$editable.on('keydown', function (event) {
4353              if (event.keyCode === key.code.ENTER) {
4354                  _this.context.triggerEvent('enter', event);
4355              }
4356              _this.context.triggerEvent('keydown', event);
4357              if (!event.isDefaultPrevented()) {
4358                  if (_this.options.shortcuts) {
4359                      _this.handleKeyMap(event);
4360                  }
4361                  else {
4362                      _this.preventDefaultEditableShortCuts(event);
4363                  }
4364              }
4365              if (_this.isLimited(1, event)) {
4366                  return false;
4367              }
4368          }).on('keyup', function (event) {
4369              _this.setLastRange();
4370              _this.context.triggerEvent('keyup', event);
4371          }).on('focus', function (event) {
4372              _this.setLastRange();
4373              _this.context.triggerEvent('focus', event);
4374          }).on('blur', function (event) {
4375              _this.context.triggerEvent('blur', event);
4376          }).on('mousedown', function (event) {
4377              _this.context.triggerEvent('mousedown', event);
4378          }).on('mouseup', function (event) {
4379              _this.setLastRange();
4380              _this.context.triggerEvent('mouseup', event);
4381          }).on('scroll', function (event) {
4382              _this.context.triggerEvent('scroll', event);
4383          }).on('paste', function (event) {
4384              _this.setLastRange();
4385              _this.context.triggerEvent('paste', event);
4386          });
4387          this.$editable.attr('spellcheck', this.options.spellCheck);
4388          // init content before set event
4389          this.$editable.html(dom.html(this.$note) || dom.emptyPara);
4390          this.$editable.on(env.inputEventName, func.debounce(function () {
4391              _this.context.triggerEvent('change', _this.$editable.html(), _this.$editable);
4392          }, 10));
4393          this.$editor.on('focusin', function (event) {
4394              _this.context.triggerEvent('focusin', event);
4395          }).on('focusout', function (event) {
4396              _this.context.triggerEvent('focusout', event);
4397          });
4398          if (!this.options.airMode) {
4399              if (this.options.width) {
4400                  this.$editor.outerWidth(this.options.width);
4401              }
4402              if (this.options.height) {
4403                  this.$editable.outerHeight(this.options.height);
4404              }
4405              if (this.options.maxHeight) {
4406                  this.$editable.css('max-height', this.options.maxHeight);
4407              }
4408              if (this.options.minHeight) {
4409                  this.$editable.css('min-height', this.options.minHeight);
4410              }
4411          }
4412          this.history.recordUndo();
4413          this.setLastRange();
4414      };
4415      Editor.prototype.destroy = function () {
4416          this.$editable.off();
4417      };
4418      Editor.prototype.handleKeyMap = function (event) {
4419          var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];
4420          var keys = [];
4421          if (event.metaKey) {
4422              keys.push('CMD');
4423          }
4424          if (event.ctrlKey && !event.altKey) {
4425              keys.push('CTRL');
4426          }
4427          if (event.shiftKey) {
4428              keys.push('SHIFT');
4429          }
4430          var keyName = key.nameFromCode[event.keyCode];
4431          if (keyName) {
4432              keys.push(keyName);
4433          }
4434          var eventName = keyMap[keys.join('+')];
4435          if (eventName) {
4436              if (this.context.invoke(eventName) !== false) {
4437                  event.preventDefault();
4438              }
4439          }
4440          else if (key.isEdit(event.keyCode)) {
4441              this.afterCommand();
4442          }
4443      };
4444      Editor.prototype.preventDefaultEditableShortCuts = function (event) {
4445          // B(Bold, 66) / I(Italic, 73) / U(Underline, 85)
4446          if ((event.ctrlKey || event.metaKey) &&
4447              lists.contains([66, 73, 85], event.keyCode)) {
4448              event.preventDefault();
4449          }
4450      };
4451      Editor.prototype.isLimited = function (pad, event) {
4452          pad = pad || 0;
4453          if (typeof event !== 'undefined') {
4454              if (key.isMove(event.keyCode) ||
4455                  (event.ctrlKey || event.metaKey) ||
4456                  lists.contains([key.code.BACKSPACE, key.code.DELETE], event.keyCode)) {
4457                  return false;
4458              }
4459          }
4460          if (this.options.maxTextLength > 0) {
4461              if ((this.$editable.text().length + pad) >= this.options.maxTextLength) {
4462                  return true;
4463              }
4464          }
4465          return false;
4466      };
4467      /**
4468       * create range
4469       * @return {WrappedRange}
4470       */
4471      Editor.prototype.createRange = function () {
4472          this.focus();
4473          this.setLastRange();
4474          return this.getLastRange();
4475      };
4476      Editor.prototype.setLastRange = function () {
4477          this.lastRange = range.create(this.editable);
4478      };
4479      Editor.prototype.getLastRange = function () {
4480          if (!this.lastRange) {
4481              this.setLastRange();
4482          }
4483          return this.lastRange;
4484      };
4485      /**
4486       * saveRange
4487       *
4488       * save current range
4489       *
4490       * @param {Boolean} [thenCollapse=false]
4491       */
4492      Editor.prototype.saveRange = function (thenCollapse) {
4493          if (thenCollapse) {
4494              this.getLastRange().collapse().select();
4495          }
4496      };
4497      /**
4498       * restoreRange
4499       *
4500       * restore lately range
4501       */
4502      Editor.prototype.restoreRange = function () {
4503          if (this.lastRange) {
4504              this.lastRange.select();
4505              this.focus();
4506          }
4507      };
4508      Editor.prototype.saveTarget = function (node) {
4509          this.$editable.data('target', node);
4510      };
4511      Editor.prototype.clearTarget = function () {
4512          this.$editable.removeData('target');
4513      };
4514      Editor.prototype.restoreTarget = function () {
4515          return this.$editable.data('target');
4516      };
4517      /**
4518       * currentStyle
4519       *
4520       * current style
4521       * @return {Object|Boolean} unfocus
4522       */
4523      Editor.prototype.currentStyle = function () {
4524          var rng = range.create();
4525          if (rng) {
4526              rng = rng.normalize();
4527          }
4528          return rng ? this.style.current(rng) : this.style.fromNode(this.$editable);
4529      };
4530      /**
4531       * style from node
4532       *
4533       * @param {jQuery} $node
4534       * @return {Object}
4535       */
4536      Editor.prototype.styleFromNode = function ($node) {
4537          return this.style.fromNode($node);
4538      };
4539      /**
4540       * undo
4541       */
4542      Editor.prototype.undo = function () {
4543          this.context.triggerEvent('before.command', this.$editable.html());
4544          this.history.undo();
4545          this.context.triggerEvent('change', this.$editable.html(), this.$editable);
4546      };
4547      /*
4548      * commit
4549      */
4550      Editor.prototype.commit = function () {
4551          this.context.triggerEvent('before.command', this.$editable.html());
4552          this.history.commit();
4553          this.context.triggerEvent('change', this.$editable.html(), this.$editable);
4554      };
4555      /**
4556       * redo
4557       */
4558      Editor.prototype.redo = function () {
4559          this.context.triggerEvent('before.command', this.$editable.html());
4560          this.history.redo();
4561          this.context.triggerEvent('change', this.$editable.html(), this.$editable);
4562      };
4563      /**
4564       * before command
4565       */
4566      Editor.prototype.beforeCommand = function () {
4567          this.context.triggerEvent('before.command', this.$editable.html());
4568          // keep focus on editable before command execution
4569          this.focus();
4570      };
4571      /**
4572       * after command
4573       * @param {Boolean} isPreventTrigger
4574       */
4575      Editor.prototype.afterCommand = function (isPreventTrigger) {
4576          this.normalizeContent();
4577          this.history.recordUndo();
4578          if (!isPreventTrigger) {
4579              this.context.triggerEvent('change', this.$editable.html(), this.$editable);
4580          }
4581      };
4582      /**
4583       * handle tab key
4584       */
4585      Editor.prototype.tab = function () {
4586          var rng = this.getLastRange();
4587          if (rng.isCollapsed() && rng.isOnCell()) {
4588              this.table.tab(rng);
4589          }
4590          else {
4591              if (this.options.tabSize === 0) {
4592                  return false;
4593              }
4594              if (!this.isLimited(this.options.tabSize)) {
4595                  this.beforeCommand();
4596                  this.typing.insertTab(rng, this.options.tabSize);
4597                  this.afterCommand();
4598              }
4599          }
4600      };
4601      /**
4602       * handle shift+tab key
4603       */
4604      Editor.prototype.untab = function () {
4605          var rng = this.getLastRange();
4606          if (rng.isCollapsed() && rng.isOnCell()) {
4607              this.table.tab(rng, true);
4608          }
4609          else {
4610              if (this.options.tabSize === 0) {
4611                  return false;
4612              }
4613          }
4614      };
4615      /**
4616       * run given function between beforeCommand and afterCommand
4617       */
4618      Editor.prototype.wrapCommand = function (fn) {
4619          return function () {
4620              this.beforeCommand();
4621              fn.apply(this, arguments);
4622              this.afterCommand();
4623          };
4624      };
4625      /**
4626       * insert image
4627       *
4628       * @param {String} src
4629       * @param {String|Function} param
4630       * @return {Promise}
4631       */
4632      Editor.prototype.insertImage = function (src, param) {
4633          var _this = this;
4634          return createImage(src, param).then(function ($image) {
4635              _this.beforeCommand();
4636              if (typeof param === 'function') {
4637                  param($image);
4638              }
4639              else {
4640                  if (typeof param === 'string') {
4641                      $image.attr('data-filename', param);
4642                  }
4643                  $image.css('width', Math.min(_this.$editable.width(), $image.width()));
4644              }
4645              $image.show();
4646              range.create(_this.editable).insertNode($image[0]);
4647              range.createFromNodeAfter($image[0]).select();
4648              _this.setLastRange();
4649              _this.afterCommand();
4650          }).fail(function (e) {
4651              _this.context.triggerEvent('image.upload.error', e);
4652          });
4653      };
4654      /**
4655       * insertImages
4656       * @param {File[]} files
4657       */
4658      Editor.prototype.insertImagesAsDataURL = function (files) {
4659          var _this = this;
4660          $$1.each(files, function (idx, file) {
4661              var filename = file.name;
4662              if (_this.options.maximumImageFileSize && _this.options.maximumImageFileSize < file.size) {
4663                  _this.context.triggerEvent('image.upload.error', _this.lang.image.maximumFileSizeError);
4664              }
4665              else {
4666                  readFileAsDataURL(file).then(function (dataURL) {
4667                      return _this.insertImage(dataURL, filename);
4668                  }).fail(function () {
4669                      _this.context.triggerEvent('image.upload.error');
4670                  });
4671              }
4672          });
4673      };
4674      /**
4675       * insertImagesOrCallback
4676       * @param {File[]} files
4677       */
4678      Editor.prototype.insertImagesOrCallback = function (files) {
4679          var callbacks = this.options.callbacks;
4680          // If onImageUpload set,
4681          if (callbacks.onImageUpload) {
4682              this.context.triggerEvent('image.upload', files);
4683              // else insert Image as dataURL
4684          }
4685          else {
4686              this.insertImagesAsDataURL(files);
4687          }
4688      };
4689      /**
4690       * return selected plain text
4691       * @return {String} text
4692       */
4693      Editor.prototype.getSelectedText = function () {
4694          var rng = this.getLastRange();
4695          // if range on anchor, expand range with anchor
4696          if (rng.isOnAnchor()) {
4697              rng = range.createFromNode(dom.ancestor(rng.sc, dom.isAnchor));
4698          }
4699          return rng.toString();
4700      };
4701      Editor.prototype.onFormatBlock = function (tagName, $target) {
4702          // [workaround] for MSIE, IE need `<`
4703          document.execCommand('FormatBlock', false, env.isMSIE ? '<' + tagName + '>' : tagName);
4704          // support custom class
4705          if ($target && $target.length) {
4706              // find the exact element has given tagName
4707              if ($target[0].tagName.toUpperCase() !== tagName.toUpperCase()) {
4708                  $target = $target.find(tagName);
4709              }
4710              if ($target && $target.length) {
4711                  var className = $target[0].className || '';
4712                  if (className) {
4713                      var currentRange = this.createRange();
4714                      var $parent = $$1([currentRange.sc, currentRange.ec]).closest(tagName);
4715                      $parent.addClass(className);
4716                  }
4717              }
4718          }
4719      };
4720      Editor.prototype.formatPara = function () {
4721          this.formatBlock('P');
4722      };
4723      Editor.prototype.fontStyling = function (target, value) {
4724          var rng = this.getLastRange();
4725          if (rng) {
4726              var spans = this.style.styleNodes(rng);
4727              $$1(spans).css(target, value);
4728              // [workaround] added styled bogus span for style
4729              //  - also bogus character needed for cursor position
4730              if (rng.isCollapsed()) {
4731                  var firstSpan = lists.head(spans);
4732                  if (firstSpan && !dom.nodeLength(firstSpan)) {
4733                      firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;
4734                      range.createFromNodeAfter(firstSpan.firstChild).select();
4735                      this.setLastRange();
4736                      this.$editable.data(KEY_BOGUS, firstSpan);
4737                  }
4738              }
4739          }
4740      };
4741      /**
4742       * unlink
4743       *
4744       * @type command
4745       */
4746      Editor.prototype.unlink = function () {
4747          var rng = this.getLastRange();
4748          if (rng.isOnAnchor()) {
4749              var anchor = dom.ancestor(rng.sc, dom.isAnchor);
4750              rng = range.createFromNode(anchor);
4751              rng.select();
4752              this.setLastRange();
4753              this.beforeCommand();
4754              document.execCommand('unlink');
4755              this.afterCommand();
4756          }
4757      };
4758      /**
4759       * returns link info
4760       *
4761       * @return {Object}
4762       * @return {WrappedRange} return.range
4763       * @return {String} return.text
4764       * @return {Boolean} [return.isNewWindow=true]
4765       * @return {String} [return.url=""]
4766       */
4767      Editor.prototype.getLinkInfo = function () {
4768          var rng = this.getLastRange().expand(dom.isAnchor);
4769          // Get the first anchor on range(for edit).
4770          var $anchor = $$1(lists.head(rng.nodes(dom.isAnchor)));
4771          var linkInfo = {
4772              range: rng,
4773              text: rng.toString(),
4774              url: $anchor.length ? $anchor.attr('href') : ''
4775          };
4776          // When anchor exists,
4777          if ($anchor.length) {
4778              // Set isNewWindow by checking its target.
4779              linkInfo.isNewWindow = $anchor.attr('target') === '_blank';
4780          }
4781          return linkInfo;
4782      };
4783      Editor.prototype.addRow = function (position) {
4784          var rng = this.getLastRange(this.$editable);
4785          if (rng.isCollapsed() && rng.isOnCell()) {
4786              this.beforeCommand();
4787              this.table.addRow(rng, position);
4788              this.afterCommand();
4789          }
4790      };
4791      Editor.prototype.addCol = function (position) {
4792          var rng = this.getLastRange(this.$editable);
4793          if (rng.isCollapsed() && rng.isOnCell()) {
4794              this.beforeCommand();
4795              this.table.addCol(rng, position);
4796              this.afterCommand();
4797          }
4798      };
4799      Editor.prototype.deleteRow = function () {
4800          var rng = this.getLastRange(this.$editable);
4801          if (rng.isCollapsed() && rng.isOnCell()) {
4802              this.beforeCommand();
4803              this.table.deleteRow(rng);
4804              this.afterCommand();
4805          }
4806      };
4807      Editor.prototype.deleteCol = function () {
4808          var rng = this.getLastRange(this.$editable);
4809          if (rng.isCollapsed() && rng.isOnCell()) {
4810              this.beforeCommand();
4811              this.table.deleteCol(rng);
4812              this.afterCommand();
4813          }
4814      };
4815      Editor.prototype.deleteTable = function () {
4816          var rng = this.getLastRange(this.$editable);
4817          if (rng.isCollapsed() && rng.isOnCell()) {
4818              this.beforeCommand();
4819              this.table.deleteTable(rng);
4820              this.afterCommand();
4821          }
4822      };
4823      /**
4824       * @param {Position} pos
4825       * @param {jQuery} $target - target element
4826       * @param {Boolean} [bKeepRatio] - keep ratio
4827       */
4828      Editor.prototype.resizeTo = function (pos, $target, bKeepRatio) {
4829          var imageSize;
4830          if (bKeepRatio) {
4831              var newRatio = pos.y / pos.x;
4832              var ratio = $target.data('ratio');
4833              imageSize = {
4834                  width: ratio > newRatio ? pos.x : pos.y / ratio,
4835                  height: ratio > newRatio ? pos.x * ratio : pos.y
4836              };
4837          }
4838          else {
4839              imageSize = {
4840                  width: pos.x,
4841                  height: pos.y
4842              };
4843          }
4844          $target.css(imageSize);
4845      };
4846      /**
4847       * returns whether editable area has focus or not.
4848       */
4849      Editor.prototype.hasFocus = function () {
4850          return this.$editable.is(':focus');
4851      };
4852      /**
4853       * set focus
4854       */
4855      Editor.prototype.focus = function () {
4856          // [workaround] Screen will move when page is scolled in IE.
4857          //  - do focus when not focused
4858          if (!this.hasFocus()) {
4859              this.$editable.focus();
4860          }
4861      };
4862      /**
4863       * returns whether contents is empty or not.
4864       * @return {Boolean}
4865       */
4866      Editor.prototype.isEmpty = function () {
4867          return dom.isEmpty(this.$editable[0]) || dom.emptyPara === this.$editable.html();
4868      };
4869      /**
4870       * Removes all contents and restores the editable instance to an _emptyPara_.
4871       */
4872      Editor.prototype.empty = function () {
4873          this.context.invoke('code', dom.emptyPara);
4874      };
4875      /**
4876       * normalize content
4877       */
4878      Editor.prototype.normalizeContent = function () {
4879          this.$editable[0].normalize();
4880      };
4881      return Editor;
4882  }());
4883
4884  var Clipboard = /** @class */ (function () {
4885      function Clipboard(context) {
4886          this.context = context;
4887          this.$editable = context.layoutInfo.editable;
4888      }
4889      Clipboard.prototype.initialize = function () {
4890          this.$editable.on('paste', this.pasteByEvent.bind(this));
4891      };
4892      /**
4893       * paste by clipboard event
4894       *
4895       * @param {Event} event
4896       */
4897      Clipboard.prototype.pasteByEvent = function (event) {
4898          var clipboardData = event.originalEvent.clipboardData;
4899          if (clipboardData && clipboardData.items && clipboardData.items.length) {
4900              // paste img file
4901              var item = clipboardData.items.length > 1 ? clipboardData.items[1] : lists.head(clipboardData.items);
4902              if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
4903                  this.context.invoke('editor.insertImagesOrCallback', [item.getAsFile()]);
4904              }
4905              this.context.invoke('editor.afterCommand');
4906          }
4907      };
4908      return Clipboard;
4909  }());
4910
4911  var Dropzone = /** @class */ (function () {
4912      function Dropzone(context) {
4913          this.context = context;
4914          this.$eventListener = $$1(document);
4915          this.$editor = context.layoutInfo.editor;
4916          this.$editable = context.layoutInfo.editable;
4917          this.options = context.options;
4918          this.lang = this.options.langInfo;
4919          this.documentEventHandlers = {};
4920          this.$dropzone = $$1([
4921              '<div class="note-dropzone">',
4922              '  <div class="note-dropzone-message"/>',
4923              '</div>',
4924          ].join('')).prependTo(this.$editor);
4925      }
4926      /**
4927       * attach Drag and Drop Events
4928       */
4929      Dropzone.prototype.initialize = function () {
4930          if (this.options.disableDragAndDrop) {
4931              // prevent default drop event
4932              this.documentEventHandlers.onDrop = function (e) {
4933                  e.preventDefault();
4934              };
4935              // do not consider outside of dropzone
4936              this.$eventListener = this.$dropzone;
4937              this.$eventListener.on('drop', this.documentEventHandlers.onDrop);
4938          }
4939          else {
4940              this.attachDragAndDropEvent();
4941          }
4942      };
4943      /**
4944       * attach Drag and Drop Events
4945       */
4946      Dropzone.prototype.attachDragAndDropEvent = function () {
4947          var _this = this;
4948          var collection = $$1();
4949          var $dropzoneMessage = this.$dropzone.find('.note-dropzone-message');
4950          this.documentEventHandlers.onDragenter = function (e) {
4951              var isCodeview = _this.context.invoke('codeview.isActivated');
4952              var hasEditorSize = _this.$editor.width() > 0 && _this.$editor.height() > 0;
4953              if (!isCodeview && !collection.length && hasEditorSize) {
4954                  _this.$editor.addClass('dragover');
4955                  _this.$dropzone.width(_this.$editor.width());
4956                  _this.$dropzone.height(_this.$editor.height());
4957                  $dropzoneMessage.text(_this.lang.image.dragImageHere);
4958              }
4959              collection = collection.add(e.target);
4960          };
4961          this.documentEventHandlers.onDragleave = function (e) {
4962              collection = collection.not(e.target);
4963              if (!collection.length) {
4964                  _this.$editor.removeClass('dragover');
4965              }
4966          };
4967          this.documentEventHandlers.onDrop = function () {
4968              collection = $$1();
4969              _this.$editor.removeClass('dragover');
4970          };
4971          // show dropzone on dragenter when dragging a object to document
4972          // -but only if the editor is visible, i.e. has a positive width and height
4973          this.$eventListener.on('dragenter', this.documentEventHandlers.onDragenter)
4974              .on('dragleave', this.documentEventHandlers.onDragleave)
4975              .on('drop', this.documentEventHandlers.onDrop);
4976          // change dropzone's message on hover.
4977          this.$dropzone.on('dragenter', function () {
4978              _this.$dropzone.addClass('hover');
4979              $dropzoneMessage.text(_this.lang.image.dropImage);
4980          }).on('dragleave', function () {
4981              _this.$dropzone.removeClass('hover');
4982              $dropzoneMessage.text(_this.lang.image.dragImageHere);
4983          });
4984          // attach dropImage
4985          this.$dropzone.on('drop', function (event) {
4986              var dataTransfer = event.originalEvent.dataTransfer;
4987              // stop the browser from opening the dropped content
4988              event.preventDefault();
4989              if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
4990                  _this.$editable.focus();
4991                  _this.context.invoke('editor.insertImagesOrCallback', dataTransfer.files);
4992              }
4993              else {
4994                  $$1.each(dataTransfer.types, function (idx, type) {
4995                      var content = dataTransfer.getData(type);
4996                      if (type.toLowerCase().indexOf('text') > -1) {
4997                          _this.context.invoke('editor.pasteHTML', content);
4998                      }
4999                      else {
5000                          $$1(content).each(function (idx, item) {
5001                              _this.context.invoke('editor.insertNode', item);
5002                          });
5003                      }
5004                  });
5005              }
5006          }).on('dragover', false); // prevent default dragover event
5007      };
5008      Dropzone.prototype.destroy = function () {
5009          var _this = this;
5010          Object.keys(this.documentEventHandlers).forEach(function (key) {
5011              _this.$eventListener.off(key.substr(2).toLowerCase(), _this.documentEventHandlers[key]);
5012          });
5013          this.documentEventHandlers = {};
5014      };
5015      return Dropzone;
5016  }());
5017
5018  var CodeMirror;
5019  if (env.hasCodeMirror) {
5020      CodeMirror = window.CodeMirror;
5021  }
5022  /**
5023   * @class Codeview
5024   */
5025  var CodeView = /** @class */ (function () {
5026      function CodeView(context) {
5027          this.context = context;
5028          this.$editor = context.layoutInfo.editor;
5029          this.$editable = context.layoutInfo.editable;
5030          this.$codable = context.layoutInfo.codable;
5031          this.options = context.options;
5032      }
5033      CodeView.prototype.sync = function () {
5034          var isCodeview = this.isActivated();
5035          if (isCodeview && env.hasCodeMirror) {
5036              this.$codable.data('cmEditor').save();
5037          }
5038      };
5039      /**
5040       * @return {Boolean}
5041       */
5042      CodeView.prototype.isActivated = function () {
5043          return this.$editor.hasClass('codeview');
5044      };
5045      /**
5046       * toggle codeview
5047       */
5048      CodeView.prototype.toggle = function () {
5049          if (this.isActivated()) {
5050              this.deactivate();
5051          }
5052          else {
5053              this.activate();
5054          }
5055          this.context.triggerEvent('codeview.toggled');
5056      };
5057      /**
5058       * purify input value
5059       * @param value
5060       * @returns {*}
5061       */
5062      CodeView.prototype.purify = function (value) {
5063          if (this.options.codeviewFilter) {
5064              // filter code view regex
5065              value = value.replace(this.options.codeviewFilterRegex, '');
5066              // allow specific iframe tag
5067              if (this.options.codeviewIframeFilter) {
5068                  var whitelist_1 = this.options.codeviewIframeWhitelistSrc.concat(this.options.codeviewIframeWhitelistSrcBase);
5069                  value = value.replace(/(<iframe.*?>.*?(?:<\/iframe>)?)/gi, function (tag) {
5070                      // remove if src attribute is duplicated
5071                      if (/<.+src(?==?('|"|\s)?)[\s\S]+src(?=('|"|\s)?)[^>]*?>/i.test(tag)) {
5072                          return '';
5073                      }
5074                      for (var _i = 0, whitelist_2 = whitelist_1; _i < whitelist_2.length; _i++) {
5075                          var src = whitelist_2[_i];
5076                          // pass if src is trusted
5077                          if ((new RegExp('src="(https?:)?\/\/' + src.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '\/(.+)"')).test(tag)) {
5078                              return tag;
5079                          }
5080                      }
5081                      return '';
5082                  });
5083              }
5084          }
5085          return value;
5086      };
5087      /**
5088       * activate code view
5089       */
5090      CodeView.prototype.activate = function () {
5091          var _this = this;
5092          this.$codable.val(dom.html(this.$editable, this.options.prettifyHtml));
5093          this.$codable.height(this.$editable.height());
5094          this.context.invoke('toolbar.updateCodeview', true);
5095          this.$editor.addClass('codeview');
5096          this.$codable.focus();
5097          // activate CodeMirror as codable
5098          if (env.hasCodeMirror) {
5099              var cmEditor_1 = CodeMirror.fromTextArea(this.$codable[0], this.options.codemirror);
5100              // CodeMirror TernServer
5101              if (this.options.codemirror.tern) {
5102                  var server_1 = new CodeMirror.TernServer(this.options.codemirror.tern);
5103                  cmEditor_1.ternServer = server_1;
5104                  cmEditor_1.on('cursorActivity', function (cm) {
5105                      server_1.updateArgHints(cm);
5106                  });
5107              }
5108              cmEditor_1.on('blur', function (event) {
5109                  _this.context.triggerEvent('blur.codeview', cmEditor_1.getValue(), event);
5110              });
5111              cmEditor_1.on('change', function (event) {
5112                  _this.context.triggerEvent('change.codeview', cmEditor_1.getValue(), cmEditor_1);
5113              });
5114              // CodeMirror hasn't Padding.
5115              cmEditor_1.setSize(null, this.$editable.outerHeight());
5116              this.$codable.data('cmEditor', cmEditor_1);
5117          }
5118          else {
5119              this.$codable.on('blur', function (event) {
5120                  _this.context.triggerEvent('blur.codeview', _this.$codable.val(), event);
5121              });
5122              this.$codable.on('input', function (event) {
5123                  _this.context.triggerEvent('change.codeview', _this.$codable.val(), _this.$codable);
5124              });
5125          }
5126      };
5127      /**
5128       * deactivate code view
5129       */
5130      CodeView.prototype.deactivate = function () {
5131          // deactivate CodeMirror as codable
5132          if (env.hasCodeMirror) {
5133              var cmEditor = this.$codable.data('cmEditor');
5134              this.$codable.val(cmEditor.getValue());
5135              cmEditor.toTextArea();
5136          }
5137          var value = this.purify(dom.value(this.$codable, this.options.prettifyHtml) || dom.emptyPara);
5138          var isChange = this.$editable.html() !== value;
5139          this.$editable.html(value);
5140          this.$editable.height(this.options.height ? this.$codable.height() : 'auto');
5141          this.$editor.removeClass('codeview');
5142          if (isChange) {
5143              this.context.triggerEvent('change', this.$editable.html(), this.$editable);
5144          }
5145          this.$editable.focus();
5146          this.context.invoke('toolbar.updateCodeview', false);
5147      };
5148      CodeView.prototype.destroy = function () {
5149          if (this.isActivated()) {
5150              this.deactivate();
5151          }
5152      };
5153      return CodeView;
5154  }());
5155
5156  var EDITABLE_PADDING = 24;
5157  var Statusbar = /** @class */ (function () {
5158      function Statusbar(context) {
5159          this.$document = $$1(document);
5160          this.$statusbar = context.layoutInfo.statusbar;
5161          this.$editable = context.layoutInfo.editable;
5162          this.options = context.options;
5163      }
5164      Statusbar.prototype.initialize = function () {
5165          var _this = this;
5166          if (this.options.airMode || this.options.disableResizeEditor) {
5167              this.destroy();
5168              return;
5169          }
5170          this.$statusbar.on('mousedown', function (event) {
5171              event.preventDefault();
5172              event.stopPropagation();
5173              var editableTop = _this.$editable.offset().top - _this.$document.scrollTop();
5174              var onMouseMove = function (event) {
5175                  var height = event.clientY - (editableTop + EDITABLE_PADDING);
5176                  height = (_this.options.minheight > 0) ? Math.max(height, _this.options.minheight) : height;
5177                  height = (_this.options.maxHeight > 0) ? Math.min(height, _this.options.maxHeight) : height;
5178                  _this.$editable.height(height);
5179              };
5180              _this.$document.on('mousemove', onMouseMove).one('mouseup', function () {
5181                  _this.$document.off('mousemove', onMouseMove);
5182              });
5183          });
5184      };
5185      Statusbar.prototype.destroy = function () {
5186          this.$statusbar.off();
5187          this.$statusbar.addClass('locked');
5188      };
5189      return Statusbar;
5190  }());
5191
5192  var Fullscreen = /** @class */ (function () {
5193      function Fullscreen(context) {
5194          var _this = this;
5195          this.context = context;
5196          this.$editor = context.layoutInfo.editor;
5197          this.$toolbar = context.layoutInfo.toolbar;
5198          this.$editable = context.layoutInfo.editable;
5199          this.$codable = context.layoutInfo.codable;
5200          this.$window = $$1(window);
5201          this.$scrollbar = $$1('html, body');
5202          this.onResize = function () {
5203              _this.resizeTo({
5204                  h: _this.$window.height() - _this.$toolbar.outerHeight()
5205              });
5206          };
5207      }
5208      Fullscreen.prototype.resizeTo = function (size) {
5209          this.$editable.css('height', size.h);
5210          this.$codable.css('height', size.h);
5211          if (this.$codable.data('cmeditor')) {
5212              this.$codable.data('cmeditor').setsize(null, size.h);
5213          }
5214      };
5215      /**
5216       * toggle fullscreen
5217       */
5218      Fullscreen.prototype.toggle = function () {
5219          this.$editor.toggleClass('fullscreen');
5220          if (this.isFullscreen()) {
5221              this.$editable.data('orgHeight', this.$editable.css('height'));
5222              this.$editable.data('orgMaxHeight', this.$editable.css('maxHeight'));
5223              this.$editable.css('maxHeight', '');
5224              this.$window.on('resize', this.onResize).trigger('resize');
5225              this.$scrollbar.css('overflow', 'hidden');
5226          }
5227          else {
5228              this.$window.off('resize', this.onResize);
5229              this.resizeTo({ h: this.$editable.data('orgHeight') });
5230              this.$editable.css('maxHeight', this.$editable.css('orgMaxHeight'));
5231              this.$scrollbar.css('overflow', 'visible');
5232          }
5233          this.context.invoke('toolbar.updateFullscreen', this.isFullscreen());
5234      };
5235      Fullscreen.prototype.isFullscreen = function () {
5236          return this.$editor.hasClass('fullscreen');
5237      };
5238      return Fullscreen;
5239  }());
5240
5241  var Handle = /** @class */ (function () {
5242      function Handle(context) {
5243          var _this = this;
5244          this.context = context;
5245          this.$document = $$1(document);
5246          this.$editingArea = context.layoutInfo.editingArea;
5247          this.options = context.options;
5248          this.lang = this.options.langInfo;
5249          this.events = {
5250              'summernote.mousedown': function (we, e) {
5251                  if (_this.update(e.target, e)) {
5252                      e.preventDefault();
5253                  }
5254              },
5255              'summernote.keyup summernote.scroll summernote.change summernote.dialog.shown': function () {
5256                  _this.update();
5257              },
5258              'summernote.disable': function () {
5259                  _this.hide();
5260              },
5261              'summernote.codeview.toggled': function () {
5262                  _this.update();
5263              }
5264          };
5265      }
5266      Handle.prototype.initialize = function () {
5267          var _this = this;
5268          this.$handle = $$1([
5269              '<div class="note-handle">',
5270              '<div class="note-control-selection">',
5271              '<div class="note-control-selection-bg"></div>',
5272              '<div class="note-control-holder note-control-nw"></div>',
5273              '<div class="note-control-holder note-control-ne"></div>',
5274              '<div class="note-control-holder note-control-sw"></div>',
5275              '<div class="',
5276              (this.options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing'),
5277              ' note-control-se"></div>',
5278              (this.options.disableResizeImage ? '' : '<div class="note-control-selection-info"></div>'),
5279              '</div>',
5280              '</div>',
5281          ].join('')).prependTo(this.$editingArea);
5282          this.$handle.on('mousedown', function (event) {
5283              if (dom.isControlSizing(event.target)) {
5284                  event.preventDefault();
5285                  event.stopPropagation();
5286                  var $target_1 = _this.$handle.find('.note-control-selection').data('target');
5287                  var posStart_1 = $target_1.offset();
5288                  var scrollTop_1 = _this.$document.scrollTop();
5289                  var onMouseMove_1 = function (event) {
5290                      _this.context.invoke('editor.resizeTo', {
5291                          x: event.clientX - posStart_1.left,
5292                          y: event.clientY - (posStart_1.top - scrollTop_1)
5293                      }, $target_1, !event.shiftKey);
5294                      _this.update($target_1[0]);
5295                  };
5296                  _this.$document
5297                      .on('mousemove', onMouseMove_1)
5298                      .one('mouseup', function (e) {
5299                      e.preventDefault();
5300                      _this.$document.off('mousemove', onMouseMove_1);
5301                      _this.context.invoke('editor.afterCommand');
5302                  });
5303                  if (!$target_1.data('ratio')) { // original ratio.
5304                      $target_1.data('ratio', $target_1.height() / $target_1.width());
5305                  }
5306              }
5307          });
5308          // Listen for scrolling on the handle overlay.
5309          this.$handle.on('wheel', function (e) {
5310              e.preventDefault();
5311              _this.update();
5312          });
5313      };
5314      Handle.prototype.destroy = function () {
5315          this.$handle.remove();
5316      };
5317      Handle.prototype.update = function (target, event) {
5318          if (this.context.isDisabled()) {
5319              return false;
5320          }
5321          var isImage = dom.isImg(target);
5322          var $selection = this.$handle.find('.note-control-selection');
5323          this.context.invoke('imagePopover.update', target, event);
5324          if (isImage) {
5325              var $image = $$1(target);
5326              var position = $image.position();
5327              var pos = {
5328                  left: position.left + parseInt($image.css('marginLeft'), 10),
5329                  top: position.top + parseInt($image.css('marginTop'), 10)
5330              };
5331              // exclude margin
5332              var imageSize = {
5333                  w: $image.outerWidth(false),
5334                  h: $image.outerHeight(false)
5335              };
5336              $selection.css({
5337                  display: 'block',
5338                  left: pos.left,
5339                  top: pos.top,
5340                  width: imageSize.w,
5341                  height: imageSize.h
5342              }).data('target', $image); // save current image element.
5343              var origImageObj = new Image();
5344              origImageObj.src = $image.attr('src');
5345              var sizingText = imageSize.w + 'x' + imageSize.h + ' (' + this.lang.image.original + ': ' + origImageObj.width + 'x' + origImageObj.height + ')';
5346              $selection.find('.note-control-selection-info').text(sizingText);
5347              this.context.invoke('editor.saveTarget', target);
5348          }
5349          else {
5350              this.hide();
5351          }
5352          return isImage;
5353      };
5354      /**
5355       * hide
5356       *
5357       * @param {jQuery} $handle
5358       */
5359      Handle.prototype.hide = function () {
5360          this.context.invoke('editor.clearTarget');
5361          this.$handle.children().hide();
5362      };
5363      return Handle;
5364  }());
5365
5366  var defaultScheme = 'http://';
5367  var linkPattern = /^([A-Za-z][A-Za-z0-9+-.]*\:[\/]{2}|mailto:[A-Z0-9._%+-]+@)?(www\.)?(.+)$/i;
5368  var AutoLink = /** @class */ (function () {
5369      function AutoLink(context) {
5370          var _this = this;
5371          this.context = context;
5372          this.events = {
5373              'summernote.keyup': function (we, e) {
5374                  if (!e.isDefaultPrevented()) {
5375                      _this.handleKeyup(e);
5376                  }
5377              },
5378              'summernote.keydown': function (we, e) {
5379                  _this.handleKeydown(e);
5380              }
5381          };
5382      }
5383      AutoLink.prototype.initialize = function () {
5384          this.lastWordRange = null;
5385      };
5386      AutoLink.prototype.destroy = function () {
5387          this.lastWordRange = null;
5388      };
5389      AutoLink.prototype.replace = function () {
5390          if (!this.lastWordRange) {
5391              return;
5392          }
5393          var keyword = this.lastWordRange.toString();
5394          var match = keyword.match(linkPattern);
5395          if (match && (match[1] || match[2])) {
5396              var link = match[1] ? keyword : defaultScheme + keyword;
5397              var node = $$1('<a />').html(keyword).attr('href', link)[0];
5398              if (this.context.options.linkTargetBlank) {
5399                  $$1(node).attr('target', '_blank');
5400              }
5401              this.lastWordRange.insertNode(node);
5402              this.lastWordRange = null;
5403              this.context.invoke('editor.focus');
5404          }
5405      };
5406      AutoLink.prototype.handleKeydown = function (e) {
5407          if (lists.contains([key.code.ENTER, key.code.SPACE], e.keyCode)) {
5408              var wordRange = this.context.invoke('editor.createRange').getWordRange();
5409              this.lastWordRange = wordRange;
5410          }
5411      };
5412      AutoLink.prototype.handleKeyup = function (e) {
5413          if (lists.contains([key.code.ENTER, key.code.SPACE], e.keyCode)) {
5414              this.replace();
5415          }
5416      };
5417      return AutoLink;
5418  }());
5419
5420  /**
5421   * textarea auto sync.
5422   */
5423  var AutoSync = /** @class */ (function () {
5424      function AutoSync(context) {
5425          var _this = this;
5426          this.$note = context.layoutInfo.note;
5427          this.events = {
5428              'summernote.change': function () {
5429                  _this.$note.val(context.invoke('code'));
5430              }
5431          };
5432      }
5433      AutoSync.prototype.shouldInitialize = function () {
5434          return dom.isTextarea(this.$note[0]);
5435      };
5436      return AutoSync;
5437  }());
5438
5439  var AutoReplace = /** @class */ (function () {
5440      function AutoReplace(context) {
5441          var _this = this;
5442          this.context = context;
5443          this.options = context.options.replace || {};
5444          this.keys = [key.code.ENTER, key.code.SPACE, key.code.PERIOD, key.code.COMMA, key.code.SEMICOLON, key.code.SLASH];
5445          this.previousKeydownCode = null;
5446          this.events = {
5447              'summernote.keyup': function (we, e) {
5448                  if (!e.isDefaultPrevented()) {
5449                      _this.handleKeyup(e);
5450                  }
5451              },
5452              'summernote.keydown': function (we, e) {
5453                  _this.handleKeydown(e);
5454              }
5455          };
5456      }
5457      AutoReplace.prototype.shouldInitialize = function () {
5458          return !!this.options.match;
5459      };
5460      AutoReplace.prototype.initialize = function () {
5461          this.lastWord = null;
5462      };
5463      AutoReplace.prototype.destroy = function () {
5464          this.lastWord = null;
5465      };
5466      AutoReplace.prototype.replace = function () {
5467          if (!this.lastWord) {
5468              return;
5469          }
5470          var self = this;
5471          var keyword = this.lastWord.toString();
5472          this.options.match(keyword, function (match) {
5473              if (match) {
5474                  var node = '';
5475                  if (typeof match === 'string') {
5476                      node = dom.createText(match);
5477                  }
5478                  else if (match instanceof jQuery) {
5479                      node = match[0];
5480                  }
5481                  else if (match instanceof Node) {
5482                      node = match;
5483                  }
5484                  if (!node)
5485                      return;
5486                  self.lastWord.insertNode(node);
5487                  self.lastWord = null;
5488                  self.context.invoke('editor.focus');
5489              }
5490          });
5491      };
5492      AutoReplace.prototype.handleKeydown = function (e) {
5493          // this forces it to remember the last whole word, even if multiple termination keys are pressed
5494          // before the previous key is let go.
5495          if (this.previousKeydownCode && lists.contains(this.keys, this.previousKeydownCode)) {
5496              this.previousKeydownCode = e.keyCode;
5497              return;
5498          }
5499          if (lists.contains(this.keys, e.keyCode)) {
5500              var wordRange = this.context.invoke('editor.createRange').getWordRange();
5501              this.lastWord = wordRange;
5502          }
5503          this.previousKeydownCode = e.keyCode;
5504      };
5505      AutoReplace.prototype.handleKeyup = function (e) {
5506          if (lists.contains(this.keys, e.keyCode)) {
5507              this.replace();
5508          }
5509      };
5510      return AutoReplace;
5511  }());
5512
5513  var Placeholder = /** @class */ (function () {
5514      function Placeholder(context) {
5515          var _this = this;
5516          this.context = context;
5517          this.$editingArea = context.layoutInfo.editingArea;
5518          this.options = context.options;
5519          this.events = {
5520              'summernote.init summernote.change': function () {
5521                  _this.update();
5522              },
5523              'summernote.codeview.toggled': function () {
5524                  _this.update();
5525              }
5526          };
5527      }
5528      Placeholder.prototype.shouldInitialize = function () {
5529          return !!this.options.placeholder;
5530      };
5531      Placeholder.prototype.initialize = function () {
5532          var _this = this;
5533          this.$placeholder = $$1('<div class="note-placeholder">');
5534          this.$placeholder.on('click', function () {
5535              _this.context.invoke('focus');
5536          }).html(this.options.placeholder).prependTo(this.$editingArea);
5537          this.update();
5538      };
5539      Placeholder.prototype.destroy = function () {
5540          this.$placeholder.remove();
5541      };
5542      Placeholder.prototype.update = function () {
5543          var isShow = !this.context.invoke('codeview.isActivated') && this.context.invoke('editor.isEmpty');
5544          this.$placeholder.toggle(isShow);
5545      };
5546      return Placeholder;
5547  }());
5548
5549  var Buttons = /** @class */ (function () {
5550      function Buttons(context) {
5551          this.ui = $$1.summernote.ui;
5552          this.context = context;
5553          this.$toolbar = context.layoutInfo.toolbar;
5554          this.options = context.options;
5555          this.lang = this.options.langInfo;
5556          this.invertedKeyMap = func.invertObject(this.options.keyMap[env.isMac ? 'mac' : 'pc']);
5557      }
5558      Buttons.prototype.representShortcut = function (editorMethod) {
5559          var shortcut = this.invertedKeyMap[editorMethod];
5560          if (!this.options.shortcuts || !shortcut) {
5561              return '';
5562          }
5563          if (env.isMac) {
5564              shortcut = shortcut.replace('CMD', '⌘').replace('SHIFT', '⇧');
5565          }
5566          shortcut = shortcut.replace('BACKSLASH', '\\')
5567              .replace('SLASH', '/')
5568              .replace('LEFTBRACKET', '[')
5569              .replace('RIGHTBRACKET', ']');
5570          return ' (' + shortcut + ')';
5571      };
5572      Buttons.prototype.button = function (o) {
5573          if (!this.options.tooltip && o.tooltip) {
5574              delete o.tooltip;
5575          }
5576          o.container = this.options.container;
5577          return this.ui.button(o);
5578      };
5579      Buttons.prototype.initialize = function () {
5580          this.addToolbarButtons();
5581          this.addImagePopoverButtons();
5582          this.addLinkPopoverButtons();
5583          this.addTablePopoverButtons();
5584          this.fontInstalledMap = {};
5585      };
5586      Buttons.prototype.destroy = function () {
5587          delete this.fontInstalledMap;
5588      };
5589      Buttons.prototype.isFontInstalled = function (name) {
5590          if (!this.fontInstalledMap.hasOwnProperty(name)) {
5591              this.fontInstalledMap[name] = env.isFontInstalled(name) ||
5592                  lists.contains(this.options.fontNamesIgnoreCheck, name);
5593          }
5594          return this.fontInstalledMap[name];
5595      };
5596      Buttons.prototype.isFontDeservedToAdd = function (name) {
5597          var genericFamilies = ['sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'];
5598          name = name.toLowerCase();
5599          return (name !== '' && this.isFontInstalled(name) && genericFamilies.indexOf(name) === -1);
5600      };
5601      Buttons.prototype.colorPalette = function (className, tooltip, backColor, foreColor) {
5602          var _this = this;
5603          return this.ui.buttonGroup({
5604              className: 'note-color ' + className,
5605              children: [
5606                  this.button({
5607                      className: 'note-current-color-button',
5608                      contents: this.ui.icon(this.options.icons.font + ' note-recent-color'),
5609                      tooltip: tooltip,
5610                      click: function (e) {
5611                          var $button = $$1(e.currentTarget);
5612                          if (backColor && foreColor) {
5613                              _this.context.invoke('editor.color', {
5614                                  backColor: $button.attr('data-backColor'),
5615                                  foreColor: $button.attr('data-foreColor')
5616                              });
5617                          }
5618                          else if (backColor) {
5619                              _this.context.invoke('editor.color', {
5620                                  backColor: $button.attr('data-backColor')
5621                              });
5622                          }
5623                          else if (foreColor) {
5624                              _this.context.invoke('editor.color', {
5625                                  foreColor: $button.attr('data-foreColor')
5626                              });
5627                          }
5628                      },
5629                      callback: function ($button) {
5630                          var $recentColor = $button.find('.note-recent-color');
5631                          if (backColor) {
5632                              $recentColor.css('background-color', _this.options.colorButton.backColor);
5633                              $button.attr('data-backColor', _this.options.colorButton.backColor);
5634                          }
5635                          if (foreColor) {
5636                              $recentColor.css('color', _this.options.colorButton.foreColor);
5637                              $button.attr('data-foreColor', _this.options.colorButton.foreColor);
5638                          }
5639                          else {
5640                              $recentColor.css('color', 'transparent');
5641                          }
5642                      }
5643                  }),
5644                  this.button({
5645                      className: 'dropdown-toggle',
5646                      contents: this.ui.dropdownButtonContents('', this.options),
5647                      tooltip: this.lang.color.more,
5648                      data: {
5649                          toggle: 'dropdown'
5650                      }
5651                  }),
5652                  this.ui.dropdown({
5653                      items: (backColor ? [
5654                          '<div class="note-palette">',
5655                          '  <div class="note-palette-title">' + this.lang.color.background + '</div>',
5656                          '  <div>',
5657                          '    <button type="button" class="note-color-reset btn btn-light" data-event="backColor" data-value="inherit">',
5658                          this.lang.color.transparent,
5659                          '    </button>',
5660                          '  </div>',
5661                          '  <div class="note-holder" data-event="backColor"/>',
5662                          '  <div>',
5663                          '    <button type="button" class="note-color-select btn" data-event="openPalette" data-value="backColorPicker">',
5664                          this.lang.color.cpSelect,
5665                          '    </button>',
5666                          '    <input type="color" id="backColorPicker" class="note-btn note-color-select-btn" value="' + this.options.colorButton.backColor + '" data-event="backColorPalette">',
5667                          '  </div>',
5668                          '  <div class="note-holder-custom" id="backColorPalette" data-event="backColor"/>',
5669                          '</div>',
5670                      ].join('') : '') +
5671                          (foreColor ? [
5672                              '<div class="note-palette">',
5673                              '  <div class="note-palette-title">' + this.lang.color.foreground + '</div>',
5674                              '  <div>',
5675                              '    <button type="button" class="note-color-reset btn btn-light" data-event="removeFormat" data-value="foreColor">',
5676                              this.lang.color.resetToDefault,
5677                              '    </button>',
5678                              '  </div>',
5679                              '  <div class="note-holder" data-event="foreColor"/>',
5680                              '  <div>',
5681                              '    <button type="button" class="note-color-select btn" data-event="openPalette" data-value="foreColorPicker">',
5682                              this.lang.color.cpSelect,
5683                              '    </button>',
5684                              '    <input type="color" id="foreColorPicker" class="note-btn note-color-select-btn" value="' + this.options.colorButton.foreColor + '" data-event="foreColorPalette">',
5685                              '  <div class="note-holder-custom" id="foreColorPalette" data-event="foreColor"/>',
5686                              '</div>',
5687                          ].join('') : ''),
5688                      callback: function ($dropdown) {
5689                          $dropdown.find('.note-holder').each(function (idx, item) {
5690                              var $holder = $$1(item);
5691                              $holder.append(_this.ui.palette({
5692                                  colors: _this.options.colors,
5693                                  colorsName: _this.options.colorsName,
5694                                  eventName: $holder.data('event'),
5695                                  container: _this.options.container,
5696                                  tooltip: _this.options.tooltip
5697                              }).render());
5698                          });
5699                          /* TODO: do we have to record recent custom colors within cookies? */
5700                          var customColors = [
5701                              ['#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF'],
5702                          ];
5703                          $dropdown.find('.note-holder-custom').each(function (idx, item) {
5704                              var $holder = $$1(item);
5705                              $holder.append(_this.ui.palette({
5706                                  colors: customColors,
5707                                  colorsName: customColors,
5708                                  eventName: $holder.data('event'),
5709                                  container: _this.options.container,
5710                                  tooltip: _this.options.tooltip
5711                              }).render());
5712                          });
5713                          $dropdown.find('input[type=color]').each(function (idx, item) {
5714                              $$1(item).change(function () {
5715                                  var $chip = $dropdown.find('#' + $$1(this).data('event')).find('.note-color-btn').first();
5716                                  var color = this.value.toUpperCase();
5717                                  $chip.css('background-color', color)
5718                                      .attr('aria-label', color)
5719                                      .attr('data-value', color)
5720                                      .attr('data-original-title', color);
5721                                  $chip.click();
5722                              });
5723                          });
5724                      },
5725                      click: function (event) {
5726                          event.stopPropagation();
5727                          var $parent = $$1('.' + className);
5728                          var $button = $$1(event.target);
5729                          var eventName = $button.data('event');
5730                          var value = $button.attr('data-value');
5731                          if (eventName === 'openPalette') {
5732                              var $picker = $parent.find('#' + value);
5733                              var $palette = $$1($parent.find('#' + $picker.data('event')).find('.note-color-row')[0]);
5734                              // Shift palette chips
5735                              var $chip = $palette.find('.note-color-btn').last().detach();
5736                              // Set chip attributes
5737                              var color = $picker.val();
5738                              $chip.css('background-color', color)
5739                                  .attr('aria-label', color)
5740                                  .attr('data-value', color)
5741                                  .attr('data-original-title', color);
5742                              $palette.prepend($chip);
5743                              $picker.click();
5744                          }
5745                          else if (lists.contains(['backColor', 'foreColor'], eventName)) {
5746                              var key = eventName === 'backColor' ? 'background-color' : 'color';
5747                              var $color = $button.closest('.note-color').find('.note-recent-color');
5748                              var $currentButton = $button.closest('.note-color').find('.note-current-color-button');
5749                              $color.css(key, value);
5750                              $currentButton.attr('data-' + eventName, value);
5751                              _this.context.invoke('editor.' + eventName, value);
5752                          }
5753                      }
5754                  }),
5755              ]
5756          }).render();
5757      };
5758      Buttons.prototype.addToolbarButtons = function () {
5759          var _this = this;
5760          this.context.memo('button.style', function () {
5761              return _this.ui.buttonGroup([
5762                  _this.button({
5763                      className: 'dropdown-toggle',
5764                      contents: _this.ui.dropdownButtonContents(_this.ui.icon(_this.options.icons.magic), _this.options),
5765                      tooltip: _this.lang.style.style,
5766                      data: {
5767                          toggle: 'dropdown'
5768                      }
5769                  }),
5770                  _this.ui.dropdown({
5771                      className: 'dropdown-style',
5772                      items: _this.options.styleTags,
5773                      title: _this.lang.style.style,
5774                      template: function (item) {
5775                          if (typeof item === 'string') {
5776                              item = { tag: item, title: (_this.lang.style.hasOwnProperty(item) ? _this.lang.style[item] : item) };
5777                          }
5778                          var tag = item.tag;
5779                          var title = item.title;
5780                          var style = item.style ? ' style="' + item.style + '" ' : '';
5781                          var className = item.className ? ' class="' + item.className + '"' : '';
5782                          return '<' + tag + style + className + '>' + title + '</' + tag + '>';
5783                      },
5784                      click: _this.context.createInvokeHandler('editor.formatBlock')
5785                  }),
5786              ]).render();
5787          });
5788          var _loop_1 = function (styleIdx, styleLen) {
5789              var item = this_1.options.styleTags[styleIdx];
5790              this_1.context.memo('button.style.' + item, function () {
5791                  return _this.button({
5792                      className: 'note-btn-style-' + item,
5793                      contents: '<div data-value="' + item + '">' + item.toUpperCase() + '</div>',
5794                      tooltip: _this.lang.style[item],
5795                      click: _this.context.createInvokeHandler('editor.formatBlock')
5796                  }).render();
5797              });
5798          };
5799          var this_1 = this;
5800          for (var styleIdx = 0, styleLen = this.options.styleTags.length; styleIdx < styleLen; styleIdx++) {
5801              _loop_1(styleIdx, styleLen);
5802          }
5803          this.context.memo('button.bold', function () {
5804              return _this.button({
5805                  className: 'note-btn-bold',
5806                  contents: _this.ui.icon(_this.options.icons.bold),
5807                  tooltip: _this.lang.font.bold + _this.representShortcut('bold'),
5808                  click: _this.context.createInvokeHandlerAndUpdateState('editor.bold')
5809              }).render();
5810          });
5811          this.context.memo('button.italic', function () {
5812              return _this.button({
5813                  className: 'note-btn-italic',
5814                  contents: _this.ui.icon(_this.options.icons.italic),
5815                  tooltip: _this.lang.font.italic + _this.representShortcut('italic'),
5816                  click: _this.context.createInvokeHandlerAndUpdateState('editor.italic')
5817              }).render();
5818          });
5819          this.context.memo('button.underline', function () {
5820              return _this.button({
5821                  className: 'note-btn-underline',
5822                  contents: _this.ui.icon(_this.options.icons.underline),
5823                  tooltip: _this.lang.font.underline + _this.representShortcut('underline'),
5824                  click: _this.context.createInvokeHandlerAndUpdateState('editor.underline')
5825              }).render();
5826          });
5827          this.context.memo('button.clear', function () {
5828              return _this.button({
5829                  contents: _this.ui.icon(_this.options.icons.eraser),
5830                  tooltip: _this.lang.font.clear + _this.representShortcut('removeFormat'),
5831                  click: _this.context.createInvokeHandler('editor.removeFormat')
5832              }).render();
5833          });
5834          this.context.memo('button.strikethrough', function () {
5835              return _this.button({
5836                  className: 'note-btn-strikethrough',
5837                  contents: _this.ui.icon(_this.options.icons.strikethrough),
5838                  tooltip: _this.lang.font.strikethrough + _this.representShortcut('strikethrough'),
5839                  click: _this.context.createInvokeHandlerAndUpdateState('editor.strikethrough')
5840              }).render();
5841          });
5842          this.context.memo('button.superscript', function () {
5843              return _this.button({
5844                  className: 'note-btn-superscript',
5845                  contents: _this.ui.icon(_this.options.icons.superscript),
5846                  tooltip: _this.lang.font.superscript,
5847                  click: _this.context.createInvokeHandlerAndUpdateState('editor.superscript')
5848              }).render();
5849          });
5850          this.context.memo('button.subscript', function () {
5851              return _this.button({
5852                  className: 'note-btn-subscript',
5853                  contents: _this.ui.icon(_this.options.icons.subscript),
5854                  tooltip: _this.lang.font.subscript,
5855                  click: _this.context.createInvokeHandlerAndUpdateState('editor.subscript')
5856              }).render();
5857          });
5858          this.context.memo('button.fontname', function () {
vendor: 7,092 bytes, lines 5859-5984
5859              var styleInfo = _this.context.invoke('editor.currentStyle');
5860              // Add 'default' fonts into the fontnames array if not exist
5861              $$1.each(styleInfo['font-family'].split(','), function (idx, fontname) {
5862                  fontname = fontname.trim().replace(/['"]+/g, '');
5863                  if (_this.isFontDeservedToAdd(fontname)) {
5864                      if (_this.options.fontNames.indexOf(fontname) === -1) {
5865                          _this.options.fontNames.push(fontname);
5866                      }
5867                  }
5868              });
5869              return _this.ui.buttonGroup([
5870                  _this.button({
5871                      className: 'dropdown-toggle',
5872                      contents: _this.ui.dropdownButtonContents('<span class="note-current-fontname"/>', _this.options),
5873                      tooltip: _this.lang.font.name,
5874                      data: {
5875                          toggle: 'dropdown'
5876                      }
5877                  }),
5878                  _this.ui.dropdownCheck({
5879                      className: 'dropdown-fontname',
5880                      checkClassName: _this.options.icons.menuCheck,
5881                      items: _this.options.fontNames.filter(_this.isFontInstalled.bind(_this)),
5882                      title: _this.lang.font.name,
5883                      template: function (item) {
5884                          return '<span style="font-family: \'' + item + '\'">' + item + '</span>';
5885                      },
5886                      click: _this.context.createInvokeHandlerAndUpdateState('editor.fontName')
5887                  }),
5888              ]).render();
5889          });
5890          this.context.memo('button.fontsize', function () {
5891              return _this.ui.buttonGroup([
5892                  _this.button({
5893                      className: 'dropdown-toggle',
5894                      contents: _this.ui.dropdownButtonContents('<span class="note-current-fontsize"/>', _this.options),
5895                      tooltip: _this.lang.font.size,
5896                      data: {
5897                          toggle: 'dropdown'
5898                      }
5899                  }),
5900                  _this.ui.dropdownCheck({
5901                      className: 'dropdown-fontsize',
5902                      checkClassName: _this.options.icons.menuCheck,
5903                      items: _this.options.fontSizes,
5904                      title: _this.lang.font.size,
5905                      click: _this.context.createInvokeHandlerAndUpdateState('editor.fontSize')
5906                  }),
5907              ]).render();
5908          });
5909          this.context.memo('button.color', function () {
5910              return _this.colorPalette('note-color-all', _this.lang.color.recent, true, true);
5911          });
5912          this.context.memo('button.forecolor', function () {
5913              return _this.colorPalette('note-color-fore', _this.lang.color.foreground, false, true);
5914          });
5915          this.context.memo('button.backcolor', function () {
5916              return _this.colorPalette('note-color-back', _this.lang.color.background, true, false);
5917          });
5918          this.context.memo('button.ul', function () {
5919              return _this.button({
5920                  contents: _this.ui.icon(_this.options.icons.unorderedlist),
5921                  tooltip: _this.lang.lists.unordered + _this.representShortcut('insertUnorderedList'),
5922                  click: _this.context.createInvokeHandler('editor.insertUnorderedList')
5923              }).render();
5924          });
5925          this.context.memo('button.ol', function () {
5926              return _this.button({
5927                  contents: _this.ui.icon(_this.options.icons.orderedlist),
5928                  tooltip: _this.lang.lists.ordered + _this.representShortcut('insertOrderedList'),
5929                  click: _this.context.createInvokeHandler('editor.insertOrderedList')
5930              }).render();
5931          });
5932          var justifyLeft = this.button({
5933              contents: this.ui.icon(this.options.icons.alignLeft),
5934              tooltip: this.lang.paragraph.left + this.representShortcut('justifyLeft'),
5935              click: this.context.createInvokeHandler('editor.justifyLeft')
5936          });
5937          var justifyCenter = this.button({
5938              contents: this.ui.icon(this.options.icons.alignCenter),
5939              tooltip: this.lang.paragraph.center + this.representShortcut('justifyCenter'),
5940              click: this.context.createInvokeHandler('editor.justifyCenter')
5941          });
5942          var justifyRight = this.button({
5943              contents: this.ui.icon(this.options.icons.alignRight),
5944              tooltip: this.lang.paragraph.right + this.representShortcut('justifyRight'),
5945              click: this.context.createInvokeHandler('editor.justifyRight')
5946          });
5947          var justifyFull = this.button({
5948              contents: this.ui.icon(this.options.icons.alignJustify),
5949              tooltip: this.lang.paragraph.justify + this.representShortcut('justifyFull'),
5950              click: this.context.createInvokeHandler('editor.justifyFull')
5951          });
5952          var outdent = this.button({
5953              contents: this.ui.icon(this.options.icons.outdent),
5954              tooltip: this.lang.paragraph.outdent + this.representShortcut('outdent'),
5955              click: this.context.createInvokeHandler('editor.outdent')
5956          });
5957          var indent = this.button({
5958              contents: this.ui.icon(this.options.icons.indent),
5959              tooltip: this.lang.paragraph.indent + this.representShortcut('indent'),
5960              click: this.context.createInvokeHandler('editor.indent')
5961          });
5962          this.context.memo('button.justifyLeft', func.invoke(justifyLeft, 'render'));
5963          this.context.memo('button.justifyCenter', func.invoke(justifyCenter, 'render'));
5964          this.context.memo('button.justifyRight', func.invoke(justifyRight, 'render'));
5965          this.context.memo('button.justifyFull', func.invoke(justifyFull, 'render'));
5966          this.context.memo('button.outdent', func.invoke(outdent, 'render'));
5967          this.context.memo('button.indent', func.invoke(indent, 'render'));
5968          this.context.memo('button.paragraph', function () {
5969              return _this.ui.buttonGroup([
5970                  _this.button({
5971                      className: 'dropdown-toggle',
5972                      contents: _this.ui.dropdownButtonContents(_this.ui.icon(_this.options.icons.alignLeft), _this.options),
5973                      tooltip: _this.lang.paragraph.paragraph,
5974                      data: {
5975                          toggle: 'dropdown'
5976                      }
5977                  }),
5978                  _this.ui.dropdown([
5979                      _this.ui.buttonGroup({
5980                          className: 'note-align',
5981                          children: [justifyLeft, justifyCenter, justifyRight, justifyFull]
5982                      }),
5983                      _this.ui.buttonGroup({
5984                          className: 'note-list',
5985                          children: [outdent, indent]
5986                      }),
5987                  ]),
5988              ]).render();
5989          });
5990          this.context.memo('button.height', function () {
5991              return _this.ui.buttonGroup([
5992                  _this.button({
5993                      className: 'dropdown-toggle',
5994                      contents: _this.ui.dropdownButtonContents(_this.ui.icon(_this.options.icons.textHeight), _this.options),
5995                      tooltip: _this.lang.font.height,
5996                      data: {
5997                          toggle: 'dropdown'
5998                      }
5999                  }),
6000                  _this.ui.dropdownCheck({
6001                      items: _this.options.lineHeights,
6002                      checkClassName: _this.options.icons.menuCheck,
6003                      className: 'dropdown-line-height',
6004                      title: _this.lang.font.height,
6005                      click: _this.context.createInvokeHandler('editor.lineHeight')
6006                  }),
6007              ]).render();
6008          });
6009          this.context.memo('button.table', function () {
6010              return _this.ui.buttonGroup([
6011                  _this.button({
6012                      className: 'dropdown-toggle',
6013                      contents: _this.ui.dropdownButtonContents(_this.ui.icon(_this.options.icons.table), _this.options),
6014                      tooltip: _this.lang.table.table,
6015                      data: {
6016                          toggle: 'dropdown'
6017                      }
6018                  }),
6019                  _this.ui.dropdown({
6020                      title: _this.lang.table.table,
6021                      className: 'note-table',
6022                      items: [
6023                          '<div class="note-dimension-picker">',
6024                          '  <div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"/>',
6025                          '  <div class="note-dimension-picker-highlighted"/>',
6026                          '  <div class="note-dimension-picker-unhighlighted"/>',
6027                          '</div>',
6028                          '<div class="note-dimension-display">1 x 1</div>',
6029                      ].join('')
6030                  }),
6031              ], {
6032                  callback: function ($node) {
6033                      var $catcher = $node.find('.note-dimension-picker-mousecatcher');
6034                      $catcher.css({
6035                          width: _this.options.insertTableMaxSize.col + 'em',
6036                          height: _this.options.insertTableMaxSize.row + 'em'
6037                      }).mousedown(_this.context.createInvokeHandler('editor.insertTable'))
6038                          .on('mousemove', _this.tableMoveHandler.bind(_this));
6039                  }
6040              }).render();
6041          });
6042          this.context.memo('button.link', function () {
6043              return _this.button({
6044                  contents: _this.ui.icon(_this.options.icons.link),
6045                  tooltip: _this.lang.link.link + _this.representShortcut('linkDialog.show'),
6046                  click: _this.context.createInvokeHandler('linkDialog.show')
6047              }).render();
6048          });
6049          this.context.memo('button.picture', function () {
6050              return _this.button({
6051                  contents: _this.ui.icon(_this.options.icons.picture),
6052                  tooltip: _this.lang.image.image,
6053                  click: _this.context.createInvokeHandler('imageDialog.show')
6054              }).render();
6055          });
6056          this.context.memo('button.video', function () {
6057              return _this.button({
6058                  contents: _this.ui.icon(_this.options.icons.video),
6059                  tooltip: _this.lang.video.video,
6060                  click: _this.context.createInvokeHandler('videoDialog.show')
6061              }).render();
6062          });
6063          this.context.memo('button.hr', function () {
6064              return _this.button({
6065                  contents: _this.ui.icon(_this.options.icons.minus),
6066                  tooltip: _this.lang.hr.insert + _this.representShortcut('insertHorizontalRule'),
6067                  click: _this.context.createInvokeHandler('editor.insertHorizontalRule')
6068              }).render();
6069          });
6070          this.context.memo('button.fullscreen', function () {
6071              return _this.button({
6072                  className: 'btn-fullscreen',
6073                  contents: _this.ui.icon(_this.options.icons.arrowsAlt),
6074                  tooltip: _this.lang.options.fullscreen,
6075                  click: _this.context.createInvokeHandler('fullscreen.toggle')
6076              }).render();
6077          });
6078          this.context.memo('button.codeview', function () {
6079              return _this.button({
6080                  className: 'btn-codeview',
6081                  contents: _this.ui.icon(_this.options.icons.code),
6082                  tooltip: _this.lang.options.codeview,
6083                  click: _this.context.createInvokeHandler('codeview.toggle')
6084              }).render();
6085          });
6086          this.context.memo('button.redo', function () {
6087              return _this.button({
6088                  contents: _this.ui.icon(_this.options.icons.redo),
6089                  tooltip: _this.lang.history.redo + _this.representShortcut('redo'),
6090                  click: _this.context.createInvokeHandler('editor.redo')
6091              }).render();
6092          });
6093          this.context.memo('button.undo', function () {
6094              return _this.button({
6095                  contents: _this.ui.icon(_this.options.icons.undo),
6096                  tooltip: _this.lang.history.undo + _this.representShortcut('undo'),
6097                  click: _this.context.createInvokeHandler('editor.undo')
6098              }).render();
6099          });
6100          this.context.memo('button.help', function () {
6101              return _this.button({
6102                  contents: _this.ui.icon(_this.options.icons.question),
6103                  tooltip: _this.lang.options.help,
6104                  click: _this.context.createInvokeHandler('helpDialog.show')
6105              }).render();
6106          });
6107      };
6108      /**
6109       * image: [
6110       *   ['imageResize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']],
6111       *   ['float', ['floatLeft', 'floatRight', 'floatNone']],
6112       *   ['remove', ['removeMedia']],
6113       * ],
6114       */
6115      Buttons.prototype.addImagePopoverButtons = function () {
6116          var _this = this;
6117          // Image Size Buttons
6118          this.context.memo('button.resizeFull', function () {
6119              return _this.button({
6120                  contents: '<span class="note-fontsize-10">100%</span>',
6121                  tooltip: _this.lang.image.resizeFull,
6122                  click: _this.context.createInvokeHandler('editor.resize', '1')
6123              }).render();
6124          });
6125          this.context.memo('button.resizeHalf', function () {
6126              return _this.button({
6127                  contents: '<span class="note-fontsize-10">50%</span>',
6128                  tooltip: _this.lang.image.resizeHalf,
6129                  click: _this.context.createInvokeHandler('editor.resize', '0.5')
6130              }).render();
6131          });
6132          this.context.memo('button.resizeQuarter', function () {
6133              return _this.button({
6134                  contents: '<span class="note-fontsize-10">25%</span>',
6135                  tooltip: _this.lang.image.resizeQuarter,
6136                  click: _this.context.createInvokeHandler('editor.resize', '0.25')
6137              }).render();
6138          });
6139          this.context.memo('button.resizeNone', function () {
6140              return _this.button({
6141                  contents: _this.ui.icon(_this.options.icons.rollback),
6142                  tooltip: _this.lang.image.resizeNone,
6143                  click: _this.context.createInvokeHandler('editor.resize', '0')
6144              }).render();
6145          });
6146          // Float Buttons
6147          this.context.memo('button.floatLeft', function () {
6148              return _this.button({
6149                  contents: _this.ui.icon(_this.options.icons.floatLeft),
6150                  tooltip: _this.lang.image.floatLeft,
6151                  click: _this.context.createInvokeHandler('editor.floatMe', 'left')
6152              }).render();
6153          });
6154          this.context.memo('button.floatRight', function () {
6155              return _this.button({
6156                  contents: _this.ui.icon(_this.options.icons.floatRight),
6157                  tooltip: _this.lang.image.floatRight,
6158                  click: _this.context.createInvokeHandler('editor.floatMe', 'right')
6159              }).render();
6160          });
6161          this.context.memo('button.floatNone', function () {
6162              return _this.button({
6163                  contents: _this.ui.icon(_this.options.icons.rollback),
6164                  tooltip: _this.lang.image.floatNone,
6165                  click: _this.context.createInvokeHandler('editor.floatMe', 'none')
6166              }).render();
6167          });
6168          // Remove Buttons
6169          this.context.memo('button.removeMedia', function () {
6170              return _this.button({
6171                  contents: _this.ui.icon(_this.options.icons.trash),
6172                  tooltip: _this.lang.image.remove,
6173                  click: _this.context.createInvokeHandler('editor.removeMedia')
6174              }).render();
6175          });
6176      };
6177      Buttons.prototype.addLinkPopoverButtons = function () {
6178          var _this = this;
6179          this.context.memo('button.linkDialogShow', function () {
6180              return _this.button({
6181                  contents: _this.ui.icon(_this.options.icons.link),
6182                  tooltip: _this.lang.link.edit,
6183                  click: _this.context.createInvokeHandler('linkDialog.show')
6184              }).render();
6185          });
6186          this.context.memo('button.unlink', function () {
6187              return _this.button({
6188                  contents: _this.ui.icon(_this.options.icons.unlink),
6189                  tooltip: _this.lang.link.unlink,
6190                  click: _this.context.createInvokeHandler('editor.unlink')
6191              }).render();
6192          });
6193      };
6194      /**
6195       * table : [
6196       *  ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
6197       *  ['delete', ['deleteRow', 'deleteCol', 'deleteTable']]
6198       * ],
6199       */
6200      Buttons.prototype.addTablePopoverButtons = function () {
6201          var _this = this;
6202          this.context.memo('button.addRowUp', function () {
6203              return _this.button({
6204                  className: 'btn-md',
6205                  contents: _this.ui.icon(_this.options.icons.rowAbove),
6206                  tooltip: _this.lang.table.addRowAbove,
6207                  click: _this.context.createInvokeHandler('editor.addRow', 'top')
6208              }).render();
6209          });
6210          this.context.memo('button.addRowDown', function () {
6211              return _this.button({
6212                  className: 'btn-md',
6213                  contents: _this.ui.icon(_this.options.icons.rowBelow),
6214                  tooltip: _this.lang.table.addRowBelow,
6215                  click: _this.context.createInvokeHandler('editor.addRow', 'bottom')
6216              }).render();
6217          });
6218          this.context.memo('button.addColLeft', function () {
6219              return _this.button({
6220                  className: 'btn-md',
6221                  contents: _this.ui.icon(_this.options.icons.colBefore),
6222                  tooltip: _this.lang.table.addColLeft,
6223                  click: _this.context.createInvokeHandler('editor.addCol', 'left')
6224              }).render();
6225          });
6226          this.context.memo('button.addColRight', function () {
6227              return _this.button({
6228                  className: 'btn-md',
6229                  contents: _this.ui.icon(_this.options.icons.colAfter),
6230                  tooltip: _this.lang.table.addColRight,
6231                  click: _this.context.createInvokeHandler('editor.addCol', 'right')
6232              }).render();
6233          });
6234          this.context.memo('button.deleteRow', function () {
6235              return _this.button({
6236                  className: 'btn-md',
6237                  contents: _this.ui.icon(_this.options.icons.rowRemove),
6238                  tooltip: _this.lang.table.delRow,
6239                  click: _this.context.createInvokeHandler('editor.deleteRow')
6240              }).render();
6241          });
6242          this.context.memo('button.deleteCol', function () {
6243              return _this.button({
6244                  className: 'btn-md',
6245                  contents: _this.ui.icon(_this.options.icons.colRemove),
6246                  tooltip: _this.lang.table.delCol,
6247                  click: _this.context.createInvokeHandler('editor.deleteCol')
6248              }).render();
6249          });
6250          this.context.memo('button.deleteTable', function () {
6251              return _this.button({
6252                  className: 'btn-md',
6253                  contents: _this.ui.icon(_this.options.icons.trash),
6254                  tooltip: _this.lang.table.delTable,
6255                  click: _this.context.createInvokeHandler('editor.deleteTable')
6256              }).render();
6257          });
6258      };
6259      Buttons.prototype.build = function ($container, groups) {
6260          for (var groupIdx = 0, groupLen = groups.length; groupIdx < groupLen; groupIdx++) {
6261              var group = groups[groupIdx];
6262              var groupName = Array.isArray(group) ? group[0] : group;
6263              var buttons = Array.isArray(group) ? ((group.length === 1) ? [group[0]] : group[1]) : [group];
6264              var $group = this.ui.buttonGroup({
6265                  className: 'note-' + groupName
6266              }).render();
6267              for (var idx = 0, len = buttons.length; idx < len; idx++) {
6268                  var btn = this.context.memo('button.' + buttons[idx]);
6269                  if (btn) {
6270                      $group.append(typeof btn === 'function' ? btn() : btn);
6271                  }
6272              }
6273              $group.appendTo($container);
6274          }
6275      };
6276      /**
6277       * @param {jQuery} [$container]
6278       */
6279      Buttons.prototype.updateCurrentStyle = function ($container) {
6280          var _this = this;
6281          var $cont = $container || this.$toolbar;
6282          var styleInfo = this.context.invoke('editor.currentStyle');
6283          this.updateBtnStates($cont, {
6284              '.note-btn-bold': function () {
6285                  return styleInfo['font-bold'] === 'bold';
6286              },
6287              '.note-btn-italic': function () {
6288                  return styleInfo['font-italic'] === 'italic';
6289              },
6290              '.note-btn-underline': function () {
6291                  return styleInfo['font-underline'] === 'underline';
6292              },
6293              '.note-btn-subscript': function () {
6294                  return styleInfo['font-subscript'] === 'subscript';
6295              },
6296              '.note-btn-superscript': function () {
6297                  return styleInfo['font-superscript'] === 'superscript';
6298              },
6299              '.note-btn-strikethrough': function () {
6300                  return styleInfo['font-strikethrough'] === 'strikethrough';
6301              }
6302          });
6303          if (styleInfo['font-family']) {
6304              var fontNames = styleInfo['font-family'].split(',').map(function (name) {
6305                  return name.replace(/[\'\"]/g, '')
6306                      .replace(/\s+$/, '')
6307                      .replace(/^\s+/, '');
6308              });
6309              var fontName_1 = lists.find(fontNames, this.isFontInstalled.bind(this));
6310              $cont.find('.dropdown-fontname a').each(function (idx, item) {
6311                  var $item = $$1(item);
6312                  // always compare string to avoid creating another func.
6313                  var isChecked = ($item.data('value') + '') === (fontName_1 + '');
6314                  $item.toggleClass('checked', isChecked);
6315              });
6316              $cont.find('.note-current-fontname').text(fontName_1).css('font-family', fontName_1);
6317          }
6318          if (styleInfo['font-size']) {
6319              var fontSize_1 = styleInfo['font-size'];
6320              $cont.find('.dropdown-fontsize a').each(function (idx, item) {
6321                  var $item = $$1(item);
6322                  // always compare with string to avoid creating another func.
6323                  var isChecked = ($item.data('value') + '') === (fontSize_1 + '');
6324                  $item.toggleClass('checked', isChecked);
6325              });
6326              $cont.find('.note-current-fontsize').text(fontSize_1);
6327          }
6328          if (styleInfo['line-height']) {
6329              var lineHeight_1 = styleInfo['line-height'];
6330              $cont.find('.dropdown-line-height li a').each(function (idx, item) {
6331                  // always compare with string to avoid creating another func.
6332                  var isChecked = ($$1(item).data('value') + '') === (lineHeight_1 + '');
6333                  _this.className = isChecked ? 'checked' : '';
6334              });
6335          }
6336      };
6337      Buttons.prototype.updateBtnStates = function ($container, infos) {
6338          var _this = this;
6339          $$1.each(infos, function (selector, pred) {
6340              _this.ui.toggleBtnActive($container.find(selector), pred());
6341          });
6342      };
6343      Buttons.prototype.tableMoveHandler = function (event) {
6344          var PX_PER_EM = 18;
6345          var $picker = $$1(event.target.parentNode); // target is mousecatcher
6346          var $dimensionDisplay = $picker.next();
6347          var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
6348          var $highlighted = $picker.find('.note-dimension-picker-highlighted');
6349          var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
6350          var posOffset;
6351          // HTML5 with jQuery - e.offsetX is undefined in Firefox
6352          if (event.offsetX === undefined) {
6353              var posCatcher = $$1(event.target).offset();
6354              posOffset = {
6355                  x: event.pageX - posCatcher.left,
6356                  y: event.pageY - posCatcher.top
6357              };
6358          }
6359          else {
6360              posOffset = {
6361                  x: event.offsetX,
6362                  y: event.offsetY
6363              };
6364          }
6365          var dim = {
6366              c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
6367              r: Math.ceil(posOffset.y / PX_PER_EM) || 1
6368          };
6369          $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });
6370          $catcher.data('value', dim.c + 'x' + dim.r);
6371          if (dim.c > 3 && dim.c < this.options.insertTableMaxSize.col) {
6372              $unhighlighted.css({ width: dim.c + 1 + 'em' });
6373          }
6374          if (dim.r > 3 && dim.r < this.options.insertTableMaxSize.row) {
6375              $unhighlighted.css({ height: dim.r + 1 + 'em' });
6376          }
6377          $dimensionDisplay.html(dim.c + ' x ' + dim.r);
6378      };
6379      return Buttons;
6380  }());
6381
6382  var Toolbar = /** @class */ (function () {
6383      function Toolbar(context) {
6384          this.context = context;
6385          this.$window = $$1(window);
6386          this.$document = $$1(document);
6387          this.ui = $$1.summernote.ui;
6388          this.$note = context.layoutInfo.note;
6389          this.$editor = context.layoutInfo.editor;
6390          this.$toolbar = context.layoutInfo.toolbar;
6391          this.$editable = context.layoutInfo.editable;
6392          this.$statusbar = context.layoutInfo.statusbar;
6393          this.options = context.options;
6394          this.isFollowing = false;
6395          this.followScroll = this.followScroll.bind(this);
6396      }
6397      Toolbar.prototype.shouldInitialize = function () {
6398          return !this.options.airMode;
6399      };
6400      Toolbar.prototype.initialize = function () {
6401          var _this = this;
6402          this.options.toolbar = this.options.toolbar || [];
6403          if (!this.options.toolbar.length) {
6404              this.$toolbar.hide();
6405          }
6406          else {
6407              this.context.invoke('buttons.build', this.$toolbar, this.options.toolbar);
6408          }
6409          if (this.options.toolbarContainer) {
6410              this.$toolbar.appendTo(this.options.toolbarContainer);
6411          }
6412          this.changeContainer(false);
6413          this.$note.on('summernote.keyup summernote.mouseup summernote.change', function () {
6414              _this.context.invoke('buttons.updateCurrentStyle');
6415          });
6416          this.context.invoke('buttons.updateCurrentStyle');
6417          if (this.options.followingToolbar) {
6418              this.$window.on('scroll resize', this.followScroll);
6419          }
6420      };
6421      Toolbar.prototype.destroy = function () {
6422          this.$toolbar.children().remove();
6423          if (this.options.followingToolbar) {
6424              this.$window.off('scroll resize', this.followScroll);
6425          }
6426      };
6427      Toolbar.prototype.followScroll = function () {
6428          if (this.$editor.hasClass('fullscreen')) {
6429              return false;
6430          }
6431          var editorHeight = this.$editor.outerHeight();
6432          var editorWidth = this.$editor.width();
6433          var toolbarHeight = this.$toolbar.height();
6434          var statusbarHeight = this.$statusbar.height();
6435          // check if the web app is currently using another static bar
6436          var otherBarHeight = 0;
6437          if (this.options.otherStaticBar) {
6438              otherBarHeight = $$1(this.options.otherStaticBar).outerHeight();
6439          }
6440          var currentOffset = this.$document.scrollTop();
6441          var editorOffsetTop = this.$editor.offset().top;
6442          var editorOffsetBottom = editorOffsetTop + editorHeight;
6443          var activateOffset = editorOffsetTop - otherBarHeight;
6444          var deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight - statusbarHeight;
6445          if (!this.isFollowing &&
6446              (currentOffset > activateOffset) && (currentOffset < deactivateOffsetBottom - toolbarHeight)) {
6447              this.isFollowing = true;
6448              this.$toolbar.css({
6449                  position: 'fixed',
6450                  top: otherBarHeight,
6451                  width: editorWidth
6452              });
6453              this.$editable.css({
6454                  marginTop: this.$toolbar.height() + 5
6455              });
6456          }
6457          else if (this.isFollowing &&
6458              ((currentOffset < activateOffset) || (currentOffset > deactivateOffsetBottom))) {
6459              this.isFollowing = false;
6460              this.$toolbar.css({
6461                  position: 'relative',
6462                  top: 0,
6463                  width: '100%'
6464              });
6465              this.$editable.css({
6466                  marginTop: ''
6467              });
6468          }
6469      };
6470      Toolbar.prototype.changeContainer = function (isFullscreen) {
6471          if (isFullscreen) {
6472              this.$toolbar.prependTo(this.$editor);
6473          }
6474          else {
6475              if (this.options.toolbarContainer) {
6476                  this.$toolbar.appendTo(this.options.toolbarContainer);
6477              }
6478          }
6479          this.followScroll();
6480      };
6481      Toolbar.prototype.updateFullscreen = function (isFullscreen) {
6482          this.ui.toggleBtnActive(this.$toolbar.find('.btn-fullscreen'), isFullscreen);
6483          this.changeContainer(isFullscreen);
6484      };
6485      Toolbar.prototype.updateCodeview = function (isCodeview) {
6486          this.ui.toggleBtnActive(this.$toolbar.find('.btn-codeview'), isCodeview);
6487          if (isCodeview) {
6488              this.deactivate();
6489          }
6490          else {
6491              this.activate();
6492          }
6493      };
6494      Toolbar.prototype.activate = function (isIncludeCodeview) {
6495          var $btn = this.$toolbar.find('button');
6496          if (!isIncludeCodeview) {
6497              $btn = $btn.not('.btn-codeview');
6498          }
6499          this.ui.toggleBtn($btn, true);
6500      };
6501      Toolbar.prototype.deactivate = function (isIncludeCodeview) {
6502          var $btn = this.$toolbar.find('button');
6503          if (!isIncludeCodeview) {
6504              $btn = $btn.not('.btn-codeview');
6505          }
6506          this.ui.toggleBtn($btn, false);
6507      };
6508      return Toolbar;
6509  }());
6510
6511  var LinkDialog = /** @class */ (function () {
6512      function LinkDialog(context) {
6513          this.context = context;
6514          this.ui = $$1.summernote.ui;
6515          this.$body = $$1(document.body);
6516          this.$editor = context.layoutInfo.editor;
6517          this.options = context.options;
6518          this.lang = this.options.langInfo;
6519          context.memo('help.linkDialog.show', this.options.langInfo.help['linkDialog.show']);
6520      }
6521      LinkDialog.prototype.initialize = function () {
6522          var $container = this.options.dialogsInBody ? this.$body : this.$editor;
6523          var body = [
6524              '<div class="form-group note-form-group">',
6525              "<label class=\"note-form-label\">" + this.lang.link.textToDisplay + "</label>",
6526              '<input class="note-link-text form-control note-form-control note-input" type="text" />',
6527              '</div>',
6528              '<div class="form-group note-form-group">',
6529              "<label class=\"note-form-label\">" + this.lang.link.url + "</label>",
6530              '<input class="note-link-url form-control note-form-control note-input" type="text" value="http://" />',
6531              '</div>',
6532              !this.options.disableLinkTarget
6533                  ? $$1('<div/>').append(this.ui.checkbox({
6534                      className: 'sn-checkbox-open-in-new-window',
6535                      text: this.lang.link.openInNewWindow,
6536                      checked: true
6537                  }).render()).html()
6538                  : '',
6539          ].join('');
6540          var buttonClass = 'btn btn-primary note-btn note-btn-primary note-link-btn';
6541          var footer = "<input type=\"button\" href=\"#\" class=\"" + buttonClass + "\" value=\"" + this.lang.link.insert + "\" disabled>";
6542          this.$dialog = this.ui.dialog({
6543              className: 'link-dialog',
6544              title: this.lang.link.insert,
6545              fade: this.options.dialogsFade,
6546              body: body,
6547              footer: footer
6548          }).render().appendTo($container);
6549      };
6550      LinkDialog.prototype.destroy = function () {
6551          this.ui.hideDialog(this.$dialog);
6552          this.$dialog.remove();
6553      };
6554      LinkDialog.prototype.bindEnterKey = function ($input, $btn) {
6555          $input.on('keypress', function (event) {
6556              if (event.keyCode === key.code.ENTER) {
6557                  event.preventDefault();
6558                  $btn.trigger('click');
6559              }
6560          });
6561      };
6562      /**
6563       * toggle update button
6564       */
6565      LinkDialog.prototype.toggleLinkBtn = function ($linkBtn, $linkText, $linkUrl) {
6566          this.ui.toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
6567      };
6568      /**
6569       * Show link dialog and set event handlers on dialog controls.
6570       *
6571       * @param {Object} linkInfo
6572       * @return {Promise}
6573       */
6574      LinkDialog.prototype.showLinkDialog = function (linkInfo) {
6575          var _this = this;
6576          return $$1.Deferred(function (deferred) {
6577              var $linkText = _this.$dialog.find('.note-link-text');
6578              var $linkUrl = _this.$dialog.find('.note-link-url');
6579              var $linkBtn = _this.$dialog.find('.note-link-btn');
6580              var $openInNewWindow = _this.$dialog
6581                  .find('.sn-checkbox-open-in-new-window input[type=checkbox]');
6582              _this.ui.onDialogShown(_this.$dialog, function () {
6583                  _this.context.triggerEvent('dialog.shown');
6584                  // If no url was given and given text is valid URL then copy that into URL Field
6585                  if (!linkInfo.url && func.isValidUrl(linkInfo.text)) {
6586                      linkInfo.url = linkInfo.text;
6587                  }
6588                  $linkText.on('input paste propertychange', function () {
6589                      // If linktext was modified by input events,
6590                      // cloning text from linkUrl will be stopped.
6591                      linkInfo.text = $linkText.val();
6592                      _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
6593                  }).val(linkInfo.text);
6594                  $linkUrl.on('input paste propertychange', function () {
6595                      // Display same text on `Text to display` as default
6596                      // when linktext has no text
6597                      if (!linkInfo.text) {
6598                          $linkText.val($linkUrl.val());
6599                      }
6600                      _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
6601                  }).val(linkInfo.url);
6602                  if (!env.isSupportTouch) {
6603                      $linkUrl.trigger('focus');
6604                  }
6605                  _this.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
6606                  _this.bindEnterKey($linkUrl, $linkBtn);
6607                  _this.bindEnterKey($linkText, $linkBtn);
6608                  var isNewWindowChecked = linkInfo.isNewWindow !== undefined
6609                      ? linkInfo.isNewWindow : _this.context.options.linkTargetBlank;
6610                  $openInNewWindow.prop('checked', isNewWindowChecked);
6611                  $linkBtn.one('click', function (event) {
6612                      event.preventDefault();
6613                      deferred.resolve({
6614                          range: linkInfo.range,
6615                          url: $linkUrl.val(),
6616                          text: $linkText.val(),
6617                          isNewWindow: $openInNewWindow.is(':checked')
6618                      });
6619                      _this.ui.hideDialog(_this.$dialog);
6620                  });
6621              });
6622              _this.ui.onDialogHidden(_this.$dialog, function () {
6623                  // detach events
6624                  $linkText.off();
6625                  $linkUrl.off();
6626                  $linkBtn.off();
6627                  if (deferred.state() === 'pending') {
6628                      deferred.reject();
6629                  }
6630              });
6631              _this.ui.showDialog(_this.$dialog);
6632          }).promise();
6633      };
6634      /**
6635       * @param {Object} layoutInfo
6636       */
6637      LinkDialog.prototype.show = function () {
6638          var _this = this;
6639          var linkInfo = this.context.invoke('editor.getLinkInfo');
6640          this.context.invoke('editor.saveRange');
6641          this.showLinkDialog(linkInfo).then(function (linkInfo) {
6642              _this.context.invoke('editor.restoreRange');
6643              _this.context.invoke('editor.createLink', linkInfo);
6644          }).fail(function () {
6645              _this.context.invoke('editor.restoreRange');
6646          });
6647      };
6648      return LinkDialog;
6649  }());
6650
6651  var LinkPopover = /** @class */ (function () {
6652      function LinkPopover(context) {
6653          var _this = this;
6654          this.context = context;
6655          this.ui = $$1.summernote.ui;
6656          this.options = context.options;
6657          this.events = {
6658              'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function () {
6659                  _this.update();
6660              },
6661              'summernote.disable summernote.dialog.shown': function () {
6662                  _this.hide();
6663              }
6664          };
6665      }
6666      LinkPopover.prototype.shouldInitialize = function () {
6667          return !lists.isEmpty(this.options.popover.link);
6668      };
6669      LinkPopover.prototype.initialize = function () {
6670          this.$popover = this.ui.popover({
6671              className: 'note-link-popover',
6672              callback: function ($node) {
6673                  var $content = $node.find('.popover-content,.note-popover-content');
6674                  $content.prepend('<span><a target="_blank"></a>&nbsp;</span>');
6675              }
6676          }).render().appendTo(this.options.container);
6677          var $content = this.$popover.find('.popover-content,.note-popover-content');
6678          this.context.invoke('buttons.build', $content, this.options.popover.link);
6679      };
6680      LinkPopover.prototype.destroy = function () {
6681          this.$popover.remove();
6682      };
6683      LinkPopover.prototype.update = function () {
6684          // Prevent focusing on editable when invoke('code') is executed
6685          if (!this.context.invoke('editor.hasFocus')) {
6686              this.hide();
6687              return;
6688          }
6689          var rng = this.context.invoke('editor.getLastRange');
6690          if (rng.isCollapsed() && rng.isOnAnchor()) {
6691              var anchor = dom.ancestor(rng.sc, dom.isAnchor);
6692              var href = $$1(anchor).attr('href');
6693              this.$popover.find('a').attr('href', href).html(href);
6694              var pos = dom.posFromPlaceholder(anchor);
6695              this.$popover.css({
6696                  display: 'block',
6697                  left: pos.left,
6698                  top: pos.top
6699              });
6700          }
6701          else {
6702              this.hide();
6703          }
6704      };
6705      LinkPopover.prototype.hide = function () {
6706          this.$popover.hide();
6707      };
6708      return LinkPopover;
6709  }());
6710
6711  var ImageDialog = /** @class */ (function () {
6712      function ImageDialog(context) {
6713          this.context = context;
6714          this.ui = $$1.summernote.ui;
6715          this.$body = $$1(document.body);
6716          this.$editor = context.layoutInfo.editor;
6717          this.options = context.options;
6718          this.lang = this.options.langInfo;
6719      }
6720      ImageDialog.prototype.initialize = function () {
6721          var $container = this.options.dialogsInBody ? this.$body : this.$editor;
6722          var imageLimitation = '';
6723          if (this.options.maximumImageFileSize) {
6724              var unit = Math.floor(Math.log(this.options.maximumImageFileSize) / Math.log(1024));
6725              var readableSize = (this.options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 +
6726                  ' ' + ' KMGTP'[unit] + 'B';
6727              imageLimitation = "<small>" + (this.lang.image.maximumFileSize + ' : ' + readableSize) + "</small>";
6728          }
6729          var body = [
6730              '<div class="form-group note-form-group note-group-select-from-files">',
6731              '<label class="note-form-label">' + this.lang.image.selectFromFiles + '</label>',
6732              '<input class="note-image-input form-control-file note-form-control note-input" ',
6733              ' type="file" name="files" accept="image/*" multiple="multiple" />',
6734              imageLimitation,
6735              '</div>',
6736              '<div class="form-group note-group-image-url" style="overflow:auto;">',
6737              '<label class="note-form-label">' + this.lang.image.url + '</label>',
6738              '<input class="note-image-url form-control note-form-control note-input ',
6739              ' col-md-12" type="text" />',
6740              '</div>',
6741          ].join('');
6742          var buttonClass = 'btn btn-primary note-btn note-btn-primary note-image-btn';
6743          var footer = "<input type=\"button\" href=\"#\" class=\"" + buttonClass + "\" value=\"" + this.lang.image.insert + "\" disabled>";
6744          this.$dialog = this.ui.dialog({
6745              title: this.lang.image.insert,
6746              fade: this.options.dialogsFade,
6747              body: body,
6748              footer: footer
6749          }).render().appendTo($container);
6750      };
6751      ImageDialog.prototype.destroy = function () {
6752          this.ui.hideDialog(this.$dialog);
6753          this.$dialog.remove();
6754      };
6755      ImageDialog.prototype.bindEnterKey = function ($input, $btn) {
6756          $input.on('keypress', function (event) {
6757              if (event.keyCode === key.code.ENTER) {
6758                  event.preventDefault();
6759                  $btn.trigger('click');
6760              }
6761          });
6762      };
6763      ImageDialog.prototype.show = function () {
6764          var _this = this;
6765          this.context.invoke('editor.saveRange');
6766          this.showImageDialog().then(function (data) {
6767              // [workaround] hide dialog before restore range for IE range focus
6768              _this.ui.hideDialog(_this.$dialog);
6769              _this.context.invoke('editor.restoreRange');
6770              if (typeof data === 'string') { // image url
6771                  // If onImageLinkInsert set,
6772                  if (_this.options.callbacks.onImageLinkInsert) {
6773                      _this.context.triggerEvent('image.link.insert', data);
6774                  }
6775                  else {
6776                      _this.context.invoke('editor.insertImage', data);
6777                  }
6778              }
6779              else { // array of files
6780                  _this.context.invoke('editor.insertImagesOrCallback', data);
6781              }
6782          }).fail(function () {
6783              _this.context.invoke('editor.restoreRange');
6784          });
6785      };
6786      /**
6787       * show image dialog
6788       *
6789       * @param {jQuery} $dialog
6790       * @return {Promise}
6791       */
6792      ImageDialog.prototype.showImageDialog = function () {
6793          var _this = this;
6794          return $$1.Deferred(function (deferred) {
6795              var $imageInput = _this.$dialog.find('.note-image-input');
6796              var $imageUrl = _this.$dialog.find('.note-image-url');
6797              var $imageBtn = _this.$dialog.find('.note-image-btn');
6798              _this.ui.onDialogShown(_this.$dialog, function () {
6799                  _this.context.triggerEvent('dialog.shown');
6800                  // Cloning imageInput to clear element.
6801                  $imageInput.replaceWith($imageInput.clone().on('change', function (event) {
6802                      deferred.resolve(event.target.files || event.target.value);
6803                  }).val(''));
6804                  $imageUrl.on('input paste propertychange', function () {
6805                      _this.ui.toggleBtn($imageBtn, $imageUrl.val());
6806                  }).val('');
6807                  if (!env.isSupportTouch) {
6808                      $imageUrl.trigger('focus');
6809                  }
6810                  $imageBtn.click(function (event) {
6811                      event.preventDefault();
6812                      deferred.resolve($imageUrl.val());
6813                  });
6814                  _this.bindEnterKey($imageUrl, $imageBtn);
6815              });
6816              _this.ui.onDialogHidden(_this.$dialog, function () {
6817                  $imageInput.off();
6818                  $imageUrl.off();
6819                  $imageBtn.off();
6820                  if (deferred.state() === 'pending') {
6821                      deferred.reject();
6822                  }
6823              });
6824              _this.ui.showDialog(_this.$dialog);
6825          });
6826      };
6827      return ImageDialog;
6828  }());
6829
6830  /**
6831   * Image popover module
6832   *  mouse events that show/hide popover will be handled by Handle.js.
6833   *  Handle.js will receive the events and invoke 'imagePopover.update'.
6834   */
6835  var ImagePopover = /** @class */ (function () {
6836      function ImagePopover(context) {
6837          var _this = this;
6838          this.context = context;
6839          this.ui = $$1.summernote.ui;
6840          this.editable = context.layoutInfo.editable[0];
6841          this.options = context.options;
6842          this.events = {
6843              'summernote.disable': function () {
6844                  _this.hide();
6845              }
6846          };
6847      }
6848      ImagePopover.prototype.shouldInitialize = function () {
6849          return !lists.isEmpty(this.options.popover.image);
6850      };
6851      ImagePopover.prototype.initialize = function () {
6852          this.$popover = this.ui.popover({
6853              className: 'note-image-popover'
6854          }).render().appendTo(this.options.container);
6855          var $content = this.$popover.find('.popover-content,.note-popover-content');
6856          this.context.invoke('buttons.build', $content, this.options.popover.image);
6857      };
6858      ImagePopover.prototype.destroy = function () {
6859          this.$popover.remove();
6860      };
6861      ImagePopover.prototype.update = function (target, event) {
6862          if (dom.isImg(target)) {
6863              var pos = dom.posFromPlaceholder(target);
6864              var posEditor = dom.posFromPlaceholder(this.editable);
6865              this.$popover.css({
6866                  display: 'block',
6867                  left: this.options.popatmouse ? event.pageX - 20 : pos.left,
6868                  top: this.options.popatmouse ? event.pageY : Math.min(pos.top, posEditor.top)
6869              });
6870          }
6871          else {
6872              this.hide();
6873          }
6874      };
6875      ImagePopover.prototype.hide = function () {
6876          this.$popover.hide();
6877      };
6878      return ImagePopover;
6879  }());
6880
6881  var TablePopover = /** @class */ (function () {
6882      function TablePopover(context) {
6883          var _this = this;
6884          this.context = context;
6885          this.ui = $$1.summernote.ui;
6886          this.options = context.options;
6887          this.events = {
6888              'summernote.mousedown': function (we, e) {
6889                  _this.update(e.target);
6890              },
6891              'summernote.keyup summernote.scroll summernote.change': function () {
6892                  _this.update();
6893              },
6894              'summernote.disable': function () {
6895                  _this.hide();
6896              }
6897          };
6898      }
6899      TablePopover.prototype.shouldInitialize = function () {
6900          return !lists.isEmpty(this.options.popover.table);
6901      };
6902      TablePopover.prototype.initialize = function () {
6903          this.$popover = this.ui.popover({
6904              className: 'note-table-popover'
6905          }).render().appendTo(this.options.container);
6906          var $content = this.$popover.find('.popover-content,.note-popover-content');
6907          this.context.invoke('buttons.build', $content, this.options.popover.table);
6908          // [workaround] Disable Firefox's default table editor
6909          if (env.isFF) {
6910              document.execCommand('enableInlineTableEditing', false, false);
6911          }
6912      };
6913      TablePopover.prototype.destroy = function () {
6914          this.$popover.remove();
6915      };
6916      TablePopover.prototype.update = function (target) {
6917          if (this.context.isDisabled()) {
6918              return false;
6919          }
6920          var isCell = dom.isCell(target);
6921          if (isCell) {
6922              var pos = dom.posFromPlaceholder(target);
6923              this.$popover.css({
6924                  display: 'block',
6925                  left: pos.left,
6926                  top: pos.top
6927              });
6928          }
6929          else {
6930              this.hide();
6931          }
6932          return isCell;
6933      };
6934      TablePopover.prototype.hide = function () {
6935          this.$popover.hide();
6936      };
6937      return TablePopover;
6938  }());
6939
6940  var VideoDialog = /** @class */ (function () {
6941      function VideoDialog(context) {
6942          this.context = context;
6943          this.ui = $$1.summernote.ui;
6944          this.$body = $$1(document.body);
6945          this.$editor = context.layoutInfo.editor;
6946          this.options = context.options;
6947          this.lang = this.options.langInfo;
6948      }
6949      VideoDialog.prototype.initialize = function () {
6950          var $container = this.options.dialogsInBody ? this.$body : this.$editor;
6951          var body = [
6952              '<div class="form-group note-form-group row-fluid">',
6953              "<label class=\"note-form-label\">" + this.lang.video.url + " <small class=\"text-muted\">" + this.lang.video.providers + "</small></label>",
6954              '<input class="note-video-url form-control note-form-control note-input" type="text" />',
6955              '</div>',
6956          ].join('');
6957          var buttonClass = 'btn btn-primary note-btn note-btn-primary note-video-btn';
6958          var footer = "<input type=\"button\" href=\"#\" class=\"" + buttonClass + "\" value=\"" + this.lang.video.insert + "\" disabled>";
6959          this.$dialog = this.ui.dialog({
6960              title: this.lang.video.insert,
6961              fade: this.options.dialogsFade,
6962              body: body,
6963              footer: footer
6964          }).render().appendTo($container);
6965      };
6966      VideoDialog.prototype.destroy = function () {
6967          this.ui.hideDialog(this.$dialog);
6968          this.$dialog.remove();
6969      };
6970      VideoDialog.prototype.bindEnterKey = function ($input, $btn) {
6971          $input.on('keypress', function (event) {
6972              if (event.keyCode === key.code.ENTER) {
6973                  event.preventDefault();
6974                  $btn.trigger('click');
6975              }
6976          });
6977      };
6978      VideoDialog.prototype.createVideoNode = function (url) {
6979          // video url patterns(youtube, instagram, vimeo, dailymotion, youku, mp4, ogg, webm)
6980          var ytRegExp = /\/\/(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([\w|-]{11})(?:(?:[\?&]t=)(\S+))?$/;
6981          var ytRegExpForStart = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
6982          var ytMatch = url.match(ytRegExp);
6983          var igRegExp = /(?:www\.|\/\/)instagram\.com\/p\/(.[a-zA-Z0-9_-]*)/;
6984          var igMatch = url.match(igRegExp);
6985          var vRegExp = /\/\/vine\.co\/v\/([a-zA-Z0-9]+)/;
6986          var vMatch = url.match(vRegExp);
6987          var vimRegExp = /\/\/(player\.)?vimeo\.com\/([a-z]*\/)*(\d+)[?]?.*/;
6988          var vimMatch = url.match(vimRegExp);
6989          var dmRegExp = /.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/;
6990          var dmMatch = url.match(dmRegExp);
6991          var youkuRegExp = /\/\/v\.youku\.com\/v_show\/id_(\w+)=*\.html/;
6992          var youkuMatch = url.match(youkuRegExp);
6993          var qqRegExp = /\/\/v\.qq\.com.*?vid=(.+)/;
6994          var qqMatch = url.match(qqRegExp);
6995          var qqRegExp2 = /\/\/v\.qq\.com\/x?\/?(page|cover).*?\/([^\/]+)\.html\??.*/;
6996          var qqMatch2 = url.match(qqRegExp2);
6997          var mp4RegExp = /^.+.(mp4|m4v)$/;
6998          var mp4Match = url.match(mp4RegExp);
6999          var oggRegExp = /^.+.(ogg|ogv)$/;
7000          var oggMatch = url.match(oggRegExp);
7001          var webmRegExp = /^.+.(webm)$/;
7002          var webmMatch = url.match(webmRegExp);
7003          var fbRegExp = /(?:www\.|\/\/)facebook\.com\/([^\/]+)\/videos\/([0-9]+)/;
7004          var fbMatch = url.match(fbRegExp);
7005          var $video;
7006          if (ytMatch && ytMatch[1].length === 11) {
7007              var youtubeId = ytMatch[1];
7008              var start = 0;
7009              if (typeof ytMatch[2] !== 'undefined') {
7010                  var ytMatchForStart = ytMatch[2].match(ytRegExpForStart);
7011                  if (ytMatchForStart) {
7012                      for (var n = [3600, 60, 1], i = 0, r = n.length; i < r; i++) {
7013                          start += (typeof ytMatchForStart[i + 1] !== 'undefined' ? n[i] * parseInt(ytMatchForStart[i + 1], 10) : 0);
7014                      }
7015                  }
7016              }
7017              $video = $$1('<iframe>')
7018                  .attr('frameborder', 0)
7019                  .attr('src', '//www.youtube.com/embed/' + youtubeId + (start > 0 ? '?start=' + start : ''))
7020                  .attr('width', '640').attr('height', '360');
7021          }
7022          else if (igMatch && igMatch[0].length) {
7023              $video = $$1('<iframe>')
7024                  .attr('frameborder', 0)
7025                  .attr('src', 'https://instagram.com/p/' + igMatch[1] + '/embed/')
7026                  .attr('width', '612').attr('height', '710')
7027                  .attr('scrolling', 'no')
7028                  .attr('allowtransparency', 'true');
7029          }
7030          else if (vMatch && vMatch[0].length) {
7031              $video = $$1('<iframe>')
7032                  .attr('frameborder', 0)
7033                  .attr('src', vMatch[0] + '/embed/simple')
7034                  .attr('width', '600').attr('height', '600')
7035                  .attr('class', 'vine-embed');
7036          }
7037          else if (vimMatch && vimMatch[3].length) {
7038              $video = $$1('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>')
7039                  .attr('frameborder', 0)
7040                  .attr('src', '//player.vimeo.com/video/' + vimMatch[3])
7041                  .attr('width', '640').attr('height', '360');
7042          }
7043          else if (dmMatch && dmMatch[2].length) {
7044              $video = $$1('<iframe>')
7045                  .attr('frameborder', 0)
7046                  .attr('src', '//www.dailymotion.com/embed/video/' + dmMatch[2])
7047                  .attr('width', '640').attr('height', '360');
7048          }
7049          else if (youkuMatch && youkuMatch[1].length) {
7050              $video = $$1('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>')
7051                  .attr('frameborder', 0)
7052                  .attr('height', '498')
7053                  .attr('width', '510')
7054                  .attr('src', '//player.youku.com/embed/' + youkuMatch[1]);
7055          }
7056          else if ((qqMatch && qqMatch[1].length) || (qqMatch2 && qqMatch2[2].length)) {
7057              var vid = ((qqMatch && qqMatch[1].length) ? qqMatch[1] : qqMatch2[2]);
7058              $video = $$1('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>')
7059                  .attr('frameborder', 0)
7060                  .attr('height', '310')
7061                  .attr('width', '500')
7062                  .attr('src', 'http://v.qq.com/iframe/player.html?vid=' + vid + '&amp;auto=0');
7063          }
7064          else if (mp4Match || oggMatch || webmMatch) {
7065              $video = $$1('<video controls>')
7066                  .attr('src', url)
7067                  .attr('width', '640').attr('height', '360');
7068          }
7069          else if (fbMatch && fbMatch[0].length) {
7070              $video = $$1('<iframe>')
7071                  .attr('frameborder', 0)
7072                  .attr('src', 'https://www.facebook.com/plugins/video.php?href=' + encodeURIComponent(fbMatch[0]) + '&show_text=0&width=560')
7073                  .attr('width', '560').attr('height', '301')
7074                  .attr('scrolling', 'no')
7075                  .attr('allowtransparency', 'true');
7076          }
7077          else {
7078              // this is not a known video link. Now what, Cat? Now what?
7079              return false;
7080          }
7081          $video.addClass('note-video-clip');
7082          return $video[0];
7083      };
7084      VideoDialog.prototype.show = function () {
7085          var _this = this;
7086          var text = this.context.invoke('editor.getSelectedText');
7087          this.context.invoke('editor.saveRange');
7088          this.showVideoDialog(text).then(function (url) {
7089              // [workaround] hide dialog before restore range for IE range focus
7090              _this.ui.hideDialog(_this.$dialog);
7091              _this.context.invoke('editor.restoreRange');
7092              // build node
7093              var $node = _this.createVideoNode(url);
7094              if ($node) {
7095                  // insert video node
7096                  _this.context.invoke('editor.insertNode', $node);
7097              }
7098          }).fail(function () {
7099              _this.context.invoke('editor.restoreRange');
7100          });
7101      };
7102      /**
7103       * show image dialog
7104       *
7105       * @param {jQuery} $dialog
7106       * @return {Promise}
7107       */
7108      VideoDialog.prototype.showVideoDialog = function (text) {
7109          var _this = this;
7110          return $$1.Deferred(function (deferred) {
7111              var $videoUrl = _this.$dialog.find('.note-video-url');
7112              var $videoBtn = _this.$dialog.find('.note-video-btn');
7113              _this.ui.onDialogShown(_this.$dialog, function () {
7114                  _this.context.triggerEvent('dialog.shown');
7115                  $videoUrl.on('input paste propertychange', function () {
7116                      _this.ui.toggleBtn($videoBtn, $videoUrl.val());
7117                  });
7118                  if (!env.isSupportTouch) {
7119                      $videoUrl.trigger('focus');
7120                  }
7121                  $videoBtn.click(function (event) {
7122                      event.preventDefault();
7123                      deferred.resolve($videoUrl.val());
7124                  });
7125                  _this.bindEnterKey($videoUrl, $videoBtn);
7126              });
7127              _this.ui.onDialogHidden(_this.$dialog, function () {
7128                  $videoUrl.off();
7129                  $videoBtn.off();
7130                  if (deferred.state() === 'pending') {
7131                      deferred.reject();
7132                  }
7133              });
7134              _this.ui.showDialog(_this.$dialog);
7135          });
7136      };
7137      return VideoDialog;
7138  }());
7139
7140  var HelpDialog = /** @class */ (function () {
7141      function HelpDialog(context) {
7142          this.context = context;
7143          this.ui = $$1.summernote.ui;
7144          this.$body = $$1(document.body);
7145          this.$editor = context.layoutInfo.editor;
7146          this.options = context.options;
7147          this.lang = this.options.langInfo;
7148      }
7149      HelpDialog.prototype.initialize = function () {
7150          var $container = this.options.dialogsInBody ? this.$body : this.$editor;
7151          var body = [
7152              '<p class="text-center">',
7153              '<a href="http://summernote.org/" target="_blank">Summernote 0.8.12</a> · ',
7154              '<a href="https://github.com/summernote/summernote" target="_blank">Project</a> · ',
7155              '<a href="https://github.com/summernote/summernote/issues" target="_blank">Issues</a>',
7156              '</p>',
7157          ].join('');
7158          this.$dialog = this.ui.dialog({
7159              title: this.lang.options.help,
7160              fade: this.options.dialogsFade,
7161              body: this.createShortcutList(),
7162              footer: body,
7163              callback: function ($node) {
7164                  $node.find('.modal-body,.note-modal-body').css({
7165                      'max-height': 300,
7166                      'overflow': 'scroll'
7167                  });
7168              }
7169          }).render().appendTo($container);
7170      };
7171      HelpDialog.prototype.destroy = function () {
7172          this.ui.hideDialog(this.$dialog);
7173          this.$dialog.remove();
7174      };
7175      HelpDialog.prototype.createShortcutList = function () {
7176          var _this = this;
7177          var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];
7178          return Object.keys(keyMap).map(function (key) {
7179              var command = keyMap[key];
7180              var $row = $$1('<div><div class="help-list-item"/></div>');
7181              $row.append($$1('<label><kbd>' + key + '</kdb></label>').css({
7182                  'width': 180,
7183                  'margin-right': 10
7184              })).append($$1('<span/>').html(_this.context.memo('help.' + command) || command));
7185              return $row.html();
7186          }).join('');
7187      };
7188      /**
7189       * show help dialog
7190       *
7191       * @return {Promise}
7192       */
7193      HelpDialog.prototype.showHelpDialog = function () {
7194          var _this = this;
7195          return $$1.Deferred(function (deferred) {
7196              _this.ui.onDialogShown(_this.$dialog, function () {
7197                  _this.context.triggerEvent('dialog.shown');
7198                  deferred.resolve();
7199              });
7200              _this.ui.showDialog(_this.$dialog);
7201          }).promise();
7202      };
7203      HelpDialog.prototype.show = function () {
7204          var _this = this;
7205          this.context.invoke('editor.saveRange');
7206          this.showHelpDialog().then(function () {
7207              _this.context.invoke('editor.restoreRange');
7208          });
7209      };
7210      return HelpDialog;
7211  }());
7212
7213  var AIR_MODE_POPOVER_X_OFFSET = 20;
7214  var AirPopover = /** @class */ (function () {
7215      function AirPopover(context) {
7216          var _this = this;
7217          this.context = context;
7218          this.ui = $$1.summernote.ui;
7219          this.options = context.options;
7220          this.events = {
7221              'summernote.keyup summernote.mouseup summernote.scroll': function () {
7222                  _this.update();
7223              },
7224              'summernote.disable summernote.change summernote.dialog.shown': function () {
7225                  _this.hide();
7226              },
7227              'summernote.focusout': function (we, e) {
7228                  // [workaround] Firefox doesn't support relatedTarget on focusout
7229                  //  - Ignore hide action on focus out in FF.
7230                  if (env.isFF) {
7231                      return;
7232                  }
7233                  if (!e.relatedTarget || !dom.ancestor(e.relatedTarget, func.eq(_this.$popover[0]))) {
7234                      _this.hide();
7235                  }
7236              }
7237          };
7238      }
7239      AirPopover.prototype.shouldInitialize = function () {
7240          return this.options.airMode && !lists.isEmpty(this.options.popover.air);
7241      };
7242      AirPopover.prototype.initialize = function () {
7243          this.$popover = this.ui.popover({
7244              className: 'note-air-popover'
7245          }).render().appendTo(this.options.container);
7246          var $content = this.$popover.find('.popover-content');
7247          this.context.invoke('buttons.build', $content, this.options.popover.air);
7248      };
7249      AirPopover.prototype.destroy = function () {
7250          this.$popover.remove();
7251      };
7252      AirPopover.prototype.update = function () {
7253          var styleInfo = this.context.invoke('editor.currentStyle');
7254          if (styleInfo.range && !styleInfo.range.isCollapsed()) {
7255              var rect = lists.last(styleInfo.range.getClientRects());
7256              if (rect) {
7257                  var bnd = func.rect2bnd(rect);
7258                  this.$popover.css({
7259                      display: 'block',
7260                      left: Math.max(bnd.left + bnd.width / 2, 0) - AIR_MODE_POPOVER_X_OFFSET,
7261                      top: bnd.top + bnd.height
7262                  });
7263                  this.context.invoke('buttons.updateCurrentStyle', this.$popover);
7264              }
7265          }
7266          else {
7267              this.hide();
7268          }
7269      };
7270      AirPopover.prototype.hide = function () {
7271          this.$popover.hide();
7272      };
7273      return AirPopover;
7274  }());
7275
7276  var POPOVER_DIST = 5;
7277  var HintPopover = /** @class */ (function () {
7278      function HintPopover(context) {
7279          var _this = this;
7280          this.context = context;
7281          this.ui = $$1.summernote.ui;
7282          this.$editable = context.layoutInfo.editable;
7283          this.options = context.options;
7284          this.hint = this.options.hint || [];
7285          this.direction = this.options.hintDirection || 'bottom';
7286          this.hints = Array.isArray(this.hint) ? this.hint : [this.hint];
7287          this.events = {
7288              'summernote.keyup': function (we, e) {
7289                  if (!e.isDefaultPrevented()) {
7290                      _this.handleKeyup(e);
7291                  }
7292              },
7293              'summernote.keydown': function (we, e) {
7294                  _this.handleKeydown(e);
7295              },
7296              'summernote.disable summernote.dialog.shown': function () {
7297                  _this.hide();
7298              }
7299          };
7300      }
7301      HintPopover.prototype.shouldInitialize = function () {
7302          return this.hints.length > 0;
7303      };
7304      HintPopover.prototype.initialize = function () {
7305          var _this = this;
7306          this.lastWordRange = null;
7307          this.$popover = this.ui.popover({
7308              className: 'note-hint-popover',
7309              hideArrow: true,
7310              direction: ''
7311          }).render().appendTo(this.options.container);
7312          this.$popover.hide();
7313          this.$content = this.$popover.find('.popover-content,.note-popover-content');
7314          this.$content.on('click', '.note-hint-item', function (e) {
7315              _this.$content.find('.active').removeClass('active');
7316              $$1(e.currentTarget).addClass('active');
7317              _this.replace();
7318          });
7319      };
7320      HintPopover.prototype.destroy = function () {
7321          this.$popover.remove();
7322      };
7323      HintPopover.prototype.selectItem = function ($item) {
7324          this.$content.find('.active').removeClass('active');
7325          $item.addClass('active');
7326          this.$content[0].scrollTop = $item[0].offsetTop - (this.$content.innerHe
7326ight() / 2);
7327      };
7328      HintPopover.prototype.moveDown = function () {
7329          var $current = this.$content.find('.note-hint-item.active');
7330          var $next = $current.next();
7331          if ($next.length) {
7332              this.selectItem($next);
7333          }
7334          else {
7335              var $nextGroup = $current.parent().next();
7336              if (!$nextGroup.length) {
7337                  $nextGroup = this.$content.find('.note-hint-group').first();
7338              }
7339              this.selectItem($nextGroup.find('.note-hint-item').first());
7340          }
7341      };
7342      HintPopover.prototype.moveUp = function () {
7343          var $current = this.$content.find('.note-hint-item.active');
7344          var $prev = $current.prev();
7345          if ($prev.length) {
7346              this.selectItem($prev);
7347          }
7348          else {
7349              var $prevGroup = $current.parent().prev();
7350              if (!$prevGroup.length) {
7351                  $prevGroup = this.$content.find('.note-hint-group').last();
7352              }
7353              this.selectItem($prevGroup.find('.note-hint-item').last());
7354          }
7355      };
7356      HintPopover.prototype.replace = function () {
7357          var $item = this.$content.find('.note-hint-item.active');
7358          if ($item.length) {
7359              var node = this.nodeFromItem($item);
7360              // XXX: consider to move codes to editor for recording redo/undo.
7361              this.lastWordRange.insertNode(node);
7362              range.createFromNode(node).collapse().select();
7363              this.lastWordRange = null;
7364              this.hide();
7365              this.context.triggerEvent('change', this.$editable.html(), this.$editable[0]);
7366              this.context.invoke('editor.focus');
7367          }
7368      };
7369      HintPopover.prototype.nodeFromItem = function ($item) {
7370          var hint = this.hints[$item.data('index')];
7371          var item = $item.data('item');
7372          var node = hint.content ? hint.content(item) : item;
7373          if (typeof node === 'string') {
7374              node = dom.createText(node);
7375          }
7376          return node;
7377      };
7378      HintPopover.prototype.createItemTemplates = function (hintIdx, items) {
7379          var hint = this.hints[hintIdx];
7380          return items.map(function (item, idx) {
7381              var $item = $$1('<div class="note-hint-item"/>');
7382              $item.append(hint.template ? hint.template(item) : item + '');
7383              $item.data({
7384                  'index': hintIdx,
7385                  'item': item
7386              });
7387              return $item;
7388          });
7389      };
7390      HintPopover.prototype.handleKeydown = function (e) {
7391          if (!this.$popover.is(':visible')) {
7392              return;
7393          }
7394          if (e.keyCode === key.code.ENTER) {
7395              e.preventDefault();
7396              this.replace();
7397          }
7398          else if (e.keyCode === key.code.UP) {
7399              e.preventDefault();
7400              this.moveUp();
7401          }
7402          else if (e.keyCode === key.code.DOWN) {
7403              e.preventDefault();
7404              this.moveDown();
7405          }
7406      };
7407      HintPopover.prototype.searchKeyword = function (index, keyword, callback) {
7408          var hint = this.hints[index];
7409          if (hint && hint.match.test(keyword) && hint.search) {
7410              var matches = hint.match.exec(keyword);
7411              hint.search(matches[1], callback);
7412          }
7413          else {
7414              callback();
7415          }
7416      };
7417      HintPopover.prototype.createGroup = function (idx, keyword) {
7418          var _this = this;
7419          var $group = $$1('<div class="note-hint-group note-hint-group-' + idx + '"/>');
7420          this.searchKeyword(idx, keyword, function (items) {
7421              items = items || [];
7422              if (items.length) {
7423                  $group.html(_this.createItemTemplates(idx, items));
7424                  _this.show();
7425              }
7426          });
7427          return $group;
7428      };
7429      HintPopover.prototype.handleKeyup = function (e) {
7430          var _this = this;
7431          if (!lists.contains([key.code.ENTER, key.code.UP, key.code.DOWN], e.keyCode)) {
7432              var wordRange = this.context.invoke('editor.getLastRange').getWordRange();
7433              var keyword_1 = wordRange.toString();
7434              if (this.hints.length && keyword_1) {
7435                  this.$content.empty();
7436                  var bnd = func.rect2bnd(lists.last(wordRange.getClientRects()));
7437                  if (bnd) {
7438                      this.$popover.hide();
7439                      this.lastWordRange = wordRange;
7440                      this.hints.forEach(function (hint, idx) {
7441                          if (hint.match.test(keyword_1)) {
7442                              _this.createGroup(idx, keyword_1).appendTo(_this.$content);
7443                          }
7444                      });
7445                      // select first .note-hint-item
7446                      this.$content.find('.note-hint-item:first').addClass('active');
7447                      // set position for popover after group is created
7448                      if (this.direction === 'top') {
7449                          this.$popover.css({
7450                              left: bnd.left,
7451                              top: bnd.top - this.$popover.outerHeight() - POPOVER_DIST
7452                          });
7453                      }
7454                      else {
7455                          this.$popover.css({
7456                              left: bnd.left,
7457                              top: bnd.top + bnd.height + POPOVER_DIST
7458                          });
7459                      }
7460                  }
7461              }
7462              else {
7463                  this.hide();
7464              }
7465          }
7466      };
7467      HintPopover.prototype.show = function () {
7468          this.$popover.show();
7469      };
7470      HintPopover.prototype.hide = function () {
7471          this.$popover.hide();
7472      };
7473      return HintPopover;
7474  }());
7475
7476  $$1.summernote = $$1.extend($$1.summernote, {
7477      version: '0.8.12',
7478      plugins: {},
7479      dom: dom,
7480      range: range,
7481      options: {
7482          langInfo: $$1.summernote.lang['en-US'],
7483          modules: {
7484              'editor': Editor,
7485              'clipboard': Clipboard,
7486              'dropzone': Dropzone,
7487              'codeview': CodeView,
7488              'statusbar': Statusbar,
7489              'fullscreen': Fullscreen,
7490              'handle': Handle,
7491              // FIXME: HintPopover must be front of autolink
7492              //  - Script error about range when Enter key is pressed on hint popover
7493              'hintPopover': HintPopover,
7494              'autoLink': AutoLink,
7495              'autoSync': AutoSync,
7496              'autoReplace': AutoReplace,
7497              'placeholder': Placeholder,
7498              'buttons': Buttons,
7499              'toolbar': Toolbar,
7500              'linkDialog': LinkDialog,
7501              'linkPopover': LinkPopover,
7502              'imageDialog': ImageDialog,
7503              'imagePopover': ImagePopover,
7504              'tablePopover': TablePopover,
7505              'videoDialog': VideoDialog,
7506              'helpDialog': HelpDialog,
7507              'airPopover': AirPopover
7508          },
7509          buttons: {},
7510          lang: 'en-US',
7511          followingToolbar: false,
7512          otherStaticBar: '',
7513          // toolbar
7514          toolbar: [
7515              ['style', ['style']],
7516              ['font', ['bold', 'underline', 'clear']],
7517              ['fontname', ['fontname']],
7518              ['color', ['color']],
7519              ['para', ['ul', 'ol', 'paragraph']],
7520              ['table', ['table']],
7521              ['insert', ['link', 'picture', 'video']],
7522              ['view', ['fullscreen', 'codeview', 'help']],
7523          ],
7524          // popover
7525          popatmouse: true,
7526          popover: {
7527              image: [
7528                  ['resize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']],
7529                  ['float', ['floatLeft', 'floatRight', 'floatNone']],
7530                  ['remove', ['removeMedia']],
7531              ],
7532              link: [
7533                  ['link', ['linkDialogShow', 'unlink']],
7534              ],
7535              table: [
7536                  ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
7537                  ['delete', ['deleteRow', 'deleteCol', 'deleteTable']],
7538              ],
7539              air: [
7540                  ['color', ['color']],
7541                  ['font', ['bold', 'underline', 'clear']],
7542                  ['para', ['ul', 'paragraph']],
7543                  ['table', ['table']],
7544                  ['insert', ['link', 'picture']],
7545              ]
7546          },
7547          // air mode: inline editor
7548          airMode: false,
7549          width: null,
7550          height: null,
7551          linkTargetBlank: true,
7552          focus: false,
7553          tabSize: 4,
7554          styleWithSpan: true,
7555          shortcuts: true,
7556          textareaAutoSync: true,
7557          hintDirection: 'bottom',
7558          tooltip: 'auto',
7559          container: 'body',
7560          maxTextLength: 0,
7561          blockquoteBreakingLevel: 2,
7562          spellCheck: true,
7563          styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
7564          fontNames: [
7565              'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
7566              'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',
7567              'Tahoma', 'Times New Roman', 'Verdana',
7568          ],
7569          fontNamesIgnoreCheck: [],
7570          fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],
7571          // pallete colors(n x n)
7572          colors: [
7573              ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],
7574              ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
7575              ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
7576              ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
7577              ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
7578              ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
7579              ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
7580              ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031'],
7581          ],
7582          // http://chir.ag/projects/name-that-color/
7583          colorsName: [
7584              ['Black', 'Tundora', 'Dove Gray', 'Star Dust', 'Pale Slate', 'Gallery', 'Alabaster', 'White'],
7585              ['Red', 'Orange Peel', 'Yellow', 'Green', 'Cyan', 'Blue', 'Electric Violet', 'Magenta'],
7586              ['Azalea', 'Karry', 'Egg White', 'Zanah', 'Botticelli', 'Tropical Blue', 'Mischka', 'Twilight'],
7587              ['Tonys Pink', 'Peach Orange', 'Cream Brulee', 'Sprout', 'Casper', 'Perano', 'Cold Purple', 'Careys Pink'],
7588              ['Mandy', 'Rajah', 'Dandelion', 'Olivine', 'Gulf Stream', 'Viking', 'Blue Marguerite', 'Puce'],
7589              ['Guardsman Red', 'Fire Bush', 'Golden Dream', 'Chelsea Cucumber', 'Smalt Blue', 'Boston Blue', 'Butterfly Bush', 'Cadillac'],
7590              ['Sangria', 'Mai Tai', 'Buddha Gold', 'Forest Green', 'Eden', 'Venice Blue', 'Meteorite', 'Claret'],
7591              ['Rosewood', 'Cinnamon', 'Olive', 'Parsley', 'Tiber', 'Midnight Blue', 'Valentino', 'Loulou'],
7592          ],
7593          colorButton: {
7594              foreColor: '#000000',
7595              backColor: '#FFFF00'
7596          },
7597          lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],
7598          tableClassName: 'table table-bordered',
7599          insertTableMaxSize: {
7600              col: 10,
7601              row: 10
7602          },
7603          dialogsInBody: false,
7604          dialogsFade: false,
7605          maximumImageFileSize: null,
7606          callbacks: {
7607              onBeforeCommand: null,
7608              onBlur: null,
7609              onBlurCodeview: null,
7610              onChange: null,
7611              onChangeCodeview: null,
7612              onDialogShown: null,
7613              onEnter: null,
7614              onFocus: null,
7615              onImageLinkInsert: null,
7616              onImageUpload: null,
7617              onImageUploadError: null,
7618              onInit: null,
7619              onKeydown: null,
7620              onKeyup: null,
7621              onMousedown: null,
7622              onMouseup: null,
7623              onPaste: null,
7624              onScroll: null
7625          },
7626          codemirror: {
7627              mode: 'text/html',
7628              htmlMode: true,
7629              lineNumbers: true
7630          },
7631          codeviewFilter: false,
7632          codeviewFilterRegex: /<\/*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]*?>/gi,
7633          codeviewIframeFilter: true,
7634          codeviewIframeWhitelistSrc: [],
7635          codeviewIframeWhitelistSrcBase: [
7636              'www.youtube.com',
7637              'www.youtube-nocookie.com',
7638              'www.facebook.com',
7639              'vine.co',
7640              'instagram.com',
7641              'player.vimeo.com',
7642              'www.dailymotion.com',
7643              'player.youku.com',
7644              'v.qq.com',
7645          ],
7646          keyMap: {
7647              pc: {
7648                  'ENTER': 'insertParagraph',
7649                  'CTRL+Z': 'undo',
7650                  'CTRL+Y': 'redo',
7651                  'TAB': 'tab',
7652                  'SHIFT+TAB': 'untab',
7653                  'CTRL+B': 'bold',
7654                  'CTRL+I': 'italic',
7655                  'CTRL+U': 'underline',
7656                  'CTRL+SHIFT+S': 'strikethrough',
7657                  'CTRL+BACKSLASH': 'removeFormat',
7658                  'CTRL+SHIFT+L': 'justifyLeft',
7659                  'CTRL+SHIFT+E': 'justifyCenter',
7660                  'CTRL+SHIFT+R': 'justifyRight',
7661                  'CTRL+SHIFT+J': 'justifyFull',
7662                  'CTRL+SHIFT+NUM7': 'insertUnorderedList',
7663                  'CTRL+SHIFT+NUM8': 'insertOrderedList',
7664                  'CTRL+LEFTBRACKET': 'outdent',
7665                  'CTRL+RIGHTBRACKET': 'indent',
7666                  'CTRL+NUM0': 'formatPara',
7667                  'CTRL+NUM1': 'formatH1',
7668                  'CTRL+NUM2': 'formatH2',
7669                  'CTRL+NUM3': 'formatH3',
7670                  'CTRL+NUM4': 'formatH4',
7671                  'CTRL+NUM5': 'formatH5',
7672                  'CTRL+NUM6': 'formatH6',
7673                  'CTRL+ENTER': 'insertHorizontalRule',
7674                  'CTRL+K': 'linkDialog.show'
7675              },
7676              mac: {
7677                  'ENTER': 'insertParagraph',
7678                  'CMD+Z': 'undo',
7679                  'CMD+SHIFT+Z': 'redo',
7680                  'TAB': 'tab',
7681                  'SHIFT+TAB': 'untab',
7682                  'CMD+B': 'bold',
7683                  'CMD+I': 'italic',
7684                  'CMD+U': 'underline',
7685                  'CMD+SHIFT+S': 'strikethrough',
7686                  'CMD+BACKSLASH': 'removeFormat',
7687                  'CMD+SHIFT+L': 'justifyLeft',
7688                  'CMD+SHIFT+E': 'justifyCenter',
7689                  'CMD+SHIFT+R': 'justifyRight',
7690                  'CMD+SHIFT+J': 'justifyFull',
7691                  'CMD+SHIFT+NUM7': 'insertUnorderedList',
7692                  'CMD+SHIFT+NUM8': 'insertOrderedList',
7693                  'CMD+LEFTBRACKET': 'outdent',
7694                  'CMD+RIGHTBRACKET': 'indent',
7695                  'CMD+NUM0': 'formatPara',
7696                  'CMD+NUM1': 'formatH1',
7697                  'CMD+NUM2': 'formatH2',
7698                  'CMD+NUM3': 'formatH3',
7699                  'CMD+NUM4': 'formatH4',
7700                  'CMD+NUM5': 'formatH5',
7701                  'CMD+NUM6': 'formatH6',
7702                  'CMD+ENTER': 'insertHorizontalRule',
7703                  'CMD+K': 'linkDialog.show'
7704              }
7705          },
7706          icons: {
7707              'align': 'note-icon-align',
7708              'alignCenter': 'note-icon-align-center',
7709              'alignJustify': 'note-icon-align-justify',
7710              'alignLeft': 'note-icon-align-left',
7711              'alignRight': 'note-icon-align-right',
7712              'rowBelow': 'note-icon-row-below',
7713              'colBefore': 'note-icon-col-before',
7714              'colAfter': 'note-icon-col-after',
7715              'rowAbove': 'note-icon-row-above',
7716              'rowRemove': 'note-icon-row-remove',
7717              'colRemove': 'note-icon-col-remove',
7718              'indent': 'note-icon-align-indent',
7719              'outdent': 'note-icon-align-outdent',
7720              'arrowsAlt': 'note-icon-arrows-alt',
7721              'bold': 'note-icon-bold',
7722              'caret': 'note-icon-caret',
7723              'circle': 'note-icon-circle',
7724              'close': 'note-icon-close',
7725              'code': 'note-icon-code',
7726              'eraser': 'note-icon-eraser',
7727              'floatLeft': 'note-icon-float-left',
7728              'floatRight': 'note-icon-float-right',
7729              'font': 'note-icon-font',
7730              'frame': 'note-icon-frame',
7731              'italic': 'note-icon-italic',
7732              'link': 'note-icon-link',
7733              'unlink': 'note-icon-chain-broken',
7734              'magic': 'note-icon-magic',
7735              'menuCheck': 'note-icon-menu-check',
7736              'minus': 'note-icon-minus',
7737              'orderedlist': 'note-icon-orderedlist',
7738              'pencil': 'note-icon-pencil',
7739              'picture': 'note-icon-picture',
7740              'question': 'note-icon-question',
7741              'redo': 'note-icon-redo',
7742              'rollback': 'note-icon-rollback',
7743              'square': 'note-icon-square',
7744              'strikethrough': 'note-icon-strikethrough',
7745              'subscript': 'note-icon-subscript',
7746              'superscript': 'note-icon-superscript',
7747              'table': 'note-icon-table',
7748              'textHeight': 'note-icon-text-height',
7749              'trash': 'note-icon-trash',
7750              'underline': 'note-icon-underline',
7751              'undo': 'note-icon-undo',
7752              'unorderedlist': 'note-icon-unorderedlist',
7753              'video': 'note-icon-video'
7754          }
7755      }
7756  });
7757
7758  $$1.summernote = $$1.extend($$1.summernote, {
7759      ui: ui
7760  });
7761  $$1.summernote.options.styleTags = [
7762      'p',
7763      { title: 'Blockquote', tag: 'blockquote', className: 'blockquote', value: 'blockquote' },
7764      'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
7765  ];
7766
7767}));
7768//# sourceMappingURL=summernote-bs4.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.