diff --git a/addons/website/models/ir_module_module.py b/addons/website/models/ir_module_module.py index 95a61c46e15..c5051a2a545 100644 --- a/addons/website/models/ir_module_module.py +++ b/addons/website/models/ir_module_module.py @@ -399,8 +399,8 @@ class IrModuleModule(models.Model): result = active_todo.action_launch() else: result = website.button_go_website(mode_edit=True) - if result.get('url') and 'enable_editor' in result['url']: - result['url'] = result['url'].replace('enable_editor', 'with_loader=1&enable_editor') + if result.get('tag') == 'website_preview' and result.get('context', {}).get('params', {}).get('enable_editor'): + result['context']['params']['with_loader'] = True return result def button_remove_theme(self): diff --git a/addons/website/models/mixins.py b/addons/website/models/mixins.py index ab64ea80d7d..88342559183 100644 --- a/addons/website/models/mixins.py +++ b/addons/website/models/mixins.py @@ -200,12 +200,7 @@ class WebsitePublishedMixin(models.AbstractModel): return self.write({'website_published': not self.website_published}) def open_website_url(self): - url = self.env['website'].get_client_action_url(self.website_url) - return { - 'type': 'ir.actions.act_url', - 'url': url, - 'target': 'self', - } + return self.env['website'].get_client_action(self.website_url) @api.model_create_multi def create(self, vals_list): @@ -283,16 +278,18 @@ class WebsitePublishedMultiMixin(WebsitePublishedMixin): return is_published def open_website_url(self): - client_action_url = self.env['website'].get_client_action_url(self.website_url) + website_id = False if self.website_id: - client_action_url = f'{client_action_url}&website_id={self.website_id.id}' + website_id = self.website_id.id if self.website_id.domain: - client_action_url = url_join(self.website_id.domain, client_action_url) - return { - 'type': 'ir.actions.act_url', - 'url': client_action_url, - 'target': 'self', - } + client_action_url = self.env['website'].get_client_action_url(self.website_url) + client_action_url = f'{client_action_url}&website_id={website_id}' + return { + 'type': 'ir.actions.act_url', + 'url': url_join(self.website_id.domain, client_action_url), + 'target': 'self', + } + return self.env['website'].get_client_action(self.website_url, False, website_id) class WebsiteSearchableMixin(models.AbstractModel): diff --git a/addons/website/models/website.py b/addons/website/models/website.py index c5109f976c7..03bbd92e24d 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -1301,18 +1301,24 @@ class Website(models.Model): action_params["enable_editor"] = 1 return "/web#" + urls.url_encode(action_params) + def get_client_action(self, url, mode_edit=False, website_id=False): + action = self.env["ir.actions.actions"]._for_xml_id("website.website_preview") + action['context'] = { + 'params': { + 'path': url, + 'enable_editor': mode_edit, + 'website_id': website_id, + } + } + return action + def button_go_website(self, path='/', mode_edit=False): self._force() if mode_edit: # If the user gets on a translated page (e.g /fr) the editor will # never start. Forcing the default language fixes this issue. path = url_for(path, self.default_lang_id.url_code) - path = self.get_client_action_url(path, True) - return { - 'type': 'ir.actions.act_url', - 'url': path, - 'target': 'self', - } + return self.get_client_action(path, mode_edit) def _get_canonical_url_localized(self, lang, canonical_params): """Returns the canonical URL for the current request with translatable diff --git a/addons/website/static/src/client_actions/website_preview/website_preview.js b/addons/website/static/src/client_actions/website_preview/website_preview.js index 392bc1224b1..fa10a20ad42 100644 --- a/addons/website/static/src/client_actions/website_preview/website_preview.js +++ b/addons/website/static/src/client_actions/website_preview/website_preview.js @@ -127,6 +127,7 @@ export class WebsitePreview extends Component { }, () => []); useEffect(() => { + let leftOnBackNavigation = false; // When reaching a "regular" url of the webclient's router, an // hashchange event should be dispatched to properly display the // content of the previous URL before reaching the client action, @@ -136,12 +137,18 @@ export class WebsitePreview extends Component { window.dispatchEvent(new HashChangeEvent('hashchange', { newURL: window.location.href.toString() })); + leftOnBackNavigation = true; } }; window.addEventListener('popstate', handleBackNavigation); return () => { - history.pushState({}, null, this.backendUrl); window.removeEventListener('popstate', handleBackNavigation); + // When leaving the client action, its original url is pushed + // so that the router can replay the action on back navigation + // from other screens. + if (!leftOnBackNavigation) { + history.pushState({}, null, this.backendUrl); + } }; }, () => []); diff --git a/addons/website/static/src/components/views/page_views_mixin.js b/addons/website/static/src/components/views/page_views_mixin.js index 87feeae3b7e..512b01c0986 100644 --- a/addons/website/static/src/components/views/page_views_mixin.js +++ b/addons/website/static/src/components/views/page_views_mixin.js @@ -20,6 +20,7 @@ export const PageControllerMixin = (component) => class extends component { super.setup(); this.website = useService('website'); this.dialog = useService('dialog'); + this.rpc = useService('rpc'); this.websiteSelection = [{id: 0, name: this.env._t("All Websites")}]; @@ -37,14 +38,15 @@ export const PageControllerMixin = (component) => class extends component { * Adds the new 'website content' record depending on the targeted model and * 'create_action' passed in context. */ - createWebsiteContent() { + async createWebsiteContent() { if (this.props.resModel === 'website.page') { return this.dialog.add(AddPageDialog, {selectWebsite: true}); } const action = this.props.context.create_action; if (action) { if (/^\//.test(action)) { - window.location.replace(action); + const url = await this.rpc(action); + this.website.goToWebsite({ path: url, edition: true }); return; } this.actionService.doAction(action, { diff --git a/addons/website/static/src/components/views/theme_preview_form.js b/addons/website/static/src/components/views/theme_preview_form.js index ca396b6f6d1..5ccad3dbaa8 100644 --- a/addons/website/static/src/components/views/theme_preview_form.js +++ b/addons/website/static/src/components/views/theme_preview_form.js @@ -28,10 +28,17 @@ export function useLoaderOnClick() { try { const resParams = params.getResParams(); const callback = await orm.silent.call(resParams.resModel, name, [[resParams.resId]]); + let keepLoader = false; if (callback) { + callback.target = 'main'; await action.doAction(callback); + if (callback.tag === 'website_preview' && callback.context.params.with_loader) { + keepLoader = true; + } + } + if (!keepLoader) { + website.hideLoader(); } - website.hideLoader(); } catch (error) { website.hideLoader(); throw error; diff --git a/addons/website/wizard/base_language_install.py b/addons/website/wizard/base_language_install.py index ddb4d262d3a..44afea31c80 100644 --- a/addons/website/wizard/base_language_install.py +++ b/addons/website/wizard/base_language_install.py @@ -27,9 +27,5 @@ class BaseLanguageInstall(models.TransientModel): params = self._context.get('params', {}) if 'url_return' in params: url = params['url_return'].replace('[lang]', self.first_lang_id.code) - return { - 'url': self.env['website'].get_client_action_url(url), - 'type': 'ir.actions.act_url', - 'target': 'self' - } + return self.env['website'].get_client_action(url) return action diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py index b22548ef2ec..e3fab92f903 100644 --- a/addons/website_forum/models/forum.py +++ b/addons/website_forum/models/forum.py @@ -252,11 +252,7 @@ class Forum(models.Model): def go_to_website(self): self.ensure_one() - return { - 'type': 'ir.actions.act_url', - 'target': 'self', - 'url': self.env['website'].get_client_action_url(self._compute_website_url()), - } + return self.env['website'].get_client_action(self._compute_website_url()) @api.model def _update_website_count(self): @@ -974,11 +970,7 @@ class Post(models.Model): def go_to_website(self): self.ensure_one() - return { - 'type': 'ir.actions.act_url', - 'target': 'self', - 'url': self.env['website'].get_client_action_url(self.website_url), - } + return self.env['website'].get_client_action(self.website_url) @api.model def _search_get_detail(self, website, order, options): diff --git a/addons/website_hr_recruitment/controllers/main.py b/addons/website_hr_recruitment/controllers/main.py index 1b3a996104f..33af683f064 100644 --- a/addons/website_hr_recruitment/controllers/main.py +++ b/addons/website_hr_recruitment/controllers/main.py @@ -85,13 +85,13 @@ class WebsiteHrRecruitment(http.Controller): 'contract_type_id': contract_type_id, }) - @http.route('/jobs/add', type='http', auth="user", website=True) + @http.route('/jobs/add', type='json', auth="user", website=True) def jobs_add(self, **kwargs): # avoid branding of website_description by setting rendering_bundle in context job = request.env['hr.job'].with_context(rendering_bundle=True).create({ 'name': _('Job Title'), }) - return request.redirect(request.env["website"].get_client_action_url(f"/jobs/detail/{slug(job)}", True)) + return f"/jobs/detail/{slug(job)}" @http.route('''/jobs/detail/''', type='http', auth="public", website=True, sitemap=True) def jobs_detail(self, job, **kwargs): diff --git a/addons/website_hr_recruitment/static/src/js/systray_items/new_content.js b/addons/website_hr_recruitment/static/src/js/systray_items/new_content.js index ef75405fd59..a4c3f2c825a 100644 --- a/addons/website_hr_recruitment/static/src/js/systray_items/new_content.js +++ b/addons/website_hr_recruitment/static/src/js/systray_items/new_content.js @@ -12,7 +12,9 @@ patch(NewContentModal.prototype, 'website_hr_recruitment_new_content', { newJobElement.status = MODULE_STATUS.INSTALLED; }, - createNewJob() { - window.location.replace('/jobs/add'); + async createNewJob() { + const url = await this.rpc('/jobs/add'); + this.website.goToWebsite({ path: url, edition: true }); + this.websiteContext.showNewContentModal = false; } }); diff --git a/addons/website_sale/models/res_config_settings.py b/addons/website_sale/models/res_config_settings.py index ded43adb42b..3a95347ab14 100644 --- a/addons/website_sale/models/res_config_settings.py +++ b/addons/website_sale/models/res_config_settings.py @@ -125,19 +125,11 @@ class ResConfigSettings(models.TransientModel): def action_update_terms(self): self.ensure_one() - return { - 'type': 'ir.actions.act_url', - 'url': self.env["website"].get_client_action_url('/terms', True), - 'target': 'self', - } + return self.env["website"].get_client_action('/terms', True) def action_open_extra_info(self): self.ensure_one() - return { - 'type': 'ir.actions.act_url', - 'url': self.env["website"].get_client_action_url('/shop/extra_info', True), - 'target': 'self', - } + return self.env["website"].get_client_action('/shop/extra_info', True) def action_open_sale_mail_templates(self): return {