[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-mod_quiz-dragdrop', function (Y, NAME) { 2 3 /** 4 * Drag and Drop for Quiz sections and slots. 5 * 6 * @module moodle-mod-quiz-dragdrop 7 */ 8 9 var CSS = { 10 ACTIONAREA: '.actions', 11 ACTIVITY: 'activity', 12 ACTIVITYINSTANCE: 'activityinstance', 13 CONTENT: 'content', 14 COURSECONTENT: 'mod-quiz-edit-content', 15 EDITINGMOVE: 'editing_move', 16 ICONCLASS: 'iconsmall', 17 JUMPMENU: 'jumpmenu', 18 LEFT: 'left', 19 LIGHTBOX: 'lightbox', 20 MOVEDOWN: 'movedown', 21 MOVEUP: 'moveup', 22 PAGE : 'page', 23 PAGECONTENT: 'page-content', 24 RIGHT: 'right', 25 SECTION: 'section', 26 SECTIONADDMENUS: 'section_add_menus', 27 SECTIONHANDLE: 'section-handle', 28 SLOTS: 'slots', 29 SUMMARY: 'summary', 30 SECTIONDRAGGABLE: 'sectiondraggable' 31 }, 32 // The CSS selectors we use. 33 SELECTOR = { 34 PAGE: 'li.page', 35 SLOT: 'li.slot' 36 }; 37 /** 38 * Section drag and drop. 39 * 40 * @class M.mod_quiz.dragdrop.section 41 * @constructor 42 * @extends M.core.dragdrop 43 */ 44 var DRAGSECTION = function() { 45 DRAGSECTION.superclass.constructor.apply(this, arguments); 46 }; 47 Y.extend(DRAGSECTION, M.core.dragdrop, { 48 sectionlistselector: null, 49 50 initializer: function() { 51 // Set group for parent class 52 this.groups = [ CSS.SECTIONDRAGGABLE ]; 53 this.samenodeclass = M.mod_quiz.edit.get_sectionwrapperclass(); 54 this.parentnodeclass = M.mod_quiz.edit.get_containerclass(); 55 56 // Check if we are in single section mode 57 if (Y.Node.one('.' + CSS.JUMPMENU)) { 58 return false; 59 } 60 // Initialise sections dragging 61 this.sectionlistselector = M.mod_quiz.edit.get_section_wrapper(Y); 62 if (this.sectionlistselector) { 63 this.sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + this.sectionlistselector; 64 65 this.setup_for_section(this.sectionlistselector); 66 67 // Make each li element in the lists of sections draggable 68 var del = new Y.DD.Delegate({ 69 container: '.' + CSS.COURSECONTENT, 70 nodes: '.' + CSS.SECTIONDRAGGABLE, 71 target: true, 72 handles: ['.' + CSS.LEFT], 73 dragConfig: {groups: this.groups} 74 }); 75 del.dd.plug(Y.Plugin.DDProxy, { 76 // Don't move the node at the end of the drag 77 moveOnEnd: false 78 }); 79 del.dd.plug(Y.Plugin.DDConstrained, { 80 // Keep it inside the .mod-quiz-edit-content 81 constrain: '#' + CSS.PAGECONTENT, 82 stickY: true 83 }); 84 del.dd.plug(Y.Plugin.DDWinScroll); 85 } 86 }, 87 88 /** 89 * Apply dragdrop features to the specified selector or node that refers to section(s) 90 * 91 * @method setup_for_section 92 * @param {String} baseselector The CSS selector or node to limit scope to 93 */ 94 setup_for_section: function(baseselector) { 95 Y.Node.all(baseselector).each(function(sectionnode) { 96 // Determine the section ID 97 var sectionid = Y.Moodle.core_course.util.section.getId(sectionnode); 98 99 // We skip the top section as it is not draggable 100 if (sectionid > 0) { 101 // Remove move icons 102 var movedown = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEDOWN); 103 var moveup = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEUP); 104 105 // Add dragger icon 106 var title = M.util.get_string('movesection', 'moodle', sectionid); 107 var cssleft = sectionnode.one('.' + CSS.LEFT); 108 109 if ((movedown || moveup) && cssleft) { 110 cssleft.setStyle('cursor', 'move'); 111 cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true)); 112 113 if (moveup) { 114 moveup.remove(); 115 } 116 if (movedown) { 117 movedown.remove(); 118 } 119 120 // This section can be moved - add the class to indicate this to Y.DD. 121 sectionnode.addClass(CSS.SECTIONDRAGGABLE); 122 } 123 } 124 }, this); 125 }, 126 127 /* 128 * Drag-dropping related functions 129 */ 130 drag_start: function(e) { 131 // Get our drag object 132 var drag = e.target; 133 // Creat a dummy structure of the outer elemnents for clean styles application 134 var containernode = Y.Node.create('<' + M.mod_quiz.edit.get_containernode() + '></' + M.mod_quiz.edit.get_containernode() + '>'); 135 containernode.addClass(M.mod_quiz.edit.get_containerclass()); 136 var sectionnode = Y.Node.create('<' + M.mod_quiz.edit.get_sectionwrappernode() + '></' + M.mod_quiz.edit.get_sectionwrappernode() + '>'); 137 sectionnode.addClass( M.mod_quiz.edit.get_sectionwrapperclass()); 138 sectionnode.setStyle('margin', 0); 139 sectionnode.setContent(drag.get('node').get('innerHTML')); 140 containernode.appendChild(sectionnode); 141 drag.get('dragNode').setContent(containernode); 142 drag.get('dragNode').addClass(CSS.COURSECONTENT); 143 }, 144 145 drag_dropmiss: function(e) { 146 // Missed the target, but we assume the user intended to drop it 147 // on the last last ghost node location, e.drag and e.drop should be 148 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 149 this.drop_hit(e); 150 }, 151 152 get_section_index: function(node) { 153 var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.mod_quiz.edit.get_section_selector(Y), 154 sectionList = Y.all(sectionlistselector), 155 nodeIndex = sectionList.indexOf(node), 156 zeroIndex = sectionList.indexOf(Y.one('#section-0')); 157 158 return (nodeIndex - zeroIndex); 159 }, 160 161 drop_hit: function(e) { 162 var drag = e.drag; 163 164 // Get references to our nodes and their IDs. 165 var dragnode = drag.get('node'), 166 dragnodeid = Y.Moodle.core_course.util.section.getId(dragnode), 167 loopstart = dragnodeid, 168 169 dropnodeindex = this.get_section_index(dragnode), 170 loopend = dropnodeindex; 171 172 if (dragnodeid === dropnodeindex) { 173 return; 174 } 175 176 177 if (loopstart > loopend) { 178 // If we're going up, we need to swap the loop order 179 // because loops can't go backwards. 180 loopstart = dropnodeindex; 181 loopend = dragnodeid; 182 } 183 184 // Get the list of nodes. 185 drag.get('dragNode').removeClass(CSS.COURSECONTENT); 186 var sectionlist = Y.Node.all(this.sectionlistselector); 187 188 // Add a lightbox if it's not there. 189 var lightbox = M.util.add_lightbox(Y, dragnode); 190 191 // Handle any variables which we must pass via AJAX. 192 var params = {}, 193 pageparams = this.get('config').pageparams, 194 varname; 195 196 for (varname in pageparams) { 197 if (!pageparams.hasOwnProperty(varname)) { 198 continue; 199 } 200 params[varname] = pageparams[varname]; 201 } 202 203 // Prepare request parameters 204 params.sesskey = M.cfg.sesskey; 205 params.courseid = this.get('courseid'); 206 params.quizid = this.get('quizid'); 207 params['class'] = 'section'; 208 params.field = 'move'; 209 params.id = dragnodeid; 210 params.value = dropnodeindex; 211 212 // Perform the AJAX request. 213 var uri = M.cfg.wwwroot + this.get('ajaxurl'); 214 Y.io(uri, { 215 method: 'POST', 216 data: params, 217 on: { 218 start: function() { 219 lightbox.show(); 220 }, 221 success: function(tid, response) { 222 // Update section titles, we can't simply swap them as 223 // they might have custom title 224 try { 225 var responsetext = Y.JSON.parse(response.responseText); 226 if (responsetext.error) { 227 new M.core.ajaxException(responsetext); 228 } 229 M.mod_quiz.edit.process_sections(Y, sectionlist, responsetext, loopstart, loopend); 230 } catch (e) {} 231 232 // Update all of the section IDs - first unset them, then set them 233 // to avoid duplicates in the DOM. 234 var index; 235 236 // Classic bubble sort algorithm is applied to the section 237 // nodes between original drag node location and the new one. 238 var swapped = false; 239 do { 240 swapped = false; 241 for (index = loopstart; index <= loopend; index++) { 242 if (Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) > 243 Y.Moodle.core_course.util.section.getId(sectionlist.item(index))) { 244 // Swap section id. 245 var sectionid = sectionlist.item(index - 1).get('id'); 246 sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id')); 247 sectionlist.item(index).set('id', sectionid); 248 249 // See what format needs to swap. 250 M.mod_quiz.edit.swap_sections(Y, index - 1, index); 251 252 // Update flag. 253 swapped = true; 254 } 255 } 256 loopend = loopend - 1; 257 } while (swapped); 258 259 window.setTimeout(function() { 260 lightbox.hide(); 261 }, 250); 262 }, 263 264 failure: function(tid, response) { 265 this.ajax_failure(response); 266 lightbox.hide(); 267 } 268 }, 269 context:this 270 }); 271 } 272 273 }, { 274 NAME: 'mod_quiz-dragdrop-section', 275 ATTRS: { 276 courseid: { 277 value: null 278 }, 279 quizid: { 280 value: null 281 }, 282 ajaxurl: { 283 value: 0 284 }, 285 config: { 286 value: 0 287 } 288 } 289 }); 290 291 M.mod_quiz = M.mod_quiz || {}; 292 M.mod_quiz.init_section_dragdrop = function(params) { 293 new DRAGSECTION(params); 294 }; 295 /** 296 * Resource drag and drop. 297 * 298 * @class M.course.dragdrop.resource 299 * @constructor 300 * @extends M.core.dragdrop 301 */ 302 var DRAGRESOURCE = function() { 303 DRAGRESOURCE.superclass.constructor.apply(this, arguments); 304 }; 305 Y.extend(DRAGRESOURCE, M.core.dragdrop, { 306 initializer: function() { 307 // Set group for parent class 308 this.groups = ['resource']; 309 this.samenodeclass = CSS.ACTIVITY; 310 this.parentnodeclass = CSS.SECTION; 311 this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS, true); 312 313 this.samenodelabel = { 314 identifier: 'dragtoafter', 315 component: 'quiz' 316 }; 317 this.parentnodelabel = { 318 identifier: 'dragtostart', 319 component: 'quiz' 320 }; 321 322 // Go through all sections 323 var sectionlistselector = M.mod_quiz.edit.get_section_selector(Y); 324 if (sectionlistselector) { 325 sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + sectionlistselector; 326 this.setup_for_section(sectionlistselector); 327 328 // Initialise drag & drop for all resources/activities 329 var nodeselector = sectionlistselector.slice(CSS.COURSECONTENT.length + 2) + ' li.' + CSS.ACTIVITY; 330 var del = new Y.DD.Delegate({ 331 container: '.' + CSS.COURSECONTENT, 332 nodes: nodeselector, 333 target: true, 334 handles: ['.' + CSS.EDITINGMOVE], 335 dragConfig: {groups: this.groups} 336 }); 337 del.dd.plug(Y.Plugin.DDProxy, { 338 // Don't move the node at the end of the drag 339 moveOnEnd: false, 340 cloneNode: true 341 }); 342 del.dd.plug(Y.Plugin.DDConstrained, { 343 // Keep it inside the .mod-quiz-edit-content 344 constrain: '#' + CSS.SLOTS 345 }); 346 del.dd.plug(Y.Plugin.DDWinScroll); 347 348 M.mod_quiz.quizbase.register_module(this); 349 M.mod_quiz.dragres = this; 350 } 351 }, 352 353 /** 354 * Apply dragdrop features to the specified selector or node that refers to section(s) 355 * 356 * @method setup_for_section 357 * @param {String} baseselector The CSS selector or node to limit scope to 358 */ 359 setup_for_section: function(baseselector) { 360 Y.Node.all(baseselector).each(function(sectionnode) { 361 var resources = sectionnode.one('.' + CSS.CONTENT + ' ul.' + CSS.SECTION); 362 // See if resources ul exists, if not create one. 363 if (!resources) { 364 resources = Y.Node.create('<ul></ul>'); 365 resources.addClass(CSS.SECTION); 366 sectionnode.one('.' + CSS.CONTENT + ' div.' + CSS.SUMMARY).insert(resources, 'after'); 367 } 368 resources.setAttribute('data-draggroups', this.groups.join(' ')); 369 // Define empty ul as droptarget, so that item could be moved to empty list 370 new Y.DD.Drop({ 371 node: resources, 372 groups: this.groups, 373 padding: '20 0 20 0' 374 }); 375 376 // Initialise each resource/activity in this section 377 this.setup_for_resource('#' + sectionnode.get('id') + ' li.' + CSS.ACTIVITY); 378 }, this); 379 }, 380 381 /** 382 * Apply dragdrop features to the specified selector or node that refers to resource(s) 383 * 384 * @method setup_for_resource 385 * @param {String} baseselector The CSS selector or node to limit scope to 386 */ 387 setup_for_resource: function(baseselector) { 388 Y.Node.all(baseselector).each(function(resourcesnode) { 389 // Replace move icons 390 var move = resourcesnode.one('a.' + CSS.EDITINGMOVE); 391 if (move) { 392 move.replace(this.resourcedraghandle.cloneNode(true)); 393 } 394 }, this); 395 }, 396 397 drag_start: function(e) { 398 // Get our drag object 399 var drag = e.target; 400 drag.get('dragNode').setContent(drag.get('node').get('innerHTML')); 401 drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline'); 402 }, 403 404 drag_dropmiss: function(e) { 405 // Missed the target, but we assume the user intended to drop it 406 // on the last ghost node location, e.drag and e.drop should be 407 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 408 this.drop_hit(e); 409 }, 410 411 drop_hit: function(e) { 412 var drag = e.drag; 413 // Get a reference to our drag node 414 var dragnode = drag.get('node'); 415 var dropnode = e.drop.get('node'); 416 417 // Add spinner if it not there 418 var actionarea = dragnode.one(CSS.ACTIONAREA); 419 var spinner = M.util.add_spinner(Y, actionarea); 420 421 var params = {}; 422 423 // Handle any variables which we must pass back through to 424 var pageparams = this.get('config').pageparams; 425 var varname; 426 for (varname in pageparams) { 427 params[varname] = pageparams[varname]; 428 } 429 430 // Prepare request parameters 431 params.sesskey = M.cfg.sesskey; 432 params.courseid = this.get('courseid'); 433 params.quizid = this.get('quizid'); 434 params['class'] = 'resource'; 435 params.field = 'move'; 436 params.id = Number(Y.Moodle.mod_quiz.util.slot.getId(dragnode)); 437 params.sectionId = Y.Moodle.core_course.util.section.getId(dropnode.ancestor(M.mod_quiz.edit.get_section_wrapper(Y), true)); 438 439 var previousslot = dragnode.previous(SELECTOR.SLOT); 440 if (previousslot) { 441 params.previousid = Number(Y.Moodle.mod_quiz.util.slot.getId(previousslot)); 442 } 443 444 var previouspage = dragnode.previous(SELECTOR.PAGE); 445 if (previouspage) { 446 params.page = Number(Y.Moodle.mod_quiz.util.page.getId(previouspage)); 447 } 448 449 // Do AJAX request 450 var uri = M.cfg.wwwroot + this.get('ajaxurl'); 451 452 Y.io(uri, { 453 method: 'POST', 454 data: params, 455 on: { 456 start: function() { 457 this.lock_drag_handle(drag, CSS.EDITINGMOVE); 458 spinner.show(); 459 }, 460 success: function(tid, response) { 461 var responsetext = Y.JSON.parse(response.responseText); 462 var params = {element: dragnode, visible: responsetext.visible}; 463 M.mod_quiz.quizbase.invoke_function('set_visibility_resource_ui', params); 464 this.unlock_drag_handle(drag, CSS.EDITINGMOVE); 465 window.setTimeout(function() { 466 spinner.hide(); 467 }, 250); 468 M.mod_quiz.resource_toolbox.reorganise_edit_page(); 469 }, 470 failure: function(tid, response) { 471 this.ajax_failure(response); 472 this.unlock_drag_handle(drag, CSS.SECTIONHANDLE); 473 spinner.hide(); 474 window.location.reload(true); 475 } 476 }, 477 context:this 478 }); 479 }, 480 481 global_drop_over: function(e) { 482 //Overriding parent method so we can stop the slots being dragged before the first page node. 483 484 // Check that drop object belong to correct group. 485 if (!e.drop || !e.drop.inGroup(this.groups)) { 486 return; 487 } 488 489 // Get a reference to our drag and drop nodes. 490 var drag = e.drag.get('node'), 491 drop = e.drop.get('node'); 492 493 // Save last drop target for the case of missed target processing. 494 this.lastdroptarget = e.drop; 495 496 // Are we dropping within the same parent node? 497 if (drop.hasClass(this.samenodeclass)) { 498 var where; 499 500 if (this.goingup) { 501 where = "before"; 502 } else { 503 where = "after"; 504 } 505 506 drop.insert(drag, where); 507 } else if ((drop.hasClass(this.parentnodeclass) || drop.test('[data-droptarget="1"]')) && !drop.contains(drag)) { 508 // We are dropping on parent node and it is empty 509 if (this.goingup) { 510 drop.append(drag); 511 } else { 512 drop.prepend(drag); 513 } 514 } 515 this.drop_over(e); 516 } 517 }, { 518 NAME: 'mod_quiz-dragdrop-resource', 519 ATTRS: { 520 courseid: { 521 value: null 522 }, 523 quizid: { 524 value: null 525 }, 526 ajaxurl: { 527 value: 0 528 }, 529 config: { 530 value: 0 531 } 532 } 533 }); 534 535 M.mod_quiz = M.mod_quiz || {}; 536 M.mod_quiz.init_resource_dragdrop = function(params) { 537 new DRAGRESOURCE(params); 538 }; 539 540 541 }, '@VERSION@', { 542 "requires": [ 543 "base", 544 "node", 545 "io", 546 "dom", 547 "dd", 548 "dd-scroll", 549 "moodle-core-dragdrop", 550 "moodle-core-notification", 551 "moodle-mod_quiz-quizbase", 552 "moodle-mod_quiz-util-base", 553 "moodle-mod_quiz-util-page", 554 "moodle-mod_quiz-util-slot", 555 "moodle-course-util" 556 ] 557 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |