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