diff options
| author | qsm-odoo <qsm@odoo.com> | 2018-04-27 12:28:57 +0200 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2018-04-27 12:28:57 +0200 |
| commit | ce6f8632cc272ca616ebc6bdedfa6347f4592b25 (patch) | |
| tree | a691acff358bab3a90e3ebd3ec68e28a41ee0a43 /addons/web_editor | |
| parent | 409970c188adaf79bc45c7e29b3b2e111c2c7775 (diff) | |
[FIX] web_editor: update summernote copy-paste feature
The copy-paste feature of summernote was messy and led most of the time
to breaking the template you were trying to edit. While it is difficult
to solve as it mostly comes from the lib itself and that the lib is in
a complicated state as Odoo had to overridde part of its internal code
for its own purposes, this commit hopes to solve the problem by updating
only the copy-paste feature to the latest summernote version.
Of course, as summernote changed a lot meanwhile, it was not possible to
just take the up-to-date summernote file. This commit refactores the
up-to-date summernote clipboard code so that it fits the old summernote
version Odoo is using.
Note: the main problems occurred while using Windows/Mac and not Linux.
opw-1837818
Diffstat (limited to 'addons/web_editor')
| -rw-r--r-- | addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js | 287 |
1 files changed, 36 insertions, 251 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 955b49437a8..4cd9088da75 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 @@ -1,256 +1,41 @@ define([ - 'summernote/core/list', - 'summernote/core/dom', - 'summernote/core/key', - 'summernote/core/agent', - 'summernote/core/range' + 'summernote/core/list', + 'summernote/core/dom', + 'summernote/core/key', + 'summernote/core/agent', + 'summernote/core/range' ], function (list, dom, key, agent, range) { - var Clipboard = function (handler) { - var $paste; - - this.attach = function (layoutInfo) { - // [workaround] getting image from clipboard - // - IE11 and Firefox: CTRL+v hook - // - Webkit: event.clipboardData - if (agent.isMSIE && agent.browserVersion > 10) { - $paste = $('<div />').attr('contenteditable', true).css({ - position : 'absolute', - left : -100000, - opacity : 0 - }); - - layoutInfo.editable().on('keydown', function (e) { - if (e.ctrlKey && e.keyCode === key.code.V) { - handler.invoke('saveRange', layoutInfo.editable()); - $paste.focus(); - - setTimeout(function () { - pasteByHook(layoutInfo); - }, 0); - } - }); - - layoutInfo.editable().before($paste); - } else { - layoutInfo.editable().on('paste', pasteByEvent); - } - }; - - var pasteByHook = function (layoutInfo) { - var $editable = layoutInfo.editable(); - var node = $paste[0].firstChild; - - if (dom.isImg(node)) { - var dataURI = node.src; - var decodedData = atob(dataURI.split(',')[1]); - var array = new Uint8Array(decodedData.length); - for (var i = 0; i < decodedData.length; i++) { - array[i] = decodedData.charCodeAt(i); - } - - var blob = new Blob([array], { type : 'image/png' }); - blob.name = 'clipboard.png'; - - handler.invoke('restoreRange', $editable); - handler.invoke('focus', $editable); - handler.insertImages(layoutInfo, [blob]); - } else { - var pasteContent = $('<div />').html($paste.html()).html(); - handler.invoke('restoreRange', $editable); - handler.invoke('focus', $editable); - - if (pasteContent) { - handler.invoke('pasteHTML', $editable, pasteContent); - } - } - - $paste.empty(); - }; - - /** - * paste by clipboard event - * - * @param {Event} event - */ - var pasteByEvent = function (event) { - var clipboardData = event.originalEvent.clipboardData; - 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) { - handler.insertImages(layoutInfo, [item.getAsFile()]); - } - 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 and unwant font - */ - $node.find('span, font').filter(':not([class]):not([style])').each(function () { - $(this).replaceWith($(this).contents()); - }); - $node.find('span + span').each(function () { - - if (dom.isText(this.previousSibling)) { - if (dom.isVisibleText(this.previousSibling)) { - return; - } else { // keep space between 2 tags, but can merge the both tags - $(this).prev().append(this.previousSibling); - } - } - if ($(this).attr('class') === $(this).prev().attr('class') && $(this).attr('style') === $(this).prev().attr('style')) { - $(this).prev().append($(this).contents()); - $(this).remove(); - } - }); - - // remove empty table row and td - var $tdr; - while(($tdr = $node.find('tr:empty, td:empty, th:empty, tbody:empty, t-head:empty, table:empty')) && $tdr.length) { - $tdr.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 ($arch.is(':empty') && dom.isText(this)) { - $last = $('<p/>').append(this); - $arch.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(); - } - - // If only pasting a <p/> element in an unique <p/> element, only paste - // the <p/> element text - var $p = $arch.children('p'); - var onlyAP = ($p.length === 1 && $arch.children().length === 1); - if (onlyAP) { - var $p1 = $(r.sc).closest('p'); - var $p2 = $(r.ec).closest('p'); - if ($p1.length && $p2.length && $p1[0] === $p2[0]) { - $arch.html($p.text()); - } - } - - /* - 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'); + // ODOO override: use 0.8.10 version of this, adapted for the old summernote + // version odoo is using + var Clipboard = function (handler) { + /** + * paste by clipboard event + * + * @param {Event} event + */ + var pasteByEvent = function (event) { + if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) { + // ODOO override: from old summernote version + return; + } + + var clipboardData = event.originalEvent.clipboardData; + var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); + var $editable = layoutInfo.editable(); + + if (clipboardData && clipboardData.items && clipboardData.items.length) { + var item = list.head(clipboardData.items); + if (item.kind === 'file' && item.type.indexOf('image/') !== -1) { + handler.insertImages(layoutInfo, [item.getAsFile()]); + } + handler.invoke('editor.afterCommand', $editable); + } + }; + + this.attach = function (layoutInfo) { + layoutInfo.editable().on('paste', pasteByEvent); + }; }; - }; - return Clipboard; + return Clipboard; }); |
