/** @odoo-module */ import { HootDomError, getTag, isFirefox, isIterable } from "../hoot_dom_utils"; import { getActiveElement, getDocument, getNextFocusableElement, getNodeRect, getNodeValue, getParentFrame, getPreviousFocusableElement, getStyle, getWindow, isCheckable, isEditable, isEventTarget, isNode, isNodeFocusable, parseDimensions, parsePosition, queryAll, queryFirst, setDimensions, toSelector, } from "./dom"; import { microTick } from "./time"; /** * @typedef {Target | Promise} AsyncTarget * * @typedef {"auto" | "blur" | "enter" | "tab" | false} ConfirmAction * * @typedef {{ * cancel: (options?: EventOptions) => Promise; * drop: (to?: AsyncTarget, options?: PointerOptions) => Promise; * moveTo: (to?: AsyncTarget, options?: PointerOptions) => Promise; * }} DragHelpers * * @typedef {import("./dom").Position} Position * * @typedef {import("./dom").Dimensions} Dimensions * * @typedef {((ev: Event) => boolean) | EventType} EventListPredicate * * @typedef {{ * eventInit?: EventInit; * }} EventOptions generic event options * * @typedef {{ * clientX: number; * clientY: number; * pageX: number; * pageY: number; * screenX: number; * screenY: number; * }} EventPosition * * @typedef {keyof HTMLElementEventMap | keyof WindowEventMap} EventType * * @typedef {EventOptions & { * confirm?: ConfirmAction; * composition?: boolean; * instantly?: boolean; * }} FillOptions * * @typedef {string | number | MaybeIterable} InputValue * * @typedef {EventOptions & KeyboardEventInit} KeyboardOptions * * @typedef {string | string[]} KeyStrokes * * @typedef {EventOptions & QueryOptions & { * button?: number, * position?: Side | `${Side}-${Side}` | Position; * relative?: boolean; * }} PointerOptions * * @typedef {import("./dom").QueryOptions} QueryOptions * * @typedef {EventOptions & QueryOptions & { * force?: boolean; * initiator?: "keyboard" | "scrollbar" | "wheel" | null; * relative?: boolean; * }} ScrollOptions * * @typedef {EventOptions & { * target: AsyncTarget; * }} SelectOptions * * @typedef {"bottom" | "left" | "right" | "top"} Side */ /** * @template [T=EventInit] * @typedef {T & { * target: EventTarget; * type: EventType; * }} FullEventInit */ /** * @template T * @typedef {T | Iterable} MaybeIterable */ /** * @template [T=Node] * @typedef {import("./dom").Target} Target */ //----------------------------------------------------------------------------- // Global //----------------------------------------------------------------------------- const { AnimationEvent, ClipboardEvent, CompositionEvent, console: { dir: $dir, groupCollapsed: $groupCollapsed, groupEnd: $groupEnd, log: $log }, DataTransfer, document, DragEvent, ErrorEvent, Event, FocusEvent, KeyboardEvent, Math: { ceil: $ceil, max: $max, min: $min }, MouseEvent, Number: { isInteger: $isInteger, isNaN: $isNaN, parseFloat: $parseFloat }, Object: { assign: $assign, values: $values }, PointerEvent, PromiseRejectionEvent, String, SubmitEvent, Touch, TouchEvent, TypeError, WheelEvent, } = globalThis; /** @type {Document["createRange"]} */ const $createRange = document.createRange.bind(document); //----------------------------------------------------------------------------- // Internal //----------------------------------------------------------------------------- /** * @param {Event} ev */ const cancelTrustedEvent = (ev) => { if (ev.isTrusted && runTime.eventsToIgnore.includes(ev.type)) { runTime.eventsToIgnore.splice(runTime.eventsToIgnore.indexOf(ev.type), 1); ev.stopPropagation(); ev.stopImmediatePropagation(); ev.preventDefault(); } }; /** * @param {HTMLElement} target * @param {number} start * @param {number} end */ const changeSelection = async (target, start, end) => { if (!isNil(start) && !isNil(target.selectionStart)) { target.selectionStart = start; } if (!isNil(end) && !isNil(target.selectionEnd)) { target.selectionEnd = end; } }; /** * @param {HTMLElement} target * @param {number} x */ const constrainScrollX = (target, x) => { let { offsetWidth, scrollWidth } = target; const document = getDocument(target); if (target === document || target === document.documentElement) { // elements in iframes consider the width of the