/* Redactor II Version 2.10 Updated: September 4, 2017 http://imperavi.com/redactor/ Copyright (c) 2009-2017, Imperavi LLC. License: http://imperavi.com/redactor/license/ Usage: $('#content').redactor(); */ (function($) { 'use strict'; if (!Function.prototype.bind) { Function.prototype.bind = function(scope) { var fn = this; return function() { return fn.apply(scope); }; }; } var uuid = 0; // Plugin $.fn.redactor = function(options) { var val = []; var args = Array.prototype.slice.call(arguments, 1); if (typeof options === 'string') { this.each(function() { var instance = $.data(this, 'redactor'); var func; if (options.search(/\./) !== '-1') { func = options.split('.'); if (typeof instance[func[0]] !== 'undefined') { func = instance[func[0]][func[1]]; } } else { func = instance[options]; } if (typeof instance !== 'undefined' && $.isFunction(func)) { var methodVal = func.apply(instance, args); if (methodVal !== undefined && methodVal !== instance) { val.push(methodVal); } } else { $.error('No such method "' + options + '" for Redactor'); } }); } else { this.each(function() { $.data(this, 'redactor', {}); $.data(this, 'redactor', Redactor(this, options)); }); } if (val.length === 0) { return this; } else if (val.length === 1) { return val[0]; } else { return val; } }; // Initialization function Redactor(el, options) { return new Redactor.prototype.init(el, options); } // Options $.Redactor = Redactor; $.Redactor.VERSION = '2.10'; $.Redactor.modules = ['air', 'autosave', 'block', 'buffer', 'build', 'button', 'caret', 'clean', 'code', 'core', 'detect', 'dropdown', 'events', 'file', 'focus', 'image', 'indent', 'inline', 'insert', 'keydown', 'keyup', 'lang', 'line', 'link', 'linkify', 'list', 'marker', 'modal', 'observe', 'offset', 'paragraphize', 'paste', 'placeholder', 'progress', 'selection', 'shortcuts', 'storage', 'toolbar', 'upload', 'uploads3', 'utils', 'browser' // deprecated ]; $.Redactor.settings = {}; $.Redactor.opts = { // settings animation: false, lang: 'en', direction: 'ltr', spellcheck: true, overrideStyles: true, stylesClass: false, scrollTarget: document, focus: false, focusEnd: false, clickToEdit: false, structure: false, tabindex: false, minHeight: false, // string maxHeight: false, // string maxWidth: false, // string plugins: false, // array callbacks: {}, placeholder: false, linkify: true, enterKey: true, pastePlainText: false, pasteImages: true, pasteLinks: true, pasteBlockTags: ['pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'table', 'tbody', 'thead', 'tfoot', 'th', 'tr', 'td', 'ul', 'ol', 'li', 'blockquote', 'p', 'figure', 'figcaption'], pasteInlineTags: ['br', 'strong', 'ins', 'code', 'del', 'span', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small', 'b', 'u', 'em', 'i'], preClass: false, // string preSpaces: 4, // or false tabAsSpaces: false, // true or number of spaces tabKey: true, autosave: false, // false or url autosaveName: false, autosaveFields: false, imageUpload: null, imageUploadParam: 'file', imageUploadFields: false, imageUploadForms: false, imageTag: 'figure', imageEditable: true, imageCaption: true, imagePosition: false, imageResizable: false, imageFloatMargin: '10px', dragImageUpload: true, multipleImageUpload: true, clipboardImageUpload: true, fileUpload: null, fileUploadParam: 'file', fileUploadFields: false, fileUploadForms: false, dragFileUpload: true, s3: false, linkNewTab: false, linkTooltip: true, linkNofollow: false, linkSize: 30, linkValidation: true, pasteLinkTarget: false, videoContainerClass: 'video-container', toolbar: true, toolbarFixed: true, toolbarFixedTarget: document, toolbarFixedTopOffset: 0, // pixels toolbarExternal: false, // ID selector toolbarOverflow: false, air: false, airWidth: false, formatting: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], formattingAdd: false, buttons: ['format', 'bold', 'italic', 'deleted', 'lists', 'image', 'file', 'link', 'horizontalrule'], // + 'horizontalrule', 'underline', 'ol', 'ul', 'indent', 'outdent' buttonsTextLabeled: false, buttonsHide: [], buttonsHideOnMobile: [], script: true, removeNewlines: false, removeComments: true, replaceTags: { 'b': 'strong', 'i': 'em', 'strike': 'del' }, keepStyleAttr: [], // tag name array keepInlineOnEnter: false, // shortcuts shortcuts: { 'ctrl+shift+m, meta+shift+m': { func: 'inline.removeFormat' }, 'ctrl+b, meta+b': { func: 'inline.format', params: ['bold'] }, 'ctrl+i, meta+i': { func: 'inline.format', params: ['italic'] }, 'ctrl+h, meta+h': { func: 'inline.format', params: ['superscript'] }, 'ctrl+l, meta+l': { func: 'inline.format', params: ['subscript'] }, 'ctrl+k, meta+k': { func: 'link.show' }, 'ctrl+shift+7': { func: 'list.toggle', params: ['orderedlist'] }, 'ctrl+shift+8': { func: 'list.toggle', params: ['unorderedlist'] } }, shortcutsAdd: false, activeButtons: ['deleted', 'italic', 'bold'], activeButtonsStates: { b: 'bold', strong: 'bold', i: 'italic', em: 'italic', del: 'deleted', strike: 'deleted' }, // private lang langs: { en: { "format": "Format", "image": "Image", "file": "File", "link": "Link", "bold": "Bold", "italic": "Italic", "deleted": "Strikethrough", "underline": "Underline", "bold-abbr": "B", "italic-abbr": "I", "deleted-abbr": "S", "underline-abbr": "U", "lists": "Lists", "link-insert": "Insert link", "link-edit": "Edit link", "link-in-new-tab": "Open link in new tab", "unlink": "Unlink", "cancel": "Cancel", "close": "Close", "insert": "Insert", "save": "Save", "delete": "Delete", "text": "Text", "edit": "Edit", "title": "Title", "paragraph": "Normal text", "quote": "Quote", "code": "Code", "heading1": "Heading 1", "heading2": "Heading 2", "heading3": "Heading 3", "heading4": "Heading 4", "heading5": "Heading 5", "heading6": "Heading 6", "filename": "Name", "optional": "optional", "unorderedlist": "Unordered List", "orderedlist": "Ordered List", "outdent": "Outdent", "indent": "Indent", "horizontalrule": "Line", "upload-label": "Drop file here or ", "caption": "Caption", "bulletslist": "Bullets", "numberslist": "Numbers", "image-position": "Position", "none": "None", "left": "Left", "right": "Right", "center": "Center", "accessibility-help-label": "Rich text editor" } }, // private type: 'textarea', // textarea, div, inline, pre inline: false, inlineTags: ['a', 'span', 'strong', 'strike', 'b', 'u', 'em', 'i', 'code', 'del', 'ins', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small'], blockTags: ['pre', 'ul', 'ol', 'li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'dt', 'dd', 'div', 'td', 'blockquote', 'output', 'figcaption', 'figure', 'address', 'section', 'header', 'footer', 'aside', 'article', 'iframe'], paragraphize: true, paragraphizeBlocks: ['table', 'div', 'pre', 'form', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'blockquote', 'figcaption', 'address', 'section', 'header', 'footer', 'aside', 'article', 'object', 'style', 'script', 'iframe', 'select', 'input', 'textarea', 'button', 'option', 'map', 'area', 'math', 'hr', 'fieldset', 'legend', 'hgroup', 'nav', 'figure', 'details', 'menu', 'summary', 'p'], emptyHtml: '
', invisibleSpace: '', emptyHtmlRendered: $('').html('').html(), imageTypes: ['image/png', 'image/jpeg', 'image/gif'], userAgent: navigator.userAgent.toLowerCase(), observe: { dropdowns: [] }, regexps: { linkyoutube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig, linkvimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/, linkimage: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/ig, url: /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/ig } }; // Functionality Redactor.fn = $.Redactor.prototype = { keyCode: { BACKSPACE: 8, DELETE: 46, UP: 38, DOWN: 40, ENTER: 13, SPACE: 32, ESC: 27, TAB: 9, CTRL: 17, META: 91, SHIFT: 16, ALT: 18, RIGHT: 39, LEFT: 37, LEFT_WIN: 91 }, // =init init: function(el, options) { this.$element = $(el); this.uuid = uuid++; this.sBuffer = []; this.sRebuffer = []; this.loadOptions(options); this.loadModules(); // click to edit if (this.opts.clickToEdit && !this.$element.hasClass('redactor-click-to-edit')) { return this.loadToEdit(options); } else if (this.$element.hasClass('redactor-click-to-edit')) { this.$element.removeClass('redactor-click-to-edit'); } // block & inline test tag regexp this.reIsBlock = new RegExp('^(' + this.opts.blockTags.join('|' ).toUpperCase() + ')$', 'i'); this.reIsInline = new RegExp('^(' + this.opts.inlineTags.join('|' ).toUpperCase() + ')$', 'i'); // set up drag upload this.opts.dragImageUpload = (this.opts.imageUpload === null) ? false : this.opts.dragImageUpload; this.opts.dragFileUpload = (this.opts.fileUpload === null) ? false : this.opts.dragFileUpload; // formatting storage this.formatting = {}; // load lang this.lang.load(); // extend shortcuts $.extend(this.opts.shortcuts, this.opts.shortcutsAdd); // set editor this.$editor = this.$element; // detect type of editor this.detectType(); // start callback this.core.callback('start'); this.core.callback('startToEdit'); // build this.start = true; this.build.start(); }, detectType: function() { if (this.build.isInline() || this.opts.inline) { this.opts.type = 'inline'; } else if (this.build.isTag('DIV')) { this.opts.type = 'div'; } else if (this.build.isTag('PRE')) { this.opts.type = 'pre'; } }, loadToEdit: function(options) { this.$element.on('click.redactor-click-to-edit', $.proxy(function() { this.initToEdit(options); }, this)); this.$element.addClass('redactor-click-to-edit'); return; }, initToEdit: function(options) { $.extend(options.callbacks, { startToEdit: function() { this.insert.node(this.marker.get(), false); }, initToEdit: function() { this.selection.restore(); this.clickToCancelStorage = this.code.get(); // cancel $(this.opts.clickToCancel).off('.redactor-click-to-edit'); $(this.opts.clickToCancel).show().on('click.redactor-click-to-edit', $.proxy(function(e) { e.preventDefault(); this.core.destroy(); this.events.syncFire = false; this.$element.html(this.clickToCancelStorage); this.core.callback('cancel', this.clickToCancelStorage); this.events.syncFire = true; this.clickToCancelStorage = ''; $(this.opts.clickToCancel).hide(); $(this.opts.clickToSave).hide(); this.$element.on('click.redactor-click-to-edit', $.proxy(function() { this.initToEdit(options); }, this)); this.$element.addClass('redactor-click-to-edit'); }, this)); // save $(this.opts.clickToSave).off('.redactor-click-to-edit'); $(this.opts.clickToSave).show().on('click.redactor-click-to-edit', $.proxy(function(e) { e.preventDefault(); this.core.destroy(); this.core.callback('save', this.code.get()); $(this.opts.clickToCancel).hide(); $(this.opts.clickToSave).hide(); this.$element.on('click.redactor-click-to-edit', $.proxy(function() { this.initToEdit(options); }, this)); this.$element.addClass('redactor-click-to-edit'); }, this)); } }); this.$element.redactor(options); this.$element.off('.redactor-click-to-edit'); }, loadOptions: function(options) { var settings = {}; // check namespace if (typeof $.Redactor.settings.namespace !== 'undefined') { if (this.$element.hasClass($.Redactor.settings.namespace)) { settings = $.Redactor.settings; } } else { settings = $.Redactor.settings; } this.opts = $.extend( {}, $.Redactor.opts, this.$element.data(), options ); this.opts = $.extend({}, this.opts, settings); }, getModuleMethods: function(object) { return Object.getOwnPropertyNames(object).filter(function(property) { return typeof object[property] === 'function'; }); }, loadModules: function() { var len = $.Redactor.modules.length; for (var i = 0; i < len; i++) { this.bindModuleMethods($.Redactor.modules[i]); } }, bindModuleMethods: function(module) { if (typeof this[module] === 'undefined') { return; } // init module this[module] = this[module](); var methods = this.getModuleMethods(this[module]); var len = methods.length; // bind methods for (var z = 0; z < len; z++) { this[module][methods[z]] = this[module][methods[z]].bind(this); } }, // =air air: function() { return { enabled: false, collapsed: function() { if (this.opts.air) { this.selection.get().collapseToStart(); } }, collapsedEnd: function() { if (this.opts.air) { this.selection.get().collapseToEnd(); } }, build: function() { if (this.detect.isMobile()) { return; } this.button.hideButtons(); this.button.hideButtonsOnMobile(); if (this.opts.buttons.length === 0) { return; } this.$air = this.air.createContainer(); if (this.opts.airWidth !== false) { this.$air.css('width', this.opts.airWidth); } this.air.append(); this.button.$toolbar = this.$air; this.button.setFormatting(); this.button.load(this.$air); this.core.editor().on('mouseup.redactor', this, $.proxy(function(e) { if (this.selection.text() !== '') { this.air.show(e); } }, this)); }, append: function() { this.$air.appendTo('body'); }, createContainer: function() { return $('