| Línea 19... |
Línea 19... |
| 19 |
* @module core_course/local/activitychooser/dialogue
|
19 |
* @module core_course/local/activitychooser/dialogue
|
| 20 |
* @copyright 2019 Mihail Geshoski <mihail@moodle.com>
|
20 |
* @copyright 2019 Mihail Geshoski <mihail@moodle.com>
|
| 21 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
21 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
| 22 |
*/
|
22 |
*/
|
| Línea 23... |
Línea 23... |
| 23 |
|
23 |
|
| 24 |
import $ from 'jquery';
|
24 |
import Carousel from 'theme_boost/bootstrap/carousel';
|
| 25 |
import * as ModalEvents from 'core/modal_events';
|
25 |
import * as ModalEvents from 'core/modal_events';
|
| 26 |
import selectors from 'core_course/local/activitychooser/selectors';
|
26 |
import selectors from 'core_course/local/activitychooser/selectors';
|
| 27 |
import * as Templates from 'core/templates';
|
27 |
import * as Templates from 'core/templates';
|
| 28 |
import {end, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';
|
28 |
import {end, arrowLeft, arrowRight, home, enter, space} from 'core/key_codes';
|
| 29 |
import {addIconToContainer} from 'core/loadingicon';
|
29 |
import {addIconToContainer} from 'core/loadingicon';
|
| 30 |
import * as Repository from 'core_course/local/activitychooser/repository';
|
30 |
import * as Repository from 'core_course/local/activitychooser/repository';
|
| 31 |
import Notification from 'core/notification';
|
31 |
import Notification from 'core/notification';
|
| - |
|
32 |
import {debounce} from 'core/utils';
|
| 32 |
import {debounce} from 'core/utils';
|
33 |
import {getFirst} from 'core/normalise';
|
| Línea 33... |
Línea 34... |
| 33 |
const getPlugin = pluginName => import(pluginName);
|
34 |
const getPlugin = pluginName => import(pluginName);
|
| 34 |
|
35 |
|
| 35 |
/**
|
36 |
/**
|
| 36 |
* Given an event from the main module 'page' navigate to it's help section via a carousel.
|
37 |
* Given an event from the main module 'page' navigate to it's help section via a carousel.
|
| 37 |
*
|
38 |
*
|
| 38 |
* @method showModuleHelp
|
39 |
* @method showModuleHelp
|
| 39 |
* @param {jQuery} carousel Our initialized carousel to manipulate
|
40 |
* @param {Element} carousel Our initialized carousel to manipulate
|
| 40 |
* @param {Object} moduleData Data of the module to carousel to
|
41 |
* @param {Object} moduleData Data of the module to carousel to
|
| 41 |
* @param {jQuery} modal We need to figure out if the current modal has a footer.
|
42 |
* @param {jQuery} modal We need to figure out if the current modal has a footer.
|
| 42 |
*/
|
43 |
*/
|
| 43 |
const showModuleHelp = (carousel, moduleData, modal = null) => {
|
44 |
const showModuleHelp = (carousel, moduleData, modal = null) => {
|
| 44 |
// If we have a real footer then we need to change temporarily.
|
45 |
// If we have a real footer then we need to change temporarily.
|
| 45 |
if (modal !== null && moduleData.showFooter === true) {
|
46 |
if (modal !== null && moduleData.showFooter === true) {
|
| 46 |
modal.setFooter(Templates.render('core_course/local/activitychooser/footer_partial', moduleData));
|
47 |
modal.setFooter(Templates.render('core_course/local/activitychooser/footer_partial', moduleData));
|
| 47 |
}
|
48 |
}
|
| 48 |
const help = carousel.find(selectors.regions.help)[0];
|
49 |
const help = carousel.querySelector(selectors.regions.help);
|
| Línea 49... |
Línea 50... |
| 49 |
help.innerHTML = '';
|
50 |
help.innerHTML = '';
|
| 50 |
help.classList.add('m-auto');
|
51 |
help.classList.add('m-auto');
|
| Línea 69... |
Línea 70... |
| 69 |
return help;
|
70 |
return help;
|
| 70 |
})
|
71 |
})
|
| 71 |
.catch(Notification.exception);
|
72 |
.catch(Notification.exception);
|
| Línea 72... |
Línea 73... |
| 72 |
|
73 |
|
| 73 |
// Move to the next slide, and resolve the transition promise when it's done.
|
74 |
// Move to the next slide, and resolve the transition promise when it's done.
|
| 74 |
carousel.one('slid.bs.carousel', () => {
|
75 |
carousel.addEventListener('slid.bs.carousel', () => {
|
| 75 |
transitionPromiseResolver();
|
76 |
transitionPromiseResolver();
|
| 76 |
});
|
77 |
}, {once: true});
|
| 77 |
// Trigger the transition between 'pages'.
|
78 |
// Trigger the transition between 'pages'.
|
| 78 |
carousel.carousel('next');
|
79 |
Carousel.getInstance(carousel).next();
|
| Línea 79... |
Línea 80... |
| 79 |
};
|
80 |
};
|
| 80 |
|
81 |
|
| 81 |
/**
|
82 |
/**
|
| Línea 113... |
Línea 114... |
| 113 |
* @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}
|
114 |
* @param {Map} mappedModules A map of all of the modules we are working with with K: mod_name V: {Object}
|
| 114 |
* @param {Function} partialFavourite Partially applied function we need to manage favourite status
|
115 |
* @param {Function} partialFavourite Partially applied function we need to manage favourite status
|
| 115 |
* @param {Object} footerData Our base footer object.
|
116 |
* @param {Object} footerData Our base footer object.
|
| 116 |
*/
|
117 |
*/
|
| 117 |
const registerListenerEvents = (modal, mappedModules, partialFavourite, footerData) => {
|
118 |
const registerListenerEvents = (modal, mappedModules, partialFavourite, footerData) => {
|
| - |
|
119 |
const modalBody = getFirst(modal.getBody());
|
| 118 |
const bodyClickListener = async(e) => {
|
120 |
const bodyClickListener = async(e) => {
|
| 119 |
if (e.target.closest(selectors.actions.optionActions.showSummary)) {
|
121 |
if (e.target.closest(selectors.actions.optionActions.showSummary)) {
|
| 120 |
const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));
|
122 |
const carousel = modalBody.querySelector(selectors.regions.carousel);
|
| Línea 121... |
Línea 123... |
| 121 |
|
123 |
|
| 122 |
const module = e.target.closest(selectors.regions.chooserOption.container);
|
124 |
const module = e.target.closest(selectors.regions.chooserOption.container);
|
| 123 |
const moduleName = module.dataset.modname;
|
125 |
const moduleName = module.dataset.modname;
|
| 124 |
const moduleData = mappedModules.get(moduleName);
|
126 |
const moduleData = mappedModules.get(moduleName);
|
| Línea 127... |
Línea 129... |
| 127 |
showModuleHelp(carousel, moduleData, modal);
|
129 |
showModuleHelp(carousel, moduleData, modal);
|
| 128 |
}
|
130 |
}
|
| Línea 129... |
Línea 131... |
| 129 |
|
131 |
|
| 130 |
if (e.target.closest(selectors.actions.optionActions.manageFavourite)) {
|
132 |
if (e.target.closest(selectors.actions.optionActions.manageFavourite)) {
|
| 131 |
const caller = e.target.closest(selectors.actions.optionActions.manageFavourite);
|
133 |
const caller = e.target.closest(selectors.actions.optionActions.manageFavourite);
|
| 132 |
await manageFavouriteState(modal.getBody()[0], caller, partialFavourite);
|
134 |
await manageFavouriteState(modalBody, caller, partialFavourite);
|
| 133 |
const activeSectionId = modal.getBody()[0].querySelector(selectors.elements.activetab).getAttribute("href");
|
135 |
const activeSectionId = modalBody.querySelector(selectors.elements.activetab).getAttribute("href");
|
| 134 |
const sectionChooserOptions = modal.getBody()[0]
|
136 |
const sectionChooserOptions = modalBody
|
| 135 |
.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));
|
137 |
.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));
|
| 136 |
const firstChooserOption = sectionChooserOptions
|
138 |
const firstChooserOption = sectionChooserOptions
|
| 137 |
.querySelector(selectors.regions.chooserOption.container);
|
139 |
.querySelector(selectors.regions.chooserOption.container);
|
| 138 |
toggleFocusableChooserOption(firstChooserOption, true);
|
140 |
toggleFocusableChooserOption(firstChooserOption, true);
|
| 139 |
initChooserOptionsKeyboardNavigation(modal.getBody()[0], mappedModules, sectionChooserOptions, modal);
|
141 |
initChooserOptionsKeyboardNavigation(modalBody, mappedModules, sectionChooserOptions, modal);
|
| Línea 140... |
Línea 142... |
| 140 |
}
|
142 |
}
|
| 141 |
|
143 |
|
| 142 |
// From the help screen go back to the module overview.
|
144 |
// From the help screen go back to the module overview.
|
| Línea 143... |
Línea 145... |
| 143 |
if (e.target.matches(selectors.actions.closeOption)) {
|
145 |
if (e.target.matches(selectors.actions.closeOption)) {
|
| 144 |
const carousel = $(modal.getBody()[0].querySelector(selectors.regions.carousel));
|
146 |
const carousel = modalBody.querySelector(selectors.regions.carousel);
|
| 145 |
|
147 |
|
| 146 |
// Trigger the transition between 'pages'.
|
148 |
// Trigger the transition between 'pages'.
|
| 147 |
carousel.carousel('prev');
|
149 |
Carousel.getInstance(carousel).prev();
|
| 148 |
carousel.on('slid.bs.carousel', () => {
|
150 |
carousel.addEventListener('slid.bs.carousel', () => {
|
| 149 |
const allModules = modal.getBody()[0].querySelector(selectors.regions.modules);
|
151 |
const allModules = modalBody.querySelector(selectors.regions.modules);
|
| 150 |
const caller = allModules.querySelector(selectors.regions.getModuleSelector(e.target.dataset.modname));
|
152 |
const caller = allModules.querySelector(selectors.regions.getModuleSelector(e.target.dataset.modname));
|
| Línea 151... |
Línea 153... |
| 151 |
caller.focus();
|
153 |
caller.focus();
|
| 152 |
});
|
154 |
});
|
| 153 |
}
|
155 |
}
|
| 154 |
|
156 |
|
| 155 |
// The "clear search" button is triggered.
|
157 |
// The "clear search" button is triggered.
|
| 156 |
if (e.target.closest(selectors.actions.clearSearch)) {
|
158 |
if (e.target.closest(selectors.actions.clearSearch)) {
|
| 157 |
// Clear the entered search query in the search bar and hide the search results container.
|
159 |
// Clear the entered search query in the search bar and hide the search results container.
|
| 158 |
const searchInput = modal.getBody()[0].querySelector(selectors.actions.search);
|
160 |
const searchInput = modalBody.querySelector(selectors.actions.search);
|
| 159 |
searchInput.value = "";
|
161 |
searchInput.value = "";
|
| Línea 178... |
Línea 180... |
| 178 |
// The return value of getBodyPromise is a jquery object containing the body NodeElement.
|
180 |
// The return value of getBodyPromise is a jquery object containing the body NodeElement.
|
| 179 |
.then(body => body[0])
|
181 |
.then(body => body[0])
|
| Línea 180... |
Línea 182... |
| 180 |
|
182 |
|
| 181 |
// Set up the carousel.
|
183 |
// Set up the carousel.
|
| 182 |
.then(body => {
|
184 |
.then(body => {
|
| 183 |
$(body.querySelector(selectors.regions.carousel))
|
185 |
const carousel = document.querySelector(selectors.regions.carousel);
|
| 184 |
.carousel({
|
186 |
new Carousel(carousel, {
|
| 185 |
interval: false,
|
187 |
interval: false,
|
| 186 |
pause: true,
|
188 |
pause: true,
|
| 187 |
keyboard: false
|
189 |
keyboard: false
|
| Línea 188... |
Línea 190... |
| 188 |
});
|
190 |
});
|
| 189 |
|
191 |
|
| Línea 190... |
Línea 192... |
| 190 |
return body;
|
192 |
return body;
|
| Línea 217... |
Línea 219... |
| 217 |
toggleFocusableChooserOption(firstChooserOption, true);
|
219 |
toggleFocusableChooserOption(firstChooserOption, true);
|
| 218 |
initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions, modal);
|
220 |
initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions, modal);
|
| Línea 219... |
Línea 221... |
| 219 |
|
221 |
|
| 220 |
return body;
|
222 |
return body;
|
| 221 |
})
|
223 |
})
|
| Línea 222... |
Línea 224... |
| 222 |
.catch();
|
224 |
.catch(Notification.exception);
|
| Línea 223... |
Línea 225... |
| 223 |
|
225 |
|
| 224 |
modal.getFooterPromise()
|
226 |
modal.getFooterPromise()
|
| 225 |
|
227 |
|
| 226 |
// The return value of getBodyPromise is a jquery object containing the body NodeElement.
|
228 |
// The return value of getBodyPromise is a jquery object containing the body NodeElement.
|
| 227 |
.then(footer => footer[0])
|
229 |
.then(footer => footer[0])
|
| 228 |
// Add the listener for clicks on the footer.
|
230 |
// Add the listener for clicks on the footer.
|
| 229 |
.then(footer => {
|
231 |
.then(footer => {
|
| 230 |
footer.addEventListener('click', footerClickListener);
|
232 |
footer.addEventListener('click', footerClickListener);
|
| 231 |
return footer;
|
233 |
return footer;
|
| Línea 232... |
Línea 234... |
| 232 |
})
|
234 |
})
|
| 233 |
.catch();
|
235 |
.catch(Notification.exception);
|
| 234 |
};
|
236 |
};
|
| Línea 253... |
Línea 255... |
| 253 |
if (e.target.matches(selectors.actions.optionActions.showSummary)) {
|
255 |
if (e.target.matches(selectors.actions.optionActions.showSummary)) {
|
| 254 |
e.preventDefault();
|
256 |
e.preventDefault();
|
| 255 |
const module = e.target.closest(selectors.regions.chooserOption.container);
|
257 |
const module = e.target.closest(selectors.regions.chooserOption.container);
|
| 256 |
const moduleName = module.dataset.modname;
|
258 |
const moduleName = module.dataset.modname;
|
| 257 |
const moduleData = mappedModules.get(moduleName);
|
259 |
const moduleData = mappedModules.get(moduleName);
|
| 258 |
const carousel = $(body.querySelector(selectors.regions.carousel));
|
260 |
const carousel = document.querySelector(selectors.regions.carousel);
|
| 259 |
carousel.carousel({
|
261 |
new Carousel({
|
| 260 |
interval: false,
|
262 |
interval: false,
|
| 261 |
pause: true,
|
263 |
pause: true,
|
| 262 |
keyboard: false
|
264 |
keyboard: false
|
| 263 |
});
|
265 |
});
|
| Línea 456... |
Línea 458... |
| 456 |
*/
|
458 |
*/
|
| 457 |
const setupKeyboardAccessibility = (modal, mappedModules) => {
|
459 |
const setupKeyboardAccessibility = (modal, mappedModules) => {
|
| 458 |
modal.getModal()[0].tabIndex = -1;
|
460 |
modal.getModal()[0].tabIndex = -1;
|
| Línea 459... |
Línea 461... |
| 459 |
|
461 |
|
| - |
|
462 |
modal.getBodyPromise().then(body => {
|
| 460 |
modal.getBodyPromise().then(body => {
|
463 |
document.querySelectorAll(selectors.elements.tab).forEach((tab) => {
|
| 461 |
$(selectors.elements.tab).on('shown.bs.tab', (e) => {
|
464 |
tab.addEventListener('shown.bs.tab', (e) => {
|
| 462 |
const activeSectionId = e.target.getAttribute("href");
|
465 |
const activeSectionId = e.target.getAttribute("href");
|
| 463 |
const activeSectionChooserOptions = body[0]
|
466 |
const activeSectionChooserOptions = body[0]
|
| 464 |
.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));
|
467 |
.querySelector(selectors.regions.getSectionChooserOptions(activeSectionId));
|
| 465 |
const firstChooserOption = activeSectionChooserOptions
|
468 |
const firstChooserOption = activeSectionChooserOptions
|
| 466 |
.querySelector(selectors.regions.chooserOption.container);
|
469 |
.querySelector(selectors.regions.chooserOption.container);
|
| 467 |
const prevActiveSectionId = e.relatedTarget.getAttribute("href");
|
470 |
const prevActiveSectionId = e.relatedTarget.getAttribute("href");
|
| 468 |
const prevActiveSectionChooserOptions = body[0]
|
471 |
const prevActiveSectionChooserOptions = body[0]
|
| 469 |
.querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId));
|
472 |
.querySelector(selectors.regions.getSectionChooserOptions(prevActiveSectionId));
|
| 470 |
|
473 |
|
| 471 |
// Disable the focus of every chooser option in the previous active section.
|
474 |
// Disable the focus of every chooser option in the previous active section.
|
| 472 |
disableFocusAllChooserOptions(prevActiveSectionChooserOptions);
|
475 |
disableFocusAllChooserOptions(prevActiveSectionChooserOptions);
|
| 473 |
// Enable the focus of the first chooser option in the current active section.
|
476 |
// Enable the focus of the first chooser option in the current active section.
|
| 474 |
toggleFocusableChooserOption(firstChooserOption, true);
|
477 |
toggleFocusableChooserOption(firstChooserOption, true);
|
| - |
|
478 |
initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions, modal);
|
| 475 |
initChooserOptionsKeyboardNavigation(body[0], mappedModules, activeSectionChooserOptions, modal);
|
479 |
});
|
| 476 |
});
|
480 |
});
|
| 477 |
return;
|
481 |
return;
|
| 478 |
}).catch(Notification.exception);
|
482 |
}).catch(Notification.exception);
|
| Línea 518... |
Línea 522... |
| 518 |
modal.getRoot().on(ModalEvents.hidden, () => {
|
522 |
modal.getRoot().on(ModalEvents.hidden, () => {
|
| 519 |
modal.destroy();
|
523 |
modal.destroy();
|
| 520 |
});
|
524 |
});
|
| Línea 521... |
Línea 525... |
| 521 |
|
525 |
|
| 522 |
return modal;
|
526 |
return modal;
|
| 523 |
}).catch();
|
527 |
}).catch(Notification.exception);
|