[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* global TOOLBOX, BODY, SELECTOR */ 2 3 /** 4 * Section toolbox class. 5 * 6 * This class is responsible for managing AJAX interactions with sections 7 * when adding, editing, removing section headings. 8 * 9 * @module moodle-mod_quiz-toolboxes 10 * @namespace M.mod_quiz.toolboxes 11 */ 12 13 /** 14 * Section toolbox class. 15 * 16 * This class is responsible for managing AJAX interactions with sections 17 * when adding, editing, removing section headings when editing a quiz. 18 * 19 * @class section 20 * @constructor 21 * @extends M.mod_quiz.toolboxes.toolbox 22 */ 23 var SECTIONTOOLBOX = function() { 24 SECTIONTOOLBOX.superclass.constructor.apply(this, arguments); 25 }; 26 27 Y.extend(SECTIONTOOLBOX, TOOLBOX, { 28 /** 29 * An Array of events added when editing a max mark field. 30 * These should all be detached when editing is complete. 31 * 32 * @property editsectionevents 33 * @protected 34 * @type Array 35 * @protected 36 */ 37 editsectionevents: [], 38 39 /** 40 * Initialize the section toolboxes module. 41 * 42 * Updates all span.commands with relevant handlers and other required changes. 43 * 44 * @method initializer 45 * @protected 46 */ 47 initializer: function() { 48 M.mod_quiz.quizbase.register_module(this); 49 50 BODY.delegate('key', this.handle_data_action, 'down:enter', SELECTOR.ACTIVITYACTION, this); 51 Y.delegate('click', this.handle_data_action, BODY, SELECTOR.ACTIVITYACTION, this); 52 Y.delegate('change', this.handle_data_action, BODY, SELECTOR.EDITSHUFFLEQUESTIONSACTION, this); 53 }, 54 55 /** 56 * Handles the delegation event. When this is fired someone has triggered an action. 57 * 58 * Note not all actions will result in an AJAX enhancement. 59 * 60 * @protected 61 * @method handle_data_action 62 * @param {EventFacade} ev The event that was triggered. 63 * @returns {boolean} 64 */ 65 handle_data_action: function(ev) { 66 // We need to get the anchor element that triggered this event. 67 var node = ev.target; 68 if (!node.test('a') && !node.test('input[data-action]')) { 69 node = node.ancestor(SELECTOR.ACTIVITYACTION); 70 } 71 72 // From the anchor we can get both the activity (added during initialisation) and the action being 73 // performed (added by the UI as a data attribute). 74 var action = node.getData('action'), 75 activity = node.ancestor(SELECTOR.ACTIVITYLI); 76 77 if ((!node.test('a') && !node.test('input[data-action]')) || !action || !activity) { 78 // It wasn't a valid action node. 79 return; 80 } 81 82 // Switch based upon the action and do the desired thing. 83 switch (action) { 84 case 'edit_section_title': 85 // The user wishes to edit the section headings. 86 this.edit_section_title(ev, node, activity, action); 87 break; 88 case 'shuffle_questions': 89 // The user wishes to edit the shuffle questions of the section (resource). 90 this.edit_shuffle_questions(ev, node, activity, action); 91 break; 92 case 'deletesection': 93 // The user is deleting the activity. 94 this.delete_section_with_confirmation(ev, node, activity, action); 95 break; 96 default: 97 // Nothing to do here! 98 break; 99 } 100 }, 101 102 /** 103 * Deletes the given section heading after confirmation. 104 * 105 * @protected 106 * @method delete_section_with_confirmation 107 * @param {EventFacade} ev The event that was fired. 108 * @param {Node} button The button that triggered this action. 109 * @param {Node} activity The activity node that this action will be performed on. 110 * @chainable 111 */ 112 delete_section_with_confirmation: function(ev, button, activity) { 113 // Prevent the default button action. 114 ev.preventDefault(); 115 116 // Create the confirmation dialogue. 117 var confirm = new M.core.confirm({ 118 question: M.util.get_string('confirmremovesectionheading', 'quiz', activity.get('aria-label')), 119 modal: true 120 }); 121 122 // If it is confirmed. 123 confirm.on('complete-yes', function() { 124 125 var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.ACTIONAREA)); 126 var data = { 127 'class': 'section', 128 'action': 'DELETE', 129 'id': activity.get('id').replace('section-', '') 130 }; 131 this.send_request(data, spinner, function(response) { 132 if (response.deleted) { 133 window.location.reload(true); 134 } 135 }); 136 137 }, this); 138 }, 139 140 /** 141 * Edit the edit section title for the section 142 * 143 * @protected 144 * @method edit_section_title 145 * @param {EventFacade} ev The event that was fired. 146 * @param {Node} button The button that triggered this action. 147 * @param {Node} activity The activity node that this action will be performed on. 148 * @param {String} action The action that has been requested. 149 * @return Boolean 150 */ 151 edit_section_title: function(ev, button, activity) { 152 // Get the element we're working on 153 var activityid = activity.get('id').replace('section-', ''), 154 instancesection = activity.one(SELECTOR.INSTANCESECTION), 155 thisevent, 156 anchor = instancesection, // Grab the anchor so that we can swap it with the edit form. 157 data = { 158 'class': 'section', 159 'field': 'getsectiontitle', 160 'id': activityid 161 }; 162 163 // Prevent the default actions. 164 ev.preventDefault(); 165 166 this.send_request(data, null, function(response) { 167 // Try to retrieve the existing string from the server. 168 var oldtext = response.instancesection; 169 170 // Create the editor and submit button. 171 var editform = Y.Node.create('<form action="#" />'); 172 var editinstructions = Y.Node.create('<span class="' + CSS.EDITINSTRUCTIONS + '" id="id_editinstructions" />') 173 .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle')); 174 var editor = Y.Node.create('<input name="section" type="text" />').setAttrs({ 175 'value': oldtext, 176 'autocomplete': 'off', 177 'aria-describedby': 'id_editinstructions', 178 'maxLength': '255' // This is the maxlength in DB. 179 }); 180 181 // Clear the existing content and put the editor in. 182 editform.appendChild(editor); 183 editform.setData('anchor', anchor); 184 instancesection.insert(editinstructions, 'before'); 185 anchor.replace(editform); 186 187 // Focus and select the editor text. 188 editor.focus().select(); 189 // Cancel the edit if we lose focus or the escape key is pressed. 190 thisevent = editor.on('blur', this.edit_section_title_cancel, this, activity, false); 191 this.editsectionevents.push(thisevent); 192 thisevent = editor.on('key', this.edit_section_title_cancel, 'esc', this, activity, true); 193 this.editsectionevents.push(thisevent); 194 // Handle form submission. 195 thisevent = editform.on('submit', this.edit_section_title_submit, this, activity, oldtext); 196 this.editsectionevents.push(thisevent); 197 }); 198 }, 199 200 /** 201 * Handles the submit event when editing section heading. 202 * 203 * @protected 204 * @method edit_section_title_submiy 205 * @param {EventFacade} ev The event that triggered this. 206 * @param {Node} activity The activity whose maxmark we are altering. 207 * @param {String} oldtext The original maxmark the activity or resource had. 208 */ 209 edit_section_title_submit: function(ev, activity, oldtext) { 210 // We don't actually want to submit anything. 211 ev.preventDefault(); 212 var newtext = Y.Lang.trim(activity.one(SELECTOR.SECTIONFORM + ' ' + SELECTOR.SECTIONINPUT).get('value')); 213 var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.INSTANCESECTIONAREA)); 214 this.edit_section_title_clear(activity); 215 if (newtext !== null && newtext !== oldtext) { 216 activity.one(SELECTOR.INSTANCESECTION).setContent(newtext); 217 var data = { 218 'class': 'section', 219 'field': 'updatesectiontitle', 220 'newheading': newtext, 221 'id': activity.get('id').replace('section-', '') 222 }; 223 this.send_request(data, spinner, function(response) { 224 if (response) { 225 activity.one(SELECTOR.INSTANCESECTION).setContent(response.instancesection); 226 activity.one(SELECTOR.EDITSECTIONICON).set('title', 227 M.util.get_string('sectionheadingedit', 'quiz', response.instancesection)); 228 activity.one(SELECTOR.EDITSECTIONICON).set('alt', 229 M.util.get_string('sectionheadingedit', 'quiz', response.instancesection)); 230 var deleteicon = activity.one(SELECTOR.DELETESECTIONICON); 231 if (deleteicon) { 232 deleteicon.set('title', M.util.get_string('sectionheadingremove', 'quiz', response.instancesection)); 233 deleteicon.set('alt', M.util.get_string('sectionheadingremove', 'quiz', response.instancesection)); 234 } 235 } 236 }); 237 } 238 }, 239 240 /** 241 * Handles the cancel event when editing the activity or resources maxmark. 242 * 243 * @protected 244 * @method edit_maxmark_cancel 245 * @param {EventFacade} ev The event that triggered this. 246 * @param {Node} activity The activity whose maxmark we are altering. 247 * @param {Boolean} preventdefault If true we should prevent the default action from occuring. 248 */ 249 edit_section_title_cancel: function(ev, activity, preventdefault) { 250 if (preventdefault) { 251 ev.preventDefault(); 252 } 253 this.edit_section_title_clear(activity); 254 }, 255 256 /** 257 * Handles clearing the editing UI and returning things to the original state they were in. 258 * 259 * @protected 260 * @method edit_maxmark_clear 261 * @param {Node} activity The activity whose maxmark we were altering. 262 */ 263 edit_section_title_clear: function(activity) { 264 // Detach all listen events to prevent duplicate triggers 265 new Y.EventHandle(this.editsectionevents).detach(); 266 267 var editform = activity.one(SELECTOR.SECTIONFORM), 268 instructions = activity.one('#id_editinstructions'); 269 if (editform) { 270 editform.replace(editform.getData('anchor')); 271 } 272 if (instructions) { 273 instructions.remove(); 274 } 275 276 // Refocus the link which was clicked originally so the user can continue using keyboard nav. 277 Y.later(100, this, function() { 278 activity.one(SELECTOR.EDITSECTION).focus(); 279 }); 280 281 // This hack is to keep Behat happy until they release a version of 282 // MinkSelenium2Driver that fixes 283 // https://github.com/Behat/MinkSelenium2Driver/issues/80. 284 if (!Y.one('input[name=section]')) { 285 Y.one('body').append('<input type="text" name="section" style="display: none">'); 286 } 287 }, 288 289 /** 290 * Edit the edit shuffle questions for the section 291 * 292 * @protected 293 * @method edit_shuffle_questions 294 * @param {EventFacade} ev The event that was fired. 295 * @param {Node} button The button that triggered this action. 296 * @param {Node} activity The activity node that this action will be performed on. 297 * @param {String} action The action that has been requested. 298 * @return Boolean 299 */ 300 edit_shuffle_questions: function(ev, button, activity) { 301 var newvalue; 302 if (activity.one(SELECTOR.EDITSHUFFLEQUESTIONSACTION).get('checked')) { 303 newvalue = 1; 304 } else { 305 newvalue = 0; 306 } 307 308 // Get the element we're working on 309 var data = { 310 'class': 'section', 311 'field': 'updateshufflequestions', 312 'id': activity.get('id').replace('section-', ''), 313 'newshuffle': newvalue 314 }; 315 316 // Prevent the default actions. 317 ev.preventDefault(); 318 319 // Send request. 320 var spinner = M.util.add_spinner(Y, activity.one(SELECTOR.EDITSHUFFLEAREA)); 321 this.send_request(data, spinner); 322 } 323 324 }, { 325 NAME: 'mod_quiz-section-toolbox', 326 ATTRS: { 327 courseid: { 328 'value': 0 329 }, 330 quizid: { 331 'value': 0 332 } 333 } 334 }); 335 336 M.mod_quiz.init_section_toolbox = function(config) { 337 return new SECTIONTOOLBOX(config); 338 };
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |