From a0b3499d348d252c3abd48154e1fd8dd545c7504 Mon Sep 17 00:00:00 2001 From: Younn Olivier Date: Tue, 23 Aug 2022 15:51:51 +0000 Subject: [PATCH] [FIX] website: fix back/forth navigation from iframe to other routes Before this commit, following this flow on enterprise: - Go to the webclient, on the homepage: '/web' - Click on the website - Click on the "contact us" menu - Click on the browser's back button => The back navigation happens in the iframe, it's normal - Click on the back button again => The url has changed for the webclient "homepage" one but the WebsitePreview is still displayed. This happens because the router service listens to the hashchange events to communicate the webclient which component to display. But with [1] it was decided to replace the regular webclient's router url from the WebsitePreview client action with the frontend's url. As a result, the 'hashchange' is never fired when navigating back from the client action to another webclient route. To fix that, the 'popstate' event is listened at the client action level. If the new url is a regular webclient's router one, an 'hashchange' event is triggered to continue the flow as if the browser's url was never changed. The same hook is used to revert back the original webclient route /web#action=website.website_preview... when leaving it, so that the router can replay it correctly when navigating back from another route. [1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b task-2687506 Part-of: odoo/odoo#97408 --- .../website_preview/website_preview.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) 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 75d553375ce..466177f04e1 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 @@ -7,6 +7,7 @@ import { AceEditorAdapterComponent } from '../../components/ace_editor/ace_edito import { WebsiteEditorComponent } from '../../components/editor/editor'; import { WebsiteTranslator } from '../../components/translator/translator'; import {OptimizeSEODialog} from '@website/components/dialog/seo'; +import { routeToUrl } from "@web/core/browser/router_service"; const { Component, onWillStart, onMounted, onWillUnmount, useRef, useEffect, useState } = owl; @@ -84,6 +85,25 @@ export class WebsitePreview extends Component { this.websiteService.websiteRootInstance = undefined; this.websiteService.pageDocument = null; }); + + useEffect(() => { + // 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, + // which was lost after being replaced for the frontend's URL. + const handleBackNavigation = () => { + if (!window.location.pathname.startsWith('/@')) { + window.dispatchEvent(new HashChangeEvent('hashchange', { + newURL: window.location.href.toString() + })); + } + }; + window.addEventListener('popstate', handleBackNavigation); + return () => { + history.pushState({}, null, this.backendUrl); + window.removeEventListener('popstate', handleBackNavigation); + }; + }, () => []); } get websiteId() { @@ -192,6 +212,12 @@ export class WebsitePreview extends Component { * the iframe's url (it is clearer for the user). */ _replaceBrowserUrl() { + // The original /web#action=... url is saved to be pushed on top of the + // history when leaving the component, so that the webclient can + // correctly find back and replay the client action. + if (!this.backendUrl) { + this.backendUrl = routeToUrl(this.router.current); + } const currentUrl = new URL(this.iframe.el.contentDocument.location.href); currentUrl.pathname = `/@${currentUrl.pathname}`; this.currentTitle = this.iframe.el.contentDocument.title;