From d3a3397c4de09aa83960d6941e6a8e27b11daa6d Mon Sep 17 00:00:00 2001 From: Younn Olivier Date: Mon, 3 Oct 2022 15:05:14 +0000 Subject: [PATCH] [FIX] website: prefer requested action url over last url Before this commit, there was a conflict between 2 of the ways to open the WebsitePreview iframe. First, introduced with [1], when a user click on the 'edit in backend' systray button, the URL he was on is stored to be used later if the user click on the "Website Preview" breadcrumb. When he will click on that breadcrumb entry, we want him to go back to where he was, not on the homepage. Second, some records in form views have a "Go to website" stat button that will go to the website preview action, loading the iframe with the URL of the record from the form view. Before this commit, the second flow was not working if the user previously click on "Edit in backend" on a record (first flow described). Indeed, if that "last url" was set, it would always be used, ignoring the requested one from the second flow. Step to reproduce: - Go to a record in the website preview, like a product - Click on edit in backend - You land on the product form view, and that url was saved in JS - From there, navigate to another record through the form view, like a m2o relation or a stat button, or by whatever other mean, but don't hard reload the page (F5) - For the example, let's say you landed on a blog post record - Click on "Go to website" on that blog post form view -> You land on the product page you were initially, not on the requested blog post page. Courtesy of @rdeodoo [1]: https://github.com/odoo/odoo/commit/31cc10b91dc7762e23b4bde9b945be0c4ce3fe3b task-2687506 closes odoo/odoo#103010 X-original-commit: 7cd55e8a1d9516a6f457320064160328a49210f9 Signed-off-by: Romain Derie (rde) Signed-off-by: Quentin Smetz (qsm) --- .../website_preview/website_preview.js | 52 +++++++++---------- .../static/src/services/website_service.js | 10 ++-- .../src/systray_items/edit_in_backend.js | 8 +-- 3 files changed, 32 insertions(+), 38 deletions(-) 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 fa10a20ad42..4d40f9a2a32 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 @@ -35,6 +35,10 @@ export class WebsitePreview extends Component { isBlocked: false, showLoader: false, }); + // The params used to configure the context should be ignored when the + // action is restored (example: click on the breadcrumb). + this.isRestored = this.props.action.jsId === this.websiteService.actionJsId; + this.websiteService.actionJsId = this.props.action.jsId; useBus(this.websiteService.bus, 'BLOCK', (event) => this.block(event.detail)); useBus(this.websiteService.bus, 'UNBLOCK', () => this.unblock()); @@ -57,12 +61,7 @@ export class WebsitePreview extends Component { useEffect(() => { this.websiteService.currentWebsiteId = this.websiteId; - - // The params used to configure the context should be ignored when - // the action is restored (example: click on the breadcrumb). - const isRestored = this.props.action.jsId === this.websiteService.actionJsId; - this.websiteService.actionJsId = this.props.action.jsId; - if (isRestored) { + if (this.isRestored) { return; } this.websiteService.context.showNewContentModal = this.props.action.context.params && this.props.action.context.params.display_new_content; @@ -95,6 +94,8 @@ export class WebsitePreview extends Component { this.env.services.messaging.modelManager.messagingCreatedPromise.then(() => { this.env.services.messaging.modelManager.messaging.update({ isWebsitePreviewOpen: false }); }); + const { pathname, search, hash } = this.iframe.el.contentWindow.location; + this.websiteService.lastUrl = `${pathname}${search}${hash}`; this.websiteService.currentWebsiteId = null; this.websiteService.websiteRootInstance = undefined; this.websiteService.pageDocument = null; @@ -189,28 +190,27 @@ export class WebsitePreview extends Component { } get path() { - let path = this.websiteService.editedObjectPath; - if (!path) { - path = this.props.action.context.params && this.props.action.context.params.path; - if (path) { - const url = new URL(path, window.location.origin); - if (this._isTopWindowURL(url)) { - // If the client action is initialized with a path that - // should not be opened inside the iframe (= something we - // would want to open on the top window), we consider that - // this is not a valid flow. Instead of trying to open it on - // the top window, we initialize the iframe with the - // website homepage... - path = '/'; - } else { - // ... otherwise, the path still needs to be normalized (as - // it would be if the given path was used as an href of a - // element). - path = url.pathname + url.search + url.hash; - } - } else { + let path = this.isRestored + ? this.websiteService.lastUrl + : this.props.action.context.params && this.props.action.context.params.path; + + if (path) { + const url = new URL(path, window.location.origin); + if (this._isTopWindowURL(url)) { + // If the client action is initialized with a path that should + // not be opened inside the iframe (= something we would want to + // open on the top window), we consider that this is not a valid + // flow. Instead of trying to open it on the top window, we + // initialize the iframe with the website homepage... path = '/'; + } else { + // ... otherwise, the path still needs to be normalized (as it + // would be if the given path was used as an href of a + // element). + path = url.pathname + url.search + url.hash; } + } else { + path = '/'; } return path; } diff --git a/addons/website/static/src/services/website_service.js b/addons/website/static/src/services/website_service.js index 046ab059018..cfffab1ebe4 100644 --- a/addons/website/static/src/services/website_service.js +++ b/addons/website/static/src/services/website_service.js @@ -32,7 +32,7 @@ export const websiteService = { let fullscreen; let pageDocument; let contentWindow; - let editedObjectPath; + let lastUrl; let websiteRootInstance; let Wysiwyg; let isRestrictedEditor; @@ -151,11 +151,11 @@ export const websiteService = { websiteRootInstance = rootInstance; context.isPublicRootReady = !!rootInstance; }, - set editedObjectPath(path) { - editedObjectPath = path; + set lastUrl(url) { + lastUrl = url; }, - get editedObjectPath() { - return editedObjectPath; + get lastUrl() { + return lastUrl; }, get isRestrictedEditor() { return isRestrictedEditor === true; diff --git a/addons/website/static/src/systray_items/edit_in_backend.js b/addons/website/static/src/systray_items/edit_in_backend.js index 93408c89730..329b4a9a38c 100644 --- a/addons/website/static/src/systray_items/edit_in_backend.js +++ b/addons/website/static/src/systray_items/edit_in_backend.js @@ -3,7 +3,7 @@ import { registry } from "@web/core/registry"; import { useService, useBus } from "@web/core/utils/hooks"; -const { Component, onWillStart, onMounted, useState } = owl; +const { Component, onWillStart, useState } = owl; const websiteSystrayRegistry = registry.category('website_systray'); @@ -15,16 +15,10 @@ export class EditInBackendSystray extends Component { onWillStart(this._updateMainObjectName); useBus(websiteSystrayRegistry, 'CONTENT-UPDATED', this._updateMainObjectName); - - onMounted(() => { - this.websiteService.editedObjectPath = null; - }); } editInBackend() { const { metadata: { mainObject } } = this.websiteService.currentWebsite; - const location = this.websiteService.contentWindow.location; - this.websiteService.editedObjectPath = location.pathname + location.search + location.hash; this.actionService.doAction({ res_model: mainObject.model, res_id: mainObject.id,