src/cm/media/js/lib/yui/yui_3.10.3/build/event-focus/event-focus.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 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                             break;
       
   228                         }
       
   229                     }
       
   230                 }
       
   231 
       
   232                 if (e.stopped) {
       
   233                     break;
       
   234                 }
       
   235             }
       
   236         },
       
   237 
       
   238         on: function (node, sub, notifier) {
       
   239             sub.handle = this._attach(node._node, notifier);
       
   240         },
       
   241 
       
   242         detach: function (node, sub) {
       
   243             sub.handle.detach();
       
   244         },
       
   245 
       
   246         delegate: function (node, sub, notifier, filter) {
       
   247             if (isString(filter)) {
       
   248                 sub.filter = function (target) {
       
   249                     return Y.Selector.test(target._node, filter,
       
   250                         node === target ? null : node._node);
       
   251                 };
       
   252             }
       
   253 
       
   254             sub.handle = this._attach(node._node, notifier, true);
       
   255         },
       
   256 
       
   257         detachDelegate: function (node, sub) {
       
   258             sub.handle.detach();
       
   259         }
       
   260     }, true);
       
   261 }
       
   262 
       
   263 // For IE, we need to defer to focusin rather than focus because
       
   264 // `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate,
       
   265 // el.onfocusin, doSomething, then el.onfocus.  All others support capture
       
   266 // phase focus, which executes before doSomething.  To guarantee consistent
       
   267 // behavior for this use case, IE's direct subscriptions are made against
       
   268 // focusin so subscribers will be notified before js following el.focus() is
       
   269 // executed.
       
   270 if (useActivate) {
       
   271     //     name     capture phase       direct subscription
       
   272     define("focus", "beforeactivate",   "focusin");
       
   273     define("blur",  "beforedeactivate", "focusout");
       
   274 } else {
       
   275     define("focus", "focus", "focus");
       
   276     define("blur",  "blur",  "blur");
       
   277 }
       
   278 
       
   279 
       
   280 }, '3.10.3', {"requires": ["event-synthetic"]});