diff --git a/app/assets/javascripts/redactor.js b/app/assets/javascripts/redactor.js
index fe77a60..e494c14 100755
--- a/app/assets/javascripts/redactor.js
+++ b/app/assets/javascripts/redactor.js
@@ -1,10 +1,10 @@
/*
- Redactor v10.0.1
- Updated: October 6, 2014
+ Redactor 10.2.5
+ Updated: October 1, 2015
http://imperavi.com/redactor/
- Copyright (c) 2009-2014, Imperavi LLC.
+ Copyright (c) 2009-2015, Imperavi LLC.
License: http://imperavi.com/redactor/license/
Usage: $('#content').redactor();
@@ -12,6 +12,7 @@
(function($)
{
+
'use strict';
if (!Function.prototype.bind)
@@ -28,9 +29,6 @@
var uuid = 0;
- var reUrlYoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig;
- var reUrlVimeo = /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/;
-
// Plugin
$.fn.redactor = function(options)
{
@@ -94,11 +92,13 @@
// Functionality
$.Redactor = Redactor;
- $.Redactor.VERSION = '10.0.1';
- $.Redactor.modules = ['core', 'build', 'lang', 'toolbar', 'button', 'dropdown', 'code',
- 'clean', 'tidy', 'paragraphize', 'tabifier', 'focus', 'placeholder', 'autosave', 'buffer', 'indent', 'alignment', 'paste',
- 'keydown', 'keyup', 'shortcuts', 'line', 'list', 'block', 'inline', 'insert', 'caret', 'selection', 'observe',
- 'link', 'image', 'file', 'modal', 'progress', 'upload', 'utils'];
+ $.Redactor.VERSION = '10.2.5';
+ $.Redactor.modules = ['alignment', 'autosave', 'block', 'buffer', 'build', 'button',
+ 'caret', 'clean', 'code', 'core', 'dropdown', 'file', 'focus',
+ 'image', 'indent', 'inline', 'insert', 'keydown', 'keyup',
+ 'lang', 'line', 'link', 'linkify', 'list', 'modal', 'observe', 'paragraphize',
+ 'paste', 'placeholder', 'progress', 'selection', 'shortcuts',
+ 'tabifier', 'tidy', 'toolbar', 'upload', 'utils'];
$.Redactor.opts = {
@@ -133,6 +133,7 @@
autosaveName: false,
autosaveInterval: 60, // seconds
autosaveOnChange: false,
+ autosaveFields: false,
linkTooltip: true,
linkProtocol: 'http',
@@ -145,14 +146,14 @@
imageFloatMargin: '10px',
imageResizable: true,
- imageUpload: false,
+ imageUpload: null,
imageUploadParam: 'file',
uploadImageField: false,
dragImageUpload: true,
- fileUpload: false,
+ fileUpload: null,
fileUploadParam: 'file',
dragFileUpload: true,
@@ -166,7 +167,7 @@
preSpaces: 4, // or false
tabAsSpaces: false, // true or number of spaces
- tabFocus: true,
+ tabKey: true,
scrollTarget: false,
@@ -177,7 +178,7 @@
toolbarExternal: false, // ID selector
toolbarOverflow: false,
- buttonSource: false,
+ source: true,
buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist',
'outdent', 'indent', 'image', 'file', 'link', 'alignment', 'horizontalrule'], // + 'underline'
@@ -189,12 +190,17 @@
tabifier: true,
- deniedTags: ['html', 'head', 'link', 'body', 'meta', 'script', 'style', 'applet'],
+ deniedTags: ['script', 'style'],
allowedTags: false, // or array
+ 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'],
+
removeComments: false,
replaceTags: [
- ['strike', 'del']
+ ['strike', 'del'],
+ ['b', 'strong']
],
replaceStyles: [
['font-weight:\\s?bold', "strong"],
@@ -247,7 +253,10 @@
inlineTags: ['strong', 'b', 'u', 'em', 'i', 'code', 'del', 'ins', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small'],
alignmentTags: ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DL', 'DT', 'DD', 'DIV', 'TD', 'BLOCKQUOTE', 'OUTPUT', 'FIGCAPTION', 'ADDRESS', 'SECTION', 'HEADER', 'FOOTER', 'ASIDE', 'ARTICLE'],
blockLevelElements: ['PRE', 'UL', 'OL', 'LI'],
-
+ highContrast: false,
+ observe: {
+ dropdowns: []
+ },
// lang
langs: {
@@ -321,9 +330,21 @@
underline: 'Underline',
alignment: 'Alignment',
filename: 'Name (optional)',
- edit: 'Edit'
+ edit: 'Edit',
+ upload_label: 'Drop file here or '
}
- }
+ },
+
+ linkify: {
+ regexps: {
+ youtube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig,
+ vimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,
+ image: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/ig,
+ url: /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/ig,
+ }
+ },
+
+ codemirror: false
};
// Functionality
@@ -332,6 +353,7 @@
keyCode: {
BACKSPACE: 8,
DELETE: 46,
+ UP: 38,
DOWN: 40,
ENTER: 13,
SPACE: 32,
@@ -341,6 +363,7 @@
META: 91,
SHIFT: 16,
ALT: 18,
+ RIGHT: 39,
LEFT: 37,
LEFT_WIN: 91
},
@@ -368,6 +391,16 @@
// setup allowed and denied tags
this.tidy.setupAllowed();
+ // setup denied tags
+ if (this.opts.deniedTags !== false)
+ {
+ var tags = ['html', 'head', 'link', 'body', 'meta', 'applet'];
+ for (var i = 0; i < tags.length; i++)
+ {
+ this.opts.deniedTags.push(tags[i]);
+ }
+ }
+
// load lang
this.lang.load();
@@ -422,2871 +455,6 @@
this[module][methods[z]] = this[module][methods[z]].bind(this);
}
},
-
- core: function()
- {
- return {
- getObject: function()
- {
- return $.extend({}, this);
- },
- getEditor: function()
- {
- return this.$editor;
- },
- getBox: function()
- {
- return this.$box;
- },
- getElement: function()
- {
- return this.$element;
- },
- getTextarea: function()
- {
- return this.$textarea;
- },
- getToolbar: function()
- {
- return (this.$toolbar) ? this.$toolbar : false;
- },
- addEvent: function(name)
- {
- this.core.event = name;
- },
- getEvent: function()
- {
- return this.core.event;
- },
- setCallback: function(type, e, data)
- {
- var callback = this.opts[type + 'Callback'];
- if ($.isFunction(callback))
- {
- return (typeof data == 'undefined') ? callback.call(this, e) : callback.call(this, e, data);
- }
- else
- {
- return (typeof data == 'undefined') ? e : data;
- }
- },
- destroy: function()
- {
- this.core.setCallback('destroy');
-
- // off events and remove data
- this.$element.off('.redactor').removeData('redactor');
- this.$editor.off('.redactor');
-
- // common
- this.$editor.removeClass('redactor-editor redactor-linebreaks redactor-placeholder');
- this.$editor.removeAttr('contenteditable');
-
- var html = this.code.get();
-
- if (this.build.isTextarea())
- {
- this.$box.after(this.$element);
- this.$box.remove();
- this.$element.val(html).show();
- }
- else
- {
- this.$box.after(this.$editor);
- this.$box.remove();
- this.$element.html(html).show();
- }
-
- // paste box
- if (this.$pasteBox) this.$pasteBox.remove();
-
- // modal
- if (this.$modalBox) this.$modalBox.remove();
- if (this.$modalOverlay) this.$modalOverlay.remove();
-
- // buttons tooltip
- $('.redactor-toolbar-tooltip').remove();
-
- // autosave
- clearInterval(this.autosaveInterval);
-
- }
- };
- },
- build: function()
- {
- return {
- run: function()
- {
-
- this.build.createContainerBox();
- this.build.loadContent();
- this.build.loadEditor();
- this.build.enableEditor();
- this.build.setCodeAndCall();
-
- },
- isTextarea: function()
- {
- return (this.$element[0].tagName === 'TEXTAREA');
- },
- createContainerBox: function()
- {
- this.$box = $('
');
- },
- createTextarea: function()
- {
- this.$textarea = $('').attr('name', this.build.getTextareaName());
- },
- getTextareaName: function()
- {
- var name = this.$element.attr('id');
- if (typeof(name) == 'undefined')
- {
- name = 'content-' + this.uuid;
- }
-
- return name;
- },
- loadContent: function()
- {
- var func = (this.build.isTextarea()) ? 'val' : 'html';
- this.content = $.trim(this.$element[func]());
- },
- enableEditor: function()
- {
- this.$editor.attr({ 'contenteditable': true, 'dir': this.opts.direction });
- },
- loadEditor: function()
- {
- var func = (this.build.isTextarea()) ? 'fromTextarea' : 'fromElement';
- this.build[func]();
- },
- fromTextarea: function()
- {
- this.$editor = $('');
- this.$textarea = this.$element;
- this.$box.insertAfter(this.$element).append(this.$editor).append(this.$element);
- this.$editor.addClass('redactor-editor');
-
- this.$element.hide();
- },
- fromElement: function()
- {
- this.$editor = this.$element;
- this.build.createTextarea();
- this.$box.insertAfter(this.$editor).append(this.$editor).append(this.$textarea);
- this.$editor.addClass('redactor-editor');
-
- this.$textarea.hide();
- },
- setCodeAndCall: function()
- {
- // set code
- this.code.set(this.content);
-
- this.build.setOptions();
- this.build.callEditor();
-
- // code mode
- if (!this.opts.visual)
- {
- setTimeout($.proxy(this.code.showCode, this), 200);
- }
- },
- callEditor: function()
- {
- this.build.disableMozillaEditing();
- this.build.setEvents();
- this.build.setHelpers();
-
- // load toolbar
- if (this.opts.toolbar)
- {
- this.opts.toolbar = this.toolbar.init();
- this.toolbar.build();
- }
-
- // modal templates init
- this.modal.loadTemplates();
-
- // plugins
- this.build.plugins();
-
- // observers
- setTimeout($.proxy(this.observe.load, this), 4);
-
- // init callback
- this.core.setCallback('init');
- },
- setOptions: function()
- {
- // textarea direction
- $(this.$textarea).attr('dir', this.opts.direction);
-
- if (this.opts.linebreaks) this.$editor.addClass('redactor-linebreaks');
-
- if (this.opts.tabindex) this.$editor.attr('tabindex', this.opts.tabindex);
-
- if (this.opts.minHeight) this.$editor.css('minHeight', this.opts.minHeight);
- if (this.opts.maxHeight) this.$editor.css('maxHeight', this.opts.maxHeight);
-
- },
- setEvents: function()
- {
- // drop
- this.$editor.on('drop.redactor', $.proxy(function(e)
- {
- e = e.originalEvent || e;
-
- if (window.FormData === undefined || !e.dataTransfer) return true;
-
- var length = e.dataTransfer.files.length;
- if (length === 0) return true;
- else
- {
- e.preventDefault();
-
- if (this.opts.dragImageUpload || this.opts.dragFileUpload)
- {
- var files = e.dataTransfer.files;
- this.upload.directUpload(files[0], e);
- }
- }
-
- setTimeout($.proxy(this.clean.clearUnverified, this), 1);
-
- this.core.setCallback('drop', e);
-
- }, this));
-
-
- // click
- this.$editor.on('click.redactor', $.proxy(function(e)
- {
- var type = 'click';
- if ((this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow'))
- {
- type = false;
- }
-
- this.core.addEvent(type);
- this.utils.disableSelectAll();
- this.core.setCallback('click', e);
-
- }, this));
-
- // paste
- this.$editor.on('paste.redactor', $.proxy(this.paste.init, this));
-
- // keydown
- this.$editor.on('keydown.redactor', $.proxy(this.keydown.init, this));
-
- // keyup
- this.$editor.on('keyup.redactor', $.proxy(this.keyup.init, this));
-
- // textarea keydown
- if ($.isFunction(this.opts.codeKeydownCallback))
- {
- this.$textarea.on('keydown.redactor-textarea', $.proxy(this.opts.codeKeydownCallback, this));
- }
-
- // textarea keyup
- if ($.isFunction(this.opts.codeKeyupCallback))
- {
- this.$textarea.on('keyup.redactor-textarea', $.proxy(this.opts.codeKeyupCallback, this));
- }
-
- // focus
- if ($.isFunction(this.opts.focusCallback))
- {
- this.$editor.on('focus.redactor', $.proxy(this.opts.focusCallback, this));
- }
-
- var clickedElement;
- $(document).on('mousedown', function(e) {
- clickedElement = $(e.target);
- });
-
- // blur
- this.$editor.on('blur.redactor', $.proxy(function(e)
- {
- if (this.rtePaste) return;
-
- var $el = $(clickedElement);
- if (!$el.hasClass('redactor-toolbar, redactor-dropdown') && !$el.is('#redactor-modal') && $el.parents('.redactor-toolbar, .redactor-dropdown, #redactor-modal').size() === 0)
- {
- this.utils.disableSelectAll();
- if ($.isFunction(this.opts.blurCallback)) this.core.setCallback('blur', e);
- }
- }, this));
- },
- setHelpers: function()
- {
- // autosave
- this.autosave.enable();
-
- // placeholder
- this.placeholder.enable();
-
- // focus
- if (this.opts.focus) setTimeout($.proxy(this.focus.setStart, this), 100);
- if (this.opts.focusEnd) setTimeout($.proxy(this.focus.setEnd, this), 100);
-
- },
- plugins: function()
- {
- if (!this.opts.plugins) return;
- if (!RedactorPlugins) return;
-
- $.each(this.opts.plugins, $.proxy(function(i, s)
- {
- if (RedactorPlugins[s])
- {
- if (!$.isFunction(RedactorPlugins[s])) return;
-
- this[s] = RedactorPlugins[s]();
-
- var methods = this.getModuleMethods(this[s]);
- var len = methods.length;
-
- // bind methods
- for (var z = 0; z < len; z++)
- {
- this[s][methods[z]] = this[s][methods[z]].bind(this);
- }
-
- if ($.isFunction(this[s].init)) this[s].init();
- }
-
- }, this));
-
-
- },
- disableMozillaEditing: function()
- {
- if (!this.utils.browser('mozilla')) return;
-
- // FF fix
- try {
- document.execCommand('enableObjectResizing', false, false);
- document.execCommand('enableInlineTableEditing', false, false);
- } catch (e) {}
- }
- };
- },
- lang: function()
- {
- return {
- load: function()
- {
- this.opts.curLang = this.opts.langs[this.opts.lang];
- },
- get: function(name)
- {
- return (typeof this.opts.curLang[name] != 'undefined') ? this.opts.curLang[name] : '';
- }
- };
- },
- toolbar: function()
- {
- return {
- init: function()
- {
- return {
- html:
- {
- title: this.lang.get('html'),
- func: 'code.toggle'
- },
- formatting:
- {
- title: this.lang.get('formatting'),
- dropdown:
- {
- p:
- {
- title: this.lang.get('paragraph'),
- func: 'block.format'
- },
- blockquote:
- {
- title: this.lang.get('quote'),
- func: 'block.format'
- },
- pre:
- {
- title: this.lang.get('code'),
- func: 'block.format'
- },
- h1:
- {
- title: this.lang.get('header1'),
- func: 'block.format'
- },
- h2:
- {
- title: this.lang.get('header2'),
- func: 'block.format'
- },
- h3:
- {
- title: this.lang.get('header3'),
- func: 'block.format'
- },
- h4:
- {
- title: this.lang.get('header4'),
- func: 'block.format'
- },
- h5:
- {
- title: this.lang.get('header5'),
- func: 'block.format'
- }
- }
- },
- bold:
- {
- title: this.lang.get('bold'),
- func: 'inline.format'
- },
- italic:
- {
- title: this.lang.get('italic'),
- func: 'inline.format'
- },
- deleted:
- {
- title: this.lang.get('deleted'),
- func: 'inline.format'
- },
- underline:
- {
- title: this.lang.get('underline'),
- func: 'inline.format'
- },
- unorderedlist:
- {
- title: '• ' + this.lang.get('unorderedlist'),
- func: 'list.toggle'
- },
- orderedlist:
- {
- title: '1. ' + this.lang.get('orderedlist'),
- func: 'list.toggle'
- },
- outdent:
- {
- title: '< ' + this.lang.get('outdent'),
- func: 'indent.decrease'
- },
- indent:
- {
- title: '> ' + this.lang.get('indent'),
- func: 'indent.increase'
- },
- image:
- {
- title: this.lang.get('image'),
- func: 'image.show'
- },
- file:
- {
- title: this.lang.get('file'),
- func: 'file.show'
- },
- link:
- {
- title: this.lang.get('link'),
- dropdown:
- {
- link:
- {
- title: this.lang.get('link_insert'),
- func: 'link.show'
- },
- unlink:
- {
- title: this.lang.get('unlink'),
- func: 'link.unlink'
- }
- }
- },
- alignment:
- {
- title: this.lang.get('alignment'),
- dropdown:
- {
- left:
- {
- title: this.lang.get('align_left'),
- func: 'alignment.left'
- },
- center:
- {
- title: this.lang.get('align_center'),
- func: 'alignment.center'
- },
- right:
- {
- title: this.lang.get('align_right'),
- func: 'alignment.right'
- },
- justify:
- {
- title: this.lang.get('align_justify'),
- func: 'alignment.justify'
- }
- }
- },
- horizontalrule:
- {
- title: this.lang.get('horizontalrule'),
- func: 'line.insert'
- }
- };
- },
- build: function()
- {
- this.toolbar.hideButtons();
- this.toolbar.hideButtonsOnMobile();
- this.toolbar.isButtonSourceNeeded();
-
- if (this.opts.buttons.length === 0) return;
-
- this.$toolbar = this.toolbar.createContainer();
-
- this.toolbar.setOverflow();
- this.toolbar.append();
- this.toolbar.setFormattingTags();
- this.toolbar.loadButtons();
- this.toolbar.setTabindex();
- this.toolbar.setFixed();
-
- // buttons response
- if (this.opts.activeButtons)
- {
- this.$editor.on('mouseup.redactor keyup.redactor focus.redactor', $.proxy(this.observe.buttons, this));
- }
-
- },
- createContainer: function()
- {
- return $('').addClass('redactor-toolbar').attr('id', 'redactor-toolbar-' + this.uuid);
- },
- setFormattingTags: function()
- {
- $.each(this.opts.toolbar.formatting.dropdown, $.proxy(function (i, s)
- {
- if ($.inArray(i, this.opts.formatting) == -1) delete this.opts.toolbar.formatting.dropdown[i];
- }, this));
-
- },
- loadButtons: function()
- {
- $.each(this.opts.buttons, $.proxy(function(i, btnName)
- {
- if (!this.opts.toolbar[btnName]) return;
-
- if (this.opts.fileUpload === false && btnName === 'file') return true;
- if ((this.opts.imageUpload === false && this.opts.s3 === false) && btnName === 'image') return true;
-
- var btnObject = this.opts.toolbar[btnName];
- this.$toolbar.append($('- ').append(this.button.build(btnName, btnObject)));
-
- }, this));
- },
- append: function()
- {
- if (this.opts.toolbarExternal)
- {
- this.$toolbar.addClass('redactor-toolbar-external');
- $(this.opts.toolbarExternal).html(this.$toolbar);
- }
- else
- {
- this.$box.prepend(this.$toolbar);
- }
- },
- setFixed: function()
- {
- if (this.utils.isMobile()) return;
- if (this.opts.toolbarExternal) return;
- if (!this.opts.toolbarFixed) return;
-
- this.toolbar.observeScroll();
- $(this.opts.toolbarFixedTarget).on('scroll.redactor', $.proxy(this.toolbar.observeScroll, this));
-
- },
- setTabindex: function()
- {
- this.$toolbar.find('a').attr('tabindex', '-1');
- },
- setOverflow: function()
- {
- if (this.utils.isMobile() && this.opts.toolbarOverflow)
- {
- this.$toolbar.addClass('redactor-toolbar-overflow');
- }
- },
- isButtonSourceNeeded: function()
- {
- if (this.opts.buttonSource) return;
-
- var index = this.opts.buttons.indexOf('html');
- if (index !== -1)
- {
- this.opts.buttons.splice(index, 1);
- }
- },
- hideButtons: function()
- {
- if (this.opts.buttonsHide.length === 0) return;
-
- $.each(this.opts.buttonsHide, $.proxy(function(i, s)
- {
- var index = this.opts.buttons.indexOf(s);
- this.opts.buttons.splice(index, 1);
-
- }, this));
- },
- hideButtonsOnMobile: function()
- {
- if (!this.utils.isMobile() && this.opts.buttonsHideOnMobile.length === 0) return;
-
- $.each(this.opts.buttonsHideOnMobile, $.proxy(function(i, s)
- {
- var index = this.opts.buttons.indexOf(s);
- this.opts.buttons.splice(index, 1);
-
- }, this));
- },
- observeScroll: function()
- {
- var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop();
- var boxTop = 1;
-
- if (this.opts.toolbarFixedTarget === document)
- {
- boxTop = this.$box.offset().top;
- }
-
- if (scrollTop > boxTop)
- {
- this.toolbar.observeScrollEnable(scrollTop, boxTop);
- }
- else
- {
- this.toolbar.observeScrollDisable();
- }
- },
- observeScrollEnable: function(scrollTop, boxTop)
- {
- var top = this.opts.toolbarFixedTopOffset + scrollTop - boxTop;
- var left = 0;
- var end = boxTop + this.$box.height() + 30;
- var width = this.$box.innerWidth();
-
- this.$toolbar.addClass('toolbar-fixed-box');
- this.$toolbar.css({
- position: 'absolute',
- width: width,
- top: top + 'px',
- left: left
- });
-
- this.toolbar.setDropdownsFixed();
- this.$toolbar.css('visibility', (scrollTop < end) ? 'visible' : 'hidden');
- },
- observeScrollDisable: function()
- {
- this.$toolbar.css({
- position: 'relative',
- width: 'auto',
- top: 0,
- left: 0,
- visibility: 'visible'
- });
-
- this.toolbar.unsetDropdownsFixed();
- this.$toolbar.removeClass('toolbar-fixed-box');
-
- },
- setDropdownsFixed: function()
- {
- var self = this;
- $('.redactor-dropdown').each(function()
- {
- $(this).css({ position: 'fixed', top: self.$toolbar.innerHeight() + self.opts.toolbarFixedTopOffset });
- });
- },
- unsetDropdownsFixed: function()
- {
- var self = this;
- $('.redactor-dropdown').each(function()
- {
- var top = (self.$toolbar.innerHeight() + self.$toolbar.offset().top) + 'px';
- $(this).css({ position: 'absolute', top: top });
- });
- }
- };
- },
- button: function()
- {
- return {
- build: function(btnName, btnObject)
- {
- var $button = $('');
-
- if (btnObject.func || btnObject.command || btnObject.dropdown)
- {
- $button.on('touchstart click', $.proxy(function(e)
- {
- if ($button.hasClass('redactor-button-disabled')) return false;
-
- var type = 'func';
- var callback = btnObject.func;
- if (btnObject.command)
- {
- type = 'command';
- callback = btnObject.command;
- }
- else if (btnObject.dropdown)
- {
- type = 'dropdown';
- callback = false;
- }
-
- this.button.onClick(e, btnName, type, callback);
-
- }, this));
- }
-
- // dropdown
- if (btnObject.dropdown)
- {
- var $dropdown = $('
');
- $button.data('dropdown', $dropdown);
- this.dropdown.build(btnName, $dropdown, btnObject.dropdown);
- }
-
- // tooltip
- if (this.utils.isDesktop())
- {
- this.button.createTooltip($button, btnName, btnObject.title);
- }
-
- return $button;
- },
- createTooltip: function($button, name, title)
- {
- var $tooltip = $('
').addClass('redactor-toolbar-tooltip redactor-toolbar-tooltip-' + name).hide().html(title);
- $tooltip.appendTo('body');
-
- $button.on('mouseover', function()
- {
- if ($(this).hasClass('redactor-button-disabled')) return;
-
- var pos = $button.offset();
- var height = $button.innerHeight();
- var width = $button.innerWidth();
-
- $tooltip.show();
- $tooltip.css({
- top: (pos.top + height) + 'px',
- left: (pos.left + width/2 - $tooltip.innerWidth()/2) + 'px'
- });
- });
-
- $button.on('mouseout', function()
- {
- $tooltip.hide();
- });
-
- },
- onClick: function(e, btnName, type, callback)
- {
- e.preventDefault();
-
- if (this.utils.browser('msie')) e.returnValue = false;
-
- if (type == 'command')
- {
- this.inline.format(callback);
- }
- else if (type == 'dropdown')
- {
- this.dropdown.show(e, btnName);
- }
- else
- {
- var func;
- if ($.isFunction(callback))
- {
- callback.call(this, btnName);
- this.observe.buttons(e, btnName);
- }
- else if (callback.search(/\./) != '-1')
- {
- func = callback.split('.');
- if (typeof this[func[0]] != 'undefined')
- {
- this[func[0]][func[1]](btnName);
- this.observe.buttons(e, btnName);
- }
- }
- else
- {
- this[callback](btnName);
- this.observe.buttons(e, btnName);
- }
- }
-
- },
- get: function(key)
- {
- return this.$toolbar.find('a.re-' + key);
- },
- setActive: function(key)
- {
- this.button.get(key).addClass('redactor-act');
- },
- setInactive: function(key)
- {
- this.button.get(key).removeClass('redactor-act');
- },
- setInactiveAll: function(key)
- {
- if (typeof key == 'undefined')
- {
- this.$toolbar.find('a.re-icon').removeClass('redactor-act');
- }
- else
- {
- this.$toolbar.find('a.re-icon').not('.re-' + key).removeClass('redactor-act');
- }
- },
- setActiveInVisual: function()
- {
- this.$toolbar.find('a.re-icon').not('a.re-html').removeClass('redactor-button-disabled');
- },
- setInactiveInCode: function()
- {
- this.$toolbar.find('a.re-icon').not('a.re-html').addClass('redactor-button-disabled');
- },
- changeIcon: function(key, classname)
- {
- this.button.get(key).addClass('re-' + classname);
- },
- removeIcon: function(key, classname)
- {
- this.button.get(key).removeClass('re-' + classname);
- },
- setAwesome: function(key, name)
- {
- var $button = this.button.get(key);
- $button.removeClass('redactor-btn-image').addClass('fa-redactor-btn');
- $button.html('');
- },
- addCallback: function($btn, callback)
- {
- var type = (callback == 'dropdown') ? 'dropdown' : 'func';
- var key = $btn.attr('rel');
- $btn.on('touchstart click', $.proxy(function(e)
- {
- if ($btn.hasClass('redactor-button-disabled')) return false;
- this.button.onClick(e, key, type, callback);
-
- }, this));
- },
- addDropdown: function($btn, dropdown)
- {
- var key = $btn.attr('rel');
- this.button.addCallback($btn, 'dropdown');
-
- var $dropdown = $('');
- $btn.data('dropdown', $dropdown);
-
- if (dropdown)
- {
- this.dropdown.build(key, $dropdown, dropdown);
- }
-
- return $dropdown;
- },
- add: function(key, title)
- {
- if (!this.opts.toolbar) return;
-
- var btn = this.button.build(key, { title: title });
- btn.addClass('redactor-btn-image');
-
- this.$toolbar.append($('
- ').append(btn));
-
- return btn;
- },
- addFirst: function(key, title)
- {
- if (!this.opts.toolbar) return;
-
- var btn = this.button.build(key, { title: title });
- this.$toolbar.prepend($('
- ').append(btn));
-
- return btn;
- },
- addAfter: function(afterkey, key, title)
- {
- if (!this.opts.toolbar) return;
-
- var btn = this.button.build(key, { title: title });
- var $btn = this.button.get(afterkey);
-
- if ($btn.size() !== 0) $btn.parent().after($('
- ').append(btn));
- else this.$toolbar.append($('
- ').append(btn));
-
- return btn;
- },
- addBefore: function(beforekey, key, title)
- {
- if (!this.opts.toolbar) return;
-
- var btn = this.button.build(key, { title: title });
- var $btn = this.button.get(beforekey);
-
- if ($btn.size() !== 0) $btn.parent().before($('
- ').append(btn));
- else this.$toolbar.append($('
- ').append(btn));
-
- return btn;
- },
- remove: function(key)
- {
- this.button.get(key).remove();
- }
- };
- },
- dropdown: function()
- {
- return {
- build: function(name, $dropdown, dropdownObject)
- {
- if (name == 'formatting' && this.opts.formattingAdd)
- {
- $.each(this.opts.formattingAdd, $.proxy(function(i,s)
- {
- var name = s.tag;
- if (typeof s.class != 'undefined')
- {
- name = name + '-' + s.class;
- }
-
- s.type = (this.utils.isBlockTag(s.tag)) ? 'block' : 'inline';
- var func = (s.type == 'inline') ? 'inline.formatting' : 'block.formatting';
-
- if (this.opts.linebreaks && s.type == 'block' && s.tag == 'p') return;
-
- this.formatting[name] = {
- tag: s.tag,
- style: s.style,
- 'class': s.class,
- attr: s.attr,
- data: s.data
- };
-
- dropdownObject[name] = {
- func: func,
- title: s.title
- };
-
- }, this));
-
- }
-
- $.each(dropdownObject, $.proxy(function(btnName, btnObject)
- {
- var $item = $('' + btnObject.title + '');
- if (name == 'formatting') $item.addClass('redactor-formatting-' + btnName);
-
- $item.on('click', $.proxy(function(e)
- {
- var type = 'func';
- var callback = btnObject.func;
- if (btnObject.command)
- {
- type = 'command';
- callback = btnObject.command;
- }
- else if (btnObject.dropdown)
- {
- type = 'dropdown';
- callback = btnObject.dropdown;
- }
-
- this.button.onClick(e, btnName, type, callback);
-
- }, this));
-
- $dropdown.append($item);
-
- }, this));
- },
- show: function(e, key)
- {
- if (!this.opts.visual)
- {
- e.preventDefault();
- return false;
- }
-
- var $button = this.button.get(key);
-
- // Always re-append it to the end of so it always has the highest sub-z-index.
- var $dropdown = $button.data('dropdown').appendTo(document.body);
-
- if ($button.hasClass('dropact'))
- {
- this.dropdown.hideAll();
- }
- else
- {
- this.dropdown.hideAll();
- this.core.setCallback('dropdownShow', { dropdown: $dropdown, key: key, button: $button });
-
- this.button.setActive(key);
-
- $button.addClass('dropact');
-
- var keyPosition = $button.offset();
-
- // fix right placement
- var dropdownWidth = $dropdown.width();
- if ((keyPosition.left + dropdownWidth) > $(document).width())
- {
- keyPosition.left -= dropdownWidth;
- }
-
- var left = keyPosition.left + 'px';
- if (this.$toolbar.hasClass('toolbar-fixed-box'))
- {
- $dropdown.css({ position: 'fixed', left: left, top: this.$toolbar.innerHeight() + this.opts.toolbarFixedTopOffset }).show();
- }
- else
- {
- var top = ($button.innerHeight() + keyPosition.top) + 'px';
-
- $dropdown.css({ position: 'absolute', left: left, top: top }).show();
- }
-
-
- this.core.setCallback('dropdownShown', { dropdown: $dropdown, key: key, button: $button });
- }
-
- $(document).one('click', $.proxy(this.dropdown.hide, this));
- this.$editor.one('click', $.proxy(this.dropdown.hide, this));
-
- $dropdown.on('mouseover', function() { $('html').css('overflow', 'hidden'); });
- $dropdown.on('mouseout', function() { $('html').css('overflow', ''); });
-
- e.stopPropagation();
- },
- hideAll: function()
- {
- this.$toolbar.find('a.dropact').removeClass('redactor-act').removeClass('dropact');
-
- $('.redactor-dropdown').hide();
- this.core.setCallback('dropdownHide');
- },
- hide: function (e)
- {
- var $dropdown = $(e.target);
- if (!$dropdown.hasClass('dropact'))
- {
- $dropdown.removeClass('dropact');
- this.dropdown.hideAll();
- }
- }
- };
- },
- code: function()
- {
- return {
- set: function(html)
- {
- html = $.trim(html.toString());
-
- // clean
- html = this.clean.onSet(html);
-
- this.$editor.html(html);
- this.code.sync();
-
- setTimeout($.proxy(this.buffer.add, this), 15);
- if (this.start === false) this.observe.load();
-
- },
- get: function()
- {
- var code = this.$textarea.val();
-
- // indent code
- code = this.tabifier.get(code);
-
- return code;
- },
- sync: function()
- {
- setTimeout($.proxy(this.code.startSync, this), 10);
- },
- startSync: function()
- {
- var html = this.$editor.html();
-
- // is there a need to synchronize
- if (this.code.syncCode && this.code.syncCode == html)
- {
- // do not sync
- return;
- }
-
- // save code
- this.code.syncCode = html;
-
- // before clean callback
- html = this.core.setCallback('syncBefore', html);
-
- // clean
- html = this.clean.onSync(html);
-
- // set code
- this.$textarea.val(html);
-
- // after sync callback
- this.core.setCallback('sync', html);
-
- if (this.start === false)
- {
- this.core.setCallback('change', html);
- }
-
- this.start = false;
-
- // autosave on change
- this.autosave.onChange();
- },
- toggle: function()
- {
- if (this.opts.visual)
- {
- this.code.showCode();
- }
- else
- {
- this.code.showVisual();
- }
- },
- showCode: function()
- {
- this.code.offset = this.caret.getOffset();
- var scroll = $(window).scrollTop();
-
- var height = this.$editor.innerHeight();
-
- this.$editor.hide();
-
- var html = this.$textarea.val();
- this.modified = this.clean.removeSpaces(html);
-
- // indent code
- html = this.tabifier.get(html);
-
- this.$textarea.val(html).height(height).show().focus();
- this.$textarea.on('keydown.redactor-textarea-indenting', this.code.textareaIndenting);
-
- $(window).scrollTop(scroll);
-
- this.opts.visual = false;
-
- this.button.setInactiveInCode();
- this.button.setActive('html');
- this.core.setCallback('source', html);
- },
- showVisual: function()
- {
- if (this.opts.visual) return;
-
- var html = this.$textarea.hide().val();
-
- if (this.modified !== this.clean.removeSpaces(html))
- {
- this.code.set(html);
- }
-
- this.$editor.show();
-
- if (!this.utils.isEmpty(html))
- {
- this.placeholder.remove();
- }
-
- this.caret.setOffset(this.code.offset);
-
- this.$textarea.off('keydown.redactor-textarea-indenting');
-
- this.button.setActiveInVisual();
- this.button.setInactive('html');
-
- this.observe.load();
- this.opts.visual = true;
- },
- textareaIndenting: function(e)
- {
- if (e.keyCode !== 9) return true;
-
- var $el = this.$textarea;
- var start = $el.get(0).selectionStart;
- $el.val($el.val().substring(0, start) + "\t" + $el.val().substring($el.get(0).selectionEnd));
- $el.get(0).selectionStart = $el.get(0).selectionEnd = start + 1;
-
- return false;
- }
- };
- },
- clean: function()
- {
- return {
- onSet: function(html)
- {
- html = this.clean.savePreCode(html);
-
- // replace dollar sign to entity
- html = html.replace(/\$/g, '$');
- html = html.replace(/”/g, '"');
- html = html.replace(/‘/g, '\'');
- html = html.replace(/’/g, '\'');
-
- if (this.opts.replaceDivs) html = this.clean.replaceDivs(html);
- if (this.opts.linebreaks) html = this.clean.replaceParagraphsToBr(html);
-
- // save form tag
- html = this.clean.saveFormTags(html);
-
- // convert font tag to span
- html = html.replace(/([\w\W]*?)<\/font>/gi, '$4');
-
- // remove font tag
- html = html.replace(//gi, '');
- html = html.replace(/<\/font>/gi, '');
-
- // tidy html
- html = this.tidy.load(html);
-
- // paragraphize
- if (this.opts.paragraphize) html = this.paragraphize.load(html);
-
- // verified
- html = this.clean.setVerified(html);
-
- // convert inline tags
- html = this.clean.convertInline(html);
-
- return html;
- },
- onSync: function(html)
- {
- // remove spaces
- html = html.replace(/[\u200B-\u200D\uFEFF]/g, '');
- html = html.replace(//gi, '');
- html = html.replace(/ /gi, ' ');
-
- if (html.search(/^
(||\s|| )<\/p>$/i) != -1)
- {
- return '';
- }
-
- // restore form tag
- html = this.clean.restoreFormTags(html);
-
- var chars = {
- '\u2122': '™',
- '\u00a9': '©',
- '\u2026': '…',
- '\u2014': '—',
- '\u2010': '‐'
- };
- // replace special characters
- $.each(chars, function(i,s)
- {
- html = html.replace(new RegExp(i, 'g'), s);
- });
-
- // remove br in the of li
- html = html.replace(new RegExp('
', 'gi'), '');
- html = html.replace(new RegExp('
', 'gi'), '');
-
- // remove verified
- html = html.replace(new RegExp('
])>', 'gi'), '
');
- html = html.replace(new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', 'gi'), '<$1$2>');
- html = html.replace(new RegExp('
])>', 'gi'), '');
- html = html.replace(new RegExp('
])>', 'gi'), '
');
- html = html.replace(new RegExp('(.*?)', 'gi'), '$1');
- html = html.replace(/ data-save-url="(.*?[^>])"/gi, '');
-
- // remove image resize
- html = html.replace(/])>([\w\W]*?)
<\/span>/gi, '$3
');
- html = html.replace(/])>(.*?)<\/span>/gi, '');
- html = html.replace(/])>(.*?)<\/span>/gi, '');
-
- // tidy html
- html = this.tidy.load(html);
-
- // link nofollow
- if (this.opts.linkNofollow)
- {
- html = html.replace(/])>/gi, '');
- html = html.replace(/])>/gi, '');
- }
-
- // reconvert inline
- html = html.replace(/<(.*?) data-redactor-tag="(.*?)"(.*?[^>])>/gi, '<$1$3>');
- html = html.replace(/<(.*?) data-redactor-class="(.*?)"(.*?[^>])>/gi, '<$1$3>');
- html = html.replace(/<(.*?) data-redactor-style="(.*?)"(.*?[^>])>/gi, '<$1$3>');
- html = html.replace(new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', 'gi'), '<$1$2>');
- html = html.replace(new RegExp('<(.*?) data-verified="redactor">', 'gi'), '<$1>');
-
- return html;
- },
- onPaste: function(html, setMode)
- {
- html = $.trim(html);
-
- html = html.replace(/\$/g, '$');
- html = html.replace(/”/g, '"');
- html = html.replace(/“/g, '"');
- html = html.replace(/‘/g, '\'');
- html = html.replace(/’/g, '\'');
-
- // convert dirty spaces
- html = html.replace(/ <\/span>/gi, ' ');
- html = html.replace(/]*>\t<\/span>/gi, '\t');
- html = html.replace(/]*>(\s| )<\/span>/gi, ' ');
-
- if (this.opts.pastePlainText)
- {
- return this.clean.getPlainText(html);
- }
-
- if (!this.utils.isSelectAll() && typeof setMode == 'undefined')
- {
- if (this.utils.isCurrentOrParent(['FIGCAPTION', 'A']))
- {
- return this.clean.getPlainText(html, false);
- }
-
- if (this.utils.isCurrentOrParent('PRE'))
- {
- return this.clean.getPreCode(html);
- }
-
- if (this.utils.isCurrentOrParent(['BLOCKQUOTE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6']))
- {
- html = this.clean.getOnlyImages(html);
-
- if (!this.utils.browser('msie'))
- {
- var block = this.selection.getBlock();
- if (block && block.tagName == 'P')
- {
- html = html.replace(/
/gi, '![]()
');
- }
- }
-
- return html;
- }
-
- if (this.utils.isCurrentOrParent(['TD']))
- {
- html = this.clean.onPasteTidy(html, 'td');
-
- if (this.opts.linebreaks) html = this.clean.replaceParagraphsToBr(html);
-
- html = this.clean.replaceDivsToBr(html);
-
- return html;
- }
-
-
- if (this.utils.isCurrentOrParent(['LI']))
- {
- return this.clean.onPasteTidy(html, 'li');
- }
- }
-
-
- html = this.clean.isSingleLine(html, setMode);
-
- if (!this.clean.singleLine)
- {
- if (this.opts.linebreaks) html = this.clean.replaceParagraphsToBr(html);
- if (this.opts.replaceDivs) html = this.clean.replaceDivs(html);
-
- html = this.clean.saveFormTags(html);
- }
-
- html = this.clean.onPasteIeFixLinks(html);
- html = this.clean.onPasteWord(html);
- html = this.clean.onPasteExtra(html);
-
- html = this.clean.onPasteTidy(html, 'all');
-
- // paragraphize
- if (!this.clean.singleLine && this.opts.paragraphize)
- {
- html = this.paragraphize.load(html);
- }
-
- html = this.clean.removeDirtyStyles(html);
- html = this.clean.onPasteRemoveSpans(html);
- html = this.clean.onPasteRemoveEmpty(html);
-
- html = this.clean.convertInline(html);
-
- return html;
- },
- onPasteWord: function(html)
- {
- // comments
- html = html.replace(//gi, '');
-
- // style
- html = html.replace(/