src/cm/media/js/lib/yui/yui_3.10.3/build/event-valuechange/event-valuechange-debug.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-valuechange', function (Y, NAME) {
       
     9 
       
    10 /**
       
    11 Adds a synthetic `valuechange` event that fires when the `value` property of an
       
    12 `<input>` or `<textarea>` node changes as a result of a keystroke, mouse
       
    13 operation, or input method editor (IME) input event.
       
    14 
       
    15 Usage:
       
    16 
       
    17     YUI().use('event-valuechange', function (Y) {
       
    18         Y.one('#my-input').on('valuechange', function (e) {
       
    19             Y.log('previous value: ' + e.prevVal);
       
    20             Y.log('new value: ' + e.newVal);
       
    21         });
       
    22     });
       
    23 
       
    24 @module event-valuechange
       
    25 **/
       
    26 
       
    27 /**
       
    28 Provides the implementation for the synthetic `valuechange` event. This class
       
    29 isn't meant to be used directly, but is public to make monkeypatching possible.
       
    30 
       
    31 Usage:
       
    32 
       
    33     YUI().use('event-valuechange', function (Y) {
       
    34         Y.one('#my-input').on('valuechange', function (e) {
       
    35             Y.log('previous value: ' + e.prevVal);
       
    36             Y.log('new value: ' + e.newVal);
       
    37         });
       
    38     });
       
    39 
       
    40 @class ValueChange
       
    41 @static
       
    42 */
       
    43 
       
    44 var DATA_KEY = '_valuechange',
       
    45     VALUE    = 'value',
       
    46 
       
    47     config, // defined at the end of this file
       
    48 
       
    49 // Just a simple namespace to make methods overridable.
       
    50 VC = {
       
    51     // -- Static Constants -----------------------------------------------------
       
    52 
       
    53     /**
       
    54     Interval (in milliseconds) at which to poll for changes to the value of an
       
    55     element with one or more `valuechange` subscribers when the user is likely
       
    56     to be interacting with it.
       
    57 
       
    58     @property POLL_INTERVAL
       
    59     @type Number
       
    60     @default 50
       
    61     @static
       
    62     **/
       
    63     POLL_INTERVAL: 50,
       
    64 
       
    65     /**
       
    66     Timeout (in milliseconds) after which to stop polling when there hasn't been
       
    67     any new activity (keypresses, mouse clicks, etc.) on an element.
       
    68 
       
    69     @property TIMEOUT
       
    70     @type Number
       
    71     @default 10000
       
    72     @static
       
    73     **/
       
    74     TIMEOUT: 10000,
       
    75 
       
    76     // -- Protected Static Methods ---------------------------------------------
       
    77 
       
    78     /**
       
    79     Called at an interval to poll for changes to the value of the specified
       
    80     node.
       
    81 
       
    82     @method _poll
       
    83     @param {Node} node Node to poll.
       
    84 
       
    85     @param {Object} options Options object.
       
    86         @param {EventFacade} [options.e] Event facade of the event that
       
    87             initiated the polling.
       
    88 
       
    89     @protected
       
    90     @static
       
    91     **/
       
    92     _poll: function (node, options) {
       
    93         var domNode = node._node, // performance cheat; getValue() is a big hit when polling
       
    94             event   = options.e,
       
    95             newVal  = domNode && domNode.value,
       
    96             vcData  = node._data && node._data[DATA_KEY], // another perf cheat
       
    97             facade, prevVal;
       
    98 
       
    99         if (!domNode || !vcData) {
       
   100             Y.log('_poll: node #' + node.get('id') + ' disappeared; stopping polling and removing all notifiers.', 'warn', 'event-valuechange');
       
   101             VC._stopPolling(node);
       
   102             return;
       
   103         }
       
   104 
       
   105         prevVal = vcData.prevVal;
       
   106 
       
   107         if (newVal !== prevVal) {
       
   108             vcData.prevVal = newVal;
       
   109 
       
   110             facade = {
       
   111                 _event       : event,
       
   112                 currentTarget: (event && event.currentTarget) || node,
       
   113                 newVal       : newVal,
       
   114                 prevVal      : prevVal,
       
   115                 target       : (event && event.target) || node
       
   116             };
       
   117 
       
   118             Y.Object.each(vcData.notifiers, function (notifier) {
       
   119                 notifier.fire(facade);
       
   120             });
       
   121 
       
   122             VC._refreshTimeout(node);
       
   123         }
       
   124     },
       
   125 
       
   126     /**
       
   127     Restarts the inactivity timeout for the specified node.
       
   128 
       
   129     @method _refreshTimeout
       
   130     @param {Node} node Node to refresh.
       
   131     @param {SyntheticEvent.Notifier} notifier
       
   132     @protected
       
   133     @static
       
   134     **/
       
   135     _refreshTimeout: function (node, notifier) {
       
   136         // The node may have been destroyed, so check that it still exists
       
   137         // before trying to get its data. Otherwise an error will occur.
       
   138         if (!node._node) {
       
   139             Y.log('_stopPolling: node disappeared', 'warn', 'event-valuechange');
       
   140             return;
       
   141         }
       
   142 
       
   143         var vcData = node.getData(DATA_KEY);
       
   144 
       
   145         VC._stopTimeout(node); // avoid dupes
       
   146 
       
   147         // If we don't see any changes within the timeout period (10 seconds by
       
   148         // default), stop polling.
       
   149         vcData.timeout = setTimeout(function () {
       
   150             Y.log('timeout: #' + node.get('id'), 'info', 'event-valuechange');
       
   151             VC._stopPolling(node, notifier);
       
   152         }, VC.TIMEOUT);
       
   153 
       
   154         Y.log('_refreshTimeout: #' + node.get('id'), 'info', 'event-valuechange');
       
   155     },
       
   156 
       
   157     /**
       
   158     Begins polling for changes to the `value` property of the specified node. If
       
   159     polling is already underway for the specified node, it will not be restarted
       
   160     unless the `force` option is `true`
       
   161 
       
   162     @method _startPolling
       
   163     @param {Node} node Node to watch.
       
   164     @param {SyntheticEvent.Notifier} notifier
       
   165 
       
   166     @param {Object} options Options object.
       
   167         @param {EventFacade} [options.e] Event facade of the event that
       
   168             initiated the polling.
       
   169         @param {Boolean} [options.force=false] If `true`, polling will be
       
   170             restarted even if we're already polling this node.
       
   171 
       
   172     @protected
       
   173     @static
       
   174     **/
       
   175     _startPolling: function (node, notifier, options) {
       
   176         if (!node.test('input,textarea')) {
       
   177             Y.log('_startPolling: aborting poll on #' + node.get('id') + ' -- not an input or textarea', 'warn', 'event-valuechange');
       
   178             return;
       
   179         }
       
   180 
       
   181         var vcData = node.getData(DATA_KEY);
       
   182 
       
   183         if (!vcData) {
       
   184             vcData = {prevVal: node.get(VALUE)};
       
   185             node.setData(DATA_KEY, vcData);
       
   186         }
       
   187 
       
   188         vcData.notifiers || (vcData.notifiers = {});
       
   189 
       
   190         // Don't bother continuing if we're already polling this node, unless
       
   191         // `options.force` is true.
       
   192         if (vcData.interval) {
       
   193             if (options.force) {
       
   194                 VC._stopPolling(node, notifier); // restart polling, but avoid dupe polls
       
   195             } else {
       
   196                 vcData.notifiers[Y.stamp(notifier)] = notifier;
       
   197                 return;
       
   198             }
       
   199         }
       
   200 
       
   201         // Poll for changes to the node's value. We can't rely on keyboard
       
   202         // events for this, since the value may change due to a mouse-initiated
       
   203         // paste event, an IME input event, or for some other reason that
       
   204         // doesn't trigger a key event.
       
   205         vcData.notifiers[Y.stamp(notifier)] = notifier;
       
   206 
       
   207         vcData.interval = setInterval(function () {
       
   208             VC._poll(node, vcData, options);
       
   209         }, VC.POLL_INTERVAL);
       
   210 
       
   211         Y.log('_startPolling: #' + node.get('id'), 'info', 'event-valuechange');
       
   212 
       
   213         VC._refreshTimeout(node, notifier);
       
   214     },
       
   215 
       
   216     /**
       
   217     Stops polling for changes to the specified node's `value` attribute.
       
   218 
       
   219     @method _stopPolling
       
   220     @param {Node} node Node to stop polling on.
       
   221     @param {SyntheticEvent.Notifier} [notifier] Notifier to remove from the
       
   222         node. If not specified, all notifiers will be removed.
       
   223     @protected
       
   224     @static
       
   225     **/
       
   226     _stopPolling: function (node, notifier) {
       
   227         // The node may have been destroyed, so check that it still exists
       
   228         // before trying to get its data. Otherwise an error will occur.
       
   229         if (!node._node) {
       
   230             Y.log('_stopPolling: node disappeared', 'info', 'event-valuechange');
       
   231             return;
       
   232         }
       
   233 
       
   234         var vcData = node.getData(DATA_KEY) || {};
       
   235 
       
   236         clearInterval(vcData.interval);
       
   237         delete vcData.interval;
       
   238 
       
   239         VC._stopTimeout(node);
       
   240 
       
   241         if (notifier) {
       
   242             vcData.notifiers && delete vcData.notifiers[Y.stamp(notifier)];
       
   243         } else {
       
   244             vcData.notifiers = {};
       
   245         }
       
   246 
       
   247         Y.log('_stopPolling: #' + node.get('id'), 'info', 'event-valuechange');
       
   248     },
       
   249 
       
   250     /**
       
   251     Clears the inactivity timeout for the specified node, if any.
       
   252 
       
   253     @method _stopTimeout
       
   254     @param {Node} node
       
   255     @protected
       
   256     @static
       
   257     **/
       
   258     _stopTimeout: function (node) {
       
   259         var vcData = node.getData(DATA_KEY) || {};
       
   260 
       
   261         clearTimeout(vcData.timeout);
       
   262         delete vcData.timeout;
       
   263     },
       
   264 
       
   265     // -- Protected Static Event Handlers --------------------------------------
       
   266 
       
   267     /**
       
   268     Stops polling when a node's blur event fires.
       
   269 
       
   270     @method _onBlur
       
   271     @param {EventFacade} e
       
   272     @param {SyntheticEvent.Notifier} notifier
       
   273     @protected
       
   274     @static
       
   275     **/
       
   276     _onBlur: function (e, notifier) {
       
   277         VC._stopPolling(e.currentTarget, notifier);
       
   278     },
       
   279 
       
   280     /**
       
   281     Resets a node's history and starts polling when a focus event occurs.
       
   282 
       
   283     @method _onFocus
       
   284     @param {EventFacade} e
       
   285     @param {SyntheticEvent.Notifier} notifier
       
   286     @protected
       
   287     @static
       
   288     **/
       
   289     _onFocus: function (e, notifier) {
       
   290         var node   = e.currentTarget,
       
   291             vcData = node.getData(DATA_KEY);
       
   292 
       
   293         if (!vcData) {
       
   294             vcData = {};
       
   295             node.setData(DATA_KEY, vcData);
       
   296         }
       
   297 
       
   298         vcData.prevVal = node.get(VALUE);
       
   299 
       
   300         VC._startPolling(node, notifier, {e: e});
       
   301     },
       
   302 
       
   303     /**
       
   304     Starts polling when a node receives a keyDown event.
       
   305 
       
   306     @method _onKeyDown
       
   307     @param {EventFacade} e
       
   308     @param {SyntheticEvent.Notifier} notifier
       
   309     @protected
       
   310     @static
       
   311     **/
       
   312     _onKeyDown: function (e, notifier) {
       
   313         VC._startPolling(e.currentTarget, notifier, {e: e});
       
   314     },
       
   315 
       
   316     /**
       
   317     Starts polling when an IME-related keyUp event occurs on a node.
       
   318 
       
   319     @method _onKeyUp
       
   320     @param {EventFacade} e
       
   321     @param {SyntheticEvent.Notifier} notifier
       
   322     @protected
       
   323     @static
       
   324     **/
       
   325     _onKeyUp: function (e, notifier) {
       
   326         // These charCodes indicate that an IME has started. We'll restart
       
   327         // polling and give the IME up to 10 seconds (by default) to finish.
       
   328         if (e.charCode === 229 || e.charCode === 197) {
       
   329             VC._startPolling(e.currentTarget, notifier, {
       
   330                 e    : e,
       
   331                 force: true
       
   332             });
       
   333         }
       
   334     },
       
   335 
       
   336     /**
       
   337     Starts polling when a node receives a mouseDown event.
       
   338 
       
   339     @method _onMouseDown
       
   340     @param {EventFacade} e
       
   341     @param {SyntheticEvent.Notifier} notifier
       
   342     @protected
       
   343     @static
       
   344     **/
       
   345     _onMouseDown: function (e, notifier) {
       
   346         VC._startPolling(e.currentTarget, notifier, {e: e});
       
   347     },
       
   348 
       
   349     /**
       
   350     Called when the `valuechange` event receives a new subscriber.
       
   351 
       
   352     @method _onSubscribe
       
   353     @param {Node} node
       
   354     @param {Subscription} sub
       
   355     @param {SyntheticEvent.Notifier} notifier
       
   356     @param {Function|String} [filter] Filter function or selector string. Only
       
   357         provided for delegate subscriptions.
       
   358     @protected
       
   359     @static
       
   360     **/
       
   361     _onSubscribe: function (node, sub, notifier, filter) {
       
   362         var _valuechange, callbacks, nodes;
       
   363 
       
   364         callbacks = {
       
   365             blur     : VC._onBlur,
       
   366             focus    : VC._onFocus,
       
   367             keydown  : VC._onKeyDown,
       
   368             keyup    : VC._onKeyUp,
       
   369             mousedown: VC._onMouseDown
       
   370         };
       
   371 
       
   372         // Store a utility object on the notifier to hold stuff that needs to be
       
   373         // passed around to trigger event handlers, polling handlers, etc.
       
   374         _valuechange = notifier._valuechange = {};
       
   375 
       
   376         if (filter) {
       
   377             // If a filter is provided, then this is a delegated subscription.
       
   378             _valuechange.delegated = true;
       
   379 
       
   380             // Add a function to the notifier that we can use to find all
       
   381             // nodes that pass the delegate filter.
       
   382             _valuechange.getNodes = function () {
       
   383                 return node.all('input,textarea').filter(filter);
       
   384             };
       
   385 
       
   386             // Store the initial values for each descendant of the container
       
   387             // node that passes the delegate filter.
       
   388             _valuechange.getNodes().each(function (child) {
       
   389                 if (!child.getData(DATA_KEY)) {
       
   390                     child.setData(DATA_KEY, {prevVal: child.get(VALUE)});
       
   391                 }
       
   392             });
       
   393 
       
   394             notifier._handles = Y.delegate(callbacks, node, filter, null,
       
   395                 notifier);
       
   396         } else {
       
   397             // This is a normal (non-delegated) event subscription.
       
   398 
       
   399             if (!node.test('input,textarea')) {
       
   400                 return;
       
   401             }
       
   402 
       
   403             if (!node.getData(DATA_KEY)) {
       
   404                 node.setData(DATA_KEY, {prevVal: node.get(VALUE)});
       
   405             }
       
   406 
       
   407             notifier._handles = node.on(callbacks, null, null, notifier);
       
   408         }
       
   409     },
       
   410 
       
   411     /**
       
   412     Called when the `valuechange` event loses a subscriber.
       
   413 
       
   414     @method _onUnsubscribe
       
   415     @param {Node} node
       
   416     @param {Subscription} subscription
       
   417     @param {SyntheticEvent.Notifier} notifier
       
   418     @protected
       
   419     @static
       
   420     **/
       
   421     _onUnsubscribe: function (node, subscription, notifier) {
       
   422         var _valuechange = notifier._valuechange;
       
   423 
       
   424         notifier._handles && notifier._handles.detach();
       
   425 
       
   426         if (_valuechange.delegated) {
       
   427             _valuechange.getNodes().each(function (child) {
       
   428                 VC._stopPolling(child, notifier);
       
   429             });
       
   430         } else {
       
   431             VC._stopPolling(node, notifier);
       
   432         }
       
   433     }
       
   434 };
       
   435 
       
   436 /**
       
   437 Synthetic event that fires when the `value` property of an `<input>` or
       
   438 `<textarea>` node changes as a result of a user-initiated keystroke, mouse
       
   439 operation, or input method editor (IME) input event.
       
   440 
       
   441 Unlike the `onchange` event, this event fires when the value actually changes
       
   442 and not when the element loses focus. This event also reports IME and
       
   443 multi-stroke input more reliably than `oninput` or the various key events across
       
   444 browsers.
       
   445 
       
   446 For performance reasons, only focused nodes are monitored for changes, so
       
   447 programmatic value changes on nodes that don't have focus won't be detected.
       
   448 
       
   449 @example
       
   450 
       
   451     YUI().use('event-valuechange', function (Y) {
       
   452         Y.one('#my-input').on('valuechange', function (e) {
       
   453             Y.log('previous value: ' + e.prevVal);
       
   454             Y.log('new value: ' + e.newVal);
       
   455         });
       
   456     });
       
   457 
       
   458 @event valuechange
       
   459 @param {String} prevVal Previous value prior to the latest change.
       
   460 @param {String} newVal New value after the latest change.
       
   461 @for YUI
       
   462 **/
       
   463 
       
   464 config = {
       
   465     detach: VC._onUnsubscribe,
       
   466     on    : VC._onSubscribe,
       
   467 
       
   468     delegate      : VC._onSubscribe,
       
   469     detachDelegate: VC._onUnsubscribe,
       
   470 
       
   471     publishConfig: {
       
   472         emitFacade: true
       
   473     }
       
   474 };
       
   475 
       
   476 Y.Event.define('valuechange', config);
       
   477 Y.Event.define('valueChange', config); // deprecated, but supported for backcompat
       
   478 
       
   479 Y.ValueChange = VC;
       
   480 
       
   481 
       
   482 }, '3.10.3', {"requires": ["event-focus", "event-synthetic"]});