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