[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-core-blocks', function (Y, NAME) { 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 My Home 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 (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) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) { 183 drop.prepend(drag); 184 } 185 186 // Block is moved within the same region 187 // stop here, no need to modify anything. 188 if (this.dragsourceregion.contains(drop)) { 189 return false; 190 } 191 192 // TODO: Hiding-displaying block region only works for base theme blocks 193 // (region-pre, region-post) at the moment. It should be improved 194 // to work with custom block regions as well. 195 196 // TODO: Fix this for the case when user drag block towards empty section, 197 // then the section appears, then user chnages his mind and moving back to 198 // original section. The opposite section remains opened and empty. 199 200 var documentbody = Y.one('body'); 201 // Moving block towards hidden region-content, display it 202 var regionname = this.get_region_id(this.dragsourceregion); 203 if (documentbody.hasClass('side-'+regionname+'-only')) { 204 documentbody.removeClass('side-'+regionname+'-only'); 205 } 206 207 // Moving from empty region-content towards the opposite one, 208 // hide empty one (only for region-pre, region-post areas at the moment). 209 regionname = this.get_region_id(drop.ancestor('div.'+CSS.BLOCKREGION)); 210 if (this.dragsourceregion.all('.'+CSS.BLOCK).size() === 0 && this.dragsourceregion.get('id').match(/(region-pre|region-post)/i)) { 211 if (!documentbody.hasClass('side-'+regionname+'-only')) { 212 documentbody.addClass('side-'+regionname+'-only'); 213 } 214 } 215 }, 216 217 drag_end : function() { 218 // clear variables 219 this.skipnodetop = null; 220 this.skipnodebottom = null; 221 this.dragsourceregion = null; 222 // Remove the blocks moving class once the drag-drop is over. 223 Y.one('body').removeClass(CSS.BLOCKSMOVING); 224 }, 225 226 drag_dropmiss : function(e) { 227 // Missed the target, but we assume the user intended to drop it 228 // on the last last ghost node location, e.drag and e.drop should be 229 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 230 this.drop_hit(e); 231 }, 232 233 drop_hit : function(e) { 234 var drag = e.drag; 235 // Get a reference to our drag node 236 var dragnode = drag.get('node'); 237 var dropnode = e.drop.get('node'); 238 239 // Amend existing skipnodes 240 if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) { 241 // the one that belongs to block below move below 242 dragnode.insert(dragnode.previous(), 'after'); 243 } 244 // Move original skipnodes 245 if (this.skipnodetop) { 246 dragnode.insert(this.skipnodetop, 'before'); 247 } 248 if (this.skipnodebottom) { 249 dragnode.insert(this.skipnodebottom, 'after'); 250 } 251 252 // Add lightbox if it not there 253 var lightbox = M.util.add_lightbox(Y, dragnode); 254 255 // Prepare request parameters 256 var params = { 257 sesskey : M.cfg.sesskey, 258 courseid : this.get('courseid'), 259 pagelayout : this.get('pagelayout'), 260 pagetype : this.get('pagetype'), 261 subpage : this.get('subpage'), 262 contextid : this.get('contextid'), 263 action : 'move', 264 bui_moveid : this.get_block_id(dragnode), 265 bui_newregion : this.get_block_region(dropnode) 266 }; 267 268 if (this.get('cmid')) { 269 params.cmid = this.get('cmid'); 270 } 271 272 if (dragnode.next('.'+this.samenodeclass) && !dragnode.next('.'+this.samenodeclass).hasClass(CSS.BLOCKADMINBLOCK)) { 273 params.bui_beforeid = this.get_block_id(dragnode.next('.'+this.samenodeclass)); 274 } 275 276 // Do AJAX request 277 Y.io(M.cfg.wwwroot+AJAXURL, { 278 method: 'POST', 279 data: params, 280 on: { 281 start : function() { 282 lightbox.show(); 283 }, 284 success: function(tid, response) { 285 window.setTimeout(function() { 286 lightbox.hide(); 287 }, 250); 288 try { 289 var responsetext = Y.JSON.parse(response.responseText); 290 if (responsetext.error) { 291 new M.core.ajaxException(responsetext); 292 } 293 } catch (e) {} 294 }, 295 failure: function(tid, response) { 296 this.ajax_failure(response); 297 lightbox.hide(); 298 } 299 }, 300 context:this 301 }); 302 } 303 }, { 304 NAME : 'core-blocks-dragdrop', 305 ATTRS : { 306 courseid : { 307 value : null 308 }, 309 cmid : { 310 value : null 311 }, 312 contextid : { 313 value : null 314 }, 315 pagelayout : { 316 value : null 317 }, 318 pagetype : { 319 value : null 320 }, 321 subpage : { 322 value : null 323 }, 324 regions : { 325 value : null 326 } 327 } 328 }); 329 330 M.core = M.core || {}; 331 M.core.blockdraganddrop = M.core.blockdraganddrop || {}; 332 333 /** 334 * True if the page is using the new blocks methods. 335 * @private 336 * @static 337 * @property M.core.blockdraganddrop._isusingnewblocksmethod 338 * @type Boolean 339 * @default null 340 */ 341 M.core.blockdraganddrop._isusingnewblocksmethod = null; 342 343 /** 344 * Returns true if the page is using the new blocks methods. 345 * @static 346 * @method M.core.blockdraganddrop.is_using_blocks_render_method 347 * @return Boolean 348 */ 349 M.core.blockdraganddrop.is_using_blocks_render_method = function() { 350 if (this._isusingnewblocksmethod === null) { 351 var goodregions = Y.all('.block-region[data-blockregion]').size(); 352 var allregions = Y.all('.block-region').size(); 353 this._isusingnewblocksmethod = (allregions === goodregions); 354 if (goodregions > 0 && allregions > 0 && goodregions !== allregions) { 355 Y.log('Both core_renderer::blocks and core_renderer::blocks_for_region have been used.', 'warn', 'moodle-core_blocks'); 356 } 357 } 358 return this._isusingnewblocksmethod; 359 }; 360 361 /** 362 * Initialises a drag and drop manager. 363 * This should only ever be called once for a page. 364 * @static 365 * @method M.core.blockdraganddrop.init 366 * @param {Object} params 367 * @return Manager 368 */ 369 M.core.blockdraganddrop.init = function(params) { 370 if (this.is_using_blocks_render_method()) { 371 Y.log('Block drag and drop initialised for the blocks method.', 'info', 'moodle-core_blocks'); 372 new MANAGER(params); 373 } else { 374 Y.log('Block drag and drop initialised with the legacy manager (blocks_for_region used).', 'info', 'moodle-core_blocks'); 375 new DRAGBLOCK(params); 376 } 377 }; 378 379 /* 380 * Legacy code to keep things working. 381 */ 382 M.core_blocks = M.core_blocks || {}; 383 M.core_blocks.init_dragdrop = function(params) { 384 M.core.blockdraganddrop.init(params); 385 }; 386 /** 387 * This file contains the drag and drop manager class. 388 * 389 * Provides drag and drop functionality for blocks. 390 * 391 * @module moodle-core-blockdraganddrop 392 */ 393 394 /** 395 * Constructs a new Block drag and drop manager. 396 * 397 * @namespace M.core.blockdraganddrop 398 * @class Manager 399 * @constructor 400 * @extends M.core.dragdrop 401 */ 402 var MANAGER = function() { 403 MANAGER.superclass.constructor.apply(this, arguments); 404 }; 405 MANAGER.prototype = { 406 407 /** 408 * The skip block link from above the block being dragged while a drag is in progress. 409 * Required by the M.core.dragdrop from whom this class extends. 410 * @private 411 * @property skipnodetop 412 * @type Node 413 * @default null 414 */ 415 skipnodetop : null, 416 417 /** 418 * The skip block link from below the block being dragged while a drag is in progress. 419 * Required by the M.core.dragdrop from whom this class extends. 420 * @private 421 * @property skipnodebottom 422 * @type Node 423 * @default null 424 */ 425 skipnodebottom : null, 426 427 /** 428 * An associative object of regions and the 429 * @property regionobjects 430 * @type {Object} Primitive object mocking an associative array. 431 * @type {BLOCKREGION} [regionname]* Each item uses the region name as the key with the value being 432 * an instance of the BLOCKREGION class. 433 */ 434 regionobjects : {}, 435 436 /** 437 * Called during the initialisation process of the object. 438 * @method initializer 439 */ 440 initializer : function() { 441 Y.log('Initialising drag and drop for blocks.', 'info'); 442 var regionnames = this.get('regions'), 443 i = 0, 444 region, 445 regionname, 446 dragdelegation; 447 448 // Evil required by M.core.dragdrop. 449 this.groups = ['block']; 450 this.samenodeclass = CSS.BLOCK; 451 this.parentnodeclass = CSS.BLOCKREGION; 452 453 // Add relevant classes and ID to 'content' block region on My Home page. 454 var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT); 455 if (myhomecontent.size() > 0) { 456 var contentregion = myhomecontent.item(0); 457 contentregion.addClass(CSS.BLOCKREGION); 458 contentregion.set('id', CSS.REGIONCONTENT); 459 contentregion.one('div').addClass(CSS.REGIONCONTENT); 460 } 461 462 for (i in regionnames) { 463 regionname = regionnames[i]; 464 region = new BLOCKREGION({ 465 manager : this, 466 region : regionname, 467 node : Y.one('#block-region-'+regionname) 468 }); 469 this.regionobjects[regionname] = region; 470 471 // Setting blockregion as droptarget (the case when it is empty) 472 // The region-post (the right one) 473 // is very narrow, so add extra padding on the left to drop block on it. 474 new Y.DD.Drop({ 475 node: region.get_droptarget(), 476 groups: this.groups, 477 padding: '40 240 40 240' 478 }); 479 480 // Make each div element in the list of blocks draggable 481 dragdelegation = new Y.DD.Delegate({ 482 container: region.get_droptarget(), 483 nodes: '.'+CSS.BLOCK, 484 target: true, 485 handles: [SELECTOR.DRAGHANDLE], 486 invalid: '.block-hider-hide, .block-hider-show, .moveto, .block_fake', 487 dragConfig: {groups: this.groups} 488 }); 489 dragdelegation.dd.plug(Y.Plugin.DDProxy, { 490 // Don't move the node at the end of the drag 491 moveOnEnd: false 492 }); 493 dragdelegation.dd.plug(Y.Plugin.DDWinScroll); 494 495 // On the DD Manager start operation, we enable all block regions so that they can be drop targets. This 496 // must be done *before* drag:start but after dragging has been initialised. 497 Y.DD.DDM.on('ddm:start', this.enable_all_regions, this); 498 499 region.change_block_move_icons(this); 500 } 501 Y.log('Initialisation of drag and drop for blocks complete.', 'info'); 502 }, 503 504 /** 505 * Returns the ID of the block the given node represents. 506 * @method get_block_id 507 * @param {Node} node 508 * @return {int} The blocks ID in the database. 509 */ 510 get_block_id : function(node) { 511 return Number(node.get('id').replace(/inst/i, '')); 512 }, 513 514 /** 515 * Returns the block region that the node is part of or belonging to. 516 * @method get_block_region 517 * @param {Y.Node} node 518 * @return {string} The region name. 519 */ 520 get_block_region : function(node) { 521 if (!node.test('[data-blockregion]')) { 522 node = node.ancestor('[data-blockregion]'); 523 } 524 return node.getData('blockregion'); 525 }, 526 527 /** 528 * Returns the BLOCKREGION instance that represents the block region the given node is part of. 529 * @method get_region_object 530 * @param {Y.Node} node 531 * @return {BLOCKREGION} 532 */ 533 get_region_object : function(node) { 534 return this.regionobjects[this.get_block_region(node)]; 535 }, 536 537 /** 538 * Enables all fo the regions so that they are all visible while dragging is occuring. 539 * 540 * @method enable_all_regions 541 */ 542 enable_all_regions : function() { 543 var groups = Y.DD.DDM.activeDrag.get('groups'); 544 545 // As we're called by Y.DD.DDM, we can't be certain that the call 546 // relates specifically to a block drag/drop operation. Test 547 // whether the relevant group applies here. 548 if (!groups || Y.Array.indexOf(groups, 'block') === -1) { 549 return; 550 } 551 552 var i; 553 for (i in this.regionobjects) { 554 if (!this.regionobjects.hasOwnProperty(i)) { 555 continue; 556 } 557 this.regionobjects[i].enable(); 558 } 559 }, 560 561 /** 562 * Disables enabled regions if they contain no blocks. 563 * @method disable_regions_if_required 564 */ 565 disable_regions_if_required : function() { 566 var i = 0; 567 for (i in this.regionobjects) { 568 this.regionobjects[i].disable_if_required(); 569 } 570 }, 571 572 /** 573 * Called by M.core.dragdrop.global_drag_start when dragging starts. 574 * @method drag_start 575 * @param {Event} e 576 */ 577 drag_start : function(e) { 578 // Get our drag object 579 var drag = e.target; 580 581 // Store the parent node of original drag node (block) 582 // we will need it later for show/hide empty regions 583 584 // Determine skipnodes and store them 585 if (drag.get('node').previous() && drag.get('node').previous().hasClass(CSS.SKIPBLOCK)) { 586 this.skipnodetop = drag.get('node').previous(); 587 } 588 if (drag.get('node').next() && drag.get('node').next().hasClass(CSS.SKIPBLOCKTO)) { 589 this.skipnodebottom = drag.get('node').next(); 590 } 591 }, 592 593 /** 594 * Called by M.core.dragdrop.global_drop_over when something is dragged over a drop target. 595 * @method drop_over 596 * @param {Event} e 597 */ 598 drop_over : function(e) { 599 // Get a reference to our drag and drop nodes 600 var drag = e.drag.get('node'); 601 var drop = e.drop.get('node'); 602 603 // We need to fix the case when parent drop over event has determined 604 // 'goingup' and appended the drag node after admin-block. 605 if (drop.hasClass(CSS.REGIONCONTENT) && drop.one('.'+CSS.BLOCKADMINBLOCK) && drop.one('.'+CSS.BLOCKADMINBLOCK).next('.'+CSS.BLOCK)) { 606 drop.prepend(drag); 607 } 608 }, 609 610 /** 611 * Called by M.core.dragdrop.global_drop_end when a drop has been completed. 612 * @method drop_end 613 */ 614 drop_end : function() { 615 // Clear variables. 616 this.skipnodetop = null; 617 this.skipnodebottom = null; 618 this.disable_regions_if_required(); 619 }, 620 621 /** 622 * Called by M.core.dragdrop.global_drag_dropmiss when something has been dropped on a node that isn't contained by a drop target. 623 * @method drag_dropmiss 624 * @param {Event} e 625 */ 626 drag_dropmiss : function(e) { 627 // Missed the target, but we assume the user intended to drop it 628 // on the last ghost node location, e.drag and e.drop should be 629 // prepared by global_drag_dropmiss parent so simulate drop_hit(e). 630 this.drop_hit(e); 631 }, 632 633 /** 634 * Called by M.core.dragdrop.global_drag_hit when something has been dropped on a drop target. 635 * @method drop_hit 636 * @param {Event} e 637 */ 638 drop_hit : function(e) { 639 // Get a reference to our drag node 640 var dragnode = e.drag.get('node'); 641 var dropnode = e.drop.get('node'); 642 643 // Amend existing skipnodes 644 if (dragnode.previous() && dragnode.previous().hasClass(CSS.SKIPBLOCK)) { 645 // the one that belongs to block below move below 646 dragnode.insert(dragnode.previous(), 'after'); 647 } 648 // Move original skipnodes 649 if (this.skipnodetop) { 650 dragnode.insert(this.skipnodetop, 'before'); 651 } 652 if (this.skipnodebottom) { 653 dragnode.insert(this.skipnodebottom, 'after'); 654 } 655 656 // Add lightbox if it not there 657 var lightbox = M.util.add_lightbox(Y, dragnode); 658 659 // Prepare request parameters 660 var params = { 661 sesskey : M.cfg.sesskey, 662 courseid : this.get('courseid'), 663 pagelayout : this.get('pagelayout'), 664 pagetype : this.get('pagetype'), 665 subpage : this.get('subpage'), 666 contextid : this.get('contextid'), 667 action : 'move', 668 bui_moveid : this.get_block_id(dragnode), 669 bui_newregion : this.get_block_region(dropnode) 670 }; 671 672 if (this.get('cmid')) { 673 params.cmid = this.get('cmid'); 674 } 675 676 if (dragnode.next('.'+CSS.BLOCK) && !dragnode.next('.'+CSS.BLOCK).hasClass(CSS.BLOCKADMINBLOCK)) { 677 params.bui_beforeid = this.get_block_id(dragnode.next('.'+CSS.BLOCK)); 678 } 679 680 // Do AJAX request 681 Y.io(M.cfg.wwwroot+AJAXURL, { 682 method: 'POST', 683 data: params, 684 on: { 685 start : function() { 686 lightbox.show(); 687 }, 688 success: function(tid, response) { 689 window.setTimeout(function() { 690 lightbox.hide(); 691 }, 250); 692 try { 693 var responsetext = Y.JSON.parse(response.responseText); 694 if (responsetext.error) { 695 new M.core.ajaxException(responsetext); 696 } 697 } catch (e) {} 698 }, 699 failure: function(tid, response) { 700 this.ajax_failure(response); 701 lightbox.hide(); 702 }, 703 complete : function() { 704 this.disable_regions_if_required(); 705 } 706 }, 707 context:this 708 }); 709 } 710 }; 711 Y.extend(MANAGER, M.core.dragdrop, MANAGER.prototype, { 712 NAME : 'core-blocks-dragdrop-manager', 713 ATTRS : { 714 /** 715 * The Course ID if there is one. 716 * @attribute courseid 717 * @type int|null 718 * @default null 719 */ 720 courseid : { 721 value : null 722 }, 723 724 /** 725 * The Course Module ID if there is one. 726 * @attribute cmid 727 * @type int|null 728 * @default null 729 */ 730 cmid : { 731 value : null 732 }, 733 734 /** 735 * The Context ID. 736 * @attribute contextid 737 * @type int|null 738 * @default null 739 */ 740 contextid : { 741 value : null 742 }, 743 744 /** 745 * The current page layout. 746 * @attribute pagelayout 747 * @type string|null 748 * @default null 749 */ 750 pagelayout : { 751 value : null 752 }, 753 754 /** 755 * The page type string, should be used as the id for the body tag in the theme. 756 * @attribute pagetype 757 * @type string|null 758 * @default null 759 */ 760 pagetype : { 761 value : null 762 }, 763 764 /** 765 * The subpage identifier, if any. 766 * @attribute subpage 767 * @type string|null 768 * @default null 769 */ 770 subpage : { 771 value : null 772 }, 773 774 /** 775 * An array of block regions that are present on the page. 776 * @attribute regions 777 * @type array|null 778 * @default Array[] 779 */ 780 regions : { 781 value : [] 782 } 783 } 784 }); 785 /** 786 * This file contains the Block Region class used by the drag and drop manager. 787 * 788 * Provides drag and drop functionality for blocks. 789 * 790 * @module moodle-core-blockdraganddrop 791 */ 792 793 /** 794 * Constructs a new block region object. 795 * 796 * @namespace M.core.blockdraganddrop 797 * @class BlockRegion 798 * @constructor 799 * @extends Base 800 */ 801 var BLOCKREGION = function() { 802 BLOCKREGION.superclass.constructor.apply(this, arguments); 803 }; 804 BLOCKREGION.prototype = { 805 /** 806 * Called during the initialisation process of the object. 807 * @method initializer 808 */ 809 initializer : function() { 810 var node = this.get('node'); 811 Y.log('Block region `'+this.get('region')+'` initialising', 'info'); 812 if (!node) { 813 Y.log('block region known about but no HTML structure found for it. Guessing structure.', 'warn'); 814 node = this.create_and_add_node(); 815 } 816 var body = Y.one('body'), 817 hasblocks = node.all('.'+CSS.BLOCK).size() > 0, 818 hasregionclass = this.get_has_region_class(); 819 this.set('hasblocks', hasblocks); 820 if (!body.hasClass(hasregionclass)) { 821 body.addClass(hasregionclass); 822 } 823 body.addClass((hasblocks) ? this.get_used_region_class() : this.get_empty_region_class()); 824 body.removeClass((hasblocks) ? this.get_empty_region_class() : this.get_used_region_class()); 825 }, 826 /** 827 * Creates a generic block region node and adds it to the DOM at the best guess location. 828 * Any calling of this method is an unfortunate circumstance. 829 * @method create_and_add_node 830 * @return Node The newly created Node 831 */ 832 create_and_add_node : function() { 833 var c = Y.Node.create, 834 region = this.get('region'), 835 node = c('<div id="block-region-'+region+'" data-droptarget="1"></div>') 836 .addClass(CSS.BLOCKREGION) 837 .setData('blockregion', region), 838 regions = this.get('manager').get('regions'), 839 i, 840 haspre = false, 841 haspost = false, 842 added = false, 843 pre, 844 post; 845 846 for (i in regions) { 847 if (regions[i].match(/(pre|left)/)) { 848 haspre = regions[i]; 849 } else if (regions[i].match(/(post|right)/)) { 850 haspost = regions[i]; 851 } 852 } 853 854 if (haspre !== false && haspost !== false) { 855 if (region === haspre) { 856 post = Y.one('#block-region-'+haspost); 857 if (post) { 858 post.insert(node, 'before'); 859 added = true; 860 } 861 } else { 862 pre = Y.one('#block-region-'+haspre); 863 if (pre) { 864 pre.insert(node, 'after'); 865 added = true; 866 } 867 } 868 } 869 if (added === false) { 870 Y.one('body').append(node); 871 } 872 this.set('node', node); 873 874 return node; 875 }, 876 877 /** 878 * Change the move icons to enhanced drag handles and changes the cursor to a move icon when over the header. 879 * @param M.core.dragdrop the block manager 880 * @method change_block_move_icons 881 */ 882 change_block_move_icons : function(manager) { 883 var handle, icon; 884 this.get('node').all('.'+CSS.BLOCK+' a.'+CSS.EDITINGMOVE).each(function(moveicon){ 885 moveicon.setStyle('cursor', 'move'); 886 handle = manager.get_drag_handle(moveicon.getAttribute('title'), '', 'icon', true); 887 icon = handle.one('img'); 888 icon.addClass('iconsmall'); 889 icon.removeClass('icon'); 890 moveicon.replace(handle); 891 }); 892 }, 893 894 /** 895 * Returns the class name on the body that signifies the document knows about this region. 896 * @method get_has_region_class 897 * @return String 898 */ 899 get_has_region_class : function() { 900 return 'has-region-'+this.get('region'); 901 }, 902 903 /** 904 * Returns the class name to use on the body if the region contains no blocks. 905 * @method get_empty_region_class 906 * @return String 907 */ 908 get_empty_region_class : function() { 909 return 'empty-region-'+this.get('region'); 910 }, 911 912 /** 913 * Returns the class name to use on the body if the region contains blocks. 914 * @method get_used_region_class 915 * @return String 916 */ 917 get_used_region_class : function() { 918 return 'used-region-'+this.get('region'); 919 }, 920 921 /** 922 * Returns the node to use as the drop target for this region. 923 * @method get_droptarget 924 * @return Node 925 */ 926 get_droptarget : function() { 927 var node = this.get('node'); 928 if (node.test('[data-droptarget="1"]')) { 929 return node; 930 } 931 return node.one('[data-droptarget="1"]'); 932 }, 933 934 /** 935 * Enables the block region so that we can be sure the user can see it. 936 * This is done even if it is empty. 937 * @method enable 938 */ 939 enable : function() { 940 Y.one('body').addClass(this.get_used_region_class()).removeClass(this.get_empty_region_class()); 941 }, 942 943 /** 944 * Disables the region if it contains no blocks, essentially hiding it from the user. 945 * @method disable_if_required 946 */ 947 disable_if_required : function() { 948 if (this.get('node').all('.'+CSS.BLOCK).size() === 0) { 949 Y.one('body').addClass(this.get_empty_region_class()).removeClass(this.get_used_region_class()); 950 } 951 } 952 }; 953 Y.extend(BLOCKREGION, Y.Base, BLOCKREGION.prototype, { 954 NAME : 'core-blocks-dragdrop-blockregion', 955 ATTRS : { 956 957 /** 958 * The drag and drop manager that created this block region instance. 959 * @attribute manager 960 * @type M.core.blockdraganddrop.Manager 961 * @writeOnce 962 */ 963 manager : { 964 // Can only be set during initialisation and must be set then. 965 writeOnce : 'initOnly', 966 validator : function (value) { 967 return Y.Lang.isObject(value) && value instanceof MANAGER; 968 } 969 }, 970 971 /** 972 * The name of the block region this object represents. 973 * @attribute region 974 * @type String 975 * @writeOnce 976 */ 977 region : { 978 // Can only be set during initialisation and must be set then. 979 writeOnce : 'initOnly', 980 validator : function (value) { 981 return Y.Lang.isString(value); 982 } 983 }, 984 985 /** 986 * The node the block region HTML starts at.s 987 * @attribute region 988 * @type Y.Node 989 */ 990 node : { 991 validator : function (value) { 992 return Y.Lang.isObject(value) || Y.Lang.isNull(value); 993 } 994 }, 995 996 /** 997 * True if the block region currently contains blocks. 998 * @attribute hasblocks 999 * @type Boolean 1000 * @default false 1001 */ 1002 hasblocks : { 1003 value : false, 1004 validator : function (value) { 1005 return Y.Lang.isBoolean(value); 1006 } 1007 } 1008 } 1009 }); 1010 1011 1012 }, '@VERSION@', { 1013 "requires": [ 1014 "base", 1015 "node", 1016 "io", 1017 "dom", 1018 "dd", 1019 "dd-scroll", 1020 "moodle-core-dragdrop", 1021 "moodle-core-notification" 1022 ] 1023 });
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 |