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