diff options
| author | Christophe Simonis <chs@odoo.com> | 2016-01-12 16:11:28 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2016-01-12 16:11:28 +0100 |
| commit | 5f997bc4ef779fd45ae80d1465be1c1b64fdc8b5 (patch) | |
| tree | c0e76018db4158b8c1f30ae6d20b665bdaa98857 /addons/web_editor/static | |
| parent | 99b6cd8119211414602c739087c57d1966198f8e (diff) | |
| parent | 7fa6f73302709d7e7b6b19ebd16d338b3dd0e2db (diff) | |
[MERGE] forward port of branch saas-7 up to 7fa6f73
Diffstat (limited to 'addons/web_editor/static')
| -rw-r--r-- | addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js | 143 | ||||
| -rw-r--r-- | addons/web_editor/static/src/js/rte.js | 8 | ||||
| -rw-r--r-- | addons/web_editor/static/src/js/summernote.js | 136 |
3 files changed, 160 insertions, 127 deletions
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js index e2d234c9dbb..26b4ea86e46 100644 --- a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js +++ b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js @@ -2,8 +2,9 @@ define([ 'summernote/core/list', 'summernote/core/dom', 'summernote/core/key', - 'summernote/core/agent' -], function (list, dom, key, agent) { + 'summernote/core/agent', + 'summernote/core/range' +], function (list, dom, key, agent, range) { var Clipboard = function (handler) { var $paste; @@ -11,7 +12,7 @@ define([ // [workaround] getting image from clipboard // - IE11 and Firefox: CTRL+v hook // - Webkit: event.clipboardData - if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) { + if (agent.isMSIE && agent.browserVersion > 10) { $paste = $('<div />').attr('contenteditable', true).css({ position : 'absolute', left : -100000, @@ -76,6 +77,10 @@ define([ var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); var $editable = layoutInfo.editable(); + if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) { + return; + } + if (clipboardData && clipboardData.items && clipboardData.items.length) { var item = list.head(clipboardData.items); if (item.kind === 'file' && item.type.indexOf('image/') !== -1) { @@ -83,6 +88,138 @@ define([ } handler.invoke('editor.afterCommand', $editable); } + + event.preventDefault(); + + var html = clipboardData.getData("text/html"); + var $node = $('<div/>').html(html); + // if copying source did not provide html, default to plain text + if(!html) { + $node.text(clipboardData.getData("text/plain")).html(function(_, html){ + return html.replace(/\r?\n/g,'<br>'); + }); + } + pasteContent($node, layoutInfo, $editable); + }; + + /* + remove undesirable tag + filter classes and style attributes + remove undesirable attributes + */ + var filter_tag = function ($nodes, $editable) { + return $nodes.each(function() { + var $node = $(this); + + if ($node.attr('style')) { + var style = _.filter(_.compact($node.attr('style').split(/\s*;\s*/)), function (style) { + style = style.split(/\s*:\s*/); + return /width|height|color|background-color|font-weight|text-align|font-style|text-decoration/i.test(style[0]) && + !(style[1] === 'initial' || style[1] === 'inherit' || $node.css(style[0]) === $editable.css(style[0]) || + (style[0] === 'background-color' && style[1] === 'rgb(255, 255, 255)') || + (style[0] === 'color' && style[1] === 'rgb(0, 0, 0)')); + }).join(';'); + if (style.length) { + $node.attr('style', style); + } else { + $node.removeAttr('style'); + } + } + + if ($node.attr('class')) { + var classes = _.filter($node.attr('class').split(/\s+/), function (style) { + return /(^|\s)(fa|pull|text|bg)(\s|-|$)/.test(style); + }).join(' '); + if (classes.length) { + $node.attr('class', classes); + } else { + $node.removeAttr('class'); + } + } + }); + }; + + var pasteContent = function ($node, layoutInfo, $editable) { + $node.find('meta, script, style').remove(); + filter_tag($node.find('*'), $editable).removeAttr('title', 'alt', 'id', 'contenteditable'); + + /* + remove unless span + */ + $node.find('span:not([class]):not([style])').each(function () { + $(this).replaceWith($(this).contents()); + }); + $node.find('span + span').each(function () { + if ($(this).attr('class') === $(this).prev().attr('class') && $(this).attr('style') === $(this).prev().attr('style')) { + $(this).prev().append($(this).contents()); + $(this).remove(); + } + }); + + /* + reset architecture HTML node and add <p> tag + */ + var $arch = $('<div/>'); + var $last = $arch; + $node.contents().each(function () { + if (dom.isBR(this)) { + $(this).remove(); + $last = $('<p/>'); + $arch.append($last); + } else if (/h[0-9]+|li|table|p/i.test(this.tagName)) { + $last = $('<p/>'); + $arch.append(this).append($last); + } else if (this.nodeType !== Node.COMMENT_NODE) { + $last.append(this); + } + }); + $arch.find(':not([class]):not([style]):empty, p:empty').remove(); + + /* + history + */ + $editable.data('NoteHistory').recordUndo($editable, "paste"); + + /* + remove selected content + */ + var r = range.create(); + if (!r.isCollapsed()) { + r = r.deleteContents(); + r.select(); + } + + /* + insert content + */ + var $nodes = $(); + $editable.on('DOMNodeInserted', function (event) { + $nodes = $nodes.add(event.originalEvent.target); + }); + window.document.execCommand('insertHTML', false, $arch.html()); + $editable.off('DOMNodeInserted'); + + /* + clean insterted content + */ + var $span = $nodes.filter('span'); + $span = $span.first().add($span.last()); + $span = $span.add($span.prev('span')); + $span = $span.add($span.next('span')); + filter_tag($span, $editable); + $span.not('[span], [style]').each(function () { + _.each(this.childNodes, function (node) { + $(node.parentNode).after(node); + }); + $(this).remove(); + }); + r = range.create(); + if (!dom.isText(r.ec)) { + r = range.create(r.sc.childNodes[r.so], dom.nodeLength(r.sc.childNodes[r.so])); + } + r.clean().select(); + + $editable.trigger('content_changed'); }; }; diff --git a/addons/web_editor/static/src/js/rte.js b/addons/web_editor/static/src/js/rte.js index f50b93912ae..85721ba0387 100644 --- a/addons/web_editor/static/src/js/rte.js +++ b/addons/web_editor/static/src/js/rte.js @@ -508,6 +508,10 @@ var RTE = Widget.extend({ var $target = $(event.target); var $editable = $target.closest('.o_editable'); + if (!$editable.size()) { + return; + } + if ($target.is('a')) { $target.attr('contenteditable', true); setTimeout(function () { @@ -518,10 +522,6 @@ var RTE = Widget.extend({ $editable.attr('contenteditable', true); } - if (!$editable.size()) { - return; - } - if (this && this.$last && (!$editable.size() || this.$last[0] != $editable[0])) { var $destroy = this.$last; history.splitNext(); diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js index 14db16a831c..6ed7be2039f 100644 --- a/addons/web_editor/static/src/js/summernote.js +++ b/addons/web_editor/static/src/js/summernote.js @@ -144,13 +144,13 @@ dom.mergeFilter = function (prev, cur, parent) { return true; } if (prev && !dom.isBR(prev) && dom.isEqual(prev, cur) && - ((prev.tagName && window.getComputedStyle(prev).display === "inline" && - cur.tagName && window.getComputedStyle(cur).display === "inline"))) { + ((prev.tagName && dom.getComputedStyle(prev).display === "inline" && + cur.tagName && dom.getComputedStyle(cur).display === "inline"))) { return true; } if (dom.isEqual(parent, cur) && - ((parent.tagName && window.getComputedStyle(parent).display === "inline" && - cur.tagName && window.getComputedStyle(cur).display === "inline"))) { + ((parent.tagName && dom.getComputedStyle(parent).display === "inline" && + cur.tagName && dom.getComputedStyle(cur).display === "inline"))) { return true; } if (parent && cur.tagName === "FONT" && (!cur.firstChild || (!cur.attributes.getNamedItem('style') && !cur.className.length))) { @@ -377,7 +377,7 @@ dom.removeSpace = function (node, begin, so, end, eo) { if (cur === begin) add = true; - if (cur.tagName && cur.tagName !== "SCRIPT" && cur.tagName !== "STYLE" && window.getComputedStyle(cur).whiteSpace !== "pre") { + if (cur.tagName && cur.tagName !== "SCRIPT" && cur.tagName !== "STYLE" && dom.getComputedStyle(cur).whiteSpace !== "pre") { __remove_space(cur); } @@ -592,7 +592,7 @@ dom.scrollIntoViewIfNeeded = function (node) { // get if a parent have a scrollbar parent = node.parentNode; while (parent != offsetParent && - (parent.tagName === "BODY" || ["auto", "scroll"].indexOf(window.getComputedStyle(parent).overflowY) === -1)) { + (parent.tagName === "BODY" || ["auto", "scroll"].indexOf(dom.getComputedStyle(parent).overflowY) === -1)) { parent = parent.parentNode; } node = parent; @@ -605,7 +605,7 @@ dom.scrollIntoViewIfNeeded = function (node) { offsetParent = node.offsetParent; } - if ((node.tagName === "BODY" || ["auto", "scroll"].indexOf(window.getComputedStyle(node).overflowY) !== -1) && + if ((node.tagName === "BODY" || ["auto", "scroll"].indexOf(dom.getComputedStyle(node).overflowY) !== -1) && (node.scrollTop + node.clientHeight) < (elY + elH)) { node.scrollTop = (elY + elH) - node.clientHeight; } @@ -710,7 +710,7 @@ dom.orderStyle = function (node) { * @return {String} className */ dom.orderClass = function (node) { - var className = node.getAttribute('class'); + var className = node.getAttribute && node.getAttribute('class'); if (!className) return null; className = className.replace(/[\s\n\r]+/, ' ').replace(/^ | $/g, '').replace(/ +/g, ' '); if (!className.length) { @@ -753,6 +753,11 @@ dom.moveContent = function (from, to) { } }; +dom.getComputedStyle = function (node) { + return node.nodeType == Node.COMMENT_NODE ? {} : window.getComputedStyle(node); +}; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////// range.WrappedRange.prototype.reRange = function (keep_end, isNotBreakable) { @@ -1221,7 +1226,6 @@ function remove_table_content(r) { node.parentNode && !$(node.parentNode).hasClass('o_editable')); } } - event.preventDefault(); return false; } @@ -1351,7 +1355,7 @@ $.summernote.pluginEvents.delete = function (event, editor, layoutInfo) { r = range.create(temp2, 0); r.select(); - if ((dom.isText(temp) || window.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || window.getComputedStyle(temp2).display === "inline")) { + if ((dom.isText(temp) || dom.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || dom.getComputedStyle(temp2).display === "inline")) { if (dom.isText(temp2)) { temp2.textContent = temp2.textContent.replace(/^\s*\S/, ''); } else { @@ -1498,7 +1502,7 @@ $.summernote.pluginEvents.backspace = function (event, editor, layoutInfo) { r = range.create(temp2, temp2.textContent.length, temp2, temp2.textContent.length); r.select(); - if ((dom.isText(temp) || window.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || window.getComputedStyle(temp2).display === "inline")) { + if ((dom.isText(temp) || dom.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || dom.getComputedStyle(temp2).display === "inline")) { if (dom.isText(temp2)) { temp2.textContent = temp2.textContent.replace(/\S\s*$/, ''); } else { @@ -2022,7 +2026,7 @@ $.summernote.pluginEvents.applyFont = function (event, editor, layoutInfo, color } if (size) { font.style.fontSize = "inherit"; - if (!isNaN(size) && Math.abs(parseInt(window.getComputedStyle(font).fontSize, 10)-size)/size > 0.05) { + if (!isNaN(size) && Math.abs(parseInt(dom.getComputedStyle(font).fontSize, 10)-size)/size > 0.05) { font.style.fontSize = size + "px"; } } @@ -2294,124 +2298,16 @@ eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) { ////////////////////////////////////////////////////////////////////////////////////////////////////////// -function summernote_paste (event) { - - // keep norma feature if copy a picture - var clipboardData = event.originalEvent.clipboardData; - if (!_.isEmpty(clipboardData.items)) { - var item = list.last(clipboardData.items); - var isClipboardImage = item.kind === 'file' && item.type.indexOf('image/') !== -1; - if (isClipboardImage) { - return true; - } - } - - if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) { - return; - } - - $(event.target).trigger('content_changed'); - - var r = range.create(); - if (!r.isCollapsed()) { - r = r.deleteContents(); - r.select(); - } - - var html = clipboardData.getData("text/html"); - var $node = $('<div/>').html(html); - // if copying source did not provide html, default to plain text - if(!html) { - $node.text(clipboardData.getData("text/plain")).html(function(_, html){ - return html.replace(/\r?\n/g,'<br>'); - }); - } - - /* - remove undesirable tag - filter classes and style attributes - remove undesirable attributes - */ - $node.find('meta, script, style').remove(); - $node.find('*').each(function() { - var $node = $(this); - - if ($node.attr('style')) { - var style = _.filter($node.attr('style').split(/\s*;\s*/), function (style) { - return /width|height|color|background-color|font-weight|text-align|font-style|text-decoration/i.test(style) && $node.css(style.split(':')[0]) !== $('body').css(style.split(':')[0]); - }).join(';'); - if (style.length) { - $node.attr('style', style); - } else { - $node.removeAttr('style'); - } - } - - if ($node.attr('class')) { - var classes = _.filter($node.attr('class').split(/\s+/), function (style) { - return /(^|\s)(fa|pull|text|bg)(\s|-|$)/.test(style); - }).join(' '); - if (classes.length) { - $node.attr('class', classes); - } else { - $node.removeAttr('class'); - } - } - }).removeAttr('title', 'alt', 'id', 'contenteditable'); - - /* - remove unless span - */ - $node.find('span:not([class]):not([style])').each(function () { - $(this).replaceWith($(this).contents()); - }); - $node.find('span + span').each(function () { - if ($(this).attr('class') === $(this).prev().attr('class') && $(this).attr('style') === $(this).prev().attr('style')) { - $(this).prev().append($(this).contents()); - $(this).remove(); - } - }); - - /* - reset architecture HTML node and add <p> tag - */ - var $arch = $('<div><p/></div>'); - var $last = $arch.find('p'); - $node.contents().each(function () { - if (dom.isBR(this)) { - $(this).remove(); - $last = $('<p/>'); - $arch.append($last); - } else if (/h[0-9]+|li|table|p/i.test(this.tagName)) { - $last = $('<p/>'); - $arch.append(this).append($last); - } else { - $last.append(this); - } - }); - $last.filter(':empty').remove(); - - /* - insert content - */ - window.document.execCommand('insertHTML', false, $arch.html()); - - event.preventDefault(); - return false; -} - var fn_attach = eventHandler.attach; eventHandler.attach = function (oLayoutInfo, options) { var $editable = oLayoutInfo.editor().hasClass('note-editable') ? oLayoutInfo.editor() : oLayoutInfo.editor().find('.note-editable'); fn_attach.call(this, oLayoutInfo, options); - $(document).off("paste", summernote_paste).on("paste",'[contenteditable]', summernote_paste); $editable.on("scroll", summernote_table_scroll); }; var fn_detach = eventHandler.detach; eventHandler.detach = function (oLayoutInfo, options) { var $editable = oLayoutInfo.editor().hasClass('note-editable') ? oLayoutInfo.editor() : oLayoutInfo.editor().find('.note-editable'); fn_detach.call(this, oLayoutInfo, options); - $(document).off("paste", summernote_paste); $editable.off("scroll", summernote_table_scroll); $('.o_table_handler').remove(); }; |
