[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/event-move/ -> event-move.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('event-move', function (Y, NAME) {
   9  
  10  /**
  11   * Adds lower level support for "gesturemovestart", "gesturemove" and "gesturemoveend" events, which can be used to create drag/drop
  12   * interactions which work across touch and mouse input devices. They correspond to "touchstart", "touchmove" and "touchend" on a touch input
  13   * device, and "mousedown", "mousemove", "mouseup" on a mouse based input device.
  14   *
  15   * <p>Documentation for the gesturemove triplet of events can be found on the <a href="../classes/YUI.html#event_gesturemove">YUI</a> global,
  16   * along with the other supported events.</p>
  17  
  18   @example
  19  
  20       YUI().use('event-move', function (Y) {
  21           Y.one('#myNode').on('gesturemovestart', function (e) {
  22           });
  23           Y.one('#myNode').on('gesturemove', function (e) {
  24           });
  25           Y.one('#myNode').on('gesturemoveend', function (e) {
  26           });
  27       });
  28  
  29   * @module event-gestures
  30   * @submodule event-move
  31   */
  32  
  33  
  34   var GESTURE_MAP = Y.Event._GESTURE_MAP,
  35       EVENT = {
  36           start: GESTURE_MAP.start,
  37           end: GESTURE_MAP.end,
  38           move: GESTURE_MAP.move
  39       },
  40      START = "start",
  41      MOVE = "move",
  42      END = "end",
  43  
  44      GESTURE_MOVE = "gesture" + MOVE,
  45      GESTURE_MOVE_END = GESTURE_MOVE + END,
  46      GESTURE_MOVE_START = GESTURE_MOVE + START,
  47  
  48      _MOVE_START_HANDLE = "_msh",
  49      _MOVE_HANDLE = "_mh",
  50      _MOVE_END_HANDLE = "_meh",
  51  
  52      _DEL_MOVE_START_HANDLE = "_dmsh",
  53      _DEL_MOVE_HANDLE = "_dmh",
  54      _DEL_MOVE_END_HANDLE = "_dmeh",
  55  
  56      _MOVE_START = "_ms",
  57      _MOVE = "_m",
  58  
  59      MIN_TIME = "minTime",
  60      MIN_DISTANCE = "minDistance",
  61      PREVENT_DEFAULT = "preventDefault",
  62      BUTTON = "button",
  63      OWNER_DOCUMENT = "ownerDocument",
  64  
  65      CURRENT_TARGET = "currentTarget",
  66      TARGET = "target",
  67  
  68      NODE_TYPE = "nodeType",
  69      SUPPORTS_POINTER = Y.config.win && ("msPointerEnabled" in Y.config.win.navigator),
  70      MS_TOUCH_ACTION_COUNT = 'msTouchActionCount',
  71      MS_INIT_TOUCH_ACTION = 'msInitTouchAction',
  72  
  73      _defArgsProcessor = function(se, args, delegate) {
  74          var iConfig = (delegate) ? 4 : 3,
  75              config = (args.length > iConfig) ? Y.merge(args.splice(iConfig,1)[0]) : {};
  76  
  77          if (!(PREVENT_DEFAULT in config)) {
  78              config[PREVENT_DEFAULT] = se.PREVENT_DEFAULT;
  79          }
  80  
  81          return config;
  82      },
  83  
  84      _getRoot = function(node, subscriber) {
  85          return subscriber._extra.root || (node.get(NODE_TYPE) === 9) ? node : node.get(OWNER_DOCUMENT);
  86      },
  87  
  88      //Checks to see if the node is the document, and if it is, returns the documentElement.
  89      _checkDocumentElem = function(node) {
  90          var elem = node.getDOMNode();
  91          if (node.compareTo(Y.config.doc) && elem.documentElement) {
  92              return elem.documentElement;
  93          }
  94          else {
  95              return false;
  96          }
  97      },
  98  
  99      _normTouchFacade = function(touchFacade, touch, params) {
 100          touchFacade.pageX = touch.pageX;
 101          touchFacade.pageY = touch.pageY;
 102          touchFacade.screenX = touch.screenX;
 103          touchFacade.screenY = touch.screenY;
 104          touchFacade.clientX = touch.clientX;
 105          touchFacade.clientY = touch.clientY;
 106          touchFacade[TARGET] = touchFacade[TARGET] || touch[TARGET];
 107          touchFacade[CURRENT_TARGET] = touchFacade[CURRENT_TARGET] || touch[CURRENT_TARGET];
 108  
 109          touchFacade[BUTTON] = (params && params[BUTTON]) || 1; // default to left (left as per vendors, not W3C which is 0)
 110      },
 111  
 112      /*
 113      In IE10 touch mode, gestures will not work properly unless the -ms-touch-action CSS property is set to something other than 'auto'. Read http://msdn.microsoft.com/en-us/library/windows/apps/hh767313.aspx for more info. To get around this, we set -ms-touch-action: none which is the same as e.preventDefault() on touch environments. This tells the browser to fire DOM events for all touch events, and not perform any default behavior.
 114  
 115      The user can over-ride this by setting a more lenient -ms-touch-action property on a node (such as pan-x, pan-y, etc.) via CSS when subscribing to the 'gesturemovestart' event.
 116      */
 117      _setTouchActions = function (node) {
 118          var elem = _checkDocumentElem(node) || node.getDOMNode(),
 119              num = node.getData(MS_TOUCH_ACTION_COUNT);
 120  
 121          //Checks to see if msTouchAction is supported.
 122          if (SUPPORTS_POINTER) {
 123              if (!num) {
 124                  num = 0;
 125                  node.setData(MS_INIT_TOUCH_ACTION, elem.style.msTouchAction);
 126              }
 127              elem.style.msTouchAction = Y.Event._DEFAULT_TOUCH_ACTION;
 128              num++;
 129              node.setData(MS_TOUCH_ACTION_COUNT, num);
 130          }
 131      },
 132  
 133      /*
 134      Resets the element's -ms-touch-action property back to the original value, This is called on detach() and detachDelegate().
 135      */
 136      _unsetTouchActions = function (node) {
 137          var elem = _checkDocumentElem(node) || node.getDOMNode(),
 138              num = node.getData(MS_TOUCH_ACTION_COUNT),
 139              initTouchAction = node.getData(MS_INIT_TOUCH_ACTION);
 140  
 141          if (SUPPORTS_POINTER) {
 142              num--;
 143              node.setData(MS_TOUCH_ACTION_COUNT, num);
 144              if (num === 0 && elem.style.msTouchAction !== initTouchAction) {
 145                  elem.style.msTouchAction = initTouchAction;
 146              }
 147          }
 148      },
 149  
 150      _prevent = function(e, preventDefault) {
 151          if (preventDefault) {
 152              // preventDefault is a boolean or a function
 153              if (!preventDefault.call || preventDefault(e)) {
 154                  e.preventDefault();
 155              }
 156          }
 157      },
 158  
 159      define = Y.Event.define;
 160      Y.Event._DEFAULT_TOUCH_ACTION = 'none';
 161  
 162  /**
 163   * Sets up a "gesturemovestart" event, that is fired on touch devices in response to a single finger "touchstart",
 164   * and on mouse based devices in response to a "mousedown". The subscriber can specify the minimum time
 165   * and distance thresholds which should be crossed before the "gesturemovestart" is fired and for the mouse,
 166   * which button should initiate a "gesturemovestart". This event can also be listened for using node.delegate().
 167   *
 168   * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
 169   * however if you want to pass the context and arguments as additional signature arguments to on/delegate,
 170   * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemovestart", fn, null, context, arg1, arg2, arg3)</code></p>
 171   *
 172   * @event gesturemovestart
 173   * @for YUI
 174   * @param type {string} "gesturemovestart"
 175   * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mousedown or touchstart.touches[0]) which contains position co-ordinates.
 176   * @param cfg {Object} Optional. An object which specifies:
 177   *
 178   * <dl>
 179   * <dt>minDistance (defaults to 0)</dt>
 180   * <dd>The minimum distance threshold which should be crossed before the gesturemovestart is fired</dd>
 181   * <dt>minTime (defaults to 0)</dt>
 182   * <dd>The minimum time threshold for which the finger/mouse should be help down before the gesturemovestart is fired</dd>
 183   * <dt>button (no default)</dt>
 184   * <dd>In the case of a mouse input device, if the event should only be fired for a specific mouse button.</dd>
 185   * <dt>preventDefault (defaults to false)</dt>
 186   * <dd>Can be set to true/false to prevent default behavior as soon as the touchstart or mousedown is received (that is before minTime or minDistance thresholds are crossed, and so before the gesturemovestart listener is notified) so that things like text selection and context popups (on touch devices) can be
 187   * prevented. This property can also be set to a function, which returns true or false, based on the event facade passed to it (for example, DragDrop can determine if the target is a valid handle or not before preventing default).</dd>
 188   * </dl>
 189   *
 190   * @return {EventHandle} the detach handle
 191   */
 192  
 193  define(GESTURE_MOVE_START, {
 194  
 195      on: function (node, subscriber, ce) {
 196  
 197          //Set -ms-touch-action on IE10 and set preventDefault to true
 198          _setTouchActions(node);
 199  
 200          subscriber[_MOVE_START_HANDLE] = node.on(EVENT[START],
 201              this._onStart,
 202              this,
 203              node,
 204              subscriber,
 205              ce);
 206      },
 207  
 208      delegate : function(node, subscriber, ce, filter) {
 209  
 210          var se = this;
 211  
 212          subscriber[_DEL_MOVE_START_HANDLE] = node.delegate(EVENT[START],
 213              function(e) {
 214                  se._onStart(e, node, subscriber, ce, true);
 215              },
 216              filter);
 217      },
 218  
 219      detachDelegate : function(node, subscriber, ce, filter) {
 220          var handle = subscriber[_DEL_MOVE_START_HANDLE];
 221  
 222          if (handle) {
 223              handle.detach();
 224              subscriber[_DEL_MOVE_START_HANDLE] = null;
 225          }
 226  
 227          _unsetTouchActions(node);
 228      },
 229  
 230      detach: function (node, subscriber, ce) {
 231          var startHandle = subscriber[_MOVE_START_HANDLE];
 232  
 233          if (startHandle) {
 234              startHandle.detach();
 235              subscriber[_MOVE_START_HANDLE] = null;
 236          }
 237  
 238          _unsetTouchActions(node);
 239      },
 240  
 241      processArgs : function(args, delegate) {
 242          var params = _defArgsProcessor(this, args, delegate);
 243  
 244          if (!(MIN_TIME in params)) {
 245              params[MIN_TIME] = this.MIN_TIME;
 246          }
 247  
 248          if (!(MIN_DISTANCE in params)) {
 249              params[MIN_DISTANCE] = this.MIN_DISTANCE;
 250          }
 251  
 252          return params;
 253      },
 254  
 255      _onStart : function(e, node, subscriber, ce, delegate) {
 256  
 257          if (delegate) {
 258              node = e[CURRENT_TARGET];
 259          }
 260  
 261          var params = subscriber._extra,
 262              fireStart = true,
 263              minTime = params[MIN_TIME],
 264              minDistance = params[MIN_DISTANCE],
 265              button = params.button,
 266              preventDefault = params[PREVENT_DEFAULT],
 267              root = _getRoot(node, subscriber),
 268              startXY;
 269  
 270          if (e.touches) {
 271              if (e.touches.length === 1) {
 272                  _normTouchFacade(e, e.touches[0], params);
 273              } else {
 274                  fireStart = false;
 275              }
 276          } else {
 277              fireStart = (button === undefined) || (button === e.button);
 278          }
 279  
 280  
 281          if (fireStart) {
 282  
 283              _prevent(e, preventDefault);
 284  
 285              if (minTime === 0 || minDistance === 0) {
 286                  this._start(e, node, ce, params);
 287  
 288              } else {
 289  
 290                  startXY = [e.pageX, e.pageY];
 291  
 292                  if (minTime > 0) {
 293  
 294  
 295                      params._ht = Y.later(minTime, this, this._start, [e, node, ce, params]);
 296  
 297                      params._hme = root.on(EVENT[END], Y.bind(function() {
 298                          this._cancel(params);
 299                      }, this));
 300                  }
 301  
 302                  if (minDistance > 0) {
 303  
 304  
 305                      params._hm = root.on(EVENT[MOVE], Y.bind(function(em) {
 306                          if (Math.abs(em.pageX - startXY[0]) > minDistance || Math.abs(em.pageY - startXY[1]) > minDistance) {
 307                              this._start(e, node, ce, params);
 308                          }
 309                      }, this));
 310                  }
 311              }
 312          }
 313      },
 314  
 315      _cancel : function(params) {
 316          if (params._ht) {
 317              params._ht.cancel();
 318              params._ht = null;
 319          }
 320          if (params._hme) {
 321              params._hme.detach();
 322              params._hme = null;
 323          }
 324          if (params._hm) {
 325              params._hm.detach();
 326              params._hm = null;
 327          }
 328      },
 329  
 330      _start : function(e, node, ce, params) {
 331  
 332          if (params) {
 333              this._cancel(params);
 334          }
 335  
 336          e.type = GESTURE_MOVE_START;
 337  
 338  
 339          node.setData(_MOVE_START, e);
 340          ce.fire(e);
 341      },
 342  
 343      MIN_TIME : 0,
 344      MIN_DISTANCE : 0,
 345      PREVENT_DEFAULT : false
 346  });
 347  
 348  /**
 349   * Sets up a "gesturemove" event, that is fired on touch devices in response to a single finger "touchmove",
 350   * and on mouse based devices in response to a "mousemove".
 351   *
 352   * <p>By default this event is only fired when the same node
 353   * has received a "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties,
 354   * if they want to listen for this event without an initial "gesturemovestart".</p>
 355   *
 356   * <p>By default this event sets up it's internal "touchmove" and "mousemove" DOM listeners on the document element. The subscriber
 357   * can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p>
 358   *
 359   * <p>This event can also be listened for using node.delegate().</p>
 360   *
 361   * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
 362   * however if you want to pass the context and arguments as additional signature arguments to on/delegate,
 363   * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemove", fn, null, context, arg1, arg2, arg3)</code></p>
 364   *
 365   * @event gesturemove
 366   * @for YUI
 367   * @param type {string} "gesturemove"
 368   * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mousemove or touchmove.touches[0]) which contains position co-ordinates.
 369   * @param cfg {Object} Optional. An object which specifies:
 370   * <dl>
 371   * <dt>standAlone (defaults to false)</dt>
 372   * <dd>true, if the subscriber should be notified even if a "gesturemovestart" has not occured on the same node.</dd>
 373   * <dt>root (defaults to document)</dt>
 374   * <dd>The node to which the internal DOM listeners should be attached.</dd>
 375   * <dt>preventDefault (defaults to false)</dt>
 376   * <dd>Can be set to true/false to prevent default behavior as soon as the touchmove or mousemove is received. As with gesturemovestart, can also be set to function which returns true/false based on the event facade passed to it.</dd>
 377   * </dl>
 378   *
 379   * @return {EventHandle} the detach handle
 380   */
 381  define(GESTURE_MOVE, {
 382  
 383      on : function (node, subscriber, ce) {
 384  
 385          _setTouchActions(node);
 386          var root = _getRoot(node, subscriber, EVENT[MOVE]),
 387  
 388              moveHandle = root.on(EVENT[MOVE],
 389                  this._onMove,
 390                  this,
 391                  node,
 392                  subscriber,
 393                  ce);
 394  
 395          subscriber[_MOVE_HANDLE] = moveHandle;
 396  
 397      },
 398  
 399      delegate : function(node, subscriber, ce, filter) {
 400  
 401          var se = this;
 402  
 403          subscriber[_DEL_MOVE_HANDLE] = node.delegate(EVENT[MOVE],
 404              function(e) {
 405                  se._onMove(e, node, subscriber, ce, true);
 406              },
 407              filter);
 408      },
 409  
 410      detach : function (node, subscriber, ce) {
 411          var moveHandle = subscriber[_MOVE_HANDLE];
 412  
 413          if (moveHandle) {
 414              moveHandle.detach();
 415              subscriber[_MOVE_HANDLE] = null;
 416          }
 417  
 418          _unsetTouchActions(node);
 419      },
 420  
 421      detachDelegate : function(node, subscriber, ce, filter) {
 422          var handle = subscriber[_DEL_MOVE_HANDLE];
 423  
 424          if (handle) {
 425              handle.detach();
 426              subscriber[_DEL_MOVE_HANDLE] = null;
 427          }
 428  
 429          _unsetTouchActions(node);
 430  
 431      },
 432  
 433      processArgs : function(args, delegate) {
 434          return _defArgsProcessor(this, args, delegate);
 435      },
 436  
 437      _onMove : function(e, node, subscriber, ce, delegate) {
 438  
 439          if (delegate) {
 440              node = e[CURRENT_TARGET];
 441          }
 442  
 443          var fireMove = subscriber._extra.standAlone || node.getData(_MOVE_START),
 444              preventDefault = subscriber._extra.preventDefault;
 445  
 446  
 447          if (fireMove) {
 448  
 449              if (e.touches) {
 450                  if (e.touches.length === 1) {
 451                      _normTouchFacade(e, e.touches[0]);
 452                  } else {
 453                      fireMove = false;
 454                  }
 455              }
 456  
 457              if (fireMove) {
 458  
 459                  _prevent(e, preventDefault);
 460  
 461  
 462                  e.type = GESTURE_MOVE;
 463                  ce.fire(e);
 464              }
 465          }
 466      },
 467  
 468      PREVENT_DEFAULT : false
 469  });
 470  
 471  /**
 472   * Sets up a "gesturemoveend" event, that is fired on touch devices in response to a single finger "touchend",
 473   * and on mouse based devices in response to a "mouseup".
 474   *
 475   * <p>By default this event is only fired when the same node
 476   * has received a "gesturemove" or "gesturemovestart" event. The subscriber can set standAlone to true, in the configuration properties,
 477   * if they want to listen for this event without a preceding "gesturemovestart" or "gesturemove".</p>
 478   *
 479   * <p>By default this event sets up it's internal "touchend" and "mouseup" DOM listeners on the document element. The subscriber
 480   * can set the root configuration property, to specify which node to attach DOM listeners to, if different from the document.</p>
 481   *
 482   * <p>This event can also be listened for using node.delegate().</p>
 483   *
 484   * <p>It is recommended that you use Y.bind to set up context and additional arguments for your event handler,
 485   * however if you want to pass the context and arguments as additional signature arguments to on/delegate,
 486   * you need to provide a null value for the configuration object, e.g: <code>node.on("gesturemoveend", fn, null, context, arg1, arg2, arg3)</code></p>
 487   *
 488   *
 489   * @event gesturemoveend
 490   * @for YUI
 491   * @param type {string} "gesturemoveend"
 492   * @param fn {function} The method the event invokes. It receives the event facade of the underlying DOM event (mouseup or touchend.changedTouches[0]).
 493   * @param cfg {Object} Optional. An object which specifies:
 494   * <dl>
 495   * <dt>standAlone (defaults to false)</dt>
 496   * <dd>true, if the subscriber should be notified even if a "gesturemovestart" or "gesturemove" has not occured on the same node.</dd>
 497   * <dt>root (defaults to document)</dt>
 498   * <dd>The node to which the internal DOM listeners should be attached.</dd>
 499   * <dt>preventDefault (defaults to false)</dt>
 500   * <dd>Can be set to true/false to prevent default behavior as soon as the touchend or mouseup is received. As with gesturemovestart, can also be set to function which returns true/false based on the event facade passed to it.</dd>
 501   * </dl>
 502   *
 503   * @return {EventHandle} the detach handle
 504   */
 505  define(GESTURE_MOVE_END, {
 506  
 507      on : function (node, subscriber, ce) {
 508          _setTouchActions(node);
 509          var root = _getRoot(node, subscriber),
 510  
 511              endHandle = root.on(EVENT[END],
 512                  this._onEnd,
 513                  this,
 514                  node,
 515                  subscriber,
 516                  ce);
 517  
 518          subscriber[_MOVE_END_HANDLE] = endHandle;
 519      },
 520  
 521      delegate : function(node, subscriber, ce, filter) {
 522  
 523          var se = this;
 524  
 525          subscriber[_DEL_MOVE_END_HANDLE] = node.delegate(EVENT[END],
 526              function(e) {
 527                  se._onEnd(e, node, subscriber, ce, true);
 528              },
 529              filter);
 530      },
 531  
 532      detachDelegate : function(node, subscriber, ce, filter) {
 533          var handle = subscriber[_DEL_MOVE_END_HANDLE];
 534  
 535          if (handle) {
 536              handle.detach();
 537              subscriber[_DEL_MOVE_END_HANDLE] = null;
 538          }
 539  
 540          _unsetTouchActions(node);
 541  
 542      },
 543  
 544      detach : function (node, subscriber, ce) {
 545          var endHandle = subscriber[_MOVE_END_HANDLE];
 546  
 547          if (endHandle) {
 548              endHandle.detach();
 549              subscriber[_MOVE_END_HANDLE] = null;
 550          }
 551  
 552          _unsetTouchActions(node);
 553      },
 554  
 555      processArgs : function(args, delegate) {
 556          return _defArgsProcessor(this, args, delegate);
 557      },
 558  
 559      _onEnd : function(e, node, subscriber, ce, delegate) {
 560  
 561          if (delegate) {
 562              node = e[CURRENT_TARGET];
 563          }
 564  
 565          var fireMoveEnd = subscriber._extra.standAlone || node.getData(_MOVE) || node.getData(_MOVE_START),
 566              preventDefault = subscriber._extra.preventDefault;
 567  
 568          if (fireMoveEnd) {
 569  
 570              if (e.changedTouches) {
 571                  if (e.changedTouches.length === 1) {
 572                      _normTouchFacade(e, e.changedTouches[0]);
 573                  } else {
 574                      fireMoveEnd = false;
 575                  }
 576              }
 577  
 578              if (fireMoveEnd) {
 579  
 580                  _prevent(e, preventDefault);
 581  
 582                  e.type = GESTURE_MOVE_END;
 583                  ce.fire(e);
 584  
 585                  node.clearData(_MOVE_START);
 586                  node.clearData(_MOVE);
 587              }
 588          }
 589      },
 590  
 591      PREVENT_DEFAULT : false
 592  });
 593  
 594  
 595  }, '3.17.2', {"requires": ["node-base", "event-touch", "event-synthetic"]});


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