87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam MooreYUI.add('event-valuechange', function(Y) {
4778ff543a041ac356d6e661cc9b66c3fafa2092Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore/**
b39897a381c2203466da5568bfd2862a54a81311Adam MooreAdds a synthetic `valueChange` event that fires when the `value` property of an
b39897a381c2203466da5568bfd2862a54a81311Adam Moore`<input>` or `<textarea>` node changes as a result of a keystroke, mouse
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Mooreoperation, or input method editor (IME) input event.
2c5ce90c334a2d0f18474e85c93b424b6ec9daaaAdam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam MooreUsage:
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore YUI().use('event-valuechange', function (Y) {
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore Y.one('#my-input').on('valueChange', function (e) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Y.log('previous value: ' + e.prevVal);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Y.log('new value: ' + e.newVal);
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore });
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore });
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore@module event-valuechange
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore**/
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore/**
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam MooreProvides the implementation for the synthetic `valueChange` event. This class
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Mooreisn't meant to be used directly, but is public to make monkeypatching possible.
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam MooreUsage:
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore YUI().use('event-valuechange', function (Y) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Y.one('#my-input').on('valueChange', function (e) {
b39897a381c2203466da5568bfd2862a54a81311Adam Moore Y.log('previous value: ' + e.prevVal);
b39897a381c2203466da5568bfd2862a54a81311Adam Moore Y.log('new value: ' + e.newVal);
b39897a381c2203466da5568bfd2862a54a81311Adam Moore });
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore });
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore@class ValueChange
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore@static
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore*/
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moorevar DATA_KEY = '_valuechange',
b39897a381c2203466da5568bfd2862a54a81311Adam Moore VALUE = 'value',
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore config, // defined at the end of this file
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore// Just a simple namespace to make methods overridable.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam MooreVC = {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore // -- Static Constants -----------------------------------------------------
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore
b45133051f787045386e6848ced7996daffd97e5Adam Moore /**
ff8e78b59d58eeca64349dff85a486594bbfa65bAdam Moore Interval (in milliseconds) at which to poll for changes to the value of an
b39897a381c2203466da5568bfd2862a54a81311Adam Moore element with one or more `valueChange` subscribers when the user is likely
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore to be interacting with it.
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore @property POLL_INTERVAL
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore @type Number
b45133051f787045386e6848ced7996daffd97e5Adam Moore @default 50
b45133051f787045386e6848ced7996daffd97e5Adam Moore @static
b45133051f787045386e6848ced7996daffd97e5Adam Moore **/
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore POLL_INTERVAL: 50,
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore /**
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Timeout (in milliseconds) after which to stop polling when there hasn't been
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore any new activity (keypresses, mouse clicks, etc.) on an element.
0263b559dcd210a19a22676b25ecbcac81d1692cAdam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @property TIMEOUT
b39897a381c2203466da5568bfd2862a54a81311Adam Moore @type Number
b39897a381c2203466da5568bfd2862a54a81311Adam Moore @default 10000
b39897a381c2203466da5568bfd2862a54a81311Adam Moore @static
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore **/
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore TIMEOUT: 10000,
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore // -- Protected Static Methods ---------------------------------------------
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore /**
b39897a381c2203466da5568bfd2862a54a81311Adam Moore Called at an interval to poll for changes to the value of the specified
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore node.
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore @method _poll
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @param {Node} node Node to poll.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore @param {Object} options Options object.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @param {EventFacade} [options.e] Event facade of the event that
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore initiated the polling.
0263b559dcd210a19a22676b25ecbcac81d1692cAdam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @protected
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore @static
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore **/
b39897a381c2203466da5568bfd2862a54a81311Adam Moore _poll: function (node, options) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore var domNode = node._node, // performance cheat; getValue() is a big hit when polling
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore event = options.e,
b39897a381c2203466da5568bfd2862a54a81311Adam Moore newVal = domNode && domNode.value,
b39897a381c2203466da5568bfd2862a54a81311Adam Moore vcData = node._data && node._data[DATA_KEY], // another perf cheat
b39897a381c2203466da5568bfd2862a54a81311Adam Moore facade, prevVal;
43692b3f865f1b1c970aedb2b96392482bd1fe3eAdam Moore
21a04e4a1f3596ab3a9e17fffa80b45eace6b29aAdam Moore if (!domNode || !vcData) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Y.log('_poll: node #' + node.get('id') + ' disappeared; stopping polling and removing all notifiers.', 'warn', 'event-valuechange');
b39897a381c2203466da5568bfd2862a54a81311Adam Moore VC._stopPolling(node);
b39897a381c2203466da5568bfd2862a54a81311Adam Moore return;
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore }
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore prevVal = vcData.prevVal;
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore if (newVal !== prevVal) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore vcData.prevVal = newVal;
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore facade = {
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore _event : event,
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore currentTarget: (event && event.currentTarget) || node,
efa57736d44cf446f1661497a8645bd388b493fbAdam Moore newVal : newVal,
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore prevVal : prevVal,
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore target : (event && event.target) || node
b39897a381c2203466da5568bfd2862a54a81311Adam Moore };
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
0263b559dcd210a19a22676b25ecbcac81d1692cAdam Moore Y.Object.each(vcData.notifiers, function (notifier) {
b39897a381c2203466da5568bfd2862a54a81311Adam Moore notifier.fire(facade);
401d3c02d890d39b7a48d94e0a9c1830f8aade42Adam Moore });
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore VC._refreshTimeout(node);
b39897a381c2203466da5568bfd2862a54a81311Adam Moore }
b1cd8b30205189b0b808fc2c4c93a184a22e24cdAdam Moore },
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore /**
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Restarts the inactivity timeout for the specified node.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @method _refreshTimeout
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @param {Node} node Node to refresh.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @param {SyntheticEvent.Notifier} notifier
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @protected
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @static
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore **/
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore _refreshTimeout: function (node, notifier) {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore // The node may have been destroyed, so check that it still exists
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore // before trying to get its data. Otherwise an error will occur.
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore if (!node._node) {
b39897a381c2203466da5568bfd2862a54a81311Adam Moore Y.log('_stopPolling: node disappeared', 'warn', 'event-valuechange');
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore return;
0263b559dcd210a19a22676b25ecbcac81d1692cAdam Moore }
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore var vcData = node.getData(DATA_KEY);
22f764173ae182052991f514d1f82bfc2251968eAdam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore VC._stopTimeout(node); // avoid dupes
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore // If we don't see any changes within the timeout period (10 seconds by
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore // default), stop polling.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore vcData.timeout = setTimeout(function () {
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore Y.log('timeout: #' + node.get('id'), 'info', 'event-valuechange');
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore VC._stopPolling(node, notifier);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore }, VC.TIMEOUT);
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore Y.log('_refreshTimeout: #' + node.get('id'), 'info', 'event-valuechange');
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore },
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore /**
b39897a381c2203466da5568bfd2862a54a81311Adam Moore Begins polling for changes to the `value` property of the specified node. If
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore polling is already underway for the specified node, it will not be restarted
0263b559dcd210a19a22676b25ecbcac81d1692cAdam Moore unless the `force` option is `true`
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig
ae1f7ed14ee90e037ce01ce4384fda0a7102b4f2Adam Moore @method _startPolling
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @param {Node} node Node to watch.
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @param {SyntheticEvent.Notifier} notifier
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @param {Object} options Options object.
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @param {EventFacade} [options.e] Event facade of the event that
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig initiated the polling.
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore @param {Boolean} [options.force=false] If `true`, polling will be
1b298c6f0ef597aa4ab0b8bcb25430b6c9a87749Adam Moore restarted even if we're already polling this node.
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @protected
a3e6db667fcd33ac653355e76d3660ecf232193bJeff Craig @static
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore **/
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore _startPolling: function (node, notifier, options) {
b39897a381c2203466da5568bfd2862a54a81311Adam Moore if (!node.test('input,textarea')) {
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore Y.log('_startPolling: aborting poll on #' + node.get('id') + ' -- not an input or textarea', 'warn', 'event-valuechange');
02b581ebfa9969c32cac8cd44ebe35e0e47f00ceAdam Moore return;
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore }
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore var vcData = node.getData(DATA_KEY);
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore if (!vcData) {
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore vcData = {prevVal: node.get(VALUE)};
eb86457f85638a9eb7c4d5f84eb367d24061abfbAdam Moore node.setData(DATA_KEY, vcData);
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore }
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore
b39897a381c2203466da5568bfd2862a54a81311Adam Moore vcData.notifiers || (vcData.notifiers = {});
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore
87d6b0a14cce52c4faa4b78fc9878eb553dab0d5Adam Moore // Don't bother continuing if we're already polling this node, unless
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore // `options.force` is true.
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore if (vcData.interval) {
efa57736d44cf446f1661497a8645bd388b493fbAdam Moore if (options.force) {
0bc189b2acbd7c4b5af63eded0c4289e224676b7Adam Moore VC._stopPolling(node, notifier); // restart polling, but avoid dupe polls
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore } else {
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore vcData.notifiers[Y.stamp(notifier)] = notifier;
b39897a381c2203466da5568bfd2862a54a81311Adam Moore return;
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore }
d8c505c303d22fc17c1b7aef7cf6d9bb9709f5f0isaacs }
b39897a381c2203466da5568bfd2862a54a81311Adam Moore
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore // Poll for changes to the node's value. We can't rely on keyboard
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore // events for this, since the value may change due to a mouse-initiated
b39897a381c2203466da5568bfd2862a54a81311Adam Moore // paste event, an IME input event, or for some other reason that
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore // doesn't trigger a key event.
b39897a381c2203466da5568bfd2862a54a81311Adam Moore vcData.notifiers[Y.stamp(notifier)] = notifier;
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore vcData.interval = setInterval(function () {
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore VC._poll(node, vcData, options);
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore }, VC.POLL_INTERVAL);
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore Y.log('_startPolling: #' + node.get('id'), 'info', 'event-valuechange');
3c245663d1bfadc0536b538247884c0667cc9313Adam Moore
VC._refreshTimeout(node, notifier);
},
/**
Stops polling for changes to the specified node's `value` attribute.
@method _stopPolling
@param {Node} node Node to stop polling on.
@param {SyntheticEvent.Notifier} [notifier] Notifier to remove from the
node. If not specified, all notifiers will be removed.
@protected
@static
**/
_stopPolling: function (node, notifier) {
// The node may have been destroyed, so check that it still exists
// before trying to get its data. Otherwise an error will occur.
if (!node._node) {
Y.log('_stopPolling: node disappeared', 'info', 'event-valuechange');
return;
}
var vcData = node.getData(DATA_KEY) || {};
clearInterval(vcData.interval);
delete vcData.interval;
VC._stopTimeout(node);
if (notifier) {
vcData.notifiers && delete vcData.notifiers[Y.stamp(notifier)];
} else {
vcData.notifiers = {};
}
Y.log('_stopPolling: #' + node.get('id'), 'info', 'event-valuechange');
},
/**
Clears the inactivity timeout for the specified node, if any.
@method _stopTimeout
@param {Node} node
@protected
@static
**/
_stopTimeout: function (node) {
var vcData = node.getData(DATA_KEY) || {};
clearTimeout(vcData.timeout);
delete vcData.timeout;
},
// -- Protected Static Event Handlers --------------------------------------
/**
Stops polling when a node's blur event fires.
@method _onBlur
@param {EventFacade} e
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onBlur: function (e, notifier) {
VC._stopPolling(e.currentTarget, notifier);
},
/**
Resets a node's history and starts polling when a focus event occurs.
@method _onFocus
@param {EventFacade} e
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onFocus: function (e, notifier) {
var node = e.currentTarget,
vcData = node.getData(DATA_KEY);
if (!vcData) {
vcData = {};
node.setData(DATA_KEY, vcData);
}
vcData.prevVal = node.get(VALUE);
VC._startPolling(node, notifier, {e: e});
},
/**
Starts polling when a node receives a keyDown event.
@method _onKeyDown
@param {EventFacade} e
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onKeyDown: function (e, notifier) {
VC._startPolling(e.currentTarget, notifier, {e: e});
},
/**
Starts polling when an IME-related keyUp event occurs on a node.
@method _onKeyUp
@param {EventFacade} e
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onKeyUp: function (e, notifier) {
// These charCodes indicate that an IME has started. We'll restart
// polling and give the IME up to 10 seconds (by default) to finish.
if (e.charCode === 229 || e.charCode === 197) {
VC._startPolling(e.currentTarget, notifier, {
e : e,
force: true
});
}
},
/**
Starts polling when a node receives a mouseDown event.
@method _onMouseDown
@param {EventFacade} e
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onMouseDown: function (e, notifier) {
VC._startPolling(e.currentTarget, notifier, {e: e});
},
/**
Called when the `valuechange` event receives a new subscriber.
@method _onSubscribe
@param {Node} node
@param {Subscription} sub
@param {SyntheticEvent.Notifier} notifier
@param {Function|String} [filter] Filter function or selector string. Only
provided for delegate subscriptions.
@protected
@static
**/
_onSubscribe: function (node, sub, notifier, filter) {
var _valuechange, callbacks, nodes;
callbacks = {
blur : VC._onBlur,
focus : VC._onFocus,
keydown : VC._onKeyDown,
keyup : VC._onKeyUp,
mousedown: VC._onMouseDown
};
// Store a utility object on the notifier to hold stuff that needs to be
// passed around to trigger event handlers, polling handlers, etc.
_valuechange = notifier._valuechange = {};
if (filter) {
// If a filter is provided, then this is a delegated subscription.
_valuechange.delegated = true;
// Add a function to the notifier that we can use to find all
// nodes that pass the delegate filter.
_valuechange.getNodes = function () {
return node.all('input,textarea').filter(filter);
};
// Store the initial values for each descendant of the container
// node that passes the delegate filter.
_valuechange.getNodes().each(function (child) {
if (!child.getData(DATA_KEY)) {
child.setData(DATA_KEY, {prevVal: child.get(VALUE)});
}
});
notifier._handles = Y.delegate(callbacks, node, filter, null,
notifier);
} else {
// This is a normal (non-delegated) event subscription.
if (!node.test('input,textarea')) {
return;
}
if (!node.getData(DATA_KEY)) {
node.setData(DATA_KEY, {prevVal: node.get(VALUE)});
}
notifier._handles = node.on(callbacks, null, null, notifier);
}
},
/**
Called when the `valuechange` event loses a subscriber.
@method _onUnsubscribe
@param {Node} node
@param {Subscription} subscription
@param {SyntheticEvent.Notifier} notifier
@protected
@static
**/
_onUnsubscribe: function (node, subscription, notifier) {
var _valuechange = notifier._valuechange;
notifier._handles && notifier._handles.detach();
if (_valuechange.delegated) {
_valuechange.getNodes().each(function (child) {
VC._stopPolling(child, notifier);
});
} else {
VC._stopPolling(node, notifier);
}
}
};
/**
Synthetic event that fires when the `value` property of an `<input>` or
`<textarea>` node changes as a result of a user-initiated keystroke, mouse
operation, or input method editor (IME) input event.
Unlike the `onchange` event, this event fires when the value actually changes
and not when the element loses focus. This event also reports IME and
multi-stroke input more reliably than `oninput` or the various key events across
browsers.
For performance reasons, only focused nodes are monitored for changes, so
programmatic value changes on nodes that don't have focus won't be detected.
@example
YUI().use('event-valuechange', function (Y) {
Y.one('#my-input').on('valueChange', function (e) {
Y.log('previous value: ' + e.prevVal);
Y.log('new value: ' + e.newVal);
});
});
@event valuechange
@param {String} prevVal Previous value prior to the latest change.
@param {String} newVal New value after the latest change.
@for YUI
**/
config = {
detach: VC._onUnsubscribe,
on : VC._onSubscribe,
delegate : VC._onSubscribe,
detachDelegate: VC._onUnsubscribe,
publishConfig: {
emitFacade: true
}
};
Y.Event.define('valuechange', config);
Y.Event.define('valueChange', config); // deprecated, but supported for backcompat
Y.ValueChange = VC;
}, '@VERSION@' ,{requires:['event-focus', 'event-synthetic']});