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