QUnit.test('repeated', async function (assert) { assert.expect(4); var $fix = $( "#qunit-fixture"); core.qweb.add_template( '<no>' + '<t t-name="test.widget.template">' + '<p><t t-esc="widget.value"/></p>' + '</t>' + '</no>' ); var widget = new (Widget.extend({ template: 'test.widget.template' }))(); widget.value = 42; await widget.appendTo($fix) .then(function () { assert.strictEqual($fix.find('p').text(), '42', "DOM fixture should contain initial value"); assert.strictEqual(widget.$el.text(), '42', "should set initial value"); widget.value = 36; widget.renderElement(); assert.strictEqual($fix.find('p').text(), '36', "DOM fixture should use new value"); assert.strictEqual(widget.$el.text(), '36', "should set new value"); }); widget.destroy(); });
_.each($items, function (item) { var $item = $(item); var $col; switch (item.tagName) { case 'OPT': var widgetName = $item.data('widget'); // Build the options template var $option = $(core.qweb.render('website.theme_customize_modal_option', { name: optionsName, id: $item.attr('id') || _.uniqueId('o_theme_customize_input_id_'), string: $item.attr('string'), icon: $item.data('icon'), font: $item.data('font'), xmlid: $item.data('xmlid'), enable: $item.data('enable'), disable: $item.data('disable'), reload: $item.data('reload'), widget: widgetName, })); if (widgetName) { var $widget = $(core.qweb.render('website.theme_customize_' + widgetName)); $option.append($widget); } if ($container.hasClass('form-row')) { $col = $('<div/>', { class: _.str.sprintf('col-%s', $item.data('col') || 6), }); $col.append($option); $container.append($col); } else { $container.append($option); } break; case 'LIST': var $listContainer = $('<div/>', {class: 'py-1 px-2 o_theme_customize_option_list'}); $col = $('<div/>', { class: _.str.sprintf('col-%s mt-2', $item.data('col') || 6), 'data-depends': $item.data('depends'), }).append($('<h6/>', {text: $item.attr('string')}), $listContainer); $container.append($col); _processItems($item.children(), $listContainer); break; } });
QUnit.test('template', function (assert) { assert.expect(3); core.qweb.add_template( '<no>' + '<t t-name="test.widget.template">' + '<ol>' + '<li t-foreach="5" t-as="counter" ' + 't-attf-class="class-#{counter}">' + '<input/>' + '<t t-esc="counter"/>' + '</li>' + '</ol>' + '</t>' + '</no>' ); var widget = new (Widget.extend({ template: 'test.widget.template' }))(); widget.renderElement(); assert.strictEqual(widget.el.nodeName, 'OL'); assert.strictEqual(widget.$el.children().length, 5); assert.strictEqual(widget.el.textContent, '01234'); widget.destroy(); });
start: function () { var def = this._super.apply(this, arguments); // If we auto start the editor, do not show a welcome message if (this._editorAutoStart) { this._startEditMode(); return def; } // Check that the page is empty var $wrap = $('#wrapwrap.homepage #wrap'); // TODO find this element another way if (!$wrap.length || $wrap.html().trim() !== '') { return def; } // If readonly empty page, show the welcome message this.$welcomeMessage = $(core.qweb.render('website.homepage_editor_welcome_message')); this.$welcomeMessage.css('min-height', $wrap.parent('main').height() - ($wrap.outerHeight(true) - $wrap.height())); $wrap.empty().append(this.$welcomeMessage); setTimeout(function () { if ($('.o_tooltip.o_animated').length) { $('.o_tooltip_container').addClass('show'); } }, 1000); // ugly hack to wait that tooltip is loaded return def; },
_.each($contents, function (content) { var $content = $(content); var contentID = _.uniqueId('content-'); // Build the nav tab for the content $navLinksContainer.append($('<li/>', { class: 'nav-item mb-1', }).append($('<a/>', { href: '#' + contentID, class: 'nav-link', 'data-toggle': 'tab', text: $content.attr('string'), }))); // Build the tab pane for the content var $navContent = $(core.qweb.render('website.theme_customize_modal_content', { id: contentID, title: $content.attr('title'), })); $navContents.append($navContent); var $optionsContainer = $navContent.find('.o_options_container'); // Process content items _processItems($content.children(), $optionsContainer); });
renderElement: function () { this._super.apply(this, arguments); if (this.contentTemplate) { var content = core.qweb.render(this.contentTemplate, {widget: this}); this.$('.o_content').append(content); } },
onFocus: function () { var self = this; (new Dialog(this, { title: _t("Confirmation"), $content: $(core.qweb.render('website.leaving_current_page_edition')), buttons: [ {text: _t("Go to Link"), classes: 'btn-primary', click: function () { self.trigger_up('request_save', { reload: false, onSuccess: function () { window.location.href = self.$target.attr('href'); }, }); }}, {text: _t("Edit the menu"), classes: 'btn-primary', click: function () { this.trigger_up('action_demand', { actionName: 'edit_menu', params: [ function () { var def = $.Deferred(); self.trigger_up('request_save', { onSuccess: def.resolve.bind(def), onFailure: def.reject.bind(def), }); return def; }, ], }); }}, {text: _t("Stay on this page"), close: true} ] })).open(); },
on_focus: function () { this._super.apply(this, arguments); (new Dialog(null, { title: _t("Confirmation"), $content: $(core.qweb.render("website.leaving_current_page_edition")), buttons: [ {text: _t("Go to Link"), classes: "btn-primary", click: save_editor_then_go_to.bind(null, this.link)}, {text: _t("Edit the menu"), classes: "btn-primary", click: function () { var self = this; website.topBar.content_menu.edit_menu(function () { return editor.editor_bar.save_without_reload(); }).then(function (dialog) { self.close(); }); }}, {text: _t("Stay on this page"), close: true} ] })).open(); function save_editor_then_go_to(url) { editor.editor_bar.save_without_reload().then(function () { window.location.href = url; }); } },
renderElement: function () { var $el; if (this.template) { $el = $(core.qweb.render(this.template, {widget: this}).trim()); } else { $el = this._makeDescriptive(); } this._replaceElement($el); },
new Model('goods').call('name_search', {name: $input.val()} ).then(function(results) { if (results.length <= 0) return self.hide_query_board(); self.$board = $(Core.qweb.render('web_stock_query.search_list', {'values': _.map(results, function(result) { return {id: result[0], name: result[1]}; })})); self.$board.attr('top', $input.height() + 2 + 'px'); $input.parent().find('.stock-query-search-list').html(self.$board); });
templates_def = templates_def.then(function() { core.qweb.add_template(template, function(err) { if (err) { def.reject(err); } else { def.resolve(); } }); return def; });
show_error: function(error) { if (!this.active) { return; } new Dialog(this, { title: "Gooderp " + _.str.capitalize(error.type), $content: core.qweb.render('CrashManager.error', {error: error}), buttons: error.buttons || error_buttons || default_buttons, }).open(); },
show_warning: function(error) { if (!this.active) { return; } new Dialog(this, { size: 'medium', title: "Gooderp " + (_.str.capitalize(error.type) || core._t("Warning")), subtitle: error.data.title, $content: $('<div>').html(core.qweb.render('CrashManager.warning', {error: error})), buttons: warning_buttons || default_buttons }).open(); },
click_handler : function(event) { var $cur = $(event.currentTarget); var edition_mode = ($cur.closest("[contenteditable='true']").size() !== 0); // show it only if not in edition mode if (!edition_mode) { var urls = [], idx = undefined, milliseconds = undefined, params = undefined, $images = $cur.closest(".o_gallery").find("img"), size = 0.8, dimensions = { min_width : Math.round( window.innerWidth * size*0.9), min_height : Math.round( window.innerHeight * size), max_width : Math.round( window.innerWidth * size*0.9), max_height : Math.round( window.innerHeight * size), width : Math.round( window.innerWidth * size*0.9), height : Math.round( window.innerHeight * size) }; $images.each(function() { urls.push($(this).attr("src")); }); var $img = ($cur.is("img") === true) ? $cur : $cur.closest("img"); idx = urls.indexOf($img.attr("src")); milliseconds = $cur.closest(".o_gallery").data("interval") || false; params = { srcs : urls, index: idx, dim : dimensions, interval : milliseconds, id: _.uniqueId("slideshow_") }; var $modal = $(core.qweb.render('website.gallery.slideshow.lightbox', params)); $modal.modal({ keyboard : true, backdrop : true }); $modal.on('hidden.bs.modal', function() { $(this).hide(); $(this).siblings().filter(".modal-backdrop").remove(); // bootstrap leaves a modal-backdrop $(this).remove(); }); $modal.find(".modal-content, .modal-body.o_slideshow").css("height", "100%"); $modal.appendTo(document.body); this.carousel = new animationRegistry.gallery_slider($modal.find(".carousel").carousel()); } } // click_handler
_renderImages: function () { var self = this; if (!this._unsplash.isActive) { return this._super.apply(this, arguments); } if (this._unsplash.error) { this.$('.unsplash_img_container').html( core.qweb.render('web_unsplash.dialog.error.content', { status: this._unsplash.error, }) ); return; } var rows = _(this._unsplash.records).chain() .groupBy(function (a, index) { return Math.floor(index / self.IMAGES_PER_ROW); }) .values() .value(); this.$('.unsplash_img_container').html(core.qweb.render('web_unsplash.dialog.image.content', {rows: rows})); this._highlightSelectedImages(); },
_render: function () { // Render the chain value this.$value.html(core.qweb.render(this.template + ".value", { chain: this.chain, pages: this.pages, })); // Toggle the warning message this.$valid.toggleClass('d-none', !!this.isValid()); // Adapt the popover content var page = _.last(this.pages); var title = ""; if (this.pages.length > 1) { var prevField = _.findWhere(this.pages[this.pages.length - 2], { name: (this.chain.length === this.pages.length) ? this.chain[this.chain.length - 2] : _.last(this.chain), }); if (prevField) title = prevField.string; } this.$(".o_field_selector_popover_header .o_field_selector_title").text(title); var lines = _.filter(page, this.options.filter); if (this.searchValue) { var matches = fuzzy.filter(this.searchValue, _.pluck(lines, 'string')); lines = _.map(_.pluck(matches, 'index'), function (i) { return lines[i]; }); } this.$(".o_field_selector_page").replaceWith(core.qweb.render(this.template + ".page", { lines: lines, followRelations: this.options.followRelations, debug: this.options.debugMode, })); this.$input.val(this.chain.join(".")); },
start_tour: function () { var dialog = new Dialog(this, { title: 'Tours', $content: core.qweb.render('WebClient.DebugManager.ToursDialog', { tours: tour.tours }), }); dialog.opened().then(function () { dialog.$('.o_start_tour').on('click', function (e) { e.preventDefault(); tour.run($(e.target).data('name')); }); }); dialog.open(); },
_getSVGText: function (font, text, width, height) { var $svg = $(core.qweb.render('portal.sign_svg_text', { width: width, height: height, font: font, text: text, type: this.signatureType, })); $svg.attr({ 'xmlns': "http://www.w3.org/2000/svg", 'xmlns:xlink': "http://www.w3.org/1999/xlink", }); return "data:image/svg+xml," + encodeURI($svg[0].outerHTML); },
displayPage: function (animation) { this.$(".o_field_selector_prev_page").toggleClass("hidden", this.pages.length === 1); var page = _.last(this.pages); var title = ""; if (this.pages.length > 1) { var chainParts = this.chain.split("."); var prevField = _.findWhere(this.pages[this.pages.length - 2], { name: this.isSelected ? chainParts[chainParts.length - 2] : _.last(chainParts), }); if (prevField) title = prevField.string; } this.$(".o_field_selector_popover_header .o_field_selector_title").text(title); this.$(".o_field_selector_page").replaceWith(core.qweb.render("FieldSelector.page", {lines: page, animation: animation, debug: this.debug})); },
beforeEach: function() { this.oldQWeb = core.qweb; core.qweb = new QWeb(); core.qweb.add_template( '<no>' + '<t t-name="test.widget.template">' + '<ol>' + '<li t-foreach="5" t-as="counter" ' + 't-attf-class="class-#{counter}">' + '<input/>' + '<t t-esc="counter"/>' + '</li>' + '</ol>' + '</t>' + '</no>' ); },
_onSnippetsLoaded: function (ev) { var self = this; var $snippetsSideBar = ev.data; var $themes = $snippetsSideBar.find("#email_designer_themes").children(); var $snippets = $snippetsSideBar.find(".oe_snippet"); var $snippets_menu = $snippetsSideBar.find("#snippets_menu"); if (config.device.isMobile) { $snippetsSideBar.hide(); console.log(this.$content[0]); this.$content.attr('style', 'padding-left: 0px !important'); } if ($themes.length === 0) { return; } /** * Initialize theme parameters. */ this._allClasses = ""; var themesParams = _.map($themes, function (theme) { var $theme = $(theme); var name = $theme.data("name"); var classname = "o_" + name + "_theme"; self._allClasses += " " + classname; var imagesInfo = _.defaults($theme.data("imagesInfo") || {}, { all: {} }); _.each(imagesInfo, function (info) { info = _.defaults(info, imagesInfo.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 (imagesInfo[filename]) { return imagesInfo[filename]; } return imagesInfo.all; } }; }); $themes.parent().remove(); /** * 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: themesParams })).dropdown(); var firstChoice = this._checkIfMustForceThemeChoice(); /** * 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", function (e) { e.stopImmediatePropagation(); e.preventDefault(); self.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 selectedTheme = false; $dropdown.on("mouseenter", ".dropdown-item", function (e) { if (firstChoice) { return; } e.preventDefault(); var themeParams = themesParams[$(e.currentTarget).index()]; self._switchThemes(firstChoice, themeParams); }); $dropdown.on("mouseleave", ".dropdown-item", function (e) { self._switchThemes(false, selectedTheme); }); $dropdown.on("click", '[data-toggle="dropdown"]', function (e) { var $menu = $dropdown.find('.dropdown-menu'); var isVisible = $menu.hasClass('show'); if (isVisible) { e.preventDefault(); e.stopImmediatePropagation(); $menu.removeClass('show'); } }); $dropdown.on("click", ".dropdown-item", function (e) { e.preventDefault(); e.stopImmediatePropagation(); var themeParams = themesParams[$(e.currentTarget).index()]; if (firstChoice) { self._switchThemes(firstChoice, themeParams); self.$content.closest('body').removeClass("o_force_mail_theme_choice"); firstChoice = false; if ($mail_themes_upgrade.length) { $dropdown.remove(); $snippets_menu.empty(); } } self._switchImages(themeParams, $snippets); selectedTheme = themeParams; // Notify form view self.wysiwyg.getEditable().trigger('change'); $dropdown.find('.dropdown-menu').removeClass('show'); $dropdown.find('.dropdown-item.selected').removeClass('selected'); $dropdown.find('.dropdown-item:eq(' + themesParams.indexOf(selectedTheme) + ')').addClass('selected'); }); /** * 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 () { selectedTheme = self._getSelectedTheme(themesParams); $dropdown.find(".dropdown-item").removeClass("selected").filter(function () { return ($(this).has(".o_thumb[style=\"" + "background-image: url(" + (selectedTheme && selectedTheme.img) + "_small.png)" + "\"]").length > 0); }).addClass("selected"); }); $dropdown.on("hidden.bs.dropdown", function () { self._switchThemes(firstChoice, selectedTheme); }); /** * On page load, check the selected theme and force switching to it (body needs the * theme style for its edition toolbar). */ selectedTheme = this._getSelectedTheme(themesParams); if (selectedTheme) { this.$content.closest('body').addClass(selectedTheme.className); $dropdown.find('.dropdown-item:eq(' + themesParams.indexOf(selectedTheme) + ')').addClass('selected'); this._switchImages(selectedTheme, $snippets); } else if (this.$content.find('.o_layout').length) { themesParams.push({ name: 'o_mass_mailing_no_theme', className: 'o_mass_mailing_no_theme', img: "", template: this.$content.find('.o_layout').addClass('o_mass_mailing_no_theme').clone().find('oe_structure').empty().end().html().trim(), nowrap: true, get_image_info: function () {} }); selectedTheme = this._getSelectedTheme(themesParams); } $dropdown.insertAfter($snippets_menu); },
_.each($items, function (item) { var $item = $(item); var $col; switch (item.tagName) { case 'OPT': var widgetName = $item.data('widget'); var xmlid = $item.data('xmlid'); var renderingOptions = _.extend({ string: $item.attr('string') || data.names[xmlid.split(',')[0].trim()], icon: $item.data('icon'), font: $item.data('font'), }, $item.data()); // Build the options template var $option = $(core.qweb.render('website.theme_customize_modal_option', _.extend({ alone: alone, name: xmlid === undefined ? _.uniqueId('option-') : optionsName, id: $item.attr('id') || _.uniqueId('o_theme_customize_input_id_'), checked: xmlid === undefined || xmlid && (!_.difference(self._getXMLIDs($item), data.enabled).length), widget: widgetName, }, renderingOptions))); $option.find('input') .addClass('o_theme_customize_option_input') .attr({ 'data-xmlid': xmlid, 'data-enable': $item.data('enable'), 'data-disable': $item.data('disable'), 'data-reload': $item.data('reload'), }); if (widgetName) { var $widget = $(core.qweb.render('website.theme_customize_widget_' + widgetName, renderingOptions)); $option.find('label').append($widget); } var $final; if ($container.hasClass('form-row')) { $final = $('<div/>', { class: _.str.sprintf('col-%s', $item.data('col') || 6), }); $final.append($option); } else { $final = $option; } $final.attr('data-depends', $item.data('depends')); $container.append($final); break; case 'LIST': var $listContainer = $('<div/>', {class: 'py-1 px-2 o_theme_customize_option_list'}); $col = $('<div/>', { class: _.str.sprintf('col-%s mt-2', $item.data('col') || 6), 'data-depends': $item.data('depends'), }).append($('<h6/>', {text: $item.attr('string')}), $listContainer); $container.append($col); _processItems($item.children(), $listContainer); break; default: _processItems($item.children(), $container); break; } });
start: function () { this.$('.o_we_search_icon').replaceWith(core.qweb.render('web_unsplash.dialog.media.search_icon')); return this._super.apply(this, arguments); },
}).then(function (data) { return core.qweb.add_template(data); });
_updateTemplateBody: function () { this.$el.empty(); this.images = _.uniq(this.images); this.$el.append(core.qweb.render('website.og_image_body', {widget: this})); },
_generateDialogHTML: function () { var $contents = this.$el.children('content'); if ($contents.length === 0) { return; } $contents.remove(); this.$el.append(core.qweb.render('website.theme_customize_modal_layout')); var $navLinksContainer = this.$('.nav'); var $navContents = this.$('.tab-content'); _.each($contents, function (content) { var $content = $(content); var contentID = _.uniqueId('content-'); // Build the nav tab for the content $navLinksContainer.append($('<li/>', { class: 'nav-item mb-1', }).append($('<a/>', { href: '#' + contentID, class: 'nav-link', 'data-toggle': 'tab', text: $content.attr('string'), }))); // Build the tab pane for the content var $navContent = $(core.qweb.render('website.theme_customize_modal_content', { id: contentID, title: $content.attr('title'), })); $navContents.append($navContent); var $optionsContainer = $navContent.find('.o_options_container'); // Process content items _processItems($content.children(), $optionsContainer); }); this.$('[title]').tooltip(); function _processItems($items, $container) { var optionsName = _.uniqueId('option-'); _.each($items, function (item) { var $item = $(item); var $col; switch (item.tagName) { case 'OPT': var widgetName = $item.data('widget'); // Build the options template var $option = $(core.qweb.render('website.theme_customize_modal_option', { name: optionsName, id: $item.attr('id') || _.uniqueId('o_theme_customize_input_id_'), string: $item.attr('string'), icon: $item.data('icon'), font: $item.data('font'), xmlid: $item.data('xmlid'), enable: $item.data('enable'), disable: $item.data('disable'), reload: $item.data('reload'), widget: widgetName, })); if (widgetName) { var $widget = $(core.qweb.render('website.theme_customize_' + widgetName)); $option.append($widget); } if ($container.hasClass('form-row')) { $col = $('<div/>', { class: _.str.sprintf('col-%s', $item.data('col') || 6), }); $col.append($option); $container.append($col); } else { $container.append($option); } break; case 'LIST': var $listContainer = $('<div/>', {class: 'py-1 px-2 o_theme_customize_option_list'}); $col = $('<div/>', { class: _.str.sprintf('col-%s mt-2', $item.data('col') || 6), 'data-depends': $item.data('depends'), }).append($('<h6/>', {text: $item.attr('string')}), $listContainer); $container.append($col); _processItems($item.children(), $listContainer); break; } }); } },
function prompt(options, qweb) { /** * A bootstrapped version of prompt() albeit asynchronous * This was built to quickly prompt the user with a single field. * For anything more complex, please use editor.Dialog class * * Usage Ex: * * website.prompt("What... is your quest ?").then(function (answer) { * arthur.reply(answer || "To seek the Holy Grail."); * }); * * website.prompt({ * select: "Please choose your destiny", * init: function() { * return [ [0, "Sub-Zero"], [1, "Robo-Ky"] ]; * } * }).then(function (answer) { * mame_station.loadCharacter(answer); * }); * * @param {Object|String} options A set of options used to configure the prompt or the text field name if string * @param {String} [options.window_title=''] title of the prompt modal * @param {String} [options.input] tell the modal to use an input text field, the given value will be the field title * @param {String} [options.textarea] tell the modal to use a textarea field, the given value will be the field title * @param {String} [options.select] tell the modal to use a select box, the given value will be the field title * @param {Object} [options.default=''] default value of the field * @param {Function} [options.init] optional function that takes the `field` (enhanced with a fillWith() method) and the `dialog` as parameters [can return a deferred] */ if (typeof options === 'string') { options = { text: options }; } if (_.isUndefined(qweb)) { qweb = 'website.prompt'; } options = _.extend({ window_title: '', field_name: '', 'default': '', // dict notation for IE<9 init: function() {}, }, options || {}); var type = _.intersection(Object.keys(options), ['input', 'textarea', 'select']); type = type.length ? type[0] : 'input'; options.field_type = type; options.field_name = options.field_name || options[type]; var def = $.Deferred(); var dialog = $(core.qweb.render(qweb, options)).appendTo("body"); options.$dialog = dialog; var field = dialog.find(options.field_type).first(); field.val(options['default']); // dict notation for IE<9 field.fillWith = function (data) { if (field.is('select')) { var select = field[0]; data.forEach(function (item) { select.options[select.options.length] = new Option(item[1], item[0]); }); } else { field.val(data); } }; var init = options.init(field, dialog); $.when(init).then(function (fill) { if (fill) { field.fillWith(fill); } dialog.modal('show'); field.focus(); dialog.on('click', '.btn-primary', function () { def.resolve(field.val(), field, dialog); dialog.remove(); $('.modal-backdrop').remove(); }); }); dialog.on('hidden.bs.modal', function () { def.reject(); dialog.remove(); $('.modal-backdrop').remove(); }); if (field.is('input[type="text"], select')) { field.keypress(function (e) { if (e.which == 13) { e.preventDefault(); dialog.find('.btn-primary').trigger('click'); } }); } return def; }
_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", 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", ".dropdown-item", function (e) { if (first_choice) return; e.preventDefault(); var theme_params = themes_params[$(e.currentTarget).index()]; switch_theme(theme_params); }); $dropdown.on("click", ".dropdown-item", function (e) { e.preventDefault(); var theme_params = themes_params[$(e.currentTarget).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(".dropdown-item").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; var $new_wrapper_content; if (theme_params.nowrap) { $new_wrapper = $('<div/>', {class: 'oe_structure'}); $new_wrapper_content = $new_wrapper; } else { // This wrapper structure is the only way to have a responsive // and centered fixed-width content column on all mail clients $new_wrapper = $('<table/>', {class: 'o_mail_wrapper'}); $new_wrapper_content = $('<td/>', {class: 'o_mail_no_options o_mail_wrapper_td oe_structure'}); $new_wrapper.append($('<tr/>').append( $('<td/>', {class: 'o_mail_no_resize o_not_editable', contenteditable: 'false'}), $new_wrapper_content, $('<td/>', {class: 'o_mail_no_resize o_not_editable', contenteditable: 'false'}) )); } var $new_layout = $('<div/>', {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(); } },
}).then( function (data) { self.$('#language-box').html(core.qweb.render('Configurator.language_promote', { 'language': data, 'def_lang': base.get_context().lang })); });
_generateDialogHTML: function (data) { var self = this; var $contents = this.$el.children('content'); if ($contents.length === 0) { return; } $contents.remove(); this.$el.append(core.qweb.render('website.theme_customize_modal_layout')); var $navLinksContainer = this.$('.nav'); var $navContents = this.$('.tab-content'); _.each($contents, function (content) { var $content = $(content); var contentID = _.uniqueId('content-'); // Build the nav tab for the content $navLinksContainer.append($('<li/>', { class: 'nav-item mb-1', }).append($('<a/>', { href: '#' + contentID, class: 'nav-link', 'data-toggle': 'tab', text: $content.attr('string'), }))); // Build the tab pane for the content var $navContent = $(core.qweb.render('website.theme_customize_modal_content', { id: contentID, title: $content.attr('title'), })); $navContents.append($navContent); var $optionsContainer = $navContent.find('.o_options_container'); // Process content items _processItems($content.children(), $optionsContainer); }); this.$('[title]').tooltip(); this.$inputs = self.$('.o_theme_customize_option_input'); // Enable data-xmlid="" inputs if none of their neighbors were enabled _.each(this.$inputs.filter('[data-xmlid=""]'), function (input) { var $input = $(input); var $neighbors = self.$inputs.filter('[name="' + $input.attr('name') + '"]').not($input); if ($neighbors.length && !$neighbors.filter(':checked').length) { $input.prop('checked', true); } }); this._setActive(); this._updateValues(); function _processItems($items, $container) { var optionsName = _.uniqueId('option-'); var alone = ($items.length === 1); _.each($items, function (item) { var $item = $(item); var $col; switch (item.tagName) { case 'OPT': var widgetName = $item.data('widget'); var xmlid = $item.data('xmlid'); var renderingOptions = _.extend({ string: $item.attr('string') || data.names[xmlid.split(',')[0].trim()], icon: $item.data('icon'), font: $item.data('font'), }, $item.data()); // Build the options template var $option = $(core.qweb.render('website.theme_customize_modal_option', _.extend({ alone: alone, name: xmlid === undefined ? _.uniqueId('option-') : optionsName, id: $item.attr('id') || _.uniqueId('o_theme_customize_input_id_'), checked: xmlid === undefined || xmlid && (!_.difference(self._getXMLIDs($item), data.enabled).length), widget: widgetName, }, renderingOptions))); $option.find('input') .addClass('o_theme_customize_option_input') .attr({ 'data-xmlid': xmlid, 'data-enable': $item.data('enable'), 'data-disable': $item.data('disable'), 'data-reload': $item.data('reload'), }); if (widgetName) { var $widget = $(core.qweb.render('website.theme_customize_widget_' + widgetName, renderingOptions)); $option.find('label').append($widget); } var $final; if ($container.hasClass('form-row')) { $final = $('<div/>', { class: _.str.sprintf('col-%s', $item.data('col') || 6), }); $final.append($option); } else { $final = $option; } $final.attr('data-depends', $item.data('depends')); $container.append($final); break; case 'LIST': var $listContainer = $('<div/>', {class: 'py-1 px-2 o_theme_customize_option_list'}); $col = $('<div/>', { class: _.str.sprintf('col-%s mt-2', $item.data('col') || 6), 'data-depends': $item.data('depends'), }).append($('<h6/>', {text: $item.attr('string')}), $listContainer); $container.append($col); _processItems($item.children(), $listContainer); break; default: _processItems($item.children(), $container); break; } }); } },