From 78c59afd133de8308f4eeb6e1a2a930d870878e7 Mon Sep 17 00:00:00 2001 From: Younn Olivier Date: Thu, 18 Aug 2022 11:58:04 +0000 Subject: [PATCH] [FIX] website, *: fix the website custom systray and menus in mobile *: website_event, website_links This commit fixes the navbar on the enterprise mobile mode. With the enterprise modules, in mobile mode, the navbar menus are removed and displayed in an an additional systray item, the BurgerMenu. This behavior was not adapted to the website systray and contextual custom menus, introduced in [1]. For the website systray, some elements are hidden in mobile: - the "edit" and "translate" buttons, - the mobile preview, - the "+ new" new content button, The logic for displaying the contextual custom menus is moved from the navbar patch to a service, so that we can define a patch for the BurgerMenu that uses that logic and has the same behavior as the navbar. For now, the "Menu Editor" and the "HTML/CSS Editor" menus are hidden in mobile. [1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b task-2687506 closes odoo/odoo#99605 Signed-off-by: Quentin Smetz (qsm) --- addons/website/__manifest__.py | 2 + .../src/components/burger_menu/burger_menu.js | 49 +++++ .../static/src/components/navbar/navbar.js | 64 ++++++ .../static/src/components/switch/switch.js | 2 +- .../static/src/components/switch/switch.scss | 1 - .../src/services/website_custom_menus.js | 187 +++++++----------- .../static/src/services/website_service.js | 3 - .../src/systray_items/edit_in_backend.xml | 4 +- .../static/src/systray_items/edit_website.xml | 2 +- .../src/systray_items/mobile_preview.xml | 2 +- .../static/src/systray_items/new_content.xml | 2 +- .../static/src/systray_items/publish.js | 2 +- .../src/systray_items/translate_website.xml | 2 +- .../src/systray_items/website_switcher.js | 1 + .../src/systray_items/website_switcher.xml | 9 +- .../static/tests/website_service_mock.js | 15 ++ .../src/js/services/website_custom_menus.js | 27 +-- .../src/services/website_custom_menus.js | 19 +- 18 files changed, 231 insertions(+), 162 deletions(-) create mode 100644 addons/website/static/src/components/burger_menu/burger_menu.js create mode 100644 addons/website/static/src/components/navbar/navbar.js diff --git a/addons/website/__manifest__.py b/addons/website/__manifest__.py index a3fbdab52ae..e232a5d55e1 100644 --- a/addons/website/__manifest__.py +++ b/addons/website/__manifest__.py @@ -241,6 +241,8 @@ 'website/static/src/components/dialog/*.scss', 'website/static/src/components/editor/editor.js', 'website/static/src/components/editor/editor.scss', + 'website/static/src/components/navbar/navbar.js', + 'website/static/src/components/burger_menu/burger_menu.js', 'website/static/src/components/switch/switch.js', 'website/static/src/components/switch/switch.scss', 'website/static/src/components/wysiwyg_adapter/wysiwyg_adapter.js', diff --git a/addons/website/static/src/components/burger_menu/burger_menu.js b/addons/website/static/src/components/burger_menu/burger_menu.js new file mode 100644 index 00000000000..f1ee3574f7d --- /dev/null +++ b/addons/website/static/src/components/burger_menu/burger_menu.js @@ -0,0 +1,49 @@ +/** @odoo-module **/ + +import { BurgerMenu } from '@web/webclient/burger_menu/burger_menu'; +import { useService } from '@web/core/utils/hooks'; +import { registry } from "@web/core/registry"; +import { patch } from 'web.utils'; + +const websiteSystrayRegistry = registry.category('website_systray'); + +patch(BurgerMenu.prototype, 'website_burger_menu', { + setup() { + this._super(); + this.websiteCustomMenus = useService('website_custom_menus'); + + if (!websiteSystrayRegistry.contains('burger_menu')) { + websiteSystrayRegistry.add('burger_menu', registry.category('systray').get('burger_menu'), {sequence: 0}); + } + }, + + /** + * @override + */ + get currentAppSections() { + const currentAppSections = this._super(); + if (this.currentApp && this.currentApp.xmlid === 'website.menu_website_configuration') { + return this.websiteCustomMenus.addCustomMenus(currentAppSections).filter(section => section.childrenTree.length); + } + return currentAppSections; + }, + + /** + * This dummy setter is only here to prevent conflicts between the + * Enterprise BurgerMenue extension and the Website BurgerMenu patch. + */ + set currentAppSections(_) {}, + + /** + * @override + */ + async _onMenuClicked(menu) { + const websiteMenu = this.websiteCustomMenus.get(menu.xmlid); + if (websiteMenu) { + this.websiteCustomMenus.open(menu.xmlid); + this._closeBurger(); + } else { + this._super(menu); + } + }, +}); diff --git a/addons/website/static/src/components/navbar/navbar.js b/addons/website/static/src/components/navbar/navbar.js new file mode 100644 index 00000000000..f1db8fcaa4a --- /dev/null +++ b/addons/website/static/src/components/navbar/navbar.js @@ -0,0 +1,64 @@ +/** @odoo-module **/ + +import { NavBar } from '@web/webclient/navbar/navbar'; +import { useService, useBus } from '@web/core/utils/hooks'; +import { registry } from "@web/core/registry"; +import { patch } from 'web.utils'; + +const websiteSystrayRegistry = registry.category('website_systray'); + +patch(NavBar.prototype, 'website_navbar', { + setup() { + this._super(); + this.websiteService = useService('website'); + this.websiteCustomMenus = useService('website_custom_menus'); + + // The navbar is rerendered with an event, as it can not naturally be + // with props/state (the WebsitePreview client action and the navbar + // are not related). + useBus(websiteSystrayRegistry, 'EDIT-WEBSITE', () => this.render(true)); + + if (this.env.debug && !websiteSystrayRegistry.contains('web.debug_mode_menu')) { + websiteSystrayRegistry.add('web.debug_mode_menu', registry.category('systray').get('web.debug_mode_menu'), {sequence: 100}); + } + + useBus(websiteSystrayRegistry, 'CONTENT-UPDATED', () => this.render(true)); + }, + + /** + * @override + */ + get systrayItems() { + if (this.websiteService.currentWebsite && this.websiteService.isRestrictedEditor) { + return websiteSystrayRegistry + .getEntries() + .map(([key, value], index) => ({ key, ...value, index })) + .filter((item) => ('isDisplayed' in item ? item.isDisplayed(this.env) : true)) + .reverse(); + } + return this._super(); + }, + + /** + * @override + */ + get currentAppSections() { + const currentAppSections = this._super(); + if (this.currentApp && this.currentApp.xmlid === 'website.menu_website_configuration') { + return this.websiteCustomMenus.addCustomMenus(currentAppSections).filter(section => section.childrenTree.length); + } + return currentAppSections; + }, + + /** + * @override + */ + onNavBarDropdownItemSelection(menu) { + const websiteMenu = this.websiteCustomMenus.get(menu.xmlid); + if (websiteMenu) { + return this.websiteCustomMenus.open(menu.xmlid); + + } + return this._super(menu); + }, +}); diff --git a/addons/website/static/src/components/switch/switch.js b/addons/website/static/src/components/switch/switch.js index 45916125cc1..6f6586dbd98 100644 --- a/addons/website/static/src/components/switch/switch.js +++ b/addons/website/static/src/components/switch/switch.js @@ -22,6 +22,6 @@ Switch.template = xml` `; diff --git a/addons/website/static/src/components/switch/switch.scss b/addons/website/static/src/components/switch/switch.scss index d61a73d95e9..24f13a5317a 100644 --- a/addons/website/static/src/components/switch/switch.scss +++ b/addons/website/static/src/components/switch/switch.scss @@ -10,7 +10,6 @@ $o-we-switch-inactive-color: rgba($text-muted, 0.4) !default; display: none; + span { - margin-right: 0.5em; border-radius: $o-we-switch-size; width: $o-we-switch-size * 1.7; padding-left: 3px; diff --git a/addons/website/static/src/services/website_custom_menus.js b/addons/website/static/src/services/website_custom_menus.js index 48d7605b195..20a60496062 100644 --- a/addons/website/static/src/services/website_custom_menus.js +++ b/addons/website/static/src/services/website_custom_menus.js @@ -1,129 +1,84 @@ /** @odoo-module **/ -import { NavBar } from '@web/webclient/navbar/navbar'; -import { useService, useBus } from '@web/core/utils/hooks'; import { registry } from "@web/core/registry"; -import { patch } from 'web.utils'; import { EditMenuDialog } from '@website/components/dialog/edit_menu'; import { OptimizeSEODialog } from '@website/components/dialog/seo'; import {PagePropertiesDialog} from '@website/components/dialog/page_properties'; -const websiteSystrayRegistry = registry.category('website_systray'); -const { useState } = owl; - -patch(NavBar.prototype, 'website_navbar', { - setup() { - this._super(); - this.orm = useService('orm'); - this.websiteService = useService('website'); - this.websiteContext = useState(this.websiteService.context); - - // The navbar is rerendered with an event, as it can not naturally be - // with props/state (the WebsitePreview client action and the navbar - // are not related). - useBus(websiteSystrayRegistry, 'EDIT-WEBSITE', () => this.render(true)); - - if (this.env.debug && !websiteSystrayRegistry.contains('web.debug_mode_menu')) { - websiteSystrayRegistry.add('web.debug_mode_menu', registry.category('systray').get('web.debug_mode_menu'), {sequence: 100}); - } - - useBus(websiteSystrayRegistry, 'CONTENT-UPDATED', () => this.render(true)); - - this.websiteEditingMenus = { - 'website.menu_edit_menu': { - Component: EditMenuDialog, - isDisplayed: () => !!this.websiteService.currentWebsite && this.websiteService.isDesigner, +/** + * This service displays contextual menus, depending of the state of the + * website. These menus are defined in xml with the "website_preview" action, + * which is overriden here for displaying dialogs, or regular components that + * are not client actions. + */ +export const websiteCustomMenus = { + dependencies: ['website', 'orm', 'dialog', 'ui'], + start(env, { website, orm, dialog, ui }) { + const services = { website, orm, dialog, ui }; + return { + get(xmlId) { + return registry.category('website_custom_menus').get(xmlId, null); }, - 'website.menu_optimize_seo': { - Component: OptimizeSEODialog, - isDisplayed: () => this.websiteService.currentWebsite && !!this.websiteService.currentWebsite.metadata.mainObject, + open(xmlId) { + const menu = this.get(xmlId); + if (menu.openWidget) { + return menu.openWidget(services); + } + return dialog.add( + menu.Component, + menu.getProps && menu.getProps(services), + ); }, - 'website.menu_current_page': { - isDisplayed: () => this.canShowAceEditor(), - }, - 'website.menu_ace_editor': { - openWidget: () => this.websiteContext.showAceEditor = true, - isDisplayed: () => this.canShowAceEditor(), - }, - 'website.menu_page_properties': { - Component: PagePropertiesDialog, - isDisplayed: () => this.canShowPageProperties(), - getProps: () => ({ - onRecordSaved: (record) => { - return this.orm.read('website.page', [record.resId], ['url']).then(res => { - this.websiteService.goToWebsite({websiteId: record.data.website_id[0], path: res[0]['url']}); - }); - }, - }) + addCustomMenus(sections) { + const filteredSections = []; + for (const section of sections) { + const isWebsiteCustomMenu = !!this.get(section.xmlid); + const displayWebsiteCustomMenu = isWebsiteCustomMenu && website.isRestrictedEditor && this.get(section.xmlid).isDisplayed(env); + if (!isWebsiteCustomMenu || displayWebsiteCustomMenu) { + let subSections = []; + if (section.childrenTree.length) { + subSections = this.addCustomMenus(section.childrenTree); + } + filteredSections.push(Object.assign({}, section, {childrenTree: subSections})); + } + } + return filteredSections; }, }; - }, + } +}; +registry.category('services').add('website_custom_menus', websiteCustomMenus); - filterWebsiteMenus(sections) { - const filteredSections = []; - for (const section of sections) { - const isWebsiteCustomMenu = this.websiteEditingMenus[section.xmlid]; - const displayWebsiteCustomMenu = isWebsiteCustomMenu && this.websiteService.isRestrictedEditor && this.websiteEditingMenus[section.xmlid].isDisplayed(); - if (!isWebsiteCustomMenu || displayWebsiteCustomMenu) { - let subSections = []; - if (section.childrenTree.length) { - subSections = this.filterWebsiteMenus(section.childrenTree); - } - filteredSections.push(Object.assign({}, section, {childrenTree: subSections})); - } - } - return filteredSections; - }, - - /** - * @override - */ - get systrayItems() { - if (this.websiteService.currentWebsite && this.websiteService.isRestrictedEditor) { - return websiteSystrayRegistry - .getEntries() - .map(([key, value], index) => ({ key, ...value, index })) - .filter((item) => ('isDisplayed' in item ? item.isDisplayed(this.env) : true)) - .reverse(); - } - return this._super(); - }, - - /** - * @override - */ - get currentAppSections() { - const currentAppSections = this._super(); - if (this.currentApp && this.currentApp.xmlid === 'website.menu_website_configuration') { - return this.filterWebsiteMenus(currentAppSections).filter(section => section.childrenTree.length); - } - return currentAppSections; - }, - - /** - * @override - */ - onNavBarDropdownItemSelection(menu) { - const websiteMenu = this.websiteEditingMenus[menu.xmlid]; - if (websiteMenu) { - return websiteMenu.openWidget ? - websiteMenu.openWidget() : - this.websiteService.openMenuDialog( - websiteMenu.Component, - websiteMenu.getProps && websiteMenu.getProps(), - ); - } - return this._super(menu); - }, - - canShowPageProperties() { - return this.websiteService.currentWebsite - && !!this.websiteService.currentWebsite.metadata.mainObject - && this.websiteService.currentWebsite.metadata.mainObject.model === 'website.page'; - }, - - canShowAceEditor() { - return this.websiteService.currentWebsite && this.websiteService.currentWebsite.metadata.viewXmlid - && !this.websiteContext.showNewContentModal && !this.websiteContext.edition; - }, +registry.category('website_custom_menus').add('website.menu_edit_menu', { + Component: EditMenuDialog, + isDisplayed: (env) => !!env.services.website.currentWebsite + && env.services.website.isDesigner + && !env.services.ui.isSmall, +}); +registry.category('website_custom_menus').add('website.menu_optimize_seo', { + Component: OptimizeSEODialog, + isDisplayed: (env) => env.services.website.currentWebsite + && !!env.services.website.currentWebsite.metadata.mainObject, +}); +registry.category('website_custom_menus').add('website.menu_current_page', { + isDisplayed: (env) => !!env.services.website.currentWebsite, +},); +registry.category('website_custom_menus').add('website.menu_ace_editor', { + openWidget: (services) => services.website.context.showAceEditor = true, + isDisplayed: (env) => env.services.website.currentWebsite + && env.services.website.currentWebsite.metadata.viewXmlid + && !env.services.ui.isSmall, +}); +registry.category('website_custom_menus').add('website.menu_page_properties', { + Component: PagePropertiesDialog, + isDisplayed: (env) => env.services.website.currentWebsite + && !!env.services.website.currentWebsite.metadata.mainObject + && env.services.website.currentWebsite.metadata.mainObject.model === 'website.page', + getProps: (services) => ({ + onRecordSaved: (record) => { + return services.orm.read('website.page', [record.resId], ['url']).then(res => { + services.website.goToWebsite({websiteId: record.data.website_id[0], path: res[0]['url']}); + }); + }, + }) }); diff --git a/addons/website/static/src/services/website_service.js b/addons/website/static/src/services/website_service.js index ebd86fa41c2..f2d72dea437 100644 --- a/addons/website/static/src/services/website_service.js +++ b/addons/website/static/src/services/website_service.js @@ -163,9 +163,6 @@ export const websiteService = { set actionJsId(jsId) { actionJsId = jsId; }, - openMenuDialog(Component, props) { - return dialog.add(Component, props); - }, goToWebsite({ websiteId, path, edition, translation } = {}) { action.doAction('website.website_preview', { clearBreadcrumbs: true, diff --git a/addons/website/static/src/systray_items/edit_in_backend.xml b/addons/website/static/src/systray_items/edit_in_backend.xml index 2d2f9614572..b4cbab5a06b 100644 --- a/addons/website/static/src/systray_items/edit_in_backend.xml +++ b/addons/website/static/src/systray_items/edit_in_backend.xml @@ -3,8 +3,8 @@ diff --git a/addons/website/static/src/systray_items/edit_website.xml b/addons/website/static/src/systray_items/edit_website.xml index 66f9ecd899e..239f321fd3b 100644 --- a/addons/website/static/src/systray_items/edit_website.xml +++ b/addons/website/static/src/systray_items/edit_website.xml @@ -1,7 +1,7 @@ -
+
diff --git a/addons/website/static/src/systray_items/mobile_preview.xml b/addons/website/static/src/systray_items/mobile_preview.xml index a34d7e6f40e..141629b6e16 100644 --- a/addons/website/static/src/systray_items/mobile_preview.xml +++ b/addons/website/static/src/systray_items/mobile_preview.xml @@ -1,7 +1,7 @@ -
+ diff --git a/addons/website/static/src/systray_items/new_content.xml b/addons/website/static/src/systray_items/new_content.xml index 63c54f33049..d13f03f90aa 100644 --- a/addons/website/static/src/systray_items/new_content.xml +++ b/addons/website/static/src/systray_items/new_content.xml @@ -40,7 +40,7 @@ -
+
New
diff --git a/addons/website/static/src/systray_items/publish.js b/addons/website/static/src/systray_items/publish.js index e8670ffe133..c10ca6d6d1a 100644 --- a/addons/website/static/src/systray_items/publish.js +++ b/addons/website/static/src/systray_items/publish.js @@ -37,7 +37,7 @@ PublishSystray.template = xml` `; PublishSystray.components = { diff --git a/addons/website/static/src/systray_items/translate_website.xml b/addons/website/static/src/systray_items/translate_website.xml index 5e1a0602574..8a753ade8e7 100644 --- a/addons/website/static/src/systray_items/translate_website.xml +++ b/addons/website/static/src/systray_items/translate_website.xml @@ -2,7 +2,7 @@ -
+
TRANSLATE diff --git a/addons/website/static/src/systray_items/website_switcher.js b/addons/website/static/src/systray_items/website_switcher.js index ec01da957e3..4da8f3f7493 100644 --- a/addons/website/static/src/systray_items/website_switcher.js +++ b/addons/website/static/src/systray_items/website_switcher.js @@ -25,6 +25,7 @@ export class WebsiteSwitcherSystray extends Component { this.websiteService.goToWebsite({ websiteId: website.id }); } }, + class: website.id === this.websiteService.currentWebsite.id ? 'active' : '', })); } } diff --git a/addons/website/static/src/systray_items/website_switcher.xml b/addons/website/static/src/systray_items/website_switcher.xml index 7e4f34911f1..d60233f572e 100644 --- a/addons/website/static/src/systray_items/website_switcher.xml +++ b/addons/website/static/src/systray_items/website_switcher.xml @@ -3,12 +3,19 @@ - +
+ + +
+
+ +
diff --git a/addons/website/static/tests/website_service_mock.js b/addons/website/static/tests/website_service_mock.js index c93bcf26b2d..1df207a6dcb 100644 --- a/addons/website/static/tests/website_service_mock.js +++ b/addons/website/static/tests/website_service_mock.js @@ -25,11 +25,26 @@ function makeFakeWebsiteService() { }; } +function makeFakeWebsiteCustomMenusService() { + return { + start() { + return { + get() {}, + open() {}, + addCustomMenus(sections) { + return sections; + }, + }; + } + }; +} + const serviceRegistry = registry.category('services'); patch(utils, 'website_test_registries', { prepareRegistriesWithCleanup() { prepareRegistriesWithCleanup(...arguments); serviceRegistry.add('website', makeFakeWebsiteService()); + serviceRegistry.add('website_custom_menus', makeFakeWebsiteCustomMenusService()); clearRegistryWithCleanup(registry.category('website_systray')); }, }); diff --git a/addons/website_event/static/src/js/services/website_custom_menus.js b/addons/website_event/static/src/js/services/website_custom_menus.js index 6d400f9a8d5..1f4ebbf1ffd 100644 --- a/addons/website_event/static/src/js/services/website_custom_menus.js +++ b/addons/website_event/static/src/js/services/website_custom_menus.js @@ -1,23 +1,14 @@ /** @odoo-module */ -import { patch } from 'web.utils'; -import { NavBar } from '@web/webclient/navbar/navbar'; +import { registry } from '@web/core/registry'; import { EditMenuDialog } from '@website/components/dialog/edit_menu'; -const { onWillStart } = owl; - -patch(NavBar.prototype, 'website_events_navbar', { - setup() { - this._super(); - - onWillStart(() => { - this.websiteEditingMenus['website_event.menu_edit_menu'] = { - Component: EditMenuDialog, - isDisplayed: () => this.websiteService.currentWebsite && this.websiteService.currentWebsite.metadata.contentMenuId, - getProps: () => ({ - rootID: parseInt(this.websiteService.currentWebsite.metadata.contentMenuId, 10), - }), - }; - }); - }, +registry.category('website_custom_menus').add('website_event.menu_edit_menu', { + Component: EditMenuDialog, + isDisplayed: (env) => env.services.website.currentWebsite + && env.services.website.currentWebsite.metadata.contentMenuId + && !env.services.ui.isSmall, + getProps: (services) => ({ + rootID: parseInt(services.website.currentWebsite.metadata.contentMenuId, 10), + }), }); diff --git a/addons/website_links/static/src/services/website_custom_menus.js b/addons/website_links/static/src/services/website_custom_menus.js index 9e404dca4ab..562d3c81a54 100644 --- a/addons/website_links/static/src/services/website_custom_menus.js +++ b/addons/website_links/static/src/services/website_custom_menus.js @@ -1,19 +1,8 @@ /** @odoo-module */ -import { patch } from 'web.utils'; -import { NavBar } from '@web/webclient/navbar/navbar'; +import { registry } from '@web/core/registry'; -const { onWillStart } = owl; - -patch(NavBar.prototype, 'website_links_navbar', { - setup() { - this._super(); - - onWillStart(() => { - this.websiteEditingMenus['website_links.menu_link_tracker'] = { - openWidget: () => this.websiteService.goToWebsite({ path: `/r?u=${encodeURIComponent(this.websiteService.contentWindow.location.href)}` }), - isDisplayed: () => this.websiteService.currentWebsite && this.websiteService.contentWindow, - }; - }); - }, +registry.category('website_custom_menus').add('website_links.menu_link_tracker', { + openWidget: (services) => services.website.goToWebsite({ path: `/r?u=${encodeURIComponent(services.website.contentWindow.location.href)}` }), + isDisplayed: (env) => env.services.website.currentWebsite && env.services.website.contentWindow, });