diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor-iframe.css b/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor-iframe.css deleted file mode 100644 index 1ce460939..000000000 --- a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor-iframe.css +++ /dev/null @@ -1,203 +0,0 @@ -html { - margin: 0; - padding: 0; -} -body { - margin: 0; - padding: 10px; - font-family: Arial, Helvetica, Verdana, Tahoma, sans-serif; -} - -code, -pre { - font-family: Menlo, Monaco, monospace, sans-serif; -} - -div, -p, -ul, -ol, -table, -dl, -blockquote, -pre { - font-size: 15px; - line-height: 1.5rem; -} -div { - border: 1px dashed #bbb !important; -} -a { - color: #15c; - text-decoration: underline; -} -.redactor_placeholder { - color: #999 !important; - display: block !important; - margin-bottom: 10px !important; -} - -object, -embed, -video, -img { - max-width: 100%; - width: auto; -} -video, -img { - height: auto; -} - -div, -p, -ul, -ol, -table, -dl, -blockquote, -pre { - margin: 0; - margin-bottom: 15px; - border: none; - background: none; - box-shadow: none; -} -iframe, -object, -hr { - margin-bottom: 15px; -} -blockquote { - margin-left: 1.5em !important; - padding-left: 0; - color: #777; - font-style: italic; -} -ul, -ol { - padding-left: 2em; -} -ul ul, -ol ol, -ul ol, -ol ul { - margin: 2px; - padding: 0; - padding-left: 2em; - border: none; -} -dl dt { font-weight: bold; } -dd { margin-left: 1em;} - -table { - border-collapse: collapse; - font-size: 1em; -} -table td { - padding: 5px; - border: 1px solid #ddd; - vertical-align: top; -} -table thead td { - border-bottom: 2px solid #000; - font-weight: bold; -} -code { - background-color: #d8d7d7; -} -pre { - overflow: auto; - padding: 1em; - border: 1px solid #ddd; - border-radius: 3px; - background: #f8f8f8; - white-space: pre; - font-size: 90%; -} -hr { - display: block; - height: 1px; - border: 0; - border-top: 1px solid #ccc; -} - -h1, -h2, -h3, -h4, -h5 { - margin: 0; - padding: 0; - background: none; - color: #000; - font-weight: bold; -} - -h1 { - margin-bottom: 10px; - font-size: 36px; - line-height: 40px; -} -h2 { - margin-bottom: 15px; - font-size: 30px; - line-height: 38px; -} -h3 { - margin-bottom: 10px; - font-size: 24px; - line-height: 30px; -} -h4 { - margin-bottom: 10px; - font-size: 18px; - line-height: 24px; -} -h5 { - margin-bottom: 10px; - font-size: 1em; -} - -body.redactor_editor_wym { - background: #f4f4f4; -} -.redactor_editor_wym div, -.redactor_editor_wym p, -.redactor_editor_wym ul, -.redactor_editor_wym ol, -.redactor_editor_wym table, -.redactor_editor_wym dl, -.redactor_editor_wym pre, -.redactor_editor_wym h1, -.redactor_editor_wym h2, -.redactor_editor_wym h3, -.redactor_editor_wym h4, -.redactor_editor_wym h5, -.redactor_editor_wym blockquote { - margin: 0 0 10px 0; - padding: 7px 10px; - border: 1px solid #e4e4e4; - background-color: #fff; -} -.redactor_editor_wym div { - border: 1px dashed #bbb !important; -} -.redactor_editor_wym pre { - border: 2px dashed #e4e4e4 !important; - background-color: #fafafa !important; -} -.redactor_editor_wym code { - background-color: #f4f4f4 !important; -} -.redactor_editor_wym ul, -.redactor_editor_wym ol { - padding-left: 2em !important; -} -.redactor_editor_wym ul li ul, -.redactor_editor_wym ul li ol, -.redactor_editor_wym ol li ol, -.redactor_editor_wym ol li ul { - border: none !important; -} - diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.css b/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.css index cd8dfbf1a..57aa6e29d 100644 --- a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.css +++ b/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.css @@ -17,21 +17,14 @@ .redactor-box { position: relative; overflow: visible; - background: #fff; margin-bottom: 24px; } -.redactor-box iframe, .redactor-box textarea { display: block; position: relative; margin: 0; padding: 0; width: 100%; -} -.redactor-box iframe { - border: 1px solid #eee; -} -.redactor-box textarea { overflow: auto; outline: none; border: none; @@ -49,21 +42,25 @@ Z-index setup */ .redactor-editor, +.redactor-box { + background: #fff; +} +.redactor-editor, .redactor-box, .redactor-box textarea { z-index: auto !important; } .redactor-box-fullscreen { - z-index: 99 !important; + z-index: 1052 !important; } .redactor-toolbar, .redactor-dropdown { - z-index: 1050 !important; + z-index: 1053 !important; } #redactor-modal-overlay, #redactor-modal-box, #redactor-modal { - z-index: 1051 !important; + z-index: 1054 !important; } /* Resize @@ -90,6 +87,12 @@ body .redactor-box-fullscreen { left: 0; width: 100%; } +/* + Utils +*/ +.body-redactor-hidden { + overflow: hidden; +} /* Editor */ @@ -124,8 +127,8 @@ body .redactor-box-fullscreen { } /* Placeholder in linebreaks mode */ .redactor-linebreaks.redactor-placeholder:after { - top: 10px; - left: 10px; + top: 20px; + left: 20px; } /* Toolbar @@ -339,7 +342,7 @@ body .redactor-box-fullscreen { */ .redactor-toolbar-tooltip { position: absolute; - z-index: 100; + z-index: 1054; text-align: center; top: 0; left: 0; @@ -383,6 +386,42 @@ body .redactor-box-fullscreen { color: #fff !important; text-decoration: none; } +/* + IMAGE BOX +*/ +#redactor-image-box { + position: relative; + max-width: 100%; + display: inline-block; + line-height: 0; + outline: 1px dashed rgba(0, 0, 0, 0.6); +} +#redactor-image-editter { + position: absolute; + z-index: 5; + top: 50%; + left: 50%; + margin-top: -11px; + margin-left: -18px; + line-height: 1; + background-color: #000; + color: #fff; + font-size: 11px; + padding: 7px 10px; + cursor: pointer; +} +#redactor-image-resizer { + position: absolute; + z-index: 2; + line-height: 1; + cursor: nw-resize; + bottom: -4px; + right: -5px; + border: 1px solid #fff; + background-color: #000; + width: 8px; + height: 8px; +} /* LINK TOOLTIP */ @@ -782,9 +821,6 @@ body .redactor-box-fullscreen { .redactor-editor hr { margin-bottom: 15px; } -.redactor-editor iframe { - width: auto; -} .redactor-editor blockquote { margin-left: 1.6em !important; padding-left: 0; @@ -851,7 +887,7 @@ body .redactor-box-fullscreen { .redactor-editor h5, .redactor-editor h6 { font-weight: bold; - color: #0000; + color: #000; padding: 0; background: none; text-rendering: optimizeLegibility; diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.js b/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.js index 869ee18d7..23baa5c45 100644 --- a/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.js +++ b/modules/backend/formwidgets/richeditor/assets/vendor/redactor/redactor.js @@ -1,10 +1,10 @@ /* - Redactor v10.0 - Updated: September 24, 2014 + Redactor v10.0.7 + Updated: January 31, 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(); @@ -94,11 +94,13 @@ // Functionality $.Redactor = Redactor; - $.Redactor.VERSION = '10.0'; - $.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.0.7'; + $.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']; $.Redactor.opts = { @@ -145,15 +147,14 @@ imageFloatMargin: '10px', imageResizable: true, - imageUpload: false, + imageUpload: null, imageUploadParam: 'file', uploadImageField: false, dragImageUpload: true, - clipboardImageUpload: false, - fileUpload: false, + fileUpload: null, fileUploadParam: 'file', dragFileUpload: true, @@ -167,7 +168,7 @@ preSpaces: 4, // or false tabAsSpaces: false, // true or number of spaces - tabFocus: true, + tabKey: true, scrollTarget: false, @@ -178,7 +179,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' @@ -342,6 +343,7 @@ META: 91, SHIFT: 16, ALT: 18, + RIGHT: 39, LEFT: 37, LEFT_WIN: 91 }, @@ -424,93 +426,716 @@ } }, - core: function() + alignment: function() { return { - getObject: function() + left: function() { - return $.extend({}, this); + this.alignment.set(''); }, - getEditor: function() + right: function() { - return this.$editor; + this.alignment.set('right'); }, - getBox: function() + center: function() { - return this.$box; + this.alignment.set('center'); }, - getElement: function() + justify: function() { - return this.$element; + this.alignment.set('justify'); }, - getTextarea: function() + set: function(type) { - 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)) + // focus + if (!this.utils.browser('msie')) this.$editor.focus(); + + this.buffer.set(); + this.selection.save(); + + // get blocks + this.alignment.blocks = this.selection.getBlocks(); + this.alignment.type = type; + + // set alignment + if (this.alignment.isLinebreaksOrNoBlocks()) { - return (typeof data == 'undefined') ? callback.call(this, e) : callback.call(this, e, data); + this.alignment.setText(); } else { - return (typeof data == 'undefined') ? e : data; + this.alignment.setBlocks(); } + + // sync + this.selection.restore(); + this.code.sync(); }, - destroy: function() + setText: 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()) + var wrapper = this.selection.wrap('div'); + $(wrapper).attr('data-tagblock', 'redactor').css('text-align', this.alignment.type); + }, + setBlocks: function() + { + $.each(this.alignment.blocks, $.proxy(function(i, el) { - this.$box.after(this.$element); - this.$box.remove(); - this.$element.val(html).show(); + var $el = this.utils.getAlignmentElement(el); + if (!$el) return; + + if (this.alignment.isNeedReplaceElement($el)) + { + this.alignment.replaceElement($el); + } + else + { + 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 { + 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) return; + this.autosaveInterval = setInterval(this.autosave.load, this.opts.autosaveInterval * 1000); + }, + onChange: function() + { + if (!this.opts.autosaveOnChange) return; + this.autosave.load(); + }, + load: function() + { + this.autosave.source = this.code.get(); + + 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] = escape(encodeURIComponent(this.autosave.source)); + + // ajax + var jsxhr = $.ajax({ + url: this.opts.autosave, + type: 'post', + data: data + }); + + jsxhr.done(this.autosave.success); + }, + success: function(data) + { + var json; + try + { + json = $.parseJSON(data); } - else + catch(e) { - this.$box.after(this.$editor); - this.$box.remove(); - this.$element.html(html).show(); + //data has already been parsed + json = data; } - // paste box - if (this.$pasteBox) this.$pasteBox.remove(); + var callbackName = (typeof json.error == 'undefined') ? 'autosave' : 'autosaveError'; - // modal - if (this.$modalBox) this.$modalBox.remove(); - if (this.$modalOverlay) this.$modalOverlay.remove(); - - // buttons tooltip - $('.redactor-toolbar-tooltip').remove(); - - // autosave + this.core.setCallback(callbackName, this.autosave.name, json); + this.autosave.html = this.autosave.source; + }, + disable: function() + { clearInterval(this.autosaveInterval); + } + }; + }, + block: function() + { + 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'; + + if (typeof this.formatting[name].clear != 'undefined') + { + this.block.clearStyle = true; + } + + if (type) value = this.formatting[name][type]; + + this.block.format(this.formatting[name].tag, type, value); + + }, + format: function(tag, type, value) + { + if (tag == 'quote') tag = 'blockquote'; + + var formatTags = ['p', 'pre', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']; + if ($.inArray(tag, formatTags) == -1) return; + + this.block.isRemoveInline = (tag == 'pre' || tag.search(/h[1-6]/i) != -1); + + // focus + if (!this.utils.browser('msie')) this.$editor.focus(); + + this.block.blocks = this.selection.getBlocks(); + + this.block.blocksSize = this.block.blocks.length; + this.block.type = type; + this.block.value = value; + + this.buffer.set(); + this.selection.save(); + + this.block.set(tag); + + this.selection.restore(); + this.code.sync(); + + }, + set: function(tag) + { + this.selection.get(); + this.block.containerTag = this.range.commonAncestorContainer.tagName; + + if (this.range.collapsed) + { + this.block.setCollapsed(tag); + } + else + { + this.block.setMultiple(tag); + } + }, + setCollapsed: function(tag) + { + var block = this.block.blocks[0]; + if (block === false) return; + + if (block.tagName == 'LI') + { + if (tag != 'blockquote') return; + + this.block.formatListToBlockquote(); + return; + } + + var isContainerTable = (this.block.containerTag == 'TD' || this.block.containerTag == 'TH'); + if (isContainerTable && !this.opts.linebreaks) + { + + document.execCommand('formatblock', false, '<' + tag + '>'); + + block = this.selection.getBlock(); + this.block.toggle($(block)); + + } + else if (block.tagName.toLowerCase() != tag) + { + if (this.opts.linebreaks && tag == 'p') + { + $(block).prepend('
').append('
'); + this.utils.replaceWithContents(block); + } + else + { + var $formatted = this.utils.replaceToTag(block, tag); + + this.block.toggle($formatted); + + if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove(); + if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted); + if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap(); + + this.block.formatTableWrapping($formatted); + } + } + else if (tag == 'blockquote' && block.tagName.toLowerCase() == tag) + { + // blockquote off + if (this.opts.linebreaks) + { + $(block).prepend('
').append('
'); + this.utils.replaceWithContents(block); + } + else + { + var $el = this.utils.replaceToTag(block, 'p'); + this.block.toggle($el); + } + } + else if (block.tagName.toLowerCase() == tag) + { + this.block.toggle($(block)); + } + + }, + setMultiple: function(tag) + { + var block = this.block.blocks[0]; + var isContainerTable = (this.block.containerTag == 'TD' || this.block.containerTag == 'TH'); + + if (block !== false && this.block.blocksSize === 1) + { + if (block.tagName.toLowerCase() == tag && tag == 'blockquote') + { + // blockquote off + if (this.opts.linebreaks) + { + $(block).prepend('
').append('
'); + this.utils.replaceWithContents(block); + } + else + { + var $el = this.utils.replaceToTag(block, 'p'); + this.block.toggle($el); + } + } + else if (block.tagName == 'LI') + { + if (tag != 'blockquote') return; + + this.block.formatListToBlockquote(); + } + else if (this.block.containerTag == 'BLOCKQUOTE') + { + this.block.formatBlockquote(tag); + } + else if (this.opts.linebreaks && ((isContainerTable) || (this.range.commonAncestorContainer != block))) + { + this.block.formatWrap(tag); + } + else + { + if (this.opts.linebreaks && tag == 'p') + { + $(block).prepend('
').append('
'); + this.utils.replaceWithContents(block); + } + else if (block.tagName === 'TD') + { + this.block.formatWrap(tag); + } + else + { + var $formatted = this.utils.replaceToTag(block, tag); + + this.block.toggle($formatted); + + if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted); + if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap(); + } + } + } + else + { + + if (this.opts.linebreaks || tag != 'p') + { + if (tag == 'blockquote') + { + var count = 0; + for (var i = 0; i < this.block.blocksSize; i++) + { + if (this.block.blocks[i].tagName == 'BLOCKQUOTE') count++; + } + + // only blockquote selected + if (count == this.block.blocksSize) + { + $.each(this.block.blocks, $.proxy(function(i,s) + { + if (this.opts.linebreaks) + { + $(s).prepend('
').append('
'); + this.utils.replaceWithContents(s); + } + else + { + this.utils.replaceToTag(s, 'p'); + } + + }, this)); + + return; + } + + } + + + this.block.formatWrap(tag); + } + else + { + var classSize = 0; + var toggleType = false; + if (this.block.type == 'class') + { + toggleType = 'toggle'; + classSize = $(this.block.blocks).filter('.' + this.block.value).length; + + if (this.block.blocksSize == classSize) toggleType = 'toggle'; + else if (this.block.blocksSize > classSize) toggleType = 'set'; + else if (classSize === 0) toggleType = 'set'; + + } + + var exceptTags = ['ul', 'ol', 'li', 'td', 'th', 'dl', 'dt', 'dd']; + $.each(this.block.blocks, $.proxy(function(i,s) + { + if ($.inArray(s.tagName.toLowerCase(), exceptTags) != -1) return; + + var $formatted = this.utils.replaceToTag(s, tag); + + if (toggleType) + { + if (toggleType == 'toggle') this.block.toggle($formatted); + else if (toggleType == 'remove') this.block.remove($formatted); + else if (toggleType == 'set') this.block.setForce($formatted); + } + else this.block.toggle($formatted); + + if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove(); + if (this.block.isRemoveInline) this.utils.removeInlineTags($formatted); + if (tag == 'p' || this.block.headTag) $formatted.find('p').contents().unwrap(); + + + }, 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); + return; + } + else if (this.block.type == 'attr' || this.block.type == 'data') + { + if ($el.attr(this.block.value.name) == this.block.value.value) + { + $el.removeAttr(this.block.value.name); + } + else + { + $el.attr(this.block.value.name, this.block.value.value); + } + + return; + } + else + { + $el.removeAttr('style class'); + return; + } + }, + remove: function($el) + { + $el.removeClass(this.block.value); + }, + formatListToBlockquote: function() + { + var block = $(this.block.blocks[0]).closest('ul, ol'); + + $(block).find('ul, ol').contents().unwrap(); + $(block).find('li').append($('
')).contents().unwrap(); + + var $el = this.utils.replaceToTag(block, 'blockquote'); + this.block.toggle($el); + }, + formatBlockquote: function(tag) + { + document.execCommand('outdent'); + document.execCommand('formatblock', false, tag); + + this.clean.clearUnverified(); + this.$editor.find('p:empty').remove(); + + var formatted = this.selection.getBlock(); + + if (tag != 'p') + { + $(formatted).find('img').remove(); + } + + if (!this.opts.linebreaks) + { + this.block.toggle($(formatted)); + } + + this.$editor.find('ul, ol, tr, blockquote, p').each($.proxy(this.utils.removeEmpty, this)); + + if (this.opts.linebreaks && tag == 'p') + { + this.utils.replaceWithContents(formatted); + } + + }, + formatWrap: function(tag) + { + if (this.block.containerTag == 'UL' || this.block.containerTag == 'OL') + { + if (tag == 'blockquote') + { + this.block.formatListToBlockquote(); + } + else + { + return; + } + } + + var formatted = this.selection.wrap(tag); + if (formatted === false) return; + + var $formatted = $(formatted); + + this.block.formatTableWrapping($formatted); + + var $elements = $formatted.find(this.opts.blockLevelElements.join(',') + ', td, table, thead, tbody, tfoot, th, tr'); + + if ((this.opts.linebreaks && tag == 'p') || tag == 'pre' || tag == 'blockquote') + { + $elements.append('
'); + } + + $elements.contents().unwrap(); + + if (tag != 'p' && tag != 'blockquote') $formatted.find('img').remove(); + + $.each(this.block.blocks, $.proxy(this.utils.removeEmpty, this)); + + $formatted.append(this.selection.getMarker(2)); + + if (!this.opts.linebreaks) + { + this.block.toggle($formatted); + } + + this.$editor.find('ul, ol, tr, blockquote, p').each($.proxy(this.utils.removeEmpty, this)); + $formatted.find('blockquote:empty').remove(); + + if (this.block.isRemoveInline) + { + this.utils.removeInlineTags($formatted); + } + + if (this.opts.linebreaks && tag == 'p') + { + this.utils.replaceWithContents($formatted); + } + + }, + formatTableWrapping: function($formatted) + { + if ($formatted.closest('table').length === 0) return; + + if ($formatted.closest('tr').length === 0) $formatted.wrap(''); + if ($formatted.closest('td').length === 0 && $formatted.closest('th').length === 0) + { + $formatted.wrap(''); + } + }, + removeData: function(name, value) + { + var blocks = this.selection.getBlocks(); + $(blocks).removeAttr('data-' + name); + + this.code.sync(); + }, + setData: function(name, value) + { + var blocks = this.selection.getBlocks(); + $(blocks).attr('data-' + name, value); + + this.code.sync(); + }, + toggleData: function(name, value) + { + var blocks = this.selection.getBlocks(); + $.each(blocks, function() + { + if ($(this).attr('data-' + name)) + { + $(this).removeAttr('data-' + name); + } + else + { + $(this).attr('data-' + name, value); + } + }); + }, + removeAttr: function(attr, value) + { + var blocks = this.selection.getBlocks(); + $(blocks).removeAttr(attr); + + this.code.sync(); + }, + setAttr: function(attr, value) + { + var blocks = this.selection.getBlocks(); + $(blocks).attr(attr, value); + + this.code.sync(); + }, + toggleAttr: function(attr, value) + { + var blocks = this.selection.getBlocks(); + $.each(blocks, function() + { + if ($(this).attr(name)) + { + $(this).removeAttr(name); + } + else + { + $(this).attr(name, value); + } + }); + }, + removeClass: function(className) + { + var blocks = this.selection.getBlocks(); + $(blocks).removeClass(className); + + this.utils.removeEmptyAttr(blocks, 'class'); + + this.code.sync(); + }, + setClass: function(className) + { + var blocks = this.selection.getBlocks(); + $(blocks).addClass(className); + + this.code.sync(); + }, + toggleClass: function(className) + { + var blocks = this.selection.getBlocks(); + $(blocks).toggleClass(className); + + this.code.sync(); + } + }; + }, + buffer: function() + { + return { + set: function(type) + { + if (typeof type == 'undefined' || type == 'undo') + { + this.buffer.setUndo(); + } + else + { + this.buffer.setRedo(); + } + }, + setUndo: function() + { + this.selection.save(); + this.opts.buffer.push(this.$editor.html()); + this.selection.restore(); + }, + setRedo: function() + { + this.selection.save(); + this.opts.rebuffer.push(this.$editor.html()); + this.selection.restore(); + }, + getUndo: function() + { + this.$editor.html(this.opts.buffer.pop()); + }, + getRedo: function() + { + this.$editor.html(this.opts.rebuffer.pop()); + }, + add: function() + { + this.opts.buffer.push(this.$editor.html()); + }, + undo: function() + { + if (this.opts.buffer.length === 0) return; + + this.buffer.set('redo'); + this.buffer.getUndo(); + + this.selection.restore(); + + setTimeout($.proxy(this.observe.load, this), 50); + }, + redo: function() + { + if (this.opts.rebuffer.length === 0) return; + + this.buffer.set('undo'); + this.buffer.getRedo(); + + this.selection.restore(); + + setTimeout($.proxy(this.observe.load, this), 50); } }; }, @@ -519,13 +1144,11 @@ return { run: function() { - this.build.createContainerBox(); this.build.loadContent(); this.build.loadEditor(); this.build.enableEditor(); this.build.setCodeAndCall(); - }, isTextarea: function() { @@ -541,13 +1164,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() { @@ -590,10 +1207,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() { @@ -633,6 +1248,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 @@ -642,21 +1272,16 @@ if (window.FormData === undefined || !e.dataTransfer) return true; - var length = e.dataTransfer.files.length; - if (length === 0) return true; + if (e.dataTransfer.files.length === 0) + { + 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)); @@ -665,11 +1290,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(); @@ -705,23 +1327,25 @@ } 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 @@ -731,8 +1355,8 @@ 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() @@ -742,26 +1366,32 @@ $.each(this.opts.plugins, $.proxy(function(i, s) { - if (RedactorPlugins[s]) + if (typeof RedactorPlugins[s] === 'undefined') return; + + if ($.inArray(s, $.Redactor.modules) !== -1) { - 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(); + $.error('Plugin name "' + s + '" matches the name of the Redactor\'s module.'); + return; } - }, this)); + if (!$.isFunction(RedactorPlugins[s])) return; + this[s] = RedactorPlugins[s](); + + // get methods + 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() @@ -776,389 +1406,17 @@ } }; }, - 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 $('