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, });