diff --git a/addons/web_editor/static/src/components/media_dialog/file_selector.js b/addons/web_editor/static/src/components/media_dialog/file_selector.js index d2621e7ce2b..b9dac0e27d7 100644 --- a/addons/web_editor/static/src/components/media_dialog/file_selector.js +++ b/addons/web_editor/static/src/components/media_dialog/file_selector.js @@ -25,28 +25,31 @@ class RemoveButton extends Component { } RemoveButton.template = xml``; -export class AttachmentError extends Dialog { +export class AttachmentError extends Component { setup() { - super.setup(); this.title = this.env._t("Alert"); } } -AttachmentError.bodyTemplate = xml ` -
-

The image could not be deleted because it is used in the - following pages or views:

- -
`; -AttachmentError.footerTemplate = xml` -`; +AttachmentError.components = { Dialog }; +AttachmentError.template = xml ` + +
+

The image could not be deleted because it is used in the + following pages or views:

+ +
+ + + +
`; export class Attachment extends Component { setup() { @@ -69,7 +72,6 @@ export class Attachment extends Component { }); } }, - cancel: () => {}, }); } } diff --git a/addons/web_editor/static/src/components/media_dialog/media_dialog.js b/addons/web_editor/static/src/components/media_dialog/media_dialog.js index b43b1961624..576794e822a 100644 --- a/addons/web_editor/static/src/components/media_dialog/media_dialog.js +++ b/addons/web_editor/static/src/components/media_dialog/media_dialog.js @@ -33,10 +33,9 @@ export const TABS = { }, }; -export class MediaDialog extends Dialog { +export class MediaDialog extends Component { setup() { - super.setup(); - this.size = 'modal-xl'; + this.size = 'xl'; this.contentClass = 'o_select_media_dialog'; this.title = this.env._t("Select a media"); @@ -173,16 +172,16 @@ export class MediaDialog extends Dialog { this.props.save(elements[0]); } } - this.close(); + this.props.close(); } } -MediaDialog.bodyTemplate = 'web_editor.MediaDialogBody'; -MediaDialog.footerTemplate = 'web_editor.MediaDialogFooter'; +MediaDialog.template = 'web_editor.MediaDialog'; MediaDialog.defaultProps = { useMediaLibrary: true, }; MediaDialog.components = { ...Object.keys(TABS).map(key => TABS[key].Component), + Dialog, }; export class MediaDialogWrapper extends Component { @@ -190,16 +189,7 @@ export class MediaDialogWrapper extends Component { this.dialogs = useWowlService('dialog'); onRendered(() => { - this.dialogs.add(MediaDialog, { - ...this.props, - close: () => { - if (this.props.close) { - this.props.close(); - } - this.destroy(); - - }, - }); + this.dialogs.add(MediaDialog, this.props); }); } } diff --git a/addons/web_editor/static/src/components/media_dialog/media_dialog.xml b/addons/web_editor/static/src/components/media_dialog/media_dialog.xml index c15e411201f..62abd8d36f2 100644 --- a/addons/web_editor/static/src/components/media_dialog/media_dialog.xml +++ b/addons/web_editor/static/src/components/media_dialog/media_dialog.xml @@ -1,21 +1,24 @@ - - - -
- -
-
-
-
- - - - +
diff --git a/addons/website/static/src/components/dialog/dialog.js b/addons/website/static/src/components/dialog/dialog.js index 7bc2de1b7d2..b5f6d291f15 100644 --- a/addons/website/static/src/components/dialog/dialog.js +++ b/addons/website/static/src/components/dialog/dialog.js @@ -2,65 +2,66 @@ import { Dialog } from '@web/core/dialog/dialog'; import { Switch } from '@website/components/switch/switch'; +import { _t } from 'web.core'; -const { xml, useState } = owl; +const { xml, useState, Component } = owl; -export class WebsiteDialog extends Dialog { - setup() { - super.setup(); - this.title = this.props.title || this.env._t("Confirmation"); - this.primaryTitle = this.props.primaryTitle || this.env._t("Ok"); - this.secondaryTitle = this.props.secondaryTitle || this.env._t("Cancel"); - this.closeOnClick = this.props.closeOnClick === false ? false : true; - } - - get showSecondaryButton() { - return this.props.showSecondaryButton; - } - - primaryClick() { +export class WebsiteDialog extends Component { + async primaryClick() { if (this.props.primaryClick) { - this.props.primaryClick(); + await this.props.primaryClick(); } - if (this.closeOnClick) { - this.close(); + if (this.props.closeOnClick) { + this.props.close(); } } - secondaryClick() { + async secondaryClick() { if (this.props.secondaryClick) { - this.props.secondaryClick(); + await this.props.secondaryClick(); } - if (this.closeOnClick) { - this.close(); + if (this.props.closeOnClick) { + this.props.close(); } } + + get contentClasses() { + const websiteDialogClass = 'o_website_dialog'; + if (this.props.contentClass) { + return `${websiteDialogClass} ${this.props.contentClass}`; + } + return websiteDialogClass; + } } +WebsiteDialog.components = { Dialog }; WebsiteDialog.props = { ...Dialog.props, - title: { type: String, optional: true }, - body: { type: String, optional: true }, primaryTitle: { type: String, optional: true }, primaryClick: { type: Function, optional: true }, secondaryTitle: { type: String, optional: true }, secondaryClick: { type: Function, optional: true }, + showSecondaryButton: { type: Boolean, optional: true }, + close: Function, closeOnClick: { type: Boolean, optional: true }, - close: { type: Function, optional: true }, }; WebsiteDialog.defaultProps = { + ...Dialog.defaultProps, + title: _t("Confirmation"), + primaryTitle: _t("Ok"), + secondaryTitle: _t("Cancel"), showSecondaryButton: true, + size: "md", + closeOnClick: true, }; -WebsiteDialog.bodyTemplate = "website.DialogBody"; -WebsiteDialog.footerTemplate = "website.DialogFooter"; -WebsiteDialog.size = "modal-md"; -WebsiteDialog.contentClass = "o_website_dialog"; +WebsiteDialog.template = "website.WebsiteDialog"; -export class AddPageDialog extends WebsiteDialog { +export class AddPageDialog extends Component { setup() { super.setup(); this.title = this.env._t("New Page"); this.primaryTitle = this.env._t("Create"); + this.switchLabel = this.env._t("Add to menu"); this.state = useState({ addMenu: true, @@ -72,20 +73,20 @@ export class AddPageDialog extends WebsiteDialog { this.state.addMenu = value; } - async primaryClick() { + async addPage() { await this.props.addPage(this.state.name, this.state.addMenu); - this.close(); } } -AddPageDialog.props = { - ...WebsiteDialog.props, - addPage: Function, -}; AddPageDialog.components = { Switch, + WebsiteDialog, }; -AddPageDialog.bodyTemplate = xml` -
+AddPageDialog.template = xml` +
- - + + `; diff --git a/addons/website/static/src/components/dialog/dialog.xml b/addons/website/static/src/components/dialog/dialog.xml index 1a89c27dedb..3f518e0868c 100644 --- a/addons/website/static/src/components/dialog/dialog.xml +++ b/addons/website/static/src/components/dialog/dialog.xml @@ -1,15 +1,21 @@ - - - - - - - + + + + + + + + + + + diff --git a/addons/website/static/src/components/dialog/edit_menu.js b/addons/website/static/src/components/dialog/edit_menu.js index 0871c412d70..af60f948af8 100644 --- a/addons/website/static/src/components/dialog/edit_menu.js +++ b/addons/website/static/src/components/dialog/edit_menu.js @@ -5,10 +5,8 @@ import { WebsiteDialog } from './dialog'; const { Component, useState, useEffect, onWillStart, useRef, onMounted } = owl; -export class MenuDialog extends WebsiteDialog { +export class MenuDialog extends Component { setup() { - super.setup(); - this.title = this.env._t("Add a menu item"); this.state = useState({ @@ -17,23 +15,23 @@ export class MenuDialog extends WebsiteDialog { }); } - primaryClick() { + onClickOk() { this.props.save(this.state.name, this.state.url); - this.close(); } } -MenuDialog.bodyTemplate = 'website.MenuDialog'; +MenuDialog.template = 'website.MenuDialog'; MenuDialog.props = { - ...WebsiteDialog.props, name: { type: String, optional: true }, url: { type: String, optional: true }, isMegaMenu: { type: Boolean, optional: true }, save: Function, + close: Function, }; MenuDialog.defaultProps = { name: '', url: '/', }; +MenuDialog.components = { WebsiteDialog }; class MenuRow extends Component { edit() { @@ -54,15 +52,14 @@ MenuRow.components = { MenuRow, }; -export class EditMenuDialog extends WebsiteDialog { +export class EditMenuDialog extends Component { setup() { - super.setup(); this.orm = useService('orm'); this.website = useService('website'); this.dialogs = useService('dialog'); this.title = this.env._t("Edit Menu"); - this.primaryTitle = this.env._t("Save"); + this.saveButton = this.env._t("Save"); this.menuEditor = useRef('menu-editor'); @@ -152,7 +149,7 @@ export class EditMenuDialog extends WebsiteDialog { this.toDelete.push(id); } - async primaryClick() { + async onClickSave() { const newMenus = this.$sortables.nestedSortable('toArray', {startDepthCount: 0}); const levels = []; const data = []; @@ -178,7 +175,6 @@ export class EditMenuDialog extends WebsiteDialog { 'to_delete': this.toDelete, } ]); - this.close(); if (this.props.save) { this.props.save(); } else { @@ -186,7 +182,8 @@ export class EditMenuDialog extends WebsiteDialog { } } } -EditMenuDialog.bodyTemplate = 'website.EditMenuDialog'; +EditMenuDialog.template = 'website.EditMenuDialog'; EditMenuDialog.components = { MenuRow, + WebsiteDialog, }; diff --git a/addons/website/static/src/components/dialog/edit_menu.xml b/addons/website/static/src/components/dialog/edit_menu.xml index 18aefa84fe7..0209d28e90a 100644 --- a/addons/website/static/src/components/dialog/edit_menu.xml +++ b/addons/website/static/src/components/dialog/edit_menu.xml @@ -1,22 +1,24 @@ -
- -
- + +
+ +
+ +
-
-
- -
- +
+ +
+ +
-
+ @@ -46,21 +48,23 @@ -
    - - - -
-
- - Drag to the right to get a submenu - - - Add Menu Item -
- - Add Mega Menu Item - -
+ +
    + + + +
+
+ + Drag to the right to get a submenu + + + Add Menu Item +
+ + Add Mega Menu Item + +
+
diff --git a/addons/website/static/src/components/dialog/page_properties.js b/addons/website/static/src/components/dialog/page_properties.js index 2144c4bda96..9cdc443fdb6 100644 --- a/addons/website/static/src/components/dialog/page_properties.js +++ b/addons/website/static/src/components/dialog/page_properties.js @@ -80,14 +80,13 @@ PageDependencies.props = { }, }; -export class DeletePageDialog extends WebsiteDialog { +export class DeletePageDialog extends Component { setup() { - super.setup(); - this.orm = useService('orm'); this.website = useService('website'); this.title = this.env._t("Delete Page"); - this.primaryTitle = this.env._t("Ok"); + this.deleteButton = this.env._t("Ok"); + this.cancelButton = this.env._t("Cancel"); this.state = useState({ confirm: false, @@ -98,28 +97,29 @@ export class DeletePageDialog extends WebsiteDialog { this.state.confirm = checked; } - async primaryClick() { + async onClickDelete() { await this.orm.unlink("website.page", [ this.props.pageId, ]); this.website.goToWebsite(); - this.close(); + this.props.close(); this.props.onClose(); } } -DeletePageDialog.components = {PageDependencies, CheckBox}; -DeletePageDialog.bodyTemplate = 'website.DeletePageContent'; -DeletePageDialog.footerTemplate = 'website.DeletePageAction'; +DeletePageDialog.components = { + PageDependencies, + CheckBox, + WebsiteDialog +}; +DeletePageDialog.template = 'website.DeletePageDialog'; DeletePageDialog.props = { - ...WebsiteDialog.props, pageId: Number, onClose: Function, + close: Function, }; -export class DuplicatePageDialog extends WebsiteDialog { +export class DuplicatePageDialog extends Component { setup() { - super.setup(); - this.orm = useService('orm'); this.website = useService('website'); @@ -128,7 +128,7 @@ export class DuplicatePageDialog extends WebsiteDialog { }); } - async primaryClick() { + async duplicate() { if (this.state.name) { const res = await this.orm.call( 'website.page', @@ -137,11 +137,12 @@ export class DuplicatePageDialog extends WebsiteDialog { ); this.website.goToWebsite({path: res, edition: true}); } - this.close(); this.props.onClose(); } } -DuplicatePageDialog.bodyTemplate = xml` +DuplicatePageDialog.components = {WebsiteDialog}; +DuplicatePageDialog.template = xml` +
+ `; DuplicatePageDialog.props = { - ...WebsiteDialog.props, onClose: Function, + close: Function, + pageId: Number, }; export class PagePropertiesDialogWrapper extends Component { diff --git a/addons/website/static/src/components/dialog/page_properties.xml b/addons/website/static/src/components/dialog/page_properties.xml index de63850fad3..903f2ac7b50 100644 --- a/addons/website/static/src/components/dialog/page_properties.xml +++ b/addons/website/static/src/components/dialog/page_properties.xml @@ -55,19 +55,24 @@ - -

Are you sure you want to delete this page ?

-

Don't forget to update all links referring to this page.

- - -

I am sure about this.

-
-
+ + +

Are you sure you want to delete this page ?

+

Don't forget to update all links referring to this page.

+ + +

I am sure about this.

+
- - - !state.confirm - + + + + +
diff --git a/addons/website/static/src/components/dialog/seo.js b/addons/website/static/src/components/dialog/seo.js index b5045cd6a28..1d82e1bd820 100644 --- a/addons/website/static/src/components/dialog/seo.js +++ b/addons/website/static/src/components/dialog/seo.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { useService, useListener } from '@web/core/utils/hooks'; +import { useService } from '@web/core/utils/hooks'; import { MediaDialog } from '@web_editor/components/media_dialog/media_dialog'; import { WebsiteDialog } from './dialog'; @@ -327,18 +327,17 @@ TitleDescription.components = { SEOPreview, }; -export class OptimizeSEODialog extends WebsiteDialog { +export class OptimizeSEODialog extends Component { setup() { - super.setup(); this.rpc = useService('rpc'); this.website = useService('website'); this.dialogs = useService('dialog'); this.orm = useService('orm'); this.title = this.env._t("Optimize SEO"); - this.primaryTitle = this.env._t("Save"); - this.size = 'modal-lg'; - this.contentClass = `${this.contentClass} oe_seo_configuration`; + this.saveButton = this.env._t("Save"); + this.size = 'lg'; + this.contentClass = "oe_seo_configuration"; onWillStart(async () => { const { metadata: { mainObject, seoObject, path } } = this.website.currentWebsite; @@ -405,7 +404,7 @@ export class OptimizeSEODialog extends WebsiteDialog { return el && el.content; } - async primaryClick() { + async save() { const data = {}; if (this.canEditTitle) { data.website_meta_title = seoContext.title; @@ -423,12 +422,12 @@ export class OptimizeSEODialog extends WebsiteDialog { } data.website_meta_og_img = seoContext.metaImage; await this.orm.write(this.object.model, [this.object.id], data); - this.close(); this.website.goToWebsite({path: this.url.replace(this.previousSeoName || this.seoNameDefault, seoContext.seoName)}); } } -OptimizeSEODialog.bodyTemplate = 'website.OptimizeSEODialog'; +OptimizeSEODialog.template = 'website.OptimizeSEODialog'; OptimizeSEODialog.components = { + WebsiteDialog, TitleDescription, ImageSelector, MetaKeywords, diff --git a/addons/website/static/src/components/dialog/seo.xml b/addons/website/static/src/components/dialog/seo.xml index a9db65c9b66..763a6b042d2 100644 --- a/addons/website/static/src/components/dialog/seo.xml +++ b/addons/website/static/src/components/dialog/seo.xml @@ -166,20 +166,27 @@ - - - + + + + + diff --git a/addons/website/static/src/components/translator/translator.js b/addons/website/static/src/components/translator/translator.js index 7cb5fa3255f..056e441a10c 100644 --- a/addons/website/static/src/components/translator/translator.js +++ b/addons/website/static/src/components/translator/translator.js @@ -4,13 +4,12 @@ import { WebsiteEditorComponent } from '../editor/editor'; import { WebsiteDialog } from '../dialog/dialog'; import localStorage from 'web.local_storage'; -const { useEffect, useRef } = owl; +const { useEffect, useRef, Component } = owl; const localStorageNoDialogKey = 'website_translator_nodialog'; -class AttributeTranslateDialog extends WebsiteDialog { +class AttributeTranslateDialog extends Component { setup() { - super.setup(); this.title = this.env._t("Translate Attribute"); this.formEl = useRef('form-container'); @@ -38,10 +37,21 @@ class AttributeTranslateDialog extends WebsiteDialog { }, () => [this.props.node]); } } -AttributeTranslateDialog.bodyTemplate = 'website.AttributeTranslateDialog'; +AttributeTranslateDialog.components = { WebsiteDialog }; +AttributeTranslateDialog.template = 'website.AttributeTranslateDialog'; -class TranslatorInfoDialog extends WebsiteDialog {} -TranslatorInfoDialog.bodyTemplate = 'website.TranslatorInfoDialog'; +class TranslatorInfoDialog extends Component { + setup() { + this.strongOkButton = this.env._t("Ok, never show me this again"); + this.okButton = this.env._t("Ok"); + } + + onStrongOkClick() { + localStorage.setItem(localStorageNoDialogKey, true); + } +} +TranslatorInfoDialog.components = { WebsiteDialog }; +TranslatorInfoDialog.template = 'website.TranslatorInfoDialog'; const savableSelector = '[data-oe-translation-id], ' + '[data-oe-model][data-oe-id][data-oe-field], ' + @@ -183,11 +193,7 @@ export class WebsiteTranslator extends WebsiteEditorComponent { }); if (!localStorage.getItem(localStorageNoDialogKey)) { - this.dialogService.add(TranslatorInfoDialog, { - primaryClick: () => localStorage.setItem(localStorageNoDialogKey, true), - primaryTitle: this.env._t("Ok, never show me this again"), - secondaryTitle: this.env._t("Ok"), - }); + this.dialogService.add(TranslatorInfoDialog); } // Apply data-oe-readonly on nested data. @@ -228,7 +234,7 @@ export class WebsiteTranslator extends WebsiteEditorComponent { }); this.$translations.prependEvent('click.translator', (ev) => { - this.dialogService.add(AttributeTranslateDialog, { node: ev.target, showSecondaryButton: false }); + this.dialogService.add(AttributeTranslateDialog, { node: ev.target }); }); } diff --git a/addons/website/static/src/components/translator/translator.scss b/addons/website/static/src/components/translator/translator.scss index 18524f0ed45..ce3d432fad0 100644 --- a/addons/website/static/src/components/translator/translator.scss +++ b/addons/website/static/src/components/translator/translator.scss @@ -3,10 +3,10 @@ margin: 10px; padding: 4px; - [data-oe-translation-state] { + &[data-oe-translation-state] { background: $o-we-translated-content-color; } - [data-oe-translation-state="to_translate"] { + &[data-oe-translation-state="to_translate"] { background: $o-we-content-to-translate-color; } } diff --git a/addons/website/static/src/components/translator/translator.xml b/addons/website/static/src/components/translator/translator.xml index e4dd94f333e..a4c0c03a1ef 100644 --- a/addons/website/static/src/components/translator/translator.xml +++ b/addons/website/static/src/components/translator/translator.xml @@ -1,19 +1,29 @@
-

You are about to enter the translation mode.

-

Here are the visuals used to help you translate efficiently:

-
    -
  • Content to translate
  • -
  • Translated content
  • -
-

- In this mode, you can only translate texts. To change the structure of the page, you must edit the master page. - Each modification on the master page is automatically applied to all translated versions. -

+ +

You are about to enter the translation mode.

+

Here are the visuals used to help you translate efficiently:

+
    +
  • Content to translate
  • +
  • Translated content
  • +
+

+ In this mode, you can only translate texts. To change the structure of the page, you must edit the master page. + Each modification on the master page is automatically applied to all translated versions. +

+
-
-
-
+ + +
+ + diff --git a/addons/website/static/src/services/website_service.js b/addons/website/static/src/services/website_service.js index 7fdc5929c03..f659a11bf9a 100644 --- a/addons/website/static/src/services/website_service.js +++ b/addons/website/static/src/services/website_service.js @@ -128,8 +128,8 @@ export const websiteService = { clearBreadcrumbs: true, additionalContext: { params: { - website_id: websiteId, - path, + website_id: websiteId || currentWebsiteId, + path: path || (contentWindow && contentWindow.location.href) || '/', enable_editor: edition, edit_translations: translation, }, diff --git a/addons/website/static/src/systray_items/new_content.js b/addons/website/static/src/systray_items/new_content.js index 03b89741e8e..e3b1853891f 100644 --- a/addons/website/static/src/systray_items/new_content.js +++ b/addons/website/static/src/systray_items/new_content.js @@ -37,6 +37,19 @@ NewContentElement.defaultProps = { status: MODULE_STATUS.INSTALLED, }; +class InstallModuleDialog extends Component { + setup() { + this.installButton = this.env._t("Install"); + } + + onClickInstall() { + this.props.close(); + this.props.installModule(); + } +} +InstallModuleDialog.components = { WebsiteDialog }; +InstallModuleDialog.template = "website.InstallModuleDialog"; + export class NewContentModal extends Component { setup() { this.user = useService('user'); @@ -158,9 +171,8 @@ export class NewContentModal extends Component { const {id, name} = this.modulesInfo[element.moduleXmlId]; const dialogProps = { title: element.title, - body: _.str.sprintf(this.newContentText.installNeeded, name), - primaryTitle: this.env._t("Install"), - primaryClick: async () => { + installationText: _.str.sprintf(this.newContentText.installNeeded, name), + installModule: async () => { // Update the NewContentElement with installing icon and text. this.state.newContentElements = this.state.newContentElements.map(el => { if (el.moduleXmlId === element.moduleXmlId) { @@ -186,7 +198,7 @@ export class NewContentModal extends Component { } }, }; - this.dialogs.add(WebsiteDialog, dialogProps); + this.dialogs.add(InstallModuleDialog, dialogProps); } } NewContentModal.template = "website.NewContentModal"; diff --git a/addons/website/static/src/systray_items/new_content.xml b/addons/website/static/src/systray_items/new_content.xml index 2aec401921f..e879319ab2e 100644 --- a/addons/website/static/src/systray_items/new_content.xml +++ b/addons/website/static/src/systray_items/new_content.xml @@ -41,4 +41,13 @@
+ + + + + +