[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 /** 2 * This file contains the drag and drop manager class. 3 * 4 * Provides drag and drop functionality for blocks. 5 * 6 * @module moodle-core-blockdraganddrop 7 */ 8 9 /** 10 * Constructs a new Block drag and drop manager. 11 * 12 * @namespace M.core.blockdraganddrop 13 * @class Manager 14 * @constructor 15 * @extends M.core.dragdrop 16 */ 17 var MANAGER = function() { 18 MANAGER.superclass.constructor.apply(this, arguments); 19 }; 20 MANAGER.prototype = { 21 22 /** 23 * The skip block link from above the block being dragged while a drag is in progress. 24 * Required by the M.core.dragdrop from whom this class extends. 25 * @private 26 * @property skipnodetop 27 * @type Node 28 * @default null 29 */ 30 skipnodetop : null, 31 32 /** 33 * The skip block link from below the block being dragged while a drag is in progress. 34 * Required by the M.core.dragdrop from whom this class extends. 35 * @private 36 * @property skipnodebottom 37 * @type Node 38 * @default null 39 */ 40 skipnodebottom : null, 41 42 /** 43 * An associative object of regions and the 44 * @property regionobjects 45 * @type {Object} Primitive object mocking an associative array. 46 * @type {BLOCKREGION} [regionname]* Each item uses the region name as the key with the value being 47 * an instance of the BLOCKREGION class. 48 */ 49 regionobjects : {}, 50 51 /** 52 * Called during the initialisation process of the object. 53 * @method initializer 54 */ 55 initializer : function() { 56 Y.log('Initialising drag and drop for blocks.', 'info'); 57 var regionnames = this.get('regions'), 58 i = 0, 59 region, 60 regionname, 61 dragdelegation; 62 63 // Evil required by M.core.dragdrop. 64 this.groups = ['block']; 65 this.samenodeclass = CSS.BLOCK; 66 this.parentnodeclass = CSS.BLOCKREGION; 67 68 // Add relevant classes and ID to 'content' block region on My Home page. 69 var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT); 70 if (myhomecontent.size() > 0) { 71 var contentregion = myhomecontent.item(0); 72 contentregion.addClass(CSS.BLOCKREGION); 73 contentregion.set('id', CSS.REGIONCONTENT); 74 contentregion.one('div').addClass(CSS.REGIONCONTENT); 75 } 76 77 for (i in regionnames) { 78 regionname = regionnames[i]; 79 region = new BLOCKREGION({ 80 manager : this, 81 region : regionname, 82 node : Y.one('#block-region-'+regionname) 83 }); 84 this.regionobjects[regionname] = region; 85 86 // Setting blockregion as droptarget (the case when it is empty) 87 // The region-post (the right one) 88 // is very narrow, so add extra padding on the left to drop block on it. 89 new Y.DD.Drop({ 90 node: region.get_droptarget(), 91 groups: this.groups, 92 padding: '40 240 40 240' 93 }); 94 95 // Make each div element in the list of blocks draggable 96 dragdelegation = new Y.DD.Delegate({ 97 container: region.get_droptarget(), 98 nodes: '.'+CSS.BLOCK, 99 target: true, 100 handles: [SELECTOR.DRAGHANDLE], 101 invalid: '.block-hider-hide, .block-hider-show, .moveto, .block_fake', 102 dragConfig: {groups: this.groups} 103 }); 104 dragdelegation.dd.plug(Y.Plugin.DDProxy, { 105 // Don't move the node at the end of the drag 106 moveOnEnd: false 107 }); 108 dragdelegation.dd.plug(Y.Plugin.DDWinScroll); 109 110 // On the DD Manager start operation, we enable all block regions so that they can be drop targets. This 111 // must be done *before* drag:start but after dragging has been initialised. 112 Y.DD.DDM.on('ddm:start', this.enable_all_regions, this); 113 114 region.change_block_move_icons(this); 115 } 116 Y.log('Initialisation of drag and drop for blocks complete.', 'info'); 117 }, 118 119 /** 120 * Returns the ID of the block the given node represents. 121 * @method get_block_id 122 * @param {Node} node 123 * @return {int} The blocks ID in the database. 124 */ 125 get_block_id : function(node) { 126 return Number(node.get('id').replace(/inst/i, '')); 127 }, 128 129 /** 130 * Returns the block region that the node is part of or belonging to. 131 * @method get_block_region 132 * @param {Y.Node} node 133 * @return {string} The region name. 134 */ 135 get_block_region : function(node) { 136 if (!node.test('[data-blockregion]')) { 137 node = node.ancestor('[data-blockregion]'); 138 } 139 return node.getData('blockregion'); 140 }, 141 142 /** 143 * Returns the BLOCKREGION instance that represents the block region the given node is part of. 144 * @method get_region_object 145 * @param {Y.Node} node 146 * @return {BLOCKREGION} 147 */ 148 get_region_object : function(node) { 149 return this.regionobjects[this.get_block_region(node)]; 150 }, 151 152 /** 153 * Enables all fo the regions so that they are all visible while dragging is occuring. 154 * 155 * @method enable_all_regions 156 */ 157 enable_all_regions : function() { 158 var groups = Y.DD.DDM.activeDrag.get('groups'); 159 160 // As we're called by Y.DD.DDM, we can't be certain that the call 161 // relates specifically to a block drag/drop operation. Test 162 // whether the relevant group applies here. 163 if (!groups || Y.Array.indexOf(groups, 'block') === -1) { 164 return; 165 } 166 167 var i; 168 for (i in this.regionobjects) { 169 if (!this.regionobjects.hasOwnProperty(i)) { 170 continue; 171 } 172 this.regionobjects[i].enable(); 173 } 174 }, 175 176 /** 177 * Disables enabled regions if they contain no blocks. 178 * @method disable_regions_if_required 179 */ 180 disable_regions_if_required : function() { 181 var i = 0; 182 for (i in this.regionobjects) { 183 this.regionobjects[i].disable_if_required(); 184 } 185 }, 186 187 /** 188 * Called by M.core.dragdrop.global_drag_start when dragging starts. 189 * @method drag_start 190 * @param {Event} e 191 */ 192 drag_start : function(e) { 193 // Get our drag object 194 var drag = e.target; 195 196 // Store the parent node of original drag node (block) 197 // we will need it later for show/hide empty regions 198 199 // Determine skipnodes and store them 200 if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) { 201 this.skipnodetop = drag.get('node').previous(); 202 } 203 if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) { 204 this.skipnodebottom = drag.get('node').next(); 205 } 206 }, 207 208 /** 209 * Called by M.core.dragdrop.global_drop_over when something is dragged over a drop target. 210 * @method drop_over 211 * @param {Event} e 212 */ 213 drop_over : function(e) { 214 // Get a reference to our drag and drop nodes 215 var drag = e.drag.get('node'); 216 var drop = e.drop.get('node'); 217 218 // We need to fix the case when parent drop over event has determined 219 // 'goingup' and appended the drag node after admin-block. 220 if (drop.hasClass(CSS.REGIONCONTENT) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) { 221 drop.prepend(drag); 222 } 223 }, 224 225 /** 226 * Called by M.core.dragdrop.global_drop_end when a drop has been completed. 227 * @method drop_end 228 */ 229 drop_end : function() { 230 // Clear variables. 231 this.skipnodetop = null; 232 this.skipnodebottom = null; 233 this.disable_regions_if_required(); 234 }, 235 236 /** 237 * Called by M.core.dragdrop.global_drag_dropmiss when something has been dropped on a node that isn't contained by a drop target. 238 * @method drag_dropmiss 239 * @param {Event} e 240 */ 241 drag_dropmiss : function(e) { 242 // Missed the target, but we assume the user intended to drop it 243 // on the last ghost node location, e.drag and e.drop should be 244 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 245 this.drop_hit(e); 246 }, 247 248 /** 249 * Called by M.core.dragdrop.global_drag_hit when something has been dropped on a drop target. 250 * @method drop_hit 251 * @param {Event} e 252 */ 253 drop_hit : function(e) { 254 // Get a reference to our drag node 255 var dragnode = e.drag.get('node'); 256 var dropnode = e.drop.get('node'); 257 258 // Amend existing skipnodes 259 if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) { 260 // the one that belongs to block below move below 261 dragnode.insert(dragnode.previous(), 'after'); 262 } 263 // Move original skipnodes 264 if (this.skipnodetop) { 265 dragnode.insert(this.skipnodetop, 'before'); 266 } 267 if (this.skipnodebottom) { 268 dragnode.insert(this.skipnodebottom, 'after'); 269 } 270 271 // Add lightbox if it not there 272 var lightbox = M.util.add_lightbox(Y, dragnode); 273 274 // Prepare request parameters 275 var params = { 276 sesskey : M.cfg.sesskey, 277 courseid : this.get('courseid'), 278 pagelayout : this.get('pagelayout'), 279 pagetype : this.get('pagetype'), 280 subpage : this.get('subpage'), 281 contextid : this.get('contextid'), 282 action : 'move', 283 bui_moveid : this.get_block_id(dragnode), 284 bui_newregion : this.get_block_region(dropnode) 285 }; 286 287 if (this.get('cmid')) { 288 params.cmid = this.get('cmid'); 289 } 290 291 if (dragnode.next('.'+CSS.BLOCK) && !dragnode.next('.'+CSS.BLOCK).hasClass(CSS.BLOCKADMINBLOCK)) { 292 params.bui_beforeid = this.get_block_id(dragnode.next('.'+CSS.BLOCK)); 293 } 294 295 // Do AJAX request 296 Y.io(M.cfg.wwwroot+AJAXURL, { 297 method: 'POST', 298 data: params, 299 on: { 300 start : function() { 301 lightbox.show(); 302 }, 303 success: function(tid, response) { 304 window.setTimeout(function() { 305 lightbox.hide(); 306 }, 250); 307 try { 308 var responsetext = Y.JSON.parse(response.responseText); 309 if (responsetext.error) { 310 new M.core.ajaxException(responsetext); 311 } 312 } catch (e) {} 313 }, 314 failure: function(tid, response) { 315 this.ajax_failure(response); 316 lightbox.hide(); 317 }, 318 complete : function() { 319 this.disable_regions_if_required(); 320 } 321 }, 322 context:this 323 }); 324 } 325 }; 326 Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, { 327 NAME : 'core-blocks-dragdrop-manager', 328 ATTRS : { 329 /** 330 * The Course ID if there is one. 331 * @attribute courseid 332 * @type int|null 333 * @default null 334 */ 335 courseid : { 336 value : null 337 }, 338 339 /** 340 * The Course Module ID if there is one. 341 * @attribute cmid 342 * @type int|null 343 * @default null 344 */ 345 cmid : { 346 value : null 347 }, 348 349 /** 350 * The Context ID. 351 * @attribute contextid 352 * @type int|null 353 * @default null 354 */ 355 contextid : { 356 value : null 357 }, 358 359 /** 360 * The current page layout. 361 * @attribute pagelayout 362 * @type string|null 363 * @default null 364 */ 365 pagelayout : { 366 value : null 367 }, 368 369 /** 370 * The page type string, should be used as the id for the body tag in the theme. 371 * @attribute pagetype 372 * @type string|null 373 * @default null 374 */ 375 pagetype : { 376 value : null 377 }, 378 379 /** 380 * The subpage identifier, if any. 381 * @attribute subpage 382 * @type string|null 383 * @default null 384 */ 385 subpage : { 386 value : null 387 }, 388 389 /** 390 * An array of block regions that are present on the page. 391 * @attribute regions 392 * @type array|null 393 * @default Array[] 394 */ 395 regions : { 396 value : [] 397 } 398 } 399 });
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 |