summaryrefslogtreecommitdiff
path: root/addons/web_editor/static
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2016-09-22 15:27:35 +0200
committerChristophe Simonis <chs@odoo.com>2016-09-22 15:27:35 +0200
commitf308b09a9ab3f3bf452fdd1ac6c2c86812732110 (patch)
tree9506e8e830ce1e6737c1f7c87b451f60bbb2cbff /addons/web_editor/static
parent30260bbb0ee683c67cf8ddd0358f40fbd2f5dd0f (diff)
parent856476d4418390ca89ef161e31faf61248eeaa1d (diff)
[MERGE] forward port branch saas-13 up to 856476d
Diffstat (limited to 'addons/web_editor/static')
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Editor.js4
-rw-r--r--addons/web_editor/static/src/js/rte.js2
-rw-r--r--addons/web_editor/static/src/js/snippets.editor.js75
-rw-r--r--addons/web_editor/static/src/js/snippets.options.js225
-rw-r--r--addons/web_editor/static/src/js/transcoder.js6
-rw-r--r--addons/web_editor/static/src/js/widgets.js35
-rw-r--r--addons/web_editor/static/src/less/web_editor.ui.less13
-rw-r--r--addons/web_editor/static/src/xml/editor.xml2
-rw-r--r--addons/web_editor/static/src/xml/snippets.xml2
9 files changed, 291 insertions, 73 deletions
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Editor.js b/addons/web_editor/static/lib/summernote/src/js/module/Editor.js
index a30ee9c18c8..b7ba30bfcd1 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Editor.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Editor.js
@@ -616,7 +616,6 @@ define([
var linkUrl = linkInfo.url;
var linkText = linkInfo.text;
var isNewWindow = linkInfo.isNewWindow;
- var className = linkInfo.className || null; // ODOO: addition
var rng = linkInfo.range || this.createRange($editable);
var isTextChanged = rng.toString() !== linkText;
@@ -647,7 +646,8 @@ define([
$.each(anchors, function (idx, anchor) {
$(anchor).attr('href', linkUrl);
- $(anchor).attr('class', className); // ODOO: addition
+ $(anchor).attr('class', linkInfo.className || null); // ODOO: addition
+ $(anchor).css(linkInfo.style || {}); // ODOO: addition
if (isNewWindow) {
$(anchor).attr('target', '_blank');
} else {
diff --git a/addons/web_editor/static/src/js/rte.js b/addons/web_editor/static/src/js/rte.js
index 1ed12eb4a73..b0366583aea 100644
--- a/addons/web_editor/static/src/js/rte.js
+++ b/addons/web_editor/static/src/js/rte.js
@@ -509,7 +509,7 @@ var RTE = Widget.extend({
*/
$target.attr('contenteditable', true);
_.defer(function () {
- $editable.attr('contenteditable', false);
+ $editable.not($target).attr('contenteditable', false);
$target.focus();
});
diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js
index d603210b576..dcfabb6feb4 100644
--- a/addons/web_editor/static/src/js/snippets.editor.js
+++ b/addons/web_editor/static/src/js/snippets.editor.js
@@ -258,11 +258,7 @@ data.Class = Widget.extend({
$("body").toggleClass("editor_has_snippets", !!number);
// select all default text to edit (if snippet default text)
- self.$snippets.find('.oe_snippet_body, .oe_snippet_body *')
- .contents()
- .filter(function () {
- return this.nodeType === 3 && this.textContent.match(/\S/);
- }).parent().addClass("o_default_snippet_text");
+ this.add_default_snippet_text_classes();
$(document).on("click", ".o_default_snippet_text", function (event) {
$(event.target).selectContent();
});
@@ -287,6 +283,9 @@ data.Class = Widget.extend({
self.make_snippet_draggable(self.$snippets);
this.associate_snippet_names(this.$snippets);
+
+ this.show_blocks();
+ this.$el.on("snippet-dropped snippet-removed", this.show_blocks.bind(this));
},
associate_snippet_names: function ($snippets) {
@@ -301,6 +300,18 @@ data.Class = Widget.extend({
});
},
+ add_default_snippet_text_classes: function ($in) {
+ if ($in === undefined) {
+ $in = this.$snippets.find(".oe_snippet_body");
+ }
+
+ $in.find("*").addBack()
+ .contents()
+ .filter(function () {
+ return this.nodeType === 3 && this.textContent.match(/\S/);
+ }).parent().addClass("o_default_snippet_text");
+ },
+
cover_target: function ($el, $target) {
if ($el.data('not-cover_target')) {
return;
@@ -322,39 +333,22 @@ data.Class = Widget.extend({
show_blocks: function () {
var self = this;
var cache = {};
- this.$(".o_panel").each(function () {
- var catcheck = false;
- var $category = $(this);
- $category.find(".oe_snippet_body").each(function () {
- var $snippet = $(this);
-
- var check = false;
-
- for (var k in self.templateOptions) {
- var option = self.templateOptions[k];
- if ($snippet.is(option.base_selector)) {
-
- cache[k] = cache[k] || {
- 'drop-near': option['drop-near'] ? option['drop-near'].all() : [],
- 'drop-in': option['drop-in'] ? option['drop-in'].all() : []
- };
+ this.$snippets.each(function () {
+ var $snippet = $(this);
+ var $snippet_body = $snippet.find(".oe_snippet_body");
- if (cache[k]['drop-near'].length || cache[k]['drop-in'].length) {
- catcheck = true;
- check = true;
- break;
- }
- }
- }
+ var check = false;
+ _.each(self.templateOptions, function (option, k) {
+ if (check || !$snippet_body.is(option.base_selector)) return;
- if (check) {
- $snippet.closest(".oe_snippet").removeClass("disable");
- } else {
- $snippet.closest(".oe_snippet").addClass("disable");
- }
+ cache[k] = cache[k] || {
+ 'drop-near': option['drop-near'] ? option['drop-near'].all().length : 0,
+ 'drop-in': option['drop-in'] ? option['drop-in'].all().length : 0
+ };
+ check = (cache[k]['drop-near'] || cache[k]['drop-in']);
});
- $('#oe_snippets .scroll a[data-toggle="tab"][href="#' + $category.attr("id") + '"]').toggle(catcheck);
+ $snippet.toggleClass("disable", !check);
});
},
bind_snippet_click_editor: function () {
@@ -900,7 +894,6 @@ data.Editor = Class.extend({
this.$overlay.removeClass("hidden");
$("body").removeClass('move-important');
$clone.remove();
- $(".oe_drop_to_remove").remove();
if (this.dropped) {
this.buildingBlock.getParent().rte.historyRecordUndo(this.$target);
@@ -1008,10 +1001,12 @@ data.Editor = Class.extend({
},
on_remove: function (event) {
- event.preventDefault();
- this.on_blur();
+ if (event !== undefined) {
+ event.preventDefault();
+ this.buildingBlock.getParent().rte.historyRecordUndo(this.$target);
+ }
- this.buildingBlock.getParent().rte.historyRecordUndo(this.$target);
+ this.on_blur();
var index = _.indexOf(this.buildingBlock.snippets, this.$target.get(0));
this.buildingBlock.call_for_all_snippets(this.$target, function (editor, $snippet) {
@@ -1044,7 +1039,7 @@ data.Editor = Class.extend({
}
if ($parent.children().length === 0 && $parent.text().trim() === "") {
_.defer(function () {
- $parent.data("snippet-editor").on_remove(event);
+ $parent.data("snippet-editor").on_remove();
});
}
}
@@ -1053,6 +1048,8 @@ data.Editor = Class.extend({
$(".note-control-selection").hide();
$('.o_table_handler').remove();
+ this.buildingBlock.$el.trigger("snippet-removed");
+
return false;
},
diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js
index b4b96beabca..6d4800cd0db 100644
--- a/addons/web_editor/static/src/js/snippets.options.js
+++ b/addons/web_editor/static/src/js/snippets.options.js
@@ -214,6 +214,231 @@ odoo.define('web_editor.snippets.options', function (require) {
/* ----- default options ---- */
+ registry.marginAndResize = SnippetOption.extend({
+ preventChildPropagation: true,
+
+ start: function () {
+ var self = this;
+ this._super();
+
+ var resize_values = this.getSize();
+ if (resize_values.n) this.$overlay.find(".oe_handle.n").removeClass("readonly");
+ if (resize_values.s) this.$overlay.find(".oe_handle.s").removeClass("readonly");
+ if (resize_values.e) this.$overlay.find(".oe_handle.e").removeClass("readonly");
+ if (resize_values.w) this.$overlay.find(".oe_handle.w").removeClass("readonly");
+ if (resize_values.size) this.$overlay.find(".oe_handle.size").removeClass("readonly");
+
+ var $auto_size = this.$overlay.find(".oe_handle.size .auto_size");
+ var $fixed_size = this.$overlay.find(".oe_handle.size .size");
+
+ var auto_sized = isNaN(parseInt(self.$target.prop("style").height));
+ $fixed_size.toggleClass("active", !auto_sized);
+ $auto_size.toggleClass("active", auto_sized);
+
+ $fixed_size.add(this.$overlay.find(".oe_handle:not(.size)")).on('mousedown', function (event) {
+ event.preventDefault();
+
+ var $handle = $(this);
+
+ var resize_values = self.getSize();
+ var compass = false;
+ var XY = false;
+ if ($handle.hasClass('n')) {
+ compass = 'n';
+ XY = 'Y';
+ }
+ else if ($handle.hasClass('s')) {
+ compass = 's';
+ XY = 'Y';
+ }
+ else if ($handle.hasClass('e')) {
+ compass = 'e';
+ XY = 'X';
+ }
+ else if ($handle.hasClass('w')) {
+ compass = 'w';
+ XY = 'X';
+ }
+ else if ($handle.hasClass('size')) {
+ compass = 'size';
+ XY = 'Y';
+ }
+
+ var resize = resize_values[compass];
+ if (!resize) return;
+
+
+ if (compass === 'size') {
+ var offset = self.$target.offset().top;
+ if (self.$target.css("background").match(/rgba\(0, 0, 0, 0\)/)) {
+ self.$target.addClass("resize_editor_busy");
+ }
+ } else {
+ var xy = event['page'+XY];
+ var current = resize[2] || 0;
+ var margin_dir = {s:'bottom', n: 'top', w: 'left', e: 'right'}[compass];
+ var real_margin = parseInt(self.$target.css('margin-'+margin_dir));
+ _.each(resize[0], function (val, key) {
+ if (self.$target.hasClass(val)) {
+ current = key;
+ } else if (resize[1][key] === real_margin) {
+ current = key;
+ }
+ });
+ var begin = current;
+ var beginClass = self.$target.attr("class");
+ var regClass = new RegExp("\\s*" + resize[0][begin].replace(/[-]*[0-9]+/, '[-]*[0-9]+'), 'g');
+ }
+
+ self.buildingBlock.editor_busy = true;
+
+ var cursor = $handle.css("cursor")+'-important';
+ var $body = $(document.body);
+ $body.addClass(cursor);
+
+ var body_mousemove = function (event) {
+ event.preventDefault();
+ if (compass === 'size') {
+ var dy = event.pageY-offset;
+ dy = dy - dy%resize;
+ if (dy <= 0) dy = resize;
+ self.$target.css("height", dy+"px");
+ self.$target.css("overflow", "hidden");
+ self.on_resize(compass, null, dy);
+ self.buildingBlock.cover_target(self.$overlay, self.$target);
+ return;
+ }
+ var dd = event['page'+XY] - xy + resize[1][begin];
+ var next = current+1 === resize[1].length ? current : (current+1);
+ var prev = current ? (current-1) : 0;
+
+ var change = false;
+ if (dd > (2*resize[1][next] + resize[1][current])/3) {
+ self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, ''));
+ self.$target.addClass(resize[0][next]);
+ current = next;
+ change = true;
+ }
+ if (prev !== current && dd < (2*resize[1][prev] + resize[1][current])/3) {
+ self.$target.attr("class", (self.$target.attr("class")||'').replace(regClass, ''));
+ self.$target.addClass(resize[0][prev]);
+ current = prev;
+ change = true;
+ }
+
+ if (change) {
+ self.on_resize(compass, beginClass, current);
+ self.buildingBlock.cover_target(self.$overlay, self.$target);
+ }
+ };
+
+ var body_mouseup = function () {
+ $body.unbind('mousemove', body_mousemove);
+ $body.unbind('mouseup', body_mouseup);
+ $body.removeClass(cursor);
+ setTimeout(function () {
+ self.buildingBlock.editor_busy = false;
+ if (begin !== current) {
+ self.buildingBlock.getParent().rte.historyRecordUndo(self.$target, 'resize_' + XY);
+ }
+ },0);
+ self.$target.removeClass("resize_editor_busy");
+
+ if (compass === "size") {
+ $fixed_size.addClass("active");
+ $auto_size.removeClass("active");
+ }
+ };
+ $body.mousemove(body_mousemove);
+ $body.mouseup(body_mouseup);
+ });
+ $auto_size.on('click', function () {
+ self.$target.css("height", "");
+ self.$target.css("overflow", "");
+ self.buildingBlock.getParent().rte.historyRecordUndo(self.$target, 'resize_Y');
+ self.buildingBlock.cover_target(self.$overlay, self.$target);
+
+ $fixed_size.removeClass("active");
+ $auto_size.addClass("active");
+
+ return false;
+ });
+ },
+ getSize: function () {
+ this.grid = {};
+ return this.grid;
+ },
+
+ on_focus : function () {
+ this._super();
+ this.change_cursor();
+ },
+
+ change_cursor : function () {
+ var _class = this.$target.attr("class") || "";
+
+ var col = _class.match(/col-md-([0-9-]+)/i);
+ col = col ? +col[1] : 0;
+
+ var offset = _class.match(/col-md-offset-([0-9-]+)/i);
+ offset = offset ? +offset[1] : 0;
+
+ var overlay_class = this.$overlay.attr("class").replace(/(^|\s+)block-[^\s]*/gi, '');
+ if (col+offset >= 12) overlay_class+= " block-e-right";
+ if (col === 1) overlay_class+= " block-w-right block-e-left";
+ if (offset === 0) overlay_class+= " block-w-left";
+
+ var mb = _class.match(/mb([0-9-]+)/i);
+ mb = mb ? +mb[1] : parseInt(this.$target.css('margin-bottom'));
+ if (mb >= 128) overlay_class+= " block-s-bottom";
+ else if (!mb) overlay_class+= " block-s-top";
+
+ var mt = _class.match(/mt([0-9-]+)/i);
+ mt = mt ? +mt[1] : parseInt(this.$target.css('margin-top'));
+ if (mt >= 128) overlay_class+= " block-n-top";
+ else if (!mt) overlay_class+= " block-n-bottom";
+
+ this.$overlay.attr("class", overlay_class);
+ },
+
+ /* on_resize
+ * called when the box is resizing and the class change, before the cover_target
+ * @compass: resize direction : 'n', 's', 'e', 'w'
+ * @beginClass: attributes class at the begin
+ * @current: curent increment in this.grid
+ */
+ on_resize: function () {
+ this.change_cursor();
+ }
+ });
+
+ registry["margin-y"] = registry.marginAndResize.extend({
+ preventChildPropagation: true,
+
+ getSize: function () {
+ this.grid = this._super();
+ var grid = [0,4,8,16,32,48,64,92,128];
+ this.grid = {
+ // list of class (Array), grid (Array), default value (INT)
+ n: [_.map(grid, function (v) {return 'mt'+v;}), grid],
+ s: [_.map(grid, function (v) {return 'mb'+v;}), grid],
+ // INT if the user can resize the snippet (resizing per INT px)
+ size: null
+ };
+ return this.grid;
+ },
+ });
+
+ registry.resize = registry.marginAndResize.extend({
+ preventChildPropagation: true,
+
+ getSize: function () {
+ this.grid = this._super();
+ this.grid.size = 8;
+ return this.grid;
+ },
+ });
+
/**
* The colorpicker option is designed to change the background color class of a snippet. This class change the
* default background color and text color of the snippet content.
diff --git a/addons/web_editor/static/src/js/transcoder.js b/addons/web_editor/static/src/js/transcoder.js
index fbdc4b34b87..ddd8ce73533 100644
--- a/addons/web_editor/static/src/js/transcoder.js
+++ b/addons/web_editor/static/src/js/transcoder.js
@@ -3,12 +3,8 @@ odoo.define('web_editor.transcoder', function (require) {
var widget = require('web_editor.widget');
-var cache = {};
var rulesCache = [];
var getMatchedCSSRules = function (a) {
- if(cache[a.tagName + "." +a.className]) {
- return cache[a.tagName + "." +a.className];
- }
if (!rulesCache.length) {
var sheets = document.styleSheets;
for(var i = sheets.length-1; i >= 0 ; i--) {
@@ -117,7 +113,7 @@ var getMatchedCSSRules = function (a) {
delete style['padding-left'];
}
- return a.className ? cache[a.tagName + "." +a.className] = style : style;
+ return style;
};
// convert font awsome into image
diff --git a/addons/web_editor/static/src/js/widgets.js b/addons/web_editor/static/src/js/widgets.js
index a34571a3f54..00a693d40f2 100644
--- a/addons/web_editor/static/src/js/widgets.js
+++ b/addons/web_editor/static/src/js/widgets.js
@@ -200,21 +200,14 @@ var MediaDialog = Dialog.extend({
$(document.body).trigger("media-saved", [media, self.old_media]);
self.trigger("saved", [media, self.old_media]);
- setTimeout(function () {
- if (!media.parentNode) {
- return;
- }
+
+ // Update editor bar after image edition (in case the image change to icon or other)
+ _.defer(function () {
+ if (!media.parentNode) return;
range.createFromNode(media).select();
click_event(media, "mousedown");
- if (!this.only_images) {
- setTimeout(function () {
- if($(media).parent().data("oe-field") !== "image") {
- click_event(media, "click");
- }
- click_event(media, "mouseup");
- },0);
- }
- },0);
+ click_event(media, "mouseup");
+ });
this._super.apply(this, arguments);
},
@@ -774,7 +767,9 @@ var fontIconsDialog = Widget.extend({
});
-function createVideoNode(url) {
+function createVideoNode(url, options) {
+ options = options || {};
+
// video url patterns(youtube, instagram, vimeo, dailymotion, youku)
var ytRegExp = /^(?:(?:https?:)?\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
var ytMatch = url.match(ytRegExp);
@@ -844,6 +839,10 @@ function createVideoNode(url) {
});
}
+ if (options.autoplay) {
+ $video.attr("src", $video.attr("src") + "?autoplay=1");
+ }
+
$video.attr('frameborder', 0);
return $video;
@@ -858,6 +857,7 @@ var VideoDialog = Widget.extend({
events : _.extend({}, Dialog.prototype.events, {
'click input#urlvideo ~ button': 'get_video',
'click input#embedvideo ~ button': 'get_embed_video',
+ 'change input#autoplay': 'get_video',
'change input#urlvideo': 'change_input',
'keyup input#urlvideo': 'change_input',
'change input#embedvideo': 'change_input',
@@ -876,6 +876,7 @@ var VideoDialog = Widget.extend({
if ($media.hasClass("media_iframe_video")) {
var src = $media.data('src');
this.$("input#urlvideo").val(src);
+ this.$("input#autoplay").prop("checked", (src || "").indexOf("autoplay") >= 0);
this.get_video();
}
return this._super.apply(this, arguments);
@@ -900,7 +901,7 @@ var VideoDialog = Widget.extend({
},
get_video: function (event) {
if (event) event.preventDefault();
- var $video = createVideoNode(this.$("input#urlvideo").val());
+ var $video = createVideoNode(this.$("input#urlvideo").val(), {autoplay: this.$("input#autoplay").is(":checked")});
this.$iframe.replaceWith($video);
this.$iframe = $video;
return false;
@@ -1091,7 +1092,9 @@ var LinkDialog = Dialog.extend({
self.data.isNewWindow = new_window;
self.data.text = label;
self.data.className = classes.replace(/\s+/gi, ' ').replace(/^\s+|\s+$/gi, '');
-
+ if (classes.replace(/(^|[ ])(btn-default|btn-success|btn-primary|btn-info|btn-warning|btn-danger)([ ]|$)/gi, ' ')) {
+ self.data.style = {'background-color': '', 'color': ''};
+ }
self.trigger("save", self.data);
}).then(_super);
},
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 81910fc0b1e..00b6414bd16 100644
--- a/addons/web_editor/static/src/less/web_editor.ui.less
+++ b/addons/web_editor/static/src/less/web_editor.ui.less
@@ -1069,23 +1069,20 @@ body.editor_enable {
#web_editor_inside_iframe {
background-color: @odoo-brand-secondary;
- &.editor_enable #wrapwrap {
+ #wrapwrap {
height: 100%;
+
> main {
height: 100%;
+
#editable_area {
position: relative;
- overflow: hidden;
- min-height: 100%;
- margin: 0 auto;
-
+ width: 100%;
+ height: 100%;
background-color: white;
}
}
}
- .note-color-palette .colorpicker {
- display: none;
- }
}
// Mixins for buttons with alpha bg-color
diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml
index 138c84da6f0..27213d7fdd8 100644
--- a/addons/web_editor/static/src/xml/editor.xml
+++ b/addons/web_editor/static/src/xml/editor.xml
@@ -210,7 +210,7 @@
</div>
<div class="text-center mt32">
<div class="checkbox">
- <label>
+ <label title="The feature might not be supported for every video type">
<input id="autoplay" type="checkbox"/>Autoplay</label>
</div>
</div>
diff --git a/addons/web_editor/static/src/xml/snippets.xml b/addons/web_editor/static/src/xml/snippets.xml
index 2b9aaf15b32..d9e8c83a495 100644
--- a/addons/web_editor/static/src/xml/snippets.xml
+++ b/addons/web_editor/static/src/xml/snippets.xml
@@ -60,7 +60,7 @@
<!-- t-field options -->
<t t-name="web_editor.many2one.button">
- <div class="dropdown">
+ <div class="btn-group">
<a href="#" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" title="Search Contact"><i class="fa fa-search"></i></a>
<ul class="dropdown-menu contact_menu" role="menu">
<li><a><input href="#" type="email" placeholder="Search"/></a></li>