UNPKG

jsdk-offical

Version:

JSDK is the most comprehensive TypeScript framework, like JDK.

1,395 lines (1,385 loc) 323 kB
/** * Super simple wysiwyg editor v0.8.12 * https://summernote.org * * Copyright 2013- Alan Hong. and other contributors * summernote may be freely distributed under the MIT license. * * Date: 2019-05-16T08:16Z */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : typeof define === 'function' && define.amd ? define(['jquery'], factory) : (global = global || self, factory(global.jQuery)); }(this, function ($$1) { 'use strict'; $$1 = $$1 && $$1.hasOwnProperty('default') ? $$1['default'] : $$1; var Renderer = /** @class */ (function () { function Renderer(markup, children, options, callback) { this.markup = markup; this.children = children; this.options = options; this.callback = callback; } Renderer.prototype.render = function ($parent) { var $node = $$1(this.markup); if (this.options && this.options.contents) { $node.html(this.options.contents); } if (this.options && this.options.className) { $node.addClass(this.options.className); } if (this.options && this.options.data) { $$1.each(this.options.data, function (k, v) { $node.attr('data-' + k, v); }); } if (this.options && this.options.click) { $node.on('click', this.options.click); } if (this.children) { var $container_1 = $node.find('.note-children-container'); this.children.forEach(function (child) { child.render($container_1.length ? $container_1 : $node); }); } if (this.callback) { this.callback($node, this.options); } if (this.options && this.options.callback) { this.options.callback($node); } if ($parent) { $parent.append($node); } return $node; }; return Renderer; }()); var renderer = { create: function (markup, callback) { return function () { var options = typeof arguments[1] === 'object' ? arguments[1] : arguments[0]; var children = Array.isArray(arguments[0]) ? arguments[0] : []; if (options && options.children) { children = options.children; } return new Renderer(markup, children, options, callback); }; } }; var TooltipUI = /** @class */ (function () { function TooltipUI($node, options) { this.$node = $node; this.options = $.extend({}, { title: '', target: options.container, trigger: 'hover focus', placement: 'bottom' }, options); // create tooltip node this.$tooltip = $([ '<div class="note-tooltip in">', ' <div class="note-tooltip-arrow"/>', ' <div class="note-tooltip-content"/>', '</div>', ].join('')); // define event if (this.options.trigger !== 'manual') { var showCallback_1 = this.show.bind(this); var hideCallback_1 = this.hide.bind(this); var toggleCallback_1 = this.toggle.bind(this); this.options.trigger.split(' ').forEach(function (eventName) { if (eventName === 'hover') { $node.off('mouseenter mouseleave'); $node.on('mouseenter', showCallback_1).on('mouseleave', hideCallback_1); } else if (eventName === 'click') { $node.on('click', toggleCallback_1); } else if (eventName === 'focus') { $node.on('focus', showCallback_1).on('blur', hideCallback_1); } }); } } TooltipUI.prototype.show = function () { var $node = this.$node; var offset = $node.offset(); var $tooltip = this.$tooltip; var title = this.options.title || $node.attr('title') || $node.data('title'); var placement = this.options.placement || $node.data('placement'); $tooltip.addClass(placement); $tooltip.addClass('in'); $tooltip.find('.note-tooltip-content').text(title); $tooltip.appendTo(this.options.target); var nodeWidth = $node.outerWidth(); var nodeHeight = $node.outerHeight(); var tooltipWidth = $tooltip.outerWidth(); var tooltipHeight = $tooltip.outerHeight(); if (placement === 'bottom') { $tooltip.css({ top: offset.top + nodeHeight, left: offset.left + (nodeWidth / 2 - tooltipWidth / 2) }); } else if (placement === 'top') { $tooltip.css({ top: offset.top - tooltipHeight, left: offset.left + (nodeWidth / 2 - tooltipWidth / 2) }); } else if (placement === 'left') { $tooltip.css({ top: offset.top + (nodeHeight / 2 - tooltipHeight / 2), left: offset.left - tooltipWidth }); } else if (placement === 'right') { $tooltip.css({ top: offset.top + (nodeHeight / 2 - tooltipHeight / 2), left: offset.left + nodeWidth }); } }; TooltipUI.prototype.hide = function () { this.$tooltip.removeClass('in'); this.$tooltip.remove(); }; TooltipUI.prototype.toggle = function () { if (this.$tooltip.hasClass('in')) { this.hide(); } else { this.show(); } }; return TooltipUI; }()); var DropdownUI = /** @class */ (function () { function DropdownUI($node, options) { this.$button = $node; this.options = $.extend({}, { target: options.container }, options); this.setEvent(); } DropdownUI.prototype.setEvent = function () { var _this = this; this.$button.on('click', function (e) { _this.toggle(); e.stopImmediatePropagation(); }); }; DropdownUI.prototype.clear = function () { var $parent = $('.note-btn-group.open'); $parent.find('.note-btn.active').removeClass('active'); $parent.removeClass('open'); }; DropdownUI.prototype.show = function () { this.$button.addClass('active'); this.$button.parent().addClass('open'); var $dropdown = this.$button.next(); var offset = $dropdown.offset(); var width = $dropdown.outerWidth(); var windowWidth = $(window).width(); var targetMarginRight = parseFloat($(this.options.target).css('margin-right')); if (offset.left + width > windowWidth - targetMarginRight) { $dropdown.css('margin-left', windowWidth - targetMarginRight - (offset.left + width)); } else { $dropdown.css('margin-left', ''); } }; DropdownUI.prototype.hide = function () { this.$button.removeClass('active'); this.$button.parent().removeClass('open'); }; DropdownUI.prototype.toggle = function () { var isOpened = this.$button.parent().hasClass('open'); this.clear(); if (isOpened) { this.hide(); } else { this.show(); } }; return DropdownUI; }()); $(document).on('click', function (e) { if (!$(e.target).closest('.note-btn-group').length) { $('.note-btn-group.open').removeClass('open'); } }); $(document).on('click.note-dropdown-menu', function (e) { $(e.target).closest('.note-dropdown-menu').parent().removeClass('open'); }); var ModalUI = /** @class */ (function () { function ModalUI($node, options) { this.options = $.extend({}, { target: options.container || 'body' }, options); this.$modal = $node; this.$backdrop = $('<div class="note-modal-backdrop" />'); } ModalUI.prototype.show = function () { if (this.options.target === 'body') { this.$backdrop.css('position', 'fixed'); this.$modal.css('position', 'fixed'); } else { this.$backdrop.css('position', 'absolute'); this.$modal.css('position', 'absolute'); } this.$backdrop.appendTo(this.options.target).show(); this.$modal.appendTo(this.options.target).addClass('open').show(); this.$modal.trigger('note.modal.show'); this.$modal.off('click', '.close').on('click', '.close', this.hide.bind(this)); }; ModalUI.prototype.hide = function () { this.$modal.removeClass('open').hide(); this.$backdrop.hide(); this.$modal.trigger('note.modal.hide'); }; return ModalUI; }()); var editor = renderer.create('<div class="note-editor note-frame"/>'); var toolbar = renderer.create('<div class="note-toolbar" role="toolbar"/>'); var editingArea = renderer.create('<div class="note-editing-area"/>'); var codable = renderer.create('<textarea class="note-codable" role="textbox" aria-multiline="true"/>'); var editable = renderer.create('<div class="note-editable" contentEditable="true" role="textbox" aria-multiline="true"/>'); var statusbar = renderer.create([ '<output class="note-status-output" role="status" aria-live="polite"/>', '<div class="note-statusbar" role="resize">', ' <div class="note-resizebar" role="seperator" aria-orientation="horizontal" aria-label="resize">', ' <div class="note-icon-bar"/>', ' <div class="note-icon-bar"/>', ' <div class="note-icon-bar"/>', ' </div>', '</div>', ].join('')); var airEditor = renderer.create('<div class="note-editor"/>'); var airEditable = renderer.create([ '<div class="note-editable" contentEditable="true" role="textbox" aria-multiline="true"/>', '<output class="note-status-output" role="status" aria-live="polite"/>', ].join('')); var buttonGroup = renderer.create('<div class="note-btn-group">'); var button = renderer.create('<button type="button" class="note-btn" role="button" tabindex="-1">', function ($node, options) { // set button type if (options && options.tooltip) { $node.attr({ 'aria-label': options.tooltip }); $node.data('_lite_tooltip', new TooltipUI($node, { title: options.tooltip, container: options.container })).on('click', function (e) { $(e.currentTarget).data('_lite_tooltip').hide(); }); } if (options.contents) { $node.html(options.contents); } if (options && options.data && options.data.toggle === 'dropdown') { $node.data('_lite_dropdown', new DropdownUI($node, { container: options.container })); } }); var dropdown = renderer.create('<div class="note-dropdown-menu" role="list">', function ($node, options) { var markup = Array.isArray(options.items) ? options.items.map(function (item) { var value = (typeof item === 'string') ? item : (item.value || ''); var content = options.template ? options.template(item) : item; var $temp = $('<a class="note-dropdown-item" href="#" data-value="' + value + '" role="listitem" aria-label="' + value + '"></a>'); $temp.html(content).data('item', item); return $temp; }) : options.items; $node.html(markup).attr({ 'aria-label': options.title }); $node.on('click', '> .note-dropdown-item', function (e) { var $a = $(this); var item = $a.data('item'); var value = $a.data('value'); if (item.click) { item.click($a); } else if (options.itemClick) { options.itemClick(e, item, value); } }); }); var dropdownCheck = renderer.create('<div class="note-dropdown-menu note-check" role="list">', function ($node, options) { var markup = Array.isArray(options.items) ? options.items.map(function (item) { var value = (typeof item === 'string') ? item : (item.value || ''); var content = options.template ? options.template(item) : item; var $temp = $('<a class="note-dropdown-item" href="#" data-value="' + value + '" role="listitem" aria-label="' + item + '"></a>'); $temp.html([icon(options.checkClassName), ' ', content]).data('item', item); return $temp; }) : options.items; $node.html(markup).attr({ 'aria-label': options.title }); $node.on('click', '> .note-dropdown-item', function (e) { var $a = $(this); var item = $a.data('item'); var value = $a.data('value'); if (item.click) { item.click($a); } else if (options.itemClick) { options.itemClick(e, item, value); } }); }); var dropdownButtonContents = function (contents, options) { return contents + ' ' + icon(options.icons.caret, 'span'); }; var dropdownButton = function (opt, callback) { return buttonGroup([ button({ className: 'dropdown-toggle', contents: opt.title + ' ' + icon('note-icon-caret'), tooltip: opt.tooltip, data: { toggle: 'dropdown' } }), dropdown({ className: opt.className, items: opt.items, template: opt.template, itemClick: opt.itemClick }), ], { callback: callback }).render(); }; var dropdownCheckButton = function (opt, callback) { return buttonGroup([ button({ className: 'dropdown-toggle', contents: opt.title + ' ' + icon('note-icon-caret'), tooltip: opt.tooltip, data: { toggle: 'dropdown' } }), dropdownCheck({ className: opt.className, checkClassName: opt.checkClassName, items: opt.items, template: opt.template, itemClick: opt.itemClick }), ], { callback: callback }).render(); }; var paragraphDropdownButton = function (opt) { return buttonGroup([ button({ className: 'dropdown-toggle', contents: opt.title + ' ' + icon('note-icon-caret'), tooltip: opt.tooltip, data: { toggle: 'dropdown' } }), dropdown([ buttonGroup({ className: 'note-align', children: opt.items[0] }), buttonGroup({ className: 'note-list', children: opt.items[1] }), ]), ]).render(); }; var tableMoveHandler = function (event, col, row) { var PX_PER_EM = 18; var $picker = $(event.target.parentNode); // target is mousecatcher var $dimensionDisplay = $picker.next(); var $catcher = $picker.find('.note-dimension-picker-mousecatcher'); var $highlighted = $picker.find('.note-dimension-picker-highlighted'); var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted'); var posOffset; // HTML5 with jQuery - e.offsetX is undefined in Firefox if (event.offsetX === undefined) { var posCatcher = $(event.target).offset(); posOffset = { x: event.pageX - posCatcher.left, y: event.pageY - posCatcher.top }; } else { posOffset = { x: event.offsetX, y: event.offsetY }; } var dim = { c: Math.ceil(posOffset.x / PX_PER_EM) || 1, r: Math.ceil(posOffset.y / PX_PER_EM) || 1 }; $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' }); $catcher.data('value', dim.c + 'x' + dim.r); if (dim.c > 3 && dim.c < col) { $unhighlighted.css({ width: dim.c + 1 + 'em' }); } if (dim.r > 3 && dim.r < row) { $unhighlighted.css({ height: dim.r + 1 + 'em' }); } $dimensionDisplay.html(dim.c + ' x ' + dim.r); }; var tableDropdownButton = function (opt) { return buttonGroup([ button({ className: 'dropdown-toggle', contents: opt.title + ' ' + icon('note-icon-caret'), tooltip: opt.tooltip, data: { toggle: 'dropdown' } }), dropdown({ className: 'note-table', items: [ '<div class="note-dimension-picker">', ' <div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"/>', ' <div class="note-dimension-picker-highlighted"/>', ' <div class="note-dimension-picker-unhighlighted"/>', '</div>', '<div class="note-dimension-display">1 x 1</div>', ].join('') }), ], { callback: function ($node) { var $catcher = $node.find('.note-dimension-picker-mousecatcher'); $catcher.css({ width: opt.col + 'em', height: opt.row + 'em' }) .mousedown(opt.itemClick) .mousemove(function (e) { tableMoveHandler(e, opt.col, opt.row); }); } }).render(); }; var palette = renderer.create('<div class="note-color-palette"/>', function ($node, options) { var contents = []; for (var row = 0, rowSize = options.colors.length; row < rowSize; row++) { var eventName = options.eventName; var colors = options.colors[row]; var colorsName = options.colorsName[row]; var buttons = []; for (var col = 0, colSize = colors.length; col < colSize; col++) { var color = colors[col]; var colorName = colorsName[col]; buttons.push([ '<button type="button" class="note-btn note-color-btn"', 'style="background-color:', color, '" ', 'data-event="', eventName, '" ', 'data-value="', color, '" ', 'title="', colorName, '" ', 'aria-label="', colorName, '" ', 'data-toggle="button" tabindex="-1"></button>', ].join('')); } contents.push('<div class="note-color-row">' + buttons.join('') + '</div>'); } $node.html(contents.join('')); $node.find('.note-color-btn').each(function () { $(this).data('_lite_tooltip', new TooltipUI($(this), { container: options.container })); }); }); var colorDropdownButton = function (opt, type) { return buttonGroup({ className: 'note-color', children: [ button({ className: 'note-current-color-button', contents: opt.title, tooltip: opt.lang.color.recent, click: opt.currentClick, callback: function ($button) { var $recentColor = $button.find('.note-recent-color'); if (type !== 'foreColor') { $recentColor.css('background-color', '#FFFF00'); $button.attr('data-backColor', '#FFFF00'); } } }), button({ className: 'dropdown-toggle', contents: icon('note-icon-caret'), tooltip: opt.lang.color.more, data: { toggle: 'dropdown' } }), dropdown({ items: [ '<div>', '<div class="note-btn-group btn-background-color">', ' <div class="note-palette-title">' + opt.lang.color.background + '</div>', ' <div>', '<button type="button" class="note-color-reset note-btn note-btn-block" ' + ' data-event="backColor" data-value="inherit">', opt.lang.color.transparent, ' </button>', ' </div>', ' <div class="note-holder" data-event="backColor"/>', ' <div class="btn-sm">', ' <input type="color" id="html5bcp" class="note-btn btn-default" value="#21104A" style="width:100%;" data-value="cp">', ' <button type="button" class="note-color-reset btn" data-event="backColor" data-value="cpbackColor">', opt.lang.color.cpSelect, ' </button>', ' </div>', '</div>', '<div class="note-btn-group btn-foreground-color">', ' <div class="note-palette-title">' + opt.lang.color.foreground + '</div>', ' <div>', '<button type="button" class="note-color-reset note-btn note-btn-block" ' + ' data-event="removeFormat" data-value="foreColor">', opt.lang.color.resetToDefault, ' </button>', ' </div>', ' <div class="note-holder" data-event="foreColor"/>', ' <div class="btn-sm">', ' <input type="color" id="html5fcp" class="note-btn btn-default" value="#21104A" style="width:100%;" data-value="cp">', ' <button type="button" class="note-color-reset btn" data-event="foreColor" data-value="cpforeColor">', opt.lang.color.cpSelect, ' </button>', ' </div>', '</div>', '</div>', ].join(''), callback: function ($dropdown) { $dropdown.find('.note-holder').each(function () { var $holder = $(this); $holder.append(palette({ colors: opt.colors, eventName: $holder.data('event') }).render()); }); if (type === 'fore') { $dropdown.find('.btn-background-color').hide(); $dropdown.css({ 'min-width': '210px' }); } else if (type === 'back') { $dropdown.find('.btn-foreground-color').hide(); $dropdown.css({ 'min-width': '210px' }); } }, click: function (event) { var $button = $(event.target); var eventName = $button.data('event'); var value = $button.data('value'); var foreinput = document.getElementById('html5fcp').value; var backinput = document.getElementById('html5bcp').value; if (value === 'cp') { event.stopPropagation(); } else if (value === 'cpbackColor') { value = backinput; } else if (value === 'cpforeColor') { value = foreinput; } if (eventName && value) { var key = eventName === 'backColor' ? 'background-color' : 'color'; var $color = $button.closest('.note-color').find('.note-recent-color'); var $currentButton = $button.closest('.note-color').find('.note-current-color-button'); $color.css(key, value); $currentButton.attr('data-' + eventName, value); if (type === 'fore') { opt.itemClick('foreColor', value); } else if (type === 'back') { opt.itemClick('backColor', value); } else { opt.itemClick(eventName, value); } } } }), ] }).render(); }; var dialog = renderer.create('<div class="note-modal" aria-hidden="false" tabindex="-1" role="dialog"/>', function ($node, options) { if (options.fade) { $node.addClass('fade'); } $node.attr({ 'aria-label': options.title }); $node.html([ ' <div class="note-modal-content">', (options.title ? ' <div class="note-modal-header">' + ' <button type="button" class="close" aria-label="Close" aria-hidden="true"><i class="note-icon-close"></i></button>' + ' <h4 class="note-modal-title">' + options.title + '</h4>' + ' </div>' : ''), ' <div class="note-modal-body">' + options.body + '</div>', (options.footer ? ' <div class="note-modal-footer">' + options.footer + '</div>' : ''), ' </div>', ].join('')); $node.data('modal', new ModalUI($node, options)); }); var videoDialog = function (opt) { var body = '<div class="note-form-group">' + '<label class="note-form-label">' + opt.lang.video.url + ' <small class="text-muted">' + opt.lang.video.providers + '</small>' + '</label>' + '<input class="note-video-url note-input" type="text" />' + '</div>'; var footer = [ '<button type="button" href="#" class="note-btn note-btn-primary note-video-btn disabled" disabled>', opt.lang.video.insert, '</button>', ].join(''); return dialog({ title: opt.lang.video.insert, fade: opt.fade, body: body, footer: footer }).render(); }; var imageDialog = function (opt) { var body = '<div class="note-form-group note-group-select-from-files">' + '<label class="note-form-label">' + opt.lang.image.selectFromFiles + '</label>' + '<input class="note-note-image-input note-input" type="file" name="files" accept="image/*" multiple="multiple" />' + opt.imageLimitation + '</div>' + '<div class="note-form-group" style="overflow:auto;">' + '<label class="note-form-label">' + opt.lang.image.url + '</label>' + '<input class="note-image-url note-input" type="text" />' + '</div>'; var footer = [ '<button href="#" type="button" class="note-btn note-btn-primary note-btn-large note-image-btn disabled" disabled>', opt.lang.image.insert, '</button>', ].join(''); return dialog({ title: opt.lang.image.insert, fade: opt.fade, body: body, footer: footer }).render(); }; var linkDialog = function (opt) { var body = '<div class="note-form-group">' + '<label class="note-form-label">' + opt.lang.link.textToDisplay + '</label>' + '<input class="note-link-text note-input" type="text" />' + '</div>' + '<div class="note-form-group">' + '<label class="note-form-label">' + opt.lang.link.url + '</label>' + '<input class="note-link-url note-input" type="text" value="http://" />' + '</div>' + (!opt.disableLinkTarget ? '<div class="checkbox">' + '<label>' + '<input type="checkbox" checked> ' + opt.lang.link.openInNewWindow + '</label>' + '</div>' : ''); var footer = [ '<button href="#" type="button" class="note-btn note-btn-primary note-link-btn disabled" disabled>', opt.lang.link.insert, '</button>', ].join(''); return dialog({ className: 'link-dialog', title: opt.lang.link.insert, fade: opt.fade, body: body, footer: footer }).render(); }; var popover = renderer.create([ '<div class="note-popover bottom">', ' <div class="note-popover-arrow"/>', ' <div class="popover-content note-children-container"/>', '</div>', ].join(''), function ($node, options) { var direction = typeof options.direction !== 'undefined' ? options.direction : 'bottom'; $node.addClass(direction).hide(); if (options.hideArrow) { $node.find('.note-popover-arrow').hide(); } }); var checkbox = renderer.create('<div class="checkbox"></div>', function ($node, options) { $node.html([ '<label' + (options.id ? ' for="' + options.id + '"' : '') + '>', ' <input role="checkbox" type="checkbox"' + (options.id ? ' id="' + options.id + '"' : ''), (options.checked ? ' checked' : ''), ' aria-checked="' + (options.checked ? 'true' : 'false') + '"/>', (options.text ? options.text : ''), '</label>', ].join('')); }); var icon = function (iconClassName, tagName) { tagName = tagName || 'i'; return '<' + tagName + ' class="' + iconClassName + '"/>'; }; var ui = { editor: editor, toolbar: toolbar, editingArea: editingArea, codable: codable, editable: editable, statusbar: statusbar, airEditor: airEditor, airEditable: airEditable, buttonGroup: buttonGroup, button: button, dropdown: dropdown, dropdownCheck: dropdownCheck, dropdownButton: dropdownButton, dropdownButtonContents: dropdownButtonContents, dropdownCheckButton: dropdownCheckButton, paragraphDropdownButton: paragraphDropdownButton, tableDropdownButton: tableDropdownButton, colorDropdownButton: colorDropdownButton, palette: palette, dialog: dialog, videoDialog: videoDialog, imageDialog: imageDialog, linkDialog: linkDialog, popover: popover, checkbox: checkbox, icon: icon, toggleBtn: function ($btn, isEnable) { $btn.toggleClass('disabled', !isEnable); $btn.attr('disabled', !isEnable); }, toggleBtnActive: function ($btn, isActive) { $btn.toggleClass('active', isActive); }, check: function ($dom, value) { $dom.find('.checked').removeClass('checked'); $dom.find('[data-value="' + value + '"]').addClass('checked'); }, onDialogShown: function ($dialog, handler) { $dialog.one('note.modal.show', handler); }, onDialogHidden: function ($dialog, handler) { $dialog.one('note.modal.hide', handler); }, showDialog: function ($dialog) { $dialog.data('modal').show(); }, hideDialog: function ($dialog) { $dialog.data('modal').hide(); }, /** * get popover content area * * @param $popover * @returns {*} */ getPopoverContent: function ($popover) { return $popover.find('.note-popover-content'); }, /** * get dialog's body area * * @param $dialog * @returns {*} */ getDialogBody: function ($dialog) { return $dialog.find('.note-modal-body'); }, createLayout: function ($note, options) { var $editor = (options.airMode ? ui.airEditor([ ui.editingArea([ ui.airEditable(), ]), ]) : ui.editor([ ui.toolbar(), ui.editingArea([ ui.codable(), ui.editable(), ]), ui.statusbar(), ])).render(); $editor.insertAfter($note); return { note: $note, editor: $editor, toolbar: $editor.find('.note-toolbar'), editingArea: $editor.find('.note-editing-area'), editable: $editor.find('.note-editable'), codable: $editor.find('.note-codable'), statusbar: $editor.find('.note-statusbar') }; }, removeLayout: function ($note, layoutInfo) { $note.html(layoutInfo.editable.html()); layoutInfo.editor.remove(); $note.off('summernote'); // remove summernote custom event $note.show(); } }; $$1.summernote = $$1.summernote || { lang: {} }; $$1.extend($$1.summernote.lang, { 'en-US': { font: { bold: 'Bold', italic: 'Italic', underline: 'Underline', clear: 'Remove Font Style', height: 'Line Height', name: 'Font Family', strikethrough: 'Strikethrough', subscript: 'Subscript', superscript: 'Superscript', size: 'Font Size' }, image: { image: 'Picture', insert: 'Insert Image', resizeFull: 'Resize full', resizeHalf: 'Resize half', resizeQuarter: 'Resize quarter', resizeNone: 'Original size', floatLeft: 'Float Left', floatRight: 'Float Right', floatNone: 'Remove float', shapeRounded: 'Shape: Rounded', shapeCircle: 'Shape: Circle', shapeThumbnail: 'Shape: Thumbnail', shapeNone: 'Shape: None', dragImageHere: 'Drag image or text here', dropImage: 'Drop image or Text', selectFromFiles: 'Select from files', maximumFileSize: 'Maximum file size', maximumFileSizeError: 'Maximum file size exceeded.', url: 'Image URL', remove: 'Remove Image', original: 'Original' }, video: { video: 'Video', videoLink: 'Video Link', insert: 'Insert Video', url: 'Video URL', providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)' }, link: { link: 'Link', insert: 'Insert Link', unlink: 'Unlink', edit: 'Edit', textToDisplay: 'Text to display', url: 'To what URL should this link go?', openInNewWindow: 'Open in new window' }, table: { table: 'Table', addRowAbove: 'Add row above', addRowBelow: 'Add row below', addColLeft: 'Add column left', addColRight: 'Add column right', delRow: 'Delete row', delCol: 'Delete column', delTable: 'Delete table' }, hr: { insert: 'Insert Horizontal Rule' }, style: { style: 'Style', p: 'Normal', blockquote: 'Quote', pre: 'Code', h1: 'Header 1', h2: 'Header 2', h3: 'Header 3', h4: 'Header 4', h5: 'Header 5', h6: 'Header 6' }, lists: { unordered: 'Unordered list', ordered: 'Ordered list' }, options: { help: 'Help', fullscreen: 'Full Screen', codeview: 'Code View' }, paragraph: { paragraph: 'Paragraph', outdent: 'Outdent', indent: 'Indent', left: 'Align left', center: 'Align center', right: 'Align right', justify: 'Justify full' }, color: { recent: 'Recent Color', more: 'More Color', background: 'Background Color', foreground: 'Foreground Color', transparent: 'Transparent', setTransparent: 'Set transparent', reset: 'Reset', resetToDefault: 'Reset to default', cpSelect: 'Select' }, shortcut: { shortcuts: 'Keyboard shortcuts', close: 'Close', textFormatting: 'Text formatting', action: 'Action', paragraphFormatting: 'Paragraph formatting', documentStyle: 'Document Style', extraKeys: 'Extra keys' }, help: { 'insertParagraph': 'Insert Paragraph', 'undo': 'Undoes the last command', 'redo': 'Redoes the last command', 'tab': 'Tab', 'untab': 'Untab', 'bold': 'Set a bold style', 'italic': 'Set a italic style', 'underline': 'Set a underline style', 'strikethrough': 'Set a strikethrough style', 'removeFormat': 'Clean a style', 'justifyLeft': 'Set left align', 'justifyCenter': 'Set center align', 'justifyRight': 'Set right align', 'justifyFull': 'Set full align', 'insertUnorderedList': 'Toggle unordered list', 'insertOrderedList': 'Toggle ordered list', 'outdent': 'Outdent on current paragraph', 'indent': 'Indent on current paragraph', 'formatPara': 'Change current block\'s format as a paragraph(P tag)', 'formatH1': 'Change current block\'s format as H1', 'formatH2': 'Change current block\'s format as H2', 'formatH3': 'Change current block\'s format as H3', 'formatH4': 'Change current block\'s format as H4', 'formatH5': 'Change current block\'s format as H5', 'formatH6': 'Change current block\'s format as H6', 'insertHorizontalRule': 'Insert horizontal rule', 'linkDialog.show': 'Show Link Dialog' }, history: { undo: 'Undo', redo: 'Redo' }, specialChar: { specialChar: 'SPECIAL CHARACTERS', select: 'Select Special characters' } } }); var isSupportAmd = typeof define === 'function' && define.amd; // eslint-disable-line /** * returns whether font is installed or not. * * @param {String} fontName * @return {Boolean} */ function isFontInstalled(fontName) { var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS'; var testText = 'mmmmmmmmmmwwwww'; var testSize = '200px'; var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); context.font = testSize + " '" + testFontName + "'"; var originalWidth = context.measureText(testText).width; context.font = testSize + " '" + fontName + "', '" + testFontName + "'"; var width = context.measureText(testText).width; return originalWidth !== width; } var userAgent = navigator.userAgent; var isMSIE = /MSIE|Trident/i.test(userAgent); var browserVersion; if (isMSIE) { var matches = /MSIE (\d+[.]\d+)/.exec(userAgent); if (matches) { browserVersion = parseFloat(matches[1]); } matches = /Trident\/.*rv:([0-9]{1,}[.0-9]{0,})/.exec(userAgent); if (matches) { browserVersion = parseFloat(matches[1]); } } var isEdge = /Edge\/\d+/.test(userAgent); var hasCodeMirror = !!window.CodeMirror; var isSupportTouch = (('ontouchstart' in window) || (navigator.MaxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)); // [workaround] IE doesn't have input events for contentEditable // - see: https://goo.gl/4bfIvA var inputEventName = (isMSIE || isEdge) ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input'; /** * @class core.env * * Object which check platform and agent * * @singleton * @alternateClassName env */ var env = { isMac: navigator.appVersion.indexOf('Mac') > -1, isMSIE: isMSIE, isEdge: isEdge, isFF: !isEdge && /firefox/i.test(userAgent), isPhantom: /PhantomJS/i.test(userAgent), isWebkit: !isEdge && /webkit/i.test(userAgent), isChrome: !isEdge && /chrome/i.test(userAgent), isSafari: !isEdge && /safari/i.test(userAgent), browserVersion: browserVersion, jqueryVersion: parseFloat($$1.fn.jquery), isSupportAmd: isSupportAmd, isSupportTouch: isSupportTouch, hasCodeMirror: hasCodeMirror, isFontInstalled: isFontInstalled, isW3CRangeSupport: !!document.createRange, inputEventName: inputEventName }; /** * @class core.func * * func utils (for high-order func's arg) * * @singleton * @alternateClassName func */ function eq(itemA) { return function (itemB) { return itemA === itemB; }; } function eq2(itemA, itemB) { return itemA === itemB; } function peq2(propName) { return function (itemA, itemB) { return itemA[propName] === itemB[propName]; }; } function ok() { return true; } function fail() { return false; } function not(f) { return function () { return !f.apply(f, arguments); }; } function and(fA, fB) { return function (item) { return fA(item) && fB(item); }; } function self(a) { return a; } function invoke(obj, method) { return function () { return obj[method].apply(obj, arguments); }; } var idCounter = 0; /** * generate a globally-unique id * * @param {String} [prefix] */ function uniqueId(prefix) { var id = ++idCounter + ''; return prefix ? prefix + id : id; } /** * returns bnd (bounds) from rect * * - IE Compatibility Issue: http://goo.gl/sRLOAo * - Scroll Issue: http://goo.gl/sNjUc * * @param {Rect} rect * @return {Object} bounds * @return {Number} bounds.top * @return {Number} bounds.left * @return {Number} bounds.width * @return {Number} bounds.height */ function rect2bnd(rect) { var $document = $(document); return { top: rect.top + $document.scrollTop(), left: rect.left + $document.scrollLeft(), width: rect.right - rect.left, height: rect.bottom - rect.top }; } /** * returns a copy of the object where the keys have become the values and the values the keys. * @param {Object} obj * @return {Object} */ function invertObject(obj) { var inverted = {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { inverted[obj[key]] = key; } } return inverted; } /** * @param {String} namespace * @param {String} [prefix] * @return {String} */ function namespaceToCamel(namespace, prefix) { prefix = prefix || ''; return prefix + namespace.split('.').map(function (name) { return name.substring(0, 1).toUpperCase() + name.substring(1); }).join(''); } /** * Returns a function, that, as long as it continues to be invoked, will not * be triggered. The function will be called after it stops being called for * N milliseconds. If `immediate` is passed, trigger the function on the * leading edge, instead of the trailing. * @param {Function} func * @param {Number} wait * @param {Boolean} immediate * @return {Function} */ function debounce(func, wait, immediate) { var timeout; return function () { var context = this; var args = arguments; var later = function () { timeout = null; if (!immediate) { func.apply(context, args); } }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) { func.apply(context, args); } }; } /** * * @param {String} url * @return {Boolean} */ function isValidUrl(url) { var expression = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi; return expression.test(url); } var func = { eq: eq, eq2: eq2, peq2: peq2, ok: ok, fail: fail, self: self, not: not, and: and, invoke: invoke, uniqueId: uniqueId, rect2bnd: rect2bnd, invertObject: invertObject, namespaceToCamel: namespaceToCamel, debounce: debounce, isValidUrl: isValidUrl }; /** * returns the first item of an array. * * @param {Array} array */ function head(array) { return array[0]; } /** * returns the last item of an array. * * @param {Array} array */ function last(array) { return array[array.length - 1]; } /** * returns everything but the last entry of the array. * * @param {Array} array */ function initial(array) { return array.slice(0, array.length - 1); } /** * returns the rest of the items in an array. * * @param {Array} array */ function tail(array) { return array.slice(1); } /** * returns item of array */ function find(array, pred) { for (var idx = 0, len = array.length; idx < len; idx++) { var item = array[idx]; if (pred(item)) { return item; } } } /** * returns true if all of the values in the array pass the predicate truth test. */ function all(array, pred) { for (var idx = 0, len = array.length; idx < len; idx++) { if (!pred(array[idx])) { return false; } } return true; } /** * returns true if the value is present in the list. */ function contains(array, item) { if (array && array.length && item) { return array.indexOf(item) !== -1; } return false; } /** * get sum from a list * * @param {Array} array - array * @param {Function} fn - iterator */ function sum(array, fn) { fn = fn || func.self; return array.reduce(function (memo, v) { return memo + fn(v); }, 0); } /** * returns a copy of the collection with array type. * @param {Collection} collection - collection eg) node.childNodes, ... */ function from(collection) { var result = []; var length = collection.length; var idx = -1; while (++idx < length) { result[idx] = collection[idx]; } return result; } /** * returns whether list is empty or not */ function isEmpty(array) { return !array || !array.length; } /** * cluster elements by predicate function. * * @param {Array} array - array * @param {Function} fn - predicate function for cluster rule * @param {Array[]} */ function clusterBy(array, fn) { if (!array.length) { return []; } var aTail = tail(array); return aTail.reduce(function (memo, v) { var aLast = last(memo); if (fn(last(aLast), v)) { aLast[aLast.length] = v; } else { memo[memo.length] = [v]; } return memo; }, [[head(array)]]); } /** * returns a copy of the array with all false values removed * * @param {Array} array - array * @param {Function} fn - predicate function for cluster rule */ function compact(array) { var aResult = []; for (var idx = 0, len = array.length; idx < len; idx++) { if (array[idx]) { aResult.push(array[idx]); } } return aResult; } /** * produces a duplicate-free version of the array * * @param {Array} array */ function unique(array) { var results = []; for (var idx = 0, len = array.length; idx < len; idx++) { if (!contains(results, array[idx])) { results.push(array[idx]); } } return results; } /** * returns next item. * @param {Array} array */ function next(array, item) { if (array && array.length && item) { var idx = array.indexOf(item); return idx === -1 ? null : array[idx + 1]; } return null; } /** * returns prev item. * @param {Array} array */ function prev(array, item) { if (array && array.length && item) { var idx = array.indexOf(item); return idx === -1 ? null : array[idx - 1]; } return null; } /** * @class core.list * * list utils * * @singleton * @alternateClassName list */ var lists = { head: head, last: last, initial: initial, tail: tail, prev: prev, next