PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/yui/3.10.0/event-valuechange/event-valuechange-debug.js

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