From be7855bad2e3b452ca0700246a376f107a75e79e Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 26 Sep 2022 19:37:14 -0400 Subject: More API documentation (#2238) * Document TextSourceRange * Document TextSourceElement * Document DocumentUtil * Document DocumentFocusController --- ext/js/dom/document-focus-controller.js | 12 ++++ ext/js/dom/document-util.js | 92 ++++++++++++++++++++++++++ ext/js/dom/text-source-element.js | 88 +++++++++++++++++++++++++ ext/js/dom/text-source-range.js | 110 ++++++++++++++++++++++++++++++++ 4 files changed, 302 insertions(+) (limited to 'ext/js/dom') diff --git a/ext/js/dom/document-focus-controller.js b/ext/js/dom/document-focus-controller.js index bc6c61b9..d6c24646 100644 --- a/ext/js/dom/document-focus-controller.js +++ b/ext/js/dom/document-focus-controller.js @@ -22,11 +22,19 @@ * focus a dummy element inside the main content, which gives keyboard scroll focus to that element. */ class DocumentFocusController { + /** + * Creates a new instance of the class. + * @param {?string} autofocusElementSelector A selector string which can be used to specify an element which + * should be automatically focused on prepare. + */ constructor(autofocusElementSelector=null) { this._autofocusElement = (autofocusElementSelector !== null ? document.querySelector(autofocusElementSelector) : null); this._contentScrollFocusElement = document.querySelector('#content-scroll-focus'); } + /** + * Initializes the instance. + */ prepare() { window.addEventListener('focus', this._onWindowFocus.bind(this), false); this._updateFocusedElement(false); @@ -35,6 +43,10 @@ class DocumentFocusController { } } + /** + * Removes focus from a given element. + * @param {Element} element The element to remove focus from. + */ blurElement(element) { if (document.activeElement !== element) { return; } element.blur(); diff --git a/ext/js/dom/document-util.js b/ext/js/dom/document-util.js index 73525ff5..ed0a98e7 100644 --- a/ext/js/dom/document-util.js +++ b/ext/js/dom/document-util.js @@ -21,6 +21,9 @@ * TextSourceRange */ +/** + * This class contains utility functions related to the HTML document. + */ class DocumentUtil { /** * Options to configure how element detection is performed. @@ -251,11 +254,23 @@ class DocumentUtil { 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 multiple rects based on the CSS zoom scaling for a given node. + * @param {DOMRect[]} 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; } @@ -266,6 +281,13 @@ class DocumentUtil { 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 && @@ -273,6 +295,13 @@ class DocumentUtil { ); } + /** + * 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[]} 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)) { @@ -282,6 +311,13 @@ class DocumentUtil { 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); @@ -302,6 +338,11 @@ class DocumentUtil { } } + /** + * Gets an array of the active modifier keys. + * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. + * @returns {string[]} An array of modifiers. + */ static getActiveModifiers(event) { const modifiers = []; if (event.altKey) { modifiers.push('alt'); } @@ -311,18 +352,33 @@ class DocumentUtil { return modifiers; } + /** + * Gets an array of the active modifier keys and buttons. + * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. + * @returns {string[]} An array of modifiers and buttons. + */ static getActiveModifiersAndButtons(event) { const modifiers = this.getActiveModifiers(event); this._getActiveButtons(event, modifiers); return modifiers; } + /** + * Gets an array of the active buttons. + * @param {KeyboardEvent|MouseEvent|TouchEvent} event The event to check. + * @returns {string[]} An array of modifiers and buttons. + */ static getActiveButtons(event) { const buttons = []; this._getActiveButtons(event, buttons); return buttons; } + /** + * Adds a fullscreen change event listener. This function handles all of the browser-specific variants. + * @param {Function} onFullscreenChanged The event callback. + * @param {?EventListenerCollection} eventListenerCollection An optional `EventListenerCollection` to add the registration to. + */ static addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection=null) { const target = document; const options = false; @@ -341,6 +397,10 @@ class DocumentUtil { } } + /** + * 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 || @@ -351,6 +411,11 @@ class DocumentUtil { ); } + /** + * 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 = []; @@ -361,6 +426,11 @@ class DocumentUtil { 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 = node.firstChild; if (next === null) { @@ -377,6 +447,12 @@ class DocumentUtil { 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; for (let node of nodes) { @@ -389,6 +465,12 @@ class DocumentUtil { 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; for (let node of nodes) { @@ -401,10 +483,20 @@ class DocumentUtil { 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 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; } diff --git a/ext/js/dom/text-source-element.js b/ext/js/dom/text-source-element.js index 13c5cd86..1c60a5b8 100644 --- a/ext/js/dom/text-source-element.js +++ b/ext/js/dom/text-source-element.js @@ -20,7 +20,18 @@ * StringUtil */ +/** + * This class represents a text source that is attached to a HTML element, such as an + * with alt text or a