AutorÃa | Ultima modificación | Ver Log |
// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Page utility helpers.** @module core/pagehelpers* @copyright 2023 Ferran Recio <ferran@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*//*** Maximum sizes for breakpoints. This needs to correspond with Bootstrap* Breakpoints** @private*/const Sizes = {small: 576,medium: 991,large: 1400};const Selectors = {focusable: 'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])',};const Classes = {behatSite: 'behat-site',};/*** Check fi the current page is a Behat site.* @returns {boolean} true if the current page is a Behat site.*/export const isBehatSite = () => {return document.body.classList.contains(Classes.behatSite);};/*** Get the current body width.* @returns {number} the current body width.*/export const getCurrentWidth = () => {const DomRect = document.body.getBoundingClientRect();return DomRect.x + DomRect.width;};/*** Check if the user uses an extra small size browser.** @returns {boolean} true if the body is smaller than sizes.small max size.*/export const isExtraSmall = () => {const browserWidth = getCurrentWidth();return browserWidth < Sizes.small;};/*** Check if the user uses a small size browser.** @returns {boolean} true if the body is smaller than sizes.medium max size.*/export const isSmall = () => {const browserWidth = getCurrentWidth();return browserWidth < Sizes.medium;};/*** Check if the user uses a large size browser.** @returns {boolean} true if the body is smaller than sizes.large max size.*/export const isLarge = () => {const browserWidth = getCurrentWidth();return browserWidth >= Sizes.large;};/*** Get the first focusable element inside a container.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @returns {HTMLElement|null}*/export const firstFocusableElement = (container) => {const containerElement = container || document;return containerElement.querySelector(Selectors.focusable);};/*** Get the last focusable element inside a container.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @returns {HTMLElement|null}*/export const lastFocusableElement = (container) => {const containerElement = container || document;const focusableElements = containerElement.querySelectorAll(Selectors.focusable);return focusableElements[focusableElements.length - 1] ?? null;};/*** Get all focusable elements inside a container.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @returns {HTMLElement[]}*/export const focusableElements = (container) => {const containerElement = container || document;return containerElement.querySelectorAll(Selectors.focusable);};/*** Get the previous focusable element in a container.* It uses the current focused element to know where to start the search.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @param {Boolean} [loopSelection] Whether to loop selection or not. Default to false.* @returns {HTMLElement|null}*/export const previousFocusableElement = (container, loopSelection) => {return getRelativeFocusableElement(container, loopSelection, -1);};/*** Get the next focusable element in a container.* It uses the current focused element to know where to start the search.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @param {Boolean} [loopSelection] Whether to loop selection or not. Default to false.* @returns {HTMLElement|null}*/export const nextFocusableElement = (container, loopSelection) => {return getRelativeFocusableElement(container, loopSelection, 1);};/*** Internal function to get the next or previous focusable element.* @param {HTMLElement} [container] Container to search in. Defaults to document.* @param {Boolean} [loopSelection] Whether to loop selection or not.* @param {Number} [direction] Direction to search in. 1 for next, -1 for previous.* @returns {HTMLElement|null}* @private*/const getRelativeFocusableElement = (container, loopSelection, direction) => {const focusedElement = document.activeElement;const focusables = [...focusableElements(container)];const focusedIndex = focusables.indexOf(focusedElement);if (focusedIndex === -1) {return null;}const newIndex = focusedIndex + direction;if (focusables[newIndex] !== undefined) {return focusables[newIndex];}if (loopSelection != true) {return null;}if (direction > 0) {return focusables[0] ?? null;}return focusables[focusables.length - 1] ?? null;};