[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/dd-constrain/ -> dd-constrain-debug.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('dd-constrain', function (Y, NAME) {
   9  
  10  
  11      /**
  12       * The Drag & Drop Utility allows you to create a draggable interface efficiently,
  13       * buffering you from browser-level abnormalities and enabling you to focus on the interesting
  14       * logic surrounding your particular implementation. This component enables you to create a
  15       * variety of standard draggable objects with just a few lines of code and then,
  16       * using its extensive API, add your own specific implementation logic.
  17       * @module dd
  18       * @main dd
  19       * @submodule dd-constrain
  20       */
  21      /**
  22       * Plugin for the dd-drag module to add the constraining methods to it.
  23       * It supports constraining to a node or viewport. It supports tick based moves and XY axis constraints.
  24       * @class DDConstrained
  25       * @extends Base
  26       * @constructor
  27       * @namespace Plugin
  28       */
  29  
  30      var DRAG_NODE = 'dragNode',
  31          OFFSET_HEIGHT = 'offsetHeight',
  32          OFFSET_WIDTH = 'offsetWidth',
  33          HOST = 'host',
  34          TICK_X_ARRAY = 'tickXArray',
  35          TICK_Y_ARRAY = 'tickYArray',
  36          DDM = Y.DD.DDM,
  37          TOP = 'top',
  38          RIGHT = 'right',
  39          BOTTOM = 'bottom',
  40          LEFT = 'left',
  41          VIEW = 'view',
  42          proto = null,
  43  
  44          /**
  45          * Fires when this node is aligned with the tickX value.
  46          * @event drag:tickAlignX
  47          * @param {EventFacade} event An Event Facade object
  48          * @type {CustomEvent}
  49          */
  50          EV_TICK_ALIGN_X = 'drag:tickAlignX',
  51  
  52          /**
  53          * Fires when this node is aligned with the tickY value.
  54          * @event drag:tickAlignY
  55          * @param {EventFacade} event An Event Facade object
  56          * @type {CustomEvent}
  57          */
  58          EV_TICK_ALIGN_Y = 'drag:tickAlignY',
  59  
  60          C = function() {
  61              this._lazyAddAttrs = false;
  62              C.superclass.constructor.apply(this, arguments);
  63          };
  64  
  65      C.NAME = 'ddConstrained';
  66      /**
  67      * The Constrained instance will be placed on the Drag instance under the con namespace.
  68      * @property NS
  69      * @default con
  70      * @readonly
  71      * @protected
  72      * @static
  73      * @type {String}
  74      */
  75      C.NS = 'con';
  76  
  77      C.ATTRS = {
  78          host: {
  79          },
  80          /**
  81          * Stick the drag movement to the X-Axis. Default: false
  82          * @attribute stickX
  83          * @type Boolean
  84          */
  85          stickX: {
  86              value: false
  87          },
  88          /**
  89          * Stick the drag movement to the Y-Axis
  90          * @type Boolean
  91          * @attribute stickY
  92          */
  93          stickY: {
  94              value: false
  95          },
  96          /**
  97          * The X tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
  98          * @type Number/false
  99          * @attribute tickX
 100          */
 101          tickX: {
 102              value: false
 103          },
 104          /**
 105          * The Y tick offset the drag node should snap to on each drag move. False for no ticks. Default: false
 106          * @type Number/false
 107          * @attribute tickY
 108          */
 109          tickY: {
 110              value: false
 111          },
 112          /**
 113          * An array of page coordinates to use as X ticks for drag movement.
 114          * @type Array
 115          * @attribute tickXArray
 116          */
 117          tickXArray: {
 118              value: false
 119          },
 120          /**
 121          * An array of page coordinates to use as Y ticks for drag movement.
 122          * @type Array
 123          * @attribute tickYArray
 124          */
 125          tickYArray: {
 126              value: false
 127          },
 128          /**
 129          * CSS style string for the gutter of a region (supports negative values): '5 0'
 130          * (sets top and bottom to 5px, left and right to 0px), '1 2 3 4' (top 1px, right 2px, bottom 3px, left 4px)
 131          * @attribute gutter
 132          * @type String
 133          */
 134          gutter: {
 135              value: '0',
 136              setter: function(gutter) {
 137                  return Y.DD.DDM.cssSizestoObject(gutter);
 138              }
 139          },
 140          /**
 141          * Will attempt to constrain the drag node to the boundaries. Arguments:<br>
 142          * 'view': Contrain to Viewport<br>
 143          * '#selector_string': Constrain to this node<br>
 144          * '{Region Object}': An Object Literal containing a valid region (top, right, bottom, left) of page positions
 145          * @attribute constrain
 146          * @type {String/Object/Node}
 147          */
 148          constrain: {
 149              value: VIEW,
 150              setter: function(con) {
 151                  var node = Y.one(con);
 152                  if (node) {
 153                      con = node;
 154                  }
 155                  return con;
 156              }
 157          },
 158          /**
 159          * An Object Literal containing a valid region (top, right, bottom, left) of page positions to constrain the drag node to.
 160          * @deprecated
 161          * @attribute constrain2region
 162          * @type Object
 163          */
 164          constrain2region: {
 165              setter: function(r) {
 166                  return this.set('constrain', r);
 167              }
 168          },
 169          /**
 170          * Will attempt to constrain the drag node to the boundaries of this node.
 171          * @deprecated
 172          * @attribute constrain2node
 173          * @type Object
 174          */
 175          constrain2node: {
 176              setter: function(n) {
 177                  return this.set('constrain', Y.one(n));
 178              }
 179          },
 180          /**
 181          * Will attempt to constrain the drag node to the boundaries of the viewport region.
 182          * @deprecated
 183          * @attribute constrain2view
 184          * @type Object
 185          */
 186          constrain2view: {
 187              setter: function() {
 188                  return this.set('constrain', VIEW);
 189              }
 190          },
 191          /**
 192          * Should the region be cached for performace. Default: true
 193          * @attribute cacheRegion
 194          * @type Boolean
 195          */
 196          cacheRegion: {
 197              value: true
 198          }
 199      };
 200  
 201      proto = {
 202          _lastTickXFired: null,
 203          _lastTickYFired: null,
 204  
 205          initializer: function() {
 206              this._createEvents();
 207  
 208              this._eventHandles = [
 209                  this.get(HOST).on('drag:end', Y.bind(this._handleEnd, this)),
 210                  this.get(HOST).on('drag:start', Y.bind(this._handleStart, this)),
 211                  this.get(HOST).after('drag:align', Y.bind(this.align, this)),
 212                  this.get(HOST).after('drag:drag', Y.bind(this.drag, this))
 213              ];
 214          },
 215          destructor: function() {
 216              Y.Array.each(
 217                  this._eventHandles,
 218                  function(handle) {
 219                      handle.detach();
 220                  }
 221              );
 222  
 223              this._eventHandles.length = 0;
 224          },
 225          /**
 226          * This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
 227          * @private
 228          * @method _createEvents
 229          */
 230          _createEvents: function() {
 231              var ev = [
 232                  EV_TICK_ALIGN_X,
 233                  EV_TICK_ALIGN_Y
 234              ];
 235  
 236              Y.Array.each(ev, function(v) {
 237                  this.publish(v, {
 238                      type: v,
 239                      emitFacade: true,
 240                      bubbles: true,
 241                      queuable: false,
 242                      prefix: 'drag'
 243                  });
 244              }, this);
 245          },
 246          /**
 247          * Fires on drag:end
 248          * @private
 249          * @method _handleEnd
 250          */
 251          _handleEnd: function() {
 252              this._lastTickYFired = null;
 253              this._lastTickXFired = null;
 254          },
 255          /**
 256          * Fires on drag:start and clears the _regionCache
 257          * @private
 258          * @method _handleStart
 259          */
 260          _handleStart: function() {
 261              this.resetCache();
 262          },
 263          /**
 264          * Store a cache of the region that we are constraining to
 265          * @private
 266          * @property _regionCache
 267          * @type Object
 268          */
 269          _regionCache: null,
 270          /**
 271          * Get's the region and caches it, called from window.resize and when the cache is null
 272          * @private
 273          * @method _cacheRegion
 274          */
 275          _cacheRegion: function() {
 276              this._regionCache = this.get('constrain').get('region');
 277          },
 278          /**
 279          * Reset the internal region cache.
 280          * @method resetCache
 281          */
 282          resetCache: function() {
 283              this._regionCache = null;
 284          },
 285          /**
 286          * Standardizes the 'constraint' attribute
 287          * @private
 288          * @method _getConstraint
 289          */
 290          _getConstraint: function() {
 291              var con = this.get('constrain'),
 292                  g = this.get('gutter'),
 293                  region;
 294  
 295              if (con) {
 296                  if (con instanceof Y.Node) {
 297                      if (!this._regionCache) {
 298                          this._eventHandles.push(Y.on('resize', Y.bind(this._cacheRegion, this), Y.config.win));
 299                          this._cacheRegion();
 300                      }
 301                      region = Y.clone(this._regionCache);
 302                      if (!this.get('cacheRegion')) {
 303                          this.resetCache();
 304                      }
 305                  } else if (Y.Lang.isObject(con)) {
 306                      region = Y.clone(con);
 307                  }
 308              }
 309              if (!con || !region) {
 310                  con = VIEW;
 311              }
 312              if (con === VIEW) {
 313                  region = this.get(HOST).get(DRAG_NODE).get('viewportRegion');
 314              }
 315  
 316              Y.Object.each(g, function(i, n) {
 317                  if ((n === RIGHT) || (n === BOTTOM)) {
 318                      region[n] -= i;
 319                  } else {
 320                      region[n] += i;
 321                  }
 322              });
 323              return region;
 324          },
 325  
 326          /**
 327          * Get the active region: viewport, node, custom region
 328          * @method getRegion
 329          * @param {Boolean} inc Include the node's height and width
 330          * @return {Object} The active region.
 331          */
 332          getRegion: function(inc) {
 333              var r = {}, oh = null, ow = null,
 334                  host = this.get(HOST);
 335  
 336              r = this._getConstraint();
 337  
 338              if (inc) {
 339                  oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT);
 340                  ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
 341                  r[RIGHT] = r[RIGHT] - ow;
 342                  r[BOTTOM] = r[BOTTOM] - oh;
 343              }
 344              return r;
 345          },
 346          /**
 347          * Check if xy is inside a given region, if not change to it be inside.
 348          * @private
 349          * @method _checkRegion
 350          * @param {Array} _xy The XY to check if it's in the current region, if it isn't
 351          * inside the region, it will reset the xy array to be inside the region.
 352          * @return {Array} The new XY that is inside the region
 353          */
 354          _checkRegion: function(_xy) {
 355              var oxy = _xy,
 356                  r = this.getRegion(),
 357                  host = this.get(HOST),
 358                  oh = host.get(DRAG_NODE).get(OFFSET_HEIGHT),
 359                  ow = host.get(DRAG_NODE).get(OFFSET_WIDTH);
 360  
 361                  if (oxy[1] > (r[BOTTOM] - oh)) {
 362                      _xy[1] = (r[BOTTOM] - oh);
 363                  }
 364                  if (r[TOP] > oxy[1]) {
 365                      _xy[1] = r[TOP];
 366  
 367                  }
 368                  if (oxy[0] > (r[RIGHT] - ow)) {
 369                      _xy[0] = (r[RIGHT] - ow);
 370                  }
 371                  if (r[LEFT] > oxy[0]) {
 372                      _xy[0] = r[LEFT];
 373                  }
 374  
 375              return _xy;
 376          },
 377          /**
 378          * Checks if the XY passed or the dragNode is inside the active region.
 379          * @method inRegion
 380          * @param {Array} xy Optional XY to check, if not supplied this.get('dragNode').getXY() is used.
 381          * @return {Boolean} True if the XY is inside the region, false otherwise.
 382          */
 383          inRegion: function(xy) {
 384              xy = xy || this.get(HOST).get(DRAG_NODE).getXY();
 385  
 386              var _xy = this._checkRegion([xy[0], xy[1]]),
 387                  inside = false;
 388                  if ((xy[0] === _xy[0]) && (xy[1] === _xy[1])) {
 389                      inside = true;
 390                  }
 391              return inside;
 392          },
 393          /**
 394          * Modifies the Drag.actXY method from the after drag:align event. This is where the constraining happens.
 395          * @method align
 396          */
 397          align: function() {
 398              var host = this.get(HOST),
 399                  _xy = [host.actXY[0], host.actXY[1]],
 400                  r = this.getRegion(true);
 401  
 402              if (this.get('stickX')) {
 403                  _xy[1] = (host.startXY[1] - host.deltaXY[1]);
 404              }
 405              if (this.get('stickY')) {
 406                  _xy[0] = (host.startXY[0] - host.deltaXY[0]);
 407              }
 408  
 409              if (r) {
 410                  _xy = this._checkRegion(_xy);
 411              }
 412  
 413              _xy = this._checkTicks(_xy, r);
 414  
 415              host.actXY = _xy;
 416          },
 417          /**
 418          * Fires after drag:drag. Handle the tickX and tickX align events.
 419          * @method drag
 420          */
 421          drag: function() {
 422              var host = this.get(HOST),
 423                  xt = this.get('tickX'),
 424                  yt = this.get('tickY'),
 425                  _xy = [host.actXY[0], host.actXY[1]];
 426  
 427              if ((Y.Lang.isNumber(xt) || this.get(TICK_X_ARRAY)) && (this._lastTickXFired !== _xy[0])) {
 428                  this._tickAlignX();
 429                  this._lastTickXFired = _xy[0];
 430              }
 431  
 432              if ((Y.Lang.isNumber(yt) || this.get(TICK_Y_ARRAY)) && (this._lastTickYFired !== _xy[1])) {
 433                  this._tickAlignY();
 434                  this._lastTickYFired = _xy[1];
 435              }
 436          },
 437          /**
 438          * This method delegates the proper helper method for tick calculations
 439          * @private
 440          * @method _checkTicks
 441          * @param {Array} xy The XY coords for the Drag
 442          * @param {Object} r The optional region that we are bound to.
 443          * @return {Array} The calced XY coords
 444          */
 445          _checkTicks: function(xy, r) {
 446              var host = this.get(HOST),
 447                  lx = (host.startXY[0] - host.deltaXY[0]),
 448                  ly = (host.startXY[1] - host.deltaXY[1]),
 449                  xt = this.get('tickX'),
 450                  yt = this.get('tickY');
 451                  if (xt && !this.get(TICK_X_ARRAY)) {
 452                      xy[0] = DDM._calcTicks(xy[0], lx, xt, r[LEFT], r[RIGHT]);
 453                  }
 454                  if (yt && !this.get(TICK_Y_ARRAY)) {
 455                      xy[1] = DDM._calcTicks(xy[1], ly, yt, r[TOP], r[BOTTOM]);
 456                  }
 457                  if (this.get(TICK_X_ARRAY)) {
 458                      xy[0] = DDM._calcTickArray(xy[0], this.get(TICK_X_ARRAY), r[LEFT], r[RIGHT]);
 459                  }
 460                  if (this.get(TICK_Y_ARRAY)) {
 461                      xy[1] = DDM._calcTickArray(xy[1], this.get(TICK_Y_ARRAY), r[TOP], r[BOTTOM]);
 462                  }
 463  
 464              return xy;
 465          },
 466          /**
 467          * Fires when the actXY[0] reach a new value respecting the tickX gap.
 468          * @private
 469          * @method _tickAlignX
 470          */
 471          _tickAlignX: function() {
 472              this.fire(EV_TICK_ALIGN_X);
 473          },
 474          /**
 475          * Fires when the actXY[1] reach a new value respecting the tickY gap.
 476          * @private
 477          * @method _tickAlignY
 478          */
 479          _tickAlignY: function() {
 480              this.fire(EV_TICK_ALIGN_Y);
 481          }
 482      };
 483  
 484      Y.namespace('Plugin');
 485      Y.extend(C, Y.Base, proto);
 486      Y.Plugin.DDConstrained = C;
 487  
 488      Y.mix(DDM, {
 489          /**
 490          * Helper method to calculate the tick offsets for a given position
 491          * @for DDM
 492          * @namespace DD
 493          * @private
 494          * @method _calcTicks
 495          * @param {Number} pos The current X or Y position
 496          * @param {Number} start The start X or Y position
 497          * @param {Number} tick The X or Y tick increment
 498          * @param {Number} off1 The min offset that we can't pass (region)
 499          * @param {Number} off2 The max offset that we can't pass (region)
 500          * @return {Number} The new position based on the tick calculation
 501          */
 502          _calcTicks: function(pos, start, tick, off1, off2) {
 503              var ix = ((pos - start) / tick),
 504                  min = Math.floor(ix),
 505                  max = Math.ceil(ix);
 506                  if ((min !== 0) || (max !== 0)) {
 507                      if ((ix >= min) && (ix <= max)) {
 508                          pos = (start + (tick * min));
 509                          if (off1 && off2) {
 510                              if (pos < off1) {
 511                                  pos = (start + (tick * (min + 1)));
 512                              }
 513                              if (pos > off2) {
 514                                  pos = (start + (tick * (min - 1)));
 515                              }
 516                          }
 517                      }
 518                  }
 519                  return pos;
 520          },
 521          /**
 522          * This method is used with the tickXArray and tickYArray config options
 523          * @for DDM
 524          * @namespace DD
 525          * @private
 526          * @method _calcTickArray
 527          * @param {Number} pos The current X or Y position
 528          * @param {Number} ticks The array containing our custom tick positions.
 529          * @param {Number} off1 The min offset that we can't pass (region)
 530          * @param {Number} off2 The max offset that we can't pass (region)
 531          * @return The tick position
 532          */
 533          _calcTickArray: function(pos, ticks, off1, off2) {
 534              var i = 0, len = ticks.length, next = 0,
 535                  diff1, diff2, ret;
 536  
 537              if (!ticks || (ticks.length === 0)) {
 538                  return pos;
 539              }
 540              if (ticks[0] >= pos) {
 541                  return ticks[0];
 542              }
 543  
 544              for (i = 0; i < len; i++) {
 545                  next = (i + 1);
 546                  if (ticks[next] && ticks[next] >= pos) {
 547                      diff1 = pos - ticks[i];
 548                      diff2 = ticks[next] - pos;
 549                      ret = (diff2 > diff1) ? ticks[i] : ticks[next];
 550                      if (off1 && off2) {
 551                          if (ret > off2) {
 552                              if (ticks[i]) {
 553                                  ret = ticks[i];
 554                              } else {
 555                                  ret = ticks[len - 1];
 556                              }
 557                          }
 558                      }
 559                      return ret;
 560                  }
 561  
 562              }
 563              return ticks[ticks.length - 1];
 564          }
 565      });
 566  
 567  
 568  
 569  }, '3.17.2', {"requires": ["dd-drag"]});


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