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