MDL-63044 javascript: add global helper for dropdowns
[moodle.git] / lib / amd / src / page_global.js
blob88360b8bf294e9502d5c89227d2bea3931e9be4a
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Provide global helper code to enhance page elements.
18  *
19  * @module     core/page_global
20  * @package    core
21  * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 define(
26     'jquery',
27     'core/custom_interaction_events',
28     'core/str',
30 function(
31     $,
32     CustomEvents,
33     Str
34 ) {
36     /**
37      * Add an event handler for dropdown menus that wish to show their active item
38      * in the dropdown toggle element.
39      *
40      * By default the handler will add the "active" class to the selected dropdown
41      * item and set it's text as the HTML for the dropdown toggle.
42      *
43      * The behaviour of this handler is controlled by adding data attributes to
44      * the HTML and requires the typically Bootstrap dropdown markup.
45      *
46      * data-show-active-item - Add to the .dropdown-menu element to enable default
47      *                         functionality.
48      * data-skip-active-class - Add to the .dropdown-menu to prevent this code from
49      *                          adding the active class to the dropdown items
50      * data-active-item-text - Add to an element within the data-toggle="dropdown" element
51      *                         to use it as the active option text placeholder otherwise the
52      *                         data-toggle="dropdown" element itself will be used.
53      * data-active-item-button-aria-label-components - String components to set the aria
54      *                         lable on the dropdown button. The string will be given the
55      *                         active item text.
56      */
57     var initActionOptionDropdownHandler = function() {
58         var body = $('body');
60         CustomEvents.define(body, [CustomEvents.events.activate]);
61         body.on(CustomEvents.events.activate, '[data-show-active-item]', function(e) {
62             // The dropdown item that the user clicked on.
63             var option = $(e.target).closest('.dropdown-item');
64             // The dropdown menu element.
65             var menuContainer = option.closest('[data-show-active-item]');
67             if (!option.hasClass('dropdown-item')) {
68                 // Ignore non Bootstrap dropdowns.
69                 return;
70             }
72             if (option.hasClass('active')) {
73                 // If it's already active then we don't need to do anything.
74                 return;
75             }
77             // Clear the active class from all other options.
78             var dropdownItems = menuContainer.find('.dropdown-item');
79             dropdownItems.removeClass('active');
80             dropdownItems.removeAttr('aria-current');
82             if (!menuContainer.attr('data-skip-active-class')) {
83                 // Make this option active unless configured to ignore it.
84                 // Some code, for example the Bootstrap tabs, may want to handle
85                 // adding the active class itself.
86                 option.addClass('active');
87             }
89             // Update aria attribute for active item.
90             option.attr('aria-current', true);
92             var activeOptionText = option.text();
93             var dropdownToggle = menuContainer.parent().find('[data-toggle="dropdown"]');
94             var dropdownToggleText = dropdownToggle.find('[data-active-item-text]');
96             if (dropdownToggleText.length) {
97                 // We have a specific placeholder for the active item text so
98                 // use that.
99                 dropdownToggleText.html(activeOptionText);
100             } else {
101                 // Otherwise just replace all of the toggle text with the active item.
102                 dropdownToggle.html(activeOptionText);
103             }
105             var activeItemAriaLabelComponent = menuContainer.attr('data-active-item-button-aria-label-components');
106             if (activeItemAriaLabelComponent) {
107                 // If we have string components for the aria label then load the string
108                 // and set the label on the dropdown toggle.
109                 var strParams = activeItemAriaLabelComponent.split(',');
110                 strParams.push(activeOptionText);
112                 Str.get_string(strParams[0].trim(), strParams[1].trim(), strParams[2].trim())
113                     .then(function(string) {
114                         dropdownToggle.attr('aria-label', string);
115                         return string;
116                     })
117                     .catch(function() {
118                         // Silently ignore that we couldn't load the string.
119                         return false;
120                     });
121             }
122         });
123     };
125     /**
126      * Initialise the global helper functions.
127      */
128     var init = function() {
129         initActionOptionDropdownHandler();
130     };
132     return {
133         init: init
134     };