[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /** 2 * A collection of utility classes for use with slots. 3 * 4 * @module moodle-mod_quiz-util 5 * @submodule moodle-mod_quiz-util-slot 6 */ 7 8 Y.namespace('Moodle.mod_quiz.util.slot'); 9 10 /** 11 * A collection of utility classes for use with slots. 12 * 13 * @class Moodle.mod_quiz.util.slot 14 * @static 15 */ 16 Y.Moodle.mod_quiz.util.slot = { 17 CSS: { 18 SLOT: 'slot', 19 QUESTIONTYPEDESCRIPTION: 'qtype_description', 20 CANNOT_DEPEND: 'question_dependency_cannot_depend' 21 }, 22 CONSTANTS: { 23 SLOTIDPREFIX: 'slot-', 24 QUESTION: M.util.get_string('question', 'moodle') 25 }, 26 SELECTORS: { 27 SLOT: 'li.slot', 28 INSTANCENAME: '.instancename', 29 NUMBER: 'span.slotnumber', 30 PAGECONTENT: 'div#page-content', 31 PAGEBREAK: 'span.page_split_join_wrapper', 32 ICON: 'img.smallicon', 33 QUESTIONTYPEDESCRIPTION: '.qtype_description', 34 SECTIONUL: 'ul.section', 35 DEPENDENCY_WRAPPER: '.question_dependency_wrapper', 36 DEPENDENCY_LINK: '.question_dependency_wrapper .cm-edit-action', 37 DEPENDENCY_ICON: '.question_dependency_wrapper img' 38 }, 39 40 /** 41 * Retrieve the slot item from one of it's child Nodes. 42 * 43 * @method getSlotFromComponent 44 * @param slotcomponent {Node} The component Node. 45 * @return {Node|null} The Slot Node. 46 */ 47 getSlotFromComponent: function(slotcomponent) { 48 return Y.one(slotcomponent).ancestor(this.SELECTORS.SLOT, true); 49 }, 50 51 /** 52 * Determines the slot ID for the provided slot. 53 * 54 * @method getId 55 * @param slot {Node} The slot to find an ID for. 56 * @return {Number|false} The ID of the slot in question or false if no ID was found. 57 */ 58 getId: function(slot) { 59 // We perform a simple substitution operation to get the ID. 60 var id = slot.get('id').replace( 61 this.CONSTANTS.SLOTIDPREFIX, ''); 62 63 // Attempt to validate the ID. 64 id = parseInt(id, 10); 65 if (typeof id === 'number' && isFinite(id)) { 66 return id; 67 } 68 return false; 69 }, 70 71 /** 72 * Determines the slot name for the provided slot. 73 * 74 * @method getName 75 * @param slot {Node} The slot to find a name for. 76 * @return {string|false} The name of the slot in question or false if no ID was found. 77 */ 78 getName: function(slot) { 79 var instance = slot.one(this.SELECTORS.INSTANCENAME); 80 if (instance) { 81 return instance.get('firstChild').get('data'); 82 } 83 return null; 84 }, 85 86 /** 87 * Determines the slot number for the provided slot. 88 * 89 * @method getNumber 90 * @param slot {Node} The slot to find the number for. 91 * @return {Number|false} The number of the slot in question or false if no number was found. 92 */ 93 getNumber: function(slot) { 94 if (!slot) { 95 return false; 96 } 97 // We perform a simple substitution operation to get the number. 98 var number = slot.one(this.SELECTORS.NUMBER).get('text').replace( 99 this.CONSTANTS.QUESTION, ''); 100 // Attempt to validate the ID. 101 number = parseInt(number, 10); 102 if (typeof number === 'number' && isFinite(number)) { 103 return number; 104 } 105 return false; 106 }, 107 108 /** 109 * Updates the slot number for the provided slot. 110 * 111 * @method setNumber 112 * @param slot {Node} The slot to update the number for. 113 * @return void 114 */ 115 setNumber: function(slot, number) { 116 var numbernode = slot.one(this.SELECTORS.NUMBER); 117 numbernode.setHTML('<span class="accesshide">' + this.CONSTANTS.QUESTION + '</span> ' + number); 118 }, 119 120 /** 121 * Returns a list of all slot elements on the page. 122 * 123 * @method getSlots 124 * @return {node[]} An array containing slot nodes. 125 */ 126 getSlots: function() { 127 return Y.all(this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL + ' ' + this.SELECTORS.SLOT); 128 }, 129 130 /** 131 * Returns a list of all slot elements on the page that have numbers. Excudes description questions. 132 * 133 * @method getSlots 134 * @return {node[]} An array containing slot nodes. 135 */ 136 getNumberedSlots: function() { 137 var selector = this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL; 138 selector += ' ' + this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')'; 139 return Y.all(selector); 140 }, 141 142 /** 143 * Returns the previous slot to the given slot. 144 * 145 * @method getPrevious 146 * @param slot Slot node 147 * @return {node|false} The previous slot node or false. 148 */ 149 getPrevious: function(slot) { 150 return slot.previous(this.SELECTORS.SLOT); 151 }, 152 153 /** 154 * Returns the previous numbered slot to the given slot. 155 * 156 * Ignores slots containing description question types. 157 * 158 * @method getPrevious 159 * @param slot Slot node 160 * @return {node|false} The previous slot node or false. 161 */ 162 getPreviousNumbered: function(slot) { 163 var previous = slot.previous(this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')'); 164 if (previous) { 165 return previous; 166 } 167 168 var section = slot.ancestor('li.section').previous('li.section'); 169 while (section) { 170 var questions = section.all(this.SELECTORS.SLOT + ':not(' + this.SELECTORS.QUESTIONTYPEDESCRIPTION + ')'); 171 if (questions.size() > 0) { 172 return questions.item(questions.size() - 1); 173 } 174 section = section.previous('li.section'); 175 } 176 return false; 177 }, 178 179 /** 180 * Reset the order of the numbers given to each slot. 181 * 182 * @method reorderSlots 183 * @return void 184 */ 185 reorderSlots: function() { 186 // Get list of slot nodes. 187 var slots = this.getSlots(); 188 // Loop through slots incrementing the number each time. 189 slots.each(function(slot) { 190 191 if (!Y.Moodle.mod_quiz.util.page.getPageFromSlot(slot)) { 192 // Move the next page to the front. 193 var nextpage = slot.next(Y.Moodle.mod_quiz.util.page.SELECTORS.PAGE); 194 slot.swap(nextpage); 195 } 196 197 var previousSlot = this.getPreviousNumbered(slot), 198 previousslotnumber = 0; 199 if (slot.hasClass(this.CSS.QUESTIONTYPEDESCRIPTION)) { 200 return; 201 } 202 203 if (previousSlot) { 204 previousslotnumber = this.getNumber(previousSlot); 205 } 206 207 // Set slot number. 208 this.setNumber(slot, previousslotnumber + 1); 209 }, this); 210 }, 211 212 /** 213 * Add class only-has-one-slot to those sections that need it. 214 * 215 * @method updateOneSlotSections 216 * @return void 217 */ 218 updateOneSlotSections: function() { 219 Y.all('.mod-quiz-edit-content ul.slots li.section').each(function(section) { 220 if (section.all(this.SELECTORS.SLOT).size() > 1) { 221 section.removeClass('only-has-one-slot'); 222 } else { 223 section.addClass('only-has-one-slot'); 224 } 225 }, this); 226 }, 227 228 /** 229 * Remove a slot and related elements from the list of slots. 230 * 231 * @method remove 232 * @param slot Slot node 233 * @return void 234 */ 235 remove: function(slot) { 236 var page = Y.Moodle.mod_quiz.util.page.getPageFromSlot(slot); 237 slot.remove(); 238 // Is the page empty. 239 if (!Y.Moodle.mod_quiz.util.page.isEmpty(page)) { 240 return; 241 } 242 // If so remove it. Including add menu and page break. 243 Y.Moodle.mod_quiz.util.page.remove(page); 244 }, 245 246 /** 247 * Returns a list of all page break elements on the page. 248 * 249 * @method getPageBreaks 250 * @return {node[]} An array containing page break nodes. 251 */ 252 getPageBreaks: function() { 253 var selector = this.SELECTORS.PAGECONTENT + ' ' + this.SELECTORS.SECTIONUL; 254 selector += ' ' + this.SELECTORS.SLOT + this.SELECTORS.PAGEBREAK; 255 return Y.all(selector); 256 }, 257 258 /** 259 * Retrieve the page break element item from the given slot. 260 * 261 * @method getPageBreak 262 * @param slot Slot node 263 * @return {Node|null} The Page Break Node. 264 */ 265 getPageBreak: function(slot) { 266 return Y.one(slot).one(this.SELECTORS.PAGEBREAK); 267 }, 268 269 /** 270 * Add a page break and related elements to the list of slots. 271 * 272 * @method addPageBreak 273 * @param beforenode Int | Node | HTMLElement | String to add 274 * @return pagebreak PageBreak node 275 */ 276 addPageBreak: function(slot) { 277 var nodetext = M.mod_quiz.resource_toolbox.get('config').addpageiconhtml; 278 nodetext = nodetext.replace('%%SLOT%%', this.getNumber(slot)); 279 var pagebreak = Y.Node.create(nodetext); 280 slot.one('div').insert(pagebreak, 'after'); 281 return pagebreak; 282 }, 283 284 /** 285 * Remove a pagebreak from the given slot. 286 * 287 * @method removePageBreak 288 * @param slot Slot node 289 * @return boolean 290 */ 291 removePageBreak: function(slot) { 292 var pagebreak = this.getPageBreak(slot); 293 if (!pagebreak) { 294 return false; 295 } 296 pagebreak.remove(); 297 return true; 298 }, 299 300 /** 301 * Reorder each pagebreak by iterating through each related slot. 302 * 303 * @method reorderPageBreaks 304 * @return void 305 */ 306 reorderPageBreaks: function() { 307 // Get list of slot nodes. 308 var slots = this.getSlots(); 309 var slotnumber = 0; 310 // Loop through slots incrementing the number each time. 311 slots.each(function(slot, key) { 312 slotnumber++; 313 var pagebreak = this.getPageBreak(slot); 314 var nextitem = slot.next('li.activity'); 315 if (!nextitem) { 316 // Last slot in a section. Should not have an icon. 317 return; 318 } 319 320 // No pagebreak and not last slot. Add one. 321 if (!pagebreak) { 322 pagebreak = this.addPageBreak(slot); 323 } 324 325 // Remove last page break if there is one. 326 if (pagebreak && key === slots.size() - 1) { 327 this.removePageBreak(slot); 328 } 329 330 // Get page break anchor element. 331 var pagebreaklink = pagebreak.get('childNodes').item(0); 332 333 // Get the correct title. 334 var action = ''; 335 var iconname = ''; 336 if (Y.Moodle.mod_quiz.util.page.isPage(nextitem)) { 337 action = 'removepagebreak'; 338 iconname = 'e/remove_page_break'; 339 } else { 340 action = 'addpagebreak'; 341 iconname = 'e/insert_page_break'; 342 } 343 344 // Update the link and image titles 345 pagebreaklink.set('title', M.util.get_string(action, 'quiz')); 346 pagebreaklink.setData('action', action); 347 // Update the image title. 348 var icon = pagebreaklink.one(this.SELECTORS.ICON); 349 icon.set('title', M.util.get_string(action, 'quiz')); 350 icon.set('alt', M.util.get_string(action, 'quiz')); 351 352 // Update the image src. 353 icon.set('src', M.util.image_url(iconname)); 354 355 // Get anchor url parameters as an associative array. 356 var params = Y.QueryString.parse(pagebreaklink.get('href')); 357 // Update slot number. 358 params.slot = slotnumber; 359 // Create the new url. 360 var newurl = ''; 361 for (var index in params) { 362 if (newurl.length) { 363 newurl += "&"; 364 } 365 newurl += index + "=" + params[index]; 366 } 367 // Update the anchor. 368 pagebreaklink.set('href', newurl); 369 }, this); 370 }, 371 372 /** 373 * Update the dependency icons. 374 * 375 * @method updateAllDependencyIcons 376 * @return void 377 */ 378 updateAllDependencyIcons: function() { 379 // Get list of slot nodes. 380 var slots = this.getSlots(), 381 slotnumber = 0, 382 previousslot = null; 383 // Loop through slots incrementing the number each time. 384 slots.each(function(slot) { 385 slotnumber++; 386 387 if (slotnumber == 1 || previousslot.getData('canfinish') === '0') { 388 slot.one(this.SELECTORS.DEPENDENCY_WRAPPER).addClass(this.CSS.CANNOT_DEPEND); 389 } else { 390 slot.one(this.SELECTORS.DEPENDENCY_WRAPPER).removeClass(this.CSS.CANNOT_DEPEND); 391 } 392 this.updateDependencyIcon(slot, null); 393 394 previousslot = slot; 395 }, this); 396 }, 397 398 /** 399 * Update the slot icon to indicate the new requiresprevious state. 400 * 401 * @method slot Slot node 402 * @method requiresprevious Whether this node now requires the previous one. 403 * @return void 404 */ 405 updateDependencyIcon: function(slot, requiresprevious) { 406 var link = slot.one(this.SELECTORS.DEPENDENCY_LINK); 407 var icon = slot.one(this.SELECTORS.DEPENDENCY_ICON); 408 var previousSlot = this.getPrevious(slot); 409 var a = {thisq: this.getNumber(slot)}; 410 if (previousSlot) { 411 a.previousq = this.getNumber(previousSlot); 412 } 413 414 if (requiresprevious === null) { 415 requiresprevious = link.getData('action') === 'removedependency'; 416 } 417 418 if (requiresprevious) { 419 link.set('title', M.util.get_string('questiondependencyremove', 'quiz', a)); 420 link.setData('action', 'removedependency'); 421 icon.set('alt', M.util.get_string('questiondependsonprevious', 'quiz')); 422 icon.set('src', M.util.image_url('t/locked', 'moodle')); 423 } else { 424 link.set('title', M.util.get_string('questiondependencyadd', 'quiz', a)); 425 link.setData('action', 'adddependency'); 426 icon.set('alt', M.util.get_string('questiondependencyfree', 'quiz')); 427 icon.set('src', M.util.image_url('t/unlocked', 'moodle')); 428 } 429 } 430 };
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 |