odoo.define('mass_mailing.editor', function (require) { "use strict"; require('web.dom_ready'); var ajax = require('web.ajax'); var core = require('web.core'); var rte = require('web_editor.rte'); var options = require('web_editor.snippets.options'); var snippets_editor = require('web_editor.snippet.editor'); var $editable_area = $('#editable_area'); var odoo_top = window.top.odoo; // Snippet option for resizing image and column width inline like excel options.registry["width-x"] = options.Class.extend({ start: function () { this.container_width = this.$target.parent().closest("td, table, div").width(); var self = this; var offset, sib_offset, target_width, sib_width; var $body = $(document.body); this.is_image = false; this._super.apply(this, arguments); this.$overlay.find(".oe_handle.e, .oe_handle.w").removeClass("readonly"); if (this.$target.is("img")) { this.$overlay.find(".oe_handle.w").addClass("readonly"); this.$overlay.find(".oe_snippet_move, .oe_snippet_clone").addClass("hidden"); this.is_image=true; } this.$overlay.find(".oe_handle").on('mousedown', function (event) { event.preventDefault(); var $handle = $(this); var compass = false; _.each(['n', 's', 'e', 'w' ], function (handler) { if ($handle.hasClass(handler)) { compass = handler; } }); if (self.is_image) { compass = "image"; } $body.on("mousemove.mass_mailing_width_x", function (event) { event.preventDefault(); offset = self.$target.offset().left; target_width = self.get_max_width(self.$target); if (compass === 'e' && self.$target.next().offset()) { sib_width = self.get_max_width(self.$target.next()); sib_offset = self.$target.next().offset().left; self.change_width(event, self.$target, target_width, offset, true); self.change_width(event, self.$target.next(), sib_width, sib_offset, false); } if (compass === 'w' && self.$target.prev().offset()) { sib_width = self.get_max_width(self.$target.prev()); sib_offset = self.$target.prev().offset().left; self.change_width(event, self.$target, target_width, offset, false); self.change_width(event, self.$target.prev(), sib_width, sib_offset, true); } if (compass === 'image') { self.change_width(event, self.$target, target_width, offset, true); } }); $body.one("mouseup", function(){ $body.off('.mass_mailing_width_x'); }); }); }, change_width: function (event, target, target_width, offset, grow) { target.css("width", grow ? (event.pageX - offset) : (offset + target_width - event.pageX)); this.trigger_up('cover_update'); }, get_int_width: function (el) { return parseInt($(el).css("width"), 10); }, get_max_width: function ($el) { return this.container_width - _.reduce(_.map($el.siblings(), this.get_int_width), function (memo, w) { return memo + w; }); }, onFocus: function () { this._super.apply(this, arguments); if (this.$target.is("td, th")) { this.$overlay.find(".oe_handle.e, .oe_handle.w").toggleClass("readonly", this.$target.siblings().length === 0); } }, }); options.registry.table_item = options.Class.extend({ onClone: function () { this._super.apply(this, arguments); // If we cloned a td or th element... if (this.$target.is("td, th")) { // ... and that the td or th element was alone on its row ... if (this.$target.siblings().length === 1) { var $tr = this.$target.parent(); $tr.clone().empty().insertAfter($tr).append(this.$target); // ... move the clone in a new row instead return; } // ... if not, if the clone neighbor is an empty cell, remove this empty cell (like if the clone content had been put in that cell) var $next = this.$target.next(); if ($next.length && $next.text().trim() === "") { $next.remove(); return; } // ... if not, insert an empty col in each other row, at the index of the clone var width = this.$target.width(); var $trs = this.$target.closest("table").children("thead, tbody, tfoot").addBack().children("tr").not(this.$target.parent()); _.each($trs.children(":nth-child(" + this.$target.index() + ")"), function (col) { $(col).after($("", {style: "width: " + width + "px;"})); }); } }, onRemove: function () { this._super.apply(this, arguments); // If we are removing a td or th element which was not alone on its row ... if (this.$target.is("td, th") && this.$target.siblings().length > 0) { var $trs = this.$target.closest("table").children("thead, tbody, tfoot").addBack().children("tr").not(this.$target.parent()); if ($trs.length) { // ... if there are other rows in the table ... var $last_tds = $trs.children(":last-child"); if (_.reduce($last_tds, function (memo, td) { return memo + (td.innerHTML || ""); }, "").trim() === "") { $last_tds.remove(); // ... remove the potential full empty column in the table } else { this.$target.parent().append(""); // ... else, if there is no full empty column, append an empty col in the current row } } } }, }); var fn_popover_update = $.summernote.eventHandler.modules.popover.update; $.summernote.eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) { fn_popover_update.call(this, $popover, oStyle, isAirMode); $("span.o_table_handler, div.note-table").remove(); }; ajax.loadXML("/mass_mailing/static/src/xml/mass_mailing.xml", core.qweb); snippets_editor.Class.include({ _computeSnippetTemplates: function (html) { var self = this; var ret = this._super.apply(this, arguments); var $themes = this.$("#email_designer_themes").children(); if ($themes.length === 0) return ret; /** * Initialize theme parameters. */ var all_classes = ""; var themes_params = _.map($themes, function (theme) { var $theme = $(theme); var name = $theme.data("name"); var classname = "o_" + name + "_theme"; all_classes += " " + classname; var images_info = _.defaults($theme.data("imagesInfo") || {}, {all: {}}); _.each(images_info, function (info) { info = _.defaults(info, images_info.all, {module: "mass_mailing", format: "jpg"}); }); return { name: name, className: classname || "", img: $theme.data("img") || "", template: $theme.html().trim(), nowrap: !!$theme.data('nowrap'), get_image_info: function (filename) { if (images_info[filename]) { return images_info[filename]; } return images_info.all; } }; }); $themes.parent().remove(); var $body = $(document.body); var $snippets = this.$(".oe_snippet"); var $snippets_menu = this.$el.find("#snippets_menu"); /** * Create theme selection screen and check if it must be forced opened. * Reforce it opened if the last snippet is removed. */ var $dropdown = $(core.qweb.render("mass_mailing.theme_selector", { themes: themes_params })); var first_choice; check_if_must_force_theme_choice(); /** * Add proposition to install enterprise themes if not installed. */ var $mail_themes_upgrade = $dropdown.find(".o_mass_mailing_themes_upgrade"); $mail_themes_upgrade.on("click", "> a", function (e) { e.stopImmediatePropagation(); e.preventDefault(); odoo_top[window.callback+"_do_action"]("mass_mailing.action_mass_mailing_configuration"); }); /** * Switch theme when a theme button is hovered. Confirm change if the theme button * is pressed. */ var selected_theme = false; $dropdown.on("mouseenter", "li > a", function (e) { if (first_choice) return; e.preventDefault(); var theme_params = themes_params[$(e.currentTarget).parent().index()]; switch_theme(theme_params); }); $dropdown.on("click", "li > a", function (e) { e.preventDefault(); var theme_params = themes_params[$(e.currentTarget).parent().index()]; if (first_choice) { switch_theme(theme_params); $body.removeClass("o_force_mail_theme_choice"); first_choice = false; if ($mail_themes_upgrade.length) { $dropdown.remove(); $snippets_menu.empty(); } } switch_images(theme_params, $snippets); selected_theme = theme_params; // Notify form view odoo_top[window.callback+"_downup"]($editable_area.addClass("o_dirty").html()); }); /** * If the user opens the theme selection screen, indicates which one is active and * saves the information... * ... then when the user closes check if the user confirmed its choice and restore * previous state if this is not the case. */ $dropdown.on("shown.bs.dropdown", function () { check_selected_theme(); $dropdown.find("li").removeClass("selected").filter(function () { return ($(this).has(".o_thumb[style=\""+ "background-image: url(" + (selected_theme && selected_theme.img) + "_small.png)"+ "\"]").length > 0); }).addClass("selected"); }); $dropdown.on("hidden.bs.dropdown", function () { switch_theme(selected_theme); }); /** * On page load, check the selected theme and force switching to it (body needs the * theme style for its edition toolbar). */ check_selected_theme(); $body.addClass(selected_theme.className); switch_images(selected_theme, $snippets); $dropdown.insertAfter($snippets_menu); return ret; function check_if_must_force_theme_choice() { first_choice = editable_area_is_empty(); $body.toggleClass("o_force_mail_theme_choice", first_choice); } function editable_area_is_empty($layout) { $layout = $layout || $editable_area.find(".o_layout"); var $mail_wrapper = $layout.children(".o_mail_wrapper"); var $mail_wrapper_content = $mail_wrapper.find('.o_mail_wrapper_td'); if (!$mail_wrapper_content.length) { // compatibility $mail_wrapper_content = $mail_wrapper; } return ( $editable_area.html().trim() === "" || ($layout.length > 0 && ($layout.html().trim() === "" || $mail_wrapper_content.length > 0 && $mail_wrapper_content.html().trim() === "")) ); } function check_selected_theme() { var $layout = $editable_area.find(".o_layout"); if ($layout.length === 0) { selected_theme = false; } else { _.each(themes_params, function (theme_params) { if ($layout.hasClass(theme_params.className)) { selected_theme = theme_params; } }); } } function switch_images(theme_params, $container) { if (!theme_params) return; $container.find("img").each(function () { var $img = $(this); var src = $img.attr("src"); var m = src.match(/^\/web\/image\/\w+\.s_default_image_(?:theme_[a-z]+_)?(.+)$/); if (!m) { m = src.match(/^\/\w+\/static\/src\/img\/(?:theme_[a-z]+\/)?s_default_image_(.+)\.[a-z]+$/); } if (!m) return; var file = m[1]; var img_info = theme_params.get_image_info(file); if (img_info.format) { src = "/" + img_info.module + "/static/src/img/theme_" + theme_params.name + "/s_default_image_" + file + "." + img_info.format; } else { src = "/web/image/" + img_info.module + ".s_default_image_theme_" + theme_params.name + "_" + file; } $img.attr("src", src); }); } function switch_theme(theme_params) { if (!theme_params || switch_theme.last === theme_params) return; switch_theme.last = theme_params; $body.removeClass(all_classes).addClass(theme_params.className); var $old_layout = $editable_area.find(".o_layout"); var $new_wrapper, $new_wrapper_content; if (theme_params.nowrap) { $new_wrapper = $new_wrapper_content = $("
", {"class": "oe_structure"}); } else { // This wrapper structure is the only way to have a responsive and // centered fixed-width content column on all mail clients $new_wrapper = $('', {class: 'o_mail_wrapper'}); $new_wrapper_content = $("').append( $("
", {class: 'o_mail_no_resize o_mail_no_colorpicker o_mail_wrapper_td oe_structure'}); $new_wrapper.append($('
", {class: 'o_mail_no_resize o_not_editable', contenteditable: 'false'}), $new_wrapper_content, $("", {class: 'o_mail_no_resize o_not_editable', contenteditable: 'false'}) )); } var $new_layout = $("
", {"class": "o_layout " + theme_params.className}).append($new_wrapper); var $contents; if (first_choice) { $contents = theme_params.template; } else if ($old_layout.length) { $contents = ($old_layout.hasClass("oe_structure") ? $old_layout : $old_layout.find(".oe_structure").first()).contents(); } else { $contents = $editable_area.contents(); } $new_wrapper_content.append($contents); switch_images(theme_params, $new_wrapper_content); $editable_area.empty().append($new_layout); $old_layout.remove(); if (first_choice) { self._registerDefaultTexts($new_wrapper_content); } self._disableUndroppableSnippets(); } }, }); var callback = window ? window["callback"] : undefined; odoo_top[callback+"_updown"] = function (value, fields_values, field_name) { if (!window || window.closed) { delete odoo_top[callback+"_updown"]; return; } var $editable = $("#editable_area"); var _val = $editable.prop("innerHTML"); var editor_enable = $('body').hasClass('editor_enable'); value = value || ""; if (value !==_val) { if (editor_enable) { if (value !== fields_values[field_name]) { rte.history.recordUndo($editable); } core.bus.trigger('deactivate_snippet'); } if (value.indexOf('on_change_model_and_list') === -1) { $editable.html(value); if (editor_enable) { if (value !== fields_values[field_name]) { $editable.trigger("content_changed"); } } } } if (fields_values.mailing_model && editor_enable) { if (value.indexOf('on_change_model_and_list') !== -1) { odoo_top[callback+"_downup"](_val); } } }; if ($editable_area.html().indexOf('on_change_model_and_list') !== -1) { $editable_area.empty(); } // Adding compatibility for the outlook compliance of mailings. // Commit of such compatibility : a14f89c8663c9cafecb1cc26918055e023ecbe42 options.registry.background.include({ start: function() { this._super(); var $table_target = this.$target.find('table:first'); if ($table_target) { this.$target = $table_target; } } }); });