From d096c60e0c7a5f8f6cfc603d8097b17d28ea792d Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Fri, 16 Jun 2023 14:52:48 +0100 Subject: [PATCH 1/2] MDL-76974 user: deprecate old method of setting user preferences. The `M.util.set_user_preference` method (plus accompanying helpers) are now deprecated, in favour of the `core_user/repository` module to achieve the same. Update current implementation to proxy calls to the new API ensuring backwards compatibility, while emitting copious developer debugging. --- lib/ajax/ajaxlib.php | 4 ++++ lib/ajax/setuserpref.php | 3 +++ lib/db/services.php | 1 + lib/javascript-static.js | 25 +++++++------------------ user/externallib.php | 17 ++++++++++++++--- user/upgrade.txt | 4 ++++ 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/lib/ajax/ajaxlib.php b/lib/ajax/ajaxlib.php index 8c7336789ba..d4f8eff2584 100644 --- a/lib/ajax/ajaxlib.php +++ b/lib/ajax/ajaxlib.php @@ -32,10 +32,14 @@ * @param string $name the name of the user_perference we should allow to be updated by remote calls. * @param integer $paramtype one of the PARAM_{TYPE} constants, user to clean submitted values before set_user_preference is called. * @return null + * + * @deprecated since Moodle 4.3 */ function user_preference_allow_ajax_update($name, $paramtype) { global $USER, $PAGE; + debugging(__FUNCTION__ . '() is deprecated. Please use the "core_user/repository" module instead.', DEBUG_DEVELOPER); + // Record in the session that this user_preference is allowed to updated remotely. $USER->ajax_updatable_user_prefs[$name] = $paramtype; } diff --git a/lib/ajax/setuserpref.php b/lib/ajax/setuserpref.php index a960a288f78..b40e103480e 100644 --- a/lib/ajax/setuserpref.php +++ b/lib/ajax/setuserpref.php @@ -24,6 +24,7 @@ * @category preference * @copyright 2008 Tim Hunt * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @deprecated since Moodle 4.3 */ require_once(__DIR__ . '/../../config.php'); @@ -39,6 +40,8 @@ if (!isset($USER->ajax_updatable_user_prefs[$name])) { throw new \moodle_exception('notallowedtoupdateprefremotely'); } +debugging('Use of setuserpref.php is deprecated. Please use the "core_user/repository" module instead.', DEBUG_DEVELOPER); + // Get and the value. $value = required_param('value', $USER->ajax_updatable_user_prefs[$name]); diff --git a/lib/db/services.php b/lib/db/services.php index 354b2da1197..e0a3148472e 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1912,6 +1912,7 @@ $functions = array( 'type' => 'write', 'capabilities' => 'moodle/site:config', 'ajax' => true, + 'loginrequired' => false, 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), 'core_user_agree_site_policy' => array( diff --git a/lib/javascript-static.js b/lib/javascript-static.js index 02c9f333181..cf790b6dbfb 100644 --- a/lib/javascript-static.js +++ b/lib/javascript-static.js @@ -195,27 +195,16 @@ M.util.CollapsibleRegion.prototype.icon = null; * user_preference_allow_ajax_update from moodlelib.php to tell Moodle that * the udpate is allowed, and how to safely clean and submitted values. * - * @param String name the name of the setting to udpate. - * @param String the value to set it to. + * @param {String} name the name of the setting to update. + * @param {String} value the value to set it to. + * + * @deprecated since Moodle 4.3. */ M.util.set_user_preference = function(name, value) { - YUI().use('io', function(Y) { - var url = M.cfg.wwwroot + '/lib/ajax/setuserpref.php?sesskey=' + - M.cfg.sesskey + '&pref=' + encodeURI(name) + '&value=' + encodeURI(value); + Y.log('M.util.set_user_preference is deprecated. Please use the "core_user/repository" module instead.', 'warn'); - // If we are a developer, ensure that failures are reported. - var cfg = { - method: 'get', - on: {} - }; - if (M.cfg.developerdebug) { - cfg.on.failure = function(id, o, args) { - alert("Error updating user preference '" + name + "' using ajax. Clicking this link will repeat the Ajax call that failed so you can see the error: "); - } - } - - // Make the request. - Y.io(url, cfg); + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference(name, value); }); }; diff --git a/user/externallib.php b/user/externallib.php index cd256926605..0213d9425d5 100644 --- a/user/externallib.php +++ b/user/externallib.php @@ -1822,14 +1822,14 @@ class core_user_external extends \core_external\external_api { * @throws moodle_exception */ public static function set_user_preferences($preferences) { - global $USER; + global $PAGE, $USER; $params = self::validate_parameters(self::set_user_preferences_parameters(), array('preferences' => $preferences)); $warnings = array(); $saved = array(); $context = context_system::instance(); - self::validate_context($context); + $PAGE->set_context($context); $userscache = array(); foreach ($params['preferences'] as $pref) { @@ -1855,7 +1855,18 @@ class core_user_external extends \core_external\external_api { } try { - if (core_user::can_edit_preference($pref['name'], $user)) { + + // Support legacy preferences from the old M.util.set_user_preference API (always using the current user). + if (isset($USER->ajax_updatable_user_prefs[$pref['name']])) { + debugging('Updating preferences via ajax_updatable_user_prefs is deprecated. ' . + 'Please use the "core_user/repository" module instead.', DEBUG_DEVELOPER); + + set_user_preference($pref['name'], $pref['value']); + $saved[] = array( + 'name' => $pref['name'], + 'userid' => $USER->id, + ); + } else if (core_user::can_edit_preference($pref['name'], $user)) { $value = core_user::clean_preference($pref['value'], $pref['name']); set_user_preference($pref['name'], $value, $user->id); $saved[] = array( diff --git a/user/upgrade.txt b/user/upgrade.txt index 13d978c65b5..292ca7d6426 100644 --- a/user/upgrade.txt +++ b/user/upgrade.txt @@ -9,6 +9,10 @@ This files describes API changes for code that uses the user API. * The `core_user/repository` Javascript module now exports new methods for manipulating user preferences: - `[get|set]UserPreference` - `[get|set]UserPreferences` +* The following user preference helpers have been deprecated, please use the `core_user/repository` module instead: + - `user_preference_allow_ajax_update` + - `M.util.set_user_preference` + - `lib/ajax/setuserpref.php` * The external `core_user_set_user_preferences` method will now default the `userid` property of each preference to that of the current user, if omitted * The following previously deprecated methods have been removed and can no longer be used: From b30245b3e21d4655593c263693bb80d636e998a1 Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Sun, 18 Jun 2023 19:11:36 +0100 Subject: [PATCH 2/2] MDL-76974 javascript: convert remaining uses of old preferences API. Implement component preference definition callbacks, update JS code to use the `core_user/repository` module instead of the now deprecated API. --- blocks/settings/block_settings.php | 4 -- lib/classes/user.php | 54 +++++++++++++++++++++++ lib/form/filemanager.js | 6 ++- lib/form/filemanager.php | 1 - lib/javascript-static.js | 8 +++- lib/weblib.php | 1 - mod/assign/classes/output/grading_app.php | 3 -- mod/workshop/lib.php | 32 ++++++++++++++ question/bank/previewquestion/lib.php | 41 +++++++++++++++++ repository/filepicker.js | 6 ++- repository/lib.php | 5 --- theme/boost/amd/build/drawer.min.js | 2 +- theme/boost/amd/build/drawer.min.js.map | 2 +- theme/boost/amd/build/drawers.min.js | 2 +- theme/boost/amd/build/drawers.min.js.map | 2 +- theme/boost/amd/src/drawer.js | 14 +++--- theme/boost/amd/src/drawers.js | 5 ++- theme/boost/layout/drawers.php | 3 -- theme/boost/lib.php | 22 +++++++++ user/selector/lib.php | 1 - user/selector/module.js | 4 +- 21 files changed, 180 insertions(+), 38 deletions(-) create mode 100644 question/bank/previewquestion/lib.php diff --git a/blocks/settings/block_settings.php b/blocks/settings/block_settings.php index e6d9c65079c..226d6870ed8 100644 --- a/blocks/settings/block_settings.php +++ b/blocks/settings/block_settings.php @@ -141,10 +141,6 @@ class block_settings extends block_base { } else { $this->content->footer = ''; } - - if (!empty($this->config->enabledock) && $this->config->enabledock == 'yes') { - user_preference_allow_ajax_update('nav_in_tab_panel_settingsnav'.block_settings::$navcount, PARAM_INT); - } } $this->contentgenerated = true; diff --git a/lib/classes/user.php b/lib/classes/user.php index 98a03f080ff..7fa691bb1a2 100644 --- a/lib/classes/user.php +++ b/lib/classes/user.php @@ -979,6 +979,60 @@ class core_user { 'permissioncallback' => function($user, $preferencename) { return self::is_current_user($user) && has_capability('moodle/blog:view', context_system::instance()); }); + $preferences['filemanager_recentviewmode'] = [ + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 1, + 'choices' => [1, 2, 3], + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['filepicker_recentrepository'] = [ + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['filepicker_recentlicense'] = [ + 'type' => PARAM_SAFEDIR, + 'null' => NULL_NOT_ALLOWED, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['filepicker_recentviewmode'] = [ + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 1, + 'choices' => [1, 2, 3], + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['userselector_optionscollapsed'] = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => true, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['userselector_autoselectunique'] = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['userselector_preserveselected'] = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['userselector_searchanywhere'] = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; + $preferences['question_bank_advanced_search'] = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [static::class, 'is_current_user'], + ]; $choices = [HOMEPAGE_SITE]; if (!empty($CFG->enabledashboard)) { diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js index 6c1ad93a281..e83f9f63feb 100644 --- a/lib/form/filemanager.js +++ b/lib/form/filemanager.js @@ -1218,8 +1218,10 @@ M.form_filemanager.init = function(Y, options) { }, set_preference: function(name, value) { if (this.userprefs[name] != value) { - M.util.set_user_preference('filemanager_' + name, value); - this.userprefs[name] = value; + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference('filemanager_' + name, value); + this.userprefs[name] = value; + }.bind(this)); } }, }); diff --git a/lib/form/filemanager.php b/lib/form/filemanager.php index e333111d683..79473a89a50 100644 --- a/lib/form/filemanager.php +++ b/lib/form/filemanager.php @@ -453,7 +453,6 @@ class form_filemanager implements renderable { $this->options->userprefs = array(); $this->options->userprefs['recentviewmode'] = get_user_preferences('filemanager_recentviewmode', ''); - user_preference_allow_ajax_update('filemanager_recentviewmode', PARAM_INT); // building file picker options $params = new stdClass(); diff --git a/lib/javascript-static.js b/lib/javascript-static.js index cf790b6dbfb..97b8c6f01a0 100644 --- a/lib/javascript-static.js +++ b/lib/javascript-static.js @@ -160,7 +160,9 @@ M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) { animation.set('reverse', this.div.hasClass('collapsed')); // Update the user preference. if (this.userpref) { - M.util.set_user_preference(this.userpref, !this.div.hasClass('collapsed')); + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference(this.userpref, !this.div.hasClass('collapsed')); + }.bind(this)); } animation.run(); }, this, animation); @@ -577,7 +579,9 @@ M.util.init_block_hider = function(Y, config) { } }, updateState : function(e, hide) { - M.util.set_user_preference(this.get('preference'), hide); + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference(this.get('preference'), hide); + }.bind(this)); if (hide) { this.get('block').addClass('hidden'); this.get('block').one('.block-hider-show').focus(); diff --git a/lib/weblib.php b/lib/weblib.php index 616caf29e04..ab4c9031653 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -2560,7 +2560,6 @@ function print_collapsible_region_start($classes, $id, $caption, $userpref = '', // Work out the initial state. if (!empty($userpref) and is_string($userpref)) { - user_preference_allow_ajax_update($userpref, PARAM_BOOL); $collapsed = get_user_preferences($userpref, $default); } else { $collapsed = $default; diff --git a/mod/assign/classes/output/grading_app.php b/mod/assign/classes/output/grading_app.php index 2770beee0b1..647f1a81a0a 100644 --- a/mod/assign/classes/output/grading_app.php +++ b/mod/assign/classes/output/grading_app.php @@ -72,9 +72,6 @@ class grading_app implements templatable, renderable { $this->userid = $userid; $this->groupid = $groupid; $this->assignment = $assignment; - user_preference_allow_ajax_update('assign_filter', PARAM_ALPHA); - user_preference_allow_ajax_update('assign_workflowfilter', PARAM_ALPHA); - user_preference_allow_ajax_update('assign_markerfilter', PARAM_ALPHANUMEXT); $this->participants = $assignment->list_participants_with_filter_status_and_group($groupid); if (!$this->userid && count($this->participants)) { $this->userid = reset($this->participants)->id; diff --git a/mod/workshop/lib.php b/mod/workshop/lib.php index e56a2ef4ffd..0ace939303c 100644 --- a/mod/workshop/lib.php +++ b/mod/workshop/lib.php @@ -2252,6 +2252,38 @@ function workshop_get_coursemodule_info($coursemodule) { return $result; } +/** + * Get the current user preferences that are available + * + * @return array[] + */ +function mod_workshop_user_preferences(): array { + $preferencedefinition = [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [core_user::class, 'is_current_user'], + ]; + + return [ + 'workshop-viewlet-allexamples-collapsed' => $preferencedefinition, + 'workshop-viewlet-allsubmissions-collapsed' => $preferencedefinition, + 'workshop-viewlet-assessmentform-collapsed' => $preferencedefinition, + 'workshop-viewlet-assignedassessments-collapsed' => $preferencedefinition, + 'workshop-viewlet-cleargrades-collapsed' => $preferencedefinition, + 'workshop-viewlet-conclusion-collapsed' => $preferencedefinition, + 'workshop-viewlet-examples-collapsed' => $preferencedefinition, + 'workshop-viewlet-examplesfail-collapsed' => $preferencedefinition, + 'workshop-viewlet-gradereport-collapsed' => $preferencedefinition, + 'workshop-viewlet-instructauthors-collapsed' => $preferencedefinition, + 'workshop-viewlet-instructreviewers-collapsed' => $preferencedefinition, + 'workshop-viewlet-intro-collapsed' => $preferencedefinition, + 'workshop-viewlet-ownsubmission-collapsed' => $preferencedefinition, + 'workshop-viewlet-publicsubmissions-collapsed' => $preferencedefinition, + 'workshop-viewlet-yourgrades-collapsed' => $preferencedefinition, + ]; +} + /** * Callback to fetch the activity event type lang string. * diff --git a/question/bank/previewquestion/lib.php b/question/bank/previewquestion/lib.php new file mode 100644 index 00000000000..db26aaca73b --- /dev/null +++ b/question/bank/previewquestion/lib.php @@ -0,0 +1,41 @@ +. + +/** + * Callback methods for preview question component + * + * @package qbank_previewquestion + * @copyright 2023 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +declare(strict_types=1); + +/** + * Get the current user preferences that are available + * + * @return array[] + */ +function qbank_previewquestion_user_preferences(): array { + return [ + 'core_question_preview_techinfo_collapsed' => [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => true, + 'permissioncallback' => [core_user::class, 'is_current_user'], + ], + ]; +} diff --git a/repository/filepicker.js b/repository/filepicker.js index 27b3da610a3..156d597f7bf 100644 --- a/repository/filepicker.js +++ b/repository/filepicker.js @@ -2125,8 +2125,10 @@ M.core_filepicker.init = function(Y, options) { }, set_preference: function(name, value) { if (this.options.userprefs[name] != value) { - M.util.set_user_preference('filepicker_' + name, value); - this.options.userprefs[name] = value; + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference('filepicker_' + name, value); + this.options.userprefs[name] = value; + }.bind(this)); } }, in_iframe: function () { diff --git a/repository/lib.php b/repository/lib.php index 978d4abebab..3bbdfffbf3a 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -3190,11 +3190,6 @@ function initialise_filepicker($args) { $return->userprefs['recentlicense'] = get_user_preferences('filepicker_recentlicense', ''); $return->userprefs['recentviewmode'] = get_user_preferences('filepicker_recentviewmode', ''); - user_preference_allow_ajax_update('filepicker_recentrepository', PARAM_INT); - user_preference_allow_ajax_update('filepicker_recentlicense', PARAM_SAFEDIR); - user_preference_allow_ajax_update('filepicker_recentviewmode', PARAM_INT); - - // provided by form element $return->accepted_types = file_get_typegroup('extension', $args->accepted_types); $return->return_types = $args->return_types; diff --git a/theme/boost/amd/build/drawer.min.js b/theme/boost/amd/build/drawer.min.js index 837aee47fe0..ae92935021e 100644 --- a/theme/boost/amd/build/drawer.min.js +++ b/theme/boost/amd/build/drawer.min.js @@ -5,6 +5,6 @@ * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("theme_boost/drawer",["jquery","core/custom_interaction_events","core/log","core/pubsub","core/aria"],(function($,CustomEvents,Log,PubSub,Aria){var SELECTORS_TOGGLE_REGION='[data-region="drawer-toggle"]',SELECTORS_TOGGLE_ACTION='[data-action="toggle-drawer"]',SELECTORS_BODY="body",SELECTORS_SECTION='.list-group-item[href*="#section-"]',SELECTORS_DRAWER="#nav-drawer",small=$(document).width()<768,Drawer=function(){$(SELECTORS_TOGGLE_REGION).length||Log.debug("Page is missing a drawer region"),$(SELECTORS_TOGGLE_ACTION).length||Log.debug("Page is missing a drawer toggle link"),$(SELECTORS_TOGGLE_REGION).each(function(index,ele){var trigger=$(ele).find(SELECTORS_TOGGLE_ACTION),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),hidden="false"==trigger.attr("aria-expanded"),side=trigger.attr("data-side"),body=$(SELECTORS_BODY),preference=trigger.attr("data-preference");small&&M.util.set_user_preference(preference,"false"),drawer.on("mousewheel DOMMouseScroll",this.preventPageScroll),hidden?trigger.attr("aria-expanded","false"):(body.addClass("drawer-open-"+side),trigger.attr("aria-expanded","true"))}.bind(this)),this.registerEventListeners(),small&&this.closeAll()};return Drawer.prototype.closeAll=function(){$(SELECTORS_TOGGLE_REGION).each((function(index,ele){var trigger=$(ele).find(SELECTORS_TOGGLE_ACTION),side=trigger.attr("data-side"),body=$(SELECTORS_BODY),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),preference=trigger.attr("data-preference");trigger.attr("aria-expanded","false"),body.removeClass("drawer-open-"+side),Aria.hide(drawer.get()),drawer.addClass("closed"),small||M.util.set_user_preference(preference,"false")}))},Drawer.prototype.toggleDrawer=function(e){var trigger=$(e.target).closest("[data-action=toggle-drawer]"),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),body=$(SELECTORS_BODY),side=trigger.attr("data-side"),preference=trigger.attr("data-preference");small&&M.util.set_user_preference(preference,"false"),body.addClass("drawer-ease");var open="true"==trigger.attr("aria-expanded");open?(body.removeClass("drawer-open-"+side),trigger.attr("aria-expanded","false"),drawer.addClass("closed").delay(500).queue((function(){$(this).hasClass("closed")&&Aria.hide(this),$(this).dequeue()})),small||M.util.set_user_preference(preference,"false")):(trigger.attr("aria-expanded","true"),Aria.unhide(drawer.get()),drawer.focus(),body.addClass("drawer-open-"+side),drawer.removeClass("closed"),small||M.util.set_user_preference(preference,"true")),PubSub.publish("nav-drawer-toggle-start",open)},Drawer.prototype.preventPageScroll=function(e){var delta=e.wheelDelta||e.originalEvent&&e.originalEvent.wheelDelta||-e.originalEvent.detail,bottomOverflow=this.scrollTop+$(this).outerHeight()-this.scrollHeight>=0,topOverflow=this.scrollTop<=0;(delta<0&&bottomOverflow||delta>0&&topOverflow)&&e.preventDefault()},Drawer.prototype.registerEventListeners=function(){$(SELECTORS_TOGGLE_ACTION).each(function(index,element){CustomEvents.define($(element),[CustomEvents.events.activate]),$(element).on(CustomEvents.events.activate,function(e,data){this.toggleDrawer(data.originalEvent),data.originalEvent.preventDefault()}.bind(this))}.bind(this)),$(SELECTORS_SECTION).click(function(){small&&this.closeAll()}.bind(this)),$(SELECTORS_DRAWER).on("webkitTransitionEnd msTransitionEnd transitionend",(function(e){var open=!!$(e.target).closest(SELECTORS_DRAWER).attr("aria-hidden");PubSub.publish("nav-drawer-toggle-end",open)}))},{init:function(){return new Drawer}}})); +define("theme_boost/drawer",["jquery","core/custom_interaction_events","core/log","core/pubsub","core/aria","core_user/repository"],(function($,CustomEvents,Log,PubSub,Aria,UserRepository){var SELECTORS_TOGGLE_REGION='[data-region="drawer-toggle"]',SELECTORS_TOGGLE_ACTION='[data-action="toggle-drawer"]',SELECTORS_BODY="body",SELECTORS_SECTION='.list-group-item[href*="#section-"]',SELECTORS_DRAWER="#nav-drawer",small=$(document).width()<768,Drawer=function(){$(SELECTORS_TOGGLE_REGION).length||Log.debug("Page is missing a drawer region"),$(SELECTORS_TOGGLE_ACTION).length||Log.debug("Page is missing a drawer toggle link"),$(SELECTORS_TOGGLE_REGION).each(function(index,ele){var trigger=$(ele).find(SELECTORS_TOGGLE_ACTION),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),hidden="false"==trigger.attr("aria-expanded"),side=trigger.attr("data-side"),body=$(SELECTORS_BODY),preference=trigger.attr("data-preference");small&&UserRepository.setUserPreference(preference,!1),drawer.on("mousewheel DOMMouseScroll",this.preventPageScroll),hidden?trigger.attr("aria-expanded","false"):(body.addClass("drawer-open-"+side),trigger.attr("aria-expanded","true"))}.bind(this)),this.registerEventListeners(),small&&this.closeAll()};return Drawer.prototype.closeAll=function(){$(SELECTORS_TOGGLE_REGION).each((function(index,ele){var trigger=$(ele).find(SELECTORS_TOGGLE_ACTION),side=trigger.attr("data-side"),body=$(SELECTORS_BODY),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),preference=trigger.attr("data-preference");trigger.attr("aria-expanded","false"),body.removeClass("drawer-open-"+side),Aria.hide(drawer.get()),drawer.addClass("closed"),small||UserRepository.setUserPreference(preference,!1)}))},Drawer.prototype.toggleDrawer=function(e){var trigger=$(e.target).closest("[data-action=toggle-drawer]"),drawerid=trigger.attr("aria-controls"),drawer=$(document.getElementById(drawerid)),body=$(SELECTORS_BODY),side=trigger.attr("data-side"),preference=trigger.attr("data-preference");small&&UserRepository.setUserPreference(preference,!1),body.addClass("drawer-ease");var open="true"==trigger.attr("aria-expanded");open?(body.removeClass("drawer-open-"+side),trigger.attr("aria-expanded","false"),drawer.addClass("closed").delay(500).queue((function(){$(this).hasClass("closed")&&Aria.hide(this),$(this).dequeue()})),small||UserRepository.setUserPreference(preference,!1)):(trigger.attr("aria-expanded","true"),Aria.unhide(drawer.get()),drawer.focus(),body.addClass("drawer-open-"+side),drawer.removeClass("closed"),small||UserRepository.setUserPreference(preference,!0)),PubSub.publish("nav-drawer-toggle-start",open)},Drawer.prototype.preventPageScroll=function(e){var delta=e.wheelDelta||e.originalEvent&&e.originalEvent.wheelDelta||-e.originalEvent.detail,bottomOverflow=this.scrollTop+$(this).outerHeight()-this.scrollHeight>=0,topOverflow=this.scrollTop<=0;(delta<0&&bottomOverflow||delta>0&&topOverflow)&&e.preventDefault()},Drawer.prototype.registerEventListeners=function(){$(SELECTORS_TOGGLE_ACTION).each(function(index,element){CustomEvents.define($(element),[CustomEvents.events.activate]),$(element).on(CustomEvents.events.activate,function(e,data){this.toggleDrawer(data.originalEvent),data.originalEvent.preventDefault()}.bind(this))}.bind(this)),$(SELECTORS_SECTION).click(function(){small&&this.closeAll()}.bind(this)),$(SELECTORS_DRAWER).on("webkitTransitionEnd msTransitionEnd transitionend",(function(e){var open=!!$(e.target).closest(SELECTORS_DRAWER).attr("aria-hidden");PubSub.publish("nav-drawer-toggle-end",open)}))},{init:function(){return new Drawer}}})); //# sourceMappingURL=drawer.min.js.map \ No newline at end of file diff --git a/theme/boost/amd/build/drawer.min.js.map b/theme/boost/amd/build/drawer.min.js.map index 35378d79a5d..07846008ffe 100644 --- a/theme/boost/amd/build/drawer.min.js.map +++ b/theme/boost/amd/build/drawer.min.js.map @@ -1 +1 @@ -{"version":3,"file":"drawer.min.js","sources":["../src/drawer.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 .\n\n/**\n * Contain the logic for a drawer.\n *\n * @module theme_boost/drawer\n * @copyright 2016 Damyon Wiese\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', 'core/aria'],\n function($, CustomEvents, Log, PubSub, Aria) {\n\n var SELECTORS = {\n TOGGLE_REGION: '[data-region=\"drawer-toggle\"]',\n TOGGLE_ACTION: '[data-action=\"toggle-drawer\"]',\n TOGGLE_TARGET: 'aria-controls',\n TOGGLE_SIDE: 'left',\n BODY: 'body',\n SECTION: '.list-group-item[href*=\"#section-\"]',\n DRAWER: '#nav-drawer'\n };\n\n var small = $(document).width() < 768;\n\n /**\n * Constructor for the Drawer.\n */\n var Drawer = function() {\n\n if (!$(SELECTORS.TOGGLE_REGION).length) {\n Log.debug('Page is missing a drawer region');\n }\n if (!$(SELECTORS.TOGGLE_ACTION).length) {\n Log.debug('Page is missing a drawer toggle link');\n }\n $(SELECTORS.TOGGLE_REGION).each(function(index, ele) {\n var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION);\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var hidden = trigger.attr('aria-expanded') == 'false';\n var side = trigger.attr('data-side');\n var body = $(SELECTORS.BODY);\n var preference = trigger.attr('data-preference');\n if (small) {\n M.util.set_user_preference(preference, 'false');\n }\n\n drawer.on('mousewheel DOMMouseScroll', this.preventPageScroll);\n\n if (!hidden) {\n body.addClass('drawer-open-' + side);\n trigger.attr('aria-expanded', 'true');\n } else {\n trigger.attr('aria-expanded', 'false');\n }\n }.bind(this));\n\n this.registerEventListeners();\n if (small) {\n this.closeAll();\n }\n };\n\n Drawer.prototype.closeAll = function() {\n $(SELECTORS.TOGGLE_REGION).each(function(index, ele) {\n var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION);\n var side = trigger.attr('data-side');\n var body = $(SELECTORS.BODY);\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var preference = trigger.attr('data-preference');\n\n trigger.attr('aria-expanded', 'false');\n body.removeClass('drawer-open-' + side);\n Aria.hide(drawer.get());\n drawer.addClass('closed');\n if (!small) {\n M.util.set_user_preference(preference, 'false');\n }\n });\n };\n\n /**\n * Open / close the blocks drawer.\n *\n * @method toggleDrawer\n * @param {Event} e\n */\n Drawer.prototype.toggleDrawer = function(e) {\n var trigger = $(e.target).closest('[data-action=toggle-drawer]');\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var body = $(SELECTORS.BODY);\n var side = trigger.attr('data-side');\n var preference = trigger.attr('data-preference');\n if (small) {\n M.util.set_user_preference(preference, 'false');\n }\n\n body.addClass('drawer-ease');\n var open = trigger.attr('aria-expanded') == 'true';\n if (!open) {\n // Open.\n trigger.attr('aria-expanded', 'true');\n Aria.unhide(drawer.get());\n drawer.focus();\n body.addClass('drawer-open-' + side);\n drawer.removeClass('closed');\n if (!small) {\n M.util.set_user_preference(preference, 'true');\n }\n } else {\n // Close.\n body.removeClass('drawer-open-' + side);\n trigger.attr('aria-expanded', 'false');\n drawer.addClass('closed').delay(500).queue(function() {\n // Ensure that during the delay, the drawer wasn't re-opened.\n if ($(this).hasClass('closed')) {\n Aria.hide(this);\n }\n $(this).dequeue();\n });\n if (!small) {\n M.util.set_user_preference(preference, 'false');\n }\n }\n\n // Publish an event to tell everything that the drawer has been toggled.\n // The drawer transitions closed so another event will fire once teh transition\n // has completed.\n PubSub.publish('nav-drawer-toggle-start', open);\n };\n\n /**\n * Prevent the page from scrolling when the drawer is at max scroll.\n *\n * @method preventPageScroll\n * @param {Event} e\n */\n Drawer.prototype.preventPageScroll = function(e) {\n var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail,\n bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0,\n topOverflow = this.scrollTop <= 0;\n\n if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {\n e.preventDefault();\n }\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n Drawer.prototype.registerEventListeners = function() {\n\n $(SELECTORS.TOGGLE_ACTION).each(function(index, element) {\n CustomEvents.define($(element), [CustomEvents.events.activate]);\n $(element).on(CustomEvents.events.activate, function(e, data) {\n this.toggleDrawer(data.originalEvent);\n data.originalEvent.preventDefault();\n }.bind(this));\n }.bind(this));\n\n $(SELECTORS.SECTION).click(function() {\n if (small) {\n this.closeAll();\n }\n }.bind(this));\n\n // Publish an event to tell everything that the drawer completed the transition\n // to either an open or closed state.\n $(SELECTORS.DRAWER).on('webkitTransitionEnd msTransitionEnd transitionend', function(e) {\n var drawer = $(e.target).closest(SELECTORS.DRAWER);\n // Note: aria-hidden is either present, or absent. It should not be set to false.\n var open = !!drawer.attr('aria-hidden');\n PubSub.publish('nav-drawer-toggle-end', open);\n });\n };\n\n return {\n 'init': function() {\n return new Drawer();\n }\n };\n});\n"],"names":["define","$","CustomEvents","Log","PubSub","Aria","SELECTORS","small","document","width","Drawer","length","debug","each","index","ele","trigger","find","drawerid","attr","drawer","getElementById","hidden","side","body","preference","M","util","set_user_preference","on","this","preventPageScroll","addClass","bind","registerEventListeners","closeAll","prototype","removeClass","hide","get","toggleDrawer","e","target","closest","open","delay","queue","hasClass","dequeue","unhide","focus","publish","delta","wheelDelta","originalEvent","detail","bottomOverflow","scrollTop","outerHeight","scrollHeight","topOverflow","preventDefault","element","events","activate","data","click"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"drawer.min.js","sources":["../src/drawer.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 .\n\n/**\n * Contain the logic for a drawer.\n *\n * @module theme_boost/drawer\n * @copyright 2016 Damyon Wiese\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', 'core/aria', 'core_user/repository'],\n function($, CustomEvents, Log, PubSub, Aria, UserRepository) {\n\n var SELECTORS = {\n TOGGLE_REGION: '[data-region=\"drawer-toggle\"]',\n TOGGLE_ACTION: '[data-action=\"toggle-drawer\"]',\n TOGGLE_TARGET: 'aria-controls',\n TOGGLE_SIDE: 'left',\n BODY: 'body',\n SECTION: '.list-group-item[href*=\"#section-\"]',\n DRAWER: '#nav-drawer'\n };\n\n var small = $(document).width() < 768;\n\n /**\n * Constructor for the Drawer.\n */\n var Drawer = function() {\n\n if (!$(SELECTORS.TOGGLE_REGION).length) {\n Log.debug('Page is missing a drawer region');\n }\n if (!$(SELECTORS.TOGGLE_ACTION).length) {\n Log.debug('Page is missing a drawer toggle link');\n }\n $(SELECTORS.TOGGLE_REGION).each(function(index, ele) {\n var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION);\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var hidden = trigger.attr('aria-expanded') == 'false';\n var side = trigger.attr('data-side');\n var body = $(SELECTORS.BODY);\n var preference = trigger.attr('data-preference');\n if (small) {\n UserRepository.setUserPreference(preference, false);\n }\n\n drawer.on('mousewheel DOMMouseScroll', this.preventPageScroll);\n\n if (!hidden) {\n body.addClass('drawer-open-' + side);\n trigger.attr('aria-expanded', 'true');\n } else {\n trigger.attr('aria-expanded', 'false');\n }\n }.bind(this));\n\n this.registerEventListeners();\n if (small) {\n this.closeAll();\n }\n };\n\n Drawer.prototype.closeAll = function() {\n $(SELECTORS.TOGGLE_REGION).each(function(index, ele) {\n var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION);\n var side = trigger.attr('data-side');\n var body = $(SELECTORS.BODY);\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var preference = trigger.attr('data-preference');\n\n trigger.attr('aria-expanded', 'false');\n body.removeClass('drawer-open-' + side);\n Aria.hide(drawer.get());\n drawer.addClass('closed');\n if (!small) {\n UserRepository.setUserPreference(preference, false);\n }\n });\n };\n\n /**\n * Open / close the blocks drawer.\n *\n * @method toggleDrawer\n * @param {Event} e\n */\n Drawer.prototype.toggleDrawer = function(e) {\n var trigger = $(e.target).closest('[data-action=toggle-drawer]');\n var drawerid = trigger.attr('aria-controls');\n var drawer = $(document.getElementById(drawerid));\n var body = $(SELECTORS.BODY);\n var side = trigger.attr('data-side');\n var preference = trigger.attr('data-preference');\n if (small) {\n UserRepository.setUserPreference(preference, false);\n }\n\n body.addClass('drawer-ease');\n var open = trigger.attr('aria-expanded') == 'true';\n if (!open) {\n // Open.\n trigger.attr('aria-expanded', 'true');\n Aria.unhide(drawer.get());\n drawer.focus();\n body.addClass('drawer-open-' + side);\n drawer.removeClass('closed');\n if (!small) {\n UserRepository.setUserPreference(preference, true);\n }\n } else {\n // Close.\n body.removeClass('drawer-open-' + side);\n trigger.attr('aria-expanded', 'false');\n drawer.addClass('closed').delay(500).queue(function() {\n // Ensure that during the delay, the drawer wasn't re-opened.\n if ($(this).hasClass('closed')) {\n Aria.hide(this);\n }\n $(this).dequeue();\n });\n if (!small) {\n UserRepository.setUserPreference(preference, false);\n }\n }\n\n // Publish an event to tell everything that the drawer has been toggled.\n // The drawer transitions closed so another event will fire once teh transition\n // has completed.\n PubSub.publish('nav-drawer-toggle-start', open);\n };\n\n /**\n * Prevent the page from scrolling when the drawer is at max scroll.\n *\n * @method preventPageScroll\n * @param {Event} e\n */\n Drawer.prototype.preventPageScroll = function(e) {\n var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail,\n bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0,\n topOverflow = this.scrollTop <= 0;\n\n if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {\n e.preventDefault();\n }\n };\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n Drawer.prototype.registerEventListeners = function() {\n\n $(SELECTORS.TOGGLE_ACTION).each(function(index, element) {\n CustomEvents.define($(element), [CustomEvents.events.activate]);\n $(element).on(CustomEvents.events.activate, function(e, data) {\n this.toggleDrawer(data.originalEvent);\n data.originalEvent.preventDefault();\n }.bind(this));\n }.bind(this));\n\n $(SELECTORS.SECTION).click(function() {\n if (small) {\n this.closeAll();\n }\n }.bind(this));\n\n // Publish an event to tell everything that the drawer completed the transition\n // to either an open or closed state.\n $(SELECTORS.DRAWER).on('webkitTransitionEnd msTransitionEnd transitionend', function(e) {\n var drawer = $(e.target).closest(SELECTORS.DRAWER);\n // Note: aria-hidden is either present, or absent. It should not be set to false.\n var open = !!drawer.attr('aria-hidden');\n PubSub.publish('nav-drawer-toggle-end', open);\n });\n };\n\n return {\n 'init': function() {\n return new Drawer();\n }\n };\n});\n"],"names":["define","$","CustomEvents","Log","PubSub","Aria","UserRepository","SELECTORS","small","document","width","Drawer","length","debug","each","index","ele","trigger","find","drawerid","attr","drawer","getElementById","hidden","side","body","preference","setUserPreference","on","this","preventPageScroll","addClass","bind","registerEventListeners","closeAll","prototype","removeClass","hide","get","toggleDrawer","e","target","closest","open","delay","queue","hasClass","dequeue","unhide","focus","publish","delta","wheelDelta","originalEvent","detail","bottomOverflow","scrollTop","outerHeight","scrollHeight","topOverflow","preventDefault","element","events","activate","data","click"],"mappings":"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"} \ No newline at end of file diff --git a/theme/boost/amd/build/drawers.min.js b/theme/boost/amd/build/drawers.min.js index 2bdb9344b33..359f25e64d2 100644 --- a/theme/boost/amd/build/drawers.min.js +++ b/theme/boost/amd/build/drawers.min.js @@ -1,3 +1,3 @@ -define("theme_boost/drawers",["exports","core/modal_backdrop","core/templates","core/aria","core/event_dispatcher","core/utils","core/pagehelpers","core/pending","jquery"],(function(_exports,_modal_backdrop,_templates,Aria,_event_dispatcher,_utils,_pagehelpers,_pending,_jquery){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal_backdrop=_interopRequireDefault(_modal_backdrop),_templates=_interopRequireDefault(_templates),Aria=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Aria),_pending=_interopRequireDefault(_pending),_jquery=_interopRequireDefault(_jquery);let backdropPromise=null;const drawerMap=new Map,SELECTORS_BUTTONS='[data-toggler="drawers"]',SELECTORS_CLOSEBTN='[data-toggler="drawers"][data-action="closedrawer"]',SELECTORS_OPENBTN='[data-toggler="drawers"][data-action="opendrawer"]',SELECTORS_TOGGLEBTN='[data-toggler="drawers"][data-action="toggle"]',SELECTORS_DRAWERS='[data-region="fixed-drawer"]',SELECTORS_DRAWERCONTENT=".drawercontent",SELECTORS_PAGECONTENT="#page-content",CLASSES_SCROLLED="scrolled",CLASSES_SHOW="show",CLASSES_NOTINITIALISED="not-initialized",getDrawerZIndex=()=>{const drawer=document.querySelector(SELECTORS_DRAWERS);return drawer?parseInt(window.getComputedStyle(drawer).zIndex,10):null},getBackdrop=()=>(backdropPromise||(backdropPromise=_templates.default.render("core/modal_backdrop",{}).then((html=>new _modal_backdrop.default(html))).then((modalBackdrop=>(getDrawerZIndex()&&modalBackdrop.setZIndex(getDrawerZIndex()-1),modalBackdrop.getAttachmentPoint().get(0).addEventListener("click",(e=>{e.preventDefault(),Drawers.closeAllDrawers()})),modalBackdrop))).catch()),backdropPromise),getDrawerOpenButton=drawerId=>{let openButton=document.querySelector("".concat(SELECTORS_OPENBTN,'[data-target="').concat(drawerId,'"]'));return openButton||(openButton=document.querySelector("".concat(SELECTORS_TOGGLEBTN,'[data-target="').concat(drawerId,'"]'))),openButton},disableDrawerTooltips=drawerNode=>{[drawerNode.querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&disableButtonTooltip(button)}))},disableButtonTooltip=(button,enableOnBlur)=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("disable"),button.setAttribute("title",button.dataset.originalTitle)):(button.dataset.disabledToggle=button.dataset.toggle,button.removeAttribute("data-toggle")),enableOnBlur&&(button.dataset.restoreTooltipOnBlur=!0)},enableButtonTooltip=button=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("enable"),button.removeAttribute("title")):button.dataset.disabledToggle&&(button.dataset.toggle=button.dataset.disabledToggle,(0,_jquery.default)(button).tooltip()),delete button.dataset.restoreTooltipOnBlur};class Drawers{constructor(drawerNode){_defineProperty(this,"drawerNode",null),_defineProperty(this,"boundingRect",null),void 0===drawerNode.dataset.behatFakeDrawer&&(this.drawerNode=drawerNode,(0,_pagehelpers.isSmall)()&&this.closeDrawer({focusOnOpenButton:!1,updatePreferences:!1}),this.drawerNode.classList.contains(CLASSES_SHOW)?this.openDrawer({focusOnCloseButton:!1}):1==this.drawerNode.dataset.forceopen?(0,_pagehelpers.isSmall)()||this.openDrawer({focusOnCloseButton:!1}):Aria.hide(this.drawerNode),(0,_pagehelpers.isSmall)()&&disableDrawerTooltips(this.drawerNode),(drawerNode=>{const content=drawerNode.querySelector(SELECTORS_DRAWERCONTENT);content&&content.addEventListener("scroll",(()=>{drawerNode.classList.toggle(CLASSES_SCROLLED,0!=content.scrollTop)}))})(this.drawerNode),drawerMap.set(drawerNode,this),drawerNode.classList.remove(CLASSES_NOTINITIALISED))}get isOpen(){return this.drawerNode.classList.contains(CLASSES_SHOW)}get closeOnResize(){return!!parseInt(this.drawerNode.dataset.closeOnResize)}static getDrawerInstanceForNode(drawerNode){return drawerMap.has(drawerNode)||new Drawers(drawerNode),drawerMap.get(drawerNode)}dispatchEvent(eventname){let cancelable=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_event_dispatcher.dispatchEvent)(eventname,{drawerInstance:this},this.drawerNode,{cancelable:cancelable})}openDrawer(){var _this$drawerNode$quer;let{focusOnCloseButton:focusOnCloseButton=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:open");if(this.dispatchEvent(Drawers.eventTypes.drawerShow,!0).defaultPrevented)return;null===(_this$drawerNode$quer=this.drawerNode.querySelector(SELECTORS_CLOSEBTN))||void 0===_this$drawerNode$quer||_this$drawerNode$quer.classList.toggle("hidden",!0);let openButton=getDrawerOpenButton(this.drawerNode.id);var _jQuery;openButton&&openButton.hasAttribute("data-original-title")&&(null===(_jQuery=(0,_jquery.default)(openButton))||void 0===_jQuery||_jQuery.tooltip("hide"));Aria.unhide(this.drawerNode),this.drawerNode.classList.add(CLASSES_SHOW);const preference=this.drawerNode.dataset.preference;preference&&!(0,_pagehelpers.isSmall)()&&1!=this.drawerNode.dataset.forceopen&&M.util.set_user_preference(preference,!0);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.add(state)}this.boundingRect=this.drawerNode.getBoundingClientRect(),(0,_pagehelpers.isSmall)()&&getBackdrop().then((backdrop=>{backdrop.show();return document.getElementById("page").style.overflow="hidden",backdrop})).catch();const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);focusOnCloseButton&&closeButton&&disableButtonTooltip(closeButton,!0),setTimeout((()=>{closeButton.classList.toggle("hidden",!1),focusOnCloseButton&&closeButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerShown)}closeDrawer(){let{focusOnOpenButton:focusOnOpenButton=!0,updatePreferences:updatePreferences=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:close");if(this.dispatchEvent(Drawers.eventTypes.drawerHide,!0).defaultPrevented)return;const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);var _jQuery2;(null==closeButton||closeButton.classList.toggle("hidden",!0),closeButton.hasAttribute("data-original-title"))&&(null===(_jQuery2=(0,_jquery.default)(closeButton))||void 0===_jQuery2||_jQuery2.tooltip("hide"));const preference=this.drawerNode.dataset.preference;preference&&updatePreferences&&!(0,_pagehelpers.isSmall)()&&M.util.set_user_preference(preference,!1);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.remove(state)}Aria.hide(this.drawerNode),this.drawerNode.classList.remove(CLASSES_SHOW),getBackdrop().then((backdrop=>{if(backdrop.hide(),(0,_pagehelpers.isSmall)()){document.getElementById("page").style.overflow="visible"}return backdrop})).catch();let openButton=getDrawerOpenButton(this.drawerNode.id);openButton&&disableButtonTooltip(openButton,!0),setTimeout((()=>{openButton&&focusOnOpenButton&&openButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerHidden)}toggleVisibility(){this.drawerNode.classList.contains(CLASSES_SHOW)?this.closeDrawer():this.openDrawer()}displace(scrollPosition){var _this$drawerNode$data;let displace=scrollPosition,openButton=getDrawerOpenButton(this.drawerNode.id);if(0===scrollPosition)return this.drawerNode.style.transform="",void(openButton&&(openButton.style.transform=""));const state=null===(_this$drawerNode$data=this.drawerNode.dataset)||void 0===_this$drawerNode$data?void 0:_this$drawerNode$data.state,drawrWidth=this.drawerNode.offsetWidth;let scrollThreshold=drawrWidth,direction=-1;"show-drawer-right"===state&&(direction=1,scrollThreshold=20),scrollPosition>scrollThreshold&&(displace=drawrWidth+20),displace*=direction;const transform="translateX(".concat(displace,"px)");openButton&&(openButton.style.transform=transform),this.drawerNode.style.transform=transform}preventOverlap(currentFocus){if(!this.isOpen)return;const drawrWidth=this.drawerNode.offsetWidth,element=currentFocus.getBoundingClientRect(),drawer=this.boundingRect;element.right+20>drawer.left&&element.left-20{drawerInstance.closeDrawer()}))}static closeOtherDrawers(comparisonInstance){drawerMap.forEach((drawerInstance=>{drawerInstance!==comparisonInstance&&drawerInstance.closeDrawer()}))}static preventCoveringFocusedElement(){const currentFocus=document.activeElement,pagecontent=document.querySelector(SELECTORS_PAGECONTENT);currentFocus&&null!=pagecontent&&pagecontent.contains(currentFocus)?drawerMap.forEach((drawerInstance=>{drawerInstance.preventOverlap(currentFocus)})):Drawers.displaceDrawers(window.scrollX)}static displaceDrawers(displace){drawerMap.forEach((drawerInstance=>{drawerInstance.displace(displace)}))}}_exports.default=Drawers,_defineProperty(Drawers,"eventTypes",{drawerShow:"theme_boost/drawers:show",drawerShown:"theme_boost/drawers:shown",drawerHide:"theme_boost/drawers:hide",drawerHidden:"theme_boost/drawers:hidden"});const setLastUsedToggle=toggleButton=>{toggleButton.dataset.target&&(document.querySelectorAll("".concat(SELECTORS_BUTTONS,'[data-target="').concat(toggleButton.dataset.target,'"]')).forEach((btn=>{btn.dataset.lastused=!1})),toggleButton.dataset.lastused=!0)};(()=>{document.addEventListener("click",(e=>{const toggleButton=e.target.closest(SELECTORS_TOGGLEBTN);if(toggleButton&&toggleButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(toggleButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.toggleVisibility()}const openDrawerButton=e.target.closest(SELECTORS_OPENBTN);if(openDrawerButton&&openDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(openDrawerButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.openDrawer()}const closeDrawerButton=e.target.closest(SELECTORS_CLOSEBTN);if(closeDrawerButton&&closeDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(closeDrawerButton.dataset.target);Drawers.getDrawerInstanceForNode(targetDrawer).closeDrawer(),(target=>{const lastUsedButton=document.querySelector("".concat(SELECTORS_BUTTONS,'[data-target="').concat(target,'"][data-lastused="true"'));lastUsedButton&&lastUsedButton.focus()})(closeDrawerButton.dataset.target)}})),document.addEventListener(Drawers.eventTypes.drawerShow,(e=>{(0,_pagehelpers.isLarge)()||Drawers.closeOtherDrawers(e.detail.drawerInstance)}));const btnSelector="".concat(SELECTORS_TOGGLEBTN,", ").concat(SELECTORS_OPENBTN,", ").concat(SELECTORS_CLOSEBTN);document.addEventListener("focusout",(e=>{const button=e.target.closest(btnSelector);void 0!==(null==button?void 0:button.dataset.restoreTooltipOnBlur)&&enableButtonTooltip(button)}));document.addEventListener("scroll",(()=>{const body=document.querySelector("body");window.scrollY>=window.innerHeight?body.classList.add(CLASSES_SCROLLED):body.classList.remove(CLASSES_SCROLLED),Drawers.displaceDrawers(window.scrollX)}));const preventOverlap=(0,_utils.debounce)(Drawers.preventCoveringFocusedElement,100);document.addEventListener("focusin",preventOverlap),document.addEventListener("focusout",preventOverlap),window.addEventListener("resize",(0,_utils.debounce)((()=>{if((0,_pagehelpers.isSmall)()){let anyOpen=!1;drawerMap.forEach((drawerInstance=>{disableDrawerTooltips(drawerInstance.drawerNode),drawerInstance.isOpen&&(drawerInstance.closeOnResize?drawerInstance.closeDrawer():anyOpen=!0)})),anyOpen&&getBackdrop().then((backdrop=>backdrop.show())).catch()}else drawerMap.forEach((drawerInstance=>{var drawerNode;[(drawerNode=drawerInstance.drawerNode).querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&enableButtonTooltip(button)}))})),getBackdrop().then((backdrop=>backdrop.hide())).catch()}),400))})();return document.querySelectorAll(SELECTORS_DRAWERS).forEach((drawerNode=>Drawers.getDrawerInstanceForNode(drawerNode))),_exports.default})); +define("theme_boost/drawers",["exports","core/modal_backdrop","core/templates","core/aria","core/event_dispatcher","core/utils","core/pagehelpers","core/pending","core_user/repository","jquery"],(function(_exports,_modal_backdrop,_templates,Aria,_event_dispatcher,_utils,_pagehelpers,_pending,_repository,_jquery){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal_backdrop=_interopRequireDefault(_modal_backdrop),_templates=_interopRequireDefault(_templates),Aria=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Aria),_pending=_interopRequireDefault(_pending),_jquery=_interopRequireDefault(_jquery);let backdropPromise=null;const drawerMap=new Map,SELECTORS_BUTTONS='[data-toggler="drawers"]',SELECTORS_CLOSEBTN='[data-toggler="drawers"][data-action="closedrawer"]',SELECTORS_OPENBTN='[data-toggler="drawers"][data-action="opendrawer"]',SELECTORS_TOGGLEBTN='[data-toggler="drawers"][data-action="toggle"]',SELECTORS_DRAWERS='[data-region="fixed-drawer"]',SELECTORS_DRAWERCONTENT=".drawercontent",SELECTORS_PAGECONTENT="#page-content",CLASSES_SCROLLED="scrolled",CLASSES_SHOW="show",CLASSES_NOTINITIALISED="not-initialized",getDrawerZIndex=()=>{const drawer=document.querySelector(SELECTORS_DRAWERS);return drawer?parseInt(window.getComputedStyle(drawer).zIndex,10):null},getBackdrop=()=>(backdropPromise||(backdropPromise=_templates.default.render("core/modal_backdrop",{}).then((html=>new _modal_backdrop.default(html))).then((modalBackdrop=>(getDrawerZIndex()&&modalBackdrop.setZIndex(getDrawerZIndex()-1),modalBackdrop.getAttachmentPoint().get(0).addEventListener("click",(e=>{e.preventDefault(),Drawers.closeAllDrawers()})),modalBackdrop))).catch()),backdropPromise),getDrawerOpenButton=drawerId=>{let openButton=document.querySelector("".concat(SELECTORS_OPENBTN,'[data-target="').concat(drawerId,'"]'));return openButton||(openButton=document.querySelector("".concat(SELECTORS_TOGGLEBTN,'[data-target="').concat(drawerId,'"]'))),openButton},disableDrawerTooltips=drawerNode=>{[drawerNode.querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&disableButtonTooltip(button)}))},disableButtonTooltip=(button,enableOnBlur)=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("disable"),button.setAttribute("title",button.dataset.originalTitle)):(button.dataset.disabledToggle=button.dataset.toggle,button.removeAttribute("data-toggle")),enableOnBlur&&(button.dataset.restoreTooltipOnBlur=!0)},enableButtonTooltip=button=>{button.hasAttribute("data-original-title")?((0,_jquery.default)(button).tooltip("enable"),button.removeAttribute("title")):button.dataset.disabledToggle&&(button.dataset.toggle=button.dataset.disabledToggle,(0,_jquery.default)(button).tooltip()),delete button.dataset.restoreTooltipOnBlur};class Drawers{constructor(drawerNode){_defineProperty(this,"drawerNode",null),_defineProperty(this,"boundingRect",null),void 0===drawerNode.dataset.behatFakeDrawer&&(this.drawerNode=drawerNode,(0,_pagehelpers.isSmall)()&&this.closeDrawer({focusOnOpenButton:!1,updatePreferences:!1}),this.drawerNode.classList.contains(CLASSES_SHOW)?this.openDrawer({focusOnCloseButton:!1}):1==this.drawerNode.dataset.forceopen?(0,_pagehelpers.isSmall)()||this.openDrawer({focusOnCloseButton:!1}):Aria.hide(this.drawerNode),(0,_pagehelpers.isSmall)()&&disableDrawerTooltips(this.drawerNode),(drawerNode=>{const content=drawerNode.querySelector(SELECTORS_DRAWERCONTENT);content&&content.addEventListener("scroll",(()=>{drawerNode.classList.toggle(CLASSES_SCROLLED,0!=content.scrollTop)}))})(this.drawerNode),drawerMap.set(drawerNode,this),drawerNode.classList.remove(CLASSES_NOTINITIALISED))}get isOpen(){return this.drawerNode.classList.contains(CLASSES_SHOW)}get closeOnResize(){return!!parseInt(this.drawerNode.dataset.closeOnResize)}static getDrawerInstanceForNode(drawerNode){return drawerMap.has(drawerNode)||new Drawers(drawerNode),drawerMap.get(drawerNode)}dispatchEvent(eventname){let cancelable=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return(0,_event_dispatcher.dispatchEvent)(eventname,{drawerInstance:this},this.drawerNode,{cancelable:cancelable})}openDrawer(){var _this$drawerNode$quer;let{focusOnCloseButton:focusOnCloseButton=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:open");if(this.dispatchEvent(Drawers.eventTypes.drawerShow,!0).defaultPrevented)return;null===(_this$drawerNode$quer=this.drawerNode.querySelector(SELECTORS_CLOSEBTN))||void 0===_this$drawerNode$quer||_this$drawerNode$quer.classList.toggle("hidden",!0);let openButton=getDrawerOpenButton(this.drawerNode.id);var _jQuery;openButton&&openButton.hasAttribute("data-original-title")&&(null===(_jQuery=(0,_jquery.default)(openButton))||void 0===_jQuery||_jQuery.tooltip("hide"));Aria.unhide(this.drawerNode),this.drawerNode.classList.add(CLASSES_SHOW);const preference=this.drawerNode.dataset.preference;preference&&!(0,_pagehelpers.isSmall)()&&1!=this.drawerNode.dataset.forceopen&&(0,_repository.setUserPreference)(preference,!0);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.add(state)}this.boundingRect=this.drawerNode.getBoundingClientRect(),(0,_pagehelpers.isSmall)()&&getBackdrop().then((backdrop=>{backdrop.show();return document.getElementById("page").style.overflow="hidden",backdrop})).catch();const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);focusOnCloseButton&&closeButton&&disableButtonTooltip(closeButton,!0),setTimeout((()=>{closeButton.classList.toggle("hidden",!1),focusOnCloseButton&&closeButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerShown)}closeDrawer(){let{focusOnOpenButton:focusOnOpenButton=!0,updatePreferences:updatePreferences=!0}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const pendingPromise=new _pending.default("theme_boost/drawers:close");if(this.dispatchEvent(Drawers.eventTypes.drawerHide,!0).defaultPrevented)return;const closeButton=this.drawerNode.querySelector(SELECTORS_CLOSEBTN);var _jQuery2;(null==closeButton||closeButton.classList.toggle("hidden",!0),closeButton.hasAttribute("data-original-title"))&&(null===(_jQuery2=(0,_jquery.default)(closeButton))||void 0===_jQuery2||_jQuery2.tooltip("hide"));const preference=this.drawerNode.dataset.preference;preference&&updatePreferences&&!(0,_pagehelpers.isSmall)()&&(0,_repository.setUserPreference)(preference,!1);const state=this.drawerNode.dataset.state;if(state){document.getElementById("page").classList.remove(state)}Aria.hide(this.drawerNode),this.drawerNode.classList.remove(CLASSES_SHOW),getBackdrop().then((backdrop=>{if(backdrop.hide(),(0,_pagehelpers.isSmall)()){document.getElementById("page").style.overflow="visible"}return backdrop})).catch();let openButton=getDrawerOpenButton(this.drawerNode.id);openButton&&disableButtonTooltip(openButton,!0),setTimeout((()=>{openButton&&focusOnOpenButton&&openButton.focus(),pendingPromise.resolve()}),300),this.dispatchEvent(Drawers.eventTypes.drawerHidden)}toggleVisibility(){this.drawerNode.classList.contains(CLASSES_SHOW)?this.closeDrawer():this.openDrawer()}displace(scrollPosition){var _this$drawerNode$data;let displace=scrollPosition,openButton=getDrawerOpenButton(this.drawerNode.id);if(0===scrollPosition)return this.drawerNode.style.transform="",void(openButton&&(openButton.style.transform=""));const state=null===(_this$drawerNode$data=this.drawerNode.dataset)||void 0===_this$drawerNode$data?void 0:_this$drawerNode$data.state,drawrWidth=this.drawerNode.offsetWidth;let scrollThreshold=drawrWidth,direction=-1;"show-drawer-right"===state&&(direction=1,scrollThreshold=20),scrollPosition>scrollThreshold&&(displace=drawrWidth+20),displace*=direction;const transform="translateX(".concat(displace,"px)");openButton&&(openButton.style.transform=transform),this.drawerNode.style.transform=transform}preventOverlap(currentFocus){if(!this.isOpen)return;const drawrWidth=this.drawerNode.offsetWidth,element=currentFocus.getBoundingClientRect(),drawer=this.boundingRect;element.right+20>drawer.left&&element.left-20{drawerInstance.closeDrawer()}))}static closeOtherDrawers(comparisonInstance){drawerMap.forEach((drawerInstance=>{drawerInstance!==comparisonInstance&&drawerInstance.closeDrawer()}))}static preventCoveringFocusedElement(){const currentFocus=document.activeElement,pagecontent=document.querySelector(SELECTORS_PAGECONTENT);currentFocus&&null!=pagecontent&&pagecontent.contains(currentFocus)?drawerMap.forEach((drawerInstance=>{drawerInstance.preventOverlap(currentFocus)})):Drawers.displaceDrawers(window.scrollX)}static displaceDrawers(displace){drawerMap.forEach((drawerInstance=>{drawerInstance.displace(displace)}))}}_exports.default=Drawers,_defineProperty(Drawers,"eventTypes",{drawerShow:"theme_boost/drawers:show",drawerShown:"theme_boost/drawers:shown",drawerHide:"theme_boost/drawers:hide",drawerHidden:"theme_boost/drawers:hidden"});const setLastUsedToggle=toggleButton=>{toggleButton.dataset.target&&(document.querySelectorAll("".concat(SELECTORS_BUTTONS,'[data-target="').concat(toggleButton.dataset.target,'"]')).forEach((btn=>{btn.dataset.lastused=!1})),toggleButton.dataset.lastused=!0)};(()=>{document.addEventListener("click",(e=>{const toggleButton=e.target.closest(SELECTORS_TOGGLEBTN);if(toggleButton&&toggleButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(toggleButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.toggleVisibility()}const openDrawerButton=e.target.closest(SELECTORS_OPENBTN);if(openDrawerButton&&openDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(openDrawerButton.dataset.target),drawerInstance=Drawers.getDrawerInstanceForNode(targetDrawer);setLastUsedToggle(toggleButton),drawerInstance.openDrawer()}const closeDrawerButton=e.target.closest(SELECTORS_CLOSEBTN);if(closeDrawerButton&&closeDrawerButton.dataset.target){e.preventDefault();const targetDrawer=document.getElementById(closeDrawerButton.dataset.target);Drawers.getDrawerInstanceForNode(targetDrawer).closeDrawer(),(target=>{const lastUsedButton=document.querySelector("".concat(SELECTORS_BUTTONS,'[data-target="').concat(target,'"][data-lastused="true"'));lastUsedButton&&lastUsedButton.focus()})(closeDrawerButton.dataset.target)}})),document.addEventListener(Drawers.eventTypes.drawerShow,(e=>{(0,_pagehelpers.isLarge)()||Drawers.closeOtherDrawers(e.detail.drawerInstance)}));const btnSelector="".concat(SELECTORS_TOGGLEBTN,", ").concat(SELECTORS_OPENBTN,", ").concat(SELECTORS_CLOSEBTN);document.addEventListener("focusout",(e=>{const button=e.target.closest(btnSelector);void 0!==(null==button?void 0:button.dataset.restoreTooltipOnBlur)&&enableButtonTooltip(button)}));document.addEventListener("scroll",(()=>{const body=document.querySelector("body");window.scrollY>=window.innerHeight?body.classList.add(CLASSES_SCROLLED):body.classList.remove(CLASSES_SCROLLED),Drawers.displaceDrawers(window.scrollX)}));const preventOverlap=(0,_utils.debounce)(Drawers.preventCoveringFocusedElement,100);document.addEventListener("focusin",preventOverlap),document.addEventListener("focusout",preventOverlap),window.addEventListener("resize",(0,_utils.debounce)((()=>{if((0,_pagehelpers.isSmall)()){let anyOpen=!1;drawerMap.forEach((drawerInstance=>{disableDrawerTooltips(drawerInstance.drawerNode),drawerInstance.isOpen&&(drawerInstance.closeOnResize?drawerInstance.closeDrawer():anyOpen=!0)})),anyOpen&&getBackdrop().then((backdrop=>backdrop.show())).catch()}else drawerMap.forEach((drawerInstance=>{var drawerNode;[(drawerNode=drawerInstance.drawerNode).querySelector(SELECTORS_CLOSEBTN),getDrawerOpenButton(drawerNode.id)].forEach((button=>{button&&enableButtonTooltip(button)}))})),getBackdrop().then((backdrop=>backdrop.hide())).catch()}),400))})();return document.querySelectorAll(SELECTORS_DRAWERS).forEach((drawerNode=>Drawers.getDrawerInstanceForNode(drawerNode))),_exports.default})); //# sourceMappingURL=drawers.min.js.map \ No newline at end of file diff --git a/theme/boost/amd/build/drawers.min.js.map b/theme/boost/amd/build/drawers.min.js.map index c46be7fe01c..f89ef522cb7 100644 --- a/theme/boost/amd/build/drawers.min.js.map +++ b/theme/boost/amd/build/drawers.min.js.map @@ -1 +1 @@ -{"version":3,"file":"drawers.min.js","sources":["../src/drawers.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 .\n\n/**\n * Toggling the visibility of the secondary navigation on mobile.\n *\n * @module theme_boost/drawers\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport ModalBackdrop from 'core/modal_backdrop';\nimport Templates from 'core/templates';\nimport * as Aria from 'core/aria';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport {debounce} from 'core/utils';\nimport {isSmall, isLarge} from 'core/pagehelpers';\nimport Pending from 'core/pending';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.\nimport jQuery from 'jquery';\n\nlet backdropPromise = null;\n\nconst drawerMap = new Map();\n\nconst SELECTORS = {\n BUTTONS: '[data-toggler=\"drawers\"]',\n CLOSEBTN: '[data-toggler=\"drawers\"][data-action=\"closedrawer\"]',\n OPENBTN: '[data-toggler=\"drawers\"][data-action=\"opendrawer\"]',\n TOGGLEBTN: '[data-toggler=\"drawers\"][data-action=\"toggle\"]',\n DRAWERS: '[data-region=\"fixed-drawer\"]',\n DRAWERCONTENT: '.drawercontent',\n PAGECONTENT: '#page-content',\n};\n\nconst CLASSES = {\n SCROLLED: 'scrolled',\n SHOW: 'show',\n NOTINITIALISED: 'not-initialized',\n};\n\n/**\n * Pixel thresshold to auto-hide drawers.\n *\n * @type {Number}\n */\nconst THRESHOLD = 20;\n\n/**\n * Try to get the drawer z-index from the page content.\n *\n * @returns {Number|null} the z-index of the drawer.\n * @private\n */\nconst getDrawerZIndex = () => {\n const drawer = document.querySelector(SELECTORS.DRAWERS);\n if (!drawer) {\n return null;\n }\n return parseInt(window.getComputedStyle(drawer).zIndex, 10);\n};\n\n/**\n * Add a backdrop to the page.\n *\n * @returns {Promise} rendering of modal backdrop.\n * @private\n */\nconst getBackdrop = () => {\n if (!backdropPromise) {\n backdropPromise = Templates.render('core/modal_backdrop', {})\n .then(html => new ModalBackdrop(html))\n .then(modalBackdrop => {\n const drawerZindex = getDrawerZIndex();\n if (drawerZindex) {\n modalBackdrop.setZIndex(getDrawerZIndex() - 1);\n }\n modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {\n e.preventDefault();\n Drawers.closeAllDrawers();\n });\n return modalBackdrop;\n })\n .catch();\n }\n return backdropPromise;\n};\n\n/**\n * Get the button element to open a specific drawer.\n *\n * @param {String} drawerId the drawer element Id\n * @return {HTMLElement|undefined} the open button element\n * @private\n */\nconst getDrawerOpenButton = (drawerId) => {\n let openButton = document.querySelector(`${SELECTORS.OPENBTN}[data-target=\"${drawerId}\"]`);\n if (!openButton) {\n openButton = document.querySelector(`${SELECTORS.TOGGLEBTN}[data-target=\"${drawerId}\"]`);\n }\n return openButton;\n};\n\n/**\n * Disable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst disableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n disableButtonTooltip(button);\n });\n};\n\n/**\n * Disable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.\n * @private\n */\nconst disableButtonTooltip = (button, enableOnBlur) => {\n if (button.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(button).tooltip('disable');\n button.setAttribute('title', button.dataset.originalTitle);\n } else {\n button.dataset.disabledToggle = button.dataset.toggle;\n button.removeAttribute('data-toggle');\n }\n if (enableOnBlur) {\n button.dataset.restoreTooltipOnBlur = true;\n }\n};\n\n/**\n * Enable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst enableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n enableButtonTooltip(button);\n });\n};\n\n/**\n * Enable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @private\n */\nconst enableButtonTooltip = (button) => {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n if (button.hasAttribute('data-original-title')) {\n jQuery(button).tooltip('enable');\n button.removeAttribute('title');\n } else if (button.dataset.disabledToggle) {\n button.dataset.toggle = button.dataset.disabledToggle;\n jQuery(button).tooltip();\n }\n delete button.dataset.restoreTooltipOnBlur;\n};\n\n/**\n * Add scroll listeners to a drawer element.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst addInnerScrollListener = (drawerNode) => {\n const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);\n if (!content) {\n return;\n }\n content.addEventListener(\"scroll\", () => {\n drawerNode.classList.toggle(\n CLASSES.SCROLLED,\n content.scrollTop != 0\n );\n });\n};\n\n/**\n * The Drawers class is used to control on-screen drawer elements.\n *\n * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when\n * another drawer is opened, and supports closing a drawer when the screen is resized.\n *\n * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,\n * or close button.\n *\n * A range of show and hide events are also dispatched as detailed in the class\n * {@link module:theme_boost/drawers#eventTypes eventTypes} object.\n *\n * @example Standard usage\n *\n * // The module just needs to be included to add drawer support.\n * import 'theme_boost/drawers';\n *\n * @example Manually open or close any drawer\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');\n * myDrawer.closeDrawer();\n *\n * @example Listen to the before show event and cancel it\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n * // The drawer which will be shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n *\n * // Prevent this drawer from being shown.\n * e.preventDefault();\n * });\n *\n * @example Listen to the shown event\n *\n * document.addEventListener(Drawers.eventTypes.drawerShown, e => {\n * // The drawer which was shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n * });\n */\nexport default class Drawers {\n /**\n * The underlying HTMLElement which is controlled.\n */\n drawerNode = null;\n\n /**\n * The drawer page bounding box dimensions.\n * @var {DOMRect} boundingRect\n */\n boundingRect = null;\n\n constructor(drawerNode) {\n // Some behat tests may use fake drawer divs to test components in drawers.\n if (drawerNode.dataset.behatFakeDrawer !== undefined) {\n return;\n }\n\n this.drawerNode = drawerNode;\n\n if (isSmall()) {\n this.closeDrawer({focusOnOpenButton: false, updatePreferences: false});\n }\n\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.openDrawer({focusOnCloseButton: false});\n } else if (this.drawerNode.dataset.forceopen == 1) {\n if (!isSmall()) {\n this.openDrawer({focusOnCloseButton: false});\n }\n } else {\n Aria.hide(this.drawerNode);\n }\n\n // Disable tooltips in small screens.\n if (isSmall()) {\n disableDrawerTooltips(this.drawerNode);\n }\n\n addInnerScrollListener(this.drawerNode);\n\n drawerMap.set(drawerNode, this);\n\n drawerNode.classList.remove(CLASSES.NOTINITIALISED);\n }\n\n /**\n * Whether the drawer is open.\n *\n * @returns {boolean}\n */\n get isOpen() {\n return this.drawerNode.classList.contains(CLASSES.SHOW);\n }\n\n /**\n * Whether the drawer should close when the window is resized\n *\n * @returns {boolean}\n */\n get closeOnResize() {\n return !!parseInt(this.drawerNode.dataset.closeOnResize);\n }\n\n /**\n * The list of event types.\n *\n * @static\n * @property {String} drawerShow See {@link event:theme_boost/drawers:show}\n * @property {String} drawerShown See {@link event:theme_boost/drawers:shown}\n * @property {String} drawerHide See {@link event:theme_boost/drawers:hide}\n * @property {String} drawerHidden See {@link event:theme_boost/drawers:hidden}\n */\n static eventTypes = {\n /**\n * An event triggered before a drawer is shown.\n *\n * @event theme_boost/drawers:show\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be opened.\n */\n drawerShow: 'theme_boost/drawers:show',\n\n /**\n * An event triggered after a drawer is shown.\n *\n * @event theme_boost/drawers:shown\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be opened.\n */\n drawerShown: 'theme_boost/drawers:shown',\n\n /**\n * An event triggered before a drawer is hidden.\n *\n * @event theme_boost/drawers:hide\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be hidden.\n */\n drawerHide: 'theme_boost/drawers:hide',\n\n /**\n * An event triggered after a drawer is hidden.\n *\n * @event theme_boost/drawers:hidden\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be hidden.\n */\n drawerHidden: 'theme_boost/drawers:hidden',\n };\n\n\n /**\n * Get the drawer instance for the specified node\n *\n * @param {HTMLElement} drawerNode\n * @returns {module:theme_boost/drawers}\n */\n static getDrawerInstanceForNode(drawerNode) {\n if (!drawerMap.has(drawerNode)) {\n new Drawers(drawerNode);\n }\n\n return drawerMap.get(drawerNode);\n }\n\n /**\n * Dispatch a drawer event.\n *\n * @param {string} eventname the event name\n * @param {boolean} cancelable if the event is cancelable\n * @returns {CustomEvent} the resulting custom event\n */\n dispatchEvent(eventname, cancelable = false) {\n return dispatchEvent(\n eventname,\n {\n drawerInstance: this,\n },\n this.drawerNode,\n {\n cancelable,\n }\n );\n }\n\n /**\n * Open the drawer.\n *\n * By default, openDrawer sets the page focus to the close drawer button. However, when a drawer is open at page\n * load, this represents an accessibility problem as the initial focus changes without any user interaction. The\n * focusOnCloseButton parameter can be set to false to prevent this behaviour.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer\n */\n openDrawer({focusOnCloseButton = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:open');\n const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);\n if (showEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button while the drawer is showing to prevent glitchy effects.\n this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);\n\n // Remove open tooltip if still visible.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton && openButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(openButton)?.tooltip('hide');\n }\n\n Aria.unhide(this.drawerNode);\n this.drawerNode.classList.add(CLASSES.SHOW);\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1)) {\n M.util.set_user_preference(preference, true);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.add(state);\n }\n\n this.boundingRect = this.drawerNode.getBoundingClientRect();\n\n if (isSmall()) {\n getBackdrop().then(backdrop => {\n backdrop.show();\n\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'hidden';\n return backdrop;\n })\n .catch();\n }\n\n // Show close button once the drawer is fully opened.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n if (focusOnCloseButton && closeButton) {\n disableButtonTooltip(closeButton, true);\n }\n setTimeout(() => {\n closeButton.classList.toggle('hidden', false);\n if (focusOnCloseButton) {\n closeButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerShown);\n }\n\n /**\n * Close the drawer.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer\n * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference\n */\n closeDrawer({focusOnOpenButton = true, updatePreferences = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:close');\n\n const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button while the drawer is hiding to prevent glitchy effects.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n closeButton?.classList.toggle('hidden', true);\n // Remove the close button tooltip if visible.\n if (closeButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(closeButton)?.tooltip('hide');\n }\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && updatePreferences && !isSmall()) {\n M.util.set_user_preference(preference, false);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.remove(state);\n }\n\n Aria.hide(this.drawerNode);\n this.drawerNode.classList.remove(CLASSES.SHOW);\n\n getBackdrop().then(backdrop => {\n backdrop.hide();\n\n if (isSmall()) {\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'visible';\n }\n return backdrop;\n })\n .catch();\n\n // Move focus to the open drawer (or toggler) button once the drawer is hidden.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton) {\n disableButtonTooltip(openButton, true);\n }\n setTimeout(() => {\n if (openButton && focusOnOpenButton) {\n openButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerHidden);\n }\n\n /**\n * Toggle visibility of the drawer.\n */\n toggleVisibility() {\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.closeDrawer();\n } else {\n this.openDrawer();\n }\n }\n\n /**\n * Displaces the drawer outsite the page.\n *\n * @param {Number} scrollPosition the page current scroll position\n */\n displace(scrollPosition) {\n let displace = scrollPosition;\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (scrollPosition === 0) {\n this.drawerNode.style.transform = '';\n if (openButton) {\n openButton.style.transform = '';\n }\n return;\n }\n const state = this.drawerNode.dataset?.state;\n const drawrWidth = this.drawerNode.offsetWidth;\n let scrollThreshold = drawrWidth;\n let direction = -1;\n if (state === 'show-drawer-right') {\n direction = 1;\n scrollThreshold = THRESHOLD;\n }\n if (scrollPosition > scrollThreshold) {\n displace = drawrWidth + THRESHOLD;\n }\n displace *= direction;\n const transform = `translateX(${displace}px)`;\n if (openButton) {\n openButton.style.transform = transform;\n }\n this.drawerNode.style.transform = transform;\n }\n\n /**\n * Prevent drawer from overlapping an element.\n *\n * @param {HTMLElement} currentFocus\n */\n preventOverlap(currentFocus) {\n if (!this.isOpen) {\n return;\n }\n const drawrWidth = this.drawerNode.offsetWidth;\n const element = currentFocus.getBoundingClientRect();\n const drawer = this.boundingRect;\n const overlapping = (\n (element.right + THRESHOLD) > drawer.left &&\n (element.left - THRESHOLD) < drawer.right\n );\n if (overlapping) {\n // Force drawer to displace out of the page.\n this.displace(drawrWidth + 1);\n } else {\n // Reset drawer displacement.\n this.displace(window.scrollX);\n }\n }\n\n /**\n * Close all drawers.\n */\n static closeAllDrawers() {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Close all drawers except for the specified drawer.\n *\n * @param {module:theme_boost/drawers} comparisonInstance\n */\n static closeOtherDrawers(comparisonInstance) {\n drawerMap.forEach(drawerInstance => {\n if (drawerInstance === comparisonInstance) {\n return;\n }\n\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Prevent drawers from covering the focused element.\n */\n static preventCoveringFocusedElement() {\n const currentFocus = document.activeElement;\n // Focus on page layout elements should be ignored.\n const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);\n if (!currentFocus || !pagecontent?.contains(currentFocus)) {\n Drawers.displaceDrawers(window.scrollX);\n return;\n }\n drawerMap.forEach(drawerInstance => {\n drawerInstance.preventOverlap(currentFocus);\n });\n }\n\n /**\n * Prevent drawer from covering the content when the page content covers the full page.\n *\n * @param {Number} displace\n */\n static displaceDrawers(displace) {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.displace(displace);\n });\n }\n}\n\n/**\n * Set the last used attribute for the last used toggle button for a drawer.\n *\n * @param {object} toggleButton The clicked button.\n */\nconst setLastUsedToggle = (toggleButton) => {\n if (toggleButton.dataset.target) {\n document.querySelectorAll(`${SELECTORS.BUTTONS}[data-target=\"${toggleButton.dataset.target}\"]`)\n .forEach(btn => {\n btn.dataset.lastused = false;\n });\n toggleButton.dataset.lastused = true;\n }\n};\n\n/**\n * Set the focus to the last used button to open this drawer.\n * @param {string} target The drawer target.\n */\nconst focusLastUsedToggle = (target) => {\n const lastUsedButton = document.querySelector(`${SELECTORS.BUTTONS}[data-target=\"${target}\"][data-lastused=\"true\"`);\n if (lastUsedButton) {\n lastUsedButton.focus();\n }\n};\n\n/**\n * Register the event listeners for the drawer.\n *\n * @private\n */\nconst registerListeners = () => {\n // Listen for show/hide events.\n document.addEventListener('click', e => {\n const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);\n if (toggleButton && toggleButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(toggleButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.toggleVisibility();\n }\n\n const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);\n if (openDrawerButton && openDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(openDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.openDrawer();\n }\n\n const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);\n if (closeDrawerButton && closeDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(closeDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n\n drawerInstance.closeDrawer();\n focusLastUsedToggle(closeDrawerButton.dataset.target);\n }\n });\n\n // Close drawer when another drawer opens.\n document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n if (isLarge()) {\n return;\n }\n Drawers.closeOtherDrawers(e.detail.drawerInstance);\n });\n\n // Tooglers and openers blur listeners.\n const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;\n document.addEventListener('focusout', (e) => {\n const button = e.target.closest(btnSelector);\n if (button?.dataset.restoreTooltipOnBlur !== undefined) {\n enableButtonTooltip(button);\n }\n });\n\n const closeOnResizeListener = () => {\n if (isSmall()) {\n let anyOpen = false;\n drawerMap.forEach(drawerInstance => {\n disableDrawerTooltips(drawerInstance.drawerNode);\n if (drawerInstance.isOpen) {\n if (drawerInstance.closeOnResize) {\n drawerInstance.closeDrawer();\n } else {\n anyOpen = true;\n }\n }\n });\n\n if (anyOpen) {\n getBackdrop().then(backdrop => backdrop.show()).catch();\n }\n } else {\n drawerMap.forEach(drawerInstance => {\n enableDrawerTooltips(drawerInstance.drawerNode);\n });\n getBackdrop().then(backdrop => backdrop.hide()).catch();\n }\n };\n\n document.addEventListener('scroll', () => {\n const body = document.querySelector('body');\n if (window.scrollY >= window.innerHeight) {\n body.classList.add(CLASSES.SCROLLED);\n } else {\n body.classList.remove(CLASSES.SCROLLED);\n }\n // Horizontal scroll listener to displace the drawers to prevent covering\n // any possible sticky content.\n Drawers.displaceDrawers(window.scrollX);\n });\n\n const preventOverlap = debounce(Drawers.preventCoveringFocusedElement, 100);\n document.addEventListener('focusin', preventOverlap);\n document.addEventListener('focusout', preventOverlap);\n\n window.addEventListener('resize', debounce(closeOnResizeListener, 400));\n};\n\nregisterListeners();\n\nconst drawers = document.querySelectorAll(SELECTORS.DRAWERS);\ndrawers.forEach(drawerNode => Drawers.getDrawerInstanceForNode(drawerNode));\n"],"names":["backdropPromise","drawerMap","Map","SELECTORS","CLASSES","getDrawerZIndex","drawer","document","querySelector","parseInt","window","getComputedStyle","zIndex","getBackdrop","Templates","render","then","html","ModalBackdrop","modalBackdrop","setZIndex","getAttachmentPoint","get","addEventListener","e","preventDefault","Drawers","closeAllDrawers","catch","getDrawerOpenButton","drawerId","openButton","disableDrawerTooltips","drawerNode","id","forEach","button","disableButtonTooltip","enableOnBlur","hasAttribute","tooltip","setAttribute","dataset","originalTitle","disabledToggle","toggle","removeAttribute","restoreTooltipOnBlur","enableButtonTooltip","constructor","undefined","behatFakeDrawer","closeDrawer","focusOnOpenButton","updatePreferences","this","classList","contains","openDrawer","focusOnCloseButton","forceopen","Aria","hide","content","scrollTop","addInnerScrollListener","set","remove","isOpen","closeOnResize","has","dispatchEvent","eventname","cancelable","drawerInstance","pendingPromise","Pending","eventTypes","drawerShow","defaultPrevented","unhide","add","preference","M","util","set_user_preference","state","getElementById","boundingRect","getBoundingClientRect","backdrop","show","style","overflow","closeButton","setTimeout","focus","resolve","drawerShown","drawerHide","drawerHidden","toggleVisibility","displace","scrollPosition","transform","_this$drawerNode$data","drawrWidth","offsetWidth","scrollThreshold","direction","preventOverlap","currentFocus","element","right","left","scrollX","comparisonInstance","activeElement","pagecontent","displaceDrawers","setLastUsedToggle","toggleButton","target","querySelectorAll","btn","lastused","closest","targetDrawer","getDrawerInstanceForNode","openDrawerButton","closeDrawerButton","lastUsedButton","focusLastUsedToggle","closeOtherDrawers","detail","btnSelector","body","scrollY","innerHeight","preventCoveringFocusedElement","anyOpen","registerListeners"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"drawers.min.js","sources":["../src/drawers.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 .\n\n/**\n * Toggling the visibility of the secondary navigation on mobile.\n *\n * @module theme_boost/drawers\n * @copyright 2021 Bas Brands\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport ModalBackdrop from 'core/modal_backdrop';\nimport Templates from 'core/templates';\nimport * as Aria from 'core/aria';\nimport {dispatchEvent} from 'core/event_dispatcher';\nimport {debounce} from 'core/utils';\nimport {isSmall, isLarge} from 'core/pagehelpers';\nimport Pending from 'core/pending';\nimport {setUserPreference} from 'core_user/repository';\n// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.\nimport jQuery from 'jquery';\n\nlet backdropPromise = null;\n\nconst drawerMap = new Map();\n\nconst SELECTORS = {\n BUTTONS: '[data-toggler=\"drawers\"]',\n CLOSEBTN: '[data-toggler=\"drawers\"][data-action=\"closedrawer\"]',\n OPENBTN: '[data-toggler=\"drawers\"][data-action=\"opendrawer\"]',\n TOGGLEBTN: '[data-toggler=\"drawers\"][data-action=\"toggle\"]',\n DRAWERS: '[data-region=\"fixed-drawer\"]',\n DRAWERCONTENT: '.drawercontent',\n PAGECONTENT: '#page-content',\n};\n\nconst CLASSES = {\n SCROLLED: 'scrolled',\n SHOW: 'show',\n NOTINITIALISED: 'not-initialized',\n};\n\n/**\n * Pixel thresshold to auto-hide drawers.\n *\n * @type {Number}\n */\nconst THRESHOLD = 20;\n\n/**\n * Try to get the drawer z-index from the page content.\n *\n * @returns {Number|null} the z-index of the drawer.\n * @private\n */\nconst getDrawerZIndex = () => {\n const drawer = document.querySelector(SELECTORS.DRAWERS);\n if (!drawer) {\n return null;\n }\n return parseInt(window.getComputedStyle(drawer).zIndex, 10);\n};\n\n/**\n * Add a backdrop to the page.\n *\n * @returns {Promise} rendering of modal backdrop.\n * @private\n */\nconst getBackdrop = () => {\n if (!backdropPromise) {\n backdropPromise = Templates.render('core/modal_backdrop', {})\n .then(html => new ModalBackdrop(html))\n .then(modalBackdrop => {\n const drawerZindex = getDrawerZIndex();\n if (drawerZindex) {\n modalBackdrop.setZIndex(getDrawerZIndex() - 1);\n }\n modalBackdrop.getAttachmentPoint().get(0).addEventListener('click', e => {\n e.preventDefault();\n Drawers.closeAllDrawers();\n });\n return modalBackdrop;\n })\n .catch();\n }\n return backdropPromise;\n};\n\n/**\n * Get the button element to open a specific drawer.\n *\n * @param {String} drawerId the drawer element Id\n * @return {HTMLElement|undefined} the open button element\n * @private\n */\nconst getDrawerOpenButton = (drawerId) => {\n let openButton = document.querySelector(`${SELECTORS.OPENBTN}[data-target=\"${drawerId}\"]`);\n if (!openButton) {\n openButton = document.querySelector(`${SELECTORS.TOGGLEBTN}[data-target=\"${drawerId}\"]`);\n }\n return openButton;\n};\n\n/**\n * Disable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst disableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n disableButtonTooltip(button);\n });\n};\n\n/**\n * Disable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @param {boolean} enableOnBlur if the tooltip must be re-enabled on blur.\n * @private\n */\nconst disableButtonTooltip = (button, enableOnBlur) => {\n if (button.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(button).tooltip('disable');\n button.setAttribute('title', button.dataset.originalTitle);\n } else {\n button.dataset.disabledToggle = button.dataset.toggle;\n button.removeAttribute('data-toggle');\n }\n if (enableOnBlur) {\n button.dataset.restoreTooltipOnBlur = true;\n }\n};\n\n/**\n * Enable drawer tooltips.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst enableDrawerTooltips = (drawerNode) => {\n const buttons = [\n drawerNode.querySelector(SELECTORS.CLOSEBTN),\n getDrawerOpenButton(drawerNode.id),\n ];\n buttons.forEach(button => {\n if (!button) {\n return;\n }\n enableButtonTooltip(button);\n });\n};\n\n/**\n * Enable the button tooltips.\n *\n * @param {HTMLElement} button the button element\n * @private\n */\nconst enableButtonTooltip = (button) => {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n if (button.hasAttribute('data-original-title')) {\n jQuery(button).tooltip('enable');\n button.removeAttribute('title');\n } else if (button.dataset.disabledToggle) {\n button.dataset.toggle = button.dataset.disabledToggle;\n jQuery(button).tooltip();\n }\n delete button.dataset.restoreTooltipOnBlur;\n};\n\n/**\n * Add scroll listeners to a drawer element.\n *\n * @param {HTMLElement} drawerNode the drawer main node\n * @private\n */\nconst addInnerScrollListener = (drawerNode) => {\n const content = drawerNode.querySelector(SELECTORS.DRAWERCONTENT);\n if (!content) {\n return;\n }\n content.addEventListener(\"scroll\", () => {\n drawerNode.classList.toggle(\n CLASSES.SCROLLED,\n content.scrollTop != 0\n );\n });\n};\n\n/**\n * The Drawers class is used to control on-screen drawer elements.\n *\n * It handles opening, and closing of drawer elements, as well as more detailed behaviours such as closing a drawer when\n * another drawer is opened, and supports closing a drawer when the screen is resized.\n *\n * Drawers are instantiated on page load, and can also be toggled lazily when toggling any drawer toggle, open button,\n * or close button.\n *\n * A range of show and hide events are also dispatched as detailed in the class\n * {@link module:theme_boost/drawers#eventTypes eventTypes} object.\n *\n * @example Standard usage\n *\n * // The module just needs to be included to add drawer support.\n * import 'theme_boost/drawers';\n *\n * @example Manually open or close any drawer\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * const myDrawer = Drawers.getDrawerInstanceForNode(document.querySelector('.myDrawerNode');\n * myDrawer.closeDrawer();\n *\n * @example Listen to the before show event and cancel it\n *\n * import Drawers from 'theme_boost/drawers';\n *\n * document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n * // The drawer which will be shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n *\n * // Prevent this drawer from being shown.\n * e.preventDefault();\n * });\n *\n * @example Listen to the shown event\n *\n * document.addEventListener(Drawers.eventTypes.drawerShown, e => {\n * // The drawer which was shown.\n * window.console.log(e.target);\n *\n * // The instance of the Drawers class for this drawer.\n * window.console.log(e.detail.drawerInstance);\n * });\n */\nexport default class Drawers {\n /**\n * The underlying HTMLElement which is controlled.\n */\n drawerNode = null;\n\n /**\n * The drawer page bounding box dimensions.\n * @var {DOMRect} boundingRect\n */\n boundingRect = null;\n\n constructor(drawerNode) {\n // Some behat tests may use fake drawer divs to test components in drawers.\n if (drawerNode.dataset.behatFakeDrawer !== undefined) {\n return;\n }\n\n this.drawerNode = drawerNode;\n\n if (isSmall()) {\n this.closeDrawer({focusOnOpenButton: false, updatePreferences: false});\n }\n\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.openDrawer({focusOnCloseButton: false});\n } else if (this.drawerNode.dataset.forceopen == 1) {\n if (!isSmall()) {\n this.openDrawer({focusOnCloseButton: false});\n }\n } else {\n Aria.hide(this.drawerNode);\n }\n\n // Disable tooltips in small screens.\n if (isSmall()) {\n disableDrawerTooltips(this.drawerNode);\n }\n\n addInnerScrollListener(this.drawerNode);\n\n drawerMap.set(drawerNode, this);\n\n drawerNode.classList.remove(CLASSES.NOTINITIALISED);\n }\n\n /**\n * Whether the drawer is open.\n *\n * @returns {boolean}\n */\n get isOpen() {\n return this.drawerNode.classList.contains(CLASSES.SHOW);\n }\n\n /**\n * Whether the drawer should close when the window is resized\n *\n * @returns {boolean}\n */\n get closeOnResize() {\n return !!parseInt(this.drawerNode.dataset.closeOnResize);\n }\n\n /**\n * The list of event types.\n *\n * @static\n * @property {String} drawerShow See {@link event:theme_boost/drawers:show}\n * @property {String} drawerShown See {@link event:theme_boost/drawers:shown}\n * @property {String} drawerHide See {@link event:theme_boost/drawers:hide}\n * @property {String} drawerHidden See {@link event:theme_boost/drawers:hidden}\n */\n static eventTypes = {\n /**\n * An event triggered before a drawer is shown.\n *\n * @event theme_boost/drawers:show\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be opened.\n */\n drawerShow: 'theme_boost/drawers:show',\n\n /**\n * An event triggered after a drawer is shown.\n *\n * @event theme_boost/drawers:shown\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be opened.\n */\n drawerShown: 'theme_boost/drawers:shown',\n\n /**\n * An event triggered before a drawer is hidden.\n *\n * @event theme_boost/drawers:hide\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that will be hidden.\n */\n drawerHide: 'theme_boost/drawers:hide',\n\n /**\n * An event triggered after a drawer is hidden.\n *\n * @event theme_boost/drawers:hidden\n * @type {CustomEvent}\n * @property {HTMLElement} target The drawer that was be hidden.\n */\n drawerHidden: 'theme_boost/drawers:hidden',\n };\n\n\n /**\n * Get the drawer instance for the specified node\n *\n * @param {HTMLElement} drawerNode\n * @returns {module:theme_boost/drawers}\n */\n static getDrawerInstanceForNode(drawerNode) {\n if (!drawerMap.has(drawerNode)) {\n new Drawers(drawerNode);\n }\n\n return drawerMap.get(drawerNode);\n }\n\n /**\n * Dispatch a drawer event.\n *\n * @param {string} eventname the event name\n * @param {boolean} cancelable if the event is cancelable\n * @returns {CustomEvent} the resulting custom event\n */\n dispatchEvent(eventname, cancelable = false) {\n return dispatchEvent(\n eventname,\n {\n drawerInstance: this,\n },\n this.drawerNode,\n {\n cancelable,\n }\n );\n }\n\n /**\n * Open the drawer.\n *\n * By default, openDrawer sets the page focus to the close drawer button. However, when a drawer is open at page\n * load, this represents an accessibility problem as the initial focus changes without any user interaction. The\n * focusOnCloseButton parameter can be set to false to prevent this behaviour.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnCloseButton=true] Whether to alter page focus when opening the drawer\n */\n openDrawer({focusOnCloseButton = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:open');\n const showEvent = this.dispatchEvent(Drawers.eventTypes.drawerShow, true);\n if (showEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button while the drawer is showing to prevent glitchy effects.\n this.drawerNode.querySelector(SELECTORS.CLOSEBTN)?.classList.toggle('hidden', true);\n\n // Remove open tooltip if still visible.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton && openButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(openButton)?.tooltip('hide');\n }\n\n Aria.unhide(this.drawerNode);\n this.drawerNode.classList.add(CLASSES.SHOW);\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1)) {\n setUserPreference(preference, true);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.add(state);\n }\n\n this.boundingRect = this.drawerNode.getBoundingClientRect();\n\n if (isSmall()) {\n getBackdrop().then(backdrop => {\n backdrop.show();\n\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'hidden';\n return backdrop;\n })\n .catch();\n }\n\n // Show close button once the drawer is fully opened.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n if (focusOnCloseButton && closeButton) {\n disableButtonTooltip(closeButton, true);\n }\n setTimeout(() => {\n closeButton.classList.toggle('hidden', false);\n if (focusOnCloseButton) {\n closeButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerShown);\n }\n\n /**\n * Close the drawer.\n *\n * @param {object} args\n * @param {boolean} [args.focusOnOpenButton=true] Whether to alter page focus when opening the drawer\n * @param {boolean} [args.updatePreferences=true] Whether to update the user prewference\n */\n closeDrawer({focusOnOpenButton = true, updatePreferences = true} = {}) {\n\n const pendingPromise = new Pending('theme_boost/drawers:close');\n\n const hideEvent = this.dispatchEvent(Drawers.eventTypes.drawerHide, true);\n if (hideEvent.defaultPrevented) {\n return;\n }\n\n // Hide close button while the drawer is hiding to prevent glitchy effects.\n const closeButton = this.drawerNode.querySelector(SELECTORS.CLOSEBTN);\n closeButton?.classList.toggle('hidden', true);\n // Remove the close button tooltip if visible.\n if (closeButton.hasAttribute('data-original-title')) {\n // The jQuery is still used in Boostrap 4. It can we removed when MDL-71979 is integrated.\n jQuery(closeButton)?.tooltip('hide');\n }\n\n const preference = this.drawerNode.dataset.preference;\n if (preference && updatePreferences && !isSmall()) {\n setUserPreference(preference, false);\n }\n\n const state = this.drawerNode.dataset.state;\n if (state) {\n const page = document.getElementById('page');\n page.classList.remove(state);\n }\n\n Aria.hide(this.drawerNode);\n this.drawerNode.classList.remove(CLASSES.SHOW);\n\n getBackdrop().then(backdrop => {\n backdrop.hide();\n\n if (isSmall()) {\n const pageWrapper = document.getElementById('page');\n pageWrapper.style.overflow = 'visible';\n }\n return backdrop;\n })\n .catch();\n\n // Move focus to the open drawer (or toggler) button once the drawer is hidden.\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (openButton) {\n disableButtonTooltip(openButton, true);\n }\n setTimeout(() => {\n if (openButton && focusOnOpenButton) {\n openButton.focus();\n }\n pendingPromise.resolve();\n }, 300);\n\n this.dispatchEvent(Drawers.eventTypes.drawerHidden);\n }\n\n /**\n * Toggle visibility of the drawer.\n */\n toggleVisibility() {\n if (this.drawerNode.classList.contains(CLASSES.SHOW)) {\n this.closeDrawer();\n } else {\n this.openDrawer();\n }\n }\n\n /**\n * Displaces the drawer outsite the page.\n *\n * @param {Number} scrollPosition the page current scroll position\n */\n displace(scrollPosition) {\n let displace = scrollPosition;\n let openButton = getDrawerOpenButton(this.drawerNode.id);\n if (scrollPosition === 0) {\n this.drawerNode.style.transform = '';\n if (openButton) {\n openButton.style.transform = '';\n }\n return;\n }\n const state = this.drawerNode.dataset?.state;\n const drawrWidth = this.drawerNode.offsetWidth;\n let scrollThreshold = drawrWidth;\n let direction = -1;\n if (state === 'show-drawer-right') {\n direction = 1;\n scrollThreshold = THRESHOLD;\n }\n if (scrollPosition > scrollThreshold) {\n displace = drawrWidth + THRESHOLD;\n }\n displace *= direction;\n const transform = `translateX(${displace}px)`;\n if (openButton) {\n openButton.style.transform = transform;\n }\n this.drawerNode.style.transform = transform;\n }\n\n /**\n * Prevent drawer from overlapping an element.\n *\n * @param {HTMLElement} currentFocus\n */\n preventOverlap(currentFocus) {\n if (!this.isOpen) {\n return;\n }\n const drawrWidth = this.drawerNode.offsetWidth;\n const element = currentFocus.getBoundingClientRect();\n const drawer = this.boundingRect;\n const overlapping = (\n (element.right + THRESHOLD) > drawer.left &&\n (element.left - THRESHOLD) < drawer.right\n );\n if (overlapping) {\n // Force drawer to displace out of the page.\n this.displace(drawrWidth + 1);\n } else {\n // Reset drawer displacement.\n this.displace(window.scrollX);\n }\n }\n\n /**\n * Close all drawers.\n */\n static closeAllDrawers() {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Close all drawers except for the specified drawer.\n *\n * @param {module:theme_boost/drawers} comparisonInstance\n */\n static closeOtherDrawers(comparisonInstance) {\n drawerMap.forEach(drawerInstance => {\n if (drawerInstance === comparisonInstance) {\n return;\n }\n\n drawerInstance.closeDrawer();\n });\n }\n\n /**\n * Prevent drawers from covering the focused element.\n */\n static preventCoveringFocusedElement() {\n const currentFocus = document.activeElement;\n // Focus on page layout elements should be ignored.\n const pagecontent = document.querySelector(SELECTORS.PAGECONTENT);\n if (!currentFocus || !pagecontent?.contains(currentFocus)) {\n Drawers.displaceDrawers(window.scrollX);\n return;\n }\n drawerMap.forEach(drawerInstance => {\n drawerInstance.preventOverlap(currentFocus);\n });\n }\n\n /**\n * Prevent drawer from covering the content when the page content covers the full page.\n *\n * @param {Number} displace\n */\n static displaceDrawers(displace) {\n drawerMap.forEach(drawerInstance => {\n drawerInstance.displace(displace);\n });\n }\n}\n\n/**\n * Set the last used attribute for the last used toggle button for a drawer.\n *\n * @param {object} toggleButton The clicked button.\n */\nconst setLastUsedToggle = (toggleButton) => {\n if (toggleButton.dataset.target) {\n document.querySelectorAll(`${SELECTORS.BUTTONS}[data-target=\"${toggleButton.dataset.target}\"]`)\n .forEach(btn => {\n btn.dataset.lastused = false;\n });\n toggleButton.dataset.lastused = true;\n }\n};\n\n/**\n * Set the focus to the last used button to open this drawer.\n * @param {string} target The drawer target.\n */\nconst focusLastUsedToggle = (target) => {\n const lastUsedButton = document.querySelector(`${SELECTORS.BUTTONS}[data-target=\"${target}\"][data-lastused=\"true\"`);\n if (lastUsedButton) {\n lastUsedButton.focus();\n }\n};\n\n/**\n * Register the event listeners for the drawer.\n *\n * @private\n */\nconst registerListeners = () => {\n // Listen for show/hide events.\n document.addEventListener('click', e => {\n const toggleButton = e.target.closest(SELECTORS.TOGGLEBTN);\n if (toggleButton && toggleButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(toggleButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.toggleVisibility();\n }\n\n const openDrawerButton = e.target.closest(SELECTORS.OPENBTN);\n if (openDrawerButton && openDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(openDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n setLastUsedToggle(toggleButton);\n\n drawerInstance.openDrawer();\n }\n\n const closeDrawerButton = e.target.closest(SELECTORS.CLOSEBTN);\n if (closeDrawerButton && closeDrawerButton.dataset.target) {\n e.preventDefault();\n const targetDrawer = document.getElementById(closeDrawerButton.dataset.target);\n const drawerInstance = Drawers.getDrawerInstanceForNode(targetDrawer);\n\n drawerInstance.closeDrawer();\n focusLastUsedToggle(closeDrawerButton.dataset.target);\n }\n });\n\n // Close drawer when another drawer opens.\n document.addEventListener(Drawers.eventTypes.drawerShow, e => {\n if (isLarge()) {\n return;\n }\n Drawers.closeOtherDrawers(e.detail.drawerInstance);\n });\n\n // Tooglers and openers blur listeners.\n const btnSelector = `${SELECTORS.TOGGLEBTN}, ${SELECTORS.OPENBTN}, ${SELECTORS.CLOSEBTN}`;\n document.addEventListener('focusout', (e) => {\n const button = e.target.closest(btnSelector);\n if (button?.dataset.restoreTooltipOnBlur !== undefined) {\n enableButtonTooltip(button);\n }\n });\n\n const closeOnResizeListener = () => {\n if (isSmall()) {\n let anyOpen = false;\n drawerMap.forEach(drawerInstance => {\n disableDrawerTooltips(drawerInstance.drawerNode);\n if (drawerInstance.isOpen) {\n if (drawerInstance.closeOnResize) {\n drawerInstance.closeDrawer();\n } else {\n anyOpen = true;\n }\n }\n });\n\n if (anyOpen) {\n getBackdrop().then(backdrop => backdrop.show()).catch();\n }\n } else {\n drawerMap.forEach(drawerInstance => {\n enableDrawerTooltips(drawerInstance.drawerNode);\n });\n getBackdrop().then(backdrop => backdrop.hide()).catch();\n }\n };\n\n document.addEventListener('scroll', () => {\n const body = document.querySelector('body');\n if (window.scrollY >= window.innerHeight) {\n body.classList.add(CLASSES.SCROLLED);\n } else {\n body.classList.remove(CLASSES.SCROLLED);\n }\n // Horizontal scroll listener to displace the drawers to prevent covering\n // any possible sticky content.\n Drawers.displaceDrawers(window.scrollX);\n });\n\n const preventOverlap = debounce(Drawers.preventCoveringFocusedElement, 100);\n document.addEventListener('focusin', preventOverlap);\n document.addEventListener('focusout', preventOverlap);\n\n window.addEventListener('resize', debounce(closeOnResizeListener, 400));\n};\n\nregisterListeners();\n\nconst drawers = document.querySelectorAll(SELECTORS.DRAWERS);\ndrawers.forEach(drawerNode => Drawers.getDrawerInstanceForNode(drawerNode));\n"],"names":["backdropPromise","drawerMap","Map","SELECTORS","CLASSES","getDrawerZIndex","drawer","document","querySelector","parseInt","window","getComputedStyle","zIndex","getBackdrop","Templates","render","then","html","ModalBackdrop","modalBackdrop","setZIndex","getAttachmentPoint","get","addEventListener","e","preventDefault","Drawers","closeAllDrawers","catch","getDrawerOpenButton","drawerId","openButton","disableDrawerTooltips","drawerNode","id","forEach","button","disableButtonTooltip","enableOnBlur","hasAttribute","tooltip","setAttribute","dataset","originalTitle","disabledToggle","toggle","removeAttribute","restoreTooltipOnBlur","enableButtonTooltip","constructor","undefined","behatFakeDrawer","closeDrawer","focusOnOpenButton","updatePreferences","this","classList","contains","openDrawer","focusOnCloseButton","forceopen","Aria","hide","content","scrollTop","addInnerScrollListener","set","remove","isOpen","closeOnResize","has","dispatchEvent","eventname","cancelable","drawerInstance","pendingPromise","Pending","eventTypes","drawerShow","defaultPrevented","unhide","add","preference","state","getElementById","boundingRect","getBoundingClientRect","backdrop","show","style","overflow","closeButton","setTimeout","focus","resolve","drawerShown","drawerHide","drawerHidden","toggleVisibility","displace","scrollPosition","transform","_this$drawerNode$data","drawrWidth","offsetWidth","scrollThreshold","direction","preventOverlap","currentFocus","element","right","left","scrollX","comparisonInstance","activeElement","pagecontent","displaceDrawers","setLastUsedToggle","toggleButton","target","querySelectorAll","btn","lastused","closest","targetDrawer","getDrawerInstanceForNode","openDrawerButton","closeDrawerButton","lastUsedButton","focusLastUsedToggle","closeOtherDrawers","detail","btnSelector","body","scrollY","innerHeight","preventCoveringFocusedElement","anyOpen","registerListeners"],"mappings":"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"} \ No newline at end of file diff --git a/theme/boost/amd/src/drawer.js b/theme/boost/amd/src/drawer.js index 8b36472daaf..d2e778d81b7 100644 --- a/theme/boost/amd/src/drawer.js +++ b/theme/boost/amd/src/drawer.js @@ -20,8 +20,8 @@ * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', 'core/aria'], - function($, CustomEvents, Log, PubSub, Aria) { +define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', 'core/aria', 'core_user/repository'], + function($, CustomEvents, Log, PubSub, Aria, UserRepository) { var SELECTORS = { TOGGLE_REGION: '[data-region="drawer-toggle"]', @@ -55,7 +55,7 @@ define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', ' var body = $(SELECTORS.BODY); var preference = trigger.attr('data-preference'); if (small) { - M.util.set_user_preference(preference, 'false'); + UserRepository.setUserPreference(preference, false); } drawer.on('mousewheel DOMMouseScroll', this.preventPageScroll); @@ -88,7 +88,7 @@ define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', ' Aria.hide(drawer.get()); drawer.addClass('closed'); if (!small) { - M.util.set_user_preference(preference, 'false'); + UserRepository.setUserPreference(preference, false); } }); }; @@ -107,7 +107,7 @@ define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', ' var side = trigger.attr('data-side'); var preference = trigger.attr('data-preference'); if (small) { - M.util.set_user_preference(preference, 'false'); + UserRepository.setUserPreference(preference, false); } body.addClass('drawer-ease'); @@ -120,7 +120,7 @@ define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', ' body.addClass('drawer-open-' + side); drawer.removeClass('closed'); if (!small) { - M.util.set_user_preference(preference, 'true'); + UserRepository.setUserPreference(preference, true); } } else { // Close. @@ -134,7 +134,7 @@ define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', ' $(this).dequeue(); }); if (!small) { - M.util.set_user_preference(preference, 'false'); + UserRepository.setUserPreference(preference, false); } } diff --git a/theme/boost/amd/src/drawers.js b/theme/boost/amd/src/drawers.js index d81429dab28..daadf6fc761 100644 --- a/theme/boost/amd/src/drawers.js +++ b/theme/boost/amd/src/drawers.js @@ -27,6 +27,7 @@ import {dispatchEvent} from 'core/event_dispatcher'; import {debounce} from 'core/utils'; import {isSmall, isLarge} from 'core/pagehelpers'; import Pending from 'core/pending'; +import {setUserPreference} from 'core_user/repository'; // The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated. import jQuery from 'jquery'; @@ -436,7 +437,7 @@ export default class Drawers { const preference = this.drawerNode.dataset.preference; if (preference && !isSmall() && (this.drawerNode.dataset.forceopen != 1)) { - M.util.set_user_preference(preference, true); + setUserPreference(preference, true); } const state = this.drawerNode.dataset.state; @@ -501,7 +502,7 @@ export default class Drawers { const preference = this.drawerNode.dataset.preference; if (preference && updatePreferences && !isSmall()) { - M.util.set_user_preference(preference, false); + setUserPreference(preference, false); } const state = this.drawerNode.dataset.state; diff --git a/theme/boost/layout/drawers.php b/theme/boost/layout/drawers.php index d442c4d0736..756d041bc7d 100644 --- a/theme/boost/layout/drawers.php +++ b/theme/boost/layout/drawers.php @@ -30,9 +30,6 @@ require_once($CFG->dirroot . '/course/lib.php'); // Add block button in editing mode. $addblockbutton = $OUTPUT->addblockbutton(); -user_preference_allow_ajax_update('drawer-open-index', PARAM_BOOL); -user_preference_allow_ajax_update('drawer-open-block', PARAM_BOOL); - if (isloggedin()) { $courseindexopen = (get_user_preferences('drawer-open-index', true) == true); $blockdraweropen = (get_user_preferences('drawer-open-block') == true); diff --git a/theme/boost/lib.php b/theme/boost/lib.php index 7e98100f6d8..13d4c421d5a 100644 --- a/theme/boost/lib.php +++ b/theme/boost/lib.php @@ -93,6 +93,28 @@ function theme_boost_pluginfile($course, $cm, $context, $filearea, $args, $force } } +/** + * Get the current user preferences that are available + * + * @return array[] + */ +function theme_boost_user_preferences(): array { + return [ + 'drawer-open-block' => [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => false, + 'permissioncallback' => [core_user::class, 'is_current_user'], + ], + 'drawer-open-index' => [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'default' => true, + 'permissioncallback' => [core_user::class, 'is_current_user'], + ], + ]; +} + /** * Returns the main SCSS content. * diff --git a/user/selector/lib.php b/user/selector/lib.php index 9cb416fb21c..1b79cec5056 100644 --- a/user/selector/lib.php +++ b/user/selector/lib.php @@ -679,7 +679,6 @@ abstract class user_selector_base { '" value="1"' . $checked . ' /> ' . $label . " \n"; - user_preference_allow_ajax_update($name, PARAM_BOOL); return $output; } diff --git a/user/selector/module.js b/user/selector/module.js index 58a8575cb26..1eed6fa8322 100644 --- a/user/selector/module.js +++ b/user/selector/module.js @@ -368,7 +368,9 @@ M.core_user.init_user_selector_options_tracker = function(Y) { * @param {string} name The name of the preference to set */ set_user_preference : function(e, name) { - M.util.set_user_preference(name, Y.one('#' + name + 'id').get('checked')); + require(['core_user/repository'], function(UserRepository) { + UserRepository.setUserPreference(name, Y.one('#' + name + 'id').get('checked')); + }); } }; // Initialise the options tracker