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