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/>./*** Course index keyboard navigation and aria-tree compatibility.** Node tree and bootstrap collapsibles don't use the same HTML structure. However,* all keybindings and logic is compatible. This class translate the primitive opetations* to a bootstrap collapsible structure.** @module core_courseformat/local/courseeditor/contenttree* @class core_courseformat/local/courseeditor/contenttree* @copyright 2021 Ferran Recio <ferran@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/// The core/tree uses jQuery to expand all nodes.import jQuery from 'jquery';import Tree from 'core/tree';import {getList} from 'core/normalise';export default class extends Tree {/*** Setup the core/tree keyboard navigation.** @param {Element|undefined} mainElement an alternative main element in case it is not from the parent component* @param {Object|undefined} selectors alternative selectors* @param {boolean} preventcache if the elements cache must be disabled.*/constructor(mainElement, selectors, preventcache) {// Init this value with the parent DOM element.super(mainElement);// Get selectors from parent.this.selectors = {SECTION: selectors.SECTION,TOGGLER: selectors.TOGGLER,COLLAPSE: selectors.COLLAPSE,ENTER: selectors.ENTER ?? selectors.TOGGLER,};// The core/tree library saves the visible elements cache inside the main tree node.// However, in edit mode content can change suddenly so we need to refresh caches when needed.if (preventcache) {this._getVisibleItems = this.getVisibleItems;this.getVisibleItems = () => {this.refreshVisibleItemsCache();return this._getVisibleItems();};}// All jQuery events can be replaced when MDL-71979 is integrated.this.treeRoot.on('hidden.bs.collapse shown.bs.collapse', () => {this.refreshVisibleItemsCache();});// Register a custom callback for pressing enter key.this.registerEnterCallback(this.enterCallback.bind(this));}/*** Return the current active node.** @return {Element|undefined} the active item if any*/getActiveItem() {const activeItem = this.treeRoot.data('activeItem');if (activeItem) {return getList(activeItem)[0];}return undefined;}/*** Handle enter key on a collpasible node.** @param {JQuery} jQueryItem the jQuery object*/enterCallback(jQueryItem) {const item = getList(jQueryItem)[0];if (this.isGroupItem(jQueryItem)) {// Group elements is like clicking a topic but without loosing the focus.const enter = item.querySelector(this.selectors.ENTER);if (enter.getAttribute('href') !== '#') {window.location.href = enter.getAttribute('href');}enter.click();} else {// Activity links just follow the link href.const link = item.querySelector('a');if (link.getAttribute('href') !== '#') {window.location.href = link.getAttribute('href');} else {link.click();}return;}}/*** Handle an item click.** @param {Event} event the click event* @param {jQuery} jQueryItem the item clicked*/handleItemClick(event, jQueryItem) {const isChevron = event.target.closest(this.selectors.COLLAPSE);// Only chevron clicks toogle the sections always.if (isChevron) {super.handleItemClick(event, jQueryItem);return;}// This is a title or activity name click.jQueryItem.focus();if (this.isGroupItem(jQueryItem)) {this.expandGroup(jQueryItem);}}/*** Check if a gorup item is collapsed.** @param {JQuery} jQueryItem the jQuery object* @returns {boolean} if the element is collapsed*/isGroupCollapsed(jQueryItem) {const item = getList(jQueryItem)[0];const toggler = item.querySelector(`[aria-expanded]`);return toggler.getAttribute('aria-expanded') === 'false';}/*** Toggle a group item.** @param {JQuery} item the jQuery object*/toggleGroup(item) {// All jQuery in this segment of code can be replaced when MDL-71979 is integrated.const toggler = item.find(this.selectors.COLLAPSE);let collapsibleId = toggler.data('target') ?? toggler.attr('href');if (!collapsibleId) {return;}collapsibleId = collapsibleId.replace('#', '');// Bootstrap 4 uses jQuery to interact with collapsibles.const collapsible = jQuery(`#${collapsibleId}`);if (collapsible.length) {jQuery(`#${collapsibleId}`).collapse('toggle');}}/*** Expand a group item.** @param {JQuery} item the jQuery object*/expandGroup(item) {if (this.isGroupCollapsed(item)) {this.toggleGroup(item);}}/*** Collpase a group item.** @param {JQuery} item the jQuery object*/collapseGroup(item) {if (!this.isGroupCollapsed(item)) {this.toggleGroup(item);}}/*** Expand all groups.*/expandAllGroups() {const togglers = getList(this.treeRoot)[0].querySelectorAll(this.selectors.SECTION);togglers.forEach(item => {this.expandGroup(jQuery(item));});}}