diff options
-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(); } |