Odoo18-Base/addons/html_editor/static/src/position_hook.js
2025-01-06 10:57:38 +07:00

52 lines
2.2 KiB
JavaScript

import { ancestors } from "@html_editor/utils/dom_traversal";
import { throttleForAnimation } from "@web/core/utils/timing";
import { couldBeScrollableX, couldBeScrollableY } from "@web/core/utils/scrolling";
import { useComponent, useEffect } from "@odoo/owl";
/**
* This hook has the same job as the PositionPlugin, but for Components.
* It was created to be used within the Html Viewer and still have overlays.
*
* TODO ABD: refactor html viewer to: either use a plugin system, or generalize
* the positioning logic so that both the plugin and the hook can use it.
*/
export function usePositionHook(containerRef, document, callback) {
const comp = useComponent();
const onLayoutGeometryChange = throttleForAnimation(callback.bind(comp));
const resizeObserver = new ResizeObserver(onLayoutGeometryChange);
const cleanups = [];
const addDomListener = (target, eventName, capture) => {
target.addEventListener(eventName, onLayoutGeometryChange, capture);
cleanups.push(() => target.removeEventListener(eventName, onLayoutGeometryChange, capture));
};
useEffect(
() => {
if (containerRef.el) {
resizeObserver.observe(document.body);
resizeObserver.observe(containerRef.el);
addDomListener(window, "resize");
if (document.defaultView !== window) {
addDomListener(document.defaultView, "resize");
}
const scrollableElements = [containerRef.el, ...ancestors(containerRef.el)].filter(
(node) => {
return couldBeScrollableX(node) || couldBeScrollableY(node);
}
);
for (const scrollableElement of scrollableElements) {
addDomListener(scrollableElement, "scroll");
resizeObserver.observe(scrollableElement);
}
}
return () => {
resizeObserver.disconnect();
for (const cleanup of cleanups.toReversed()) {
cleanup();
cleanups.pop();
}
};
},
() => [containerRef.el]
);
}