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 c5dbbce69e7..c68bcc85678 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 @@ -353,7 +353,44 @@ export class WebsitePreview extends Component { this.title.setParts({ action: currentTitle }); } - _onPageLoaded() { + _onPageLoaded(ev) { + // FIX Chrome-only. If you have the backend in a language A but the + // website in English only, you can 1) modify a record's (event, + // product...) name in language A (say "New Name"). + // 2) visit the page `/new-name-11` => the server will redirect you to + // the English page `/origin-11`, which is the only one existing. + // Chrome caches the redirection. + // 3) give the same name in English as in language A, try to visit + // => the server now wants to access `/new-name-11` + // => Chrome uses the cache to redirect `/new-name-11` to `/origin-11`, + // => the server tries to redirect to `/new-name-11` => loop. + // Chrome injects a "Too many redirects" layout in the iframe, which in + // turn raises a CORS error when the app tries to update the iframe. + // If we detect that behavior, we reload the iframe with a new query + // parameter, so that it's not cached for Chrome. + if ( + navigator.userAgent.toLowerCase().includes("chrome") + && !this.iframe.el.src.includes("iframe_reload") + ) { + try { + /* eslint-disable no-unused-expressions */ + this.iframe.el.contentWindow.location.href; + } catch (err) { + if (err.name === "SecurityError") { + ev.stopImmediatePropagation(); + // Note that iframe's `src` is the URL used to start the + // website preview, it's not sync'd with iframe navigation. + const srcUrl = new URL(this.iframe.el.src); + const pathUrl = new URL(srcUrl.searchParams.get("path"), srcUrl.origin); + pathUrl.searchParams.set("iframe_reload", "1"); + srcUrl.searchParams.set("path", `${pathUrl.pathname}${pathUrl.search}`); + // We could inject `pathUrl` directly but keep the same + // expected URL format `/website/force/1?path=..` + this.iframe.el.src = srcUrl.toString(); + return; + } + } + } if (this.lastHiddenPageURL !== this.iframe.el.contentWindow.location.href) { // Hide Ace Editor when moving to another page. this.websiteService.context.showResourceEditor = false;