This commit is contained in:
Jun Pataleta 2020-02-19 14:44:13 +08:00
commit 56a73a3f1e
14 changed files with 180 additions and 13 deletions

View File

@ -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+="&section="+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+="&section="+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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -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,
};
};

View File

@ -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) => {

View File

@ -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: {

View File

@ -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>

View File

@ -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"

View File

@ -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 ')]"
]
),
];
}

View File

@ -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';

View File

@ -1644,6 +1644,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';