summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web_editor/static/src')
-rw-r--r--addons/web_editor/static/src/js/editor.js2
-rw-r--r--addons/web_editor/static/src/js/snippets.editor.js85
-rw-r--r--addons/web_editor/static/src/js/snippets.options.js26
-rw-r--r--addons/web_editor/static/src/js/summernote.js29
-rw-r--r--addons/web_editor/static/src/js/widgets.js18
5 files changed, 97 insertions, 63 deletions
diff --git a/addons/web_editor/static/src/js/editor.js b/addons/web_editor/static/src/js/editor.js
index f9255716697..4480101bf6a 100644
--- a/addons/web_editor/static/src/js/editor.js
+++ b/addons/web_editor/static/src/js/editor.js
@@ -144,6 +144,8 @@ editor.Class = Widget.extend({
d.resolve();
}).on('hidden.bs.modal', function () {
d.reject();
+ }).on('keydown.dismiss.bs.modal', function (event) {
+ event.stopImmediatePropagation();
});
d.always(function () {
$dialog.remove();
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index cc380833074..3de9b71d5f8 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -531,7 +531,8 @@ var BuildingBlock = Widget.extend({
this.snippets.push($snippet.get(0));
}
this.$active_snipped_id = $snippet;
- this.create_overlay(this.$active_snipped_id);
+ this.create_snippet_editor(this.$active_snipped_id);
+ this.cover_target($snippet.data('overlay'), $snippet);
this.snippet_focus($snippet);
}
this.$snippet.trigger('snippet-activated', $snippet);
@@ -539,13 +540,11 @@ var BuildingBlock = Widget.extend({
$snippet.trigger('snippet-activated', $snippet);
}
},
- create_overlay: function ($snippet) {
+ create_snippet_editor: function ($snippet) {
if (typeof $snippet.data("snippet-editor") === 'undefined') {
- var $targets = this.activate_overlay_zones($snippet);
- if (!$targets.length) return;
+ if (!this.activate_overlay_zones($snippet).length) return;
$snippet.data("snippet-editor", new Editor(this, $snippet));
}
- this.cover_target($snippet.data('overlay'), $snippet);
},
// activate drag and drop for the snippets in the snippet toolbar
@@ -657,22 +656,12 @@ var BuildingBlock = Widget.extend({
animation.start(true, $target);
- // drop_and_build_snippet
- self.create_overlay($target);
- if ($target.data("snippet-editor")) {
- $target.data("snippet-editor").drop_and_build_snippet();
- }
- for (var k in self.templateOptions) {
- self.templateOptions[k].selector.all($target).each(function () {
- var $snippet = $(this);
- self.create_overlay($snippet);
- if ($snippet.data("snippet-editor")) {
- $snippet.data("snippet-editor").drop_and_build_snippet();
- }
- });
- }
+ self.call_for_all_snippets($target, function (editor, $snippet) {
+ editor.drop_and_build_snippet();
+ });
+ self.create_snippet_editor($target);
+ self.cover_target($target.data('overlay'), $target);
$target.closest(".o_editable").trigger("content_changed");
- // end
self.make_active($target);
},0);
@@ -683,6 +672,20 @@ var BuildingBlock = Widget.extend({
});
},
+ // call a method on a snippet and all his children
+ call_for_all_snippets: function ($snippet, callback) {
+ var self = this;
+ $snippet.add(globalSelector.all($snippet)).each(function () {
+ var $snippet = $(this);
+ setTimeout(function () {
+ self.create_snippet_editor($snippet);
+ if ($snippet.data("snippet-editor")) {
+ callback.call(self, $snippet.data("snippet-editor"), $snippet);
+ }
+ });
+ });
+ },
+
// return the original snippet in the editor bar from a snippet id (string)
get_snippet_from_id: function(id){
return $('.oe_snippet').filter(function(){
@@ -845,14 +848,12 @@ var BuildingBlock = Widget.extend({
var timer;
$target.closest('.o_editable').on("content_changed", function (event) {
- if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) {
- clearTimeout(timer);
- timer = setTimeout(function () {
- if ($target.data('overlay')) {
- self.cover_target($target.data('overlay'), $target);
- }
- },50);
- }
+ clearTimeout(timer);
+ timer = setTimeout(function () {
+ if ($target.data('overlay') && $target.data('overlay').hasClass("oe_active")) {
+ self.cover_target($target.data('overlay'), $target);
+ }
+ },50);
});
var resize = function () {
@@ -985,7 +986,9 @@ var Editor = Class.extend({
self.buildingBlock.editor_busy = false;
self.get_parent_block();
- setTimeout(function () {self.buildingBlock.create_overlay(self.$target);},0);
+ setTimeout(function () {
+ self.BuildingBlock.cover_target(self.$target.data('overlay'), self.$target);
+ },0);
},
load_style_options: function () {
@@ -1022,7 +1025,10 @@ var Editor = Class.extend({
get_parent_block: function () {
var self = this;
var $button = this.$overlay.find('.oe_snippet_parent');
- var $parent = globalSelector.closest(this.$target.parent());
+ var $parent = this.$target.parents().filter(function () { return $(this).data("snippet-editor"); });
+ if (!$parent.length) {
+ $parent = globalSelector.closest(this.$target.parent());
+ }
if ($parent.length) {
$button.removeClass("hidden");
$button.off("click").on('click', function (event) {
@@ -1056,12 +1062,13 @@ var Editor = Class.extend({
var $clone = this.$target.clone(false);
this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
-
+
this.$target.after($clone);
- for (var i in this.styles){
- this.styles[i].on_clone($clone);
- }
- this.buildingBlock.create_overlay(this.$target);
+ this.BuildingBlock.call_for_all_snippets($clone, function (editor, $snippet) {
+ for (var i in editor.styles){
+ editor.styles[i].on_clone($snippet);
+ }
+ });
return false;
},
@@ -1072,9 +1079,11 @@ var Editor = Class.extend({
this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0));
- for (var i in this.styles){
- this.styles[i].on_remove();
- }
+ this.BuildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) {
+ for (var i in editor.styles){
+ editor.styles[i].on_remove();
+ }
+ });
delete this.buildingBlock.snippets[index];
var $editable = this.$target.closest(".o_editable");
diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js
index 4dce2e358ed..df4ec303894 100644
--- a/addons/web_editor/static/src/js/snippets.options.js
+++ b/addons/web_editor/static/src/js/snippets.options.js
@@ -319,20 +319,20 @@ var colorpicker = Option.extend({
var background = Option.extend({
start: function ($change_target) {
- this.$bg = $change_target || this.$target;
+ this.$target = $change_target || this.$target;
this._super();
- var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
- if (this.$bg.hasClass('oe_custom_bg')) {
+ var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ if (this.$target.hasClass('oe_custom_bg')) {
this.$el.find('li[data-choose_image]').data("background", src).attr("data-background", src);
}
},
background: function(type, value, $li) {
if (value && value.length) {
- this.$bg.attr("style", 'background-image: url(' + value + '); ' + (this.$bg.attr("style") || '').replace(/background-image:[^;]+/, '') );
- this.$bg.addClass("oe_img_bg");
+ this.$target.attr("style", 'background-image: url(' + value + '); ' + (this.$target.attr("style") || '').replace(/background-image:[^;]+/, '') );
+ this.$target.addClass("oe_img_bg");
} else {
- this.$bg.css("background-image", "");
- this.$bg.removeClass("oe_img_bg").removeClass("oe_custom_bg");
+ this.$target.css("background-image", "");
+ this.$target.removeClass("oe_img_bg").removeClass("oe_custom_bg");
}
},
select_class : function(type, value, $li) {
@@ -345,7 +345,7 @@ var background = Option.extend({
var self = this;
var $image = $('<img class="hidden"/>');
$image.attr("src", value);
- $image.appendTo(self.$bg);
+ $image.appendTo(self.$target);
var _editor = new widget.MediaDialog(null, $image[0]);
_editor.appendTo(document.body);
@@ -356,8 +356,8 @@ var background = Option.extend({
$image.remove();
self.$el.find('li[data-choose_image]').data("background", value).attr("data-background", value);
self.background(type, value,$li);
- self.$bg.addClass('oe_custom_bg');
- self.$bg.trigger("snippet-option-change", [self]);
+ self.$target.addClass('oe_custom_bg');
+ self.$target.trigger("snippet-option-change", [self]);
self.set_active();
});
_editor.on('cancel', self, function () {
@@ -366,9 +366,13 @@ var background = Option.extend({
},
set_active: function () {
var self = this;
- var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ var src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
this._super();
+ if (this.$target.hasClass('oe_custom_bg')) {
+ this.$el.find('li[data-choose_image]').data("background", src).attr("data-background", src);
+ }
+
this.$el.find('li[data-background]:not([data-background=""])')
.removeClass("active")
.each(function () {
diff --git a/addons/web_editor/static/src/js/summernote.js b/addons/web_editor/static/src/js/summernote.js
index 46b21aeec88..235bd6c3500 100644
--- a/addons/web_editor/static/src/js/summernote.js
+++ b/addons/web_editor/static/src/js/summernote.js
@@ -26,7 +26,7 @@ dom.hasContentAfter = function (node) {
var next;
while (node.nextSibling) {
next = node.nextSibling;
- if (next.tagName || next.textContent.match(/\S|\u00A0/) || dom.isBR(next)) return next;
+ if (next.tagName || dom.isVisibleText(next) || dom.isBR(next)) return next;
node = next;
}
};
@@ -34,7 +34,7 @@ dom.hasContentBefore = function (node) {
var prev;
while (node.previousSibling) {
prev = node.previousSibling;
- if (prev.tagName || prev.textContent.match(/\S|\u00A0/) || dom.isBR(prev)) return prev;
+ if (prev.tagName || dom.isVisibleText(prev) || dom.isBR(prev)) return prev;
node = prev;
}
};
@@ -138,7 +138,7 @@ dom.mergeFilter = function (prev, cur, parent) {
if (prev && prev.tagName === "P" && dom.isText(cur)) {
return true;
}
- if (prev && dom.isText(cur) && !cur.textContent.match(/\S|\u00A0/) && (dom.isText(prev) || prev.textContent.match(/\S|\u00A0/))) {
+ if (prev && dom.isText(cur) && !dom.isVisibleText(cur) && (dom.isText(prev) || dom.isVisibleText(prev))) {
return true;
}
if (prev && !dom.isBR(prev) && dom.isEqual(prev, cur) &&
@@ -382,7 +382,7 @@ dom.removeSpace = function (node, begin, so, end, eo) {
if (cur === end) add = false;
// remove begin empty text node
- if (node.childNodes.length > 1 && dom.isText(cur) && !cur.textContent.match(/\S|\u00A0/)) {
+ if (node.childNodes.length > 1 && dom.isText(cur) && !dom.isVisibleText(cur)) {
removed = true;
if (cur === begin) {
so = 0;
@@ -579,7 +579,7 @@ dom.removeBetween = function (sc, so, ec, eo, towrite) {
}
eo = so;
- if(!dom.isBR(sc) && !sc.textContent.match(/\S|\u00A0/) && !dom.isText(dom.hasContentBefore(sc)) && !dom.isText(dom.hasContentAfter(sc))) {
+ if(!dom.isBR(sc) && !dom.isVisibleText(sc) && !dom.isText(dom.hasContentBefore(sc)) && !dom.isText(dom.hasContentAfter(sc))) {
ancestor = dom.node(sc);
var text = document.createTextNode('\u00A0');
$(sc).before(text);
@@ -699,6 +699,9 @@ dom.isContentEditable = function (node) {
return $(node).closest('[contenteditable]').is('[contenteditable="true"]');
};
+dom.isPre = function (node) {
+ return node.tagName === "PRE";
+};
dom.isFont = function (node) {
var nodeName = node && node.nodeName.toUpperCase();
return node && (nodeName === "FONT" ||
@@ -1025,6 +1028,8 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
}
var node = dom.node(r.sc);
+ var exist = r.sc.childNodes[r.so] || r.sc;
+ exist = dom.isVisibleText(exist) || dom.isBR(exist) ? exist : dom.hasContentAfter(exist) || (dom.hasContentBefore(exist) || exist);
var last = node;
while (node && dom.isSplitable(node) && !dom.isList(node)) {
last = node;
@@ -1042,7 +1047,7 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
} while (node && dom.isBR(node));
// create an other br because the user can't see the new line with only br in a block
- if (!node) {
+ if (!node && (!br.nextElementSibling || !dom.isBR(br.nextElementSibling))) {
$(br).before($("<br/>")[0]);
}
node = br.nextSibling || br;
@@ -1051,7 +1056,11 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
node = br;
} else if (!r.so && r.isOnList() && !r.sc.textContent.length && !dom.ancestor(r.sc, dom.isLi).nextElementSibling) {
// double enter on the end of a list = new line out of the list
- node = $('<p></p>').append(br).insertAfter(dom.ancestor(r.sc, dom.isList))[0];
+ $('<p></p>').append(br).insertAfter(dom.ancestor(r.sc, dom.isList));
+ node = br;
+ } else if (dom.isBR(exist) && $(r.sc).closest('blockquote, pre').length && !dom.hasContentAfter($(exist.parentNode).closest('blockquote *, pre *').length ? exist.parentNode : exist)) {
+ // double enter on the end of a blockquote & pre = new line out of the list
+ $('<p></p>').append(br).insertAfter($(r.sc).closest('blockquote, pre'));
node = br;
} else if (last === r.sc) {
if (dom.isBR(last)) {
@@ -1071,7 +1080,7 @@ $.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
$(cur).html(br);
}
}
- if (!node.textContent.match(/\S|\u00A0/)) {
+ if (!dom.isVisibleText(node)) {
node = dom.firstChild(node);
$(dom.node( dom.isBR(node) ? node.parentNode : node )).html(br);
node = br;
@@ -1105,7 +1114,7 @@ $.summernote.pluginEvents.visible = function (event, editor, layoutInfo) {
while (node.parentNode) {
if (dom.isForbiddenNode(node)) {
var text = node.previousSibling;
- if (text && dom.isText(text) && text.textContent.match(/\S|\u00A0/)) {
+ if (text && dom.isText(text) && dom.isVisibleText(text)) {
range.create(text, text.textContent.length, text, text.textContent.length).select();
} else {
text = node.parentNode.insertBefore(document.createTextNode( "." ), node);
@@ -1715,7 +1724,7 @@ $.summernote.pluginEvents.formatBlock = function (event, editor, layoutInfo, sTa
// fix by odoo because if you select a style in a li with no p tag all the ul is wrapped by the style tag
var nodes = dom.listBetween(r.sc, r.ec);
for (var i=0; i<nodes.length; i++) {
- if (dom.isBR(nodes[i]) || (dom.isText(nodes[i]) && nodes[i].textContent.match(/\S|\u00A0/)) || dom.isB(nodes[i]) || dom.isU(nodes[i]) || dom.isS(nodes[i]) || dom.isI(nodes[i]) || dom.isFont(nodes[i])) {
+ if (dom.isBR(nodes[i]) || (dom.isText(nodes[i]) && dom.isVisibleText(nodes[i])) || dom.isB(nodes[i]) || dom.isU(nodes[i]) || dom.isS(nodes[i]) || dom.isI(nodes[i]) || dom.isFont(nodes[i])) {
var ancestor = dom.ancestor(nodes[i], isFormatNode);
if (!ancestor) {
dom.wrap(nodes[i], sTagName);
diff --git a/addons/web_editor/static/src/js/widgets.js b/addons/web_editor/static/src/js/widgets.js
index acd8c859535..5e852a1c5ef 100644
--- a/addons/web_editor/static/src/js/widgets.js
+++ b/addons/web_editor/static/src/js/widgets.js
@@ -16,6 +16,7 @@ var dom = $.summernote.core.dom;
var Dialog = Widget.extend({
events: {
'hidden.bs.modal': 'destroy',
+ 'keydown.dismiss.bs.modal': 'stop_escape',
'click button.save': 'save',
'click button[data-dismiss="modal"]': 'cancel',
},
@@ -38,6 +39,11 @@ var Dialog = Widget.extend({
close: function () {
this.$el.modal('hide');
},
+ stop_escape: function(event) {
+ if($(".modal.in").length>0 && event.which == 27){
+ event.stopPropagation();
+ }
+ }
});
/**
@@ -251,6 +257,7 @@ var ImageDialog = Widget.extend({
//'change select.image-style': 'preview_image',
'click .existing-attachments [data-src]': 'select_existing',
'click .existing-attachment-remove': 'try_remove',
+ 'keydown.dismiss.bs.modal': function(){},
}),
init: function (parent, media, options) {
this._super();
@@ -339,7 +346,7 @@ var ImageDialog = Widget.extend({
return this.media;
},
clear: function () {
- this.media.className = this.media.className.replace(/(^|\s)(img(\s|$)|img-[^\s]*)/g, ' ');
+ this.media.className = this.media.className.replace(/(^|\s+)(img(\s|$)|img-(?!circle|rounded|thumbnail)[^\s]*)/g, ' ');
},
cancel: function () {
this.trigger('cancel');
@@ -609,6 +616,7 @@ var fontIconsDialog = Widget.extend({
$(".font-icons-icon").removeClass("font-icons-selected");
$(event.target).addClass("font-icons-selected");
},
+ 'keydown.dismiss.bs.modal': function(){},
}),
// extract list of font (like awsome) from the cheatsheet.
@@ -662,12 +670,14 @@ var fontIconsDialog = Widget.extend({
var icons = this.icons;
var style = this.media.attributes.style ? this.media.attributes.style.value : '';
var classes = (this.media.className||"").split(/\s+/);
+ var custom_classes = /^fa(-[1-5]x|spin|rotate-(9|18|27)0|flip-(horizont|vertic)al|fw|border)?$/;
var non_fa_classes = _.reject(classes, function (cls) {
- return self.getFont(cls);
+ return self.getFont(cls) || custom_classes.test(cls);
});
var final_classes = non_fa_classes.concat(this.get_fa_classes());
if (this.media.tagName !== "SPAN") {
var media = document.createElement('span');
+ $(media).data($(this.media).data());
$(this.media).replaceWith(media);
this.media = media;
style = style.replace(/\s*width:[^;]+/, '');
@@ -828,7 +838,8 @@ var VideoDialog = Widget.extend({
'change input#urlvideo': 'change_input',
'keyup input#urlvideo': 'change_input',
'change input#embedvideo': 'change_input',
- 'keyup input#embedvideo': 'change_input'
+ 'keyup input#embedvideo': 'change_input',
+ 'keydown.dismiss.bs.modal': function(){},
}),
init: function (parent, media) {
this._super();
@@ -842,7 +853,6 @@ var VideoDialog = Widget.extend({
if ($media.hasClass("media_iframe_video")) {
var src = $media.data('src');
this.$("input#urlvideo").val(src);
- this.$("#autoplay").attr("checked", src.indexOf('autoplay=1') != -1);
this.get_video();
} else {
this.add_class = "pull-left";