summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/snippets.options.js
diff options
context:
space:
mode:
authorChristophe Matthieu <chm@odoo.com>2015-07-07 16:02:53 +0200
committerChristophe Matthieu <chm@odoo.com>2015-07-10 17:00:11 +0200
commit8c559044a5e1be111dcb577ad7e5ab462c1002a0 (patch)
treeba1602e15b2bca38babd6cca63a41da1d05b4321 /addons/web_editor/static/src/js/snippets.options.js
parenta616c57c609da0e5e56835dcb45e1c05590d25b8 (diff)
[IMP] web_editor: split website into web_editor (to use editor in backend for html field) and website
Diffstat (limited to 'addons/web_editor/static/src/js/snippets.options.js')
-rw-r--r--addons/web_editor/static/src/js/snippets.options.js534
1 files changed, 534 insertions, 0 deletions
diff --git a/addons/web_editor/static/src/js/snippets.options.js b/addons/web_editor/static/src/js/snippets.options.js
new file mode 100644
index 00000000000..a46c00baa25
--- /dev/null
+++ b/addons/web_editor/static/src/js/snippets.options.js
@@ -0,0 +1,534 @@
+odoo.define('web_editor.snippets.options', function (require) {
+'use strict';
+
+var Class = require('web.Class');
+var ajax = require('web.ajax');
+var core = require('web.core');
+var base = require('web_editor.base');
+var editor = require('web_editor.editor');
+var widget = require('web_editor.widget');
+var animation = require('web_editor.snippets.animation');
+
+var qweb = core.qweb;
+
+/* ----- Editor option (object link the the xml with data-js) ---- */
+
+var Option = Class.extend({
+ // initialisation (don't overwrite)
+ init: function (BuildingBlock, editor, $target, option_id) {
+ this.buildingBlock = BuildingBlock;
+ this.editor = editor;
+ this.$target = $target;
+ var option = this.buildingBlock.templateOptions[option_id];
+ var styles = this.$target.data("snippet-option-ids") || {};
+ styles[option_id] = this;
+ this.$target.data("snippet-option-ids", styles);
+ this.$overlay = this.$target.data('overlay') || $('<div>');
+ this.option= option_id;
+ this.$el = option.$el.find(">li").clone();
+ this.data = option.$el.data();
+ },
+
+ // helper for this.$target.find
+ $: function (selector) {
+ return this.$target(selector);
+ },
+
+ _bind_li_menu: function () {
+ this.$el.filter("li:hasData").find('a:first')
+ .off('mouseenter click')
+ .on('mouseenter click', _.bind(this._mouse, this));
+
+ this.$el
+ .off('mouseenter click', "li:hasData a")
+ .on('mouseenter click', "li:hasData a", _.bind(this._mouse, this));
+
+ this.$el.closest("ul").add(this.$el)
+ .off('mouseleave')
+ .on('mouseleave', _.bind(this.reset, this));
+
+ this.$el
+ .off('mouseleave', "ul")
+ .on('mouseleave', "ul", _.bind(this.reset, this));
+
+ this.reset_methods = [];
+ },
+
+ /**
+ * this method handles mouse:over and mouse:leave on the snippet editor menu
+ */
+ _time_mouseleave: null,
+ _mouse: function (event) {
+ var $next = $(event.currentTarget).parent();
+
+ // triggers preview or apply methods if a menu item has been clicked
+ this.select(event.type === "click" ? "click" : "over", $next);
+ if (event.type === 'click') {
+ this.set_active();
+ this.$target.trigger("snippet-option-change", [this]);
+ } else {
+ this.$target.trigger("snippet-option-preview", [this]);
+ }
+ },
+ /*
+ * select and set item active or not (add highlight item and his parents)
+ * called before start
+ */
+ set_active: function () {
+ var classes = _.uniq((this.$target.attr("class") || '').split(/\s+/));
+ this.$el.find('[data-toggle_class], [data-select_class]')
+ .add(this.$el)
+ .filter('[data-toggle_class], [data-select_class]')
+ .removeClass("active")
+ .filter('[data-toggle_class="' + classes.join('"], [data-toggle_class="') + '"] ,'+
+ '[data-select_class="' + classes.join('"], [data-select_class="') + '"]')
+ .addClass("active");
+ },
+
+ start: function () {
+ this.set_active();
+ this.$target.on('snippet-option-reset', _.bind(this.set_active, this));
+ this._bind_li_menu();
+ },
+
+ on_focus : function () {
+ this._bind_li_menu();
+ },
+
+ on_blur : function () {
+ },
+
+ on_clone: function ($clone) {
+ },
+
+ on_move: function () {
+ },
+
+ on_remove: function () {
+ },
+
+ drop_and_build_snippet: function () {
+ },
+
+ reset: function () {
+ var self = this;
+ var lis = self.$el.add(self.$el.find('li')).filter('.active').get();
+ lis.reverse();
+ _.each(lis, function (li) {
+ var $li = $(li);
+ for (var k in self.reset_methods) {
+ var method = self.reset_methods[k];
+ if ($li.is('[data-'+method+']') || $li.closest('[data-'+method+']').size()) {
+ delete self.reset_methods[k];
+ }
+ }
+ self.select("reset", $li);
+ });
+
+ for (var k in self.reset_methods) {
+ var method = self.reset_methods[k];
+ if (method) {
+ self[method]("reset", null);
+ }
+ }
+ self.reset_methods = [];
+ self.$target.trigger("snippet-option-reset", [this]);
+ },
+
+ // call data-method args as method (data-only can be used)
+ select: function (type, $li) {
+ var self = this,
+ $methods = [],
+ el = $li[0];
+
+ if ($li.data('only') && type !== $li.data('only')) {
+ return;
+ }
+
+ if (type==="click") {
+ this.reset();
+ this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
+ }
+
+ function filter (k) { return k !== 'oeId' && k !== 'oeModel' && k !== 'oeField' && k !== 'oeXpath' && k !== 'oeSourceId' && k !== 'only';}
+ function hasData(el) {
+ for (var k in el.dataset) {
+ if (filter (k)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ function method(el) {
+ var data = {};
+ for (var k in el.dataset) {
+ if (filter (k)) {
+ data[k] = el.dataset[k];
+ }
+ }
+ return data;
+ }
+
+ while (el && this.$el.is(el) || _.some(this.$el.map(function () {return $.contains(this, el);}).get()) ) {
+ if (hasData(el)) {
+ $methods.push(el);
+ }
+ el = el.parentNode;
+ }
+
+ $methods.reverse();
+
+ _.each($methods, function (el) {
+ var $el = $(el);
+ var methods = method(el);
+
+ for (var k in methods) {
+ if (self[k]) {
+ if (type !== "reset" && self.reset_methods.indexOf(k) === -1) {
+ self.reset_methods.push(k);
+ }
+ self[k](type, methods[k], $el);
+ } else {
+ console.error("'"+self.option+"' snippet have not method '"+k+"'");
+ }
+ }
+ });
+ },
+
+ // default method for snippet
+ toggle_class: function (type, value, $li) {
+ var $lis = this.$el.find('[data-toggle_class]').add(this.$el).filter('[data-toggle_class]');
+
+ function map ($lis) {
+ return $lis.map(function () {return $(this).data("toggle_class");}).get().join(" ");
+ }
+ var classes = map($lis);
+ var active_classes = map($lis.filter('.active, :has(.active)'));
+
+ this.$target.removeClass(classes);
+ this.$target.addClass(active_classes);
+
+ if (type !== 'reset') {
+ this.$target.toggleClass(value);
+ }
+ },
+ select_class: function (type, value, $li) {
+ var $lis = this.$el.find('[data-select_class]').add(this.$el).filter('[data-select_class]');
+
+ var classes = $lis.map(function () {return $(this).data('select_class');}).get();
+
+ this.$target.removeClass(classes.join(" "));
+ if(value) this.$target.addClass(value);
+ },
+ eval: function (type, value, $li) {
+ var fn = new Function("node", "type", "value", "$li", value);
+ fn.call(this, this, type, value, $li);
+ },
+
+ clean_for_save: editor.dummy
+});
+
+/* ----- default options ---- */
+
+var media = Option.extend({
+ start: function () {
+ var self =this;
+ this._super();
+ animation.start(true, this.$target);
+ this.$target.closest(".o_editable").on("content_changed", function () {
+ if (!self.$target.parent().length) {
+ self.$target.remove();
+ self.$overlay.remove();
+ }
+ });
+ },
+ edition: function (type, value) {
+ if(type !== "click") return;
+ var self = this;
+ var _editor = new widget.MediaDialog(this.$target.closest('.o_editable'), this.$target[0]);
+ _editor.appendTo(document.body);
+ _editor.on('saved', this, function (item, old) {
+ self.editor.on_blur();
+ self.buildingBlock.make_active(false);
+ if (self.$target.parent().data("oe-field") !== "image") {
+ setTimeout(function () {
+ self.buildingBlock.make_active($(item));
+ },0);
+ }
+ });
+ },
+ on_focus : function () {
+ var self = this;
+ var $parent = this.$target.parent();
+
+ if ($parent.data("oe-field") === "image" && $parent.hasClass('o_editable')) {
+ this.$overlay.addClass("hidden");
+ self.edition('click', null);
+ self.buildingBlock.make_active(false);
+ }
+ }
+});
+
+var colorpicker = Option.extend({
+ start: function () {
+ var self = this;
+ var res = this._super();
+
+ if (!this.$el.find('.colorpicker').length) {
+ this.$el.find('li').append( qweb.render('web_editor.colorpicker') );
+ }
+ if (this.$el.data('area')) {
+ this.$target = this.$target.find(this.$el.data('area'));
+ this.$el.removeData('area').removeAttr('area');
+ }
+
+ var classes = [];
+ this.$el.find(".colorpicker button").map(function () {
+ var $color = $(this);
+ var color = $color.attr("class");
+ if (self.$target.hasClass(color)) {
+ self.color = color;
+ $color.parent().addClass("selected");
+ }
+ classes.push(color);
+ });
+ this.classes = classes.join(" ");
+
+ this.bind_events();
+ return res;
+ },
+ bind_events: function () {
+ var self = this;
+ var $td = this.$el.find(".colorpicker td");
+ var $colors = this.$el.find(".colorpicker button");
+ $colors
+ .mouseenter(function () {
+ self.$target.removeClass(self.classes).addClass($(this).attr("class"));
+ })
+ .mouseleave(function () {
+ self.$target.removeClass(self.classes)
+ .addClass($td.filter(".selected").children().attr("class"));
+ })
+ .click(function () {
+ $td.removeClass("selected");
+ $(this).parent().addClass("selected");
+ });
+ }
+});
+
+var background = Option.extend({
+ start: function ($change_target) {
+ this.$bg = $change_target || this.$target;
+ this._super();
+ var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ if (this.$bg.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");
+ } else {
+ this.$bg.css("background-image", "");
+ this.$bg.removeClass("oe_img_bg").removeClass("oe_custom_bg");
+ }
+ },
+ choose_image: function(type, value, $li) {
+ if(type !== "click") return;
+
+ var self = this;
+ var $image = $('<img class="hidden"/>');
+ $image.attr("src", value);
+ $image.appendTo(self.$bg);
+
+ var _editor = new widget.MediaDialog(null, $image[0]);
+ _editor.appendTo(document.body);
+ _editor.$('[href="#editor-media-video"], [href="#editor-media-icon"]').addClass('hidden');
+
+ _editor.on('saved', self, function () {
+ var value = $image.attr("src");
+ $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.set_active();
+ });
+ _editor.on('cancel', self, function () {
+ $image.remove();
+ });
+ },
+ set_active: function () {
+ var self = this;
+ var src = this.$bg.css("background-image").replace(/url\(['"]*|['"]*\)|^none$/g, "");
+ this._super();
+
+ this.$el.find('li[data-background]:not([data-background=""])')
+ .removeClass("active")
+ .each(function () {
+ var background = $(this).data("background") || $(this).attr("data-background");
+ if ((src.length && background.length && src.indexOf(background) !== -1) || (!src.length && !background.length)) {
+ $(this).addClass("active");
+ }
+ });
+
+ if (!this.$el.find('li[data-background].active').size()) {
+ this.$el.find('li[data-background=""]:not([data-choose_image])').addClass("active");
+ } else {
+ this.$el.find('li[data-background=""]:not([data-choose_image])').removeClass("active");
+ }
+ }
+});
+
+/* t-field options */
+
+var many2one = Option.extend({
+ start: function () {
+ var self = this;
+
+ this.Model = this.$target.data('oe-many2one-model');
+ this.ID = +this.$target.data('oe-many2one-id');
+
+ // create search button and bind search bar
+ this.$btn = $(qweb.render("web_editor.many2one.button"))
+ .insertAfter(this.$overlay.find('.oe_options'));
+
+ this.$ul = this.$btn.find("ul");
+ this.$search = this.$ul.find('li:first');
+ this.$search.find('input').on('mousedown click mouseup keyup keydown', function (e) {
+ e.stopPropagation();
+ });
+
+ // move menu item
+ setTimeout(function () {
+ if (self.$overlay.find('.oe_options').hasClass('hidden')) {
+ self.$btn.css('height', '0').find('> a').addClass('hidden');
+ self.$ul.show().css({
+ 'top': '-24px', 'margin': '0', 'padding': '2px 0', 'position': 'relative'
+ });
+ } else {
+ self.$btn.find('a').on('click', function (e) {
+ self.clear();
+ });
+ }
+ },0);
+
+ // bind search input
+ this.$search.find('input')
+ .focus()
+ .on('keyup', function(e) {
+ self.find_existing($(this).val());
+ });
+
+ // bind result
+ this.$ul.on('click', "li:not(:first) a", function (e) {
+ self.select_record(this);
+ });
+ },
+
+ on_focus: function () {
+ this.$target.attr('contentEditable', 'false');
+ this.clear();
+ this._super();
+ },
+
+ clear: function () {
+ var self = this;
+ this.$search.siblings().remove();
+ self.$search.find('input').val("");
+ setTimeout(function () {
+ self.$search.find('input').focus();
+ },0);
+ },
+
+ find_existing: function (name) {
+ var self = this;
+ var domain = [];
+ if (!name || !name.length) {
+ self.$search.siblings().remove();
+ return;
+ }
+ if (isNaN(+name)) {
+ if (this.Model === "res.partner") {
+ domain.push(['name', 'ilike', name]);
+ } else {
+ domain.push('|', ['name', 'ilike', name], ['email', 'ilike', name]);
+ }
+ } else {
+ domain.push(['id', '=', name]);
+ }
+
+ ajax.jsonRpc('/web/dataset/call_kw', 'call', {
+ model: this.Model,
+ method: 'search_read',
+ args: [domain, this.Model === "res.partner" ? ['name', 'display_name', 'city', 'country_id'] : ['name', 'display_name']],
+ kwargs: {
+ order: 'name DESC',
+ limit: 5,
+ context: base.get_context(),
+ }
+ }).then(function (result){
+ self.$search.siblings().remove();
+ self.$search.after(qweb.render("web_editor.many2one.search",{contacts:result}));
+ });
+ },
+
+ get_contact_rendering: function (options) {
+ return ajax.jsonRpc('/web/dataset/call_kw', 'call', {
+ model: 'ir.qweb.field.contact',
+ method: 'get_record_to_html',
+ args: [[this.ID]],
+ kwargs: {
+ options: options,
+ context: base.get_context(),
+ }
+ });
+ },
+
+ select_record: function (li) {
+ var self = this;
+
+ this.ID = +$(li).data("id");
+ this.$target.attr('data-oe-many2one-id', this.ID).data('oe-many2one-id', this.ID);
+
+ this.buildingBlock.parent.rte.historyRecordUndo(this.$target);
+
+ if (self.$target.data('oe-type') === "contact") {
+ $('[data-oe-contact-options]')
+ .filter('[data-oe-model="'+self.$target.data('oe-model')+'"]')
+ .filter('[data-oe-id="'+self.$target.data('oe-id')+'"]')
+ .filter('[data-oe-field="'+self.$target.data('oe-field')+'"]')
+ .filter('[data-oe-contact-options!="'+self.$target.data('oe-contact-options')+'"]')
+ .add(self.$target)
+ .attr('data-oe-many2one-id', self.ID).data('oe-many2one-id', self.ID)
+ .each(function () {
+ var $node = $(this);
+ self.get_contact_rendering($node.data('oe-contact-options'))
+ .then(function (html){
+ $node.html(html);
+ });
+ });
+ } else {
+ self.$target.html($(li).data("name"));
+ }
+
+ setTimeout(function () {
+ self.buildingBlock.make_active(false);
+ },0);
+ }
+});
+
+/* end*/
+
+return {
+ 'registry': {
+ 'media': media,
+ 'colorpicker': colorpicker,
+ 'background': background,
+ 'many2one': many2one,
+ },
+ 'Class': Option
+};
+
+});