src/cm/media/js/lib/yui/yui_3.10.3/docs/event/synths.html
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 <!DOCTYPE html>
       
     2 <html lang="en">
       
     3 <head>
       
     4     <meta charset="utf-8">
       
     5     <title>Creating Synthetic Events</title>
       
     6     <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic,700italic">
       
     7     <link rel="stylesheet" href="../../build/cssgrids/cssgrids-min.css">
       
     8     <link rel="stylesheet" href="../assets/css/main.css">
       
     9     <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
       
    10     <link rel="shortcut icon" type="image/png" href="../assets/favicon.png">
       
    11     <script src="../../build/yui/yui-min.js"></script>
       
    12     
       
    13 </head>
       
    14 <body>
       
    15 <!--
       
    16 <a href="https://github.com/yui/yui3"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a>
       
    17 -->
       
    18 <div id="doc">
       
    19     <div id="hd">
       
    20         <h1><img src="http://yuilibrary.com/img/yui-logo.png"></h1>
       
    21     </div>
       
    22     
       
    23         <a href="#toc" class="jump">Jump to Table of Contents</a>
       
    24     
       
    25 
       
    26             <h1>Creating Synthetic Events</h1>
       
    27     <div class="yui3-g">
       
    28         <div class="yui3-u-3-4">
       
    29             <div id="main">
       
    30                 <div class="content"><div class="intro">
       
    31     <p>Synthetic events are usually named abstractions that bind to existing
       
    32     DOM events to monitor user actions for specific patterns.  However, at 
       
    33     heart they are no more than a set of callbacks executed in response to
       
    34     various triggering methods in the DOM event system.</p>
       
    35     
       
    36     <p>You can do all sorts of things with synthetic events, including:</p>
       
    37 
       
    38     <ul>
       
    39         <li>
       
    40             redefine native DOM events that behave inconsistently across
       
    41             browsers (e.g. <a href="focus.html"><code>focus</code> and <code>blur</code></a>)
       
    42         </li>
       
    43         <li>
       
    44             provide abstract events that attach to different DOM events based on
       
    45             the environment (e.g. <a href="touch.html#move"><code>gesturemovestart</code>
       
    46             and family</a>)
       
    47         </li>
       
    48         <li>
       
    49             create events with different subscription signatures (e.g.
       
    50             <a href="hover.html"><code>hover</code></a>)
       
    51         </li>
       
    52         <li>
       
    53             create configurable events that only execute subscribers when
       
    54             criteria passed during subscription are met (e.g.
       
    55             <a href="touch.html#flick"><code>flick</code></a> or
       
    56             <a href="key.html"><code>key</code></a>)
       
    57         </li>
       
    58         <li>
       
    59             create events that encapsulate common UX patterns (e.g.
       
    60             <a href="outside.html"><code>clickoutside</code></a>)
       
    61         </li>
       
    62         <li>
       
    63             create fun little easter eggs (e.g. <a
       
    64             href="http://yuilibrary.com/gallery/show/event-konami"><code>konami</code></a>)
       
    65         </li>
       
    66         <li>and more...</li>
       
    67     </ul>
       
    68 </div>
       
    69 
       
    70 <h2 id="the-hooks">The hooks</h2>
       
    71 
       
    72 <p>Synthetic events hook into the subscription binding and unbinding methods.  Specifically:</p>
       
    73 
       
    74 <ol>
       
    75     <li><code>node.on(&quot;eventName&quot;, ...)</code>, <code>Y.on(&quot;eventName&quot;, ...)</code>, <a href="index.html#one-time-subscriptions">and family</a></li>
       
    76     <li><code>node.delegate(&quot;eventName&quot;, ...)</code> or <code>Y.delegate(&quot;eventName&quot;, ...)</code></li>
       
    77     <li><code>node.detach(...)</code> or <code>subscription.detach()</code></li>
       
    78 </ol>
       
    79 
       
    80 <p>With the exception of a separate <code>detachDelegate()</code> method, the names used when defining synthetic events are the same as these basic methods.</p>
       
    81 
       
    82 <pre class="code prettyprint">Y.Event.define(&quot;tripleclick&quot;, {
       
    83     on: function (node, subscription, notifier) {
       
    84         &#x2F;&#x2F; called in response to individual subscriptions
       
    85     },
       
    86 
       
    87     delegate: function (node, subscription, notifier, filter) {
       
    88         &#x2F;&#x2F; called in response to delegate subscriptions
       
    89     },
       
    90 
       
    91     detach: function (node, subscription, notifier) {
       
    92         &#x2F;&#x2F; called when individual subscriptions are detached in any way
       
    93     },
       
    94 
       
    95     detachDelegate: function (node, subscription, notifier) {
       
    96         &#x2F;&#x2F; called when delegate subscriptions are detached in any way
       
    97     }
       
    98 });</pre>
       
    99 
       
   100 
       
   101 <h2 id="subscriptions-and-notifiers">Subscriptions and Notifiers</h2>
       
   102 
       
   103 <p>In addition to the subscribing Node, each method receives a
       
   104 <em>subscription</em> and a <em>notifier</em>.  Use the <em>subscription</em>
       
   105 to store event handles or other data that may be needed by another method.  Use
       
   106 <em><code>notifier.fire(e)</code></em> to dispatch the event to the callbacks that were
       
   107 bound to it.</p>
       
   108 
       
   109 <pre class="code prettyprint">Y.Event.define(&quot;tripleclick&quot;, {
       
   110     on: function (node, subscription, notifier) {
       
   111         var count = 0;
       
   112 
       
   113         subscription._handle = node.on(&quot;click&quot;, function (e) {
       
   114             if (++count === 3) {
       
   115                 &#x2F;&#x2F; Call notifier.fire(e) to execute subscribers.
       
   116                 &#x2F;&#x2F; Pass the triggering event facade to fire()
       
   117                 notifier.fire(e);
       
   118             } else {
       
   119                 ...
       
   120             }
       
   121         });
       
   122     },
       
   123 
       
   124     detach: function (node, subscription, notifier) {
       
   125         subscription._handle.detach();
       
   126     },
       
   127 
       
   128     delegate: function (node, subscription, notifier, filter) { ... },
       
   129     detachDelegate: function (node, subscription, notifier) { ... }
       
   130 });</pre>
       
   131 
       
   132 
       
   133 <p>Subscribers to the synthetic event should receive a <code>DOMEventFacade</code>.  The
       
   134 easiest way to provide one is to pass the triggering DOM event's facade to
       
   135 <code>notifier.fire(e)</code>.  The facade's <code>e.type</code> will be updated to the name of the
       
   136 synth.  You will also have the opportunity to add extra data to the event
       
   137 before dispatching to the subscription callbacks.</p>
       
   138 
       
   139 <pre class="code prettyprint">Y.Event.define(&#x27;multiclick&#x27;, {
       
   140     on: function (node, sub, notifier) {
       
   141         var count = 0,
       
   142             timer;
       
   143 
       
   144         sub._handle = node.on(&#x27;click&#x27;, function (e) {
       
   145             count++;
       
   146 
       
   147             if (timer) {
       
   148                 timer.cancel();
       
   149             }
       
   150 
       
   151             timer = Y.later(200, null, function () {
       
   152                 e.clicks = count;
       
   153                 count = 0;
       
   154                 
       
   155                 &#x2F;&#x2F; subscribers will get e with e.type == &#x27;multiclick&#x27;
       
   156                 &#x2F;&#x2F; and extra property e.clicks
       
   157                 notifier.fire(e);
       
   158             });
       
   159         });
       
   160     },
       
   161     ...
       
   162 });</pre>
       
   163 
       
   164 
       
   165 <h2 id="delegation-support">Delegation support</h2>
       
   166 
       
   167 <p>The <code>delegate</code> function implementation takes an extra argument, the <code>filter</code> 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>
       
   168 
       
   169 <p>Typically, it is just passed along to a <code>node.delegate(...)</code> call against another event, deferring the filtration to the core <code>delegate()</code> method.</p>
       
   170 
       
   171 <pre class="code prettyprint">Y.Event.define(&quot;tripleclick&quot;, {
       
   172     on: function (node, subscription, notifier) { ...  },
       
   173     detach: function (node, subscription, notifier) { ...  },
       
   174 
       
   175     delegate: function (node, subscription, notifier, filter) {
       
   176         var activeNode = null,
       
   177             count = 0,
       
   178             timer;
       
   179 
       
   180         subscription._handle = node.delegate(&quot;click&quot;, function (e) {
       
   181             if (timer) {
       
   182                 timer.cancel();
       
   183             }
       
   184 
       
   185             if (this !== activeNode) {
       
   186                 activeNode = this;
       
   187                 count = 0;
       
   188             }
       
   189 
       
   190             if (++count === 3) {
       
   191                 &#x2F;&#x2F; Call notifier.fire(e) just as with &#x60;on&#x60;
       
   192                 notifier.fire(e);
       
   193             } else {
       
   194                 timer = Y.later(300, null, function () {
       
   195                     count = 0;
       
   196                 });
       
   197             }
       
   198         }, filter); &#x2F;&#x2F; filter is passed on to the underlying &#x60;delegate()&#x60; call
       
   199     },
       
   200 
       
   201     detachDelegate: function (node, subscription, notifier) {
       
   202         subscription._handle.detach();
       
   203     }
       
   204 });</pre>
       
   205 
       
   206 
       
   207 <h2 id="extra-arguments">Extra Arguments</h2>
       
   208 
       
   209 <p>Supply a <code>processArgs</code> method in the event definition to support a custom
       
   210 subscription signature.  The method receives two arguments:</p>
       
   211 
       
   212 <ol>
       
   213     <li>an array of the subscription arguments for analysis</li>
       
   214     <li>
       
   215         a boolean <code>true</code> if the subscription is being made through
       
   216         <code>delegate(...)</code>
       
   217     </li>
       
   218 </ol>
       
   219 
       
   220 <p>If this method is supplied, it</p>
       
   221 <ul>
       
   222     <li>
       
   223         <strong>MUST</strong> remove the extra arguments from the arg array
       
   224         that is passed in, and
       
   225     </li>
       
   226     <li>
       
   227         <strong>SHOULD</strong> return the extra data relevant to the
       
   228         subscription.
       
   229     </li>
       
   230 </ul>
       
   231 
       
   232 
       
   233 <p>The same <code>processArgs</code> method is used by both <code>on</code> and <code>delegate</code>, but there
       
   234 are various signatures to account for.  The easiest way to accept extra
       
   235 arguments is to require them from index 3 in the argument list.  It's also best
       
   236 to limit the number of extra arguments to one and require an object literal to
       
   237 allow for future changes.</p>
       
   238 
       
   239 <pre class="code prettyprint">&#x2F;&#x2F; for an event that takes one extra param
       
   240 processArgs: function (args, isDelegate) {
       
   241     var extra = args[3];
       
   242     
       
   243     &#x2F;&#x2F; remove the extra arguments from the array
       
   244     args.splice(3,1);
       
   245 
       
   246     return extra;
       
   247 }
       
   248 
       
   249 &#x2F;&#x2F; for an event that takes three extra args
       
   250 processArgs: function (args, isDelegate) {
       
   251     return args.splice(3,3);
       
   252 }</pre>
       
   253 
       
   254 
       
   255 <p>Requiring extra params start at index 3 of the <code>args</code> array results in the
       
   256 following subscription signatures:</p>
       
   257 <pre class="code prettyprint">var extraConfig = { ... };
       
   258 
       
   259 &#x2F;&#x2F; Third argument for node.on() and node.delegate
       
   260 node.on(&#x27;extraArgEvent&#x27;, callback, extraConfig, thisOverride, arg...);
       
   261 node.delegate(&#x27;extraArgEvent&#x27;, callback, extraConfig, filter, thisOverride, arg...);
       
   262 
       
   263 &#x2F;&#x2F; Fourth argument for Y.on() and Y.delegate
       
   264 Y.on(&#x27;extraArgEvent&#x27;, callback, targetSelector, extraConfig, thisOverride, arg...);
       
   265 Y.delegate(&#x27;extraArgEvent&#x27;, callback, parentSelector, extraConfig, filter, thisOverride, arg...);</pre>
       
   266 
       
   267 
       
   268 <p>For some custom signatures, the placement of the extra argument for
       
   269 implementers using <code>Y.on()</code> or <code>Y.delegate()</code> may look awkward.  Sometimes you
       
   270 can support extras at other indexes if you can reliably tell that the argument
       
   271 is not part of
       
   272 <a href="index.html#binding-this-and-additional-callback-arguments">the extended
       
   273 signature for <code>on(...)</code> or <code>delegate(...)</code></a>. See the <a
       
   274 href="http://yuilibrary.com/yui/docs/api/files/event_js_hover.js.html">source for the "hover"
       
   275 event</a> for an example of supporting multiple signatures.</p>
       
   276 
       
   277 <p>The return value of <code>processArgs</code> is assigned to <code>subscription._extras</code> for the <code>on</code> and <code>delegate</code> definition methods.</p>
       
   278 
       
   279 <pre class="code prettyprint">Y.Event.define(&#x27;multiclick&#x27;, {
       
   280     processArgs: function (args, isDelegate) {
       
   281         &#x2F;&#x2F; The args list will look like this coming in:
       
   282         &#x2F;&#x2F; [ type, callback, node, (extras...), [filter,] thisObj, arg0...argN ]
       
   283         return args.splice(3,1)[1] || {};
       
   284     },
       
   285 
       
   286     &#x2F;&#x2F; Custom subscription signatures don&#x27;t change the params of on&#x2F;delegate
       
   287     on: function (node, sub, notifier) {
       
   288         var clicks = 0,
       
   289             &#x2F;&#x2F; data returned from processArgs is available at sub._extras
       
   290             min = sub._extras.minClicks || 3,
       
   291             max = sub._extras.maxClicks || 10,
       
   292             timer;
       
   293 
       
   294         sub._handle = node.on(&#x27;click&#x27;, function (e) {
       
   295             if (timer) {
       
   296                 timer.cancel();
       
   297             }
       
   298 
       
   299             if (++clicks === max) {
       
   300                 e.clicks = clicks;
       
   301                 notifier.fire(e);
       
   302             } else {
       
   303                 timer = Y.later(200, null, function () {
       
   304                     if (clicks &gt; min) {
       
   305                         e.clicks = count;
       
   306                         notifier.fire(e);
       
   307                     }
       
   308                     count = 0;
       
   309                 });
       
   310             }
       
   311         });
       
   312     },
       
   313     ...
       
   314 });</pre>
       
   315 
       
   316 
       
   317 <p>Usage of this synthetic event then expects a third argument as a
       
   318 configuration object with <code>minClicks</code> and <code>maxClicks</code> properties.</p>
       
   319 
       
   320 <pre class="code prettyprint">node.on(&#x27;multiclick&#x27;, obj.method, {
       
   321     minClicks: 5,
       
   322     maxClicks: 8
       
   323 }, obj);
       
   324 
       
   325 &#x2F;&#x2F; extra args are supplied before the delegate filter
       
   326 container.delegate(&#x27;multiclick&#x27;, doSomething, {
       
   327     minClicks: 3,
       
   328     maxClicks: 55
       
   329 }, &#x27;.clickable&#x27;);</pre>
       
   330 
       
   331 
       
   332 <h2 id="a-tip-to-make-your-synth-definition-smaller">A Tip to Make Your Synth Definition Smaller</h2>
       
   333 
       
   334 <p>If the only difference between your <code>on</code> and <code>delegate</code> definitions is which method is used to bind to the supporting events, then you can propably get away with defining <code>delegate</code> and aliasing it to <code>on</code> (and so with <code>detach</code> and <code>detachDelegate</code>).  See the
       
   335 <a href="http://yuilibrary.com/yui/docs/api/files/event_js_hover.js.html">source for the "hover"
       
   336 event</a> for an example of this approach.</p>
       
   337 </div>
       
   338             </div>
       
   339         </div>
       
   340 
       
   341         <div class="yui3-u-1-4">
       
   342             <div class="sidebar">
       
   343                 
       
   344                     <div id="toc" class="sidebox">
       
   345                         <div class="hd">
       
   346                             <h2 class="no-toc">Table of Contents</h2>
       
   347                         </div>
       
   348 
       
   349                         <div class="bd">
       
   350                             <ul class="toc">
       
   351 <li>
       
   352 <a href="#the-hooks">The hooks</a>
       
   353 </li>
       
   354 <li>
       
   355 <a href="#subscriptions-and-notifiers">Subscriptions and Notifiers</a>
       
   356 </li>
       
   357 <li>
       
   358 <a href="#delegation-support">Delegation support</a>
       
   359 </li>
       
   360 <li>
       
   361 <a href="#extra-arguments">Extra Arguments</a>
       
   362 </li>
       
   363 <li>
       
   364 <a href="#a-tip-to-make-your-synth-definition-smaller">A Tip to Make Your Synth Definition Smaller</a>
       
   365 </li>
       
   366 </ul>
       
   367                         </div>
       
   368                     </div>
       
   369                 
       
   370 
       
   371                 
       
   372                     <div class="sidebox">
       
   373                         <div class="hd">
       
   374                             <h2 class="no-toc">Examples</h2>
       
   375                         </div>
       
   376 
       
   377                         <div class="bd">
       
   378                             <ul class="examples">
       
   379                                 
       
   380                                     
       
   381                                         <li data-description="Use the Event Utility to attach simple DOM event handlers.">
       
   382                                             <a href="basic-example.html">Simple DOM Events</a>
       
   383                                         </li>
       
   384                                     
       
   385                                 
       
   386                                     
       
   387                                         <li data-description="Using the synthetic event API to create a DOM event that fires in response to arrow keys being pressed.">
       
   388                                             <a href="synth-example.html">Creating an Arrow Event for DOM Subscription</a>
       
   389                                         </li>
       
   390                                     
       
   391                                 
       
   392                                     
       
   393                                         <li data-description="Supporting cross-device swipe gestures, using the event-move gesture events">
       
   394                                             <a href="swipe-example.html">Supporting A Swipe Left Gesture</a>
       
   395                                         </li>
       
   396                                     
       
   397                                 
       
   398                                     
       
   399                                 
       
   400                                     
       
   401                                 
       
   402                                     
       
   403                                 
       
   404                                     
       
   405                                 
       
   406                                     
       
   407                                 
       
   408                             </ul>
       
   409                         </div>
       
   410                     </div>
       
   411                 
       
   412 
       
   413                 
       
   414                     <div class="sidebox">
       
   415                         <div class="hd">
       
   416                             <h2 class="no-toc">Examples That Use This Component</h2>
       
   417                         </div>
       
   418 
       
   419                         <div class="bd">
       
   420                             <ul class="examples">
       
   421                                 
       
   422                                     
       
   423                                 
       
   424                                     
       
   425                                 
       
   426                                     
       
   427                                 
       
   428                                     
       
   429                                         <li data-description="Creating an accessible menu button using the Focus Manager Node Plugin, Event&#x27;s delegation support and mouseenter event, along with the Overlay widget and Node&#x27;s support for the WAI-ARIA Roles and States.">
       
   430                                             <a href="../node-focusmanager/node-focusmanager-button.html">Accessible Menu Button</a>
       
   431                                         </li>
       
   432                                     
       
   433                                 
       
   434                                     
       
   435                                         <li data-description="Shows how to extend the base widget class, to create your own Widgets.">
       
   436                                             <a href="../widget/widget-extend.html">Extending the Base Widget Class</a>
       
   437                                         </li>
       
   438                                     
       
   439                                 
       
   440                                     
       
   441                                         <li data-description="Example Photo Browser application.">
       
   442                                             <a href="../dd/photo-browser.html">Photo Browser</a>
       
   443                                         </li>
       
   444                                     
       
   445                                 
       
   446                                     
       
   447                                         <li data-description="Portal style example using Drag &amp; Drop Event Bubbling and Animation.">
       
   448                                             <a href="../dd/portal-drag.html">Portal Style Example</a>
       
   449                                         </li>
       
   450                                     
       
   451                                 
       
   452                                     
       
   453                                         <li data-description="Use IO to request data over HTTP.">
       
   454                                             <a href="../io/get.html">HTTP GET to request data</a>
       
   455                                         </li>
       
   456                                     
       
   457                                 
       
   458                             </ul>
       
   459                         </div>
       
   460                     </div>
       
   461                 
       
   462             </div>
       
   463         </div>
       
   464     </div>
       
   465 </div>
       
   466 
       
   467 <script src="../assets/vendor/prettify/prettify-min.js"></script>
       
   468 <script>prettyPrint();</script>
       
   469 
       
   470 <script>
       
   471 YUI.Env.Tests = {
       
   472     examples: [],
       
   473     project: '../assets',
       
   474     assets: '../assets/event',
       
   475     name: 'event',
       
   476     title: 'Creating Synthetic Events',
       
   477     newWindow: '',
       
   478     auto:  false 
       
   479 };
       
   480 YUI.Env.Tests.examples.push('basic-example');
       
   481 YUI.Env.Tests.examples.push('synth-example');
       
   482 YUI.Env.Tests.examples.push('swipe-example');
       
   483 YUI.Env.Tests.examples.push('node-focusmanager-button');
       
   484 YUI.Env.Tests.examples.push('widget-extend');
       
   485 YUI.Env.Tests.examples.push('photo-browser');
       
   486 YUI.Env.Tests.examples.push('portal-drag');
       
   487 YUI.Env.Tests.examples.push('get');
       
   488 
       
   489 </script>
       
   490 <script src="../assets/yui/test-runner.js"></script>
       
   491 
       
   492 
       
   493 
       
   494 </body>
       
   495 </html>