[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
This commit is contained in:
Younn Olivier
2022-08-31 22:13:22 +02:00
committed by qsm-odoo
parent 444b07f031
commit a0b3499d34
@@ -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;