summaryrefslogtreecommitdiff
path: root/addons/website/static/src
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-09-13 18:07:59 +0200
committerChristophe Simonis <chs@odoo.com>2019-09-13 18:07:59 +0200
commit6c948c36bbf72dd896e0bff03aa7fbddadcbb0cd (patch)
treef8620905c011735d8a3c340c46d1417a54a75972 /addons/website/static/src
parent48503fcf08eac6fed12e080d4f501f9bbc8d257d (diff)
parent197474e5b9ad43ab2d587a98136a1a809ce9a2e7 (diff)
[MERGE] forward port branch saas-12.5 up to 197474e5b9a
Diffstat (limited to 'addons/website/static/src')
-rwxr-xr-xaddons/website/static/src/img/snippets_thumbs/s_mega_menu_menu_image_menu.pngbin0 -> 669 bytes
-rwxr-xr-xaddons/website/static/src/img/snippets_thumbs/s_mega_menu_multi_menus.pngbin0 -> 372 bytes
-rw-r--r--addons/website/static/src/js/backend/dashboard.js2
-rw-r--r--addons/website/static/src/js/content/menu.js3
-rw-r--r--addons/website/static/src/js/content/website_root.js2
-rw-r--r--addons/website/static/src/js/editor/editor_menu.js2
-rw-r--r--addons/website/static/src/js/editor/snippets.options.js76
-rw-r--r--addons/website/static/src/js/editor/wysiwyg_multizone.js142
-rw-r--r--addons/website/static/src/js/menu/content.js121
-rw-r--r--addons/website/static/src/js/menu/seo.js10
-rw-r--r--addons/website/static/src/js/menu/translate.js7
-rw-r--r--addons/website/static/src/js/tours/banner.js10
-rw-r--r--addons/website/static/src/scss/website.edit_mode.scss252
-rw-r--r--addons/website/static/src/scss/website.editor.ui.scss225
-rw-r--r--addons/website/static/src/scss/website.scss45
-rw-r--r--addons/website/static/src/scss/website.ui.scss4
-rw-r--r--addons/website/static/src/scss/website.wysiwyg.scss380
-rw-r--r--addons/website/static/src/xml/website.contentMenu.xml8
-rw-r--r--addons/website/static/src/xml/website.seo.xml6
19 files changed, 591 insertions, 704 deletions
diff --git a/addons/website/static/src/img/snippets_thumbs/s_mega_menu_menu_image_menu.png b/addons/website/static/src/img/snippets_thumbs/s_mega_menu_menu_image_menu.png
new file mode 100755
index 00000000000..47a0c3a0d0a
--- /dev/null
+++ b/addons/website/static/src/img/snippets_thumbs/s_mega_menu_menu_image_menu.png
Binary files differ
diff --git a/addons/website/static/src/img/snippets_thumbs/s_mega_menu_multi_menus.png b/addons/website/static/src/img/snippets_thumbs/s_mega_menu_multi_menus.png
new file mode 100755
index 00000000000..28832219719
--- /dev/null
+++ b/addons/website/static/src/img/snippets_thumbs/s_mega_menu_multi_menus.png
Binary files differ
diff --git a/addons/website/static/src/js/backend/dashboard.js b/addons/website/static/src/js/backend/dashboard.js
index dda40102904..28b9a55c8a4 100644
--- a/addons/website/static/src/js/backend/dashboard.js
+++ b/addons/website/static/src/js/backend/dashboard.js
@@ -185,7 +185,7 @@ var Dashboard = AbstractAction.extend({
};
});
- var ctx = document.getElementById(chart_id);
+ var ctx = this.$canvas[0];
this.chart = new Chart(ctx, {
type: 'line',
data: {
diff --git a/addons/website/static/src/js/content/menu.js b/addons/website/static/src/js/content/menu.js
index 9d3d5621f65..1b6fa07a5c0 100644
--- a/addons/website/static/src/js/content/menu.js
+++ b/addons/website/static/src/js/content/menu.js
@@ -19,6 +19,7 @@ publicWidget.registry.affixMenu = publicWidget.Widget.extend({
this.$headerClone.insertAfter(this.$target);
this.$headers = this.$target.add(this.$headerClone);
this.$dropdowns = this.$headers.find('.dropdown');
+ this.$dropdownMenus = this.$headers.find('.dropdown-menu');
this.$navbarCollapses = this.$headers.find('.navbar-collapse');
this._adaptDefaultOffset();
@@ -100,7 +101,7 @@ publicWidget.registry.affixMenu = publicWidget.Widget.extend({
this.$headerClone.toggleClass('affixed', wOffset > (hOffset + 300));
// Reset opened menus
- this.$dropdowns.removeClass('show');
+ this.$dropdowns.add(this.$dropdownMenus).removeClass('show');
this.$navbarCollapses.removeClass('show').attr('aria-expanded', false);
},
});
diff --git a/addons/website/static/src/js/content/website_root.js b/addons/website/static/src/js/content/website_root.js
index 4b61a33d779..a8e208f1408 100644
--- a/addons/website/static/src/js/content/website_root.js
+++ b/addons/website/static/src/js/content/website_root.js
@@ -105,7 +105,7 @@ var WebsiteRoot = publicRootData.PublicRoot.extend({
var $target = $(ev.target);
// retrieve the hash before the redirect
var redirect = {
- lang: $target.data('lang'),
+ lang: $target.data('url_code'),
url: encodeURIComponent($target.attr('href').replace(/[&?]edit_translations[^&?]+/, '')),
hash: encodeURIComponent(window.location.hash)
};
diff --git a/addons/website/static/src/js/editor/editor_menu.js b/addons/website/static/src/js/editor/editor_menu.js
index 72c2e6bee81..87422efdb1f 100644
--- a/addons/website/static/src/js/editor/editor_menu.js
+++ b/addons/website/static/src/js/editor/editor_menu.js
@@ -113,7 +113,7 @@ var EditorMenu = Widget.extend({
save: function (reload) {
var self = this;
this.trigger_up('edition_will_stopped');
- return this.wysiwyg.save(true).then(function (result) {
+ return this.wysiwyg.save(false).then(function (result) {
var $wrapwrap = $('#wrapwrap');
self.editable($wrapwrap).removeClass('o_editable');
if (result.isDirty && reload !== false) {
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index d659677c478..baa1d8c5a7c 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -1297,35 +1297,51 @@ options.registry.gallery = options.Class.extend({
* @override
*/
_setActive: function () {
- this._super();
- var classes = _.uniq((this.$target.attr('class').replace(/(^|\s)o_/g, ' ') || '').split(/\s+/));
- this.$el.find('[data-mode]')
- .removeClass('active')
- .filter('[data-mode="' + classes.join('"], [data-mode="') + '"]').addClass('active');
- var mode = this.$el.find('[data-mode].active').data('mode');
+ this._super(...arguments);
- classes = _.uniq((this.$('img:first').attr('class') || '').split(/\s+/));
- this.$el.find('[data-styling]')
+ var activeModeSelectors = [];
+ for (const className of this.$target[0].classList) {
+ if (className.startsWith('o_')) {
+ activeModeSelectors.push('[data-mode="' + className.substring(2) + '"]');
+ }
+ }
+ var activeMode = this.$el.find('[data-mode]')
.removeClass('active')
- .filter('[data-styling="' + classes.join('"], [data-styling="') + '"]').addClass('active');
-
- this.$el.find('[data-interval]').removeClass('active')
- .filter('[data-interval='+this.$target.find('.carousel:first').attr('data-interval')+']')
+ .filter(activeModeSelectors.join(', '))
+ .addClass('active')
+ .data('mode');
+
+ var carousel = this.$target[0].querySelector('.carousel');
+ var activeInterval = carousel ? carousel.dataset.interval : undefined;
+ var $intervalOptions = this.$el.find('[data-interval]');
+ $intervalOptions.removeClass('active')
+ .filter('[data-interval="' + activeInterval + '"]')
.addClass('active');
-
- var interval = this.$target.find('.carousel:first').attr('data-interval');
- this.$el.find('[data-interval]')
- .removeClass('active')
- .filter('[data-interval=' + interval + ']').addClass('active');
+ $intervalOptions.closest('we-collapse-area')[0]
+ .classList.toggle('d-none', activeMode !== 'slideshow');
var columns = this._getColumns();
- this.$el.find('[data-columns]')
- .removeClass('active')
- .filter('[data-columns=' + columns + ']').addClass('active');
-
- this.$el.find('[data-columns]:first, [data-select-class="spc-none"]')
- .parent().parent().toggle(['grid', 'masonry'].indexOf(mode) !== -1);
- this.$el.find('[data-interval]:first').parent().parent().toggle(mode === 'slideshow');
+ var $columnOptions = this.$el.find('[data-columns]');
+ $columnOptions.removeClass('active')
+ .filter('[data-columns="' + columns + '"]')
+ .addClass('active');
+ $columnOptions.closest('we-collapse-area')[0]
+ .classList.toggle('d-none', !(activeMode === 'grid' || activeMode === 'masonry'));
+
+ this.el.querySelector('.o_w_image_spacing_option')
+ .classList.toggle('d-none', activeMode === 'slideshow');
+
+ var $stylingOptions = this.$el.find('[data-styling]');
+ $stylingOptions.removeClass('active');
+ var img = this.$target[0].querySelector('img');
+ if (img) {
+ var activeStyleSelectors = [];
+ for (const className of img.classList) {
+ activeStyleSelectors.push('[data-styling="' + className + '"]');
+ }
+ $stylingOptions.filter(activeStyleSelectors.join(', '))
+ .addClass('active');
+ }
},
});
@@ -1410,7 +1426,7 @@ options.registry.topMenuTransparency = options.Class.extend({
enabled = value;
},
});
- this.$el.find('[data-transparent]').addBack('[data-transparent]').toggleClass('active', !!enabled);
+ this.$el.find('[data-transparent]').toggleClass('active', !!enabled);
},
});
@@ -1465,7 +1481,6 @@ options.registry.topMenuColor = options.registry.colorpicker.extend({
*/
options.registry.anchorName = options.Class.extend({
xmlDependencies: ['/website/static/src/xml/website.editor.xml'],
- preventChildPropagation: true,
//--------------------------------------------------------------------------
// Public
@@ -1493,6 +1508,13 @@ options.registry.anchorName = options.Class.extend({
click: function () {
var $input = this.$('.o_input_anchor_name');
var anchorName = $input.val().trim().replace(/\s/g, '_');
+ if (self.$target[0].id === anchorName) {
+ // If the chosen anchor name is already the one used by the
+ // element, close the dialog and do nothing else
+ this.close();
+ return;
+ }
+
var isValid = /^[\w-]+$/.test(anchorName);
var alreadyExists = isValid && $('#' + anchorName).length > 0;
var anchorOK = isValid && !alreadyExists;
@@ -1520,7 +1542,7 @@ options.registry.anchorName = options.Class.extend({
});
}
new Dialog(this, {
- title: _t("Anchor Name"),
+ title: _t("Link Anchor"),
$content: $(qweb.render('website.dialog.anchorName', {
currentAnchor: this.$target.attr('id'),
})),
diff --git a/addons/website/static/src/js/editor/wysiwyg_multizone.js b/addons/website/static/src/js/editor/wysiwyg_multizone.js
index 202257857d2..9ed31d3afe5 100644
--- a/addons/website/static/src/js/editor/wysiwyg_multizone.js
+++ b/addons/website/static/src/js/editor/wysiwyg_multizone.js
@@ -1,7 +1,38 @@
odoo.define('web_editor.wysiwyg.multizone', function (require) {
'use strict';
+
var Wysiwyg = require('web_editor.wysiwyg');
+var snippetsEditor = require('web_editor.snippet.editor');
+/**
+ * Show/hide the dropdowns associated to the given toggles and allows to wait
+ * for when it is fully shown/hidden.
+ *
+ * Note: this also takes care of the fact the 'toggle' method of bootstrap does
+ * not properly work in all cases.
+ *
+ * @param {jQuery} $toggles
+ * @param {boolean} [show]
+ * @returns {Promise<jQuery>}
+ */
+function toggleDropdown($toggles, show) {
+ return Promise.all(_.map($toggles, toggle => {
+ var $toggle = $(toggle);
+ var $dropdown = $toggle.parent();
+ var shown = $dropdown.hasClass('show');
+ if (shown === show) {
+ return;
+ }
+ var toShow = !shown;
+ return new Promise(resolve => {
+ $dropdown.one(
+ toShow ? 'shown.bs.dropdown' : 'hidden.bs.dropdown',
+ () => resolve()
+ );
+ $toggle.dropdown(toShow ? 'show' : 'hide');
+ });
+ })).then(() => $toggles);
+}
/**
* HtmlEditor
@@ -13,7 +44,6 @@ var Wysiwyg = require('web_editor.wysiwyg');
*
*/
var WysiwygMultizone = Wysiwyg.extend({
-
/**
* @override
*/
@@ -24,7 +54,35 @@ var WysiwygMultizone = Wysiwyg.extend({
var outerHTML = this._getEscapedElement($el).prop('outerHTML');
return self._saveElement(outerHTML, self.options.recordInfo, $el[0]);
};
- return this._super();
+
+ // Mega menu initialization: handle dropdown openings by hand
+ var $megaMenuToggles = this.$('.o_mega_menu_toggle');
+ $megaMenuToggles.removeAttr('data-toggle').dropdown('dispose');
+ $megaMenuToggles.on('click.wysiwyg_multizone', ev => {
+ var $toggle = $(ev.currentTarget);
+
+ // Each time we toggle a dropdown, we will destroy the dropdown
+ // behavior afterwards to keep manual control of it
+ var dispose = ($els => $els.dropdown('dispose'));
+
+ // First hide all other mega menus
+ toggleDropdown($megaMenuToggles.not($toggle), false).then(dispose);
+
+ // Then toggle the clicked one
+ toggleDropdown($toggle)
+ .then(dispose)
+ .then($el => {
+ var isShown = $el.parent().hasClass('show');
+ this.editor.snippetsMenu.toggleMegaMenuSnippets(isShown);
+ });
+ });
+
+ return this._super.apply(this, arguments).then(() => {
+ // Showing Mega Menu snippets if one dropdown is already opened
+ if (this.$('.o_mega_menu').hasClass('show')) {
+ this.editor.snippetsMenu.toggleMegaMenuSnippets(true);
+ }
+ });
},
/**
* @override
@@ -32,20 +90,26 @@ var WysiwygMultizone = Wysiwyg.extend({
*/
save: function () {
if (this.isDirty()) {
- return this.editor.save().then(function() {
- return {isDirty: true};
- });
+ return this._restoreMegaMenus()
+ .then(() => this.editor.save(false))
+ .then(() => ({isDirty: true}));
} else {
return {isDirty: false};
}
},
-
+ /**
+ * @override
+ */
+ destroy: function () {
+ this._restoreMegaMenus();
+ this._super.apply(this, arguments);
+ },
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
- _getEditableArea: function() {
+ _getEditableArea: function () {
return $(':o_editable');
},
/**
@@ -59,8 +123,9 @@ var WysiwygMultizone = Wysiwyg.extend({
* page element)
*/
_saveElement: function (outerHTML, recordInfo, editable) {
+ var promises = [];
var $el = $(editable);
- return this._rpc({
+ promises.push(this._rpc({
model: 'ir.ui.view',
method: 'save',
args: [
@@ -69,7 +134,66 @@ var WysiwygMultizone = Wysiwyg.extend({
$el.data('oe-xpath') || null,
],
context: recordInfo.context,
- });
+ }));
+ if ($el.data('oe-field') === 'mega_menu_content') {
+ // On top of saving the mega menu content like any other field
+ // content, we must save the custom classes that were set on the
+ // menu itself.
+ // FIXME normally removing the 'show' class should not be necessary here
+ // TODO check that editor classes are removed here as well
+ var classes = _.without($el.attr('class').split(' '), 'dropdown-menu', 'o_mega_menu', 'show');
+ promises.push(this._rpc({
+ model: 'website.menu',
+ method: 'write',
+ args: [
+ [parseInt($el.data('oe-id'))],
+ {
+ 'mega_menu_classes': classes.join(' '),
+ },
+ ],
+ }));
+ }
+ return Promise.all(promises);
+ },
+ /**
+ * Restores mega menu behaviors and closes them (important to do before
+ * saving otherwise they would be saved opened).
+ *
+ * @private
+ * @returns {Promise}
+ */
+ _restoreMegaMenus: function () {
+ var $megaMenuToggles = this.$('.o_mega_menu_toggle');
+ $megaMenuToggles.off('.wysiwyg_multizone')
+ .attr('data-toggle', 'dropdown')
+ .dropdown({});
+ return toggleDropdown($megaMenuToggles, false);
+ },
+});
+
+snippetsEditor.Class.include({
+ /**
+ * @private
+ * @param {boolean} show
+ */
+ toggleMegaMenuSnippets: function (show) {
+ setTimeout(() => this._activateSnippet(false));
+ this.$('#snippet_mega_menu').toggleClass('d-none', !show);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _insertDropzone: function ($hook) {
+ var $hookParent = $hook.parent();
+ var $dropzone = this._super(...arguments);
+ $dropzone.attr('data-editor-message', $hookParent.attr('data-editor-message'));
+ $dropzone.attr('data-editor-sub-message', $hookParent.attr('data-editor-sub-message'));
+ return $dropzone;
},
});
diff --git a/addons/website/static/src/js/menu/content.js b/addons/website/static/src/js/menu/content.js
index 9582e0f4778..c0daa93925f 100644
--- a/addons/website/static/src/js/menu/content.js
+++ b/addons/website/static/src/js/menu/content.js
@@ -369,14 +369,15 @@ var MenuEntryDialog = weWidgets.LinkDialog.extend({
* @constructor
*/
init: function (parent, options, data) {
- data.text = data.name || '';
- data.isNewWindow = data.new_window;
-
this._super(parent, _.extend({
title: _t("Add a menu item"),
}, options || {}), _.extend({
needLabel: true,
+ text: data.name || '',
+ isNewWindow: data.new_window,
}, data || {}));
+
+ this.menuType = data.menuType;
},
/**
* @override
@@ -391,6 +392,13 @@ var MenuEntryDialog = weWidgets.LinkDialog.extend({
// Adapt URL label
this.$('label[for="o_link_dialog_label_input"]').text(_t("Menu Label"));
+ // Auto add '#' URL and hide the input if for mega menu
+ if (this.menuType === 'mega') {
+ var $url = this.$('input[name="url"]');
+ $url.val('#').trigger('change');
+ $url.closest('.form-group').addClass('d-none');
+ }
+
return this._super.apply(this, arguments);
},
@@ -469,7 +477,6 @@ var EditMenuDialog = weWidgets.Dialog.extend({
*/
willStart: function () {
var defs = [this._super.apply(this, arguments)];
- var self = this;
var context;
this.trigger_up('context_get', {
callback: function (ctx) {
@@ -480,11 +487,11 @@ var EditMenuDialog = weWidgets.Dialog.extend({
model: 'website.menu',
method: 'get_tree',
args: [context.website_id, this.rootID],
- }).then(function (menu) {
- self.menu = menu;
- self.root_menu_id = menu.id;
- self.flat = self._flatenize(menu);
- self.to_delete = [];
+ }).then(menu => {
+ this.menu = menu;
+ this.rootMenuID = menu.fields['id'];
+ this.flat = this._flatenize(menu);
+ this.toDelete = [];
}));
return Promise.all(defs);
},
@@ -505,6 +512,10 @@ var EditMenuDialog = weWidgets.Dialog.extend({
tolerance: 'pointer',
attribute: 'data-menu-id',
expression: '()(.+)', // nestedSortable takes the second match of an expression (*sigh*)
+ isAllowed: (placeholder, placeholderParent, currentItem) => {
+ return !placeholderParent
+ || !currentItem[0].dataset.megaMenu && !placeholderParent[0].dataset.megaMenu;
+ },
});
return r;
},
@@ -518,8 +529,7 @@ var EditMenuDialog = weWidgets.Dialog.extend({
*/
save: function () {
var _super = this._super.bind(this);
- var self = this;
- var new_menu = this.$('.oe_menu_editor').nestedSortable('toArray', {startDepthCount: 0});
+ var newMenus = this.$('.oe_menu_editor').nestedSortable('toArray', {startDepthCount: 0});
var levels = [];
var data = [];
var context;
@@ -529,20 +539,25 @@ var EditMenuDialog = weWidgets.Dialog.extend({
},
});
// Resequence, re-tree and remove useless data
- new_menu.forEach(function (menu) {
+ newMenus.forEach(menu => {
if (menu.id) {
levels[menu.depth] = (levels[menu.depth] || 0) + 1;
- var mobj = self.flat[menu.id];
- mobj.sequence = levels[menu.depth];
- mobj.parent_id = (menu.parent_id|0) || menu.parent_id || self.root_menu_id;
- delete(mobj.children);
- data.push(mobj);
+ var menuFields = this.flat[menu.id].fields;
+ menuFields['sequence'] = levels[menu.depth];
+ menuFields['parent_id'] = menu['parent_id'] || this.rootMenuID;
+ data.push(menuFields);
}
});
- this._rpc({
+ return this._rpc({
model: 'website.menu',
method: 'save',
- args: [context.website_id, { data: data, to_delete: self.to_delete }],
+ args: [
+ context.website_id,
+ {
+ 'data': data,
+ 'to_delete': this.toDelete,
+ }
+ ],
}).then(function () {
return _super();
});
@@ -563,10 +578,9 @@ var EditMenuDialog = weWidgets.Dialog.extend({
*/
_flatenize: function (node, _dict) {
_dict = _dict || {};
- var self = this;
- _dict[node.id] = node;
- node.children.forEach(function (child) {
- self._flatenize(child, _dict);
+ _dict[node.fields['id']] = node;
+ node.children.forEach(child => {
+ this._flatenize(child, _dict);
});
return _dict;
},
@@ -580,23 +594,31 @@ var EditMenuDialog = weWidgets.Dialog.extend({
* dialog to edit this new menu.
*
* @private
+ * @param {Event} ev
*/
- _onAddMenuButtonClick: function () {
- var self = this;
- var dialog = new MenuEntryDialog(this, {}, {});
- dialog.on('save', this, function (link) {
- var new_menu = {
- id: _.uniqueId('new-'),
- name: link.text,
- url: link.url,
- new_window: link.isNewWindow,
- parent_id: false,
- sequence: 0,
- children: [],
+ _onAddMenuButtonClick: function (ev) {
+ var menuType = ev.currentTarget.dataset.type;
+ var dialog = new MenuEntryDialog(this, {}, {
+ menuType: menuType,
+ });
+ dialog.on('save', this, link => {
+ var newMenu = {
+ 'fields': {
+ 'id': _.uniqueId('new-'),
+ 'name': link.text,
+ 'url': link.url,
+ 'new_window': link.isNewWindow,
+ 'is_mega_menu': menuType === 'mega',
+ 'sequence': 0,
+ 'parent_id': false,
+ },
+ 'children': [],
+ 'is_homepage': false,
};
- self.flat[new_menu.id] = new_menu;
- self.$('.oe_menu_editor').append(
- qweb.render('website.contentMenu.dialog.submenu', { submenu: new_menu }));
+ this.flat[newMenu.fields['id']] = newMenu;
+ this.$('.oe_menu_editor').append(
+ qweb.render('website.contentMenu.dialog.submenu', {submenu: newMenu})
+ );
});
dialog.open();
},
@@ -607,9 +629,9 @@ var EditMenuDialog = weWidgets.Dialog.extend({
*/
_onDeleteMenuButtonClick: function (ev) {
var $menu = $(ev.currentTarget).closest('[data-menu-id]');
- var menuID = $menu.data('menu-id')|0;
+ var menuID = parseInt($menu.data('menu-id'));
if (menuID) {
- this.to_delete.push(menuID);
+ this.toDelete.push(menuID);
}
$menu.remove();
},
@@ -620,21 +642,20 @@ var EditMenuDialog = weWidgets.Dialog.extend({
* @private
*/
_onEditMenuButtonClick: function (ev) {
- var self = this;
- var menu_id = $(ev.currentTarget).closest('[data-menu-id]').data('menu-id');
- var menu = self.flat[menu_id];
+ var $menu = $(ev.currentTarget).closest('[data-menu-id]');
+ var menuID = $menu.data('menu-id');
+ var menu = this.flat[menuID];
if (menu) {
- var dialog = new MenuEntryDialog(this, {}, menu);
- dialog.on('save', this, function (link) {
- var id = link.id;
- var menu_obj = self.flat[id];
- _.extend(menu_obj, {
+ var dialog = new MenuEntryDialog(this, {}, _.extend({
+ menuType: menu.fields['is_mega_menu'] ? 'mega' : undefined,
+ }, menu.fields));
+ dialog.on('save', this, link => {
+ _.extend(menu.fields, {
'name': link.text,
'url': link.url,
'new_window': link.isNewWindow,
});
- var $menu = self.$('[data-menu-id="' + id + '"]');
- $menu.find('.js_menu_label').first().text(menu_obj.name);
+ $menu.find('.js_menu_label').first().text(menu.fields['name']);
});
dialog.open();
} else {
diff --git a/addons/website/static/src/js/menu/seo.js b/addons/website/static/src/js/menu/seo.js
index 3844a1d4731..60bc2318955 100644
--- a/addons/website/static/src/js/menu/seo.js
+++ b/addons/website/static/src/js/menu/seo.js
@@ -20,7 +20,7 @@ var Suggestion = Widget.extend({
template: 'website.seo_suggestion',
xmlDependencies: ['/website/static/src/xml/website.seo.xml'],
events: {
- 'click .js_seo_suggestion': 'select',
+ 'click .o_seo_suggestion': 'select',
},
init: function (parent, options) {
@@ -106,7 +106,7 @@ var Keyword = Widget.extend({
},
start: function () {
var self = this;
- this.$('.js_seo_keyword_suggestion').empty();
+ this.$('.o_seo_keyword_suggestion').empty();
this.suggestionList = new SuggestionList(this, {
root: this.keyword,
language: this.language,
@@ -115,7 +115,7 @@ var Keyword = Widget.extend({
this.suggestionList.on('selected', this, function (word, language) {
this.trigger('selected', word, language);
});
- return this.suggestionList.appendTo(this.$('.js_seo_keyword_suggestion')).then(function() {
+ return this.suggestionList.appendTo(this.$('.o_seo_keyword_suggestion')).then(function() {
self.htmlPage.on('title-changed', self, self._updateTitle);
self.htmlPage.on('description-changed', self, self._updateDescription);
self._updateTitle();
@@ -497,9 +497,7 @@ var MetaKeywords = Widget.extend({
},
});
this._rpc({
- model: 'website',
- method: 'get_languages',
- args: [[context.website_id]],
+ route: '/website/get_languages',
}).then(function (data) {
self.$('#language-box').html(core.qweb.render('Configurator.language_promote', {
'language': data,
diff --git a/addons/website/static/src/js/menu/translate.js b/addons/website/static/src/js/menu/translate.js
index 043a900fff6..cab37bf3473 100644
--- a/addons/website/static/src/js/menu/translate.js
+++ b/addons/website/static/src/js/menu/translate.js
@@ -46,14 +46,11 @@ var TranslatePageMenu = websiteNavbarData.WebsiteNavbarActionWidget.extend({
* @returns {Promise}
*/
_goToMasterPage: function () {
- var lang = '/' + utils.get_cookie('frontend_lang');
-
var current = document.createElement('a');
current.href = window.location.toString();
current.search += (current.search ? '&' : '?') + 'enable_editor=1';
- if (current.pathname.indexOf(lang) === 0) {
- current.pathname = current.pathname.replace(lang, '');
- }
+ // we are in translate mode, the pathname starts with '/<url_code/'
+ current.pathname = current.pathname.substr(current.pathname.indexOf('/', 1));
var link = document.createElement('a');
link.href = '/website/lang/default';
diff --git a/addons/website/static/src/js/tours/banner.js b/addons/website/static/src/js/tours/banner.js
index 5febdf1c749..f4ddc040c69 100644
--- a/addons/website/static/src/js/tours/banner.js
+++ b/addons/website/static/src/js/tours/banner.js
@@ -24,10 +24,14 @@ tour.register("banner", {
position: "bottom",
run: "text",
}, {
- trigger: ".oe_overlay_options .oe_options",
+ trigger: ".o_we_customize_panel",
extra_trigger: "#wrapwrap .s_cover h1:not(:containsExact(\"Catchy Headline\"))",
content: _t("Customize any block through this menu. Try to change the background color of this block."),
- position: "top",
+ position: "right",
+}, {
+ trigger: '.o_we_add_snippet_btn',
+ content: _t("Go back to the blocks menu."),
+ position: 'bottom',
}, {
trigger: "#snippet_structure .oe_snippet:eq(3) .oe_snippet_thumbnail",
content: _t("Drag another block in your page, below the cover."),
@@ -35,7 +39,6 @@ tour.register("banner", {
run: "drag_and_drop #wrap",
}, {
trigger: "button[data-action=save]",
- extra_trigger: ".oe_overlay_options .oe_options",
content: _t("Click the <b>Save</b> button."),
position: "bottom",
}, {
@@ -69,7 +72,6 @@ tour.register("banner", {
run: "drag_and_drop #wrap",
}, {
trigger: "button[data-action=save]",
- extra_trigger: ".oe_overlay_options .oe_options",
content: _t("Click the <b>Save</b> button."),
position: "bottom",
}, {
diff --git a/addons/website/static/src/scss/website.edit_mode.scss b/addons/website/static/src/scss/website.edit_mode.scss
index 17c3ee13bb3..5693f6e7526 100644
--- a/addons/website/static/src/scss/website.edit_mode.scss
+++ b/addons/website/static/src/scss/website.edit_mode.scss
@@ -1,223 +1,20 @@
+$-editor-messages-margin-x: 2%;
+%o-editor-messages {
+ width: 100% - $-editor-messages-margin-x * 2; // Need to be forced here to avoid flickering
+ margin: 20px $-editor-messages-margin-x;
+ border: 2px dashed $o-we-color-text-normal;
+ padding: 112px 0px;
+ text-align: center;
+ color: $o-we-color-text-normal;
-@each $url in $o-theme-font-urls {
- @if $url {
- @import url("https://fonts.googleapis.com/css?family=#{unquote($url)}");
+ &:before {
+ content: attr(data-editor-message);
+ display: block;
+ font-size: 20px;
}
-}
-
-.modal.o_theme_customize_modal {
- .modal-dialog {
- @include o-position-absolute(0, 2%);
- width: 96%;
- max-width: 550px;
- }
- .modal-header {
- background-color: $o-brand-odoo;
- color: white;
- border-radius: 0;
-
- * {
- color: inherit;
- }
- }
-
- .close:hover, .close:focus {
- color: white;
- }
-
- .nav {
- padding: 0;
-
- .nav-item {
- background-color: $o-brand-lightsecondary;
-
- .nav-link {
- color: $o-main-text-color;
-
- &.active {
- font-weight: bold;
- background-color: white;
- border: 1px solid #d9d7d7;
- border-left: 1px solid #333333;
- }
- &:hover, &:focus {
- text-decoration: none;
- }
- }
- }
- }
-
- .dropdown-menu {
- position: static !important;
- transform: none !important;
- min-width: 100%;
- }
-
- .o_theme_customize_option {
- position: relative;
- width: 100%;
-
- > img {
- width: 100%;
-
- + label {
- @include o-position-absolute(0, 0, 0, 0);
- width: auto;
- background: transparent !important;
- }
- }
-
- label {
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- min-height: 24px;
- margin: 0;
- padding: 8px;
- text-align: center;
- font-size: 14px;
- line-height: 1;
- cursor: pointer;
-
- &:hover::after {
- content: "";
- pointer-events: none;
- @include o-position-absolute(0, 0, 0, 0);
- background-color: rgba(0, 32, 64, 0.03);
- }
-
- &.o_switch {
- justify-content: flex-start;
- }
- }
- &:not(.dropdown-item) label {
- border: 2px solid transparent;
- background-color: $o-brand-lightsecondary;
-
- &.checked {
- border-color: $o-brand-odoo;
- color: $o-brand-odoo;
- }
- }
-
- &.o_theme_customize_with_widget {
- label {
- justify-content: flex-start;
- text-align: left;
-
- &.checked {
- border-color: transparent;
- color: inherit;
- }
- }
- }
- }
-
- .o_theme_customize_color {
- position: relative;
- width: 30px;
- height: 20px;
- margin-left: auto;
- border: 1px solid black;
-
- &::before, &::after {
- content: "";
- @include o-position-absolute(0, 0, 0, 0);
- }
- &::before {
- background-image: url('/web_editor/static/src/img/transparent.png');
- }
- &::after {
- background-color: inherit;
- }
- }
-
- .o_theme_customize_input {
- flex: 1 1 auto;
- text-align: right;
-
- .fa-edit {
- visibility: hidden;
- color: $o-brand-primary;
- }
- }
- .o_theme_customize_option:hover .o_theme_customize_input .fa-edit {
- visibility: visible;
- }
-
- .o_theme_customize_active_input {
- @include o-position-absolute(0, 0, 0, 0);
- width: auto;
- padding: 3px;
-
- > * {
- height: 100% !important;
-
- &.form-control {
- background: white !important;
- }
-
- &.form-control, .btn {
- padding: 2px 8px !important;
- text-align: right !important;
- font-size: $font-size-sm !important;
- }
- }
- }
-
- .o_theme_customize_option_input {
- position: absolute;
- clip: rect(0, 0, 0, 0);
- pointer-events: none;
- }
-
- .o_theme_customize_option_list {
- box-shadow: 0 0 40px 0 rgba(0, 0, 0, 0.05);
- }
-
- .o_theme_customize_dropdown_btn {
- background-color: $o-brand-lightsecondary;
- }
-
- $i: 1;
- @each $font in $o-theme-fonts {
- .o_theme_customize_option_font_#{$i} {
- font-family: if($font, $font, $font-family-base);
-
- &.o_theme_customize_option > label > span,
- &.dropdown-toggle {
- &::before {
- content: nth($o-theme-font-names, $i);
- }
- }
- }
- $i: $i + 1;
- }
-
- .o_theme_customize_delete_google_font {
- @include o-position-absolute(1px, 1px, 1px, auto);
- padding: 0 8px !important;
- }
-}
-
-
-.o_homepage_editor_welcome_message {
- padding-top: 128px;
- padding-bottom: 128px;
- font-family: Roboto, $font-family-sans-serif;
-
- .o_tooltip_container {
- transition: opacity 1s linear;
-
- > .o_tooltip {
- @include o-position-absolute;
- position: relative;
- display: inline-block;
- margin: 0 8px;
- opacity: 1;
- z-index: auto;
- }
+ &:after {
+ content: attr(data-editor-sub-message);
+ display: block;
}
}
@@ -249,19 +46,12 @@
&.oe_structure.oe_empty, &[data-oe-type=html] {
&:empty {
- border: 2px dashed gray('400');
- margin: 20px;
- padding: 112px 0px;
- text-align: center;
- color: gray('400');
- &:before {
- content: attr(data-editor-message);
- font-size: 20px;
- }
- &:after {
- display: block;
- content: attr(data-editor-sub-message);
- }
+ @extend %o-editor-messages;
+ }
+ > .oe_drop_zone.oe_insert:not(.oe_vertical):only-child {
+ @extend %o-editor-messages;
+ height: auto;
+ color: $o-brand-odoo;
}
> p:empty:only-child {
color: #aaa;
diff --git a/addons/website/static/src/scss/website.editor.ui.scss b/addons/website/static/src/scss/website.editor.ui.scss
index 403b7929a92..5071e2f8b90 100644
--- a/addons/website/static/src/scss/website.editor.ui.scss
+++ b/addons/website/static/src/scss/website.editor.ui.scss
@@ -1,3 +1,224 @@
+@each $url in $o-theme-font-urls {
+ @if $url {
+ @import url("https://fonts.googleapis.com/css?family=#{unquote($url)}");
+ }
+}
+
+.modal.o_theme_customize_modal {
+ .modal-dialog {
+ @include o-position-absolute(0, 2%);
+ width: 96%;
+ max-width: 550px;
+ }
+ .modal-header {
+ background-color: $o-brand-odoo;
+ color: white;
+ border-radius: 0;
+
+ * {
+ color: inherit;
+ }
+ }
+
+ .close:hover, .close:focus {
+ color: white;
+ }
+
+ .nav {
+ padding: 0;
+
+ .nav-item {
+ background-color: $o-brand-lightsecondary;
+
+ .nav-link {
+ color: $o-main-text-color;
+
+ &.active {
+ font-weight: bold;
+ background-color: white;
+ border: 1px solid #d9d7d7;
+ border-left: 1px solid #333333;
+ }
+ &:hover, &:focus {
+ text-decoration: none;
+ }
+ }
+ }
+ }
+
+ .dropdown-menu {
+ position: static !important;
+ transform: none !important;
+ min-width: 100%;
+ }
+
+ .o_theme_customize_option {
+ position: relative;
+ width: 100%;
+
+ > img {
+ width: 100%;
+
+ + label {
+ @include o-position-absolute(0, 0, 0, 0);
+ width: auto;
+ background: transparent !important;
+ }
+ }
+
+ label {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ min-height: 24px;
+ margin: 0;
+ padding: 8px;
+ text-align: center;
+ font-size: 14px;
+ line-height: 1;
+ cursor: pointer;
+
+ &:hover::after {
+ content: "";
+ pointer-events: none;
+ @include o-position-absolute(0, 0, 0, 0);
+ background-color: rgba(0, 32, 64, 0.03);
+ }
+
+ &.o_switch {
+ justify-content: flex-start;
+ }
+ }
+ &:not(.dropdown-item) label {
+ border: 2px solid transparent;
+ background-color: $o-brand-lightsecondary;
+
+ &.checked {
+ border-color: $o-brand-odoo;
+ color: $o-brand-odoo;
+ }
+ }
+
+ &.o_theme_customize_with_widget {
+ label {
+ justify-content: flex-start;
+ text-align: left;
+
+ &.checked {
+ border-color: transparent;
+ color: inherit;
+ }
+ }
+ }
+ }
+
+ .o_theme_customize_color {
+ position: relative;
+ width: 30px;
+ height: 20px;
+ margin-left: auto;
+ border: 1px solid black;
+
+ &::before, &::after {
+ content: "";
+ @include o-position-absolute(0, 0, 0, 0);
+ }
+ &::before {
+ background-image: url('/web_editor/static/src/img/transparent.png');
+ }
+ &::after {
+ background-color: inherit;
+ }
+ }
+
+ .o_theme_customize_input {
+ flex: 1 1 auto;
+ text-align: right;
+
+ .fa-edit {
+ visibility: hidden;
+ color: $o-brand-primary;
+ }
+ }
+ .o_theme_customize_option:hover .o_theme_customize_input .fa-edit {
+ visibility: visible;
+ }
+
+ .o_theme_customize_active_input {
+ @include o-position-absolute(0, 0, 0, 0);
+ width: auto;
+ padding: 3px;
+
+ > * {
+ height: 100% !important;
+
+ &.form-control {
+ background: white !important;
+ }
+
+ &.form-control, .btn {
+ padding: 2px 8px !important;
+ text-align: right !important;
+ font-size: $font-size-sm !important;
+ }
+ }
+ }
+
+ .o_theme_customize_option_input {
+ position: absolute;
+ clip: rect(0, 0, 0, 0);
+ pointer-events: none;
+ }
+
+ .o_theme_customize_option_list {
+ box-shadow: 0 0 40px 0 rgba(0, 0, 0, 0.05);
+ }
+
+ .o_theme_customize_dropdown_btn {
+ background-color: $o-brand-lightsecondary;
+ }
+
+ $i: 1;
+ @each $font in $o-theme-fonts {
+ .o_theme_customize_option_font_#{$i} {
+ font-family: if($font, $font, $font-family-base);
+
+ &.o_theme_customize_option > label > span,
+ &.dropdown-toggle {
+ &::before {
+ content: nth($o-theme-font-names, $i);
+ }
+ }
+ }
+ $i: $i + 1;
+ }
+
+ .o_theme_customize_delete_google_font {
+ @include o-position-absolute(1px, 1px, 1px, auto);
+ padding: 0 8px !important;
+ }
+}
+
+.o_homepage_editor_welcome_message {
+ padding-top: 128px;
+ padding-bottom: 128px;
+ font-family: Roboto, $font-family-sans-serif;
+
+ .o_tooltip_container {
+ transition: opacity 1s linear;
+
+ > .o_tooltip {
+ @include o-position-absolute;
+ position: relative;
+ display: inline-block;
+ margin: 0 8px;
+ opacity: 1;
+ z-index: auto;
+ }
+ }
+}
+
// INPUTS
.o_switch {
display: flex;
@@ -8,7 +229,7 @@
>input {
display: none;
- +span {
+ + span {
background-color: $o-we-switch-inactive-color;
box-shadow: inset 0 0 0px 1px darken($o-we-switch-inactive-color, 10%);
border-radius: 100rem;
@@ -20,7 +241,7 @@
&:after {
content: "";
- background: $o-we-color-paper;
+ background: $o-we-bg-color;
display: block;
width: $o-we-switch-size - 0.2;
height: $o-we-switch-size - 0.2;
diff --git a/addons/website/static/src/scss/website.scss b/addons/website/static/src/scss/website.scss
index cb919db80d4..b5ce0126afb 100644
--- a/addons/website/static/src/scss/website.scss
+++ b/addons/website/static/src/scss/website.scss
@@ -840,10 +840,15 @@ table.table_desc tr td {
&.o_slideshow {
.carousel {
height: 100%;
+
.carousel-inner {
height: 100%;
}
- .carousel-item {
+ .carousel-item.active,
+ .carousel-item-next,
+ .carousel-item-prev {
+ display: flex;
+ align-items: center;
height: 100%;
padding-bottom: 64px;
}
@@ -909,8 +914,14 @@ table.table_desc tr td {
background-color: inherit;
}
}
- &.s_parallax_is_fixed > .s_parallax_bg {
- background-attachment: fixed;
+ @include media-breakpoint-up(xl) {
+ // Fixed backgrounds are disabled when using a mobile/tablet device,
+ // which is not a big deal but, on some of them (iOS...), defining the
+ // background as fixed breaks the background-size/position props.
+ // So we enable this only for >= XL devices.
+ &.s_parallax_is_fixed > .s_parallax_bg {
+ background-attachment: fixed;
+ }
}
}
@@ -1089,6 +1100,34 @@ table.table_desc tr td {
}
}
+// Mega menu
+.o_mega_menu {
+ width: 100%;
+ padding: 0;
+ margin-top: 0;
+
+ .container, .container-fluid {
+ // Need to reforce those because they are removed since its a container
+ // inside another container (the one in the navbar)
+ padding-left: $grid-gutter-width / 2;
+ padding-right: $grid-gutter-width / 2;
+ }
+}
+.o_mega_menu_container_size {
+ @include media-breakpoint-up(md) {
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ $-mm-max-widths: ();
+ @each $k, $v in $container-max-widths {
+ $-mm-max-widths: map-merge($-mm-max-widths, (
+ #{$k}: $v - $grid-gutter-width,
+ ));
+ }
+ @include make-container-max-widths($-mm-max-widths);
+}
+
// Copyright
.o_footer_copyright {
padding: 8px;
diff --git a/addons/website/static/src/scss/website.ui.scss b/addons/website/static/src/scss/website.ui.scss
index 0acd4c36cd0..e2f4cf7f3b6 100644
--- a/addons/website/static/src/scss/website.ui.scss
+++ b/addons/website/static/src/scss/website.ui.scss
@@ -284,6 +284,10 @@ body .modal {
}
}
}
+
+ td.o_seo_keyword_suggestion span.o_seo_suggestion.badge {
+ cursor: pointer;
+ }
}
}
diff --git a/addons/website/static/src/scss/website.wysiwyg.scss b/addons/website/static/src/scss/website.wysiwyg.scss
index 1f5151f5da8..3206e4b027a 100644
--- a/addons/website/static/src/scss/website.wysiwyg.scss
+++ b/addons/website/static/src/scss/website.wysiwyg.scss
@@ -1,48 +1,27 @@
-//------------------------------------------------------------------------------
-// Modifications applied on normal website DOM while being in the editor.
-//------------------------------------------------------------------------------
-
-//------------------------------------------------------------------------------
-// Editor components style.
-//------------------------------------------------------------------------------
-
-body.editor_enable {
- padding-top: $o-navbar-height !important;
+// Override css variables to influence the default style of the editor without
+// duplicating the css.
+:root {
+ --o-we-toolbar-height: #{$o-navbar-height};
+ --o-we-bg-color: #{$o-we-color-dark};
+ --o-we-bg-color-dark: #{$o-we-color-darker};
+ --o-we-color: #{$o-we-color-text-normal};
+ --o-we-color-accent: #{$o-we-color-text-light};
+
+ --o-we-dropdown-bg-color: #{$o-we-color-darker};
+ --o-we-dropdown-color: #{$o-we-color-text-normal};
+
+ --o-we-snippets-bg-color: #{$o-we-color-normal};
+ --o-we-snippets-color: #{$o-we-color-text-light};
}
-#wrapwrap {
- height: calc(100vh - #{$o-navbar-height});
-}
-
-// TOP BAR (EDIT)
+// EDITOR TOP BAR AND POPOVER
#web_editor-top-edit {
- height: $o-navbar-height;
- background-color: $o-we-color-dark;
- border: 0;
- z-index: $zindex-modal - 9;
-
- .note-popover .popover {
- width: 100%;
- height: $o-navbar-height;
- text-align: left;
-
- .popover-body {
- height: $o-navbar-height;
-
- .btn {
- height: $o-navbar-height;
- }
- }
- }
-
form.navbar-form {
+ @include o-position-absolute(0, 0, 0, auto);
+ z-index: $zindex-popover + 5;
height: $o-navbar-height;
- z-index: 1060;
margin: 0;
padding: 0;
- position: absolute;
- top: -1px;
- right: -1px;
transition: right 0.4s $o-we-md-ease 0s;
border-left: 1px solid $o-we-color-divider;
@@ -96,19 +75,11 @@ body.editor_enable {
}
}
-body:not(.editor_enable) form.navbar-form {
+.note-statusbar {
display: none;
}
-// SNIPPETS
-#oe_snippets {
- border: 0;
- #snippets_menu {
- height: $o-navbar-height;
- }
-}
-
-// Translations
+// TRANSLATIONS
.oe_translate_examples li {
margin: 10px;
padding: 4px;
@@ -126,60 +97,10 @@ html[lang] > body.editor_enable [data-oe-translation-state] {
}
}
-// NOTE EDITOR
-
-// SNIPPET PANEL
-#oe_snippets {
- @include o-w-preserve-btn;
- position: fixed;
- width: $o-we-sidebar-width;
- z-index: 1042;
-
- border-top: 0;
- border-right: 1px solid $o-we-color-divider;
- transition: left 400ms $o-we-md-ease 0s;
- background-image: linear-gradient(45deg, $o-we-color-normal, darken($o-we-color-normal, 10%));
-
- #snippets_menu {
- color: #999999;
- background: $o-we-color-dark;
- font-family: $o-we-font-family;
- height: $o-navbar-height;
- line-height: $o-navbar-height;
- }
-
- #o_scroll {
- .o_panel_header {
- color: #999999;
- }
- }
-}
-
-.oe_snippet {
- background-color: $o-we-color-normal;
-
- .oe_snippet_thumbnail {
- .oe_snippet_thumbnail_img {
- border: 1px solid $o-we-color-normal;
- }
-
- img.oe_snippet_thumbnail_img {}
-
- .oe_snippet_thumbnail_title {
- border: 1px solid $o-we-color-dark;
- color: $o-we-color-text-light;
- }
-
- &:hover .oe_snippet_thumbnail_title {
- color: $o-we-color-text-lighter;
- }
- }
-}
-
// SNIPPET OPTIONS
.colorpicker {
.o_colorpicker_sections {
- .note-color-palette>div {
+ .note-color-palette > div {
color: $o-we-color-text-light;
}
}
@@ -191,7 +112,7 @@ html[lang] > body.editor_enable [data-oe-translation-state] {
clear: both;
}
- >button {
+ > button {
&:hover,
&.selected {
@@ -223,173 +144,22 @@ html[lang] > body.editor_enable [data-oe-translation-state] {
}
}
-// DROPZONES
-#wrapwrap .oe_drop_zone {
- &.oe_insert {
- height: $o-we-dropzone-size;
- margin: (-$o-we-dropzone-size/2) 0;
-
- &:after {
- border-bottom: $o-we-dropzone-border;
- }
-
- &.oe_vertical {
- width: $o-we-dropzone-size;
- margin: 0 (-$o-we-dropzone-size/2);
-
- &:after {
- border-right: $o-we-dropzone-border;
- }
- }
- }
-}
-
-// MANIPULATORS
-#oe_manipulators {
-
- // SNIPPET MANIPULATORS
- .oe_overlay {
-
- // OVERLAY OPTIONS
- >.oe_overlay_options {
- font-family: $o-we-font-family;
-
- >.btn-group {
- .btn {
- height: $o-we-overlay-option-size;
- border: 1px solid $o-we-color-dark;
- line-height: #{$o-we-overlay-option-size - 2px};
-
- color: $o-we-color-text-light;
- background-color: $o-we-color-light;
-
- &:hover {
- background-color: lighten($o-we-color-dark, 10%);
- }
-
- &.oe_snippet_remove {
- background-color: $o-we-color-danger;
- border-color: darken($o-we-color-danger, 20%);
-
- &:hover {
- background-color: darken($o-we-color-danger, 20%);
- }
- }
-
- >.fa {
- color: $o-we-color-text-light;
- }
- }
-
- // CUSTOMIZE MENU BUTTON
- >.oe_options {
- .btn {
- background-color: $o-we-color-dark;
- color: $o-we-color-text-light;
-
- &:hover,
- &:active,
- &:focus {
- background-color: lighten($o-we-color-dark, 5%);
- border-color: lighten($o-we-color-dark, 10%);
- }
-
- &:before,
- &:after {
- background-color: $o-we-color-text-light;
- }
- }
-
- // Open menu
- &.show .btn {
- // background-color: $o-we-color-light;
- }
-
- // CUSTOMIZE MENU
- .dropdown-menu {
- border: 1px solid $o-we-color-dark;
- background-color: $o-we-color-light;
-
- .dropdown-item {
- color: $o-we-color-text-light;
-
- &:hover {
- background-color: fade-out($o-we-color-dark, 0.5);
- }
-
- &.active {
- background-color: fade-out($o-we-color-dark, 0.5);
- }
- }
-
- .dropdown-header {
- color: wheat;
-
- &.o_parent_editor_header {
- color: wheat;
- }
- }
-
- .dropdown-submenu {
- &::before {
- border-left-color: $o-we-color-text-light;
- }
- }
- }
- }
- }
- }
-
- &.o_top_cover>.oe_overlay_options {
- top: $o-we-handle-border-width;
- right: $o-we-handle-border-width;
- }
-
- }
-}
-
-// Animations
-@keyframes fadeInDownSmall {
- 0% {
- opacity: 0;
- transform: translate(0, -5px);
- }
-
- 100% {
- opacity: 1;
- transform: translate(0, 0);
- }
-}
-
+// ANIMATIONS
@keyframes fadeInOut {
0% {
opacity: 0;
}
-
25% {
opacity: 1;
}
-
75% {
opacity: 1;
}
-
100% {
opacity: 0;
}
}
-@keyframes inputHighlighter {
- from {
- background: $o-brand-primary;
- }
-
- to {
- width: 0;
- background: transparent;
- }
-}
-
// MODALS
body .modal {
@@ -547,109 +317,3 @@ body .modal {
}
}
}
-
-.note-editor {
- &>.note-toolbar-wrapper .note-toolbar {
- height: $o-navbar-height;
-
- .btn {
- height: $o-navbar-height !important; // force this because of themes
- }
- }
-
- &>.note-statusbar {
- display: none;
- }
-
- &>.note-editing-area {
- overflow: visible;
- }
-}
-
-#web_editor-toolbars .popover,
-.note-popover,
-.note-editor>.note-toolbar-wrapper .note-toolbar {
- // force this because of themes
- background-color: $o-we-color-dark !important;
-
- .btn {
- background-color: $o-we-color-dark !important;
- color: $o-we-color-text-normal !important;
- border: none !important;
- padding: 0.0625rem 0.3125rem !important;
-
- >.fa {
- color: $o-we-color-text-normal !important;
- }
-
- &:hover {
- color: $o-we-color-text-light !important;
-
- >.fa {
- color: $o-we-color-text-light !important;
- }
- }
-
- &.active {
- background-color: $o-we-color-dark !important;
- color: $o-we-color-text-light !important;
-
- >.fa {
- color: $o-we-color-text-light !important;
- }
- }
- }
-
- >.btn-group {
- margin-top: 0 !important;
-
- &.show,
- .btn-group.show {
- .dropdown-toggle {
- border-top: 2px solid white !important;
- background-color: $o-we-color-darker !important;
- color: white !important;
- box-shadow: none !important;
-
- >.fa,
- >span {
- color: white !important;
- }
- }
- }
- }
-
- .dropdown-menu {
- margin: 0 !important;
- border-radius: 0 !important;
- background-color: $o-we-color-darker !important;
- color: $o-we-color-text-normal !important;
- white-space: normal !important;
-
- .dropdown-item {
- width: 100% !important;
- color: $o-we-color-text-light !important;
-
- >.fa {
- color: $o-we-color-text-light !important;
- }
-
- &:hover {
- background-color: $o-we-tab-active-bg !important;
- color: white !important;
-
- >.fa {
- color: white !important;
- }
- }
- }
- }
-
- .note-para .dropdown-menu {
- min-width: 147px !important;
- }
-
- .note-style .dropdown-item * {
- color: $o-we-color-text-light !important;
- }
-}
diff --git a/addons/website/static/src/xml/website.contentMenu.xml b/addons/website/static/src/xml/website.contentMenu.xml
index edf166b946d..af318703b5c 100644
--- a/addons/website/static/src/xml/website.contentMenu.xml
+++ b/addons/website/static/src/xml/website.contentMenu.xml
@@ -1,15 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website.contentMenu.dialog.submenu">
- <li t-att-data-menu-id="submenu.id">
+ <li t-att-data-menu-id="submenu.fields['id']" t-att-data-mega-menu="submenu.fields['is_mega_menu'] ? true : undefined">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text fa fa-bars" role="img" aria-label="Dropdown menu" title="Dropdown menu"/>
</div>
<span class="form-control d-flex align-items-center">
<span class="js_menu_label o_text_overflow flex-grow-1">
- <t t-esc="submenu.name"/>
+ <t t-esc="submenu.fields['name']"/>
</span>
+ <span t-if="submenu.fields['is_mega_menu']" class="badge badge-primary">Mega Menu</span>
<i t-if="submenu.is_homepage" class="fa fa-home ml-3" role="img" aria-label="Home" title="Home"/>
</span>
<span class="input-group-append">
@@ -49,6 +50,9 @@
</small>
<a href="#" class="js_add_menu">
<i class="fa fa-plus-circle"/> Add Menu Item
+ </a><br/>
+ <a href="#" class="js_add_menu" data-type="mega">
+ <i class="fa fa-plus-circle"/> Add Mega Menu Item
</a>
</div>
</div>
diff --git a/addons/website/static/src/xml/website.seo.xml b/addons/website/static/src/xml/website.seo.xml
index e3c442d8f32..de1fc86fa23 100644
--- a/addons/website/static/src/xml/website.seo.xml
+++ b/addons/website/static/src/xml/website.seo.xml
@@ -2,7 +2,7 @@
<templates id="template" xml:space="preserve">
<t t-name="Configurator.language_promote">
<t t-foreach="language" t-as="lang">
- <option t-att-value="lang[0]" t-att-selected="lang[0] == def_lang ? 'selected' : null"><t t-esc="lang[1]" /></option>
+ <option t-att-value="lang[0]" t-att-selected="lang[0] == def_lang ? 'selected' : null"><t t-esc="lang[2]" /></option>
</t>
</t>
@@ -32,14 +32,14 @@
<td class="text-center"><i class="js_seo_keyword_title fa fa-check" style="visibility: hidden;" t-attf-title="{{ widget.keyword }} is used in page title"/></td>
<td class="text-center"><i class="js_seo_keyword_description fa fa-check" style="visibility: hidden;" t-attf-title="{{ widget.keyword }} is used in page description"/></td>
<td class="text-center"><i t-if="widget.used_content" class="fa fa-check" t-attf-title="{{ widget.keyword }} is used in page content"/></td>
- <td class="js_seo_keyword_suggestion"/>
+ <td class="o_seo_keyword_suggestion"/>
<td class="text-center"><a href="#" class="oe_remove" data-action="remove-keyword" t-attf-title="Remove {{ widget.keyword }}"><i class="fa fa-trash"/></a></td>
</tr>
</t>
<t t-name="website.seo_suggestion">
<li class="list-inline-item">
- <span class="js_seo_suggestion badge badge-info" t-att-data-keyword="widget.keyword" t-esc="widget.keyword"/>
+ <span class="o_seo_suggestion badge badge-info" t-att-data-keyword="widget.keyword" t-attf-title="Add {{ widget.keyword }}" t-esc="widget.keyword"/>
</li>
</t>