mirror of
https://github.com/moodle/moodle.git
synced 2025-04-18 23:15:38 +02:00
Merge branch 'MDL-69301-master' of git://github.com/rezaies/moodle
This commit is contained in:
commit
b4e6552776
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
define ("core_course/local/activitychooser/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={regions:{chooser:b("region","chooser-container"),getSectionChooserOptions:function getSectionChooserOptions(a){return"".concat(a," ").concat(b("region","chooser-options-container"))},chooserOption:{container:b("region","chooser-option-container"),actions:b("region","chooser-option-actions-container"),info:b("region","chooser-option-info-container")},chooserSummary:{container:b("region","chooser-option-summary-container"),content:b("region","chooser-option-summary-content-container"),header:b("region","summary-header"),actions:b("region","chooser-option-summary-actions-container")},carousel:b("region","carousel"),help:b("region","help"),modules:b("region","modules"),favouriteTabNav:b("region","favourite-tab-nav"),recommendedTabNav:b("region","recommended-tab-nav"),defaultTabNav:b("region","default-tab-nav"),activityTabNav:b("region","activity-tab-nav"),resourceTabNav:b("region","resources-tab-nav"),favouriteTab:b("region","favourites"),recommendedTab:b("region","recommended"),defaultTab:b("region","default"),activityTab:b("region","activity"),resourceTab:b("region","resources"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")},searchResults:b("region","search-results-container"),searchResultItems:b("region","search-result-items-container")},actions:{optionActions:{showSummary:b("action","show-option-summary"),manageFavourite:b("action","manage-module-favourite")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide"),search:b("action","search"),clearSearch:b("action","clearsearch")},render:{favourites:b("render","favourites-area")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic",tab:"a[data-toggle=\"tab\"]",activetab:"a[data-toggle=\"tab\"][aria-selected=\"true\"]",visibletabs:"a[data-toggle=\"tab\"]:not(.d-none)"}};a.default=c;return a.default});
|
||||
define ("core_course/local/activitychooser/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={regions:{chooser:b("region","chooser-container"),getSectionChooserOptions:function getSectionChooserOptions(a){return"".concat(a," ").concat(b("region","chooser-options-container"))},chooserOption:{container:b("region","chooser-option-container"),actions:b("region","chooser-option-actions-container"),info:b("region","chooser-option-info-container")},chooserSummary:{container:b("region","chooser-option-summary-container"),content:b("region","chooser-option-summary-content-container"),header:b("region","summary-header"),actions:b("region","chooser-option-summary-actions-container")},carousel:b("region","carousel"),help:b("region","help"),modules:b("region","modules"),favouriteTabNav:b("region","favourite-tab-nav"),defaultTabNav:b("region","default-tab-nav"),activityTabNav:b("region","activity-tab-nav"),favouriteTab:b("region","favourites"),recommendedTab:b("region","recommended"),defaultTab:b("region","default"),activityTab:b("region","activity"),resourceTab:b("region","resources"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")},searchResults:b("region","search-results-container"),searchResultItems:b("region","search-result-items-container")},actions:{optionActions:{showSummary:b("action","show-option-summary"),manageFavourite:b("action","manage-module-favourite")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide"),search:b("action","search"),clearSearch:b("action","clearsearch")},render:{favourites:b("render","favourites-area")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic",tab:"a[data-toggle=\"tab\"]",activetab:"a[data-toggle=\"tab\"][aria-selected=\"true\"]",visibletabs:"a[data-toggle=\"tab\"]:not(.d-none)"}};a.default=c;return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
@ -216,7 +216,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
|
||||
const firstChooserOption = sectionChooserOptions.querySelector(selectors.regions.chooserOption.container);
|
||||
|
||||
toggleFocusableChooserOption(firstChooserOption, true);
|
||||
initTabsKeyboardNavigation(body);
|
||||
initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions, modal);
|
||||
|
||||
return body;
|
||||
@ -235,77 +234,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
|
||||
.catch();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the keyboard navigation controls for the tab list items.
|
||||
*
|
||||
* @method initTabsKeyboardNavigation
|
||||
* @param {HTMLElement} body Our modal that we are working with
|
||||
*/
|
||||
const initTabsKeyboardNavigation = (body) => {
|
||||
// Set up the tab handlers.
|
||||
const favTabNav = body.querySelector(selectors.regions.favouriteTabNav);
|
||||
const recommendedTabNav = body.querySelector(selectors.regions.recommendedTabNav);
|
||||
const defaultTabNav = body.querySelector(selectors.regions.defaultTabNav);
|
||||
const activityTabNav = body.querySelector(selectors.regions.activityTabNav);
|
||||
const resourceTabNav = body.querySelector(selectors.regions.resourceTabNav);
|
||||
const tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav, activityTabNav, resourceTabNav];
|
||||
tabNavArray.forEach((element) => {
|
||||
return element.addEventListener('keydown', (e) => {
|
||||
// The first visible navigation tab link.
|
||||
const firstLink = e.target.parentElement.querySelector(selectors.elements.visibletabs);
|
||||
// The last navigation tab link. It would always be the default activities tab link.
|
||||
const lastLink = e.target.parentElement.lastElementChild;
|
||||
|
||||
if (e.keyCode === arrowRight) {
|
||||
const nextLink = e.target.nextElementSibling;
|
||||
if (nextLink === null) {
|
||||
e.target.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
} else if (nextLink.classList.contains('d-none')) {
|
||||
e.target.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
} else {
|
||||
e.target.tabIndex = -1;
|
||||
nextLink.tabIndex = 0;
|
||||
nextLink.focus();
|
||||
}
|
||||
}
|
||||
if (e.keyCode === arrowLeft) {
|
||||
const previousLink = e.target.previousElementSibling;
|
||||
if (previousLink === null) {
|
||||
e.target.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
} else if (previousLink.classList.contains('d-none')) {
|
||||
e.target.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
} else {
|
||||
e.target.tabIndex = -1;
|
||||
previousLink.tabIndex = 0;
|
||||
previousLink.focus();
|
||||
}
|
||||
}
|
||||
if (e.keyCode === home) {
|
||||
e.target.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
}
|
||||
if (e.keyCode === end) {
|
||||
e.target.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
}
|
||||
if (e.keyCode === space) {
|
||||
e.preventDefault();
|
||||
e.target.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the keyboard navigation controls for the chooser options.
|
||||
*
|
||||
|
@ -52,10 +52,8 @@ export default {
|
||||
help: getDataSelector('region', 'help'),
|
||||
modules: getDataSelector('region', 'modules'),
|
||||
favouriteTabNav: getDataSelector('region', 'favourite-tab-nav'),
|
||||
recommendedTabNav: getDataSelector('region', 'recommended-tab-nav'),
|
||||
defaultTabNav: getDataSelector('region', 'default-tab-nav'),
|
||||
activityTabNav: getDataSelector('region', 'activity-tab-nav'),
|
||||
resourceTabNav: getDataSelector('region', 'resources-tab-nav'),
|
||||
favouriteTab: getDataSelector('region', 'favourites'),
|
||||
recommendedTab: getDataSelector('region', 'recommended'),
|
||||
defaultTab: getDataSelector('region', 'default'),
|
||||
|
@ -40,7 +40,7 @@
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<!-- First the top most node and immediate children -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#link{{node.key}}" data-toggle="tab" role="tab">{{node.text}}</a>
|
||||
<a class="nav-link active" href="#link{{node.key}}" data-toggle="tab" role="tab" aria-selected="true">{{node.text}}</a>
|
||||
</li>
|
||||
<!-- Now the first level children with sub nodes -->
|
||||
{{#node.children}}
|
||||
@ -48,7 +48,7 @@
|
||||
{{#display}}
|
||||
{{^is_short_branch}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#link{{key}}" data-toggle="tab" role="tab">{{text}}</a>
|
||||
<a class="nav-link" href="#link{{key}}" data-toggle="tab" role="tab" aria-selected="false" tabindex="-1">{{text}}</a>
|
||||
</li>
|
||||
{{/is_short_branch}}
|
||||
{{/display}}
|
||||
|
2
theme/boost/amd/build/aria.min.js
vendored
2
theme/boost/amd/build/aria.min.js
vendored
@ -1,2 +1,2 @@
|
||||
define ("theme_boost/aria",["jquery","core/pending"],function(a,b){return{init:function init(){var c=!1,d=function(){c=!0},e=function(){var a=c;c=!1;return a};a("[data-toggle=\"dropdown\"]").keydown(function(b){var c=b.which||b.keyCode,e;if(38==c){d()}if(27==c){e=a(b.target).attr("aria-expanded");b.preventDefault();if("false"==e){a(b.target).click()}}if(32==c||13==c){b.preventDefault();a(b.target).click()}});var f=function(c){var d=function(b){a(this).focus();b.resolve()}.bind(c);setTimeout(d,50,new b("core/aria:delayed-focus"))};a(".dropdown").on("shown.bs.dropdown",function(b){var c=a(b.target).find("[role=\"menu\"]"),d=!1,g=!1;if(c){d=a(c).find("[role=\"menuitem\"]")}if(d&&0<d.length){if(e()){g=d[d.length-1]}else{g=d[0]}}if(g){f(g)}});a(".dropdown [role=\"menu\"] [role=\"menuitem\"]").keypress(function(b){var c=String.fromCharCode(b.which||b.keyCode),d=a(b.target).closest("[role=\"menu\"]"),e=0,g=!1,h,j;if(!d){return}g=a(d).find("[role=\"menuitem\"]");if(!g){return}c=c.toLowerCase();for(e=0;e<g.length;e++){h=a(g[e]);j=h.text().trim().toLowerCase();if(0==j.indexOf(c)){f(h);break}}});a(".dropdown [role=\"menu\"] [role=\"menuitem\"]").keydown(function(b){var c=b.which||b.keyCode,d=!1,e=a(b.target).closest("[role=\"menu\"]"),g=0,h=!1;if(!e){return}h=a(e).find("[role=\"menuitem\"]");if(!h){return}if(40==c){for(g=0;g<h.length-1;g++){if(h[g]==b.target){d=h[g+1];break}}if(!d){d=h[0]}}else if(38==c){for(g=1;g<h.length;g++){if(h[g]==b.target){d=h[g-1];break}}if(!d){d=h[h.length-1]}}else if(36==c){d=h[0]}else if(35==c){d=h[h.length-1]}if(d){b.preventDefault();f(d)}});a(".dropdown").on("hidden.bs.dropdown",function(b){var c=a(b.target).find("[data-toggle=\"dropdown\"]");if(c){f(c)}});window.addEventListener("load",function(){var a=document.querySelectorAll("[data-aria-autofocus=\"true\"][role=\"alert\"]");Array.prototype.forEach.call(a,function(a){a.innerHTML+=" ";a.removeAttribute("data-aria-autofocus")})})}}});
|
||||
define ("theme_boost/aria",["exports","jquery","core/pending"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}var e=function(){var a=!1,d=function(){a=!0},e=function(){var b=a;a=!1;return b};document.addEventListener("keydown",function(a){if(a.target.matches("[data-toggle=\"dropdown\"]")){var b=a.key;if("ArrowUp"==b){d()}if("Escape"==b){var c=a.target.getAttribute("aria-expanded");a.preventDefault();if("false"==c){a.target.click()}}if(" "==b||"Enter"==b){a.preventDefault();a.target.click()}}});var f=function(a){setTimeout(function delayedFocus(b){a.focus();b.resolve()},50,new c.default("core/aria:delayed-focus"))};(0,b.default)(".dropdown").on("shown.bs.dropdown",function(a){var b=a.target.querySelector("[role=\"menu\"]"),c=!1,d=!1;if(b){c=b.querySelectorAll("[role=\"menuitem\"]")}if(c&&0<c.length){if(e()){d=c[c.length-1]}else{d=c[0]}}if(d){f(d)}});document.addEventListener("keypress",function(a){if(a.target.matches(".dropdown [role=\"menu\"] [role=\"menuitem\"]")){var g=a.target.closest("[role=\"menu\"]");if(!g){return}var h=g.querySelectorAll("[role=\"menuitem\"]");if(!h){return}for(var b=a.key.toLowerCase(),c=0;c<h.length;c++){var d=h[c],e=d.text.trim().toLowerCase();if(0==e.indexOf(b)){f(d);break}}}});document.addEventListener("keydown",function(a){if(a.target.matches(".dropdown [role=\"menu\"] [role=\"menuitem\"]")){var b=a.key,c=!1,d=a.target.closest("[role=\"menu\"]");if(!d){return}var e=d.querySelectorAll("[role=\"menuitem\"]");if(!e){return}if("ArrowDown"==b){for(var g=0;g<e.length-1;g++){if(e[g]==a.target){c=e[g+1];break}}if(!c){c=e[0]}}else if("ArrowUp"==b){for(var h=1;h<e.length;h++){if(e[h]==a.target){c=e[h-1];break}}if(!c){c=e[e.length-1]}}else if("Home"==b){c=e[0]}else if("End"==b){c=e[e.length-1]}if(c){a.preventDefault();f(c)}}});(0,b.default)(".dropdown").on("hidden.bs.dropdown",function(a){var b=a.target.querySelector("[data-toggle=\"dropdown\"]");if(b){f(b)}})},f=function(){window.addEventListener("load",function(){var a=document.querySelectorAll("[data-aria-autofocus=\"true\"][role=\"alert\"]");Array.prototype.forEach.call(a,function(a){a.innerHTML+=" ";a.removeAttribute("data-aria-autofocus")})})},g=function(a){for(var c=a.target.closest("[role=\"tablist\"]"),d="vertical"==c.getAttribute("aria-orientation"),e=window.right_to_left(),f=d?"ArrowDown":e?"ArrowLeft":"ArrowRight",g=d?"ArrowUp":e?"ArrowRight":"ArrowLeft",h=Array.prototype.filter.call(c.querySelectorAll("[role=\"tab\"]"),function(a){return"none"!==getComputedStyle(a).display}),j=0;j<h.length;j++){h[j].index=j}switch(a.key){case f:a.preventDefault();if(a.target.index!==void 0&&h[a.target.index+1]){h[a.target.index+1].focus()}else{h[0].focus()}break;case g:a.preventDefault();if(a.target.index!==void 0&&h[a.target.index-1]){h[a.target.index-1].focus()}else{h[h.length-1].focus()}break;case"Home":a.preventDefault();h[0].focus();break;case"End":a.preventDefault();h[h.length-1].focus();break;case"Enter":case" ":a.preventDefault();(0,b.default)(a.target).tab("show");h.forEach(function(a){a.tabIndex=-1});a.target.tabIndex=0;}},h=function(){document.addEventListener("keydown",function(a){if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Home","End","Enter"," "].includes(a.key)){if(a.target.matches("[role=\"tablist\"] [role=\"tab\"]")){g(a)}}});document.addEventListener("click",function(a){if(a.target.matches("[role=\"tablist\"] [role=\"tab\"]")){var c=a.target.closest("[role=\"tablist\"]").querySelectorAll("[role=\"tab\"]");a.preventDefault();(0,b.default)(a.target).tab("show");c.forEach(function(a){a.tabIndex=-1});a.target.tabIndex=0}})};a.init=function init(){e();f();h()}});
|
||||
//# sourceMappingURL=aria.min.js.map
|
||||
|
File diff suppressed because one or more lines are too long
2
theme/boost/amd/build/loader.min.js
vendored
2
theme/boost/amd/build/loader.min.js
vendored
@ -1,2 +1,2 @@
|
||||
define ("theme_boost/loader",["exports","jquery","./aria","./bootstrap/index","core/pending","./scroll","./pending"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Bootstrap",{enumerable:!0,get:function get(){return d.default}});b=h(b);c=h(c);d=h(d);e=h(e);f=h(f);g=h(g);function h(a){return a&&a.__esModule?a:{default:a}}var i=function(){(0,b.default)("a[data-toggle=\"tab\"]").on("shown.bs.tab",function(a){var c=(0,b.default)(a.target).attr("href");if(history.replaceState){history.replaceState(null,null,c)}else{location.hash=c}});var a=window.location.hash;if(a){(0,b.default)(".nav-link[href=\""+a+"\"]").tab("show")}},j=function(){(0,b.default)("body").popover({container:"body",selector:"[data-toggle=\"popover\"]",trigger:"focus"});document.addEventListener("keydown",function(a){if("Escape"===a.key&&a.target.closest("[data-toggle=\"popover\"]")){(0,b.default)(a.target).popover("hide")}})},k=function(){(0,b.default)("body").tooltip({container:"body",selector:"[data-toggle=\"tooltip\"]"})},l=new e.default("theme_boost/loader:init");(0,g.default)();i();j();k();new f.default().init();b.default.fn.dropdown.Constructor.Default.flip=!1;c.default.init();l.resolve()});
|
||||
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("theme_boost/loader",["exports","jquery","./aria","./bootstrap/index","core/pending","./scroll","./pending"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Bootstrap",{enumerable:!0,get:function get(){return d.default}});b=j(b);c=i(c);d=j(d);e=j(e);f=j(f);g=j(g);function h(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;h=function(){return a};return a}function i(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=h();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function j(a){return a&&a.__esModule?a:{default:a}}var k=function(){(0,b.default)("a[data-toggle=\"tab\"]").on("shown.bs.tab",function(a){var c=(0,b.default)(a.target).attr("href");if(history.replaceState){history.replaceState(null,null,c)}else{location.hash=c}});var a=window.location.hash;if(a){var c=document.querySelector(".nav-link[href=\""+a+"\"]");if(c){c.click()}}},l=function(){(0,b.default)("body").popover({container:"body",selector:"[data-toggle=\"popover\"]",trigger:"focus"});document.addEventListener("keydown",function(a){if("Escape"===a.key&&a.target.closest("[data-toggle=\"popover\"]")){(0,b.default)(a.target).popover("hide")}})},m=function(){(0,b.default)("body").tooltip({container:"body",selector:"[data-toggle=\"tooltip\"]"})},n=new e.default("theme_boost/loader:init");(0,g.default)();c.init();k();l();m();new f.default().init();b.default.fn.dropdown.Constructor.Default.flip=!1;n.resolve()});
|
||||
//# sourceMappingURL=loader.min.js.map
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/loader.js"],"names":["rememberTabs","on","e","hash","target","attr","history","replaceState","location","window","tab","enablePopovers","popover","container","selector","trigger","document","addEventListener","key","closest","enableTooltips","tooltip","pendingPromise","Pending","Scroll","init","$","fn","dropdown","Constructor","Default","flip","Aria","resolve"],"mappings":"qSA0BA,OACA,OACA,OACA,OACA,OACA,O,sDAKMA,CAAAA,CAAY,CAAG,UAAM,CACvB,cAAE,wBAAF,EAA0BC,EAA1B,CAA6B,cAA7B,CAA6C,SAASC,CAAT,CAAY,CACrD,GAAIC,CAAAA,CAAI,CAAG,cAAED,CAAC,CAACE,MAAJ,EAAYC,IAAZ,CAAiB,MAAjB,CAAX,CACA,GAAIC,OAAO,CAACC,YAAZ,CAA0B,CACtBD,OAAO,CAACC,YAAR,CAAqB,IAArB,CAA2B,IAA3B,CAAiCJ,CAAjC,CACH,CAFD,IAEO,CACHK,QAAQ,CAACL,IAAT,CAAgBA,CACnB,CACJ,CAPD,EAQA,GAAIA,CAAAA,CAAI,CAAGM,MAAM,CAACD,QAAP,CAAgBL,IAA3B,CACA,GAAIA,CAAJ,CAAU,CACP,cAAE,oBAAqBA,CAArB,CAA4B,KAA9B,EAAoCO,GAApC,CAAwC,MAAxC,CACF,CACJ,C,CAMKC,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdC,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAGdC,OAAO,CAAE,OAHK,CAAlB,EAMAC,QAAQ,CAACC,gBAAT,CAA0B,SAA1B,CAAqC,SAAAf,CAAC,CAAI,CACtC,GAAc,QAAV,GAAAA,CAAC,CAACgB,GAAF,EAAsBhB,CAAC,CAACE,MAAF,CAASe,OAAT,CAAiB,2BAAjB,CAA1B,CAAuE,CACnE,cAAEjB,CAAC,CAACE,MAAJ,EAAYQ,OAAZ,CAAoB,MAApB,CACH,CACJ,CAJD,CAKH,C,CAMKQ,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdR,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAAlB,CAIH,C,CAEKQ,CAAc,CAAG,GAAIC,UAAJ,CAAY,yBAAZ,C,CAGvB,gBAGAvB,CAAY,GAGZW,CAAc,GAGdS,CAAc,GAGb,GAAII,UAAJ,EAAD,CAAeC,IAAf,GAGAC,UAAEC,EAAF,CAAKC,QAAL,CAAcC,WAAd,CAA0BC,OAA1B,CAAkCC,IAAlC,IAGAC,UAAKP,IAAL,GAEAH,CAAc,CAACW,OAAf,E","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Template renderer for Moodle. Load and render Moodle templates with Mustache.\n *\n * @module core/templates\n * @package core\n * @class templates\n * @copyright 2015 Damyon Wiese <damyon@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 2.9\n */\n\nimport $ from 'jquery';\nimport Aria from './aria';\nimport Bootstrap from './bootstrap/index';\nimport Pending from 'core/pending';\nimport Scroll from './scroll';\nimport setupBootstrapPendingChecks from './pending';\n\n/**\n * Rember the last visited tabs.\n */\nconst rememberTabs = () => {\n $('a[data-toggle=\"tab\"]').on('shown.bs.tab', function(e) {\n var hash = $(e.target).attr('href');\n if (history.replaceState) {\n history.replaceState(null, null, hash);\n } else {\n location.hash = hash;\n }\n });\n var hash = window.location.hash;\n if (hash) {\n $('.nav-link[href=\"' + hash + '\"]').tab('show');\n }\n};\n\n/**\n * Enable all popovers\n *\n */\nconst enablePopovers = () => {\n $('body').popover({\n container: 'body',\n selector: '[data-toggle=\"popover\"]',\n trigger: 'focus',\n });\n\n document.addEventListener('keydown', e => {\n if (e.key === 'Escape' && e.target.closest('[data-toggle=\"popover\"]')) {\n $(e.target).popover('hide');\n }\n });\n};\n\n/**\n * Enable tooltips\n *\n */\nconst enableTooltips = () => {\n $('body').tooltip({\n container: 'body',\n selector: '[data-toggle=\"tooltip\"]',\n });\n};\n\nconst pendingPromise = new Pending('theme_boost/loader:init');\n\n// Add pending promise event listeners to relevant Bootstrap custom events.\nsetupBootstrapPendingChecks();\n\n// Remember the last visited tabs.\nrememberTabs();\n\n// Enable all popovers.\nenablePopovers();\n\n// Enable all tooltips.\nenableTooltips();\n\n// Add scroll handling.\n(new Scroll()).init();\n\n// Disables flipping the dropdowns up and getting hidden behind the navbar.\n$.fn.dropdown.Constructor.Default.flip = false;\n\n// Setup Aria helpers for Bootstrap features.\nAria.init();\n\npendingPromise.resolve();\n\nexport {\n Bootstrap,\n};\n"],"file":"loader.min.js"}
|
||||
{"version":3,"sources":["../src/loader.js"],"names":["rememberTabs","on","e","hash","target","attr","history","replaceState","location","window","tab","document","querySelector","click","enablePopovers","popover","container","selector","trigger","addEventListener","key","closest","enableTooltips","tooltip","pendingPromise","Pending","Aria","init","Scroll","$","fn","dropdown","Constructor","Default","flip","resolve"],"mappings":"wkBA0BA,OACA,OACA,OACA,OACA,OACA,O,4lBAKMA,CAAAA,CAAY,CAAG,UAAM,CACvB,cAAE,wBAAF,EAA0BC,EAA1B,CAA6B,cAA7B,CAA6C,SAASC,CAAT,CAAY,CACrD,GAAIC,CAAAA,CAAI,CAAG,cAAED,CAAC,CAACE,MAAJ,EAAYC,IAAZ,CAAiB,MAAjB,CAAX,CACA,GAAIC,OAAO,CAACC,YAAZ,CAA0B,CACtBD,OAAO,CAACC,YAAR,CAAqB,IAArB,CAA2B,IAA3B,CAAiCJ,CAAjC,CACH,CAFD,IAEO,CACHK,QAAQ,CAACL,IAAT,CAAgBA,CACnB,CACJ,CAPD,EAQA,GAAMA,CAAAA,CAAI,CAAGM,MAAM,CAACD,QAAP,CAAgBL,IAA7B,CACA,GAAIA,CAAJ,CAAU,CACN,GAAMO,CAAAA,CAAG,CAAGC,QAAQ,CAACC,aAAT,CAAuB,oBAAqBT,CAArB,CAA4B,KAAnD,CAAZ,CACA,GAAIO,CAAJ,CAAS,CACLA,CAAG,CAACG,KAAJ,EACH,CACJ,CACJ,C,CAMKC,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdC,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAGdC,OAAO,CAAE,OAHK,CAAlB,EAMAP,QAAQ,CAACQ,gBAAT,CAA0B,SAA1B,CAAqC,SAAAjB,CAAC,CAAI,CACtC,GAAc,QAAV,GAAAA,CAAC,CAACkB,GAAF,EAAsBlB,CAAC,CAACE,MAAF,CAASiB,OAAT,CAAiB,2BAAjB,CAA1B,CAAuE,CACnE,cAAEnB,CAAC,CAACE,MAAJ,EAAYW,OAAZ,CAAoB,MAApB,CACH,CACJ,CAJD,CAKH,C,CAMKO,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdP,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAAlB,CAIH,C,CAEKO,CAAc,CAAG,GAAIC,UAAJ,CAAY,yBAAZ,C,CAGvB,gBAGAC,CAAI,CAACC,IAAL,GAGA3B,CAAY,GAGZc,CAAc,GAGdQ,CAAc,GAGb,GAAIM,UAAJ,EAAD,CAAeD,IAAf,GAGAE,UAAEC,EAAF,CAAKC,QAAL,CAAcC,WAAd,CAA0BC,OAA1B,CAAkCC,IAAlC,IAEAV,CAAc,CAACW,OAAf,E","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Template renderer for Moodle. Load and render Moodle templates with Mustache.\n *\n * @module core/templates\n * @package core\n * @class templates\n * @copyright 2015 Damyon Wiese <damyon@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 2.9\n */\n\nimport $ from 'jquery';\nimport * as Aria from './aria';\nimport Bootstrap from './bootstrap/index';\nimport Pending from 'core/pending';\nimport Scroll from './scroll';\nimport setupBootstrapPendingChecks from './pending';\n\n/**\n * Rember the last visited tabs.\n */\nconst rememberTabs = () => {\n $('a[data-toggle=\"tab\"]').on('shown.bs.tab', function(e) {\n var hash = $(e.target).attr('href');\n if (history.replaceState) {\n history.replaceState(null, null, hash);\n } else {\n location.hash = hash;\n }\n });\n const hash = window.location.hash;\n if (hash) {\n const tab = document.querySelector('.nav-link[href=\"' + hash + '\"]');\n if (tab) {\n tab.click();\n }\n }\n};\n\n/**\n * Enable all popovers\n *\n */\nconst enablePopovers = () => {\n $('body').popover({\n container: 'body',\n selector: '[data-toggle=\"popover\"]',\n trigger: 'focus',\n });\n\n document.addEventListener('keydown', e => {\n if (e.key === 'Escape' && e.target.closest('[data-toggle=\"popover\"]')) {\n $(e.target).popover('hide');\n }\n });\n};\n\n/**\n * Enable tooltips\n *\n */\nconst enableTooltips = () => {\n $('body').tooltip({\n container: 'body',\n selector: '[data-toggle=\"tooltip\"]',\n });\n};\n\nconst pendingPromise = new Pending('theme_boost/loader:init');\n\n// Add pending promise event listeners to relevant Bootstrap custom events.\nsetupBootstrapPendingChecks();\n\n// Setup Aria helpers for Bootstrap features.\nAria.init();\n\n// Remember the last visited tabs.\nrememberTabs();\n\n// Enable all popovers.\nenablePopovers();\n\n// Enable all tooltips.\nenableTooltips();\n\n// Add scroll handling.\n(new Scroll()).init();\n\n// Disables flipping the dropdowns up and getting hidden behind the navbar.\n$.fn.dropdown.Constructor.Default.flip = false;\n\npendingPromise.resolve();\n\nexport {\n Bootstrap,\n};\n"],"file":"loader.min.js"}
|
@ -20,181 +20,272 @@
|
||||
* @copyright 2018 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(['jquery', 'core/pending'], function($, Pending) {
|
||||
return {
|
||||
init: function() {
|
||||
// Drop downs from bootstrap don't support keyboard accessibility by default.
|
||||
var focusEnd = false,
|
||||
setFocusEnd = function() {
|
||||
focusEnd = true;
|
||||
},
|
||||
getFocusEnd = function() {
|
||||
var result = focusEnd;
|
||||
focusEnd = false;
|
||||
return result;
|
||||
};
|
||||
|
||||
// Special handling for "up" keyboard control.
|
||||
$('[data-toggle="dropdown"]').keydown(function(e) {
|
||||
var trigger = e.which || e.keyCode,
|
||||
expanded;
|
||||
import $ from 'jquery';
|
||||
import Pending from 'core/pending';
|
||||
|
||||
// Up key opens the menu at the end.
|
||||
if (trigger == 38) {
|
||||
// Focus the end of the menu, not the beginning.
|
||||
setFocusEnd();
|
||||
/**
|
||||
* Drop downs from bootstrap don't support keyboard accessibility by default.
|
||||
*/
|
||||
const dropdownFix = () => {
|
||||
let focusEnd = false;
|
||||
const setFocusEnd = () => {
|
||||
focusEnd = true;
|
||||
};
|
||||
const getFocusEnd = () => {
|
||||
const result = focusEnd;
|
||||
focusEnd = false;
|
||||
return result;
|
||||
};
|
||||
|
||||
// Special handling for "up" keyboard control.
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.target.matches('[data-toggle="dropdown"]')) {
|
||||
const trigger = e.key;
|
||||
|
||||
// Up key opens the menu at the end.
|
||||
if (trigger == 'ArrowUp') {
|
||||
// Focus the end of the menu, not the beginning.
|
||||
setFocusEnd();
|
||||
}
|
||||
|
||||
// Escape key only closes the menu, it doesn't open it.
|
||||
if (trigger == 'Escape') {
|
||||
const expanded = e.target.getAttribute('aria-expanded');
|
||||
e.preventDefault();
|
||||
if (expanded == "false") {
|
||||
e.target.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Escape key only closes the menu, it doesn't open it.
|
||||
if (trigger == 27) {
|
||||
expanded = $(e.target).attr('aria-expanded');
|
||||
e.preventDefault();
|
||||
if (expanded == "false") {
|
||||
$(e.target).click();
|
||||
}
|
||||
}
|
||||
// Space key or Enter key opens the menu.
|
||||
if (trigger == ' ' || trigger == 'Enter') {
|
||||
// Cancel random scroll.
|
||||
e.preventDefault();
|
||||
// Open the menu instead.
|
||||
e.target.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Space key or Enter key opens the menu.
|
||||
if (trigger == 32 || trigger == 13) {
|
||||
// Cancel random scroll.
|
||||
e.preventDefault();
|
||||
// Open the menu instead.
|
||||
$(e.target).click();
|
||||
}
|
||||
});
|
||||
// Special handling for navigation keys when menu is open.
|
||||
const shiftFocus = element => {
|
||||
const delayedFocus = pendingPromise => {
|
||||
element.focus();
|
||||
pendingPromise.resolve();
|
||||
};
|
||||
setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));
|
||||
};
|
||||
|
||||
// Special handling for navigation keys when menu is open.
|
||||
var shiftFocus = function(element) {
|
||||
var delayedFocus = function(pendingPromise) {
|
||||
$(this).focus();
|
||||
pendingPromise.resolve();
|
||||
}.bind(element);
|
||||
setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));
|
||||
};
|
||||
$('.dropdown').on('shown.bs.dropdown', e => {
|
||||
// We need to focus on the first menuitem.
|
||||
const menu = e.target.querySelector('[role="menu"]');
|
||||
let menuItems = false;
|
||||
let foundMenuItem = false;
|
||||
|
||||
$('.dropdown').on('shown.bs.dropdown', function(e) {
|
||||
// We need to focus on the first menuitem.
|
||||
var menu = $(e.target).find('[role="menu"]'),
|
||||
menuItems = false,
|
||||
foundMenuItem = false;
|
||||
if (menu) {
|
||||
menuItems = menu.querySelectorAll('[role="menuitem"]');
|
||||
}
|
||||
if (menuItems && menuItems.length > 0) {
|
||||
if (getFocusEnd()) {
|
||||
foundMenuItem = menuItems[menuItems.length - 1];
|
||||
} else {
|
||||
// The first menu entry, pretty reasonable.
|
||||
foundMenuItem = menuItems[0];
|
||||
}
|
||||
}
|
||||
if (foundMenuItem) {
|
||||
shiftFocus(foundMenuItem);
|
||||
}
|
||||
});
|
||||
// Search for menu items by finding the first item that has
|
||||
// text starting with the typed character (case insensitive).
|
||||
document.addEventListener('keypress', e => {
|
||||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
|
||||
const menu = e.target.closest('[role="menu"]');
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
const menuItems = menu.querySelectorAll('[role="menuitem"]');
|
||||
if (!menuItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (menu) {
|
||||
menuItems = $(menu).find('[role="menuitem"]');
|
||||
}
|
||||
if (menuItems && menuItems.length > 0) {
|
||||
if (getFocusEnd()) {
|
||||
foundMenuItem = menuItems[menuItems.length - 1];
|
||||
} else {
|
||||
// The first menu entry, pretty reasonable.
|
||||
foundMenuItem = menuItems[0];
|
||||
}
|
||||
}
|
||||
if (foundMenuItem) {
|
||||
shiftFocus(foundMenuItem);
|
||||
}
|
||||
});
|
||||
// Search for menu items by finding the first item that has
|
||||
// text starting with the typed character (case insensitive).
|
||||
$('.dropdown [role="menu"] [role="menuitem"]').keypress(function(e) {
|
||||
var trigger = String.fromCharCode(e.which || e.keyCode),
|
||||
menu = $(e.target).closest('[role="menu"]'),
|
||||
i = 0,
|
||||
menuItems = false,
|
||||
item,
|
||||
itemText;
|
||||
const trigger = e.key.toLowerCase();
|
||||
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
menuItems = $(menu).find('[role="menuitem"]');
|
||||
if (!menuItems) {
|
||||
return;
|
||||
for (let i = 0; i < menuItems.length; i++) {
|
||||
const item = menuItems[i];
|
||||
const itemText = item.text.trim().toLowerCase();
|
||||
if (itemText.indexOf(trigger) == 0) {
|
||||
shiftFocus(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
trigger = trigger.toLowerCase();
|
||||
for (i = 0; i < menuItems.length; i++) {
|
||||
item = $(menuItems[i]);
|
||||
itemText = item.text().trim().toLowerCase();
|
||||
if (itemText.indexOf(trigger) == 0) {
|
||||
shiftFocus(item);
|
||||
// Keyboard navigation for arrow keys, home and end keys.
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) {
|
||||
const trigger = e.key;
|
||||
let next = false;
|
||||
const menu = e.target.closest('[role="menu"]');
|
||||
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
const menuItems = menu.querySelectorAll('[role="menuitem"]');
|
||||
if (!menuItems) {
|
||||
return;
|
||||
}
|
||||
// Down key.
|
||||
if (trigger == 'ArrowDown') {
|
||||
for (let i = 0; i < menuItems.length - 1; i++) {
|
||||
if (menuItems[i] == e.target) {
|
||||
next = menuItems[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard navigation for arrow keys, home and end keys.
|
||||
$('.dropdown [role="menu"] [role="menuitem"]').keydown(function(e) {
|
||||
var trigger = e.which || e.keyCode,
|
||||
next = false,
|
||||
menu = $(e.target).closest('[role="menu"]'),
|
||||
i = 0,
|
||||
menuItems = false;
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
menuItems = $(menu).find('[role="menuitem"]');
|
||||
if (!menuItems) {
|
||||
return;
|
||||
}
|
||||
// Down key.
|
||||
if (trigger == 40) {
|
||||
for (i = 0; i < menuItems.length - 1; i++) {
|
||||
if (menuItems[i] == e.target) {
|
||||
next = menuItems[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!next) {
|
||||
// Wrap to first item.
|
||||
next = menuItems[0];
|
||||
}
|
||||
|
||||
} else if (trigger == 38) {
|
||||
// Up key.
|
||||
for (i = 1; i < menuItems.length; i++) {
|
||||
if (menuItems[i] == e.target) {
|
||||
next = menuItems[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!next) {
|
||||
// Wrap to last item.
|
||||
next = menuItems[menuItems.length - 1];
|
||||
}
|
||||
|
||||
} else if (trigger == 36) {
|
||||
// Home key.
|
||||
if (!next) {
|
||||
// Wrap to first item.
|
||||
next = menuItems[0];
|
||||
}
|
||||
|
||||
} else if (trigger == 35) {
|
||||
// End key.
|
||||
} else if (trigger == 'ArrowUp') {
|
||||
// Up key.
|
||||
for (let i = 1; i < menuItems.length; i++) {
|
||||
if (menuItems[i] == e.target) {
|
||||
next = menuItems[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!next) {
|
||||
// Wrap to last item.
|
||||
next = menuItems[menuItems.length - 1];
|
||||
}
|
||||
// Variable next is set if we do want to act on the keypress.
|
||||
if (next) {
|
||||
e.preventDefault();
|
||||
shiftFocus(next);
|
||||
}
|
||||
return;
|
||||
});
|
||||
$('.dropdown').on('hidden.bs.dropdown', function(e) {
|
||||
// We need to focus on the menu trigger.
|
||||
var trigger = $(e.target).find('[data-toggle="dropdown"]');
|
||||
if (trigger) {
|
||||
shiftFocus(trigger);
|
||||
}
|
||||
});
|
||||
|
||||
// After page load, focus on any element with special autofocus attribute.
|
||||
window.addEventListener("load", () => {
|
||||
const alerts = document.querySelectorAll('[data-aria-autofocus="true"][role="alert"]');
|
||||
Array.prototype.forEach.call(alerts, autofocusElement => {
|
||||
// According to the specification an role="alert" region is only read out on change to the content
|
||||
// of that region.
|
||||
autofocusElement.innerHTML += ' ';
|
||||
autofocusElement.removeAttribute('data-aria-autofocus');
|
||||
});
|
||||
});
|
||||
} else if (trigger == 'Home') {
|
||||
// Home key.
|
||||
next = menuItems[0];
|
||||
|
||||
} else if (trigger == 'End') {
|
||||
// End key.
|
||||
next = menuItems[menuItems.length - 1];
|
||||
}
|
||||
// Variable next is set if we do want to act on the keypress.
|
||||
if (next) {
|
||||
e.preventDefault();
|
||||
shiftFocus(next);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
$('.dropdown').on('hidden.bs.dropdown', e => {
|
||||
// We need to focus on the menu trigger.
|
||||
const trigger = e.target.querySelector('[data-toggle="dropdown"]');
|
||||
if (trigger) {
|
||||
shiftFocus(trigger);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* After page load, focus on any element with special autofocus attribute.
|
||||
*/
|
||||
const autoFocus = () => {
|
||||
window.addEventListener("load", () => {
|
||||
const alerts = document.querySelectorAll('[data-aria-autofocus="true"][role="alert"]');
|
||||
Array.prototype.forEach.call(alerts, autofocusElement => {
|
||||
// According to the specification an role="alert" region is only read out on change to the content
|
||||
// of that region.
|
||||
autofocusElement.innerHTML += ' ';
|
||||
autofocusElement.removeAttribute('data-aria-autofocus');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the focus to the correct tab based on the key that is pressed.
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
const updateTabFocus = e => {
|
||||
const tabList = e.target.closest('[role="tablist"]');
|
||||
const vertical = tabList.getAttribute('aria-orientation') == 'vertical';
|
||||
const rtl = window.right_to_left();
|
||||
const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight');
|
||||
const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft');
|
||||
const tabs = Array.prototype.filter.call(
|
||||
tabList.querySelectorAll('[role="tab"]'),
|
||||
tab => getComputedStyle(tab).display !== 'none'); // We only work with the visible tabs.
|
||||
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
tabs[i].index = i;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case arrowNext:
|
||||
e.preventDefault();
|
||||
if (e.target.index !== undefined && tabs[e.target.index + 1]) {
|
||||
tabs[e.target.index + 1].focus();
|
||||
} else {
|
||||
tabs[0].focus();
|
||||
}
|
||||
break;
|
||||
case arrowPrevious:
|
||||
e.preventDefault();
|
||||
if (e.target.index !== undefined && tabs[e.target.index - 1]) {
|
||||
tabs[e.target.index - 1].focus();
|
||||
} else {
|
||||
tabs[tabs.length - 1].focus();
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
e.preventDefault();
|
||||
tabs[0].focus();
|
||||
break;
|
||||
case 'End':
|
||||
e.preventDefault();
|
||||
tabs[tabs.length - 1].focus();
|
||||
break;
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
e.preventDefault();
|
||||
$(e.target).tab('show');
|
||||
tabs.forEach(tab => {
|
||||
tab.tabIndex = -1;
|
||||
});
|
||||
e.target.tabIndex = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs.
|
||||
*/
|
||||
const tabElementFix = () => {
|
||||
document.addEventListener('keydown', e => {
|
||||
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(e.key)) {
|
||||
if (e.target.matches('[role="tablist"] [role="tab"]')) {
|
||||
updateTabFocus(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', e => {
|
||||
if (e.target.matches('[role="tablist"] [role="tab"]')) {
|
||||
const tabs = e.target.closest('[role="tablist"]').querySelectorAll('[role="tab"]');
|
||||
e.preventDefault();
|
||||
$(e.target).tab('show');
|
||||
tabs.forEach(tab => {
|
||||
tab.tabIndex = -1;
|
||||
});
|
||||
e.target.tabIndex = 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const init = () => {
|
||||
dropdownFix();
|
||||
autoFocus();
|
||||
tabElementFix();
|
||||
};
|
||||
|
@ -25,7 +25,7 @@
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
import Aria from './aria';
|
||||
import * as Aria from './aria';
|
||||
import Bootstrap from './bootstrap/index';
|
||||
import Pending from 'core/pending';
|
||||
import Scroll from './scroll';
|
||||
@ -43,9 +43,12 @@ const rememberTabs = () => {
|
||||
location.hash = hash;
|
||||
}
|
||||
});
|
||||
var hash = window.location.hash;
|
||||
const hash = window.location.hash;
|
||||
if (hash) {
|
||||
$('.nav-link[href="' + hash + '"]').tab('show');
|
||||
const tab = document.querySelector('.nav-link[href="' + hash + '"]');
|
||||
if (tab) {
|
||||
tab.click();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -83,6 +86,9 @@ const pendingPromise = new Pending('theme_boost/loader:init');
|
||||
// Add pending promise event listeners to relevant Bootstrap custom events.
|
||||
setupBootstrapPendingChecks();
|
||||
|
||||
// Setup Aria helpers for Bootstrap features.
|
||||
Aria.init();
|
||||
|
||||
// Remember the last visited tabs.
|
||||
rememberTabs();
|
||||
|
||||
@ -98,9 +104,6 @@ enableTooltips();
|
||||
// Disables flipping the dropdowns up and getting hidden behind the navbar.
|
||||
$.fn.dropdown.Constructor.Default.flip = false;
|
||||
|
||||
// Setup Aria helpers for Bootstrap features.
|
||||
Aria.init();
|
||||
|
||||
pendingPromise.resolve();
|
||||
|
||||
export {
|
||||
|
@ -39,7 +39,9 @@
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
{{#tabs}}
|
||||
<li class="nav-item">
|
||||
<a href="#{{name}}" class="nav-link {{#active}}active{{/active}}" data-toggle="tab" role="tab">{{displayname}}</a>
|
||||
<a href="#{{name}}" class="nav-link {{#active}}active{{/active}}" data-toggle="tab" role="tab"
|
||||
{{#active}}aria-selected="true"{{/active}}
|
||||
{{^active}}aria-selected="false" tabindex="-1"{{/active}}>{{displayname}}</a>
|
||||
</li>
|
||||
{{/tabs}}
|
||||
</ul>
|
||||
|
Loading…
x
Reference in New Issue
Block a user