[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/event-focus/ -> event-focus.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-focus', function (Y, NAME) {
   9  
  10  /**
  11   * Adds bubbling and delegation support to DOM events focus and blur.
  12   *
  13   * @module event
  14   * @submodule event-focus
  15   */
  16  var Event    = Y.Event,
  17  
  18      YLang    = Y.Lang,
  19  
  20      isString = YLang.isString,
  21  
  22      arrayIndex = Y.Array.indexOf,
  23  
  24      useActivate = (function() {
  25  
  26          // Changing the structure of this test, so that it doesn't use inline JS in HTML,
  27          // which throws an exception in Win8 packaged apps, due to additional security restrictions:
  28          // http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences
  29  
  30          var supported = false,
  31              doc = Y.config.doc,
  32              p;
  33  
  34          if (doc) {
  35  
  36              p = doc.createElement("p");
  37              p.setAttribute("onbeforeactivate", ";");
  38  
  39              // onbeforeactivate is a function in IE8+.
  40              // onbeforeactivate is a string in IE6,7 (unfortunate, otherwise we could have just checked for function below).
  41              // onbeforeactivate is a function in IE10, in a Win8 App environment (no exception running the test).
  42  
  43              // onbeforeactivate is undefined in Webkit/Gecko.
  44              // onbeforeactivate is a function in Webkit/Gecko if it's a supported event (e.g. onclick).
  45  
  46              supported = (p.onbeforeactivate !== undefined);
  47          }
  48  
  49          return supported;
  50      }());
  51  
  52  function define(type, proxy, directEvent) {
  53      var nodeDataKey = '_' + type + 'Notifiers';
  54  
  55      Y.Event.define(type, {
  56  
  57          _useActivate : useActivate,
  58  
  59          _attach: function (el, notifier, delegate) {
  60              if (Y.DOM.isWindow(el)) {
  61                  return Event._attach([type, function (e) {
  62                      notifier.fire(e);
  63                  }, el]);
  64              } else {
  65                  return Event._attach(
  66                      [proxy, this._proxy, el, this, notifier, delegate],
  67                      { capture: true });
  68              }
  69          },
  70  
  71          _proxy: function (e, notifier, delegate) {
  72              var target        = e.target,
  73                  currentTarget = e.currentTarget,
  74                  notifiers     = target.getData(nodeDataKey),
  75                  yuid          = Y.stamp(currentTarget._node),
  76                  defer         = (useActivate || target !== currentTarget),
  77                  directSub;
  78  
  79              notifier.currentTarget = (delegate) ? target : currentTarget;
  80              notifier.container     = (delegate) ? currentTarget : null;
  81  
  82              // Maintain a list to handle subscriptions from nested
  83              // containers div#a>div#b>input #a.on(focus..) #b.on(focus..),
  84              // use one focus or blur subscription that fires notifiers from
  85              // #b then #a to emulate bubble sequence.
  86              if (!notifiers) {
  87                  notifiers = {};
  88                  target.setData(nodeDataKey, notifiers);
  89  
  90                  // only subscribe to the element's focus if the target is
  91                  // not the current target (
  92                  if (defer) {
  93                      directSub = Event._attach(
  94                          [directEvent, this._notify, target._node]).sub;
  95                      directSub.once = true;
  96                  }
  97              } else {
  98                  // In old IE, defer is always true.  In capture-phase browsers,
  99                  // The delegate subscriptions will be encountered first, which
 100                  // will establish the notifiers data and direct subscription
 101                  // on the node.  If there is also a direct subscription to the
 102                  // node's focus/blur, it should not call _notify because the
 103                  // direct subscription from the delegate sub(s) exists, which
 104                  // will call _notify.  So this avoids _notify being called
 105                  // twice, unnecessarily.
 106                  defer = true;
 107              }
 108  
 109              if (!notifiers[yuid]) {
 110                  notifiers[yuid] = [];
 111              }
 112  
 113              notifiers[yuid].push(notifier);
 114  
 115              if (!defer) {
 116                  this._notify(e);
 117              }
 118          },
 119  
 120          _notify: function (e, container) {
 121              var currentTarget = e.currentTarget,
 122                  notifierData  = currentTarget.getData(nodeDataKey),
 123                  axisNodes     = currentTarget.ancestors(),
 124                  doc           = currentTarget.get('ownerDocument'),
 125                  delegates     = [],
 126                                  // Used to escape loops when there are no more
 127                                  // notifiers to consider
 128                  count         = notifierData ?
 129                                      Y.Object.keys(notifierData).length :
 130                                      0,
 131                  target, notifiers, notifier, yuid, match, tmp, i, len, sub, ret;
 132  
 133              // clear the notifications list (mainly for delegation)
 134              currentTarget.clearData(nodeDataKey);
 135  
 136              // Order the delegate subs by their placement in the parent axis
 137              axisNodes.push(currentTarget);
 138              // document.get('ownerDocument') returns null
 139              // which we'll use to prevent having duplicate Nodes in the list
 140              if (doc) {
 141                  axisNodes.unshift(doc);
 142              }
 143  
 144              // ancestors() returns the Nodes from top to bottom
 145              axisNodes._nodes.reverse();
 146  
 147              if (count) {
 148                  // Store the count for step 2
 149                  tmp = count;
 150                  axisNodes.some(function (node) {
 151                      var yuid      = Y.stamp(node),
 152                          notifiers = notifierData[yuid],
 153                          i, len;
 154  
 155                      if (notifiers) {
 156                          count--;
 157                          for (i = 0, len = notifiers.length; i < len; ++i) {
 158                              if (notifiers[i].handle.sub.filter) {
 159                                  delegates.push(notifiers[i]);
 160                              }
 161                          }
 162                      }
 163  
 164                      return !count;
 165                  });
 166                  count = tmp;
 167              }
 168  
 169              // Walk up the parent axis, notifying direct subscriptions and
 170              // testing delegate filters.
 171              while (count && (target = axisNodes.shift())) {
 172                  yuid = Y.stamp(target);
 173  
 174                  notifiers = notifierData[yuid];
 175  
 176                  if (notifiers) {
 177                      for (i = 0, len = notifiers.length; i < len; ++i) {
 178                          notifier = notifiers[i];
 179                          sub      = notifier.handle.sub;
 180                          match    = true;
 181  
 182                          e.currentTarget = target;
 183  
 184                          if (sub.filter) {
 185                              match = sub.filter.apply(target,
 186                                  [target, e].concat(sub.args || []));
 187  
 188                              // No longer necessary to test against this
 189                              // delegate subscription for the nodes along
 190                              // the parent axis.
 191                              delegates.splice(
 192                                  arrayIndex(delegates, notifier), 1);
 193                          }
 194  
 195                          if (match) {
 196                              // undefined for direct subs
 197                              e.container = notifier.container;
 198                              ret = notifier.fire(e);
 199                          }
 200  
 201                          if (ret === false || e.stopped === 2) {
 202                              break;
 203                          }
 204                      }
 205  
 206                      delete notifiers[yuid];
 207                      count--;
 208                  }
 209  
 210                  if (e.stopped !== 2) {
 211                      // delegates come after subs targeting this specific node
 212                      // because they would not normally report until they'd
 213                      // bubbled to the container node.
 214                      for (i = 0, len = delegates.length; i < len; ++i) {
 215                          notifier = delegates[i];
 216                          sub = notifier.handle.sub;
 217  
 218                          if (sub.filter.apply(target,
 219                              [target, e].concat(sub.args || []))) {
 220  
 221                              e.container = notifier.container;
 222                              e.currentTarget = target;
 223                              ret = notifier.fire(e);
 224                          }
 225  
 226                          if (ret === false || e.stopped === 2 ||
 227                              // If e.stopPropagation() is called, notify any
 228                              // delegate subs from the same container, but break
 229                              // once the container changes. This emulates
 230                              // delegate() behavior for events like 'click' which
 231                              // won't notify delegates higher up the parent axis.
 232                              (e.stopped && delegates[i+1] &&
 233                               delegates[i+1].container !== notifier.container)) {
 234                              break;
 235                          }
 236                      }
 237                  }
 238  
 239                  if (e.stopped) {
 240                      break;
 241                  }
 242              }
 243          },
 244  
 245          on: function (node, sub, notifier) {
 246              sub.handle = this._attach(node._node, notifier);
 247          },
 248  
 249          detach: function (node, sub) {
 250              sub.handle.detach();
 251          },
 252  
 253          delegate: function (node, sub, notifier, filter) {
 254              if (isString(filter)) {
 255                  sub.filter = function (target) {
 256                      return Y.Selector.test(target._node, filter,
 257                          node === target ? null : node._node);
 258                  };
 259              }
 260  
 261              sub.handle = this._attach(node._node, notifier, true);
 262          },
 263  
 264          detachDelegate: function (node, sub) {
 265              sub.handle.detach();
 266          }
 267      }, true);
 268  }
 269  
 270  // For IE, we need to defer to focusin rather than focus because
 271  // `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
 272  // el.onfocusin, doSomething, then el.onfocus.  All others support capture
 273  // phase focus, which executes before doSomething.  To guarantee consistent
 274  // behavior for this use case, IE's direct subscriptions are made against
 275  // focusin so subscribers will be notified before js following el.focus() is
 276  // executed.
 277  if (useActivate) {
 278      //     name     capture phase       direct subscription
 279      define("focus", "beforeactivate",   "focusin");
 280      define("blur",  "beforedeactivate", "focusout");
 281  } else {
 282      define("focus", "focus", "focus");
 283      define("blur",  "blur",  "blur");
 284  }
 285  
 286  
 287  }, '3.17.2', {"requires": ["event-synthetic"]});


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