From: Alexander Ebert Date: Fri, 5 May 2017 16:01:37 +0000 (+0200) Subject: Upgraded to Redactor II 2.5 X-Git-Tag: 3.0.5~17 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=e120acb5e5c2af6c28ee8020686e804ae5d237d7;p=GitHub%2FWoltLab%2FWCF.git Upgraded to Redactor II 2.5 --- diff --git a/wcfsetup/install/files/js/3rdParty/redactor2/redactor.js b/wcfsetup/install/files/js/3rdParty/redactor2/redactor.js index 778fc7349c..8ecf818cf5 100644 --- a/wcfsetup/install/files/js/3rdParty/redactor2/redactor.js +++ b/wcfsetup/install/files/js/3rdParty/redactor2/redactor.js @@ -1,7 +1,7 @@ /* Redactor II - Version 2.4 - Updated: March 24, 2017 + Version 2.5 + Updated: May 1, 2017 http://imperavi.com/redactor/ @@ -101,7 +101,7 @@ // Options $.Redactor = Redactor; - $.Redactor.VERSION = '2.4'; + $.Redactor.VERSION = '2.5'; $.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', @@ -194,6 +194,7 @@ toolbarFixedTarget: document, toolbarFixedTopOffset: 0, // pixels toolbarExternal: false, // ID selector + toolbarOverflow: false, air: false, airWidth: false, @@ -202,7 +203,7 @@ formattingAdd: false, buttons: ['format', 'bold', 'italic', 'deleted', 'lists', 'image', 'file', 'link'], // + 'horizontalrule', 'underline', 'ol', 'ul', 'indent', 'outdent' - + buttonsTextLabeled: false, buttonsHide: [], buttonsHideOnMobile: [], @@ -844,11 +845,21 @@ return; } - if (currentTag === tag) + var clearAllAttrs = false; + if (currentTag === tag && attr === undefined) { tag = 'p'; + clearAllAttrs = true; } + + if (clearAllAttrs) + { + this.block.removeAllClass(); + this.block.removeAllAttr(); + } + + var replaced; if (currentTag === 'blockquote' && this.utils.isEndOfElement(block)) { @@ -871,6 +882,7 @@ replaced = this.utils.replaceToTag(block, tag); } + if (typeof attr === 'object') { type = value; @@ -903,9 +915,9 @@ var replaced = []; var blocks = this.selection.blocks(); - if (blocks[0] && $(blocks[0]).hasClass('redactor-in')) + if (blocks[0] && ($(blocks[0]).hasClass('redactor-in') || $(blocks[0]).hasClass('redactor-box'))) { - blocks = $(blocks[0]).find(this.opts.blockTags.join(', ')); + blocks = this.core.editor().find(this.opts.blockTags.join(', ')); } var len = blocks.length; @@ -1823,7 +1835,7 @@ $button.addClass('re-button re-' + btnName); $button.attr({ 'role': 'button', 'aria-label': title, 'tabindex': '-1' }); - if (typeof btnObject.icon !== 'undefined') + if (typeof btnObject.icon !== 'undefined' && !this.opts.buttonsTextLabeled) { var $icon = $(''); $icon.addClass('re-icon-' + btnName); @@ -2083,8 +2095,11 @@ }, setIcon: function($btn, icon) { - $btn.html(icon).addClass('re-button-icon'); - this.button.buildButtonTooltip($btn, $btn.attr('alt')); + if (!this.opts.buttonsTextLabeled) + { + $btn.html(icon).addClass('re-button-icon'); + this.button.buildButtonTooltip($btn, $btn.attr('alt')); + } }, changeIcon: function(key, newIconClass) { @@ -2191,7 +2206,9 @@ return { set: function(node1, node2, end) { - this.core.editor().focus(); + var cs = this.core.editor().scrollTop(); + this.core.editor().focus(); + this.core.editor().scrollTop(cs); end = (typeof end === 'undefined') ? 0 : 1; @@ -2525,7 +2542,10 @@ } // add span marker - $div.find('span, a').attr('data-redactor-span', true).each(function() + $div.find('span, a').attr('data-redactor-span', true); + + // add style cache + $div.find(this.opts.inlineTags.join(',')).each(function() { // add style cache var $el = $(this); @@ -2596,6 +2616,10 @@ $div.find('*[style=""]').removeAttr('style'); $div.find('*[class=""]').removeAttr('class'); $div.find('*[rel=""]').removeAttr('rel'); + $div.find('*[data-image=""]').removeAttr('data-image'); + $div.find('*[alt=""]').removeAttr('alt'); + $div.find('*[title=""]').removeAttr('title'); + $div.find('*[data-redactor-style-cache]').removeAttr('data-redactor-style-cache'); // remove markers $div.find('.redactor-invisible-space, .redactor-unlink').each(function() @@ -3055,10 +3079,11 @@ { html = html.replace(new RegExp('<' + tags[i] + '(.*?[^>])((colspan|rowspan)="(.*?[^>])")?(.*?[^>])>', 'gi'), '###' + tags[i] + ' $2###'); } - else if (tags[i] === 'span') + else if (this.utils.isInlineTag(tags[i])) { html = html.replace(new RegExp('<' + tags[i] + '([^>]*)class="([^>]*)"[^>]*>', 'gi'), '###' + tags[i] + ' class="$2"###'); html = html.replace(new RegExp('<' + tags[i] + '([^>]*)data-redactor-style-cache="([^>]*)"[^>]*>', 'gi'), '###' + tags[i] + ' cache="$2"###'); + html = html.replace(new RegExp('<' + tags[i] + '[^>]*>', 'gi'), '###' + tags[i] + '###'); } else { @@ -3113,9 +3138,12 @@ { html = html.replace(new RegExp('###' + tags[i] + '\s?(.*?[^#])###', 'gi'), '<' + tags[i] + '$1>'); } - else if (tags[i] === 'span') + else if (this.utils.isInlineTag(tags[i])) { - html = html.replace(new RegExp('###' + tags[i] + ' cache="(.*?[^#])"###', 'gi'), '<' + tags[i] + ' style="$1" data-redactor-span="true" data-redactor-style-cache="$1">'); + + var spanMarker = (tags[i] === 'span') ? ' data-redactor-span="true"' : ''; + + html = html.replace(new RegExp('###' + tags[i] + ' cache="(.*?[^#])"###', 'gi'), '<' + tags[i] + ' style="$1"' + spanMarker + ' data-redactor-style-cache="$1">'); html = html.replace(new RegExp('###' + tags[i] + '\s?(.*?[^#])###', 'gi'), '<' + tags[i] + '$1>'); } } @@ -4374,7 +4402,7 @@ this.caret.after($link); // callback - this.storage.add({ type: type, node: $link[0], url: $link[0].href, id: id }); + this.storage.add({ type: type, node: $link[0], url: json.url, id: id }); if (direct !== null) { @@ -4614,7 +4642,7 @@ } this.events.dropImage = false; - this.storage.add({ type: type, node: $img[0], url: $img[0].src, id: id }); + this.storage.add({ type: type, node: $img[0], url: json.url, id: id }); var nextNode = $img[0].nextSibling; var $nextFigure = $figure.next(); @@ -4894,11 +4922,9 @@ $('#redactor-image-preview').html($('')); $('#redactor-image-title').val($image.attr('alt')); - var $redactorImageLink = $('#redactor-image-link'); - $redactorImageLink.attr('href', $image.attr('src')); if ($link.length !== 0) { - $redactorImageLink.val($link.attr('href')); + $('#redactor-image-link').val($link.attr('href')); if ($link.attr('target') === '_blank') { $('#redactor-image-link-blank').prop('checked', true); @@ -5304,6 +5330,118 @@ inline: function() { return { + format: function(tag, attr, value, type) + { + // Stop formatting pre/code + if (this.utils.isCurrentOrParent(['PRE', 'CODE'])) return; + + // Get params + var params = this.inline.getParams(attr, value, type); + + // Arrange tag + tag = this.inline.arrangeTag(tag); + + this.placeholder.hide(); + this.buffer.set(); + + (this.utils.isCollapsed()) ? this.inline.formatCollapsed(tag, params) : this.inline.formatUncollapsed(tag, params); + }, + formatCollapsed: function(tag, params) + { + var newInline; + var inline = this.selection.inline(); + + if (inline) + { + var currentTag = inline.tagName.toLowerCase(); + if (currentTag === tag) + { + // empty = remove + if (this.utils.isEmpty(inline.innerHTML)) + { + this.caret.after(inline); + $(inline).remove(); + } + // not empty = break + else + { + var $first = this.inline.insertBreakpoint(inline, currentTag); + this.caret.after($first); + } + } + else if ($(inline).closest(tag).length === 0) + { + newInline = this.inline.insertInline(tag); + newInline = this.inline.setParams(newInline, params); + } + else + { + this.caret.start(inline); + } + } + else + { + newInline = this.inline.insertInline(tag); + newInline = this.inline.setParams(newInline, params); + } + }, + formatUncollapsed: function(tag, params) + { + this.selection.save(); + + var nodes = this.inline.getClearedNodes(); + this.inline.setNodesStriked(nodes, tag, params); + + this.selection.restore(); + + document.execCommand('strikethrough'); + + this.selection.saveInstant(); + + var self = this; + this.core.editor().find('strike').each(function() + { + var $el = self.utils.replaceToTag(this, tag); + self.inline.setParams($el[0], params); + + var $inside = $el.find(tag); + var $parent = $el.parent(); + var $parentAround = $parent.parent(); + + // revert formatting (safari bug) + if ($parentAround.length !== 0 && $parentAround[0].tagName.toLowerCase() === tag && $parentAround.html() == $parent[0].outerHTML) + { + $el.replaceWith(function() { return $(this).contents(); }); + $parentAround.replaceWith(function() { return $(this).contents(); }); + + return; + } + + // remove inside + if ($inside.length !== 0) self.inline.cleanInsideOrParent($inside, params); + + // same parent + if ($parent.html() == $el[0].outerHTML) self.inline.cleanInsideOrParent($parent, params); + + // bugfix: remove empty inline tags after selection + if (self.detect.isFirefox()) + { + self.core.editor().find(tag + ':empty').remove(); + } + }); + + this.selection.restoreInstant(); + }, + cleanInsideOrParent: function($el, params) + { + if (params) + { + for (var key in params.data) + { + this.inline.removeSpecificAttr($el, key, params.data[key]); + } + } + }, getClearedNodes: function() { var nodes = this.selection.nodes(); @@ -5332,14 +5470,13 @@ return newNodes; }, - isConvertableAttr: function(node, attr, value) + isConvertableAttr: function(node, name, value) { - var nodeAttrValue = $(node).attr(attr); + var nodeAttrValue = $(node).attr(name); if (nodeAttrValue) { - if (attr === 'style') + if (name === 'style') { - value = $.trim(value).replace(/;$/, '') var rules = value.split(';'); @@ -5378,19 +5515,19 @@ return 0; }, - isConvertable: function(node, nodeTag, tag, attr) + isConvertable: function(node, nodeTag, tag, params) { if (nodeTag === tag) { - if (attr) + if (params) { var count = 0; - for (var key in attr) + for (var key in params.data) { - count += this.inline.isConvertableAttr(node, key, attr[key]); + count += this.inline.isConvertableAttr(node, key, params.data[key]); } - if (count === Object.keys(attr).length) + if (count === Object.keys(params.data).length) { return true; } @@ -5403,7 +5540,7 @@ return false; }, - setNodesStriked: function(nodes, tag, attr) + setNodesStriked: function(nodes, tag, params) { for (var i = 0; i < nodes.length; i++) { @@ -5412,7 +5549,7 @@ var parent = nodes[i].parentNode; var parentTag = (parent && parent.tagName) ? parent.tagName.toLowerCase() : undefined; - var convertable = this.inline.isConvertable(parent, parentTag, tag, attr); + var convertable = this.inline.isConvertable(parent, parentTag, tag, params); if (convertable) { var $el = $(parent).replaceWith(function() @@ -5423,7 +5560,7 @@ $el.attr('data-redactor-inline-converted'); } - var convertable = this.inline.isConvertable(nodes[i], nodeTag, tag, attr); + var convertable = this.inline.isConvertable(nodes[i], nodeTag, tag, params); if (convertable) { var $el = $(nodes[i]).replaceWith(function() @@ -5433,136 +5570,6 @@ } } }, - format: function(tag, attr, value, type) - { - if (typeof attr !== 'undefined' && typeof attr !== 'object') - { - var obj = {}; - obj[attr] = value; - attr = obj; - } - - tag = tag.toLowerCase(); - - // Stop formatting pre/code - if (this.utils.isCurrentOrParent(['PRE', 'CODE'])) - { - return; - } - - var tags = ['b', 'bold', 'i', 'italic', 'underline', 'strikethrough', 'deleted', 'superscript', 'subscript']; - var replaced = ['strong', 'strong', 'em', 'em', 'u', 'del', 'del', 'sup', 'sub']; - - for (var i = 0; i < tags.length; i++) - { - if (tag === tags[i]) - { - tag = replaced[i]; - } - } - - this.placeholder.hide(); - this.buffer.set(); - - if (this.utils.isCollapsed()) - { - this.inline.formatCollapsed(tag, attr, value, type); - } - else - { - this.inline.formatUncollapsed(tag, attr, value, type); - } - }, - formatUncollapsed: function(tag, attr, value, type) - { - this.selection.save(); - - var nodes = this.inline.getClearedNodes(); - this.inline.setNodesStriked(nodes, tag, attr); - - this.selection.restore(); - - document.execCommand('strikethrough'); - - this.selection.saveInstant(); - - var self = this; - this.core.editor().find('strike').each(function() - { - var $el = self.utils.replaceToTag(this, tag); - for (var key in attr) - { - self.inline.setAttr($el, key, attr[key], type); - } - - // remove inside - var $inside = $el.find(tag); - if ($inside.length !== 0) - { - for (var key in attr) - { - self.inline.removeSpecificAttr($inside, key, attr[key]); - } - } - - // same parent - var $parent = $el.parent(); - if ($parent.html() == $el[0].outerHTML) - { - for (var key in attr) - { - self.inline.removeSpecificAttr($parent, key, attr[key]); - } - } - - // bugfix: remove empty inline tags after selection - if (self.detect.isFirefox()) - { - self.core.editor().find(tag + ':empty').remove(); - } - - // cache style - $el.attr('data-redactor-style-cache', $el.attr('style')); - - }); - - this.selection.restoreInstant(); - }, - formatCollapsed: function(tag, attr, value, type) - { - var inline = this.selection.inline(); - if (inline) - { - var currentTag = inline.tagName.toLowerCase(); - if (currentTag === tag) - { - // empty = remove - if (this.utils.isEmpty(inline.innerHTML)) - { - this.caret.after(inline); - $(inline).remove(); - } - // not empty = break - else - { - var $first = this.inline.insertBreakpoint(inline, currentTag); - this.caret.after($first); - } - } - else if ($(inline).closest(tag).length === 0) - { - this.inline.insertInline(tag, attr, value, type); - } - else - { - this.caret.start(inline); - } - } - else - { - this.inline.insertInline(tag, attr, value, type); - } - }, insertBreakpoint: function(inline, currentTag) { var breakpoint = document.createElement('span'); @@ -5573,7 +5580,8 @@ var code = this.utils.getOuterHtml(inline); var endTag = (end) ? '' : '<' + currentTag + '>'; - code = code.replace(/​<\/span>/i, '' + endTag); + code = code.replace(/<\/span>/i, "" + endTag); + var $code = $(code); $(inline).replaceWith($code); @@ -5584,234 +5592,430 @@ return $code.first(); }, - insertInline: function(tag, attr, value, type) + insertInline: function(tag) { var node = document.createElement(tag); - node = this.inline.setAttr(node, attr, value, type); this.insert.node(node); this.caret.start(node); + + return node; }, - setAttr: function(inline, attr, value, type) + arrangeTag: function(tag) { - if (typeof attr === 'undefined') - { - return inline; - } + var tags = ['b', 'bold', 'i', 'italic', 'underline', 'strikethrough', 'deleted', 'superscript', 'subscript']; + var replaced = ['strong', 'strong', 'em', 'em', 'u', 'del', 'del', 'sup', 'sub']; - var func = (typeof type === 'undefined') ? 'toggle' : type; + tag = tag.toLowerCase(); - if (attr === 'class') - { - inline = this.inline[func + 'Class'](value, inline); - } - else + for (var i = 0; i < tags.length; i++) { - if (func === 'remove') - { - inline = this.inline[func + 'Attr'](attr, inline); - } - else if (func === 'removeAll') - { - inline = this.inline[func + 'Attr'](inline); - } - else + if (tag === tags[i]) { - inline = this.inline[func + 'Attr'](attr, value, inline); - - if (attr === 'style' && inline[0].tagName === 'SPAN') - { - $(inline).attr('data-redactor-span', true); - } + tag = replaced[i]; } } - return inline; + return tag; }, - getInlines: function(inline) + getStyleParams: function(params) { - return (typeof inline === 'undefined') ? this.selection.inlines() : inline; + var result = {}; + var rules = params.trim().replace(/;$/, '').split(';'); + for (var i = 0; i < rules.length; i++) + { + var rule = rules[i].split(':'); + if (rule) + { + result[rule[0].trim()] = rule[1].trim(); + } + } + + return result; }, - update: function(tag, attr, value, type) + getParams: function(attr, value, type) { - var inlines = this.selection.inlines(); - var result = []; - var self = this; + var data = false; + var func = 'toggle'; + if (typeof attr === 'object') + { + data = attr; + func = (value !== undefined) ? value : func; + } + else if (attr !== undefined && value !== undefined) + { + data = {}; + data[attr] = value; + func = (type !== undefined) ? type : func; + } - $.each(inlines, function(i,s) - { - if ($.isArray(tag)) - { - if ($.inArray(s.tagName.toLowerCase(), tag) === -1) - { - return; - } - } - else - { - if (tag !== '*' && s.tagName.toLowerCase() !== tag) - { - return; - } - } + return (data) ? { 'func': func, 'data': data } : false; + }, + setParams: function(node, params) + { + if (params) + { + for (var key in params.data) + { + var $node = $(node); + if (key === 'style') + { + node = this.inline[params.func + 'Style'](params.data[key], node); + $node.attr('data-redactor-style-cache', $node.attr('style')); + } + else if (key === 'class') + { + node = this.inline[params.func + 'Class'](params.data[key], node); + } + // attr + else + { + node = (params.func === 'remove') ? this.inline[params.func + 'Attr'](key, node) : this.inline[params.func + 'Attr'](key, params.data[key], node); + } - result.push(self.inline.setAttr(s, attr, value, type)); + if (key === 'style' && node.tagName === 'SPAN') + { + $node.attr('data-redactor-span', true); + } + } + } - }); + return node; + }, - return result; + // Each + eachInline: function(node, callback) + { + var lastNode; + var nodes = (node === undefined) ? this.selection.inlines() : [node]; + if (nodes) + { + for (var i = 0; i < nodes.length; i++) + { + lastNode = callback(nodes[i])[0]; + } + } + return lastNode; + }, + + // Class + replaceClass: function(value, node) + { + return this.inline.eachInline(node, function(el) + { + return $(el).removeAttr('class').addClass(value); + }); }, - replaceClass: function(value, inline) + toggleClass: function(value, node) { - return $(this.inline.getInlines(inline)).removeAttr('class').addClass(value)[0]; + return this.inline.eachInline(node, function(el) + { + return $(el).toggleClass(value); + }); }, - toggleClass: function(value, inline) + addClass: function(value, node) { - return $(this.inline.getInlines(inline)).toggleClass(value)[0]; + return this.inline.eachInline(node, function(el) + { + return $(el).addClass(value); + }); }, - addClass: function(value, inline) + removeClass: function(value, node) { - return $(this.inline.getInlines(inline)).addClass(value)[0]; + return this.inline.eachInline(node, function(el) + { + return $(el).removeClass(value); + }); }, - removeClass: function(value, inline) + removeAllClass: function(node) { - return $(this.inline.getInlines(inline)).removeClass(value)[0]; + return this.inline.eachInline(node, function(el) + { + return $(el).removeAttr('class'); + }); }, - removeAllClass: function(inline) + + // Attr + replaceAttr: function(name, value, node) { - return $(this.inline.getInlines(inline)).removeAttr('class')[0]; + return this.inline.eachInline(node, function(el) + { + return $(el).removeAttr(name).attr(name. value); + }); }, - replaceAttr: function(inline, attr, value) + toggleAttr: function(name, value, node) { - inline = this.inline.removeAttr(attr, this.inline.getInlines(inline)); + return this.inline.eachInline(node, function(el) + { + var attr = $(el).attr(name); - return $(inline).attr(attr, value)[0]; + return (attr) ? $(el).removeAttr(name) : $(el).attr(name. value); + }); }, - toggleAttr: function(attr, value, inline) + addAttr: function(name, value, node) { - inline = this.inline.getInlines(inline); - - var self = this; - var returned = []; - $.each(inline, function(i,s) - { - var $el = $(s); - if ($el.attr(attr)) - { - returned.push(self.inline.removeAttr(attr, s)); - } - else - { - returned.push(self.inline.addAttr(attr, value, s)); - } - }); + return this.inline.eachInline(node, function(el) + { + return $(el).attr(name, value); + }); + }, + removeAttr: function(name, node) + { + return this.inline.eachInline(node, function(el) + { + var $el = $(el); - return returned; + $el.removeAttr(name); + if (name === 'style') + { + $el.removeAttr('data-redactor-style-cache'); + } + return $el; + }); }, - addAttr: function(attr, value, inline) + removeAllAttr: function(node) { - return $(this.inline.getInlines(inline)).attr(attr, value)[0]; + return this.inline.eachInline(node, function(el) + { + var $el = $(el); + var len = el.attributes.length; + for (var z = 0; z < len; z++) + { + $el.removeAttr(el.attributes[z].name); + } + + return $el; + }); }, - removeSpecificAttr: function(inline, key, value) + removeSpecificAttr: function(node, key, value) { + var $el = $(node); if (key === 'style') { var arr = value.split(':'); var name = arr[0].trim(); - $(inline).css(name, ''); - this.utils.removeEmptyAttr(inline, 'style'); + $el.css(name, ''); + + if (this.utils.removeEmptyAttr(node, 'style')) + { + $el.removeAttr('data-redactor-style-cache'); + } } else { - $(inline).removeAttr(key)[0]; + $el.removeAttr(key)[0]; } }, - removeAttr: function(attr, inline) + + // Style + hasParentStyle: function($el) { - return $(this.inline.getInlines(inline)).removeAttr(attr)[0]; + var $parent = $el.parent(); + + return ($parent.length === 1 && $parent[0].tagName === $el[0].tagName && $parent.html() === $el[0].outerHTML) ? $parent : false; }, - removeAllAttr: function(inline) + addParentStyle: function($el) { - inline = this.inline.getInlines(inline); + var $parent = this.inline.hasParentStyle($el); + if ($parent) + { + var style = this.inline.getStyleParams($el.attr('style')); + $parent.css(style); + $parent.attr('data-redactor-style-cache', $parent.attr('style')); - var returned = []; - $.each(inline, function(i, s) - { - if (typeof s.attributes === 'undefined') - { - returned.push(s); - } + $el.replaceWith(function() + { + return $(this).contents(); + }); + } + else + { + $el.attr('data-redactor-style-cache', $el.attr('style')); + } - var $el = $(s); - var len = s.attributes.length; - for (var z = 0; z < len; z++) - { - $el.removeAttr(s.attributes[z].name); - } + return $el; + }, + replaceStyle: function(params, node) + { + params = this.inline.getStyleParams(params); - returned.push($el[0]); - }); + var self = this; + return this.inline.eachInline(node, function(el) + { + var $el = $(el); + $el.removeAttr('style').css(params); + $el = self.inline.addParentStyle($el); - return returned; + return $el; + }); }, - removeFormat: function() + toggleStyle: function(params, node) { - this.selection.save(); - - var nodes = this.inline.getClearedNodes(); + params = this.inline.getStyleParams(params); - for (var i = 0; i < nodes.length; i++) + var self = this; + return this.inline.eachInline(node, function(el) { - if (nodes[i].nodeType === 1) - { - $(nodes[i]).replaceWith(function() + var $el = $(el); + + for (var key in params) + { + var newVal = params[key]; + var oldVal = $el.css(key); + + oldVal = (self.utils.isRgb(oldVal)) ? self.utils.rgb2hex(oldVal) : oldVal; + newVal = (self.utils.isRgb(newVal)) ? self.utils.rgb2hex(newVal) : newVal; + + if (oldVal === newVal) { - return $(this).contents(); - }); + $el.css(key, ''); + } + else + { + $el.css(key, newVal); + } + } - } - } + if (!self.utils.removeEmptyAttr(el, 'style')) + { + $el = self.inline.addParentStyle($el); + } + else + { + $el.removeAttr('data-redactor-style-cache'); + } - this.selection.restore(); + return $el; + }); }, - removeStyleRule: function(name) + addStyle: function(params, node) + { + params = this.inline.getStyleParams(params); + + var self = this; + return this.inline.eachInline(node, function(el) + { + var $el = $(el); + + $el.css(params); + $el = self.inline.addParentStyle($el); + + return $el; + }); + }, + removeStyle: function(params, node) + { + params = this.inline.getStyleParams(params); + + var self = this; + return this.inline.eachInline(node, function(el) + { + var $el = $(el); + + for (var key in params) + { + $el.css(key, ''); + } + + if (self.utils.removeEmptyAttr(el, 'style')) + { + $el.removeAttr('data-redactor-style-cache'); + } + else + { + $el.attr('data-redactor-style-cache', $el.attr('style')); + } + + return $el; + }); + }, + removeAllStyle: function(node) + { + return this.inline.eachInline(node, function(el) + { + return $(el).removeAttr('style').removeAttr('data-redactor-style-cache'); + }); + }, + removeStyleRule: function(name) { - this.buffer.set(); var parent = this.selection.parent(); var nodes = this.selection.inlines(); - this.selection.save(); + this.buffer.set(); if (parent && parent.tagName === 'SPAN') { - var $s = $(parent); + this.inline.removeStyleRuleAttr($(parent), name); + } - $s.css(name, ''); - $s.removeAttr('data-redactor-span'); - this.utils.removeEmptyAttr($s, 'style'); - if ($s[0].attributes.length === 0) + for (var i = 0; i < nodes.length; i++) + { + var el = nodes[i]; + var $el = $(el); + if ($.inArray(el.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$el.hasClass('redactor-selection-marker')) { - $s.replaceWith($s.contents()); + this.inline.removeStyleRuleAttr($el, name); } } - $.each(nodes, $.proxy(function(i,s) + }, + removeStyleRuleAttr: function($el, name) + { + $el.css(name, ''); + if (this.utils.removeEmptyAttr($el, 'style')) { - var $s = $(s); - if ($.inArray(s.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$s.hasClass('redactor-selection-marker')) - { - $s.css(name, ''); - this.utils.removeEmptyAttr($s, 'style'); - if ($s[0].attributes.length === 0) - { - $s.replaceWith($s.contents()); - } - } - }, this)); + $el.removeAttr('data-redactor-style-cache'); + } + else + { + $el.attr('data-redactor-style-cache', $el.attr('style')); + } + }, - this.selection.restore(); + // Update + update: function(tag, attr, value, type) + { + tag = this.inline.arrangeTag(tag); + + var params = this.inline.getParams(attr, value, type); + var nodes = this.selection.inlines(); + var result = []; + + if (nodes) + { + for (var i = 0; i < nodes.length; i++) + { + var el = nodes[i]; + if (tag === '*' || el.tagName.toLowerCase() === tag) + { + result.push(this.inline.setParams(el, params)); + } + } + } + + return result; + }, + + // All + removeFormat: function() + { + this.selection.save(); + + var nodes = this.inline.getClearedNodes(); + for (var i = 0; i < nodes.length; i++) + { + if (nodes[i].nodeType === 1) + { + $(nodes[i]).replaceWith(function() + { + return $(this).contents(); + }); + } + } + + this.selection.restore(); } }; @@ -6497,7 +6701,7 @@ this.code.syncFire = false; this.keydown.removeEmptyLists(); - this.core.editor().find('*[style]').not('img, figure, #redactor-image-box, #redactor-image-editter, [data-redactor-span]').removeAttr('style'); + this.core.editor().find('*[style]').not('img, figure, iframe, #redactor-image-box, #redactor-image-editter, [data-redactor-style-cache], [data-redactor-span]').removeAttr('style'); this.keydown.formatEmpty(e); this.code.syncFire = true; @@ -6855,7 +7059,8 @@ e.preventDefault(); var p = document.createElement('p'); - p.innerHTML = this.opts.invisibleSpace; + //p.innerHTML = this.opts.invisibleSpace; + p.innerHTML = '
'; var sel = this.selection.get(); var range = this.selection.range(sel); @@ -6902,7 +7107,6 @@ var node = $('

').append($current.clone()); $current.replaceWith(node); - var next = $(node).next(); if (typeof(next[0]) !== 'undefined' && next[0].tagName === 'BR') { @@ -7096,6 +7300,7 @@ if (this.utils.isSelectAll()) { this.focus.start(); + this.toolbar.setUnfixed(); return; } @@ -7725,7 +7930,14 @@ // escaping url var regexp = new RegExp('(' + href.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + regexB + ')', 'g'); - html = html.replace(regexp, '' + $.trim(text) + ''); + // target + var target = ''; + if (this.opts.pasteLinkTarget !== false) + { + target = ' target="' + this.opts.pasteLinkTarget + '"'; + } + + html = html.replace(regexp, '' + $.trim(text) + ''); } return html; @@ -8368,30 +8580,21 @@ }, toolbar: function() { - this.observe.buttons(); - this.observe.dropdowns(); + this.observe.buttons(); + this.observe.dropdowns(); }, buttons: function(e, btnName) { var current = this.selection.current(); var parent = this.selection.parent(); - if (e !== false) - { - this.button.setInactiveAll(); - } - else - { - this.button.setInactiveAll(btnName); - } + if (e !== false) this.button.setInactiveAll(); + else this.button.setInactiveAll(btnName); + if (e === false && btnName !== 'html') { - if ($.inArray(btnName, this.opts.activeButtons) !== -1) - { - this.button.toggleActive(btnName); - } - + if ($.inArray(btnName, this.opts.activeButtons) !== -1) this.button.toggleActive(btnName); return; } @@ -8410,7 +8613,6 @@ this.button.enable('horizontalrule'); } - $.each(this.opts.activeButtonsStates, $.proxy(function(key, value) { var parentEl = $(parent).closest(key, this.$editor[0]); @@ -9463,14 +9665,16 @@ }, nodes: function(tag) { - var filter = (typeof tag === 'undefined') ? [] : (($.isArray(tag)) ? tag : [tag]); + var filter = (typeof tag === 'undefined') ? [] : (($.isArray(tag)) ? tag : [tag]); var sel = this.selection.get(); var range = this.selection.range(sel); + var nodes = []; + var resultNodes = []; if (this.utils.isCollapsed()) { - return [this.selection.current()]; + nodes = [this.selection.current()]; } else { @@ -9484,7 +9688,6 @@ } // iterate - var nodes = []; while (node && node !== endNode) { nodes.push(node = this.selection.nextNode(node)); @@ -9497,33 +9700,31 @@ nodes.unshift(node); node = node.parentNode; } + } - // remove service nodes - var resultNodes = []; - $.each(nodes, function(i,s) + // remove service nodes + $.each(nodes, function(i,s) + { + if (s) { - if (s) - { - var tagName = (s.nodeType !== 1) ? false : s.tagName.toLowerCase(); - - if ($(s).hasClass('redactor-script-tag, redactor-selection-marker')) - { - return; - } - else if (tagName && filter.length !== 0 && $.inArray(tagName, filter) === -1) - { - return; - } - else - { - resultNodes.push(s); - } - } - }); + var tagName = (s.nodeType !== 1) ? false : s.tagName.toLowerCase(); - return (resultNodes.length === 0) ? [] : resultNodes; - } + if ($(s).hasClass('redactor-script-tag') || $(s).hasClass('redactor-selection-marker')) + { + return; + } + else if (tagName && filter.length !== 0 && $.inArray(tagName, filter) === -1) + { + return; + } + else + { + resultNodes.push(s); + } + } + }); + return (resultNodes.length === 0) ? [] : resultNodes; }, nextNode: function(node) { @@ -9883,7 +10084,7 @@ { // type, node, url, id data.status = true; - data.url = decodeURI(this.link.removeSelfHostFromUrl(data.url)); + data.url = decodeURI(data.url); this.storage.data[data.url] = data; }, @@ -9955,6 +10156,8 @@ this.button.$toolbar = this.$toolbar; this.button.setFormatting(); this.button.load(this.$toolbar); + + this.toolbar.setOverflow(); this.toolbar.setFixed(); }, @@ -9982,6 +10185,13 @@ } }, + setOverflow: function() + { + if (this.opts.toolbarOverflow) + { + this.$toolbar.addClass('redactor-toolbar-overflow'); + } + }, setFixed: function() { if (!this.opts.toolbarFixed || this.opts.toolbarExternal) @@ -10036,6 +10246,10 @@ }, this), late); + }, + setUnfixed: function() + { + this.toolbar.observeScrollDisable(); }, getBoxTop: function() { @@ -10336,6 +10550,9 @@ } }, this); + // before send + this.core.callback('uploadBeforeSend', xhr); + xhr.send(formData); }, onDrag: function(e) diff --git a/wcfsetup/install/files/js/3rdParty/redactor2/redactor.min.js b/wcfsetup/install/files/js/3rdParty/redactor2/redactor.min.js index 38d67895d6..ca132f6951 100644 --- a/wcfsetup/install/files/js/3rdParty/redactor2/redactor.min.js +++ b/wcfsetup/install/files/js/3rdParty/redactor2/redactor.min.js @@ -1,5 +1,6 @@ -!function(t){"use strict";function e(t,i){return new e.prototype.init(t,i)}Function.prototype.bind||(Function.prototype.bind=function(t){var e=this;return function(){return e.apply(t)}});var i=0;t.fn.redactor=function(i){var o=[],r=Array.prototype.slice.call(arguments,1);return"string"==typeof i?this.each(function(){var e,s=t.data(this,"redactor");if("-1"!==i.search(/\./)?(e=i.split("."),"undefined"!=typeof s[e[0]]&&(e=s[e[0]][e[1]])):e=s[i],"undefined"!=typeof s&&t.isFunction(e)){var n=e.apply(s,r);void 0!==n&&n!==s&&o.push(n)}else t.error('No such method "'+i+'" for Redactor')}):this.each(function(){t.data(this,"redactor",{}),t.data(this,"redactor",e(this,i))}),0===o.length?this:1===o.length?o[0]:o},t.Redactor=e,t.Redactor.VERSION="2.4",t.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"],t.Redactor.settings={},t.Redactor.opts={animation:!1,lang:"en",direction:"ltr",spellcheck:!0,overrideStyles:!0,scrollTarget:document,focus:!1,focusEnd:!1,clickToEdit:!1,structure:!1,tabindex:!1,minHeight:!1,maxHeight:!1,maxWidth:!1,plugins:!1,callbacks:{},placeholder:!1,linkify:!0,enterKey:!0,pastePlainText:!1,pasteImages:!0,pasteLinks:!0,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:!1,preSpaces:4,tabAsSpaces:!1,tabKey:!0,autosave:!1,autosaveName:!1,autosaveFields:!1,imageUpload:null,imageUploadParam:"file",imageUploadFields:!1,imageUploadForms:!1,imageTag:"figure",imageEditable:!0,imageCaption:!0,imagePosition:!1,imageResizable:!1,imageFloatMargin:"10px",dragImageUpload:!0,multipleImageUpload:!0,clipboardImageUpload:!0,fileUpload:null,fileUploadParam:"file",fileUploadFields:!1,fileUploadForms:!1,dragFileUpload:!0,s3:!1,linkNewTab:!1,linkTooltip:!0,linkNofollow:!1,linkSize:30,pasteLinkTarget:!1,videoContainerClass:"video-container",toolbar:!0,toolbarFixed:!0,toolbarFixedTarget:document,toolbarFixedTopOffset:0,toolbarExternal:!1,air:!1,airWidth:!1,formatting:["p","blockquote","pre","h1","h2","h3","h4","h5","h6"],formattingAdd:!1,buttons:["format","bold","italic","deleted","lists","image","file","link"],buttonsHide:[],buttonsHideOnMobile:[],script:!0,removeNewlines:!1,removeComments:!0,replaceTags:{b:"strong",i:"em",strike:"del"},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:!1,activeButtons:["deleted","italic","bold"],activeButtonsStates:{b:"bold",strong:"bold",i:"italic",em:"italic",del:"deleted",strike:"deleted"},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"}},type:"textarea",inline:!1,buffer:[],rebuffer:[],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:!0,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:t("").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.-]*/gi,linkvimeo:/https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,linkimage:/((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/gi,url:/(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/gi}},e.fn=t.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:function(e,o){return this.$element=t(e),this.uuid=i++,this.loadOptions(o),this.loadModules(),this.opts.clickToEdit&&!this.$element.hasClass("redactor-click-to-edit")?this.loadToEdit(o):(this.$element.hasClass("redactor-click-to-edit")&&this.$element.removeClass("redactor-click-to-edit"),this.reIsBlock=new RegExp("^("+this.opts.blockTags.join("|").toUpperCase()+")$","i"),this.reIsInline=new RegExp("^("+this.opts.inlineTags.join("|").toUpperCase()+")$","i"),this.opts.dragImageUpload=null===this.opts.imageUpload?!1:this.opts.dragImageUpload,this.opts.dragFileUpload=null===this.opts.fileUpload?!1:this.opts.dragFileUpload,this.formatting={},this.lang.load(),t.extend(this.opts.shortcuts,this.opts.shortcutsAdd),this.$editor=this.$element,this.detectType(),this.core.callback("start"),this.core.callback("startToEdit"),this.start=!0,void this.build.start())},detectType:function(){this.build.isInline()||this.opts.inline?this.opts.type="inline":this.build.isTag("DIV")?this.opts.type="div":this.build.isTag("PRE")&&(this.opts.type="pre")},loadToEdit:function(e){this.$element.on("click.redactor-click-to-edit",t.proxy(function(){this.initToEdit(e)},this)),this.$element.addClass("redactor-click-to-edit")},initToEdit:function(e){t.extend(e.callbacks,{startToEdit:function(){this.insert.node(this.marker.get(),!1)},initToEdit:function(){this.selection.restore(),this.clickToCancelStorage=this.code.get(),t(this.opts.clickToCancel).off(".redactor-click-to-edit"),t(this.opts.clickToCancel).show().on("click.redactor-click-to-edit",t.proxy(function(i){i.preventDefault(),this.core.destroy(),this.events.syncFire=!1,this.$element.html(this.clickToCancelStorage),this.core.callback("cancel",this.clickToCancelStorage),this.events.syncFire=!0,this.clickToCancelStorage="",t(this.opts.clickToCancel).hide(),t(this.opts.clickToSave).hide(),this.$element.on("click.redactor-click-to-edit",t.proxy(function(){this.initToEdit(e)},this)),this.$element.addClass("redactor-click-to-edit")},this)),t(this.opts.clickToSave).off(".redactor-click-to-edit"),t(this.opts.clickToSave).show().on("click.redactor-click-to-edit",t.proxy(function(i){i.preventDefault(),this.core.destroy(),this.core.callback("save",this.code.get()),t(this.opts.clickToCancel).hide(),t(this.opts.clickToSave).hide(),this.$element.on("click.redactor-click-to-edit",t.proxy(function(){this.initToEdit(e)},this)),this.$element.addClass("redactor-click-to-edit")},this))}}),this.$element.redactor(e),this.$element.off(".redactor-click-to-edit")},loadOptions:function(e){var i={};"undefined"!=typeof t.Redactor.settings.namespace?this.$element.hasClass(t.Redactor.settings.namespace)&&(i=t.Redactor.settings):i=t.Redactor.settings,this.opts=t.extend({},t.Redactor.opts,this.$element.data(),e),this.opts=t.extend(!0,this.opts,i)},getModuleMethods:function(t){return Object.getOwnPropertyNames(t).filter(function(e){return"function"==typeof t[e]})},loadModules:function(){for(var e=t.Redactor.modules.length,i=0;e>i;i++)this.bindModuleMethods(t.Redactor.modules[i])},bindModuleMethods:function(t){if("undefined"!=typeof this[t]){this[t]=this[t]();for(var e=this.getModuleMethods(this[t]),i=e.length,o=0;i>o;o++)this[t][e[o]]=this[t][e[o]].bind(this)}},air:function(){return{enabled:!1,collapsed:function(){this.opts.air&&this.selection.get().collapseToStart()},collapsedEnd:function(){this.opts.air&&this.selection.get().collapseToEnd()},build:function(){this.detect.isMobile()||(this.button.hideButtons(),this.button.hideButtonsOnMobile(),0!==this.opts.buttons.length&&(this.$air=this.air.createContainer(),this.opts.airWidth!==!1&&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,t.proxy(function(t){""!==this.selection.text()&&this.air.show(t)},this))))},append:function(){this.$air.appendTo("body")},createContainer:function(){return t("