From 31c52824beed56e4ca3b65e25cff83540570cc8d Mon Sep 17 00:00:00 2001 From: Bruno Boi Date: Thu, 12 Oct 2023 10:13:59 +0200 Subject: [PATCH] [REF] web_tour: replace a deprecated function **Before this commit** The TourPointer component make use of a deprecated function (reposition) in order to position itself. **After this commit** The TourPointer now make use of the usePosition hook, which is the recommended way to compute this kind of positioning. Part-of: odoo/odoo#135188 --- .../static/src/tour_pointer/tour_pointer.js | 168 ++++++++---------- .../src/tour_service/tour_pointer_state.js | 3 +- 2 files changed, 80 insertions(+), 91 deletions(-) diff --git a/addons/web_tour/static/src/tour_pointer/tour_pointer.js b/addons/web_tour/static/src/tour_pointer/tour_pointer.js index 79f9c73f440..e6713311531 100644 --- a/addons/web_tour/static/src/tour_pointer/tour_pointer.js +++ b/addons/web_tour/static/src/tour_pointer/tour_pointer.js @@ -1,7 +1,7 @@ /** @odoo-module **/ import { Component, useEffect, useRef } from "@odoo/owl"; -import { reposition } from "@web/core/position_hook"; +import { usePosition } from "@web/core/position_hook"; /** * @typedef {import("../tour_service/tour_pointer_state").TourPointerState} TourPointerState @@ -48,6 +48,26 @@ export class TourPointer extends Component { static height = 28; // in pixels setup() { + const positionOptions = { + margin: 6, + onPositioned: (pointer, position) => { + const popperRect = pointer.getBoundingClientRect(); + const { top, left, direction } = position; + if (direction === "top") { + // position from the bottom instead of the top as it is needed + // to ensure the expand animation is properly done + pointer.style.bottom = `${window.innerHeight - top - popperRect.height}px`; + pointer.style.removeProperty("top"); + } else if (direction === "left") { + // position from the right instead of the left as it is needed + // to ensure the expand animation is properly done + pointer.style.right = `${window.innerWidth - left - popperRect.width}px`; + pointer.style.removeProperty("left"); + } + }, + }; + Object.defineProperty(positionOptions, "position", { get: () => this.position, enumerable: true }); + const position = usePosition("pointer", () => this.props.pointerState.anchor, positionOptions); const rootRef = useRef("pointer"); /** @type {DOMREct | null} */ let dimensions = null; @@ -55,96 +75,66 @@ export class TourPointer extends Component { let lastOpenState = this.isOpen; let lastAnchor; let [anchorX, anchorY] = [0, 0]; + useEffect(() => { + const { el: pointer } = rootRef; + if (pointer) { + const hasContentChanged = lastMeasuredContent !== this.content; + const hasOpenStateChanged = lastOpenState !== this.isOpen; + lastOpenState = this.isOpen; - useEffect( - () => { - const { el: pointer } = rootRef; - if (pointer) { - const hasContentChanged = lastMeasuredContent !== this.content; - const hasOpenStateChanged = lastOpenState !== this.isOpen; - lastOpenState = this.isOpen; - - // Content changed: we must re-measure the dimensions of the text. - if (hasContentChanged) { - lastMeasuredContent = this.content; - pointer.style.removeProperty("width"); - pointer.style.removeProperty("height"); - dimensions = pointer.getBoundingClientRect(); - } - - // If the content or the "is open" state changed: we must apply - // new width and height properties - if (hasContentChanged || hasOpenStateChanged) { - const [width, height] = this.isOpen - ? [dimensions.width, dimensions.height] - : [this.constructor.width, this.constructor.height]; - if (this.isOpen) { - pointer.style.removeProperty("transition"); - } else { - // No transition if switching from open to closed - pointer.style.setProperty("transition", "none"); - } - pointer.style.setProperty("width", `${width}px`); - pointer.style.setProperty("height", `${height}px`); - } - - if (!this.isOpen) { - const { anchor } = this.props.pointerState; - if (anchor === lastAnchor) { - const { x, y, width } = anchor.getBoundingClientRect(); - const [lastAnchorX, lastAnchorY] = [anchorX, anchorY]; - [anchorX, anchorY] = [x, y]; - // Let's just say that the anchor is static if it moved less than 1px. - const delta = Math.sqrt( - Math.pow(x - lastAnchorX, 2) + Math.pow(y - lastAnchorY, 2) - ); - if (delta < 1) { - return; - } - const wouldOverflow = - window.innerWidth - x - width / 2 < dimensions?.width; - pointer.classList.toggle("o_expand_left", wouldOverflow); - } - lastAnchor = anchor; - pointer.style.bottom = ""; - pointer.style.right = ""; - reposition( - pointer, - anchor, - { - position: this.position, - margin: 6, - onPositioned: (_, position) => { - const popperRect = pointer.getBoundingClientRect(); - const { top, left, direction } = position; - if (direction === "top") { - // position from the bottom instead of the top as it is needed - // to ensure the expand animation is properly done - pointer.style.bottom = `${ - window.innerHeight - top - popperRect.height - }px`; - pointer.style.removeProperty("top"); - } else if (direction === "left") { - // position from the right instead of the left as it is needed - // to ensure the expand animation is properly done - pointer.style.right = `${ - window.innerWidth - left - popperRect.width - }px`; - pointer.style.removeProperty("left"); - } - }, - } - ); - } - } else { - lastMeasuredContent = null; - lastOpenState = false; - lastAnchor = null; - dimensions = null; + // Content changed: we must re-measure the dimensions of the text. + if (hasContentChanged) { + lastMeasuredContent = this.content; + pointer.style.removeProperty("width"); + pointer.style.removeProperty("height"); + dimensions = pointer.getBoundingClientRect(); } - }, - () => [this.props.pointerState.rev] - ); + + // If the content or the "is open" state changed: we must apply + // new width and height properties + if (hasContentChanged || hasOpenStateChanged) { + const [width, height] = this.isOpen + ? [dimensions.width, dimensions.height] + : [this.constructor.width, this.constructor.height]; + if (this.isOpen) { + pointer.style.removeProperty("transition"); + } else { + // No transition if switching from open to closed + pointer.style.setProperty("transition", "none"); + } + pointer.style.setProperty("width", `${width}px`); + pointer.style.setProperty("height", `${height}px`); + } + + if (!this.isOpen) { + const { anchor } = this.props.pointerState; + if (anchor === lastAnchor) { + const { x, y, width } = anchor.getBoundingClientRect(); + const [lastAnchorX, lastAnchorY] = [anchorX, anchorY]; + [anchorX, anchorY] = [x, y]; + // Let's just say that the anchor is static if it moved less than 1px. + const delta = Math.sqrt( + Math.pow(x - lastAnchorX, 2) + Math.pow(y - lastAnchorY, 2) + ); + if (delta < 1) { + position.lock(); + return; + } + const wouldOverflow = window.innerWidth - x - width / 2 < dimensions?.width; + pointer.classList.toggle("o_expand_left", wouldOverflow); + } + lastAnchor = anchor; + pointer.style.bottom = ""; + pointer.style.right = ""; + position.unlock(); + } + } else { + lastMeasuredContent = null; + lastOpenState = false; + lastAnchor = null; + dimensions = null; + } + }); } get content() { diff --git a/addons/web_tour/static/src/tour_service/tour_pointer_state.js b/addons/web_tour/static/src/tour_service/tour_pointer_state.js index b7189f987c9..94cedb47544 100644 --- a/addons/web_tour/static/src/tour_service/tour_pointer_state.js +++ b/addons/web_tour/static/src/tour_service/tour_pointer_state.js @@ -94,7 +94,7 @@ export function createPointerState() { * @param {Partial} newState */ const setState = (newState) => { - Object.assign(state, newState, { rev: currentRev++ }); + Object.assign(state, newState); }; /** @@ -171,7 +171,6 @@ export function createPointerState() { } } - let currentRev = 1; /** @type {TourPointerState} */ const state = reactive({}); const intersection = new Intersection();