[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* global MANAGER */ 2 3 /** 4 * Provides drag and drop functionality for blocks. 5 * 6 * @module moodle-core-blockdraganddrop 7 */ 8 9 var AJAXURL = '/lib/ajax/blocks.php', 10 CSS = { 11 BLOCK: 'block', 12 BLOCKREGION: 'block-region', 13 BLOCKADMINBLOCK: 'block_adminblock', 14 EDITINGMOVE: 'editing_move', 15 HEADER: 'header', 16 LIGHTBOX: 'lightbox', 17 REGIONCONTENT: 'region-content', 18 SKIPBLOCK: 'skip-block', 19 SKIPBLOCKTO: 'skip-block-to', 20 MYINDEX: 'page-my-index', 21 REGIONMAIN: 'region-main', 22 BLOCKSMOVING: 'blocks-moving' 23 }; 24 25 var SELECTOR = { 26 DRAGHANDLE: '.' + CSS.HEADER + ' .commands .moodle-core-dragdrop-draghandle' 27 }; 28 29 /** 30 * Legacy drag and drop manager. 31 * This drag and drop manager is specifically designed for themes using side-pre and side-post 32 * that do not make use of the block output methods introduced by MDL-39824. 33 * 34 * @namespace M.core.blockdraganddrop 35 * @class LegacyManager 36 * @constructor 37 * @extends M.core.dragdrop 38 */ 39 var DRAGBLOCK = function() { 40 DRAGBLOCK.superclass.constructor.apply(this, arguments); 41 }; 42 Y.extend(DRAGBLOCK, M.core.dragdrop, { 43 skipnodetop: null, 44 skipnodebottom: null, 45 dragsourceregion: null, 46 initializer: function() { 47 // Set group for parent class 48 this.groups = ['block']; 49 this.samenodeclass = CSS.BLOCK; 50 this.parentnodeclass = CSS.REGIONCONTENT; 51 52 // Add relevant classes and ID to 'content' block region on Dashboard page. 53 var myhomecontent = Y.Node.all('body#' + CSS.MYINDEX + ' #' + CSS.REGIONMAIN + ' > .' + CSS.REGIONCONTENT); 54 if (myhomecontent.size() > 0) { 55 var contentregion = myhomecontent.item(0); 56 contentregion.addClass(CSS.BLOCKREGION); 57 contentregion.set('id', CSS.REGIONCONTENT); 58 contentregion.one('div').addClass(CSS.REGIONCONTENT); 59 } 60 61 // Initialise blocks dragging 62 // Find all block regions on the page 63 var blockregionlist = Y.Node.all('div.' + CSS.BLOCKREGION); 64 65 if (blockregionlist.size() === 0) { 66 return false; 67 } 68 69 // See if we are missing either of block regions, 70 // if yes we need to add an empty one to use as target 71 if (blockregionlist.size() !== this.get('regions').length) { 72 var blockregion = Y.Node.create('<div></div>') 73 .addClass(CSS.BLOCKREGION); 74 var regioncontent = Y.Node.create('<div></div>') 75 .addClass(CSS.REGIONCONTENT); 76 blockregion.appendChild(regioncontent); 77 var pre = blockregionlist.filter('#region-pre'); 78 var post = blockregionlist.filter('#region-post'); 79 80 if (pre.size() === 0 && post.size() === 1) { 81 // pre block is missing, instert it before post 82 blockregion.setAttrs({id: 'region-pre'}); 83 post.item(0).insert(blockregion, 'before'); 84 blockregionlist.unshift(blockregion); 85 } else if (post.size() === 0 && pre.size() === 1) { 86 // post block is missing, instert it after pre 87 blockregion.setAttrs({id: 'region-post'}); 88 pre.item(0).insert(blockregion, 'after'); 89 blockregionlist.push(blockregion); 90 } 91 } 92 93 blockregionlist.each(function(blockregionnode) { 94 95 // Setting blockregion as droptarget (the case when it is empty) 96 // The region-post (the right one) 97 // is very narrow, so add extra padding on the left to drop block on it. 98 new Y.DD.Drop({ 99 node: blockregionnode.one('div.' + CSS.REGIONCONTENT), 100 groups: this.groups, 101 padding: '40 240 40 240' 102 }); 103 104 // Make each div element in the list of blocks draggable 105 var del = new Y.DD.Delegate({ 106 container: blockregionnode, 107 nodes: '.' + CSS.BLOCK, 108 target: true, 109 handles: [SELECTOR.DRAGHANDLE], 110 invalid: '.block-hider-hide, .block-hider-show, .moveto', 111 dragConfig: {groups: this.groups} 112 }); 113 del.dd.plug(Y.Plugin.DDProxy, { 114 // Don't move the node at the end of the drag 115 moveOnEnd: false 116 }); 117 del.dd.plug(Y.Plugin.DDWinScroll); 118 119 var blocklist = blockregionnode.all('.' + CSS.BLOCK); 120 blocklist.each(function(blocknode) { 121 var move = blocknode.one('a.' + CSS.EDITINGMOVE); 122 if (move) { 123 move.replace(this.get_drag_handle(move.getAttribute('title'), '', 'iconsmall', true)); 124 blocknode.one(SELECTOR.DRAGHANDLE).setStyle('cursor', 'move'); 125 } 126 }, this); 127 }, this); 128 }, 129 130 get_block_id: function(node) { 131 return Number(node.get('id').replace(/inst/i, '')); 132 }, 133 134 get_block_region: function(node) { 135 var region = node.ancestor('div.' + CSS.BLOCKREGION).get('id').replace(/region-/i, ''); 136 if (Y.Array.indexOf(this.get('regions'), region) === -1) { 137 // Must be standard side-X 138 if (window.right_to_left()) { 139 if (region === 'post') { 140 region = 'pre'; 141 } else if (region === 'pre') { 142 region = 'post'; 143 } 144 } 145 return 'side-' + region; 146 } 147 // Perhaps custom region 148 return region; 149 }, 150 151 get_region_id: function(node) { 152 return node.get('id').replace(/region-/i, ''); 153 }, 154 155 drag_start: function(e) { 156 // Get our drag object 157 var drag = e.target; 158 159 // Store the parent node of original drag node (block) 160 // we will need it later for show/hide empty regions 161 this.dragsourceregion = drag.get('node').ancestor('div.' + CSS.BLOCKREGION); 162 163 // Determine skipnodes and store them 164 if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) { 165 this.skipnodetop = drag.get('node').previous(); 166 } 167 if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) { 168 this.skipnodebottom = drag.get('node').next(); 169 } 170 171 // Add the blocks-moving class so that the theme can respond if need be. 172 Y.one('body').addClass(CSS.BLOCKSMOVING); 173 }, 174 175 drop_over: function(e) { 176 // Get a reference to our drag and drop nodes 177 var drag = e.drag.get('node'); 178 var drop = e.drop.get('node'); 179 180 // We need to fix the case when parent drop over event has determined 181 // 'goingup' and appended the drag node after admin-block. 182 if (drop.hasClass(this.parentnodeclass) && 183 drop.one('.' + CSS.BLOCKADMINBLOCK) && 184 drop.one('.' + CSS.BLOCKADMINBLOCK).next('.' + CSS.BLOCK)) { 185 drop.prepend(drag); 186 } 187 188 // Block is moved within the same region 189 // stop here, no need to modify anything. 190 if (this.dragsourceregion.contains(drop)) { 191 return false; 192 } 193 194 // TODO: Hiding-displaying block region only works for base theme blocks 195 // (region-pre, region-post) at the moment. It should be improved 196 // to work with custom block regions as well. 197 198 // TODO: Fix this for the case when user drag block towards empty section, 199 // then the section appears, then user chnages his mind and moving back to 200 // original section. The opposite section remains opened and empty. 201 202 var documentbody = Y.one('body'); 203 // Moving block towards hidden region-content, display it 204 var regionname = this.get_region_id(this.dragsourceregion); 205 if (documentbody.hasClass('side-' + regionname + '-only')) { 206 documentbody.removeClass('side-' + regionname + '-only'); 207 } 208 209 // Moving from empty region-content towards the opposite one, 210 // hide empty one (only for region-pre, region-post areas at the moment). 211 regionname = this.get_region_id(drop.ancestor('div.' + CSS.BLOCKREGION)); 212 if (this.dragsourceregion.all('.' + CSS.BLOCK).size() === 0 && 213 this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) { 214 if (!documentbody.hasClass('side-' + regionname + '-only')) { 215 documentbody.addClass('side-' + regionname + '-only'); 216 } 217 } 218 }, 219 220 drag_end: function() { 221 // clear variables 222 this.skipnodetop = null; 223 this.skipnodebottom = null; 224 this.dragsourceregion = null; 225 // Remove the blocks moving class once the drag-drop is over. 226 Y.one('body').removeClass(CSS.BLOCKSMOVING); 227 }, 228 229 drag_dropmiss: function(e) { 230 // Missed the target, but we assume the user intended to drop it 231 // on the last last ghost node location, e.drag and e.drop should be 232 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 233 this.drop_hit(e); 234 }, 235 236 drop_hit: function(e) { 237 var drag = e.drag; 238 // Get a reference to our drag node 239 var dragnode = drag.get('node'); 240 var dropnode = e.drop.get('node'); 241 242 // Amend existing skipnodes 243 if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) { 244 // the one that belongs to block below move below 245 dragnode.insert(dragnode.previous(), 'after'); 246 } 247 // Move original skipnodes 248 if (this.skipnodetop) { 249 dragnode.insert(this.skipnodetop, 'before'); 250 } 251 if (this.skipnodebottom) { 252 dragnode.insert(this.skipnodebottom, 'after'); 253 } 254 255 // Add lightbox if it not there 256 var lightbox = M.util.add_lightbox(Y, dragnode); 257 258 // Prepare request parameters 259 var params = { 260 sesskey: M.cfg.sesskey, 261 courseid: this.get('courseid'), 262 pagelayout: this.get('pagelayout'), 263 pagetype: this.get('pagetype'), 264 subpage: this.get('subpage'), 265 contextid: this.get('contextid'), 266 action: 'move', 267 bui_moveid: this.get_block_id(dragnode), 268 bui_newregion: this.get_block_region(dropnode) 269 }; 270 271 if (this.get('cmid')) { 272 params.cmid = this.get('cmid'); 273 } 274 275 if (dragnode.next('.' + this.samenodeclass) && !dragnode.next('.' + this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) { 276 params.bui_beforeid = this.get_block_id(dragnode.next('.' + this.samenodeclass)); 277 } 278 279 // Do AJAX request 280 Y.io(M.cfg.wwwroot + AJAXURL, { 281 method: 'POST', 282 data: params, 283 on: { 284 start: function() { 285 lightbox.show(); 286 }, 287 success: function(tid, response) { 288 window.setTimeout(function() { 289 lightbox.hide(); 290 }, 250); 291 try { 292 var responsetext = Y.JSON.parse(response.responseText); 293 if (responsetext.error) { 294 new M.core.ajaxException(responsetext); 295 } 296 } catch (e) { 297 // Ignore. 298 } 299 }, 300 failure: function(tid, response) { 301 this.ajax_failure(response); 302 lightbox.hide(); 303 } 304 }, 305 context: this 306 }); 307 } 308 }, { 309 NAME: 'core-blocks-dragdrop', 310 ATTRS: { 311 courseid: { 312 value: null 313 }, 314 cmid: { 315 value: null 316 }, 317 contextid: { 318 value: null 319 }, 320 pagelayout: { 321 value: null 322 }, 323 pagetype: { 324 value: null 325 }, 326 subpage: { 327 value: null 328 }, 329 regions: { 330 value: null 331 } 332 } 333 }); 334 335 M.core = M.core || {}; 336 M.core.blockdraganddrop = M.core.blockdraganddrop || {}; 337 338 /** 339 * True if the page is using the new blocks methods. 340 * @private 341 * @static 342 * @property M.core.blockdraganddrop._isusingnewblocksmethod 343 * @type Boolean 344 * @default null 345 */ 346 M.core.blockdraganddrop._isusingnewblocksmethod = null; 347 348 /** 349 * Returns true if the page is using the new blocks methods. 350 * @static 351 * @method M.core.blockdraganddrop.is_using_blocks_render_method 352 * @return Boolean 353 */ 354 M.core.blockdraganddrop.is_using_blocks_render_method = function() { 355 if (this._isusingnewblocksmethod === null) { 356 var goodregions = Y.all('.block-region[data-blockregion]').size(); 357 var allregions = Y.all('.block-region').size(); 358 this._isusingnewblocksmethod = (allregions === goodregions); 359 if (goodregions > 0 && allregions > 0 && goodregions !== allregions) { 360 Y.log('Both core_renderer::blocks and core_renderer::blocks_for_region have been used.', 'warn', 'moodle-core_blocks'); 361 } 362 } 363 return this._isusingnewblocksmethod; 364 }; 365 366 /** 367 * Initialises a drag and drop manager. 368 * This should only ever be called once for a page. 369 * @static 370 * @method M.core.blockdraganddrop.init 371 * @param {Object} params 372 * @return Manager 373 */ 374 M.core.blockdraganddrop.init = function(params) { 375 if (this.is_using_blocks_render_method()) { 376 Y.log('Block drag and drop initialised for the blocks method.', 'info', 'moodle-core_blocks'); 377 new MANAGER(params); 378 } else { 379 Y.log('Block drag and drop initialised with the legacy manager (blocks_for_region used).', 'info', 'moodle-core_blocks'); 380 new DRAGBLOCK(params); 381 } 382 }; 383 384 /* 385 * Legacy code to keep things working. 386 */ 387 M.core_blocks = M.core_blocks || {}; 388 M.core_blocks.init_dragdrop = function(params) { 389 M.core.blockdraganddrop.init(params); 390 };
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 |