diff --git a/addons/web/static/src/core/notebook/notebook.js b/addons/web/static/src/core/notebook/notebook.js index 1da99e393b7..3445022d3e7 100644 --- a/addons/web/static/src/core/notebook/notebook.js +++ b/addons/web/static/src/core/notebook/notebook.js @@ -59,7 +59,7 @@ export class Notebook extends Component { this.anchorTarget = null; this.pages = this.computePages(this.props); this.state = useState({ currentPage: null }); - this.state.currentPage = this.props.defaultPage || this.computeActivePage(); + this.state.currentPage = this.computeActivePage(this.props.defaultPage, true); const onAnchorClicked = this.onAnchorClicked.bind(this); this.env.bus.addEventListener("SCROLLER:ANCHOR_LINK_CLICKED", onAnchorClicked); useEffect( @@ -74,8 +74,10 @@ export class Notebook extends Component { () => [this.state.currentPage] ); onWillUpdateProps((nextProps) => { + const activateDefault = + this.props.defaultPage !== nextProps.defaultPage || !this.defaultVisible; this.pages = this.computePages(nextProps); - this.state.currentPage = this.computeActivePage(); + this.state.currentPage = this.computeActivePage(nextProps.defaultPage, activateDefault); }); onWillDestroy(() => { this.env.bus.removeEventListener("SCROLLER:ANCHOR_LINK_CLICKED", onAnchorClicked); @@ -131,15 +133,27 @@ export class Notebook extends Component { return pages; } - computeActivePage() { + computeActivePage(defaultPage, activateDefault) { if (!this.pages.length) { return null; } - const current = this.state.currentPage; - if (!current || (current && !this.pages.find((e) => e[0] === current)[1].isVisible)) { - const candidate = this.pages.find((v) => v[1].isVisible); - return candidate ? candidate[0] : null; + const pages = this.pages.filter((e) => e[1].isVisible).map((e) => e[0]); + + if (defaultPage) { + if (!pages.includes(defaultPage)) { + this.defaultVisible = false; + } else { + this.defaultVisible = true; + if (activateDefault) { + return defaultPage; + } + } } + const current = this.state.currentPage; + if (!current || (current && !pages.includes(current))) { + return pages[0]; + } + return current; } } diff --git a/addons/web/static/tests/core/notebook_tests.js b/addons/web/static/tests/core/notebook_tests.js index b71c3058ec3..ab3043f8f78 100644 --- a/addons/web/static/tests/core/notebook_tests.js +++ b/addons/web/static/tests/core/notebook_tests.js @@ -2,7 +2,7 @@ import { Notebook } from "@web/core/notebook/notebook"; import { makeTestEnv } from "@web/../tests/helpers/mock_env"; -import { click, getFixture, mount } from "@web/../tests/helpers/utils"; +import { click, getFixture, mount, nextTick } from "@web/../tests/helpers/utils"; const { Component, xml } = owl; let target; @@ -139,11 +139,12 @@ QUnit.module("Components", (hooks) => { await mount(Parent, target, { env }); assert.containsOnce(target, "div.o_notebook"); - assert.containsNone( - target, - ".o_notebook_headers .nav-item a.active", - "no tab is selected as the default page is not visible" + assert.strictEqual( + target.querySelector(".o_notebook_headers .nav-item a.active").textContent, + "About", + "The first page is selected" ); + assert.containsN( target, ".o_notebook_headers a.nav-link", @@ -152,7 +153,7 @@ QUnit.module("Components", (hooks) => { ); assert.strictEqual( target.querySelector(".tab-pane.active").firstElementChild.textContent, - "Oooops", + "About the bird", "third page content is displayed by the notebook" ); }); @@ -291,4 +292,46 @@ QUnit.module("Components", (hooks) => { assert.notEqual(firstPage, secondPage); }); + + QUnit.test("defaultPage recomputed when isVisible is dynamic", async (assert) => { + let defaultPageVisible = false; + class Parent extends Component { + get defaultPageVisible() { + return defaultPageVisible; + } + } + Parent.components = { Notebook }; + Parent.template = xml` + + +
+ + +
+ + +
+ + `; + + const env = await makeTestEnv(); + const parent = await mount(Parent, target, { env }); + assert.containsOnce(target, ".page1"); + assert.strictEqual(target.querySelector(".nav-link.active").textContent, "page1"); + + defaultPageVisible = true; + parent.render(true); + await nextTick(); + assert.containsOnce(target, ".page3"); + assert.strictEqual(target.querySelector(".nav-link.active").textContent, "page3"); + + await click(target.querySelectorAll(".nav-link")[1]); + assert.containsOnce(target, ".page2"); + assert.strictEqual(target.querySelector(".nav-link.active").textContent, "page2"); + + parent.render(true); + await nextTick(); + assert.containsOnce(target, ".page2"); + assert.strictEqual(target.querySelector(".nav-link.active").textContent, "page2"); + }); });