[FIX] web_editor: copy-paste content keep architecture

The paste don't keep the architecture, usability team want to past the architecture but remove extra style and wrong node like span.
This commit is contained in:
Christophe Matthieu
2015-10-26 11:43:36 +01:00
parent d7b5eeabeb
commit a291adb314
+81 -85
View File
@@ -134,7 +134,7 @@ dom.hasProgrammaticStyle = function (node) {
};
dom.mergeFilter = function (prev, cur, parent) {
// merge text nodes
if (prev && (dom.isText(prev) || (dom.pasteTextApply.indexOf(prev.tagName) !== -1 && prev !== cur.parentNode)) && dom.isText(cur)) {
if (prev && (dom.isText(prev) || ("H1 H2 H3 H4 H5 H6 LI P".indexOf(prev.tagName) !== -1 && prev !== cur.parentNode)) && dom.isText(cur)) {
return true;
}
if (prev && prev.tagName === "P" && dom.isText(cur)) {
@@ -444,75 +444,6 @@ dom.removeSpace = function (node, begin, so, end, eo) {
dom.node = function (node) {
return node.tagName ? node : node.parentNode;
};
dom.pasteTextApply = "h1 h2 h3 h4 h5 h6 li p".split(" ");
dom.pasteTextClose = "h1 h2 h3 h4 h5 h6 p b bold i u code sup strong small li pre".split(" ");
dom.pasteText = function (textNode, offset, text, isOnlyText) {
// clean the node
var node = dom.node(textNode);
var data = dom.merge(node.parentNode, textNode, offset, textNode, offset, null, true);
data = dom.removeSpace(node.parentNode, data.sc, data.so, data.ec, data.eo);
// Break the text node up
if (data.sc.tagName) {
if (node === data.sc.parentNode) {
data.sc = node.insertBefore(document.createTextNode(" "), data.sc);
} else if (node.firstChild && !dom.isBR(dom.firstChild(node))) {
data.sc = node.insertBefore(document.createTextNode(" "), dom.firstChild(node));
} else if (dom.isBR(node)) {
data.sc = node.parentNode.insertBefore(document.createTextNode(" "), node);
} else {
data.sc = node.appendChild(document.createTextNode(" "));
}
data.so = 0;
}
var first = data.sc;
var try_to_clean = [first, first.splitText(data.so)];
isOnlyText = isOnlyText || !text.match('\n');
var sc, so, ec, eo;
if (!isOnlyText) {
var paste_after = dom.isBR(node) ? node.parentElement : node;
// tag to close and open
var tag = paste_after.tagName.toLowerCase();
if(dom.pasteTextApply.indexOf(tag) === -1) {
text = text.split('\n').join("<br/>");
paste_after = data.sc;
} else {
text = "<"+tag+">"+text.split('\n').join("</"+tag+"><"+tag+">")+"</"+tag+">";
try_to_clean.push(paste_after);
}
var nodes = _.toArray($('<div/>').html(text).prop('childNodes'));
sc = nodes[0];
so = 0;
ec = dom.lastChild(nodes[nodes.length - 1]);
eo = dom.nodeLength(ec);
// split parent node and insert text
if(!dom.isText(paste_after) && dom.pasteTextClose.indexOf(tag) !== -1) {
try_to_clean.push(dom.splitTree(paste_after, {node: first, offset: data.so}));
$(paste_after).after( nodes );
} else {
$(paste_after).after( nodes );
}
} else {
sc = ec = first;
so = dom.nodeLength(first);
eo = so + text.length;
first.appendData( text );
}
// move caret
range.create(sc, so, ec, eo).clean().select();
_(try_to_clean).each(function(node){
_(dom.listDescendant(node).reverse().concat(node)).each(function(subnode){
if(dom.isEmpty(subnode) || (dom.isText(subnode) && !dom.isVisibleText(subnode))) $(subnode).remove();
});
});
};
dom.removeBetween = function (sc, so, ec, eo, towrite) {
if (ec.tagName) {
if (ec.childNodes[eo]) {
@@ -2301,6 +2232,7 @@ 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 (clipboardData.items) {
@@ -2311,36 +2243,100 @@ function summernote_paste (event) {
}
}
var $editable = $(event.currentTarget);
$editable = $editable.is('[contenteditable]') ? $editable : $editable.find('[contenteditable]');
$editable.data('NoteHistory').recordUndo($editable);
if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) {
return;
}
if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) === -1) {
var r = range.create();
if (!r.isCollapsed()) {
r = r.deleteContents();
r.select();
$(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);
/*
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 ($(this).attr('style')) {
var style = _.filter($(this).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');
}
}
var text = $('<div />').text(clipboardData.getData("text/plain").toString()).html();
dom.pasteText(r.sc, r.so, text);
event.preventDefault();
return false;
}
if ($(this).attr('class')) {
var classes = _.filter($(this).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());
});
/*
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);
oLayoutInfo.editor().on("paste", summernote_paste);
$(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);
oLayoutInfo.editor().off("paste", summernote_paste);
$(document).off("paste", summernote_paste);
$editable.off("scroll", summernote_table_scroll);
$('.o_table_handler').remove();
};