Ir a la última revisión | Autoría | Comparar con el anterior | 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/>./*** A small dropdown to filter users within the gradebook.** @module core_grades/searchwidget/initials* @copyright 2022 Mathew May <mathew.solutions>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/import Pending from 'core/pending';import * as Url from 'core/url';import CustomEvents from "core/custom_interaction_events";import $ from 'jquery';/*** Whether the event listener has already been registered for this module.** @type {boolean}*/let registered = false;// Contain our selectors within this file until they could be of use elsewhere.const selectors = {pageListItem: 'page-item',pageClickableItem: '.page-link',activeItem: 'active',formDropdown: '.initialsdropdownform',parentDomNode: '.initials-selector',firstInitial: 'firstinitial',lastInitial: 'lastinitial',initialBars: '.initialbar', // Both first and last name use this class.targetButton: 'initialswidget',formItems: {type: 'submit',save: 'save',cancel: 'cancel'}};/*** Our initial hook into the module which will eventually allow us to handle the dropdown initials bar form.** @param {String} callingLink The link to redirect upon form submission.* @param {Null|Number} gpr_userid The user id to filter by.* @param {Null|String} gpr_search The search value to filter by.*/export const init = (callingLink, gpr_userid = null, gpr_search = null) => {if (registered) {return;}const pendingPromise = new Pending();registerListenerEvents(callingLink, gpr_userid, gpr_search);// BS events always bubble so, we need to listen for the event higher up the chain.$(selectors.parentDomNode).on('shown.bs.dropdown', () => {document.querySelector(selectors.pageClickableItem).focus({preventScroll: true});});pendingPromise.resolve();registered = true;};/*** Register event listeners.** @param {String} callingLink The link to redirect upon form submission.* @param {Null|Number} gpr_userid The user id to filter by.* @param {Null|String} gpr_search The search value to filter by.*/const registerListenerEvents = (callingLink, gpr_userid = null, gpr_search = null) => {const events = ['click',CustomEvents.events.activate,CustomEvents.events.keyboardActivate];CustomEvents.define(document, events);// Register events.events.forEach((event) => {document.addEventListener(event, (e) => {// Always fetch the latest information when we click as state is a fickle thing.let {firstActive, lastActive, sifirst, silast} = onClickVariables();let itemToReset = '';// Prevent the usual form behaviour.if (e.target.closest(selectors.formDropdown)) {e.preventDefault();}// Handle the state of active initials before form submission.if (e.target.closest(`${selectors.formDropdown} .${selectors.pageListItem}`)) {// Ensure the li items don't cause weird clicking emptying out the form.if (e.target.classList.contains(selectors.pageListItem)) {return;}const initialsBar = e.target.closest(selectors.initialBars); // Find out which initial bar we are in.// We want to find the current active item in the menu area the user selected.// We also want to fetch the raw item out of the array for instant manipulation.if (initialsBar.classList.contains(selectors.firstInitial)) {sifirst = e.target;itemToReset = firstActive;} else {silast = e.target;itemToReset = lastActive;}swapActiveItems(itemToReset, e);}// Handle form submissions.if (e.target.closest(`${selectors.formDropdown}`) && e.target.type === selectors.formItems.type) {if (e.target.dataset.action === selectors.formItems.save) {// Ensure we strip out the value (All) as it messes with the PHP side of the initials bar.// Then we will redirect the user back onto the page with new filters applied.const params = {'id': e.target.closest(selectors.formDropdown).dataset.courseid,'gpr_search': gpr_search !== null ? gpr_search : '','sifirst': sifirst.parentElement.classList.contains('initialbarall') ? '' : sifirst.value,'silast': silast.parentElement.classList.contains('initialbarall') ? '' : silast.value,};if (gpr_userid !== null) {params.gpr_userid = gpr_userid;}window.location = Url.relativeUrl(callingLink, params);}if (e.target.dataset.action === selectors.formItems.cancel) {$(`.${selectors.targetButton}`).dropdown('toggle');}}});});};/*** A small abstracted helper function which allows us to ensure we have up-to-date lists of nodes.** @returns {{firstActive: HTMLElement, lastActive: HTMLElement, sifirst: ?String, silast: ?String}}*/const onClickVariables = () => {// Ensure we have an up-to-date initials bar.const firstItems = [...document.querySelectorAll(`.${selectors.firstInitial} li`)];const lastItems = [...document.querySelectorAll(`.${selectors.lastInitial} li`)];const firstActive = firstItems.filter((item) => item.classList.contains(selectors.activeItem))[0];const lastActive = lastItems.filter((item) => item.classList.contains(selectors.activeItem))[0];// Ensure we retain both of the selections from a previous instance.let sifirst = firstActive.querySelector(selectors.pageClickableItem);let silast = lastActive.querySelector(selectors.pageClickableItem);return {firstActive, lastActive, sifirst, silast};};/*** Given we are provided the old li and current click event, swap around the active properties.** @param {HTMLElement} itemToReset* @param {Event} e*/const swapActiveItems = (itemToReset, e) => {itemToReset.classList.remove(selectors.activeItem);itemToReset.querySelector(selectors.pageClickableItem).ariaCurrent = false;// Set the select item as the current item.const itemToSetActive = e.target.parentElement;itemToSetActive.classList.add(selectors.activeItem);e.target.ariaCurrent = true;};