[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yui/build/moodle-core-blocks/ -> moodle-core-blocks.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1