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