MDL-23919 mod_data: completionentries can be null
[moodle.git] / mod / quiz / yui / src / toolboxes / js / toolbox.js
1 /* eslint-disable no-unused-vars */
2 /**
3  * Resource and activity toolbox class.
4  *
5  * This class is responsible for managing AJAX interactions with activities and resources
6  * when viewing a course in editing mode.
7  *
8  * @module moodle-course-toolboxes
9  * @namespace M.course.toolboxes
10  */
12 // The CSS classes we use.
13 var CSS = {
14         ACTIVITYINSTANCE: 'activityinstance',
15         AVAILABILITYINFODIV: 'div.availabilityinfo',
16         CONTENTWITHOUTLINK: 'contentwithoutlink',
17         CONDITIONALHIDDEN: 'conditionalhidden',
18         DIMCLASS: 'dimmed',
19         DIMMEDTEXT: 'dimmed_text',
20         EDITINSTRUCTIONS: 'editinstructions',
21         EDITINGMAXMARK: 'editor_displayed',
22         HIDE: 'hide',
23         JOIN: 'page_join',
24         MODINDENTCOUNT: 'mod-indent-',
25         MODINDENTHUGE: 'mod-indent-huge',
26         PAGE: 'page',
27         SECTIONHIDDENCLASS: 'hidden',
28         SECTIONIDPREFIX: 'section-',
29         SLOT: 'slot',
30         SHOW: 'editing_show',
31         TITLEEDITOR: 'titleeditor'
32     },
33     // The CSS selectors we use.
34     SELECTOR = {
35         ACTIONAREA: '.actions',
36         ACTIONLINKTEXT: '.actionlinktext',
37         ACTIVITYACTION: 'a.cm-edit-action[data-action], a.editing_maxmark, a.editing_section, input.shuffle_questions',
38         ACTIVITYFORM: 'span.instancemaxmarkcontainer form',
39         ACTIVITYINSTANCE: '.' + CSS.ACTIVITYINSTANCE,
40         SECTIONINSTANCE: '.sectioninstance',
41         ACTIVITYLI: 'li.activity, li.section',
42         ACTIVITYMAXMARK: 'input[name=maxmark]',
43         COMMANDSPAN: '.commands',
44         CONTENTAFTERLINK: 'div.contentafterlink',
45         CONTENTWITHOUTLINK: 'div.contentwithoutlink',
46         DELETESECTIONICON: 'a.editing_delete .icon',
47         EDITMAXMARK: 'a.editing_maxmark',
48         EDITSECTION: 'a.editing_section',
49         EDITSECTIONICON: 'a.editing_section .icon',
50         EDITSHUFFLEQUESTIONSACTION: 'input.cm-edit-action[data-action]',
51         EDITSHUFFLEAREA: '.instanceshufflequestions .shuffle-progress',
52         HIDE: 'a.editing_hide',
53         HIGHLIGHT: 'a.editing_highlight',
54         INSTANCENAME: 'span.instancename',
55         INSTANCEMAXMARK: 'span.instancemaxmark',
56         INSTANCESECTION: 'span.instancesection',
57         INSTANCESECTIONAREA: 'div.section-heading',
58         MODINDENTDIV: '.mod-indent',
59         MODINDENTOUTER: '.mod-indent-outer',
60         NUMQUESTIONS: '.numberofquestions',
61         PAGECONTENT: 'div#page-content',
62         PAGELI: 'li.page',
63         SECTIONUL: 'ul.section',
64         SECTIONFORM: '.instancesectioncontainer form',
65         SECTIONINPUT: 'input[name=section]',
66         SHOW: 'a.' + CSS.SHOW,
67         SLOTLI: 'li.slot',
68         SUMMARKS: '.mod_quiz_summarks'
69     },
70     BODY = Y.one(document.body);
72 // Setup the basic namespace.
73 M.mod_quiz = M.mod_quiz || {};
75 /**
76  * The toolbox class is a generic class which should never be directly
77  * instantiated. Please extend it instead.
78  *
79  * @class toolbox
80  * @constructor
81  * @protected
82  * @extends Base
83  */
84 var TOOLBOX = function() {
85     TOOLBOX.superclass.constructor.apply(this, arguments);
86 };
88 Y.extend(TOOLBOX, Y.Base, {
89     /**
90      * Send a request using the REST API
91      *
92      * @method send_request
93      * @param {Object} data The data to submit with the AJAX request
94      * @param {Node} [statusspinner] A statusspinner which may contain a section loader
95      * @param {Function} success_callback The callback to use on success
96      * @param {Object} [optionalconfig] Any additional configuration to submit
97      * @chainable
98      */
99     send_request: function(data, statusspinner, success_callback, optionalconfig) {
100         // Default data structure
101         if (!data) {
102             data = {};
103         }
104         // Handle any variables which we must pass back through to
105         var pageparams = this.get('config').pageparams,
106             varname;
107         for (varname in pageparams) {
108             data[varname] = pageparams[varname];
109         }
111         data.sesskey = M.cfg.sesskey;
112         data.courseid = this.get('courseid');
113         data.quizid = this.get('quizid');
115         var uri = M.cfg.wwwroot + this.get('ajaxurl');
117         // Define the configuration to send with the request
118         var responsetext = [];
119         var config = {
120             method: 'POST',
121             data: data,
122             on: {
123                 success: function(tid, response) {
124                     try {
125                         responsetext = Y.JSON.parse(response.responseText);
126                         if (responsetext.error) {
127                             new M.core.ajaxException(responsetext);
128                         }
129                     } catch (e) {
130                         // Ignore.
131                     }
133                     // Run the callback if we have one.
134                     if (responsetext.hasOwnProperty('newsummarks')) {
135                         Y.one(SELECTOR.SUMMARKS).setHTML(responsetext.newsummarks);
136                     }
137                     if (responsetext.hasOwnProperty('newnumquestions')) {
138                         Y.one(SELECTOR.NUMQUESTIONS).setHTML(
139                                 M.util.get_string('numquestionsx', 'quiz', responsetext.newnumquestions)
140                             );
141                     }
142                     if (success_callback) {
143                         Y.bind(success_callback, this, responsetext)();
144                     }
146                     if (statusspinner) {
147                         window.setTimeout(function() {
148                             statusspinner.hide();
149                         }, 400);
150                     }
151                 },
152                 failure: function(tid, response) {
153                     if (statusspinner) {
154                         statusspinner.hide();
155                     }
156                     new M.core.ajaxException(response);
157                 }
158             },
159             context: this
160         };
162         // Apply optional config
163         if (optionalconfig) {
164             for (varname in optionalconfig) {
165                 config[varname] = optionalconfig[varname];
166             }
167         }
169         if (statusspinner) {
170             statusspinner.show();
171         }
173         // Send the request
174         Y.io(uri, config);
175         return this;
176     }
177 },
179     NAME: 'mod_quiz-toolbox',
180     ATTRS: {
181         /**
182          * The ID of the Moodle Course being edited.
183          *
184          * @attribute courseid
185          * @default 0
186          * @type Number
187          */
188         courseid: {
189             'value': 0
190         },
192         /**
193          * The Moodle course format.
194          *
195          * @attribute format
196          * @default 'topics'
197          * @type String
198          */
199         quizid: {
200             'value': 0
201         },
202         /**
203          * The URL to use when submitting requests.
204          * @attribute ajaxurl
205          * @default null
206          * @type String
207          */
208         ajaxurl: {
209             'value': null
210         },
211         /**
212          * Any additional configuration passed when creating the instance.
213          *
214          * @attribute config
215          * @default {}
216          * @type Object
217          */
218         config: {
219             'value': {}
220         }
221     }
223 );