[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/yui/src/blocks/js/ -> blocks.js (source)

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1