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