on-demand release 2.8beta+
[moodle.git] / mod / quiz / yui / build / moodle-mod_quiz-toolboxes / moodle-mod_quiz-toolboxes.js
CommitLineData
e1a2d0d9
CC
1YUI.add('moodle-mod_quiz-toolboxes', function (Y, NAME) {
2
3/**
4 * Resource and activity toolbox class.
5 *
6 * This class is responsible for managing AJAX interactions with activities and resources
7 * when viewing a course in editing mode.
8 *
9 * @module moodle-course-toolboxes
10 * @namespace M.course.toolboxes
11 */
12
13// The CSS classes we use.
14 var CSS = {
15 ACTIVITYINSTANCE : 'activityinstance',
16 AVAILABILITYINFODIV : 'div.availabilityinfo',
17 CONTENTWITHOUTLINK : 'contentwithoutlink',
18 CONDITIONALHIDDEN : 'conditionalhidden',
19 DIMCLASS : 'dimmed',
20 DIMMEDTEXT : 'dimmed_text',
21 EDITINSTRUCTIONS : 'editinstructions',
22 EDITINGMAXMARK: 'editor_displayed',
23 HIDE : 'hide',
24 JOIN: 'page_join',
25 MODINDENTCOUNT : 'mod-indent-',
26 MODINDENTHUGE : 'mod-indent-huge',
27 MODULEIDPREFIX : 'slot-',
28 PAGE: 'page',
29 SECTIONHIDDENCLASS : 'hidden',
30 SECTIONIDPREFIX : 'section-',
31 SLOT : 'slot',
32 SHOW : 'editing_show',
33 TITLEEDITOR : 'titleeditor'
34 },
35 // The CSS selectors we use.
36 SELECTOR = {
37 ACTIONAREA: '.actions',
38 ACTIONLINKTEXT : '.actionlinktext',
39 ACTIVITYACTION : 'a.cm-edit-action[data-action], a.editing_maxmark',
40 ACTIVITYFORM : 'span.instancemaxmarkcontainer form',
41 ACTIVITYICON : 'img.activityicon',
42 ACTIVITYINSTANCE : '.' + CSS.ACTIVITYINSTANCE,
43 ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a',
44 ACTIVITYLI : 'li.activity',
45 ACTIVITYMAXMARK : 'input[name=maxmark]',
46 COMMANDSPAN : '.commands',
47 CONTENTAFTERLINK : 'div.contentafterlink',
48 CONTENTWITHOUTLINK : 'div.contentwithoutlink',
49 EDITMAXMARK: 'a.editing_maxmark',
50 HIDE : 'a.editing_hide',
51 HIGHLIGHT : 'a.editing_highlight',
52 INSTANCENAME : 'span.instancename',
53 INSTANCEMAXMARK : 'span.instancemaxmark',
54 MODINDENTDIV : '.mod-indent',
55 MODINDENTOUTER : '.mod-indent-outer',
56 PAGECONTENT : 'div#page-content',
57 PAGELI : 'li.page',
58 SECTIONUL : 'ul.section',
59 SHOW : 'a.' + CSS.SHOW,
60 SHOWHIDE : 'a.editing_showhide',
61 SLOTLI : 'li.slot',
62 SUMMARKS : '.mod_quiz_summarks'
63 },
64 BODY = Y.one(document.body);
65
66// Setup the basic namespace.
67M.mod_quiz = M.mod_quiz || {};
68
69/**
70 * The toolbox class is a generic class which should never be directly
71 * instantiated. Please extend it instead.
72 *
73 * @class toolbox
74 * @constructor
75 * @protected
76 * @extends Base
77 */
78var TOOLBOX = function() {
79 TOOLBOX.superclass.constructor.apply(this, arguments);
80};
81
82Y.extend(TOOLBOX, Y.Base, {
83 /**
84 * Send a request using the REST API
85 *
86 * @method send_request
87 * @param {Object} data The data to submit with the AJAX request
88 * @param {Node} [statusspinner] A statusspinner which may contain a section loader
89 * @param {Function} success_callback The callback to use on success
90 * @param {Object} [optionalconfig] Any additional configuration to submit
91 * @chainable
92 */
93 send_request: function(data, statusspinner, success_callback, optionalconfig) {
94 // Default data structure
95 if (!data) {
96 data = {};
97 }
98 // Handle any variables which we must pass back through to
99 var pageparams = this.get('config').pageparams,
100 varname;
101 for (varname in pageparams) {
102 data[varname] = pageparams[varname];
103 }
104
105 data.sesskey = M.cfg.sesskey;
106 data.courseid = this.get('courseid');
107 data.quizid = this.get('quizid');
108
109 var uri = M.cfg.wwwroot + this.get('ajaxurl');
110
111 // Define the configuration to send with the request
112 var responsetext = [];
113 var config = {
114 method: 'POST',
115 data: data,
116 on: {
117 success: function(tid, response) {
118 try {
119 responsetext = Y.JSON.parse(response.responseText);
120 if (responsetext.error) {
121 new M.core.ajaxException(responsetext);
122 }
123 } catch (e) {}
124
125 // Run the callback if we have one.
126 if (responsetext.newsummarks) {
127 Y.one(SELECTOR.SUMMARKS).setHTML(responsetext.newsummarks);
128 }
129 if (success_callback) {
130 Y.bind(success_callback, this, responsetext)();
131 }
132
133 if (statusspinner) {
134 window.setTimeout(function() {
135 statusspinner.hide();
136 }, 400);
137 }
138 },
139 failure: function(tid, response) {
140 if (statusspinner) {
141 statusspinner.hide();
142 }
143 new M.core.ajaxException(response);
144 }
145 },
146 context: this
147 };
148
149 // Apply optional config
150 if (optionalconfig) {
151 for (varname in optionalconfig) {
152 config[varname] = optionalconfig[varname];
153 }
154 }
155
156 if (statusspinner) {
157 statusspinner.show();
158 }
159
160 // Send the request
161 Y.io(uri, config);
162 return this;
163 }
164},
165{
166 NAME: 'mod_quiz-toolbox',
167 ATTRS: {
168 /**
169 * The ID of the Moodle Course being edited.
170 *
171 * @attribute courseid
172 * @default 0
173 * @type Number
174 */
175 courseid: {
176 'value': 0
177 },
178
179 /**
180 * The Moodle course format.
181 *
182 * @attribute format
183 * @default 'topics'
184 * @type String
185 */
186 quizid: {
187 'value': 0
188 },
189 /**
190 * The URL to use when submitting requests.
191 * @attribute ajaxurl
192 * @default null
193 * @type String
194 */
195 ajaxurl: {
196 'value': null
197 },
198 /**
199 * Any additional configuration passed when creating the instance.
200 *
201 * @attribute config
202 * @default {}
203 * @type Object
204 */
205 config: {
206 'value': {}
207 }
208 }
209}
210);
211/**
212 * Resource and activity toolbox class.
213 *
214 * This class is responsible for managing AJAX interactions with activities and resources
215 * when viewing a quiz in editing mode.
216 *
217 * @module mod_quiz-resource-toolbox
218 * @namespace M.mod_quiz.resource_toolbox
219 */
220
221/**
222 * Resource and activity toolbox class.
223 *
224 * This is a class extending TOOLBOX containing code specific to resources
225 *
226 * This class is responsible for managing AJAX interactions with activities and resources
227 * when viewing a quiz in editing mode.
228 *
229 * @class resources
230 * @constructor
231 * @extends M.course.toolboxes.toolbox
232 */
233var RESOURCETOOLBOX = function() {
234 RESOURCETOOLBOX.superclass.constructor.apply(this, arguments);
235};
236
237Y.extend(RESOURCETOOLBOX, TOOLBOX, {
238 /**
239 * An Array of events added when editing a max mark field.
240 * These should all be detached when editing is complete.
241 *
242 * @property editmaxmarkevents
243 * @protected
244 * @type Array
245 * @protected
246 */
247 editmaxmarkevents: [],
248
249 /**
250 *
251 */
252 NODE_PAGE: 1,
253 NODE_SLOT: 2,
254 NODE_JOIN: 3,
255
256 /**
257 * Initialize the resource toolbox
258 *
259 * For each activity the commands are updated and a reference to the activity is attached.
260 * This way it doesn't matter where the commands are going to called from they have a reference to the
261 * activity that they relate to.
262 * This is essential as some of the actions are displayed in an actionmenu which removes them from the
263 * page flow.
264 *
265 * This function also creates a single event delegate to manage all AJAX actions for all activities on
266 * the page.
267 *
268 * @method initializer
269 * @protected
270 */
271 initializer: function() {
272 M.mod_quiz.quizbase.register_module(this);
273 BODY.delegate('key', this.handle_data_action, 'down:enter', SELECTOR.ACTIVITYACTION, this);
274 Y.delegate('click', this.handle_data_action, BODY, SELECTOR.ACTIVITYACTION, this);
275 },
276
277 /**
278 * Handles the delegation event. When this is fired someone has triggered an action.
279 *
280 * Note not all actions will result in an AJAX enhancement.
281 *
282 * @protected
283 * @method handle_data_action
284 * @param {EventFacade} ev The event that was triggered.
285 * @returns {boolean}
286 */
287 handle_data_action: function(ev) {
288 // We need to get the anchor element that triggered this event.
289 var node = ev.target;
290 if (!node.test('a')) {
291 node = node.ancestor(SELECTOR.ACTIVITYACTION);
292 }
293
294 // From the anchor we can get both the activity (added during initialisation) and the action being
295 // performed (added by the UI as a data attribute).
296 var action = node.getData('action'),
297 activity = node.ancestor(SELECTOR.ACTIVITYLI);
298
299 if (!node.test('a') || !action || !activity) {
300 // It wasn't a valid action node.
301 return;
302 }
303
304 // Switch based upon the action and do the desired thing.
305 switch (action) {
306 case 'editmaxmark':
307 // The user wishes to edit the maxmark of the resource.
308 this.edit_maxmark(ev, node, activity, action);
309 break;
310 case 'delete':
311 // The user is deleting the activity.
312 this.delete_with_confirmation(ev, node, activity, action);
313 break;
314 case 'linkpage':
315 case 'unlinkpage':
316 // The user is linking or unlinking pages.
317 this.link_page(ev, node, activity, action);
318 break;
319 default:
320 // Nothing to do here!
321 break;
322 }
323 },
324
325 /**
326 * Add a loading icon to the specified activity.
327 *
328 * The icon is added within the action area.
329 *
330 * @method add_spinner
331 * @param {Node} activity The activity to add a loading icon to
332 * @return {Node|null} The newly created icon, or null if the action area was not found.
333 */
334 add_spinner: function(activity) {
335 var actionarea = activity.one(SELECTOR.ACTIONAREA);
336 if (actionarea) {
337 return M.util.add_spinner(Y, actionarea);
338 }
339 return null;
340 },
341
342 /**
343 * Deletes the given activity or resource after confirmation.
344 *
345 * @protected
346 * @method delete_with_confirmation
347 * @param {EventFacade} ev The event that was fired.
348 * @param {Node} button The button that triggered this action.
349 * @param {Node} activity The activity node that this action will be performed on.
350 * @chainable
351 */
352 delete_with_confirmation: function(ev, button, activity) {
353 // Prevent the default button action
354 ev.preventDefault();
355
356 // Get the element we're working on
357 var element = activity,
358 // Create confirm string (different if element has or does not have name)
359 confirmstring = '',
360 qtypename = M.util.get_string('pluginname',
361 'qtype_' + element.getAttribute('class').match(/qtype_([^\s]*)/)[1]);
362 confirmstring = M.util.get_string('confirmremovequestion', 'quiz', qtypename);
363
364 // Create the confirmation dialogue.
365 var confirm = new M.core.confirm({
366 question: confirmstring,
367 modal: true
368 });
369
370 // If it is confirmed.
371 confirm.on('complete-yes', function() {
372
373 // Actually remove the element.
374 element.remove();
375 Y.Moodle.mod_quiz.util.slot.reorder_slots();
376 var data = {
377 'class': 'resource',
378 'action': 'DELETE',
379 'id': Y.Moodle.mod_quiz.util.slot.getId(element)
380 };
381 this.send_request(data);
382 if (M.core.actionmenu && M.core.actionmenu.instance) {
383 M.core.actionmenu.instance.hideMenu();
384 }
385 window.location.reload(true);
386
387 }, this);
388
389 return this;
390 },
391
392
393 /**
394 * Edit the maxmark for the resource
395 *
396 * @protected
397 * @method edit_maxmark
398 * @param {EventFacade} ev The event that was fired.
399 * @param {Node} button The button that triggered this action.
400 * @param {Node} activity The activity node that this action will be performed on.
401 * @param {String} action The action that has been requested.
402 * @return Boolean
403 */
404 edit_maxmark : function(ev, button, activity) {
405 // Get the element we're working on
406 var activityid = Y.Moodle.mod_quiz.util.slot.getId(activity),
407 instancemaxmark = activity.one(SELECTOR.INSTANCEMAXMARK),
408 instance = activity.one(SELECTOR.ACTIVITYINSTANCE),
409 currentmaxmark = instancemaxmark.get('firstChild'),
410 oldmaxmark = currentmaxmark.get('data'),
411 maxmarktext = oldmaxmark,
412 thisevent,
413 anchor = instancemaxmark,// Grab the anchor so that we can swap it with the edit form.
414 data = {
415 'class' : 'resource',
416 'field' : 'getmaxmark',
417 'id' : activityid
418 };
419
420 // Prevent the default actions.
421 ev.preventDefault();
422
423 this.send_request(data, null, function(response) {
424 if (M.core.actionmenu && M.core.actionmenu.instance) {
425 M.core.actionmenu.instance.hideMenu();
426 }
427
428 // Try to retrieve the existing string from the server
429 if (response.instancemaxmark) {
430 maxmarktext = response.instancemaxmark;
431 }
432
433 // Create the editor and submit button
434 var editform = Y.Node.create('<form action="#" />');
435 var editinstructions = Y.Node.create('<span class="' + CSS.EDITINSTRUCTIONS + '" id="id_editinstructions" />')
436 .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
437 var editor = Y.Node.create('<input name="maxmark" type="text" class="' + CSS.TITLEEDITOR + '" />').setAttrs({
438 'value' : maxmarktext,
439 'autocomplete' : 'off',
440 'aria-describedby' : 'id_editinstructions',
441 'maxLength' : '12',
442 'size' : parseInt(this.get('config').questiondecimalpoints, 10) + 2
443 });
444
445 // Clear the existing content and put the editor in
446 editform.appendChild(editor);
447 editform.setData('anchor', anchor);
448 instance.insert(editinstructions, 'before');
449 anchor.replace(editform);
450
451 // Force the editing instruction to match the mod-indent position.
452 var padside = 'left';
453 if (right_to_left()) {
454 padside = 'right';
455 }
456
457 // We hide various components whilst editing:
458 activity.addClass(CSS.EDITINGMAXMARK);
459
460 // Focus and select the editor text
461 editor.focus().select();
462
463 // Cancel the edit if we lose focus or the escape key is pressed.
464 thisevent = editor.on('blur', this.edit_maxmark_cancel, this, activity, false);
465 this.editmaxmarkevents.push(thisevent);
466 thisevent = editor.on('key', this.edit_maxmark_cancel, 'esc', this, activity, true);
467 this.editmaxmarkevents.push(thisevent);
468
469 // Handle form submission.
470 thisevent = editform.on('submit', this.edit_maxmark_submit, this, activity, oldmaxmark);
471 this.editmaxmarkevents.push(thisevent);
472 });
473 },
474
475 /**
476 * Handles the submit event when editing the activity or resources maxmark.
477 *
478 * @protected
479 * @method edit_maxmark_submit
480 * @param {EventFacade} ev The event that triggered this.
481 * @param {Node} activity The activity whose maxmark we are altering.
482 * @param {String} originalmaxmark The original maxmark the activity or resource had.
483 */
484 edit_maxmark_submit : function(ev, activity, originalmaxmark) {
485 // We don't actually want to submit anything
486 ev.preventDefault();
487 var newmaxmark = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYMAXMARK).get('value'));
488 var spinner = this.add_spinner(activity);
489 this.edit_maxmark_clear(activity);
490 activity.one(SELECTOR.INSTANCEMAXMARK).setContent(newmaxmark);
491 if (newmaxmark !== null && newmaxmark !== "" && newmaxmark !== originalmaxmark) {
492 var data = {
493 'class' : 'resource',
494 'field' : 'updatemaxmark',
495 'maxmark' : newmaxmark,
496 'id' : Y.Moodle.mod_quiz.util.slot.getId(activity)
497 };
498 this.send_request(data, spinner, function(response) {
499 if (response.instancemaxmark) {
500 activity.one(SELECTOR.INSTANCEMAXMARK).setContent(response.instancemaxmark);
501 }
502 });
503 }
504 },
505
506 /**
507 * Handles the cancel event when editing the activity or resources maxmark.
508 *
509 * @protected
510 * @method edit_maxmark_cancel
511 * @param {EventFacade} ev The event that triggered this.
512 * @param {Node} activity The activity whose maxmark we are altering.
513 * @param {Boolean} preventdefault If true we should prevent the default action from occuring.
514 */
515 edit_maxmark_cancel : function(ev, activity, preventdefault) {
516 if (preventdefault) {
517 ev.preventDefault();
518 }
519 this.edit_maxmark_clear(activity);
520 },
521
522 /**
523 * Handles clearing the editing UI and returning things to the original state they were in.
524 *
525 * @protected
526 * @method edit_maxmark_clear
527 * @param {Node} activity The activity whose maxmark we were altering.
528 */
529 edit_maxmark_clear : function(activity) {
530 // Detach all listen events to prevent duplicate triggers
531 new Y.EventHandle(this.editmaxmarkevents).detach();
532
533 var editform = activity.one(SELECTOR.ACTIVITYFORM),
534 instructions = activity.one('#id_editinstructions');
535 if (editform) {
536 editform.replace(editform.getData('anchor'));
537 }
538 if (instructions) {
539 instructions.remove();
540 }
541
542 // Remove the editing class again to revert the display.
543 activity.removeClass(CSS.EDITINGMAXMARK);
544
545 // Refocus the link which was clicked originally so the user can continue using keyboard nav.
546 Y.later(100, this, function() {
547 activity.one(SELECTOR.EDITMAXMARK).focus();
548 });
549
550 // This hack is to keep Behat happy until they release a version of
551 // MinkSelenium2Driver that fixes
552 // https://github.com/Behat/MinkSelenium2Driver/issues/80.
553 if (!Y.one('input[name=maxmark')) {
554 Y.one('body').append('<input type="text" name="maxmark" style="display: none">');
555 }
556 },
557
558 /**
559 * Joins or separates the given slot with the page of the previous slot. Reorders the pages of
560 * the other slots
561 *
562 * @protected
563 * @method link_page
564 * @param {EventFacade} ev The event that was fired.
565 * @param {Node} button The button that triggered this action.
566 * @param {Node} activity The activity node that this action will be performed on.
567 * @chainable
568 */
569 link_page: function(ev, button, activity, action) {
570 // Prevent the default button action
571 ev.preventDefault();
572
573 activity = activity.next('li.activity.slot');
574 var spinner = this.add_spinner(activity),
575 slotid = 0;
576 var value = action === 'linkpage' ? 1:2;
577
578 var data = {
579 'class': 'resource',
580 'field': 'linkslottopage',
581 'id': slotid,
582 'value': value
583 };
584
585 slotid = Y.Moodle.mod_quiz.util.slot.getId(activity);
586 if (slotid) {
587 data.id = Number(slotid);
588 }
589 this.send_request(data, spinner, function(response) {
590 window.location.reload(true);
591// if (response.slots) {
592// this.repaginate_slots(response.slots);
593// }
594 });
595
596 return this;
597 },
598 repaginate_slots: function(slots) {
599 this.slots = slots;
600 var section = Y.one(SELECTOR.PAGECONTENT + ' ' + SELECTOR.SECTIONUL),
601 activities = section.all(SELECTOR.ACTIVITYLI);
602 activities.each(function(node) {
603
604 // What element is it? page/slot/link
605 // what is the current slot?
606 var type;
607 var slot;
608 if(node.hasClass(CSS.PAGE)){
609 type = this.NODE_PAGE;
610 slot = node.next(SELECTOR.SLOTLI);
611 } else if (node.hasClass(CSS.SLOT)){
612 type = this.NODE_SLOT;
613 slot = node;
614 } else if (node.hasClass(CSS.JOIN)){
615 type = this.NODE_JOIN;
616 slot = node.previous(SELECTOR.SLOTLI);
617 }
618
619 // getSlotnumber() Should be a method of util.slot
620 var slotnumber = Number(Y.Moodle.mod_quiz.util.slot.getNumber(slot));
621 if(!type){
622 // Nothing we can do.
623 return;
624 }
625
626 // Is it correct?
627 if(!this.slots.hasOwnProperty(slotnumber)){
628 // An error. We should handle this.
629 return;
630 }
631
632 var slotdata = this.slots[slotnumber];
633
634 if(type === this.NODE_PAGE){
635 // Get page number
636 var pagenumber = Y.Moodle.mod_quiz.util.page.getNumber(node);
637 // Is the page number correct?
638 if (slotdata.page === pagenumber) {
639 console.log('slotdata.page == pagenumber return');
640 return;
641 }
642
643 if (pagenumber < slotdata.page) {
644 // Remove page node.
645 node.remove();
646 }
647 else {
648 // Add page node.
649 console.log('pagenumber > slotdata.page update page number');
650 }
651
652 }
653 }, this);
654 },
655
656 NAME : 'mod_quiz-resource-toolbox',
657 ATTRS : {
658 courseid : {
659 'value' : 0
660 },
661 quizid : {
662 'value' : 0
663 }
664 }
665});
666
667M.mod_quiz.resource_toolbox = null;
668M.mod_quiz.init_resource_toolbox = function(config) {
669 M.mod_quiz.resource_toolbox = new RESOURCETOOLBOX(config);
670 return M.mod_quiz.resource_toolbox;
671};
672/**
673 * Resource and activity toolbox class.
674 *
675 * This class is responsible for managing AJAX interactions with activities and resources
676 * when viewing a course in editing mode.
677 *
678 * @module moodle-mod_quiz-toolboxes
679 * @namespace M.mod_quiz.toolboxes
680 */
681
682/**
683 * Section toolbox class.
684 *
685 * This class is responsible for managing AJAX interactions with sections
686 * when viewing a course in editing mode.
687 *
688 * @class section
689 * @constructor
690 * @extends M.mod_quiz.toolboxes.toolbox
691 */
692var SECTIONTOOLBOX = function() {
693 SECTIONTOOLBOX.superclass.constructor.apply(this, arguments);
694};
695
696Y.extend(SECTIONTOOLBOX, TOOLBOX, {
697 /**
698 * Initialize the section toolboxes module.
699 *
700 * Updates all span.commands with relevant handlers and other required changes.
701 *
702 * @method initializer
703 * @protected
704 */
705 initializer : function() {
706 M.mod_quiz.quizbase.register_module(this);
707
708 // Section Highlighting.
709 Y.delegate('click', this.toggle_highlight, SELECTOR.PAGECONTENT, SELECTOR.SECTIONLI + ' ' + SELECTOR.HIGHLIGHT, this);
710
711 // Section Visibility.
712 Y.delegate('click', this.toggle_hide_section, SELECTOR.PAGECONTENT, SELECTOR.SECTIONLI + ' ' + SELECTOR.SHOWHIDE, this);
713 },
714
715 toggle_hide_section : function(e) {
716 // Prevent the default button action.
717 e.preventDefault();
718
719 // Get the section we're working on.
720 var section = e.target.ancestor(M.mod_quiz.format.get_section_selector(Y)),
721 button = e.target.ancestor('a', true),
722 hideicon = button.one('img'),
723
724 // The value to submit
725 value,
726
727 // The text for strings and images. Also determines the icon to display.
728 action,
729 nextaction;
730
731 if (!section.hasClass(CSS.SECTIONHIDDENCLASS)) {
732 section.addClass(CSS.SECTIONHIDDENCLASS);
733 value = 0;
734 action = 'hide';
735 nextaction = 'show';
736 } else {
737 section.removeClass(CSS.SECTIONHIDDENCLASS);
738 value = 1;
739 action = 'show';
740 nextaction = 'hide';
741 }
742
743 var newstring = M.util.get_string(nextaction + 'fromothers', 'format_' + this.get('format'));
744 hideicon.setAttrs({
745 'alt' : newstring,
746 'src' : M.util.image_url('i/' + nextaction)
747 });
748 button.set('title', newstring);
749
750 // Change the highlight status
751 var data = {
752 'class' : 'section',
753 'field' : 'visible',
754 'id' : Y.Moodle.core_course.util.section.getId(section.ancestor(M.mod_quiz.edit.get_section_wrapper(Y), true)),
755 'value' : value
756 };
757
758 var lightbox = M.util.add_lightbox(Y, section);
759 lightbox.show();
760
761 this.send_request(data, lightbox, function(response) {
762 var activities = section.all(SELECTOR.ACTIVITYLI);
763 activities.each(function(node) {
764 var button;
765 if (node.one(SELECTOR.SHOW)) {
766 button = node.one(SELECTOR.SHOW);
767 } else {
768 button = node.one(SELECTOR.HIDE);
769 }
770 var activityid = Y.Moodle.mod_quiz.util.slot.getId(node);
771
772 // NOTE: resourcestotoggle is returned as a string instead
773 // of a Number so we must cast our activityid to a String.
774 if (Y.Array.indexOf(response.resourcestotoggle, "" + activityid) !== -1) {
775 M.mod_quiz.resource_toolbox.handle_resource_dim(button, node, action);
776 }
777 }, this);
778 });
779 },
780
781 /**
782 * Toggle highlighting the current section.
783 *
784 * @method toggle_highlight
785 * @param {EventFacade} e
786 */
787 toggle_highlight : function(e) {
788 // Prevent the default button action.
789 e.preventDefault();
790
791 // Get the section we're working on.
792 var section = e.target.ancestor(M.mod_quiz.edit.get_section_selector(Y));
793 var button = e.target.ancestor('a', true);
794 var buttonicon = button.one('img');
795
796 // Determine whether the marker is currently set.
797 var togglestatus = section.hasClass('current');
798 var value = 0;
799
800 // Set the current highlighted item text.
801 var old_string = M.util.get_string('markthistopic', 'moodle');
802 Y.one(SELECTOR.PAGECONTENT)
803 .all(M.mod_quiz.edit.get_section_selector(Y) + '.current ' + SELECTOR.HIGHLIGHT)
804 .set('title', old_string);
805 Y.one(SELECTOR.PAGECONTENT)
806 .all(M.mod_quiz.edit.get_section_selector(Y) + '.current ' + SELECTOR.HIGHLIGHT + ' img')
807 .set('alt', old_string)
808 .set('src', M.util.image_url('i/marker'));
809
810 // Remove the highlighting from all sections.
811 Y.one(SELECTOR.PAGECONTENT).all(M.mod_quiz.edit.get_section_selector(Y))
812 .removeClass('current');
813
814 // Then add it if required to the selected section.
815 if (!togglestatus) {
816 section.addClass('current');
817 value = Y.Moodle.core_course.util.section.getId(section.ancestor(M.mod_quiz.edit.get_section_wrapper(Y), true));
818 var new_string = M.util.get_string('markedthistopic', 'moodle');
819 button
820 .set('title', new_string);
821 buttonicon
822 .set('alt', new_string)
823 .set('src', M.util.image_url('i/marked'));
824 }
825
826 // Change the highlight status.
827 var data = {
828 'class' : 'course',
829 'field' : 'marker',
830 'value' : value
831 };
832 var lightbox = M.util.add_lightbox(Y, section);
833 lightbox.show();
834 this.send_request(data, lightbox);
835 }
836}, {
837 NAME : 'mod_quiz-section-toolbox',
838 ATTRS : {
839 courseid : {
840 'value' : 0
841 },
842 quizid : {
843 'value' : 0
844 },
845 format : {
846 'value' : 'topics'
847 }
848 }
849});
850
851M.mod_quiz.init_section_toolbox = function(config) {
852 return new SECTIONTOOLBOX(config);
853};
854
855
856}, '@VERSION@', {
857 "requires": [
858 "base",
859 "node",
860 "event",
861 "event-key",
862 "io",
863 "moodle-mod_quiz-quizbase",
864 "moodle-mod_quiz-util-slot",
865 "moodle-core-notification-ajaxexception"
866 ]
867});