From 061f5fdb6c9507a38345d7096ea3d01c3223c949 Mon Sep 17 00:00:00 2001 From: Adam Pope Date: Wed, 20 May 2015 10:09:49 +0100 Subject: [PATCH 01/13] Upgrade to 10.1.1 --- .../javascripts/redactor-rails/redactor.js | 1813 ++++++++++++----- .../redactor-rails/redactor.min.js | 8 +- .../redactor-rails/css/redactor.css | 46 +- 3 files changed, 1295 insertions(+), 572 deletions(-) mode change 100644 => 100755 vendor/assets/javascripts/redactor-rails/redactor.js mode change 100644 => 100755 vendor/assets/stylesheets/redactor-rails/css/redactor.css diff --git a/vendor/assets/javascripts/redactor-rails/redactor.js b/vendor/assets/javascripts/redactor-rails/redactor.js old mode 100644 new mode 100755 index ca1d943f..80dc3d9a --- a/vendor/assets/javascripts/redactor-rails/redactor.js +++ b/vendor/assets/javascripts/redactor-rails/redactor.js @@ -1,10 +1,10 @@ /* - Redactor v10.0.4 - Updated: November 10, 2014 + Redactor v10.1.1 + Updated: April 28, 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(); @@ -28,9 +28,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,13 +91,13 @@ // Functionality $.Redactor = Redactor; - $.Redactor.VERSION = '10.0.4'; + $.Redactor.VERSION = '10.1.1'; $.Redactor.modules = ['alignment', 'autosave', 'block', 'buffer', 'build', 'button', 'caret', 'clean', 'code', 'core', 'dropdown', 'file', 'focus', 'image', 'indent', 'inline', 'insert', 'keydown', 'keyup', 'lang', 'line', 'link', 'list', 'modal', 'observe', 'paragraphize', 'paste', 'placeholder', 'progress', 'selection', 'shortcuts', - 'tabifier', 'tidy', 'toolbar', 'upload', 'utils']; + 'tabifier', 'tidy', 'toolbar', 'upload', 'utils', 'linkify']; $.Redactor.opts = { @@ -135,6 +132,7 @@ autosaveName: false, autosaveInterval: 60, // seconds autosaveOnChange: false, + autosaveFields: false, linkTooltip: true, linkProtocol: 'http', @@ -147,14 +145,14 @@ imageFloatMargin: '10px', imageResizable: true, - imageUpload: false, + imageUpload: null, imageUploadParam: 'file', uploadImageField: false, dragImageUpload: true, - fileUpload: false, + fileUpload: null, fileUploadParam: 'file', dragFileUpload: true, @@ -168,7 +166,7 @@ preSpaces: 4, // or false tabAsSpaces: false, // true or number of spaces - tabFocus: true, + tabKey: true, scrollTarget: false, @@ -179,7 +177,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' @@ -191,9 +189,13 @@ 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'] @@ -323,9 +325,22 @@ 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 @@ -343,6 +358,7 @@ META: 91, SHIFT: 16, ALT: 18, + RIGHT: 39, LEFT: 37, LEFT_WIN: 91 }, @@ -370,6 +386,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(); @@ -446,92 +472,130 @@ }, set: function(type) { + // focus if (!this.utils.browser('msie')) this.$editor.focus(); this.buffer.set(); this.selection.save(); + // get blocks this.alignment.blocks = this.selection.getBlocks(); - if (this.opts.linebreaks && this.alignment.blocks[0] === false) + this.alignment.type = type; + + // set alignment + if (this.alignment.isLinebreaksOrNoBlocks()) { - this.alignment.setText(type); + this.alignment.setText(); } else { - this.alignment.setBlocks(type); + this.alignment.setBlocks(); } + // sync this.selection.restore(); this.code.sync(); }, - setText: function(type) + setText: function() { var wrapper = this.selection.wrap('div'); - $(wrapper).attr('data-tagblock', 'redactor'); - $(wrapper).css('text-align', type); + $(wrapper).attr('data-tagblock', 'redactor').css('text-align', this.alignment.type); }, - setBlocks: function(type) + setBlocks: function() { $.each(this.alignment.blocks, $.proxy(function(i, el) { var $el = this.utils.getAlignmentElement(el); - if (!$el) return; - if (type === '' && typeof($el.data('tagblock')) !== 'undefined') + if (this.alignment.isNeedReplaceElement($el)) { - $el.replaceWith($el.html()); + this.alignment.replaceElement($el); } else { - $el.css('text-align', type); - this.utils.removeEmptyAttr($el, 'style'); + this.alignment.alignElement($el); } - }, this)); + }, + isLinebreaksOrNoBlocks: function() + { + return (this.opts.linebreaks && this.alignment.blocks[0] === false); + }, + isNeedReplaceElement: function($el) + { + return (this.alignment.type === '' && typeof($el.data('tagblock')) !== 'undefined'); + }, + replaceElement: function($el) + { + $el.replaceWith($el.html()); + }, + alignElement: function($el) + { + $el.css('text-align', this.alignment.type); + this.utils.removeEmptyAttr($el, 'style'); } }; }, autosave: function() { return { + html: false, enable: function() { if (!this.opts.autosave) return; - this.autosave.html = false; this.autosave.name = (this.opts.autosaveName) ? this.opts.autosaveName : this.$textarea.attr('name'); - if (!this.opts.autosaveOnChange) - { - this.autosaveInterval = setInterval($.proxy(this.autosave.load, this), this.opts.autosaveInterval * 1000); - } + if (this.opts.autosaveOnChange) return; + this.autosaveInterval = setInterval(this.autosave.load, this.opts.autosaveInterval * 1000); }, onChange: function() { if (!this.opts.autosaveOnChange) return; - this.autosave.load(); }, load: function() { - var html = this.code.get(); - if (this.autosave.html === html) return; - if (this.utils.isEmpty(html)) return; + this.autosave.source = this.code.get(); - $.ajax({ + if (this.autosave.html === this.autosave.source) return; + //if (this.utils.isEmpty(this.autosave.source)) return; + + // data + var data = {}; + data['name'] = this.autosave.name; + data[this.autosave.name] = this.autosave.source; + data = this.autosave.getHiddenFields(data); + + // ajax + var jsxhr = $.ajax({ url: this.opts.autosave, type: 'post', - data: 'name=' + this.autosave.name + '&' + this.autosave.name + '=' + escape(encodeURIComponent(html)), - success: $.proxy(function(data) - { - this.autosave.success(data, html); - - }, this) + data: data }); + + jsxhr.done(this.autosave.success); + }, + getHiddenFields: function(data) + { + if (this.opts.autosaveFields === false || typeof this.opts.autosaveFields !== 'object') + { + return data; + } + + $.each(this.opts.autosaveFields, $.proxy(function(k, v) + { + if (v !== null && v.toString().indexOf('#') === 0) v = $(v).val(); + data[k] = v; + + }, this)); + + return data; + }, - success: function(data, html) + success: function(data) { var json; try @@ -547,7 +611,7 @@ var callbackName = (typeof json.error == 'undefined') ? 'autosave' : 'autosaveError'; this.core.setCallback(callbackName, this.autosave.name, json); - this.autosave.html = html; + this.autosave.html = this.autosave.source; }, disable: function() { @@ -560,11 +624,17 @@ return { formatting: function(name) { + this.block.clearStyle = false; var type, value; if (typeof this.formatting[name].data != 'undefined') type = 'data'; else if (typeof this.formatting[name].attr != 'undefined') type = 'attr'; - else if (typeof this.formatting[name].class != 'undefined') type = 'class'; + else if (typeof this.formatting[name]['class'] != 'undefined') type = 'class'; + + if (typeof this.formatting[name].clear != 'undefined') + { + this.block.clearStyle = true; + } if (type) value = this.formatting[name][type]; @@ -674,6 +744,11 @@ this.block.toggle($(block)); } + if (typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined') + { + $(block).removeAttr('class').removeAttr('style'); + } + }, setMultiple: function(tag) { @@ -734,6 +809,7 @@ } else { + if (this.opts.linebreaks || tag != 'p') { if (tag == 'blockquote') @@ -749,14 +825,20 @@ { $.each(this.block.blocks, $.proxy(function(i,s) { + var $formatted = false; if (this.opts.linebreaks) { $(s).prepend('
').append('
'); - this.utils.replaceWithContents(s); + $formatted = this.utils.replaceWithContents(s); } else { - this.utils.replaceToTag(s, 'p'); + $formatted = this.utils.replaceToTag(s, 'p'); + } + + if ($formatted && typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined') + { + $formatted.removeAttr('class').removeAttr('style'); } }, this)); @@ -766,6 +848,7 @@ } + this.block.formatWrap(tag); } else @@ -775,7 +858,7 @@ if (this.block.type == 'class') { toggleType = 'toggle'; - classSize = $(this.block.blocks).filter('.' + this.block.value).size(); + classSize = $(this.block.blocks).filter('.' + this.block.value).length; if (this.block.blocksSize == classSize) toggleType = 'toggle'; else if (this.block.blocksSize > classSize) toggleType = 'set'; @@ -794,7 +877,7 @@ { if (toggleType == 'toggle') this.block.toggle($formatted); else if (toggleType == 'remove') this.block.remove($formatted); - else if (toggleType == 'set') this.block.set2($formatted); + else if (toggleType == 'set') this.block.setForce($formatted); } else this.block.toggle($formatted); @@ -802,13 +885,43 @@ if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted); if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap(); + if (typeof this.block.type == 'undefined' && typeof this.block.value == 'undefined') + { + $formatted.removeAttr('class').removeAttr('style'); + } + }, this)); } } }, + setForce: function($el) + { + // remove style and class if the specified setting + if (this.block.clearStyle) + { + $el.removeAttr('class').removeAttr('style'); + } + + if (this.block.type == 'class') + { + $el.addClass(this.block.value); + return; + } + else if (this.block.type == 'attr' || this.block.type == 'data') + { + $el.attr(this.block.value.name, this.block.value.value); + return; + } + }, toggle: function($el) { + // remove style and class if the specified setting + if (this.block.clearStyle) + { + $el.removeAttr('class').removeAttr('style'); + } + if (this.block.type == 'class') { $el.toggleClass(this.block.value); @@ -839,7 +952,7 @@ }, formatListToBlockquote: function() { - var block = $(this.block.blocks[0]).closest('ul, ol'); + var block = $(this.block.blocks[0]).closest('ul, ol', this.$editor[0]); $(block).find('ul, ol').contents().unwrap(); $(block).find('li').append($('
')).contents().unwrap(); @@ -932,10 +1045,10 @@ }, formatTableWrapping: function($formatted) { - if ($formatted.closest('table').size() === 0) return; + if ($formatted.closest('table', this.$editor[0]).length === 0) return; - if ($formatted.closest('tr').size() === 0) $formatted.wrap(''); - if ($formatted.closest('td').size() === 0 && $formatted.closest('th').size() === 0) + if ($formatted.closest('tr', this.$editor[0]).length === 0) $formatted.wrap(''); + if ($formatted.closest('td', this.$editor[0]).length === 0 && $formatted.closest('th').length === 0) { $formatted.wrap(''); } @@ -1090,13 +1203,11 @@ return { run: function() { - this.build.createContainerBox(); this.build.loadContent(); this.build.loadEditor(); this.build.enableEditor(); this.build.setCodeAndCall(); - }, isTextarea: function() { @@ -1112,13 +1223,7 @@ }, getTextareaName: function() { - var name = this.$element.attr('id'); - if (typeof(name) == 'undefined') - { - name = 'content-' + this.uuid; - } - - return name; + return ((typeof(name) == 'undefined')) ? 'content-' + this.uuid : this.$element.attr('id'); }, loadContent: function() { @@ -1161,10 +1266,8 @@ this.build.callEditor(); // code mode - if (!this.opts.visual) - { - setTimeout($.proxy(this.code.showCode, this), 200); - } + if (this.opts.visual) return; + setTimeout($.proxy(this.code.showCode, this), 200); }, callEditor: function() { @@ -1204,6 +1307,21 @@ if (this.opts.maxHeight) this.$editor.css('maxHeight', this.opts.maxHeight); }, + setEventDropUpload: function(e) + { + e.preventDefault(); + + if (!this.opts.dragImageUpload || !this.opts.dragFileUpload) return; + + var files = e.dataTransfer.files; + this.upload.directUpload(files[0], e); + }, + setEventDrop: function(e) + { + this.code.sync(); + setTimeout(this.clean.clearUnverified, 1); + this.core.setCallback('drop', e); + }, setEvents: function() { // drop @@ -1213,28 +1331,16 @@ if (window.FormData === undefined || !e.dataTransfer) return true; - var length = e.dataTransfer.files.length; - if (length === 0) + if (e.dataTransfer.files.length === 0) { - this.code.sync(); - setTimeout($.proxy(this.clean.clearUnverified, this), 1); - this.core.setCallback('drop', e); - - return true; + return this.build.setEventDrop(e); } else { - e.preventDefault(); - - if (this.opts.dragImageUpload || this.opts.dragFileUpload) - { - var files = e.dataTransfer.files; - this.upload.directUpload(files[0], e); - } + this.build.setEventDropUpload(e); } - setTimeout($.proxy(this.clean.clearUnverified, this), 1); - + setTimeout(this.clean.clearUnverified, 1); this.core.setCallback('drop', e); }, this)); @@ -1243,11 +1349,8 @@ // click this.$editor.on('click.redactor', $.proxy(function(e) { - var type = 'click'; - if ((this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow')) - { - type = false; - } + var event = this.core.getEvent(); + var type = (event == 'click' || event == 'arrow') ? false : 'click'; this.core.addEvent(type); this.utils.disableSelectAll(); @@ -1258,6 +1361,9 @@ // paste this.$editor.on('paste.redactor', $.proxy(this.paste.init, this)); + // cut + this.$editor.on('cut.redactor', $.proxy(this.code.sync, this)); + // keydown this.$editor.on('keydown.redactor', $.proxy(this.keydown.init, this)); @@ -1283,34 +1389,39 @@ } var clickedElement; - $(document).on('mousedown', function(e) { - clickedElement = $(e.target); - }); + $(document).on('mousedown', function(e) { clickedElement = e.target; }); // blur this.$editor.on('blur.redactor', $.proxy(function(e) { if (this.rtePaste) return; + if (!this.build.isBlured(clickedElement)) return; + + this.utils.disableSelectAll(); + if ($.isFunction(this.opts.blurCallback)) this.core.setCallback('blur', e); - 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)); }, + isBlured: function(clickedElement) + { + var $el = $(clickedElement); + + return (!$el.hasClass('redactor-toolbar, redactor-dropdown') && !$el.is('#redactor-modal') && $el.parents('.redactor-toolbar, .redactor-dropdown, #redactor-modal').length === 0); + }, setHelpers: function() { - // autosave - this.autosave.enable(); + // linkify + if (this.linkify.isEnabled()) + { + this.linkify.format(); + } // 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); + if (this.opts.focus) setTimeout(this.focus.setStart, 100); + if (this.opts.focusEnd) setTimeout(this.focus.setEnd, 100); }, plugins: function() @@ -1332,6 +1443,7 @@ this[s] = RedactorPlugins[s](); + // get methods var methods = this.getModuleMethods(this[s]); var len = methods.length; @@ -1346,7 +1458,6 @@ }, this)); - }, disableMozillaEditing: function() { @@ -1367,34 +1478,16 @@ { var $button = $('').attr('tabindex', '-1'); + // click 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)); + this.button.setEvent($button, btnName, btnObject); } // dropdown if (btnObject.dropdown) { - var $dropdown = $('