summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqsm-odoo <qsm@odoo.com>2016-05-20 17:43:31 +0200
committerqsm-odoo <qsm@odoo.com>2016-07-04 17:23:59 +0200
commitb309f3ab543b5195eedc5b06ad08cfa81f43171a (patch)
tree6edfb097ef024fce18445bbe9548b6fe3a7f44fd
parent05d064f85531d04056ad02bd2d26ef2341839f3b (diff)
[IMP] web_editor,website: snippet options (parent & deletion)
* Always allow to delete a part (and delete parent if empty) * Show parent options (by displaying the snippet name if any, "column" for col-* and "Block" otherwise) * ...
-rw-r--r--addons/web_editor/static/src/js/snippets.editor.js181
-rw-r--r--addons/web_editor/static/src/js/snippets.options.js1
-rw-r--r--addons/web_editor/static/src/less/web_editor.ui.less26
-rw-r--r--addons/web_editor/static/src/xml/snippets.xml2
-rw-r--r--addons/website/static/src/js/website.js2
-rw-r--r--addons/website/static/src/js/website.snippets.editor.js30
6 files changed, 167 insertions, 75 deletions
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index 1bfab9d3dc2..082a3b6204d 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -10,6 +10,7 @@ var animation = require('web_editor.snippets.animation');
var options = require('web_editor.snippets.options');
var qweb = core.qweb;
+var _t = core._t;
ajax.loadXML('/web_editor/static/src/xml/snippets.xml', qweb);
@@ -238,14 +239,15 @@ data.Class = Widget.extend({
self.$snippets = $scroll.find(".o_panel_body").children()
.addClass("oe_snippet")
.each(function () {
+ var $snippet = $(this);
if (!$('.oe_snippet_thumbnail', this).size()) {
var $div = $(
'<div class="oe_snippet_thumbnail">'+
'<div class="oe_snippet_thumbnail_img"/>'+
'<span class="oe_snippet_thumbnail_title"></span>'+
'</div>');
- $div.find('span').text($(this).attr("name"));
- $(this).prepend($div);
+ $div.find('span').text($snippet.attr("name"));
+ $snippet.prepend($div);
// from t-snippet
var thumbnail = $("[data-oe-thumbnail]", this).data("oe-thumbnail");
@@ -254,7 +256,7 @@ data.Class = Widget.extend({
}
// end
}
- if (!$(this).data("selector")) {
+ if (!$snippet.data("selector")) {
$("> *:not(.oe_snippet_thumbnail)", this).addClass('oe_snippet_body');
}
number++;
@@ -318,6 +320,19 @@ data.Class = Widget.extend({
});
self.make_snippet_draggable(self.$snippets);
+ this.associate_snippet_names(this.$snippets);
+ },
+
+ associate_snippet_names: function ($snippets) {
+ _.each($snippets, function (snippet) {
+ var $snippet = $(snippet);
+ var $sbody = $snippet.find(".oe_snippet_body");
+ var snippet_classes = $sbody.attr("class").match(/s_[^ ]+/g);
+ if (snippet_classes && snippet_classes.length) {
+ snippet_classes = snippet_classes.join(".");
+ }
+ $("#wrapwrap ." + snippet_classes).data("name", $snippet.find(".oe_snippet_thumbnail_title").text());
+ });
},
cover_target: function ($el, $target) {
@@ -510,7 +525,7 @@ data.Class = Widget.extend({
}
}
- $toInsert = $base_body.clone();
+ $toInsert = $base_body.clone().data("name", $snippet.find(".oe_snippet_thumbnail_title").text());
if (!$selector_siblings.length && !$selector_children.length) {
console.warn($snippet.find(".oe_snippet_thumbnail_title").text() + " have not insert action: data-drop-near or data-drop-in");
@@ -733,9 +748,9 @@ data.Class = Widget.extend({
var self = this;
function is_visible($el) {
- return $el.css('display') != 'none'
- && $el.css('opacity') != '0'
- && $el.css('visibility') != 'hidden';
+ return $el.css('display') !== 'none'
+ && $el.css('opacity') !== '0'
+ && $el.css('visibility') !== 'hidden';
}
// filter out invisible elements
@@ -803,9 +818,27 @@ data.Editor = Class.extend({
this.buildingBlock = BuildingBlock;
this.$target = $(dom);
this.$overlay = this.$target.data('overlay');
+
+ // Initialize parent button
+ this.init_parent_options();
+
+ // Load overlay options content
this.load_style_options();
- this.get_parent_block();
- this.start();
+
+ // Initialize move/clone/remove buttons
+ this.$overlay.on('click', '.oe_snippet_clone', _.bind(this.on_clone, this));
+ this.$overlay.on('click', '.oe_snippet_remove', _.bind(this.on_remove, this));
+ this._drag_and_drop();
+ },
+
+ getName: function () {
+ if (this.$target.data("name") !== undefined) {
+ return this.$target.data("name");
+ }
+ if (this.$target.parent(".row").length) {
+ return _t("Column");
+ }
+ return _t("Block");
},
// activate drag and drop for the snippets in the snippet toolbar
@@ -910,7 +943,7 @@ data.Editor = Class.extend({
self.buildingBlock.editor_busy = false;
- self.get_parent_block();
+ self.init_parent_options();
_.defer(function () {
self.buildingBlock.cover_target(self.$target.data('overlay'), self.$target);
});
@@ -924,6 +957,8 @@ data.Editor = Class.extend({
this.selector_siblings = [];
this.selector_children = [];
+ var i = 0;
+ $ul.append($("<li/>", {"class": "dropdown-header o_main_header", text: this.getName()}).data("editor", this));
_.each(this.buildingBlock.templateOptions, function (val, option_id) {
if (!val.selector.is(self.$target)) {
return;
@@ -932,14 +967,28 @@ data.Editor = Class.extend({
if (val['drop-in']) self.selector_children.push(val['drop-in']);
var option = val['option'];
- var Editor = options.registry[option] || options.Class;
- var editor = self.styles[option] = new Editor(self.buildingBlock, self, self.$target, option_id);
- $ul.append(editor.$el.addClass("snippet-option-" + option));
- editor.start();
+ self.styles[option] = new (options.registry[option] || options.Class)(self.buildingBlock, self, self.$target, option_id);
+ $ul.append(self.styles[option].$el.addClass("snippet-option-" + option));
+ self.styles[option].start();
+ self.styles[option].__order = i++;
+ });
+ $ul.append($("<li/>", {"class": "divider"}));
+
+ var $parents = this.$target.parents();
+ _.each($parents, function (parent) {
+ var parentEditor = $(parent).data("snippet-editor");
+ if (parentEditor) {
+ for (var styleName in parentEditor.styles) {
+ if (!parentEditor.styles[styleName].preventChildPropagation) {
+ $ul.append($("<li/>", {"class": "dropdown-header o_parent_editor_header", text: parentEditor.getName()}).data("editor", parentEditor));
+ break;
+ }
+ }
+ }
});
if (!this.selector_siblings.length && !this.selector_children.length) {
- this.$overlay.find(".oe_snippet_move, .oe_snippet_clone, .oe_snippet_remove").addClass('hidden');
+ this.$overlay.find(".oe_snippet_move, .oe_snippet_clone").addClass('hidden');
}
if ($ul.children().length) {
@@ -948,35 +997,25 @@ data.Editor = Class.extend({
this.$overlay.find('[data-toggle="dropdown"]').dropdown();
},
- get_parent_block: function () {
+ /**
+ * The init_parent_options method initializes the "go to parent" button and create the editor options
+ * management for them if they do not already have one.
+ */
+ init_parent_options: function () {
var self = this;
var $button = this.$overlay.find('.oe_snippet_parent');
var $parent = data.globalSelector.closest(this.$target.parent());
- if ($parent.length) {
- $button.removeClass("hidden");
- $button.off("click").on('click', function (event) {
- event.preventDefault();
- setTimeout(function () {
- self.buildingBlock.make_active($parent);
- }, 0);
- });
- } else {
- $button.addClass("hidden");
+ if (!$parent.data("snippet-editor")) {
+ this.buildingBlock.create_snippet_editor($parent);
}
- },
- /*
- * start
- * This method is called after init and _readXMLData
- */
- start: function () {
- if (!this.$target.parent().is(':o_editable')) {
- this.$overlay.find('.oe_snippet_move, .oe_snippet_clone, .oe_snippet_remove').remove();
- } else {
- this.$overlay.on('click', '.oe_snippet_clone', _.bind(this.on_clone, this));
- this.$overlay.on('click', '.oe_snippet_remove', _.bind(this.on_remove, this));
- this._drag_and_drop();
- }
+ $button.toggleClass("hidden", $parent.length === 0);
+ $button.off("click").on('click', function (event) {
+ event.preventDefault();
+ _.defer(function () {
+ self.buildingBlock.make_active($parent);
+ });
+ });
},
on_clone: function (event) {
@@ -1008,16 +1047,31 @@ data.Editor = Class.extend({
});
delete this.buildingBlock.snippets[index];
- // remove node and his empty
- var node = this.$target.parent()[0];
-
+ var $parent = this.$target.parent();
+ this.$target.find("*").andSelf().tooltip("destroy");
this.$target.remove();
this.$overlay.remove();
+ var node = $parent[0];
if (node && node.firstChild) {
$.summernote.core.dom.removeSpace(node, node.firstChild, 0, node.lastChild, 1);
if (!node.firstChild.tagName && node.firstChild.textContent === " ") {
- node.firstChild.parentNode.removeChild(node.firstChild);
+ node.removeChild(node.firstChild);
+ }
+ }
+
+ if($parent.closest(":data(\"snippet-editor\")").length) {
+ while (!$parent.data("snippet-editor")) {
+ var $nextParent = $parent.parent();
+ if ($parent.children().length === 0 && $parent.text().trim() === "") {
+ $parent.remove();
+ }
+ $parent = $nextParent;
+ }
+ if ($parent.children().length === 0 && $parent.text().trim() === "") {
+ _.defer(function () {
+ $parent.data("snippet-editor").on_remove(event);
+ });
}
}
@@ -1042,21 +1096,44 @@ data.Editor = Class.extend({
/* on_focus
* This method is called when the user click inside the snippet in the dom
*/
- on_focus : function () {
- this.$overlay.addClass('oe_active');
- for (var i in this.styles) {
- this.styles[i].on_focus();
- }
+ on_focus: function () {
+ this._on_focus_blur(true);
},
/* on_focus
* This method is called when the user click outside the snippet in the dom, after a focus
*/
- on_blur : function () {
- for (var i in this.styles) {
- this.styles[i].on_blur();
+ on_blur: function () {
+ this._on_focus_blur(false);
+ },
+
+ _on_focus_blur: function (focus) {
+ var do_action = (focus ? _do_action_focus : _do_action_blur);
+
+ // Attach own and parent options on the current overlay
+ var $headers = this.$overlay.find(".oe_options ul:first .dropdown-header:data(editor)");
+ _.each($headers, function (el) {
+ var $el = $(el);
+ var styles = _.values($el.data("editor").styles);
+ if ($el.data("editor") !== this) {
+ styles = _.filter(styles, function (option) { return !option.preventChildPropagation; });
+ }
+ _.each(_.sortBy(styles, "__order").reverse(), function (style) {
+ do_action(style, $el);
+ });
+ });
+
+ // Activate the overlay
+ this.$overlay.toggleClass("oe_active", !!focus);
+
+ function _do_action_focus(style, $dest) {
+ style.$el.insertAfter($dest);
+ style.on_focus();
+ }
+ function _do_action_blur(style, $dest) {
+ style.$el.detach();
+ style.on_blur();
}
- this.$overlay.removeClass('oe_active');
},
});
diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js
index 77879ce8803..34e51b4509d 100644
--- a/addons/web_editor/static/src/js/snippets.options.js
+++ b/addons/web_editor/static/src/js/snippets.options.js
@@ -18,7 +18,6 @@ odoo.define('web_editor.snippets.options', function (require) {
* thanks to the data-js key of the full options web_editor template.
*/
var SnippetOption = Class.extend({
- // initialisation (don't overwrite)
init: function (BuildingBlock, editor, $target, option_id) {
this.buildingBlock = BuildingBlock;
this.editor = editor;
diff --git a/addons/web_editor/static/src/less/web_editor.ui.less b/addons/web_editor/static/src/less/web_editor.ui.less
index 9167cbc2e2a..d52fdac720f 100644
--- a/addons/web_editor/static/src/less/web_editor.ui.less
+++ b/addons/web_editor/static/src/less/web_editor.ui.less
@@ -347,6 +347,9 @@ html[lang] > body.editor_enable{
background-color: darken(@o-we-color-danger, 20%);
}
}
+ &.oe_snippet_parent > i {
+ .scaleX(-1);
+ }
}
// CUSTOMIZE MENU BUTTON
@@ -444,6 +447,29 @@ html[lang] > body.editor_enable{
color: @odoo-brand-optional;
}
}
+ &.dropdown-header {
+ color: wheat;
+ font-weight: bold;
+
+ &:hover {
+ background-color: initial;
+ }
+
+ &.o_main_header {
+ padding-left: 4px;
+ }
+ &.o_parent_editor_header {
+ &::before {
+ content: "\f148";
+ .o-position-absolute(@top: 0, @left: 5px);
+ font-family: FontAwesome;
+ .scaleX(-1);
+ }
+ ~ li:not(.dropdown-header) {
+ padding-left: 16px;
+ }
+ }
+ }
}
}
}
diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml
index 9bb064f5e2b..f1cb9fc0fed 100644
--- a/addons/web_editor/static/src/xml/snippets.xml
+++ b/addons/web_editor/static/src/xml/snippets.xml
@@ -27,7 +27,7 @@
</div>
<div class="oe_overlay_options" contentEditable="false">
<div class="btn-group">
- <a href="#" class="btn btn-default btn-sm oe_snippet_parent" title="Select Container Block"><i class="fa fa-upload"/></a>
+ <a href="#" class="btn btn-default btn-sm oe_snippet_parent" title="Select Container Block"><i class="fa fa-lg fa-level-up"/></a>
<div class="dropdown oe_options hidden btn-group">
<a href="#" data-toggle="dropdown" class="btn btn-primary btn-sm" title="Customize">Customize</a>
<ul class="dropdown-menu" role="menu"/>
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index 6a442b85c90..00d2af0367c 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -38,7 +38,7 @@ odoo.define('website.website', function (require) {
/* ----------------------------------------------------
Widgets
- ---------------------------------------------------- */
+ ---------------------------------------------------- */
var prompt = function (options, _qweb) {
/**
* A bootstrapped version of prompt() albeit asynchronous
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index 1ab57c3c9af..8afcab6b506 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -11,24 +11,6 @@ snippet_editor.Class.include({
}
});
-var preventParentEmpty = {
- hide_remove_button: function () {
- this.$overlay.find('.oe_snippet_remove, .oe_snippet_move').toggleClass("hidden", !this.$target.siblings().length);
- },
- on_focus : function () {
- this._super();
- this.hide_remove_button();
- },
- on_clone: function ($clone) {
- this._super($clone);
- this.hide_remove_button();
- },
- on_remove: function () {
- this._super();
- this.hide_remove_button();
- },
-};
-
options.registry.slider = options.Class.extend({
drop_and_build_snippet: function () {
this.id = "myCarousel" + new Date().getTime();
@@ -185,6 +167,8 @@ options.registry.carousel = options.registry.slider.extend({
});
options.registry.marginAndResize = options.Class.extend({
+ preventChildPropagation: true,
+
start: function () {
var self = this;
this._super();
@@ -381,6 +365,8 @@ options.registry.marginAndResize = options.Class.extend({
});
options.registry["margin-y"] = options.registry.marginAndResize.extend({
+ preventChildPropagation: true,
+
getSize: function () {
this.grid = this._super();
var grid = [0,4,8,16,32,48,64,92,128];
@@ -395,7 +381,9 @@ options.registry["margin-y"] = options.registry.marginAndResize.extend({
},
});
-options.registry["margin-x"] = options.registry.marginAndResize.extend(preventParentEmpty).extend({
+options.registry["margin-x"] = options.registry.marginAndResize.extend({
+ preventChildPropagation: true,
+
getSize: function () {
this.grid = this._super();
var width = this.$target.parents(".row:first").first().outerWidth();
@@ -467,6 +455,8 @@ options.registry["margin-x"] = options.registry.marginAndResize.extend(preventPa
});
options.registry.resize = options.registry.marginAndResize.extend({
+ preventChildPropagation: true,
+
getSize: function () {
this.grid = this._super();
this.grid.size = 8;
@@ -564,7 +554,7 @@ options.registry.ul = options.Class.extend({
}
});
-options.registry.collapse = options.Class.extend(preventParentEmpty).extend({
+options.registry.collapse = options.Class.extend({
start: function () {
var self = this;
this._super();