Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"tree.min.js","sources":["../src/tree.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Implement an accessible aria tree widget, from a nested unordered list.\n * Based on http://oaa-accessibility.org/example/41/.\n *\n * @module     core/tree\n * @copyright  2015 Damyon Wiese <damyon@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery'], function($) {\n    // Private variables and functions.\n    var SELECTORS = {\n        ITEM: '[role=treeitem]',\n        GROUP: '[role=treeitem]:has([role=group]), [role=treeitem][aria-owns], [role=treeitem][data-requires-ajax=true]',\n        CLOSED_GROUP: '[role=treeitem]:has([role=group])[aria-expanded=false], [role=treeitem][aria-owns][aria-expanded=false], ' +\n                 '[role=treeitem][data-requires-ajax=true][aria-expanded=false]',\n        FIRST_ITEM: '[role=treeitem]:first',\n        VISIBLE_ITEM: '[role=treeitem]:visible',\n        UNLOADED_AJAX_ITEM: '[role=treeitem][data-requires-ajax=true][data-loaded=false][aria-expanded=true]'\n    };\n\n    /**\n     * Constructor.\n     *\n     * @param {String} selector\n     * @param {function} selectCallback Called when the active node is changed.\n     */\n    var Tree = function(selector, selectCallback) {\n        this.treeRoot = $(selector);\n\n        this.treeRoot.data('activeItem', null);\n        this.selectCallback = selectCallback;\n        this.keys = {\n            tab:      9,\n            enter:    13,\n            space:    32,\n            pageup:   33,\n            pagedown: 34,\n            end:      35,\n            home:     36,\n            left:     37,\n            up:       38,\n            right:    39,\n            down:     40,\n            asterisk: 106\n        };\n\n        // Apply the standard default initialisation for all nodes, starting with the tree root.\n        this.initialiseNodes(this.treeRoot);\n        // Make the first item the active item for the tree so that it is added to the tab order.\n        this.setActiveItem(this.treeRoot.find(SELECTORS.FIRST_ITEM));\n        // Create the cache of the visible items.\n        this.refreshVisibleItemsCache();\n        // Create the event handlers for the tree.\n        this.bindEventHandlers();\n    };\n\n    Tree.prototype.registerEnterCallback = function(callback) {\n        this.enterCallback = callback;\n    };\n\n    /**\n     * Find all visible tree items and save a cache of them on the tree object.\n     *\n     * @method refreshVisibleItemsCache\n     */\n    Tree.prototype.refreshVisibleItemsCache = function() {\n        this.treeRoot.data('visibleItems', this.treeRoot.find(SELECTORS.VISIBLE_ITEM));\n    };\n\n    /**\n     * Get all visible tree items.\n     *\n     * @method getVisibleItems\n     * @return {Object} visible items\n     */\n    Tree.prototype.getVisibleItems = function() {\n        return this.treeRoot.data('visibleItems');\n    };\n\n    /**\n     * Mark the given item as active within the tree and fire the callback for when the active item is set.\n     *\n     * @method setActiveItem\n     * @param {object} item jquery object representing an item on the tree.\n     */\n    Tree.prototype.setActiveItem = function(item) {\n        var currentActive = this.treeRoot.data('activeItem');\n        if (item === currentActive) {\n            return;\n        }\n\n        // Remove previous active from tab order.\n        if (currentActive) {\n            currentActive.attr('tabindex', '-1');\n            currentActive.attr('aria-selected', 'false');\n        }\n        item.attr('tabindex', '0');\n        item.attr('aria-selected', 'true');\n\n        // Set the new active item.\n        this.treeRoot.data('activeItem', item);\n\n        if (typeof this.selectCallback === 'function') {\n            this.selectCallback(item);\n        }\n    };\n\n    /**\n     * Determines if the given item is a group item (contains child tree items) in the tree.\n     *\n     * @method isGroupItem\n     * @param {object} item jquery object representing an item on the tree.\n     * @returns {bool}\n     */\n    Tree.prototype.isGroupItem = function(item) {\n        return item.is(SELECTORS.GROUP);\n    };\n\n    /**\n     * Determines if the given item is a group item (contains child tree items) in the tree.\n     *\n     * @method isGroupItem\n     * @param {object} item jquery object representing an item on the tree.\n     * @returns {bool}\n     */\n    Tree.prototype.getGroupFromItem = function(item) {\n        var ariaowns = this.treeRoot.find('#' + item.attr('aria-owns'));\n        var plain = item.children('[role=group]');\n        if (ariaowns.length > plain.length) {\n            return ariaowns;\n        } else {\n            return plain;\n        }\n    };\n\n    /**\n     * Determines if the given group item (contains child tree items) is collapsed.\n     *\n     * @method isGroupCollapsed\n     * @param {object} item jquery object representing a group item on the tree.\n     * @returns {bool}\n     */\n    Tree.prototype.isGroupCollapsed = function(item) {\n        return item.attr('aria-expanded') === 'false';\n    };\n\n    /**\n     * Determines if the given group item (contains child tree items) can be collapsed.\n     *\n     * @method isGroupCollapsible\n     * @param {object} item jquery object representing a group item on the tree.\n     * @returns {bool}\n     */\n    Tree.prototype.isGroupCollapsible = function(item) {\n        return item.attr('data-collapsible') !== 'false';\n    };\n\n    /**\n     * Performs the tree initialisation for all child items from the given node,\n     * such as removing everything from the tab order and setting aria selected\n     * on items.\n     *\n     * @method initialiseNodes\n     * @param {object} node jquery object representing a node.\n     */\n    Tree.prototype.initialiseNodes = function(node) {\n        this.removeAllFromTabOrder(node);\n        this.setAriaSelectedFalseOnItems(node);\n\n        // Get all ajax nodes that have been rendered as expanded but haven't loaded the child items yet.\n        var thisTree = this;\n        node.find(SELECTORS.UNLOADED_AJAX_ITEM).each(function() {\n            var unloadedNode = $(this);\n            // Collapse and then expand to trigger the ajax loading.\n            thisTree.collapseGroup(unloadedNode);\n            thisTree.expandGroup(unloadedNode);\n        });\n    };\n\n    /**\n     * Removes all child DOM elements of the given node from the tab order.\n     *\n     * @method removeAllFromTabOrder\n     * @param {object} node jquery object representing a node.\n     */\n    Tree.prototype.removeAllFromTabOrder = function(node) {\n        node.find('*').attr('tabindex', '-1');\n        this.getGroupFromItem($(node)).find('*').attr('tabindex', '-1');\n    };\n\n    /**\n     * Find all child tree items from the given node and set the aria selected attribute to false.\n     *\n     * @method setAriaSelectedFalseOnItems\n     * @param {object} node jquery object representing a node.\n     */\n    Tree.prototype.setAriaSelectedFalseOnItems = function(node) {\n        node.find(SELECTORS.ITEM).attr('aria-selected', 'false');\n    };\n\n    /**\n     * Expand all group nodes within the tree.\n     *\n     * @method expandAllGroups\n     */\n    Tree.prototype.expandAllGroups = function() {\n        var thisTree = this;\n\n        this.treeRoot.find(SELECTORS.CLOSED_GROUP).each(function() {\n            var groupNode = $(this);\n\n            thisTree.expandGroup($(this)).done(function() {\n                thisTree.expandAllChildGroups(groupNode);\n            });\n        });\n    };\n\n    /**\n     * Find all child group nodes from the given node and expand them.\n     *\n     * @method expandAllChildGroups\n     * @param {Object} item is the jquery id of the group.\n     */\n    Tree.prototype.expandAllChildGroups = function(item) {\n        var thisTree = this;\n\n        this.getGroupFromItem(item).find(SELECTORS.CLOSED_GROUP).each(function() {\n            var groupNode = $(this);\n\n            thisTree.expandGroup($(this)).done(function() {\n                thisTree.expandAllChildGroups(groupNode);\n            });\n        });\n    };\n\n    /**\n     * Expand a collapsed group.\n     *\n     * Handles expanding nodes that are ajax loaded (marked with a data-requires-ajax attribute).\n     *\n     * @method expandGroup\n     * @param {Object} item is the jquery id of the parent item of the group.\n     * @return {Object} a promise that is resolved when the group has been expanded.\n     */\n    Tree.prototype.expandGroup = function(item) {\n        var promise = $.Deferred();\n        // Ignore nodes that are explicitly maked as not expandable or are already expanded.\n        if (item.attr('data-expandable') !== 'false' && this.isGroupCollapsed(item)) {\n            // If this node requires ajax load and we haven't already loaded it.\n            if (item.attr('data-requires-ajax') === 'true' && item.attr('data-loaded') !== 'true') {\n                item.attr('data-loaded', false);\n                // Get the closes ajax loading module specificed in the tree.\n                var moduleName = item.closest('[data-ajax-loader]').attr('data-ajax-loader');\n                var thisTree = this;\n                // Flag this node as loading.\n                const p = item.find('p');\n                p.addClass('loading');\n                // Require the ajax module (must be AMD) and try to load the items.\n                require([moduleName], function(loader) {\n                    // All ajax module must implement a \"load\" method.\n                    loader.load(item).done(function() {\n                        item.attr('data-loaded', true);\n\n                        // Set defaults on the newly constructed part of the tree.\n                        thisTree.initialiseNodes(item);\n                        thisTree.finishExpandingGroup(item);\n                        // Make sure no child elements of the item we just loaded are tabbable.\n                        p.removeClass('loading');\n                        promise.resolve();\n                    });\n                });\n            } else {\n                this.finishExpandingGroup(item);\n                promise.resolve();\n            }\n        } else {\n            promise.resolve();\n        }\n        return promise;\n    };\n\n    /**\n     * Perform the necessary DOM changes to display a group item.\n     *\n     * @method finishExpandingGroup\n     * @param {Object} item is the jquery id of the parent item of the group.\n     */\n    Tree.prototype.finishExpandingGroup = function(item) {\n        // Expand the group.\n        var group = this.getGroupFromItem(item);\n        group.removeAttr('aria-hidden');\n        item.attr('aria-expanded', 'true');\n\n        // Update the list of visible items.\n        this.refreshVisibleItemsCache();\n    };\n\n    /**\n     * Collapse an expanded group.\n     *\n     * @method collapseGroup\n     * @param {Object} item is the jquery id of the parent item of the group.\n     */\n    Tree.prototype.collapseGroup = function(item) {\n        // If the item is not collapsible or already collapsed then do nothing.\n        if (!this.isGroupCollapsible(item) || this.isGroupCollapsed(item)) {\n            return;\n        }\n\n        // Collapse the group.\n        var group = this.getGroupFromItem(item);\n        group.attr('aria-hidden', 'true');\n        item.attr('aria-expanded', 'false');\n\n        // Update the list of visible items.\n        this.refreshVisibleItemsCache();\n    };\n\n    /**\n     * Expand or collapse a group.\n     *\n     * @method toggleGroup\n     * @param {Object} item is the jquery id of the parent item of the group.\n     */\n    Tree.prototype.toggleGroup = function(item) {\n        if (item.attr('aria-expanded') === 'true') {\n            this.collapseGroup(item);\n        } else {\n            this.expandGroup(item);\n        }\n    };\n\n    /**\n     * Handle a key down event - ie navigate the tree.\n     *\n     * @method handleKeyDown\n     * @param {Event} e The event.\n     */\n     // This function should be simplified. In the meantime..\n     // eslint-disable-next-line complexity\n    Tree.prototype.handleKeyDown = function(e) {\n        var item = $(e.target);\n        var currentIndex = this.getVisibleItems()?.index(item);\n\n        if ((e.altKey || e.ctrlKey || e.metaKey) || (e.shiftKey && e.keyCode != this.keys.tab)) {\n            // Do nothing.\n            return;\n        }\n\n        switch (e.keyCode) {\n            case this.keys.home: {\n                // Jump to first item in tree.\n                this.getVisibleItems().first().focus();\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.end: {\n                // Jump to last visible item.\n                this.getVisibleItems().last().focus();\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.enter: {\n                var links = item.children('a').length ? item.children('a') : item.children().not(SELECTORS.GROUP).find('a');\n                if (links.length) {\n                    if (links.first().data('overrides-tree-activation-key-handler')) {\n                        // If the link overrides handling of activation keys, let it do so.\n                        links.first().triggerHandler(e);\n                    } else if (typeof this.enterCallback === 'function') {\n                        // Use callback if there is one.\n                        this.enterCallback(item);\n                    } else {\n                        window.location.href = links.first().attr('href');\n                    }\n                } else if (this.isGroupItem(item)) {\n                    this.toggleGroup(item, true);\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.space: {\n                if (this.isGroupItem(item)) {\n                    this.toggleGroup(item, true);\n                } else if (item.children('a').length) {\n                    var firstLink = item.children('a').first();\n\n                    if (firstLink.data('overrides-tree-activation-key-handler')) {\n                        firstLink.triggerHandler(e);\n                    }\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.left: {\n                var focusParent = function(tree) {\n                    // Get the immediate visible parent group item that contains this element.\n                    tree.getVisibleItems().filter(function() {\n                        return tree.getGroupFromItem($(this)).has(item).length;\n                    }).focus();\n                };\n\n                // If this is a group item then collapse it and focus the parent group\n                // in accordance with the aria spec.\n                if (this.isGroupItem(item)) {\n                    if (this.isGroupCollapsed(item)) {\n                        focusParent(this);\n                    } else {\n                        this.collapseGroup(item);\n                    }\n                } else {\n                    focusParent(this);\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.right: {\n                // If this is a group item then expand it and focus the first child item\n                // in accordance with the aria spec.\n                if (this.isGroupItem(item)) {\n                    if (this.isGroupCollapsed(item)) {\n                        this.expandGroup(item);\n                    } else {\n                        // Move to the first item in the child group.\n                        this.getGroupFromItem(item).find(SELECTORS.ITEM).first().focus();\n                    }\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.up: {\n\n                if (currentIndex > 0) {\n                    var prev = this.getVisibleItems().eq(currentIndex - 1);\n\n                    prev.focus();\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.down: {\n\n                if (currentIndex < this.getVisibleItems().length - 1) {\n                    var next = this.getVisibleItems().eq(currentIndex + 1);\n\n                    next.focus();\n                }\n\n                e.preventDefault();\n                return;\n            }\n            case this.keys.asterisk: {\n                // Expand all groups.\n                this.expandAllGroups();\n                e.preventDefault();\n                return;\n            }\n        }\n    };\n\n    /**\n     * Handle an item click.\n     *\n     * @param {Event} event the click event\n     * @param {jQuery} item the item clicked\n     */\n    Tree.prototype.handleItemClick = function(event, item) {\n        // Update the active item.\n        item.focus();\n\n        // If the item is a group node.\n        if (this.isGroupItem(item)) {\n            this.toggleGroup(item);\n        }\n    };\n\n    /**\n     * Handle a click (select).\n     *\n     * @method handleClick\n     * @param {Event} event The event.\n     */\n    Tree.prototype.handleClick = function(event) {\n        if (event.altKey || event.ctrlKey || event.shiftKey || event.metaKey) {\n            // Do nothing.\n            return;\n        }\n\n        // Get the closest tree item from the event target.\n        var item = $(event.target).closest('[role=\"treeitem\"]');\n        if (!item.is(event.currentTarget)) {\n            return;\n        }\n\n        this.handleItemClick(event, item);\n    };\n\n    /**\n     * Handle a focus event.\n     *\n     * @method handleFocus\n     * @param {Event} e The event.\n     */\n    Tree.prototype.handleFocus = function(e) {\n        this.setActiveItem($(e.target));\n    };\n\n    /**\n     * Bind the event listeners we require.\n     *\n     * @method bindEventHandlers\n     */\n    Tree.prototype.bindEventHandlers = function() {\n        // Bind event handlers to the tree items. Use event delegates to allow\n        // for dynamically loaded parts of the tree.\n        this.treeRoot.on({\n            click: this.handleClick.bind(this),\n            keydown: this.handleKeyDown.bind(this),\n            focus: this.handleFocus.bind(this),\n        }, SELECTORS.ITEM);\n    };\n\n    return /** @alias module:core/tree */ Tree;\n});\n"],"names":["define","$","SELECTORS","Tree","selector","selectCallback","treeRoot","data","keys","tab","enter","space","pageup","pagedown","end","home","left","up","right","down","asterisk","initialiseNodes","this","setActiveItem","find","refreshVisibleItemsCache","bindEventHandlers","prototype","registerEnterCallback","callback","enterCallback","getVisibleItems","item","currentActive","attr","isGroupItem","is","getGroupFromItem","ariaowns","plain","children","length","isGroupCollapsed","isGroupCollapsible","node","removeAllFromTabOrder","setAriaSelectedFalseOnItems","thisTree","each","unloadedNode","collapseGroup","expandGroup","expandAllGroups","groupNode","done","expandAllChildGroups","promise","Deferred","moduleName","closest","p","addClass","require","loader","load","finishExpandingGroup","removeClass","resolve","removeAttr","toggleGroup","handleKeyDown","e","target","currentIndex","_this$getVisibleItems","index","altKey","ctrlKey","metaKey","shiftKey","keyCode","first","focus","preventDefault","last","links","not","triggerHandler","window","location","href","firstLink","focusParent","tree","filter","has","eq","handleItemClick","event","handleClick","currentTarget","handleFocus","on","click","bind","keydown"],"mappings":"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"}