diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2024-02-18 08:11:47 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-18 13:11:47 +0000 | 
| commit | cfc65c31313731dfa0d36c2eceaca35e9d50992f (patch) | |
| tree | ec96ec7ab1c3dae559fe5d7930c186347fb64a25 | |
| parent | 6cf38229b54efbbc3ae7bc174c3999f9dfa7b1d2 (diff) | |
Refactor DocumentUtil (#706)
* Refactor DocumentUtil
* Isolate suppression
| -rw-r--r-- | ext/js/accessibility/google-docs-util.js | 6 | ||||
| -rw-r--r-- | ext/js/app/frontend.js | 6 | ||||
| -rw-r--r-- | ext/js/app/popup.js | 10 | ||||
| -rw-r--r-- | ext/js/dom/document-util.js | 798 | ||||
| -rw-r--r-- | ext/js/dom/dom-data-binder.js | 4 | ||||
| -rw-r--r-- | ext/js/dom/text-source-element.js | 4 | ||||
| -rw-r--r-- | ext/js/dom/text-source-generator.js | 8 | ||||
| -rw-r--r-- | ext/js/dom/text-source-range.js | 16 | ||||
| -rw-r--r-- | ext/js/input/hotkey-handler.js | 6 | ||||
| -rw-r--r-- | ext/js/language/text-scanner.js | 16 | ||||
| -rw-r--r-- | ext/js/pages/settings/generic-setting-controller.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/keyboard-mouse-input-field.js | 8 | ||||
| -rw-r--r-- | ext/js/pages/settings/keyboard-shortcuts-controller.js | 6 | ||||
| -rw-r--r-- | ext/js/pages/settings/nested-popups-controller.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/profile-conditions-ui.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/scan-inputs-controller.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/settings-display-controller.js | 4 | 
17 files changed, 454 insertions, 454 deletions
| diff --git a/ext/js/accessibility/google-docs-util.js b/ext/js/accessibility/google-docs-util.js index 31ae5982..f3f800fd 100644 --- a/ext/js/accessibility/google-docs-util.js +++ b/ext/js/accessibility/google-docs-util.js @@ -16,7 +16,7 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -import {DocumentUtil} from '../dom/document-util.js'; +import {computeZoomScale, isPointInAnyRect} from '../dom/document-util.js';  import {TextSourceRange} from '../dom/text-source-range.js';  /** @@ -126,7 +126,7 @@ export class GoogleDocsUtil {       */      _getRangeWithPoint(textNode, x, y, normalizeCssZoom) {          if (normalizeCssZoom) { -            const scale = DocumentUtil.computeZoomScale(textNode); +            const scale = computeZoomScale(textNode);              x /= scale;              y /= scale;          } @@ -137,7 +137,7 @@ export class GoogleDocsUtil {              const mid = Math.floor((start + end) / 2);              range.setStart(textNode, mid);              range.setEnd(textNode, end); -            if (DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) { +            if (isPointInAnyRect(x, y, range.getClientRects())) {                  start = mid;              } else {                  end = mid; diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js index 9c4778cc..04f8673f 100644 --- a/ext/js/app/frontend.js +++ b/ext/js/app/frontend.js @@ -20,7 +20,7 @@ import {createApiMap, invokeApiMapHandler} from '../core/api-map.js';  import {EventListenerCollection} from '../core/event-listener-collection.js';  import {log} from '../core/log.js';  import {promiseAnimationFrame} from '../core/promise-animation-frame.js'; -import {DocumentUtil} from '../dom/document-util.js'; +import {addFullscreenChangeEventListener, getFullscreenElement} from '../dom/document-util.js';  import {TextSourceElement} from '../dom/text-source-element.js';  import {TextSourceGenerator} from '../dom/text-source-generator.js';  import {TextSourceRange} from '../dom/text-source-range.js'; @@ -163,7 +163,7 @@ export class Frontend {          this._textScanner.prepare();          window.addEventListener('resize', this._onResize.bind(this), false); -        DocumentUtil.addFullscreenChangeEventListener(this._updatePopup.bind(this)); +        addFullscreenChangeEventListener(this._updatePopup.bind(this));          const {visualViewport} = window;          if (typeof visualViewport !== 'undefined' && visualViewport !== null) { @@ -523,7 +523,7 @@ export class Frontend {          } else if (              isIframe &&              showIframePopupsInRootFrame && -            DocumentUtil.getFullscreenElement() === null && +            getFullscreenElement() === null &&              this._allowRootFramePopupProxy          ) {              popupPromise = this._popupCache.get('iframe'); diff --git a/ext/js/app/popup.js b/ext/js/app/popup.js index 103a5468..c9011932 100644 --- a/ext/js/app/popup.js +++ b/ext/js/app/popup.js @@ -22,7 +22,7 @@ import {EventDispatcher} from '../core/event-dispatcher.js';  import {EventListenerCollection} from '../core/event-listener-collection.js';  import {ExtensionError} from '../core/extension-error.js';  import {deepEqual} from '../core/utilities.js'; -import {DocumentUtil} from '../dom/document-util.js'; +import {addFullscreenChangeEventListener, computeZoomScale, convertRectZoomCoordinates, getFullscreenElement} from '../dom/document-util.js';  import {loadStyle} from '../dom/style-util.js';  import {ThemeController} from './theme-controller.js'; @@ -594,7 +594,7 @@ export class Popup extends EventDispatcher {              return;          } -        DocumentUtil.addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners); +        addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners);      }      /** @@ -748,7 +748,7 @@ export class Popup extends EventDispatcher {          if (defaultParent !== null && defaultParent.tagName.toLowerCase() === 'frameset') {              defaultParent = document.documentElement;          } -        const fullscreenElement = DocumentUtil.getFullscreenElement(); +        const fullscreenElement = getFullscreenElement();          if (              fullscreenElement === null ||              fullscreenElement.shadowRoot || @@ -1091,7 +1091,7 @@ export class Popup extends EventDispatcher {       * @returns {DOMRect} The rectangle of the frame.       */      _getFrameBoundingClientRect() { -        return DocumentUtil.convertRectZoomCoordinates(this._frame.getBoundingClientRect(), this._container); +        return convertRectZoomCoordinates(this._frame.getBoundingClientRect(), this._container);      }      /** @@ -1100,7 +1100,7 @@ export class Popup extends EventDispatcher {       * @returns {import('popup').Rect[]} Either an updated list of rectangles, or `sourceRects` if no change is required.       */      _convertSourceRectsCoordinateSpace(sourceRects) { -        let scale = DocumentUtil.computeZoomScale(this._container); +        let scale = computeZoomScale(this._container);          if (scale === 1) { return sourceRects; }          scale = 1 / scale;          const sourceRects2 = []; diff --git a/ext/js/dom/document-util.js b/ext/js/dom/document-util.js index a98bfe86..bf11f421 100644 --- a/ext/js/dom/document-util.js +++ b/ext/js/dom/document-util.js @@ -15,466 +15,466 @@   * You should have received a copy of the GNU General Public License   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -  /** - * This class contains utility functions related to the HTML document. - * TODO : This class should be made non-static + * This variable is stateful, but it is only used to do feature detection, + * and its value should be constant for the lifetime of the extension. + * @type {?boolean}   */ -// eslint-disable-next-line unicorn/no-static-only-class -export class DocumentUtil { -    /** @type {?boolean} */ -    static _cssZoomSupported = null; +let cssZoomSupported = null; -    /** -     * Computes the scaling adjustment that is necessary for client space coordinates based on the -     * CSS zoom level. -     * @param {?Node} node A node in the document. -     * @returns {number} The scaling factor. -     */ -    static computeZoomScale(node) { -        if (this._cssZoomSupported === null) { -            this._cssZoomSupported = this._computeCssZoomSupported(); -        } -        if (!this._cssZoomSupported) { return 1; } -        // documentElement must be excluded because the computer style of its zoom property is inconsistent. -        // * If CSS `:root{zoom:X;}` is specified, the computed zoom will always report `X`. -        // * If CSS `:root{zoom:X;}` is not specified, the computed zoom report the browser's zoom level. -        // Therefor, if CSS root zoom is specified as a value other than 1, the adjusted {x, y} values -        // would be incorrect, which is not new behaviour. -        let scale = 1; -        const {ELEMENT_NODE, DOCUMENT_FRAGMENT_NODE} = Node; -        const {documentElement} = document; -        for (; node !== null && node !== documentElement; node = node.parentNode) { -            const {nodeType} = node; -            if (nodeType === DOCUMENT_FRAGMENT_NODE) { -                const {host} = /** @type {ShadowRoot} */ (node); -                if (typeof host !== 'undefined') { -                    node = host; -                } -                continue; -            } else if (nodeType !== ELEMENT_NODE) { -                continue; +/** + * Computes the scaling adjustment that is necessary for client space coordinates based on the + * CSS zoom level. + * @param {?Node} node A node in the document. + * @returns {number} The scaling factor. + */ +export function computeZoomScale(node) { +    if (cssZoomSupported === null) { +        cssZoomSupported = computeCssZoomSupported(); +    } +    if (!cssZoomSupported) { return 1; } +    // documentElement must be excluded because the computer style of its zoom property is inconsistent. +    // * If CSS `:root{zoom:X;}` is specified, the computed zoom will always report `X`. +    // * If CSS `:root{zoom:X;}` is not specified, the computed zoom report the browser's zoom level. +    // Therefor, if CSS root zoom is specified as a value other than 1, the adjusted {x, y} values +    // would be incorrect, which is not new behaviour. +    let scale = 1; +    const {ELEMENT_NODE, DOCUMENT_FRAGMENT_NODE} = Node; +    const {documentElement} = document; +    for (; node !== null && node !== documentElement; node = node.parentNode) { +        const {nodeType} = node; +        if (nodeType === DOCUMENT_FRAGMENT_NODE) { +            const {host} = /** @type {ShadowRoot} */ (node); +            if (typeof host !== 'undefined') { +                node = host;              } -            const zoomString = getComputedStyle(/** @type {HTMLElement} */ (node)).getPropertyValue('zoom'); -            if (typeof zoomString !== 'string' || zoomString.length === 0) { continue; } -            const zoom = Number.parseFloat(zoomString); -            if (!Number.isFinite(zoom) || zoom === 0) { continue; } -            scale *= zoom; +            continue; +        } else if (nodeType !== ELEMENT_NODE) { +            continue;          } -        return scale; +        const zoomString = getComputedStyle(/** @type {HTMLElement} */ (node)).getPropertyValue('zoom'); +        if (typeof zoomString !== 'string' || zoomString.length === 0) { continue; } +        const zoom = Number.parseFloat(zoomString); +        if (!Number.isFinite(zoom) || zoom === 0) { continue; } +        scale *= zoom;      } +    return scale; +} -    /** -     * Converts a rect based on the CSS zoom scaling for a given node. -     * @param {DOMRect} rect The rect to convert. -     * @param {Node} node The node to compute the zoom from. -     * @returns {DOMRect} The updated rect, or the same rect if no change is needed. -     */ -    static convertRectZoomCoordinates(rect, node) { -        const scale = this.computeZoomScale(node); -        return (scale === 1 ? rect : new DOMRect(rect.left * scale, rect.top * scale, rect.width * scale, rect.height * scale)); -    } +/** + * Converts a rect based on the CSS zoom scaling for a given node. + * @param {DOMRect} rect The rect to convert. + * @param {Node} node The node to compute the zoom from. + * @returns {DOMRect} The updated rect, or the same rect if no change is needed. + */ +export function convertRectZoomCoordinates(rect, node) { +    const scale = computeZoomScale(node); +    return (scale === 1 ? rect : new DOMRect(rect.left * scale, rect.top * scale, rect.width * scale, rect.height * scale)); +} -    /** -     * Converts multiple rects based on the CSS zoom scaling for a given node. -     * @param {DOMRect[]|DOMRectList} rects The rects to convert. -     * @param {Node} node The node to compute the zoom from. -     * @returns {DOMRect[]} The updated rects, or the same rects array if no change is needed. -     */ -    static convertMultipleRectZoomCoordinates(rects, node) { -        const scale = this.computeZoomScale(node); -        if (scale === 1) { return [...rects]; } -        const results = []; -        for (const rect of rects) { -            results.push(new DOMRect(rect.left * scale, rect.top * scale, rect.width * scale, rect.height * scale)); -        } -        return results; +/** + * Converts multiple rects based on the CSS zoom scaling for a given node. + * @param {DOMRect[]|DOMRectList} rects The rects to convert. + * @param {Node} node The node to compute the zoom from. + * @returns {DOMRect[]} The updated rects, or the same rects array if no change is needed. + */ +export function convertMultipleRectZoomCoordinates(rects, node) { +    const scale = computeZoomScale(node); +    if (scale === 1) { return [...rects]; } +    const results = []; +    for (const rect of rects) { +        results.push(new DOMRect(rect.left * scale, rect.top * scale, rect.width * scale, rect.height * scale));      } +    return results; +} -    /** -     * Checks whether a given point is contained within a rect. -     * @param {number} x The horizontal coordinate. -     * @param {number} y The vertical coordinate. -     * @param {DOMRect} rect The rect to check. -     * @returns {boolean} `true` if the point is inside the rect, `false` otherwise. -     */ -    static isPointInRect(x, y, rect) { -        return ( -            x >= rect.left && x < rect.right && -            y >= rect.top && y < rect.bottom -        ); -    } +/** + * Checks whether a given point is contained within a rect. + * @param {number} x The horizontal coordinate. + * @param {number} y The vertical coordinate. + * @param {DOMRect} rect The rect to check. + * @returns {boolean} `true` if the point is inside the rect, `false` otherwise. + */ +export function isPointInRect(x, y, rect) { +    return ( +        x >= rect.left && x < rect.right && +        y >= rect.top && y < rect.bottom +    ); +} -    /** -     * Checks whether a given point is contained within any rect in a list. -     * @param {number} x The horizontal coordinate. -     * @param {number} y The vertical coordinate. -     * @param {DOMRect[]|DOMRectList} rects The rect to check. -     * @returns {boolean} `true` if the point is inside any of the rects, `false` otherwise. -     */ -    static isPointInAnyRect(x, y, rects) { -        for (const rect of rects) { -            if (this.isPointInRect(x, y, rect)) { -                return true; -            } +/** + * Checks whether a given point is contained within any rect in a list. + * @param {number} x The horizontal coordinate. + * @param {number} y The vertical coordinate. + * @param {DOMRect[]|DOMRectList} rects The rect to check. + * @returns {boolean} `true` if the point is inside any of the rects, `false` otherwise. + */ +export function isPointInAnyRect(x, y, rects) { +    for (const rect of rects) { +        if (isPointInRect(x, y, rect)) { +            return true;          } -        return false;      } +    return false; +} -    /** -     * Checks whether a given point is contained within a selection range. -     * @param {number} x The horizontal coordinate. -     * @param {number} y The vertical coordinate. -     * @param {Selection} selection The selection to check. -     * @returns {boolean} `true` if the point is inside the selection, `false` otherwise. -     */ -    static isPointInSelection(x, y, selection) { -        for (let i = 0; i < selection.rangeCount; ++i) { -            const range = selection.getRangeAt(i); -            if (this.isPointInAnyRect(x, y, range.getClientRects())) { -                return true; -            } +/** + * Checks whether a given point is contained within a selection range. + * @param {number} x The horizontal coordinate. + * @param {number} y The vertical coordinate. + * @param {Selection} selection The selection to check. + * @returns {boolean} `true` if the point is inside the selection, `false` otherwise. + */ +export function isPointInSelection(x, y, selection) { +    for (let i = 0; i < selection.rangeCount; ++i) { +        const range = selection.getRangeAt(i); +        if (isPointInAnyRect(x, y, range.getClientRects())) { +            return true;          } -        return false;      } +    return false; +} -    /** -     * Gets an array of the active modifier keys. -     * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. -     * @returns {import('input').ModifierKey[]} An array of modifiers. -     */ -    static getActiveModifiers(event) { -        /** @type {import('input').ModifierKey[]} */ -        const modifiers = []; -        if (event.altKey) { modifiers.push('alt'); } -        if (event.ctrlKey) { modifiers.push('ctrl'); } -        if (event.metaKey) { modifiers.push('meta'); } -        if (event.shiftKey) { modifiers.push('shift'); } -        return modifiers; -    } +/** + * Gets an array of the active modifier keys. + * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. + * @returns {import('input').ModifierKey[]} An array of modifiers. + */ +export function getActiveModifiers(event) { +    /** @type {import('input').ModifierKey[]} */ +    const modifiers = []; +    if (event.altKey) { modifiers.push('alt'); } +    if (event.ctrlKey) { modifiers.push('ctrl'); } +    if (event.metaKey) { modifiers.push('meta'); } +    if (event.shiftKey) { modifiers.push('shift'); } +    return modifiers; +} -    /** -     * Gets an array of the active modifier keys and buttons. -     * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. -     * @returns {import('input').Modifier[]} An array of modifiers and buttons. -     */ -    static getActiveModifiersAndButtons(event) { -        /** @type {import('input').Modifier[]} */ -        const modifiers = this.getActiveModifiers(event); -        if (event instanceof MouseEvent) { -            this._getActiveButtons(event, modifiers); -        } -        return modifiers; +/** + * Gets an array of the active modifier keys and buttons. + * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. + * @returns {import('input').Modifier[]} An array of modifiers and buttons. + */ +export function getActiveModifiersAndButtons(event) { +    /** @type {import('input').Modifier[]} */ +    const modifiers = getActiveModifiers(event); +    if (event instanceof MouseEvent) { +        getActiveButtonsInternal(event, modifiers);      } +    return modifiers; +} -    /** -     * Gets an array of the active buttons. -     * @param {MouseEvent} event The event to check. -     * @returns {import('input').ModifierMouseButton[]} An array of modifiers and buttons. -     */ -    static getActiveButtons(event) { -        /** @type {import('input').ModifierMouseButton[]} */ -        const buttons = []; -        this._getActiveButtons(event, buttons); -        return buttons; -    } +/** + * Gets an array of the active buttons. + * @param {MouseEvent} event The event to check. + * @returns {import('input').ModifierMouseButton[]} An array of modifiers and buttons. + */ +export function getActiveButtons(event) { +    /** @type {import('input').ModifierMouseButton[]} */ +    const buttons = []; +    getActiveButtonsInternal(event, buttons); +    return buttons; +} -    /** -     * Adds a fullscreen change event listener. This function handles all of the browser-specific variants. -     * @param {EventListener} onFullscreenChanged The event callback. -     * @param {?import('../core/event-listener-collection.js').EventListenerCollection} eventListenerCollection An optional `EventListenerCollection` to add the registration to. -     */ -    static addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection = null) { -        const target = document; -        const options = false; -        const fullscreenEventNames = [ -            'fullscreenchange', -            'MSFullscreenChange', -            'mozfullscreenchange', -            'webkitfullscreenchange' -        ]; -        for (const eventName of fullscreenEventNames) { -            if (eventListenerCollection === null) { -                target.addEventListener(eventName, onFullscreenChanged, options); -            } else { -                eventListenerCollection.addEventListener(target, eventName, onFullscreenChanged, options); -            } +/** + * Adds a fullscreen change event listener. This function handles all of the browser-specific variants. + * @param {EventListener} onFullscreenChanged The event callback. + * @param {?import('../core/event-listener-collection.js').EventListenerCollection} eventListenerCollection An optional `EventListenerCollection` to add the registration to. + */ +export function addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection = null) { +    const target = document; +    const options = false; +    const fullscreenEventNames = [ +        'fullscreenchange', +        'MSFullscreenChange', +        'mozfullscreenchange', +        'webkitfullscreenchange' +    ]; +    for (const eventName of fullscreenEventNames) { +        if (eventListenerCollection === null) { +            target.addEventListener(eventName, onFullscreenChanged, options); +        } else { +            eventListenerCollection.addEventListener(target, eventName, onFullscreenChanged, options);          }      } +} -    /** -     * Returns the current fullscreen element. This function handles all of the browser-specific variants. -     * @returns {?Element} The current fullscreen element, or `null` if the window is not fullscreen. -     */ -    static getFullscreenElement() { -        return ( -            document.fullscreenElement || -            // @ts-expect-error - vendor prefix -            document.msFullscreenElement || -            // @ts-expect-error - vendor prefix -            document.mozFullScreenElement || -            // @ts-expect-error - vendor prefix -            document.webkitFullscreenElement || -            null -        ); -    } +/** + * Returns the current fullscreen element. This function handles all of the browser-specific variants. + * @returns {?Element} The current fullscreen element, or `null` if the window is not fullscreen. + */ +export function getFullscreenElement() { +    return ( +        document.fullscreenElement || +        // @ts-expect-error - vendor prefix +        document.msFullscreenElement || +        // @ts-expect-error - vendor prefix +        document.mozFullScreenElement || +        // @ts-expect-error - vendor prefix +        document.webkitFullscreenElement || +        null +    ); +} -    /** -     * Gets all of the nodes within a `Range`. -     * @param {Range} range The range to check. -     * @returns {Node[]} The list of nodes. -     */ -    static getNodesInRange(range) { -        const end = range.endContainer; -        const nodes = []; -        for (let node = /** @type {?Node} */ (range.startContainer); node !== null; node = this.getNextNode(node)) { -            nodes.push(node); -            if (node === end) { break; } -        } -        return nodes; +/** + * Gets all of the nodes within a `Range`. + * @param {Range} range The range to check. + * @returns {Node[]} The list of nodes. + */ +export function getNodesInRange(range) { +    const end = range.endContainer; +    const nodes = []; +    for (let node = /** @type {?Node} */ (range.startContainer); node !== null; node = getNextNode(node)) { +        nodes.push(node); +        if (node === end) { break; }      } +    return nodes; +} -    /** -     * Gets the next node after a specified node. This traverses the DOM in its logical order. -     * @param {Node} node The node to start at. -     * @returns {?Node} The next node, or `null` if there is no next node. -     */ -    static getNextNode(node) { -        let next = /** @type {?Node} */ (node.firstChild); -        if (next === null) { -            while (true) { -                next = node.nextSibling; -                if (next !== null) { break; } +/** + * Gets the next node after a specified node. This traverses the DOM in its logical order. + * @param {Node} node The node to start at. + * @returns {?Node} The next node, or `null` if there is no next node. + */ +export function getNextNode(node) { +    let next = /** @type {?Node} */ (node.firstChild); +    if (next === null) { +        while (true) { +            next = node.nextSibling; +            if (next !== null) { break; } -                next = node.parentNode; -                if (next === null) { break; } +            next = node.parentNode; +            if (next === null) { break; } -                node = next; -            } +            node = next;          } -        return next;      } +    return next; +} -    /** -     * Checks whether any node in a list of nodes matches a selector. -     * @param {Node[]} nodes The list of ndoes to check. -     * @param {string} selector The selector to test. -     * @returns {boolean} `true` if any element node matches the selector, `false` otherwise. -     */ -    static anyNodeMatchesSelector(nodes, selector) { -        const ELEMENT_NODE = Node.ELEMENT_NODE; -        // This is a rather ugly way of getting the "node" variable to be a nullable -        for (let node of /** @type {(?Node)[]} */ (nodes)) { -            while (node !== null) { -                if (node.nodeType !== ELEMENT_NODE) { -                    node = node.parentNode; -                    continue; -                } -                if (/** @type {HTMLElement} */ (node).matches(selector)) { return true; } -                break; +/** + * Checks whether any node in a list of nodes matches a selector. + * @param {Node[]} nodes The list of ndoes to check. + * @param {string} selector The selector to test. + * @returns {boolean} `true` if any element node matches the selector, `false` otherwise. + */ +export function anyNodeMatchesSelector(nodes, selector) { +    const ELEMENT_NODE = Node.ELEMENT_NODE; +    // This is a rather ugly way of getting the "node" variable to be a nullable +    for (let node of /** @type {(?Node)[]} */ (nodes)) { +        while (node !== null) { +            if (node.nodeType !== ELEMENT_NODE) { +                node = node.parentNode; +                continue;              } +            if (/** @type {HTMLElement} */ (node).matches(selector)) { return true; } +            break;          } -        return false;      } +    return false; +} -    /** -     * Checks whether every node in a list of nodes matches a selector. -     * @param {Node[]} nodes The list of ndoes to check. -     * @param {string} selector The selector to test. -     * @returns {boolean} `true` if every element node matches the selector, `false` otherwise. -     */ -    static everyNodeMatchesSelector(nodes, selector) { -        const ELEMENT_NODE = Node.ELEMENT_NODE; -        // This is a rather ugly way of getting the "node" variable to be a nullable -        for (let node of /** @type {(?Node)[]} */ (nodes)) { -            while (true) { -                if (node === null) { return false; } -                if (node.nodeType === ELEMENT_NODE && /** @type {HTMLElement} */ (node).matches(selector)) { break; } -                node = node.parentNode; -            } +/** + * Checks whether every node in a list of nodes matches a selector. + * @param {Node[]} nodes The list of ndoes to check. + * @param {string} selector The selector to test. + * @returns {boolean} `true` if every element node matches the selector, `false` otherwise. + */ +export function everyNodeMatchesSelector(nodes, selector) { +    const ELEMENT_NODE = Node.ELEMENT_NODE; +    // This is a rather ugly way of getting the "node" variable to be a nullable +    for (let node of /** @type {(?Node)[]} */ (nodes)) { +        while (true) { +            if (node === null) { return false; } +            if (node.nodeType === ELEMENT_NODE && /** @type {HTMLElement} */ (node).matches(selector)) { break; } +            node = node.parentNode;          } -        return true;      } +    return true; +} -    /** -     * Checks whether the meta key is supported in the browser on the specified operating system. -     * @param {string} os The operating system to check. -     * @param {string} browser The browser to check. -     * @returns {boolean} `true` if supported, `false` otherwise. -     */ -    static isMetaKeySupported(os, browser) { -        return !(browser === 'firefox' || browser === 'firefox-mobile') || os === 'mac'; -    } +/** + * Checks whether the meta key is supported in the browser on the specified operating system. + * @param {string} os The operating system to check. + * @param {string} browser The browser to check. + * @returns {boolean} `true` if supported, `false` otherwise. + */ +export function isMetaKeySupported(os, browser) { +    return !(browser === 'firefox' || browser === 'firefox-mobile') || os === 'mac'; +} -    /** -     * Checks whether an element on the page that can accept input is focused. -     * @returns {boolean} `true` if an input element is focused, `false` otherwise. -     */ -    static isInputElementFocused() { -        const element = document.activeElement; -        if (element === null) { return false; } -        const type = element.nodeName.toUpperCase(); -        switch (type) { -            case 'INPUT': -            case 'TEXTAREA': -            case 'SELECT': -                return true; -            default: -                return element instanceof HTMLElement && element.isContentEditable; -        } +/** + * Checks whether an element on the page that can accept input is focused. + * @returns {boolean} `true` if an input element is focused, `false` otherwise. + */ +export function isInputElementFocused() { +    const element = document.activeElement; +    if (element === null) { return false; } +    const type = element.nodeName.toUpperCase(); +    switch (type) { +        case 'INPUT': +        case 'TEXTAREA': +        case 'SELECT': +            return true; +        default: +            return element instanceof HTMLElement && element.isContentEditable;      } +} -    /** -     * Offsets an array of DOMRects by a given amount. -     * @param {DOMRect[]} rects The DOMRects to offset. -     * @param {number} x The horizontal offset amount. -     * @param {number} y The vertical offset amount. -     * @returns {DOMRect[]} The DOMRects with the offset applied. -     */ -    static offsetDOMRects(rects, x, y) { -        const results = []; -        for (const rect of rects) { -            results.push(new DOMRect(rect.left + x, rect.top + y, rect.width, rect.height)); -        } -        return results; +/** + * Offsets an array of DOMRects by a given amount. + * @param {DOMRect[]} rects The DOMRects to offset. + * @param {number} x The horizontal offset amount. + * @param {number} y The vertical offset amount. + * @returns {DOMRect[]} The DOMRects with the offset applied. + */ +export function offsetDOMRects(rects, x, y) { +    const results = []; +    for (const rect of rects) { +        results.push(new DOMRect(rect.left + x, rect.top + y, rect.width, rect.height));      } +    return results; +} -    /** -     * Gets the parent writing mode of an element. -     * See: https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode. -     * @param {?Element} element The HTML element to check. -     * @returns {import('document-util').NormalizedWritingMode} The writing mode. -     */ -    static getElementWritingMode(element) { -        if (element !== null) { -            const {writingMode} = getComputedStyle(element); -            if (typeof writingMode === 'string') { -                return this.normalizeWritingMode(writingMode); -            } +/** + * Gets the parent writing mode of an element. + * See: https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode. + * @param {?Element} element The HTML element to check. + * @returns {import('document-util').NormalizedWritingMode} The writing mode. + */ +export function getElementWritingMode(element) { +    if (element !== null) { +        const {writingMode} = getComputedStyle(element); +        if (typeof writingMode === 'string') { +            return normalizeWritingMode(writingMode);          } -        return 'horizontal-tb';      } +    return 'horizontal-tb'; +} -    /** -     * Normalizes a CSS writing mode value by converting non-standard and deprecated values -     * into their corresponding standard vaules. -     * @param {string} writingMode The writing mode to normalize. -     * @returns {import('document-util').NormalizedWritingMode} The normalized writing mode. -     */ -    static normalizeWritingMode(writingMode) { -        switch (writingMode) { -            case 'tb': -                return 'vertical-lr'; -            case 'tb-rl': -                return 'vertical-rl'; -            case 'horizontal-tb': -            case 'vertical-rl': -            case 'vertical-lr': -            case 'sideways-rl': -            case 'sideways-lr': -                return writingMode; -            default: // 'lr', 'lr-tb', 'rl' -                return 'horizontal-tb'; -        } +/** + * Normalizes a CSS writing mode value by converting non-standard and deprecated values + * into their corresponding standard vaules. + * @param {string} writingMode The writing mode to normalize. + * @returns {import('document-util').NormalizedWritingMode} The normalized writing mode. + */ +export function normalizeWritingMode(writingMode) { +    switch (writingMode) { +        case 'tb': +            return 'vertical-lr'; +        case 'tb-rl': +            return 'vertical-rl'; +        case 'horizontal-tb': +        case 'vertical-rl': +        case 'vertical-lr': +        case 'sideways-rl': +        case 'sideways-lr': +            return writingMode; +        default: // 'lr', 'lr-tb', 'rl' +            return 'horizontal-tb';      } +} -    /** -     * Converts a value from an element to a number. -     * @param {string} valueString A string representation of a number. -     * @param {import('document-util').ToNumberConstraints} constraints An object which might contain `min`, `max`, and `step` fields which are used to constrain the value. -     * @returns {number} The parsed and constrained number. -     */ -    static convertElementValueToNumber(valueString, constraints) { -        let value = Number.parseFloat(valueString); -        if (!Number.isFinite(value)) { value = 0; } +/** + * Converts a value from an element to a number. + * @param {string} valueString A string representation of a number. + * @param {import('document-util').ToNumberConstraints} constraints An object which might contain `min`, `max`, and `step` fields which are used to constrain the value. + * @returns {number} The parsed and constrained number. + */ +export function convertElementValueToNumber(valueString, constraints) { +    let value = Number.parseFloat(valueString); +    if (!Number.isFinite(value)) { value = 0; } -        const min = this._convertToNumberOrNull(constraints.min); -        const max = this._convertToNumberOrNull(constraints.max); -        const step = this._convertToNumberOrNull(constraints.step); -        if (typeof min === 'number') { value = Math.max(value, min); } -        if (typeof max === 'number') { value = Math.min(value, max); } -        if (typeof step === 'number' && step !== 0) { value = Math.round(value / step) * step; } -        return value; -    } +    const min = convertToNumberOrNull(constraints.min); +    const max = convertToNumberOrNull(constraints.max); +    const step = convertToNumberOrNull(constraints.step); +    if (typeof min === 'number') { value = Math.max(value, min); } +    if (typeof max === 'number') { value = Math.min(value, max); } +    if (typeof step === 'number' && step !== 0) { value = Math.round(value / step) * step; } +    return value; +} -    /** -     * @param {string} value -     * @returns {?import('input').Modifier} -     */ -    static normalizeModifier(value) { -        switch (value) { -            case 'alt': -            case 'ctrl': -            case 'meta': -            case 'shift': -            case 'mouse0': -            case 'mouse1': -            case 'mouse2': -            case 'mouse3': -            case 'mouse4': -            case 'mouse5': -                return value; -            default: -                return null; -        } +/** + * @param {string} value + * @returns {?import('input').Modifier} + */ +export function normalizeModifier(value) { +    switch (value) { +        case 'alt': +        case 'ctrl': +        case 'meta': +        case 'shift': +        case 'mouse0': +        case 'mouse1': +        case 'mouse2': +        case 'mouse3': +        case 'mouse4': +        case 'mouse5': +            return value; +        default: +            return null;      } +} -    /** -     * @param {string} value -     * @returns {?import('input').ModifierKey} -     */ -    static normalizeModifierKey(value) { -        switch (value) { -            case 'alt': -            case 'ctrl': -            case 'meta': -            case 'shift': -                return value; -            default: -                return null; -        } +/** + * @param {string} value + * @returns {?import('input').ModifierKey} + */ +export function normalizeModifierKey(value) { +    switch (value) { +        case 'alt': +        case 'ctrl': +        case 'meta': +        case 'shift': +            return value; +        default: +            return null;      } +} -    /** -     * @param {MouseEvent} event The event to check. -     * @param {import('input').ModifierMouseButton[]|import('input').Modifier[]} array -     */ -    static _getActiveButtons(event, array) { -        let {buttons} = event; -        if (typeof buttons === 'number' && buttons > 0) { -            for (let i = 0; i < 6; ++i) { -                const buttonFlag = (1 << i); -                if ((buttons & buttonFlag) !== 0) { -                    array.push(/** @type {import('input').ModifierMouseButton} */ (`mouse${i}`)); -                    buttons &= ~buttonFlag; -                    if (buttons === 0) { break; } -                } +/** + * @param {MouseEvent} event The event to check. + * @param {import('input').ModifierMouseButton[]|import('input').Modifier[]} array + */ +function getActiveButtonsInternal(event, array) { +    let {buttons} = event; +    if (typeof buttons === 'number' && buttons > 0) { +        for (let i = 0; i < 6; ++i) { +            const buttonFlag = (1 << i); +            if ((buttons & buttonFlag) !== 0) { +                array.push(/** @type {import('input').ModifierMouseButton} */ (`mouse${i}`)); +                buttons &= ~buttonFlag; +                if (buttons === 0) { break; }              }          }      } +} -    /** -     * @param {string|number|undefined} value -     * @returns {?number} -     */ -    static _convertToNumberOrNull(value) { -        if (typeof value !== 'number') { -            if (typeof value !== 'string' || value.length === 0) { -                return null; -            } -            value = Number.parseFloat(value); +/** + * @param {string|number|undefined} value + * @returns {?number} + */ +function convertToNumberOrNull(value) { +    if (typeof value !== 'number') { +        if (typeof value !== 'string' || value.length === 0) { +            return null;          } -        return !Number.isNaN(value) ? value : null; +        value = Number.parseFloat(value);      } +    return !Number.isNaN(value) ? value : null; +} -    /** -     * Computes whether or not this browser and document supports CSS zoom, which is primarily a legacy Chromium feature. -     * @returns {boolean} -     */ -    static _computeCssZoomSupported() { -        // 'style' can be undefined in certain contexts, such as when document is an SVG document. -        const {style} = document.createElement('div'); +/** + * Computes whether or not this browser and document supports CSS zoom, which is primarily a legacy Chromium feature. + * @returns {boolean} + */ +function computeCssZoomSupported() { +    // 'style' can be undefined in certain contexts, such as when document is an SVG document. +    const {style} = document.createElement('div'); +    return ( +        typeof style === 'object' && +        style !== null &&          // @ts-expect-error - zoom is a non-standard property. -        return (typeof style === 'object' && style !== null && typeof style.zoom === 'string'); -    } +        typeof style.zoom === 'string' +    );  } diff --git a/ext/js/dom/dom-data-binder.js b/ext/js/dom/dom-data-binder.js index 7523e434..be5633d7 100644 --- a/ext/js/dom/dom-data-binder.js +++ b/ext/js/dom/dom-data-binder.js @@ -17,7 +17,7 @@   */  import {TaskAccumulator} from '../general/task-accumulator.js'; -import {DocumentUtil} from './document-util.js'; +import {convertElementValueToNumber} from './document-util.js';  import {SelectorObserver} from './selector-observer.js';  /** @@ -264,7 +264,7 @@ export class DOMDataBinder {              case 'text':                  return `${/** @type {HTMLInputElement} */ (element).value}`;              case 'number': -                return DocumentUtil.convertElementValueToNumber(/** @type {HTMLInputElement} */ (element).value, /** @type {HTMLInputElement} */ (element)); +                return convertElementValueToNumber(/** @type {HTMLInputElement} */ (element).value, /** @type {HTMLInputElement} */ (element));              case 'textarea':                  return /** @type {HTMLTextAreaElement} */ (element).value;              case 'select': diff --git a/ext/js/dom/text-source-element.js b/ext/js/dom/text-source-element.js index 927783d1..b2829e75 100644 --- a/ext/js/dom/text-source-element.js +++ b/ext/js/dom/text-source-element.js @@ -17,7 +17,7 @@   */  import {readCodePointsBackward, readCodePointsForward} from '../data/sandbox/string-util.js'; -import {DocumentUtil} from './document-util.js'; +import {convertMultipleRectZoomCoordinates} from './document-util.js';  /**   * This class represents a text source that is attached to a HTML element, such as an <img> @@ -145,7 +145,7 @@ export class TextSourceElement {       * @returns {DOMRect[]} The rects.       */      getRects() { -        return DocumentUtil.convertMultipleRectZoomCoordinates(this._element.getClientRects(), this._element); +        return convertMultipleRectZoomCoordinates(this._element.getClientRects(), this._element);      }      /** diff --git a/ext/js/dom/text-source-generator.js b/ext/js/dom/text-source-generator.js index 83c7271c..68bf036a 100644 --- a/ext/js/dom/text-source-generator.js +++ b/ext/js/dom/text-source-generator.js @@ -15,7 +15,7 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -import {DocumentUtil} from './document-util.js'; +import {computeZoomScale, isPointInAnyRect} from './document-util.js';  import {DOMTextScanner} from './dom-text-scanner.js';  import {TextSourceElement} from './text-source-element.js';  import {TextSourceRange} from './text-source-range.js'; @@ -358,7 +358,7 @@ export class TextSourceGenerator {          // Convert CSS zoom coordinates          if (normalizeCssZoom) { -            const scale = DocumentUtil.computeZoomScale(startContainer); +            const scale = computeZoomScale(startContainer);              x /= scale;              y /= scale;          } @@ -370,7 +370,7 @@ export class TextSourceGenerator {              const {node, offset, content} = new DOMTextScanner(nodePre, offsetPre, true, false).seek(1);              range.setEnd(node, offset); -            if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) { +            if (!this._isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) {                  return true;              }          } finally { @@ -381,7 +381,7 @@ export class TextSourceGenerator {          const {node, offset, content} = new DOMTextScanner(startContainer, range.startOffset, true, false).seek(-1);          range.setStart(node, offset); -        if (!this._isWhitespace(content) && DocumentUtil.isPointInAnyRect(x, y, range.getClientRects())) { +        if (!this._isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) {              // This purposefully leaves the starting offset as modified and sets the range length to 0.              range.setEnd(node, offset);              return true; diff --git a/ext/js/dom/text-source-range.js b/ext/js/dom/text-source-range.js index 05e7b6fb..2012af7a 100644 --- a/ext/js/dom/text-source-range.js +++ b/ext/js/dom/text-source-range.js @@ -17,7 +17,7 @@   */  import {toError} from '../core/to-error.js'; -import {DocumentUtil} from './document-util.js'; +import {convertMultipleRectZoomCoordinates, convertRectZoomCoordinates, getElementWritingMode, getNodesInRange, offsetDOMRects} from './document-util.js';  import {DOMTextScanner} from './dom-text-scanner.js';  /** @@ -170,7 +170,7 @@ export class TextSourceRange {       */      getRects() {          if (this._isImposterDisconnected()) { return this._getCachedRects(); } -        return DocumentUtil.convertMultipleRectZoomCoordinates(this._range.getClientRects(), this._range.startContainer); +        return convertMultipleRectZoomCoordinates(this._range.getClientRects(), this._range.startContainer);      }      /** @@ -181,7 +181,7 @@ export class TextSourceRange {      getWritingMode() {          let node = this._isImposterDisconnected() ? this._imposterSourceElement : this._range.startContainer;          if (node !== null && node.nodeType !== Node.ELEMENT_NODE) { node = node.parentElement; } -        return DocumentUtil.getElementWritingMode(/** @type {?Element} */ (node)); +        return getElementWritingMode(/** @type {?Element} */ (node));      }      /** @@ -243,7 +243,7 @@ export class TextSourceRange {       * @returns {Node[]} The nodes in the range.       */      getNodesInRange() { -        return DocumentUtil.getNodesInRange(this._range); +        return getNodesInRange(this._range);      }      /** @@ -263,8 +263,8 @@ export class TextSourceRange {       * @returns {TextSourceRange} A new instance of the class corresponding to the range.       */      static createFromImposter(range, imposterElement, imposterSourceElement) { -        const cachedRects = DocumentUtil.convertMultipleRectZoomCoordinates(range.getClientRects(), range.startContainer); -        const cachedSourceRect = DocumentUtil.convertRectZoomCoordinates(imposterSourceElement.getBoundingClientRect(), imposterSourceElement); +        const cachedRects = convertMultipleRectZoomCoordinates(range.getClientRects(), range.startContainer); +        const cachedSourceRect = convertRectZoomCoordinates(imposterSourceElement.getBoundingClientRect(), imposterSourceElement);          return new TextSourceRange(range, range.startOffset, range.toString(), imposterElement, imposterSourceElement, cachedRects, cachedSourceRect);      } @@ -289,8 +289,8 @@ export class TextSourceRange {          ) {              throw new Error('Cached rects not valid for this instance');          } -        const sourceRect = DocumentUtil.convertRectZoomCoordinates(this._imposterSourceElement.getBoundingClientRect(), this._imposterSourceElement); -        return DocumentUtil.offsetDOMRects( +        const sourceRect = convertRectZoomCoordinates(this._imposterSourceElement.getBoundingClientRect(), this._imposterSourceElement); +        return offsetDOMRects(              this._cachedRects,              sourceRect.left - this._cachedSourceRect.left,              sourceRect.top - this._cachedSourceRect.top diff --git a/ext/js/input/hotkey-handler.js b/ext/js/input/hotkey-handler.js index 6d7d3d7a..818c0155 100644 --- a/ext/js/input/hotkey-handler.js +++ b/ext/js/input/hotkey-handler.js @@ -18,7 +18,7 @@  import {EventDispatcher} from '../core/event-dispatcher.js';  import {EventListenerCollection} from '../core/event-listener-collection.js'; -import {DocumentUtil} from '../dom/document-util.js'; +import {getActiveModifiers, isInputElementFocused} from '../dom/document-util.js';  /**   * Class which handles hotkey events and actions. @@ -173,7 +173,7 @@ export class HotkeyHandler extends EventDispatcher {      _onKeyDown(event) {          const hotkeyInfo = this._hotkeys.get(event.code);          if (typeof hotkeyInfo !== 'undefined') { -            const eventModifiers = DocumentUtil.getActiveModifiers(event); +            const eventModifiers = getActiveModifiers(event);              if (this._invokeHandlers(eventModifiers, hotkeyInfo, event.key)) {                  event.preventDefault();                  return; @@ -269,7 +269,7 @@ export class HotkeyHandler extends EventDispatcher {      _isHotkeyPermitted(modifiers, key) {          return !(              (modifiers.length === 0 || (modifiers.length === 1 && modifiers[0] === 'shift')) && -            DocumentUtil.isInputElementFocused() && +            isInputElementFocused() &&              this._isKeyCharacterInput(key)          );      } diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index 697e2b4d..d4caa643 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -20,7 +20,7 @@ import {EventDispatcher} from '../core/event-dispatcher.js';  import {EventListenerCollection} from '../core/event-listener-collection.js';  import {log} from '../core/log.js';  import {clone} from '../core/utilities.js'; -import {DocumentUtil} from '../dom/document-util.js'; +import {anyNodeMatchesSelector, everyNodeMatchesSelector, getActiveModifiers, getActiveModifiersAndButtons, isPointInSelection} from '../dom/document-util.js';  import {TextSourceElement} from '../dom/text-source-element.js';  /** @@ -609,8 +609,8 @@ export class TextScanner extends EventDispatcher {          if (preventNextClickScan) { return; } -        const modifiers = DocumentUtil.getActiveModifiersAndButtons(e); -        const modifierKeys = DocumentUtil.getActiveModifiers(e); +        const modifiers = getActiveModifiersAndButtons(e); +        const modifierKeys = getActiveModifiers(e);          const inputInfo = this._createInputInfo(null, 'mouse', 'click', false, modifiers, modifierKeys);          this._searchAt(e.clientX, e.clientY, inputInfo);      } @@ -658,7 +658,7 @@ export class TextScanner extends EventDispatcher {          this._preventNextClick = false;          const selection = window.getSelection(); -        if (selection !== null && DocumentUtil.isPointInSelection(x, y, selection)) { +        if (selection !== null && isPointInSelection(x, y, selection)) {              return;          } @@ -1393,8 +1393,8 @@ export class TextScanner extends EventDispatcher {       * @returns {?import('text-scanner').InputInfo}       */      _getMatchingInputGroupFromEvent(pointerType, eventType, event) { -        const modifiers = DocumentUtil.getActiveModifiersAndButtons(event); -        const modifierKeys = DocumentUtil.getActiveModifiers(event); +        const modifiers = getActiveModifiersAndButtons(event); +        const modifierKeys = getActiveModifiers(event);          return this._getMatchingInputGroup(pointerType, eventType, modifiers, modifierKeys);      } @@ -1534,8 +1534,8 @@ export class TextScanner extends EventDispatcher {          while (length > 0) {              const nodes = textSource.getNodesInRange();              if ( -                (includeSelector !== null && !DocumentUtil.everyNodeMatchesSelector(nodes, includeSelector)) || -                (excludeSelector !== null && DocumentUtil.anyNodeMatchesSelector(nodes, excludeSelector)) +                (includeSelector !== null && !everyNodeMatchesSelector(nodes, includeSelector)) || +                (excludeSelector !== null && anyNodeMatchesSelector(nodes, excludeSelector))              ) {                  --length;                  textSource.setEndOffset(length, false, layoutAwareScan); diff --git a/ext/js/pages/settings/generic-setting-controller.js b/ext/js/pages/settings/generic-setting-controller.js index 12db2ab7..7c082a96 100644 --- a/ext/js/pages/settings/generic-setting-controller.js +++ b/ext/js/pages/settings/generic-setting-controller.js @@ -18,7 +18,7 @@  import {ExtensionError} from '../../core/extension-error.js';  import {parseJson} from '../../core/json.js'; -import {DocumentUtil} from '../../dom/document-util.js'; +import {convertElementValueToNumber} from '../../dom/document-util.js';  import {DOMDataBinder} from '../../dom/dom-data-binder.js';  export class GenericSettingController { @@ -328,7 +328,7 @@ export class GenericSettingController {      _toNumber(value, data) {          /** @type {import('document-util').ToNumberConstraints} */          const constraints = typeof data.constraints === 'object' && data.constraints !== null ? data.constraints : {}; -        return typeof value === 'string' ? DocumentUtil.convertElementValueToNumber(value, constraints) : 0; +        return typeof value === 'string' ? convertElementValueToNumber(value, constraints) : 0;      }      /** diff --git a/ext/js/pages/settings/keyboard-mouse-input-field.js b/ext/js/pages/settings/keyboard-mouse-input-field.js index 310cbb19..0c45d4bb 100644 --- a/ext/js/pages/settings/keyboard-mouse-input-field.js +++ b/ext/js/pages/settings/keyboard-mouse-input-field.js @@ -18,7 +18,7 @@  import {EventDispatcher} from '../../core/event-dispatcher.js';  import {EventListenerCollection} from '../../core/event-listener-collection.js'; -import {DocumentUtil} from '../../dom/document-util.js'; +import {getActiveButtons, getActiveModifiers} from '../../dom/document-util.js';  import {HotkeyUtil} from '../../input/hotkey-util.js';  /** @@ -139,7 +139,7 @@ export class KeyboardMouseInputField extends EventDispatcher {       * @returns {Set<import('input').ModifierKey>}       */      _getModifierKeys(e) { -        const modifiers = new Set(DocumentUtil.getActiveModifiers(e)); +        const modifiers = new Set(getActiveModifiers(e));          // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey          // https://askubuntu.com/questions/567731/why-is-shift-alt-being-mapped-to-meta          // It works with mouse events on some platforms, so try to determine if metaKey is pressed. @@ -216,7 +216,7 @@ export class KeyboardMouseInputField extends EventDispatcher {       */      _onMouseButtonMouseDown(e) {          e.preventDefault(); -        this._addModifiers(DocumentUtil.getActiveButtons(e)); +        this._addModifiers(getActiveButtons(e));      }      /** @@ -236,7 +236,7 @@ export class KeyboardMouseInputField extends EventDispatcher {              return;          }          e.preventDefault(); -        this._addModifiers(DocumentUtil.getActiveButtons(e)); +        this._addModifiers(getActiveButtons(e));      }      /** diff --git a/ext/js/pages/settings/keyboard-shortcuts-controller.js b/ext/js/pages/settings/keyboard-shortcuts-controller.js index 907cf4a1..0a01b836 100644 --- a/ext/js/pages/settings/keyboard-shortcuts-controller.js +++ b/ext/js/pages/settings/keyboard-shortcuts-controller.js @@ -17,7 +17,7 @@   */  import {EventListenerCollection} from '../../core/event-listener-collection.js'; -import {DocumentUtil} from '../../dom/document-util.js'; +import {convertElementValueToNumber, normalizeModifierKey} from '../../dom/document-util.js';  import {querySelectorNotNull} from '../../dom/query-selector.js';  import {ObjectPropertyAccessor} from '../../general/object-property-accessor.js';  import {KeyboardMouseInputField} from './keyboard-mouse-input-field.js'; @@ -400,7 +400,7 @@ class KeyboardShortcutHotkeyEntry {          /** @type {import('input').ModifierKey[]} */          const modifiers2 = [];          for (const modifier of modifiers) { -            const modifier2 = DocumentUtil.normalizeModifierKey(modifier); +            const modifier2 = normalizeModifierKey(modifier);              if (modifier2 === null) { continue; }              modifiers2.push(modifier2);          } @@ -435,7 +435,7 @@ class KeyboardShortcutHotkeyEntry {          let value = this._getArgumentInputValue(node);          switch (template) {              case 'hotkey-argument-move-offset': -                value = `${DocumentUtil.convertElementValueToNumber(value, node)}`; +                value = `${convertElementValueToNumber(value, node)}`;                  break;          }          this._setArgument(value); diff --git a/ext/js/pages/settings/nested-popups-controller.js b/ext/js/pages/settings/nested-popups-controller.js index ccdc3c9c..077b1a66 100644 --- a/ext/js/pages/settings/nested-popups-controller.js +++ b/ext/js/pages/settings/nested-popups-controller.js @@ -16,7 +16,7 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -import {DocumentUtil} from '../../dom/document-util.js'; +import {convertElementValueToNumber} from '../../dom/document-util.js';  import {querySelectorNotNull} from '../../dom/query-selector.js';  export class NestedPopupsController { @@ -71,7 +71,7 @@ export class NestedPopupsController {       */      _onNestedPopupsCountChange(e) {          const node = /** @type {HTMLInputElement} */ (e.currentTarget); -        const value = Math.max(1, DocumentUtil.convertElementValueToNumber(node.value, node)); +        const value = Math.max(1, convertElementValueToNumber(node.value, node));          this._setPopupNestingMaxDepth(value);      } diff --git a/ext/js/pages/settings/profile-conditions-ui.js b/ext/js/pages/settings/profile-conditions-ui.js index 5801af17..d2bf03bf 100644 --- a/ext/js/pages/settings/profile-conditions-ui.js +++ b/ext/js/pages/settings/profile-conditions-ui.js @@ -18,7 +18,7 @@  import {EventDispatcher} from '../../core/event-dispatcher.js';  import {EventListenerCollection} from '../../core/event-listener-collection.js'; -import {DocumentUtil} from '../../dom/document-util.js'; +import {normalizeModifier} from '../../dom/document-util.js';  import {querySelectorNotNull} from '../../dom/query-selector.js';  import {KeyboardMouseInputField} from './keyboard-mouse-input-field.js'; @@ -941,7 +941,7 @@ class ProfileConditionUI {          /** @type {import('input').Modifier[]} */          const results = [];          for (const item of modifiersString.split(/[,;\s]+/)) { -            const modifier = DocumentUtil.normalizeModifier(item.trim().toLowerCase()); +            const modifier = normalizeModifier(item.trim().toLowerCase());              if (modifier !== null) { results.push(modifier); }          }          return results; diff --git a/ext/js/pages/settings/scan-inputs-controller.js b/ext/js/pages/settings/scan-inputs-controller.js index f1547fe4..144eae9f 100644 --- a/ext/js/pages/settings/scan-inputs-controller.js +++ b/ext/js/pages/settings/scan-inputs-controller.js @@ -17,7 +17,7 @@   */  import {EventListenerCollection} from '../../core/event-listener-collection.js'; -import {DocumentUtil} from '../../dom/document-util.js'; +import {normalizeModifier} from '../../dom/document-util.js';  import {querySelectorNotNull} from '../../dom/query-selector.js';  import {KeyboardMouseInputField} from './keyboard-mouse-input-field.js'; @@ -417,7 +417,7 @@ class ScanInputField {          /** @type {import('input').Modifier[]} */          const results = [];          for (const modifier of modifiersString.split(/[,;\s]+/)) { -            const modifier2 = DocumentUtil.normalizeModifier(modifier.trim().toLowerCase()); +            const modifier2 = normalizeModifier(modifier.trim().toLowerCase());              if (modifier2 === null) { continue; }              results.push(modifier2);          } diff --git a/ext/js/pages/settings/settings-display-controller.js b/ext/js/pages/settings/settings-display-controller.js index 47aa9c9c..6e740e13 100644 --- a/ext/js/pages/settings/settings-display-controller.js +++ b/ext/js/pages/settings/settings-display-controller.js @@ -16,7 +16,7 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -import {DocumentUtil} from '../../dom/document-util.js'; +import {isInputElementFocused} from '../../dom/document-util.js';  import {PopupMenu} from '../../dom/popup-menu.js';  import {querySelectorNotNull} from '../../dom/query-selector.js';  import {SelectorObserver} from '../../dom/selector-observer.js'; @@ -184,7 +184,7 @@ export class SettingsDisplayController {      _onKeyDown(e) {          switch (e.code) {              case 'Escape': -                if (!DocumentUtil.isInputElementFocused()) { +                if (!isInputElementFocused()) {                      this._closeTopMenuOrModal();                      e.preventDefault();                  } |