2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<div class="intro">
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <p>Synthetic events are usually named abstractions that bind to existing
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith DOM events to monitor user actions for specific patterns. However, at
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith heart they are no more than a set of callbacks executed in response to
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith various triggering methods in the DOM event system.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <p>You can do all sorts of things with synthetic events, including:</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <ul>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith redefine native DOM events that behave inconsistently across
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith browsers (e.g. <a href="focus.html">`focus` and `blur`</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith provide abstract events that attach to different DOM events based on
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith the environment (e.g. <a href="touch.html#move">`gesturemovestart`
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith and family</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith create events with different subscription signatures (e.g.
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith <a href="hover.html">`hover`</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith create configurable events that only execute subscribers when
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith criteria passed during subscription are met (e.g.
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <a href="touch.html#flick">`flick`</a> or
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <a href="key.html">`key`</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith create events that encapsulate common UX patterns (e.g.
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <a href="outside.html">`clickoutside`</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith create fun little easter eggs (e.g. <a
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith href="http://yuilibrary.com/gallery/show/event-konami">`konami`</a>)
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>and more...</li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </ul>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith</div>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<h2>The hooks</h2>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>Synthetic events hook into the subscription binding and unbinding methods. Specifically:</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<ol>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>`node.on("eventName", ...)`, `Y.on("eventName", ...)`, <a href="index.html#one-time-subscriptions">and family</a></li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>`node.delegate("eventName", ...)` or `Y.delegate("eventName", ...)`</li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>`node.detach(...)` or `subscription.detach()`</li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith</ol>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>With the exception of a separate `detachDelegate()` method, the names used when defining synthetic events are the same as these basic methods.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke SmithY.Event.define("tripleclick", {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith on: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // called in response to individual subscriptions
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith delegate: function (node, subscription, notifier, filter) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // called in response to delegate subscriptions
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detach: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // called when individual subscriptions are detached in any way
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detachDelegate: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // called when delegate subscriptions are detached in any way
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith});
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<h2>Subscriptions and Notifiers</h2>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>In addition to the subscribing Node, each method receives a
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<em>subscription</em> and a <em>notifier</em>. Use the <em>subscription</em>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smithto store event handles or other data that may be needed by another method. Use
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<em>`notifier.fire(e)`</em> to dispatch the event to the callbacks that were
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithbound to it.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke SmithY.Event.define("tripleclick", {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith on: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith var count = 0;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith subscription._handle = node.on("click", function (e) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (++count === 3) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // Call notifier.fire(e) to execute subscribers.
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // Pass the triggering event facade to fire()
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith notifier.fire(e);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith } else {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith ...
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detach: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith subscription._handle.detach();
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith delegate: function (node, subscription, notifier, filter) { ... },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detachDelegate: function (node, subscription, notifier) { ... }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith});
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>Subscribers to the synthetic event should receive a `DOMEventFacade`. The
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smitheasiest way to provide one is to pass the triggering DOM event's facade to
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith`notifier.fire(e)`. The facade's `e.type` will be updated to the name of the
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smithsynth. You will also have the opportunity to add extra data to the event
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smithbefore dispatching to the subscription callbacks.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke SmithY.Event.define('multiclick', {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith on: function (node, sub, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith var count = 0,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith sub._handle = node.on('click', function (e) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count++;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (timer) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer.cancel();
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer = Y.later(200, null, function () {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith e.clicks = count;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count = 0;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith // subscribers will get e with e.type == 'multiclick'
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith // and extra property e.clicks
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith notifier.fire(e);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith ...
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith});
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<h2>Delegation support</h2>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>The `delegate` function implementation takes an extra argument, the `filter` that was passed <code>node.delegate(type, callback, <em>HERE</em>)</code>. It's your responsibility to make sense of this filter for your event.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<p>Typically, it is just passed along to a `node.delegate(...)` call against another event, deferring the filtration to the core `delegate()` method.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke SmithY.Event.define("tripleclick", {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith on: function (node, subscription, notifier) { ... },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detach: function (node, subscription, notifier) { ... },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith delegate: function (node, subscription, notifier, filter) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith var activeNode = null,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count = 0,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith subscription._handle = node.delegate("click", function (e) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (timer) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer.cancel();
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (this !== activeNode) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith activeNode = this;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count = 0;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (++count === 3) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // Call notifier.fire(e) just as with `on`
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith notifier.fire(e);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith } else {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer = Y.later(300, null, function () {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count = 0;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith }, filter); // filter is passed on to the underlying `delegate()` call
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith detachDelegate: function (node, subscription, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith subscription._handle.detach();
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith});
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<h2>Extra Arguments</h2>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>Supply a `processArgs` method in the event definition to support a custom
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithsubscription signature. The method receives two arguments:</p>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<ol>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith <li>an array of the subscription arguments for analysis</li>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith <li>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith a boolean `true` if the subscription is being made through
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith `delegate(...)`
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith </li>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith</ol>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>If this method is supplied, it</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith<ul>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <strong>MUST</strong> remove the extra arguments from the arg array
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith that is passed in, and
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith <strong>SHOULD</strong> return the extra data relevant to the
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith subscription.
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith </li>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith</ul>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>The same `processArgs` method is used by both `on` and `delegate`, but there
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithare various signatures to account for. The easiest way to accept extra
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smitharguments is to require them from index 3 in the argument list. It's also best
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithto limit the number of extra arguments to one and require an object literal to
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithallow for future changes.</p>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith// for an event that takes one extra param
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke SmithprocessArgs: function (args, isDelegate) {
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith var extra = args[3];
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith // remove the extra arguments from the array
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith args.splice(3,1);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith return extra;
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith}
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith// for an event that takes three extra args
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke SmithprocessArgs: function (args, isDelegate) {
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith return args.splice(3,3);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith}
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>Requiring extra params start at index 3 of the `args` array results in the
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithfollowing subscription signatures:</p>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithvar extraConfig = { ... };
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith// Third argument for node.on() and node.delegate
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithnode.on('extraArgEvent', callback, extraConfig, thisOverride, arg...);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithnode.delegate('extraArgEvent', callback, extraConfig, filter, thisOverride, arg...);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith// Fourth argument for Y.on() and Y.delegate
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke SmithY.on('extraArgEvent', callback, targetSelector, extraConfig, thisOverride, arg...);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke SmithY.delegate('extraArgEvent', callback, parentSelector, extraConfig, filter, thisOverride, arg...);
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>For some custom signatures, the placement of the extra argument for
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithimplementers using `Y.on()` or `Y.delegate()` may look awkward. Sometimes you
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithcan support extras at other indexes if you can reliably tell that the argument
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithis not part of
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<a href="index.html#binding-this-and-additional-callback-arguments">the extended
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithsignature for `on(...)` or `delegate(...)`</a>. See the <a
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithhref="{{apiDocs}}/files/event_js_hover.js.html">source for the "hover"
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithevent</a> for an example of supporting multiple signatures.</p>
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>The return value of `processArgs` is assigned to `subscription._extras` for the `on` and `delegate` definition methods.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke SmithY.Event.define('multiclick', {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith processArgs: function (args, isDelegate) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // The args list will look like this coming in:
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith // [ type, callback, node, (extras...), [filter,] thisObj, arg0...argN ]
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith return args.splice(3,1)[1] || {};
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith // Custom subscription signatures don't change the params of on/delegate
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith on: function (node, sub, notifier) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith var clicks = 0,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith // data returned from processArgs is available at sub._extras
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith min = sub._extras.minClicks || 3,
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith max = sub._extras.maxClicks || 10,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith sub._handle = node.on('click', function (e) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (timer) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer.cancel();
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (++clicks === max) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith e.clicks = clicks;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith notifier.fire(e);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith } else {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith timer = Y.later(200, null, function () {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith if (clicks > min) {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith e.clicks = count;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith notifier.fire(e);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith count = 0;
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith }
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith });
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith },
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith ...
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith});
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>Usage of this synthetic event then expects a third argument as a
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithconfiguration object with `minClicks` and `maxClicks` properties.</p>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smithnode.on('multiclick', obj.method, {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith minClicks: 5,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith maxClicks: 8
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith}, obj);
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith// extra args are supplied before the delegate filter
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smithcontainer.delegate('multiclick', doSomething, {
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith minClicks: 3,
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith maxClicks: 55
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith}, '.clickable');
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith```
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<h2>A Tip to Make Your Synth Definition Smaller</h2>
2e7441169df0fcc324f2d44947beba7d237f5a37Luke Smith
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<p>If the only difference between your `on` and `delegate` definitions is which method is used to bind to the supporting events, then you can propably get away with defining `delegate` and aliasing it to `on` (and so with `detach` and `detachDelegate`). See the
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smith<a href="{{apiDocs}}/files/event_js_hover.js.html">source for the "hover"
42f04b06465678a6d795fc4c3aa4bcc5aa8bfda8Luke Smithevent</a> for an example of this approach.</p>