MDL-67321 core_course: Add support for tabbing activities in the chooser
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core_course/activitychooser",["exports","core_course/local/activitychooser/dialogue","core_course/local/activitychooser/repository","core_course/local/activitychooser/selectors","core/custom_interaction_events","core/templates","core/modal_factory","core/str","core/pending"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=k(b);c=k(c);d=j(d);e=j(e);f=k(f);g=k(g);i=j(i);function j(a){return a&&a.__esModule?a:{default:a}}function k(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}var n=function(a){var b=new i.default;o(a);b.resolve()};a.init=n;var o=function(a){var f=["click",e.default.events.activate,e.default.events.keyboardActivate],g=function(){var b=null;return function(){if(!b){b=new Promise(function(b){b(c.activityModules(a))})}return b}}();e.default.define(document,f);f.forEach(function(a){document.addEventListener(a,function(){var a=m(regeneratorRuntime.mark(function a(c){var e,f,h;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.closest(d.default.elements.sectionmodchooser)){a.next=12;break}e=c.target.closest(d.default.elements.sectionmodchooser);a.t0=p;a.next=5;return g();case 5:a.t1=a.sent;a.t2=e.dataset.sectionid;f=(0,a.t0)(a.t1,a.t2);a.next=10;return q(f);case 10:h=a.sent;b.displayChooser(e,h,f);case 12:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}())})},p=function(a,b){var c=JSON.parse(JSON.stringify(a));c.allmodules.forEach(function(a){a.urls.addoption+="§ion="+b});return c.allmodules},q=function(a){return s(r(a))},r=function(a){return{default:a}},s=function(a){return g.create({type:g.types.DEFAULT,title:(0,h.get_string)("addresourceoractivity"),body:f.render("core_course/chooser",a),large:!0,templateContext:{classes:"modchooser"}})}});
|
||||
define ("core_course/activitychooser",["exports","core_course/local/activitychooser/dialogue","core_course/local/activitychooser/repository","core_course/local/activitychooser/selectors","core/custom_interaction_events","core/templates","core/modal_factory","core/str","core/pending"],function(a,b,c,d,e,f,g,h,i){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=k(b);c=k(c);d=j(d);e=j(e);f=k(f);g=k(g);i=j(i);function j(a){return a&&a.__esModule?a:{default:a}}function k(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}var n=function(a){var b=new i.default;o(a);b.resolve()};a.init=n;var o=function(a){var f=["click",e.default.events.activate,e.default.events.keyboardActivate],g=function(){var b=null;return function(){if(!b){b=new Promise(function(b){b(c.activityModules(a))})}return b}}();e.default.define(document,f);f.forEach(function(a){document.addEventListener(a,function(){var a=m(regeneratorRuntime.mark(function a(c){var e,f,h;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.closest(d.default.elements.sectionmodchooser)){a.next=12;break}e=c.target.closest(d.default.elements.sectionmodchooser);a.t0=p;a.next=5;return g();case 5:a.t1=a.sent;a.t2=e.dataset.sectionid;f=(0,a.t0)(a.t1,a.t2);a.next=10;return q(f);case 10:h=a.sent;b.displayChooser(e,h,f);case 12:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}())})},p=function(a,b){var c=JSON.parse(JSON.stringify(a));c.allmodules.forEach(function(a){a.urls.addoption+="§ion="+b});return c.allmodules},q=function(a){return s(r(a))},r=function(a){var b=[],c=[],d=!!b.length,e=!!(c.length&&!1===d);return{default:a,favourites:b,recommended:c,favouritesFirst:d,recommendedFirst:e,fallback:!1===d&&!1===e}},s=function(a){return g.create({type:g.types.DEFAULT,title:(0,h.get_string)("addresourceoractivity"),body:f.render("core_course/chooser",a),large:!0,templateContext:{classes:"modchooser"}})}});
|
||||
//# sourceMappingURL=activitychooser.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
@@ -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"),chooserOptions: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"),description:b("region","summary-description"),actions:b("region","chooser-option-summary-actions-container")},carousel:b("region","carousel"),help:b("region","help"),modules:b("region","modules"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")}},actions:{optionActions:{showSummary:b("action","show-option-summary")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic"}};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"),chooserOptions: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"),description:b("region","summary-description"),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"),favouriteTab:b("region","favourites"),recommendedTab:b("region","recommended"),defaultTab:b("region","default"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")}},actions:{optionActions:{showSummary:b("action","show-option-summary")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic"}};a.default=c;return a.default});
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -123,8 +123,26 @@ const modalBuilder = data => buildModal(templateDataBuilder(data));
|
||||
* @return {Object} Our built object ready to render out
|
||||
*/
|
||||
const templateDataBuilder = (data) => {
|
||||
// Filter the incoming data to find favourite & recommended modules.
|
||||
const favourites = [];
|
||||
const recommended = [];
|
||||
|
||||
// Given the results of the above filters lets figure out what tab to set active.
|
||||
|
||||
// We have some favourites.
|
||||
const favouritesFirst = !!favourites.length;
|
||||
// Check if we have no favourites but have some recommended.
|
||||
const recommendedFirst = !!(recommended.length && favouritesFirst === false);
|
||||
// We have nothing fallback to show all modules.
|
||||
const fallback = favouritesFirst === false && recommendedFirst === false;
|
||||
|
||||
return {
|
||||
'default': data,
|
||||
favourites: favourites,
|
||||
recommended: recommended,
|
||||
favouritesFirst: favouritesFirst,
|
||||
recommendedFirst: recommendedFirst,
|
||||
fallback: fallback,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -137,11 +137,71 @@ const registerListenerEvents = (modal, mappedModules) => {
|
||||
* Initialise the keyboard navigation controls for the chooser.
|
||||
*
|
||||
* @method initKeyboardNavigation
|
||||
* @param {NodeElement} body Our modal that we are working with
|
||||
* @param {HTMLElement} body Our modal that we are working with
|
||||
* @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}
|
||||
*/
|
||||
const initKeyboardNavigation = (body, mappedModules) => {
|
||||
|
||||
// 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 tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav];
|
||||
tabNavArray.forEach((element) => {
|
||||
return element.addEventListener('keyup', (e) => {
|
||||
const firstLink = e.target.parentElement.parentElement.firstElementChild.firstElementChild;
|
||||
const lastLink = e.target.parentElement.parentElement.lastElementChild.firstElementChild;
|
||||
|
||||
if (e.keyCode === arrowRight) {
|
||||
const nextLink = e.target.parentElement.nextElementSibling;
|
||||
if (nextLink === null) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
} else if (nextLink.firstElementChild.classList.contains('d-none')) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
} else {
|
||||
e.srcElement.tabIndex = -1;
|
||||
nextLink.firstElementChild.tabIndex = 0;
|
||||
nextLink.firstElementChild.focus();
|
||||
}
|
||||
}
|
||||
if (e.keyCode === arrowLeft) {
|
||||
const previousLink = e.target.parentElement.previousElementSibling;
|
||||
if (previousLink === null) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
} else if (previousLink.firstElementChild.classList.contains('d-none')) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
} else {
|
||||
e.srcElement.tabIndex = -1;
|
||||
previousLink.firstElementChild.tabIndex = 0;
|
||||
previousLink.firstElementChild.focus();
|
||||
}
|
||||
}
|
||||
if (e.keyCode === home) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
firstLink.tabIndex = 0;
|
||||
firstLink.focus();
|
||||
}
|
||||
if (e.keyCode === end) {
|
||||
e.srcElement.tabIndex = -1;
|
||||
lastLink.tabIndex = 0;
|
||||
lastLink.focus();
|
||||
}
|
||||
if (e.keyCode === space) {
|
||||
e.preventDefault();
|
||||
e.target.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Set up the handlers for the modules.
|
||||
const chooserOptions = body.querySelectorAll(selectors.regions.chooserOption.container);
|
||||
|
||||
Array.from(chooserOptions).forEach((element) => {
|
||||
|
||||
@@ -51,6 +51,12 @@ export default {
|
||||
carousel: getDataSelector('region', 'carousel'),
|
||||
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'),
|
||||
favouriteTab: getDataSelector('region', 'favourites'),
|
||||
recommendedTab: getDataSelector('region', 'recommended'),
|
||||
defaultTab: getDataSelector('region', 'default'),
|
||||
getModuleSelector: modname => `[role="menuitem"][data-modname="${modname}"]`
|
||||
},
|
||||
actions: {
|
||||
|
||||
@@ -34,12 +34,80 @@
|
||||
}}
|
||||
<div data-region="carousel" class="carousel slide">
|
||||
<div class="carousel-inner" aria-live="polite">
|
||||
<div class="carousel-item active" data-region="modules">
|
||||
<div class="modchoosercontainer" data-region="chooser-container" aria-label="{{#str}} activitymodules {{/str}}">
|
||||
<div class="optionscontainer d-flex flex-wrap mw-100 p-3 position-relative" role="menubar" data-region="chooser-options-container">
|
||||
{{#default}}
|
||||
{{>core_course/chooser_item}}
|
||||
{{/default}}
|
||||
<div class="carousel-item p-4 active" data-region="modules">
|
||||
<ul class="nav nav-tabs mb-2" id="activities-{{uniqid}}" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#favouritesFirst}}active{{/favouritesFirst}} {{^favourites}}d-none{{/favourites}}"
|
||||
id="starred-tab-{{uniqid}}"
|
||||
data-toggle="tab"
|
||||
data-region="favourite-tab-nav"
|
||||
href="#starred-{{uniqid}}"
|
||||
role="tab"
|
||||
aria-label="{{#str}} aria:favouritestab, core_course {{/str}}"
|
||||
aria-controls="starred-{{uniqid}}"
|
||||
aria-selected="{{#favouritesFirst}}true{{/favouritesFirst}}{{^favouritesFirst}}false{{/favouritesFirst}}"
|
||||
tabindex="{{#favouritesFirst}}0{{/favouritesFirst}}{{^favouritesFirst}}-1{{/favouritesFirst}}"
|
||||
>
|
||||
{{#str}}favourites{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#recommendedFirst}}active{{/recommendedFirst}} {{^recommended}}d-none{{/recommended}}"
|
||||
id="recommended-tab-{{uniqid}}"
|
||||
data-region="recommended-tab-nav"
|
||||
data-toggle="tab"
|
||||
href="#recommended-{{uniqid}}"
|
||||
role="tab"
|
||||
aria-label="{{#str}} aria:recommendedtab, core_course {{/str}}"
|
||||
aria-controls="recommended-{{uniqid}}"
|
||||
aria-selected="{{#recommendedFirst}}true{{/recommendedFirst}}{{^recommendedFirst}}false{{/recommendedFirst}}"
|
||||
tabindex="{{#recommendedFirst}}0{{/recommendedFirst}}{{^recommendedFirst}}-1{{/recommendedFirst}}">
|
||||
{{#str}}recommended{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#fallback}}active{{/fallback}}"
|
||||
id="all-tab-{{uniqid}}"
|
||||
data-toggle="tab"
|
||||
data-region="default-tab-nav"
|
||||
href="#all-{{uniqid}}"
|
||||
role="tab"
|
||||
aria-label="{{#str}} aria:defaulttab, core_course {{/str}}"
|
||||
aria-controls="all-{{uniqid}}"
|
||||
aria-selected="{{#fallback}}true{{/fallback}}{{^fallback}}false{{/fallback}}"
|
||||
tabindex="{{#fallback}}0{{/fallback}}{{^fallback}}-1{{/fallback}}"
|
||||
>
|
||||
{{#str}}activities{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content" id="tabbed-activities-{{uniqid}}">
|
||||
<div class="tab-pane {{#favouritesFirst}}active{{/favouritesFirst}}" id="starred-{{uniqid}}" data-region="favourites" role="tabpanel" aria-labelledby="starred-tab-{{uniqid}}">
|
||||
<div class="modchoosercontainer" data-region="chooser-container" aria-label="{{#str}} activitymodules {{/str}}">
|
||||
<div class="optionscontainer d-flex flex-wrap mw-100 p-3 position-relative" role="menubar" data-region="chooser-options-container" data-render="favourites-area">
|
||||
{{#favourites}}
|
||||
{{>core_course/chooser_item}}
|
||||
{{/favourites}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane {{#recommendedFirst}}active{{/recommendedFirst}}" id="recommended-{{uniqid}}" data-region="recommended" role="tabpanel" aria-labelledby="recommended-tab-{{uniqid}}">
|
||||
<div class="modchoosercontainer" data-region="chooser-container" aria-label="{{#str}} activitymodules {{/str}}">
|
||||
<div class="optionscontainer d-flex flex-wrap mw-100 p-3 position-relative" role="menubar" data-region="chooser-options-container">
|
||||
{{#recommended}}
|
||||
{{>core_course/chooser_item}}
|
||||
{{/recommended}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane {{#fallback}}active{{/fallback}}" id="all-{{uniqid}}" data-region="default" role="tabpanel" aria-labelledby="all-tab-{{uniqid}}">
|
||||
<div class="modchoosercontainer" data-region="chooser-container" aria-label="{{#str}} activitymodules {{/str}}">
|
||||
<div class="optionscontainer d-flex flex-wrap mw-100 p-3 position-relative" role="menubar" data-region="chooser-options-container">
|
||||
{{#default}}
|
||||
{{>core_course/chooser_item}}
|
||||
{{/default}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,3 +53,9 @@ Feature: Display and choose from the available activities in course
|
||||
And "help" "core_course > Activity chooser screen" should not exist
|
||||
And "Back" "button" should not exist in the "modules" "core_course > Activity chooser screen"
|
||||
And I should not see "The assignment activity module enables a teacher to communicate tasks, collect work and provide grades and feedback." in the "Add an activity or resource" "dialogue"
|
||||
|
||||
# Currently stubbed out in MDL-67321 as further issues will add more tabs.
|
||||
Scenario: Navigate between module tabs
|
||||
Given I open the activity chooser
|
||||
And I should see "Activities" in the "Add an activity or resource" "dialogue"
|
||||
Then I should see "Forum" in the "default" "core_course > Activity chooser tab"
|
||||
|
||||
@@ -54,6 +54,11 @@ class behat_course extends behat_base {
|
||||
"%core_course/activityChooser%//*[@data-region=%locator%][contains(concat(' ', @class, ' '), ' carousel-item ')]"
|
||||
]
|
||||
),
|
||||
new behat_component_named_selector(
|
||||
'Activity chooser tab', [
|
||||
"%core_course/activityChooser%//*[@data-region=%locator%][contains(concat(' ', @class, ' '), ' tab-pane ')]"
|
||||
]
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ $string['aria:coursecategory'] = 'Course category';
|
||||
$string['aria:courseimage'] = 'Course image';
|
||||
$string['aria:courseshortname'] = 'Course short name';
|
||||
$string['aria:coursename'] = 'Course name';
|
||||
$string['aria:defaulttab'] = 'The default modules';
|
||||
$string['aria:favourite'] = 'Course is starred';
|
||||
$string['aria:favouritestab'] = 'Your starred modules';
|
||||
$string['aria:recommendedtab'] = 'The recommended modules';
|
||||
$string['coursealreadyfinished'] = 'Course already finished';
|
||||
$string['coursenotyetstarted'] = 'The course has not yet started';
|
||||
$string['coursenotyetfinished'] = 'The course has not yet finished';
|
||||
|
||||
@@ -1637,6 +1637,7 @@ $string['readme'] = 'README';
|
||||
$string['recentactivity'] = 'Recent activity';
|
||||
$string['recentactivityreport'] = 'Full report of recent activity...';
|
||||
$string['recipientslist'] = 'Recipients list';
|
||||
$string['recommended'] = 'Recommended';
|
||||
$string['recreatedcategory'] = 'Recreated category {$a}';
|
||||
$string['redirect'] = 'Redirect';
|
||||
$string['reducesections'] = 'Reduce the number of sections';
|
||||
|
||||
Reference in New Issue
Block a user