52 lines
2.2 KiB
JavaScript
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]
|
|
);
|
|
}
|