Dashboard sipadu mbip
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

event-synthetic-debug.js 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('event-synthetic', function(Y) {
  9. /* Define new DOM events that can be subscribed to from Nodes.
  10. *
  11. * @module event
  12. * @submodule event-synthetic
  13. */
  14. var DOMMap = Y.Env.evt.dom_map,
  15. toArray = Y.Array,
  16. YLang = Y.Lang,
  17. isObject = YLang.isObject,
  18. isString = YLang.isString,
  19. isArray = YLang.isArray,
  20. query = Y.Selector.query,
  21. noop = function () {};
  22. /**
  23. * <p>The triggering mechanism used by SyntheticEvents.</p>
  24. *
  25. * <p>Implementers should not instantiate these directly. Use the Notifier
  26. * provided to the event's implemented <code>on(node, sub, notifier)</code> or
  27. * <code>delegate(node, sub, notifier, filter)</code> methods.</p>
  28. *
  29. * @class SyntheticEvent.Notifier
  30. * @constructor
  31. * @param handle {EventHandle} the detach handle for the subscription to an
  32. * internal custom event used to execute the callback passed to
  33. * on(..) or delegate(..)
  34. * @param emitFacade {Boolean} take steps to ensure the first arg received by
  35. * the subscription callback is an event facade
  36. * @private
  37. * @since 3.2.0
  38. */
  39. function Notifier(handle, emitFacade) {
  40. this.handle = handle;
  41. this.emitFacade = emitFacade;
  42. }
  43. /**
  44. * <p>Executes the subscription callback, passing the firing arguments as the
  45. * first parameters to that callback. For events that are configured with
  46. * emitFacade=true, it is common practice to pass the triggering DOMEventFacade
  47. * as the first parameter. Barring a proper DOMEventFacade or EventFacade
  48. * (from a CustomEvent), a new EventFacade will be generated. In that case, if
  49. * fire() is called with a simple object, it will be mixed into the facade.
  50. * Otherwise, the facade will be prepended to the callback parameters.</p>
  51. *
  52. * <p>For notifiers provided to delegate logic, the first argument should be an
  53. * object with a &quot;currentTarget&quot; property to identify what object to
  54. * default as 'this' in the callback. Typically this is gleaned from the
  55. * DOMEventFacade or EventFacade, but if configured with emitFacade=false, an
  56. * object must be provided. In that case, the object will be removed from the
  57. * callback parameters.</p>
  58. *
  59. * <p>Additional arguments passed during event subscription will be
  60. * automatically added after those passed to fire().</p>
  61. *
  62. * @method fire
  63. * @param e {EventFacade|DOMEventFacade|Object|any} (see description)
  64. * @param arg* {any} additional arguments received by all subscriptions
  65. * @private
  66. */
  67. Notifier.prototype.fire = function (e) {
  68. // first arg to delegate notifier should be an object with currentTarget
  69. var args = toArray(arguments, 0, true),
  70. handle = this.handle,
  71. ce = handle.evt,
  72. sub = handle.sub,
  73. thisObj = sub.context,
  74. delegate = sub.filter,
  75. event = e || {},
  76. ret;
  77. if (this.emitFacade) {
  78. if (!e || !e.preventDefault) {
  79. event = ce._getFacade();
  80. if (isObject(e) && !e.preventDefault) {
  81. Y.mix(event, e, true);
  82. args[0] = event;
  83. } else {
  84. args.unshift(event);
  85. }
  86. }
  87. event.type = ce.type;
  88. event.details = args.slice();
  89. if (delegate) {
  90. event.container = ce.host;
  91. }
  92. } else if (delegate && isObject(e) && e.currentTarget) {
  93. args.shift();
  94. }
  95. sub.context = thisObj || event.currentTarget || ce.host;
  96. ret = ce.fire.apply(ce, args);
  97. sub.context = thisObj; // reset for future firing
  98. // to capture callbacks that return false to stopPropagation.
  99. // Useful for delegate implementations
  100. return ret;
  101. };
  102. /**
  103. * Manager object for synthetic event subscriptions to aggregate multiple synths on the same node without colliding with actual DOM subscription entries in the global map of DOM subscriptions. Also facilitates proper cleanup on page unload.
  104. *
  105. * @class SynthRegistry
  106. * @constructor
  107. * @param el {HTMLElement} the DOM element
  108. * @param yuid {String} the yuid stamp for the element
  109. * @param key {String} the generated id token used to identify an event type +
  110. * element in the global DOM subscription map.
  111. * @private
  112. */
  113. function SynthRegistry(el, yuid, key) {
  114. this.handles = [];
  115. this.el = el;
  116. this.key = key;
  117. this.domkey = yuid;
  118. }
  119. SynthRegistry.prototype = {
  120. constructor: SynthRegistry,
  121. // A few object properties to fake the CustomEvent interface for page
  122. // unload cleanup. DON'T TOUCH!
  123. type : '_synth',
  124. fn : noop,
  125. capture : false,
  126. /**
  127. * Adds a subscription from the Notifier registry.
  128. *
  129. * @method register
  130. * @param handle {EventHandle} the subscription
  131. * @since 3.4.0
  132. */
  133. register: function (handle) {
  134. handle.evt.registry = this;
  135. this.handles.push(handle);
  136. },
  137. /**
  138. * Removes the subscription from the Notifier registry.
  139. *
  140. * @method _unregisterSub
  141. * @param sub {Subscription} the subscription
  142. * @since 3.4.0
  143. */
  144. unregister: function (sub) {
  145. var handles = this.handles,
  146. events = DOMMap[this.domkey],
  147. i;
  148. for (i = handles.length - 1; i >= 0; --i) {
  149. if (handles[i].sub === sub) {
  150. handles.splice(i, 1);
  151. break;
  152. }
  153. }
  154. // Clean up left over objects when there are no more subscribers.
  155. if (!handles.length) {
  156. delete events[this.key];
  157. if (!Y.Object.size(events)) {
  158. delete DOMMap[this.domkey];
  159. }
  160. }
  161. },
  162. /**
  163. * Used by the event system's unload cleanup process. When navigating
  164. * away from the page, the event system iterates the global map of element
  165. * subscriptions and detaches everything using detachAll(). Normally,
  166. * the map is populated with custom events, so this object needs to
  167. * at least support the detachAll method to duck type its way to
  168. * cleanliness.
  169. *
  170. * @method detachAll
  171. * @private
  172. * @since 3.4.0
  173. */
  174. detachAll : function () {
  175. var handles = this.handles,
  176. i = handles.length;
  177. while (--i >= 0) {
  178. handles[i].detach();
  179. }
  180. }
  181. };
  182. /**
  183. * <p>Wrapper class for the integration of new events into the YUI event
  184. * infrastructure. Don't instantiate this object directly, use
  185. * <code>Y.Event.define(type, config)</code>. See that method for details.</p>
  186. *
  187. * <p>Properties that MAY or SHOULD be specified in the configuration are noted
  188. * below and in the description of <code>Y.Event.define</code>.</p>
  189. *
  190. * @class SyntheticEvent
  191. * @constructor
  192. * @param cfg {Object} Implementation pieces and configuration
  193. * @since 3.1.0
  194. * @in event-synthetic
  195. */
  196. function SyntheticEvent() {
  197. this._init.apply(this, arguments);
  198. }
  199. Y.mix(SyntheticEvent, {
  200. Notifier: Notifier,
  201. SynthRegistry: SynthRegistry,
  202. /**
  203. * Returns the array of subscription handles for a node for the given event
  204. * type. Passing true as the third argument will create a registry entry
  205. * in the event system's DOM map to host the array if one doesn't yet exist.
  206. *
  207. * @method getRegistry
  208. * @param node {Node} the node
  209. * @param type {String} the event
  210. * @param create {Boolean} create a registration entry to host a new array
  211. * if one doesn't exist.
  212. * @return {Array}
  213. * @static
  214. * @protected
  215. * @since 3.2.0
  216. */
  217. getRegistry: function (node, type, create) {
  218. var el = node._node,
  219. yuid = Y.stamp(el),
  220. key = 'event:' + yuid + type + '_synth',
  221. events = DOMMap[yuid];
  222. if (create) {
  223. if (!events) {
  224. events = DOMMap[yuid] = {};
  225. }
  226. if (!events[key]) {
  227. events[key] = new SynthRegistry(el, yuid, key);
  228. }
  229. }
  230. return (events && events[key]) || null;
  231. },
  232. /**
  233. * Alternate <code>_delete()</code> method for the CustomEvent object
  234. * created to manage SyntheticEvent subscriptions.
  235. *
  236. * @method _deleteSub
  237. * @param sub {Subscription} the subscription to clean up
  238. * @private
  239. * @since 3.2.0
  240. */
  241. _deleteSub: function (sub) {
  242. if (sub && sub.fn) {
  243. var synth = this.eventDef,
  244. method = (sub.filter) ? 'detachDelegate' : 'detach';
  245. this._subscribers = [];
  246. synth[method](sub.node, sub, this.notifier, sub.filter);
  247. this.registry.unregister(sub);
  248. delete sub.fn;
  249. delete sub.node;
  250. delete sub.context;
  251. }
  252. },
  253. prototype: {
  254. constructor: SyntheticEvent,
  255. /**
  256. * Construction logic for the event.
  257. *
  258. * @method _init
  259. * @protected
  260. */
  261. _init: function () {
  262. var config = this.publishConfig || (this.publishConfig = {});
  263. // The notification mechanism handles facade creation
  264. this.emitFacade = ('emitFacade' in config) ?
  265. config.emitFacade :
  266. true;
  267. config.emitFacade = false;
  268. },
  269. /**
  270. * <p>Implementers MAY provide this method definition.</p>
  271. *
  272. * <p>Implement this function if the event supports a different
  273. * subscription signature. This function is used by both
  274. * <code>on()</code> and <code>delegate()</code>. The second parameter
  275. * indicates that the event is being subscribed via
  276. * <code>delegate()</code>.</p>
  277. *
  278. * <p>Implementations must remove extra arguments from the args list
  279. * before returning. The required args for <code>on()</code>
  280. * subscriptions are</p>
  281. * <pre><code>[type, callback, target, context, argN...]</code></pre>
  282. *
  283. * <p>The required args for <code>delegate()</code>
  284. * subscriptions are</p>
  285. *
  286. * <pre><code>[type, callback, target, filter, context, argN...]</code></pre>
  287. *
  288. * <p>The return value from this function will be stored on the
  289. * subscription in the '_extra' property for reference elsewhere.</p>
  290. *
  291. * @method processArgs
  292. * @param args {Array} parmeters passed to Y.on(..) or Y.delegate(..)
  293. * @param delegate {Boolean} true if the subscription is from Y.delegate
  294. * @return {any}
  295. */
  296. processArgs: noop,
  297. /**
  298. * <p>Implementers MAY override this property.</p>
  299. *
  300. * <p>Whether to prevent multiple subscriptions to this event that are
  301. * classified as being the same. By default, this means the subscribed
  302. * callback is the same function. See the <code>subMatch</code>
  303. * method. Setting this to true will impact performance for high volume
  304. * events.</p>
  305. *
  306. * @property preventDups
  307. * @type {Boolean}
  308. * @default false
  309. */
  310. //preventDups : false,
  311. /**
  312. * <p>Implementers SHOULD provide this method definition.</p>
  313. *
  314. * Implementation logic for subscriptions done via <code>node.on(type,
  315. * fn)</code> or <code>Y.on(type, fn, target)</code>. This
  316. * function should set up the monitor(s) that will eventually fire the
  317. * event. Typically this involves subscribing to at least one DOM
  318. * event. It is recommended to store detach handles from any DOM
  319. * subscriptions to make for easy cleanup in the <code>detach</code>
  320. * method. Typically these handles are added to the <code>sub</code>
  321. * object. Also for SyntheticEvents that leverage a single DOM
  322. * subscription under the hood, it is recommended to pass the DOM event
  323. * object to <code>notifier.fire(e)</code>. (The event name on the
  324. * object will be updated).
  325. *
  326. * @method on
  327. * @param node {Node} the node the subscription is being applied to
  328. * @param sub {Subscription} the object to track this subscription
  329. * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
  330. * trigger the execution of the subscribers
  331. */
  332. on: noop,
  333. /**
  334. * <p>Implementers SHOULD provide this method definition.</p>
  335. *
  336. * <p>Implementation logic for detaching subscriptions done via
  337. * <code>node.on(type, fn)</code>. This function should clean up any
  338. * subscriptions made in the <code>on()</code> phase.</p>
  339. *
  340. * @method detach
  341. * @param node {Node} the node the subscription was applied to
  342. * @param sub {Subscription} the object tracking this subscription
  343. * @param notifier {SyntheticEvent.Notifier} the Notifier used to
  344. * trigger the execution of the subscribers
  345. */
  346. detach: noop,
  347. /**
  348. * <p>Implementers SHOULD provide this method definition.</p>
  349. *
  350. * <p>Implementation logic for subscriptions done via
  351. * <code>node.delegate(type, fn, filter)</code> or
  352. * <code>Y.delegate(type, fn, container, filter)</code>. Like with
  353. * <code>on()</code> above, this function should monitor the environment
  354. * for the event being fired, and trigger subscription execution by
  355. * calling <code>notifier.fire(e)</code>.</p>
  356. *
  357. * <p>This function receives a fourth argument, which is the filter
  358. * used to identify which Node's are of interest to the subscription.
  359. * The filter will be either a boolean function that accepts a target
  360. * Node for each hierarchy level as the event bubbles, or a selector
  361. * string. To translate selector strings into filter functions, use
  362. * <code>Y.delegate.compileFilter(filter)</code>.</p>
  363. *
  364. * @method delegate
  365. * @param node {Node} the node the subscription is being applied to
  366. * @param sub {Subscription} the object to track this subscription
  367. * @param notifier {SyntheticEvent.Notifier} call notifier.fire(..) to
  368. * trigger the execution of the subscribers
  369. * @param filter {String|Function} Selector string or function that
  370. * accepts an event object and returns null, a Node, or an
  371. * array of Nodes matching the criteria for processing.
  372. * @since 3.2.0
  373. */
  374. delegate : noop,
  375. /**
  376. * <p>Implementers SHOULD provide this method definition.</p>
  377. *
  378. * <p>Implementation logic for detaching subscriptions done via
  379. * <code>node.delegate(type, fn, filter)</code> or
  380. * <code>Y.delegate(type, fn, container, filter)</code>. This function
  381. * should clean up any subscriptions made in the
  382. * <code>delegate()</code> phase.</p>
  383. *
  384. * @method detachDelegate
  385. * @param node {Node} the node the subscription was applied to
  386. * @param sub {Subscription} the object tracking this subscription
  387. * @param notifier {SyntheticEvent.Notifier} the Notifier used to
  388. * trigger the execution of the subscribers
  389. * @param filter {String|Function} Selector string or function that
  390. * accepts an event object and returns null, a Node, or an
  391. * array of Nodes matching the criteria for processing.
  392. * @since 3.2.0
  393. */
  394. detachDelegate : noop,
  395. /**
  396. * Sets up the boilerplate for detaching the event and facilitating the
  397. * execution of subscriber callbacks.
  398. *
  399. * @method _on
  400. * @param args {Array} array of arguments passed to
  401. * <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
  402. * @param delegate {Boolean} true if called from
  403. * <code>Y.delegate(...)</code>
  404. * @return {EventHandle} the detach handle for this subscription
  405. * @private
  406. * since 3.2.0
  407. */
  408. _on: function (args, delegate) {
  409. var handles = [],
  410. originalArgs = args.slice(),
  411. extra = this.processArgs(args, delegate),
  412. selector = args[2],
  413. method = delegate ? 'delegate' : 'on',
  414. nodes, handle;
  415. // Can't just use Y.all because it doesn't support window (yet?)
  416. nodes = (isString(selector)) ?
  417. query(selector) :
  418. toArray(selector || Y.one(Y.config.win));
  419. if (!nodes.length && isString(selector)) {
  420. handle = Y.on('available', function () {
  421. Y.mix(handle, Y[method].apply(Y, originalArgs), true);
  422. }, selector);
  423. return handle;
  424. }
  425. Y.Array.each(nodes, function (node) {
  426. var subArgs = args.slice(),
  427. filter;
  428. node = Y.one(node);
  429. if (node) {
  430. if (delegate) {
  431. filter = subArgs.splice(3, 1)[0];
  432. }
  433. // (type, fn, el, thisObj, ...) => (fn, thisObj, ...)
  434. subArgs.splice(0, 4, subArgs[1], subArgs[3]);
  435. if (!this.preventDups ||
  436. !this.getSubs(node, args, null, true))
  437. {
  438. handles.push(this._subscribe(node, method, subArgs, extra, filter));
  439. }
  440. }
  441. }, this);
  442. return (handles.length === 1) ?
  443. handles[0] :
  444. new Y.EventHandle(handles);
  445. },
  446. /**
  447. * Creates a new Notifier object for use by this event's
  448. * <code>on(...)</code> or <code>delegate(...)</code> implementation
  449. * and register the custom event proxy in the DOM system for cleanup.
  450. *
  451. * @method _subscribe
  452. * @param node {Node} the Node hosting the event
  453. * @param method {String} "on" or "delegate"
  454. * @param args {Array} the subscription arguments passed to either
  455. * <code>Y.on(...)</code> or <code>Y.delegate(...)</code>
  456. * after running through <code>processArgs(args)</code> to
  457. * normalize the argument signature
  458. * @param extra {any} Extra data parsed from
  459. * <code>processArgs(args)</code>
  460. * @param filter {String|Function} the selector string or function
  461. * filter passed to <code>Y.delegate(...)</code> (not
  462. * present when called from <code>Y.on(...)</code>)
  463. * @return {EventHandle}
  464. * @private
  465. * @since 3.2.0
  466. */
  467. _subscribe: function (node, method, args, extra, filter) {
  468. var dispatcher = new Y.CustomEvent(this.type, this.publishConfig),
  469. handle = dispatcher.on.apply(dispatcher, args),
  470. notifier = new Notifier(handle, this.emitFacade),
  471. registry = SyntheticEvent.getRegistry(node, this.type, true),
  472. sub = handle.sub;
  473. sub.node = node;
  474. sub.filter = filter;
  475. if (extra) {
  476. this.applyArgExtras(extra, sub);
  477. }
  478. Y.mix(dispatcher, {
  479. eventDef : this,
  480. notifier : notifier,
  481. host : node, // I forget what this is for
  482. currentTarget: node, // for generating facades
  483. target : node, // for generating facades
  484. el : node._node, // For category detach
  485. _delete : SyntheticEvent._deleteSub
  486. }, true);
  487. handle.notifier = notifier;
  488. registry.register(handle);
  489. // Call the implementation's "on" or "delegate" method
  490. this[method](node, sub, notifier, filter);
  491. return handle;
  492. },
  493. /**
  494. * <p>Implementers MAY provide this method definition.</p>
  495. *
  496. * <p>Implement this function if you want extra data extracted during
  497. * processArgs to be propagated to subscriptions on a per-node basis.
  498. * That is to say, if you call <code>Y.on('xyz', fn, xtra, 'div')</code>
  499. * the data returned from processArgs will be shared
  500. * across the subscription objects for all the divs. If you want each
  501. * subscription to receive unique information, do that processing
  502. * here.</p>
  503. *
  504. * <p>The default implementation adds the data extracted by processArgs
  505. * to the subscription object as <code>sub._extra</code>.</p>
  506. *
  507. * @method applyArgExtras
  508. * @param extra {any} Any extra data extracted from processArgs
  509. * @param sub {Subscription} the individual subscription
  510. */
  511. applyArgExtras: function (extra, sub) {
  512. sub._extra = extra;
  513. },
  514. /**
  515. * Removes the subscription(s) from the internal subscription dispatch
  516. * mechanism. See <code>SyntheticEvent._deleteSub</code>.
  517. *
  518. * @method _detach
  519. * @param args {Array} The arguments passed to
  520. * <code>node.detach(...)</code>
  521. * @private
  522. * @since 3.2.0
  523. */
  524. _detach: function (args) {
  525. // Can't use Y.all because it doesn't support window (yet?)
  526. // TODO: Does Y.all support window now?
  527. var target = args[2],
  528. els = (isString(target)) ?
  529. query(target) : toArray(target),
  530. node, i, len, handles, j;
  531. // (type, fn, el, context, filter?) => (type, fn, context, filter?)
  532. args.splice(2, 1);
  533. for (i = 0, len = els.length; i < len; ++i) {
  534. node = Y.one(els[i]);
  535. if (node) {
  536. handles = this.getSubs(node, args);
  537. if (handles) {
  538. for (j = handles.length - 1; j >= 0; --j) {
  539. handles[j].detach();
  540. }
  541. }
  542. }
  543. }
  544. },
  545. /**
  546. * Returns the detach handles of subscriptions on a node that satisfy a
  547. * search/filter function. By default, the filter used is the
  548. * <code>subMatch</code> method.
  549. *
  550. * @method getSubs
  551. * @param node {Node} the node hosting the event
  552. * @param args {Array} the array of original subscription args passed
  553. * to <code>Y.on(...)</code> (before
  554. * <code>processArgs</code>
  555. * @param filter {Function} function used to identify a subscription
  556. * for inclusion in the returned array
  557. * @param first {Boolean} stop after the first match (used to check for
  558. * duplicate subscriptions)
  559. * @return {EventHandle[]} detach handles for the matching subscriptions
  560. */
  561. getSubs: function (node, args, filter, first) {
  562. var registry = SyntheticEvent.getRegistry(node, this.type),
  563. handles = [],
  564. allHandles, i, len, handle;
  565. if (registry) {
  566. allHandles = registry.handles;
  567. if (!filter) {
  568. filter = this.subMatch;
  569. }
  570. for (i = 0, len = allHandles.length; i < len; ++i) {
  571. handle = allHandles[i];
  572. if (filter.call(this, handle.sub, args)) {
  573. if (first) {
  574. return handle;
  575. } else {
  576. handles.push(allHandles[i]);
  577. }
  578. }
  579. }
  580. }
  581. return handles.length && handles;
  582. },
  583. /**
  584. * <p>Implementers MAY override this to define what constitutes a
  585. * &quot;same&quot; subscription. Override implementations should
  586. * consider the lack of a comparator as a match, so calling
  587. * <code>getSubs()</code> with no arguments will return all subs.</p>
  588. *
  589. * <p>Compares a set of subscription arguments against a Subscription
  590. * object to determine if they match. The default implementation
  591. * compares the callback function against the second argument passed to
  592. * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
  593. *
  594. * @method subMatch
  595. * @param sub {Subscription} the existing subscription
  596. * @param args {Array} the calling arguments passed to
  597. * <code>Y.on(...)</code> etc.
  598. * @return {Boolean} true if the sub can be described by the args
  599. * present
  600. * @since 3.2.0
  601. */
  602. subMatch: function (sub, args) {
  603. // Default detach cares only about the callback matching
  604. return !args[1] || sub.fn === args[1];
  605. }
  606. }
  607. }, true);
  608. Y.SyntheticEvent = SyntheticEvent;
  609. /**
  610. * <p>Defines a new event in the DOM event system. Implementers are
  611. * responsible for monitoring for a scenario whereby the event is fired. A
  612. * notifier object is provided to the functions identified below. When the
  613. * criteria defining the event are met, call notifier.fire( [args] ); to
  614. * execute event subscribers.</p>
  615. *
  616. * <p>The first parameter is the name of the event. The second parameter is a
  617. * configuration object which define the behavior of the event system when the
  618. * new event is subscribed to or detached from. The methods that should be
  619. * defined in this configuration object are <code>on</code>,
  620. * <code>detach</code>, <code>delegate</code>, and <code>detachDelegate</code>.
  621. * You are free to define any other methods or properties needed to define your
  622. * event. Be aware, however, that since the object is used to subclass
  623. * SyntheticEvent, you should avoid method names used by SyntheticEvent unless
  624. * your intention is to override the default behavior.</p>
  625. *
  626. * <p>This is a list of properties and methods that you can or should specify
  627. * in the configuration object:</p>
  628. *
  629. * <dl>
  630. * <dt><code>on</code></dt>
  631. * <dd><code>function (node, subscription, notifier)</code> The
  632. * implementation logic for subscription. Any special setup you need to
  633. * do to create the environment for the event being fired--E.g. native
  634. * DOM event subscriptions. Store subscription related objects and
  635. * state on the <code>subscription</code> object. When the
  636. * criteria have been met to fire the synthetic event, call
  637. * <code>notifier.fire(e)</code>. See Notifier's <code>fire()</code>
  638. * method for details about what to pass as parameters.</dd>
  639. *
  640. * <dt><code>detach</code></dt>
  641. * <dd><code>function (node, subscription, notifier)</code> The
  642. * implementation logic for cleaning up a detached subscription. E.g.
  643. * detach any DOM subscriptions added in <code>on</code>.</dd>
  644. *
  645. * <dt><code>delegate</code></dt>
  646. * <dd><code>function (node, subscription, notifier, filter)</code> The
  647. * implementation logic for subscription via <code>Y.delegate</code> or
  648. * <code>node.delegate</code>. The filter is typically either a selector
  649. * string or a function. You can use
  650. * <code>Y.delegate.compileFilter(selectorString)</code> to create a
  651. * filter function from a selector string if needed. The filter function
  652. * expects an event object as input and should output either null, a
  653. * matching Node, or an array of matching Nodes. Otherwise, this acts
  654. * like <code>on</code> DOM event subscriptions. Store subscription
  655. * related objects and information on the <code>subscription</code>
  656. * object. When the criteria have been met to fire the synthetic event,
  657. * call <code>notifier.fire(e)</code> as noted above.</dd>
  658. *
  659. * <dt><code>detachDelegate</code></dt>
  660. * <dd><code>function (node, subscription, notifier)</code> The
  661. * implementation logic for cleaning up a detached delegate subscription.
  662. * E.g. detach any DOM delegate subscriptions added in
  663. * <code>delegate</code>.</dd>
  664. *
  665. * <dt><code>publishConfig</code></dt>
  666. * <dd>(Object) The configuration object that will be used to instantiate
  667. * the underlying CustomEvent. See Notifier's <code>fire</code> method
  668. * for details.</dd>
  669. *
  670. * <dt><code>processArgs</code></dt
  671. * <dd>
  672. * <p><code>function (argArray, fromDelegate)</code> Optional method
  673. * to extract any additional arguments from the subscription
  674. * signature. Using this allows <code>on</code> or
  675. * <code>delegate</code> signatures like
  676. * <code>node.on(&quot;hover&quot;, overCallback,
  677. * outCallback)</code>.</p>
  678. * <p>When processing an atypical argument signature, make sure the
  679. * args array is returned to the normal signature before returning
  680. * from the function. For example, in the &quot;hover&quot; example
  681. * above, the <code>outCallback</code> needs to be <code>splice</code>d
  682. * out of the array. The expected signature of the args array for
  683. * <code>on()</code> subscriptions is:</p>
  684. * <pre>
  685. * <code>[type, callback, target, contextOverride, argN...]</code>
  686. * </pre>
  687. * <p>And for <code>delegate()</code>:</p>
  688. * <pre>
  689. * <code>[type, callback, target, filter, contextOverride, argN...]</code>
  690. * </pre>
  691. * <p>where <code>target</code> is the node the event is being
  692. * subscribed for. You can see these signatures documented for
  693. * <code>Y.on()</code> and <code>Y.delegate()</code> respectively.</p>
  694. * <p>Whatever gets returned from the function will be stored on the
  695. * <code>subscription</code> object under
  696. * <code>subscription._extra</code>.</p></dd>
  697. * <dt><code>subMatch</code></dt>
  698. * <dd>
  699. * <p><code>function (sub, args)</code> Compares a set of
  700. * subscription arguments against a Subscription object to determine
  701. * if they match. The default implementation compares the callback
  702. * function against the second argument passed to
  703. * <code>Y.on(...)</code> or <code>node.detach(...)</code> etc.</p>
  704. * </dd>
  705. * </dl>
  706. *
  707. * @method define
  708. * @param type {String} the name of the event
  709. * @param config {Object} the prototype definition for the new event (see above)
  710. * @param force {Boolean} override an existing event (use with caution)
  711. * @return {SyntheticEvent} the subclass implementation instance created to
  712. * handle event subscriptions of this type
  713. * @static
  714. * @for Event
  715. * @since 3.1.0
  716. * @in event-synthetic
  717. */
  718. Y.Event.define = function (type, config, force) {
  719. var eventDef, Impl, synth;
  720. if (type && type.type) {
  721. eventDef = type;
  722. force = config;
  723. } else if (config) {
  724. eventDef = Y.merge({ type: type }, config);
  725. }
  726. if (eventDef) {
  727. if (force || !Y.Node.DOM_EVENTS[eventDef.type]) {
  728. Impl = function () {
  729. SyntheticEvent.apply(this, arguments);
  730. };
  731. Y.extend(Impl, SyntheticEvent, eventDef);
  732. synth = new Impl();
  733. type = synth.type;
  734. Y.Node.DOM_EVENTS[type] = Y.Env.evt.plugins[type] = {
  735. eventDef: synth,
  736. on: function () {
  737. return synth._on(toArray(arguments));
  738. },
  739. delegate: function () {
  740. return synth._on(toArray(arguments), true);
  741. },
  742. detach: function () {
  743. return synth._detach(toArray(arguments));
  744. }
  745. };
  746. }
  747. } else if (isString(type) || isArray(type)) {
  748. Y.Array.each(toArray(type), function (t) {
  749. Y.Node.DOM_EVENTS[t] = 1;
  750. });
  751. }
  752. return synth;
  753. };
  754. }, '3.4.0' ,{requires:['node-base', 'event-custom-complex']});