--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/media/js/lib/yui/yui_3.10.3/docs/event/synth-example.html Tue Jul 16 14:29:46 2013 +0200
@@ -0,0 +1,778 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Example: Creating an Arrow Event for DOM Subscription</title>
+ <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic,700italic">
+ <link rel="stylesheet" href="../../build/cssgrids/cssgrids-min.css">
+ <link rel="stylesheet" href="../assets/css/main.css">
+ <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
+ <link rel="shortcut icon" type="image/png" href="../assets/favicon.png">
+ <script src="../../build/yui/yui-min.js"></script>
+
+</head>
+<body>
+<!--
+<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>
+-->
+<div id="doc">
+ <div id="hd">
+ <h1><img src="http://yuilibrary.com/img/yui-logo.png"></h1>
+ </div>
+
+
+ <h1>Example: Creating an Arrow Event for DOM Subscription</h1>
+ <div class="yui3-g">
+ <div class="yui3-u-3-4">
+ <div id="main">
+ <div class="content"><style scoped>
+ #demo {
+ position: relative;
+ }
+ #homebase {
+ margin-left: 100px;
+ position: absolute;
+ left: 0;
+ top: 40px;
+ height: 150px;
+ width: 200px;
+ }
+ .robot {
+ height: 210px;
+ width: 180px;
+ position: absolute;
+ top: 0px;
+ left: 0;
+ outline-style: none;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+ }
+ .yui3-focused {
+ opacity: 1;
+ z-index: 1;
+ filter: alpha(opacity=100);
+ }
+ #B {
+ left: 125px;
+ }
+ #demo input {
+ margin-left: 4em;
+ }
+ #demo label {
+ font-size: 87%;
+ color: #555;
+ }
+ #detach {
+ margin-top: 150px;
+ }
+</style>
+
+<div class="intro">
+ <p>
+ This example will illustrate how to use the synthetic event creation
+ API. We'll create an <code>arrow</code> event that fires in response
+ to the user pressing the arrow keys (up, down, left, right) and adds a
+ <code>direction</code> property to the generated event.
+ </p>
+
+ <p>Subscribing to this new event will look like this:</p>
+<pre class="code prettyprint">node.on("arrow", onArrowHandler);</pre>
+
+
+ <p>
+ Support will also be added for delegation, allowing a single subscriber
+ from a node higher up the DOM tree, to listen for the new event
+ emanating from its descendant elements.
+ </p>
+
+<pre class="code prettyprint">containerNode.delegate("arrow", onArrowHandler, ".robot");</pre>
+
+ <p>
+ This example is not applicable to touch devices, since they don't have arrow keys.
+ </p>
+</div>
+
+<div class="example yui3-skin-sam">
+ <div id="demo">
+ <p>Step 1. <button type="button" id="attach" tabindex="1">subscribe</button> to the <code>arrow</code> event.<br>
+ <input type="checkbox" id="delegate" value="1" tabindex="1">
+ <label for="delegate">Use a delegated subscription</label></p>
+ <p>Step 2. Click on a toaster-bot and move it around with the arrow keys.</p>
+
+ <div id="homebase">
+ <img id="A" class="robot" tabindex="3" src="../assets/event/toast-8b-left.png" />
+ <img id="B" class="robot" tabindex="3" src="../assets/event/toast-8b-right.png" />
+ </div>
+
+ <button type="button" id="detach" tabindex="4">Detach subscriptions</button>
+</div>
+
+<script>
+YUI({ filter: 'raw' }).use('node', 'event-synthetic', 'transition', function (Y) {
+ Y.Event.define("arrow", {
+ // Webkit and IE repeat keydown when you hold down arrow keys.
+ // Opera links keypress to page scroll; others keydown.
+ // Firefox prevents page scroll via preventDefault() on either
+ // keydown or keypress.
+ _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress',
+
+ _keys: {
+ '37': 'left',
+ '38': 'up',
+ '39': 'right',
+ '40': 'down'
+ },
+
+ _keyHandler: function (e, notifier) {
+ if (this._keys[e.keyCode]) {
+ e.direction = this._keys[e.keyCode];
+ notifier.fire(e);
+ }
+ },
+
+ on: function (node, sub, notifier) {
+ sub._detacher = node.on(this._event, this._keyHandler,
+ this, notifier);
+ },
+
+ detach: function (node, sub, notifier) {
+ sub._detacher.detach();
+ },
+
+ delegate: function (node, sub, notifier, filter) {
+ sub._delegateDetacher = node.delegate(this._event, this._keyHandler,
+ filter, this, notifier);
+ },
+
+ detachDelegate: function (node, sub, notifier) {
+ sub._delegateDetacher.detach();
+ }
+ });
+
+
+ var robotA = Y.one('#A'),
+ robotB = Y.one('#B'),
+ subs,
+ moving = false;
+
+ robotA.setData('x', parseInt(robotA.getStyle('left'), 10));
+ robotA.setData('y', parseInt(robotA.getStyle('top'), 10));
+ robotB.setData('x', parseInt(robotB.getStyle('left'), 10));
+ robotB.setData('y', parseInt(robotB.getStyle('top'), 10));
+
+ // create variables for image path/filenames
+ // Use 8bit pngs for IE
+ var imgBits = (Y.UA.ie && Y.UA.ie < 9) ? '-8b-' : '-24b-',
+ imgNamePre = '../assets/event/toast' + imgBits,
+
+ imgUp = imgNamePre + 'up.png',
+ imgDown = imgNamePre + 'down.png',
+ imgLeft = imgNamePre + 'left.png',
+ imgRight = imgNamePre + 'right.png';
+
+ Y.one('#A').setAttribute('src', imgLeft);
+ Y.one('#B').setAttribute('src', imgRight);
+
+ function move(e) {
+ // to prevent page scrolling
+ e.preventDefault();
+ if(moving){
+ return; // Don't move during a transition (a move)
+ }else{
+ moving = true; // During moving, block other arrow keys from moving
+ }
+
+ var xy = this.getData(),
+ imgWidth,
+ imgHeight,
+ // var scale is used to make the image size and distance moved
+ // proportional to the Y position of the image
+ scale = (150 + xy.y) / 150,
+ moveXDistance = 40,
+ moveYDistance = 20;
+
+ switch (e.direction) {
+ case 'up':
+ if(xy.y < -100){
+ moving = false;
+ return; // Stop moving when image gets too small
+ }
+ xy.y -= Math.round(moveYDistance * scale);
+ e.target.setAttribute('src', imgUp);
+ break;
+ case 'down':
+ if(xy.y > 90){
+ moving = false;
+ return; // Stop moving when image gets too big
+ }
+ xy.y += Math.round(moveYDistance * scale);
+ e.target.setAttribute('src', imgDown);
+ break;
+ case 'left':
+ xy.x -= Math.round(moveXDistance * scale);
+ e.target.setAttribute('src', imgLeft);
+ break;
+ case 'right':
+ xy.x += Math.round(moveXDistance * scale);
+ e.target.setAttribute('src', imgRight);
+ break;
+ }
+ scale = 150 / (150 - xy.y); // calculate scale with new Y dimentions
+ imgWidth = Math.round(scale * 180) + 'px';
+ imgHeight = Math.round(scale * 210) + 'px';
+ this.transition({
+ top : (xy.y + 'px'),
+ left: (xy.x + 'px'),
+ width: imgWidth,
+ height: imgHeight,
+ duration: .8
+ }, function(){
+ moving = false; // now that move is done, allow arrow keys to move again
+ });
+
+ this.setData('x', xy.x);
+ this.setData('y', xy.y);
+ }
+
+ function detachSubs() {
+ if (subs) {
+ subs.detach();
+ subs = null;
+ Y.all('.robot').removeClass('yui3-focused');
+ }
+ }
+
+ Y.one("#attach").on("click", function (e) {
+ detachSubs();
+
+ if (Y.one("#delegate").get('checked')) {
+ subs = Y.one('#demo').delegate('arrow', move, '.robot');
+ } else {
+ subs = new Y.EventHandle([
+ robotA.on("arrow", move),
+ robotB.on("arrow", move)
+ ]);
+ }
+ });
+
+ Y.one("#detach").on("click", detachSubs);
+ Y.all('.robot').on('focus', function(e){
+ if (subs) {
+ Y.all('.robot').removeClass('yui3-focused');
+ e.target.addClass('yui3-focused');
+ }
+ });
+
+ Y.all('.robot').on('click', function(e){
+ e.target.focus();
+ });
+
+});
+</script>
+
+</div>
+
+<h2><code>on</code>, <code>fire</code>, and <code>detach</code></h2>
+
+<p>
+ The three interesting moments in the lifecycle of a DOM event subscription
+ are
+</p>
+
+<ol>
+ <li>The event is subscribed to</li>
+ <li>The event is fired</li>
+ <li>The event is unsubscribed from</li>
+</ol>
+
+<p>
+ Create a new synthetic DOM event with `Y.Event.define( <em>name</em>,
+ <em>config</em> )`. Define the implementation logic for the
+ <code>on</code> and <code>detach</code> moments in the configuration.
+ Typically the condition triggering the event firing is set up in the
+ <code>on</code> phase.
+</p>
+
+<pre class="code prettyprint">Y.Event.define("arrow", {
+ on: function (node, sub, notifier) {
+ // what happens when a subscription is made
+
+ // if (condition) {
+ notifier.fire(); // subscribers executed
+ // }
+ },
+
+ detach: function (node, sub, notifier) {
+ // what happens when a subscription is removed
+ }
+});</pre>
+
+
+<p>
+ In the case of arrow handling, the trigger is simply a key event with a
+ <code>keyCode</code> between 37 and 40. There are a few browser quirks with arrow
+ handling that warrant listening to <code>keydown</code> for some browsers and
+ <code>keypress</code> for others, so we'll take care of that transparently for <code>arrow</code>
+ subscribers.
+</p>
+
+<pre class="code prettyprint">Y.Event.define("arrow", {
+ on: function (node, sub, notifier) {
+ var directions = {
+ 37: 'left',
+ 38: 'up',
+ 39: 'right',
+ 40: 'down'
+ };
+
+ // Webkit and IE repeat keydown when you hold down arrow keys.
+ // Opera links keypress to page scroll; others keydown.
+ // Firefox prevents page scroll via preventDefault() on either
+ // keydown or keypress.
+ // Bummer to sniff, but can't test the repeating behavior, and a
+ // feature test for the scrolling would more than double the code size.
+ var eventName = (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress';
+
+ // To make detaching the associated DOM event easy, store the detach
+ // handle from the DOM subscription on the synthethic subscription
+ // object.
+ sub._detacher = node.on(eventName, function (e) {
+ // Only notify subscribers if one of the arrow keys was pressed
+ if (directions[e.keyCode]) {
+ // Add the extra property
+ e.direction = directions[e.keyCode];
+
+ // Firing the notifier event executes the arrow subscribers
+ // Pass along the key event, which will be renamed "arrow"
+ notifier.fire(e);
+ }
+ });
+ },
+
+ detach: function (node, sub, notifier) {
+ // Detach the key event subscription using the stored detach handle
+ sub._detacher.detach();
+ }
+} );</pre>
+
+
+<h2>Add Delegation Support</h2>
+<p>
+ Since the <code>arrow</code> event is simply a filtered <code>keydown</code> or <code>keypress</code> event,
+ no special handling needs to be done for delegate subscriptions. We will
+ extract the key event handler and use it for both <code>on("arrow", ...)</code> and
+ <code>delegate("arrow", ...)</code> subscriptions.
+</p>
+
+<pre class="code prettyprint">Y.Event.define("arrow", {
+ // Webkit and IE repeat keydown when you hold down arrow keys.
+ // Opera links keypress to page scroll; others keydown.
+ // Firefox prevents page scroll via preventDefault() on either
+ // keydown or keypress.
+ _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress',
+
+ _keys: {
+ '37': 'left',
+ '38': 'up',
+ '39': 'right',
+ '40': 'down'
+ },
+
+ _keyHandler: function (e, notifier) {
+ if (this._keys[e.keyCode]) {
+ e.direction = this._keys[e.keyCode];
+ notifier.fire(e);
+ }
+ },
+
+ on: function (node, sub, notifier) {
+ // Use the extended subscription signature to set the 'this' object
+ // in the callback and pass the notifier as a second parameter to
+ // _keyHandler
+ sub._detacher = node.on(this._event, this._keyHandler,
+ this, notifier);
+ },
+
+ detach: function (node, sub, notifier) {
+ sub._detacher.detach();
+ },
+
+ // Note the delegate handler receives a fourth parameter, the filter
+ // passed (e.g.) container.delegate('click', callback, '.HERE');
+ // The filter could be either a string or a function.
+ delegate: function (node, sub, notifier, filter) {
+ sub._delegateDetacher = node.delegate(this._event, this._keyHandler,
+ filter, this, notifier);
+ },
+
+ // Delegate uses a separate detach function to facilitate undoing more
+ // complex wiring created in the delegate logic above. Not needed here.
+ detachDelegate: function (node, sub, notifier) {
+ sub._delegateDetacher.detach();
+ }
+});</pre>
+
+
+<h2>Use it</h2>
+<p>
+ Subscribe to the new event or detach the event as you would any other DOM
+ event.
+</p>
+
+<pre class="code prettyprint">function move(e) {
+ // to prevent page scrolling
+ e.preventDefault();
+
+ // See full code listing to show the data set up
+ var xy = this.getData();
+
+ switch (e.direction) {
+ case 'up': xy.y -= 10; break;
+ case 'down': xy.y += 10; break;
+ case 'left': xy.x -= 10; break;
+ case 'right': xy.x += 10; break;
+ }
+
+ this.transition({
+ top : (xy.y + 'px'),
+ left: (xy.x + 'px'),
+ duration: .2
+ });
+}
+
+// Subscribe using node.on("arrow", ...);
+Y.one("#A").on("arrow", move),
+Y.one("#B").on("arrow", move)
+
+// OR using container.delegate("arrow", ...);
+subs = Y.one('#demo').delegate('arrow', move, '.robot');</pre>
+
+
+<h2>Bonus Step: to the Gallery!</h2>
+<p>
+ Synthetic events are perfect candidates for Gallery modules. There are a
+ number already hosted there, and there are plenty of UI interaction
+ patterns that would benefit from being encapsulated in synthetic
+ events.
+</p>
+
+<p>
+ The <code>arrow</code> event in this example is also
+ <a href="http://yuilibrary.com/gallery/show/event-arrow">in the gallery</a>,
+ but with additional functionality. Check out
+ <a href="https://github.com/lsmith/yui3-gallery/blob/master/build/gallery-event-arrow/gallery-event-arrow-debug.js">its source</a>
+ to see what you can do with synthetic events.
+</p>
+
+<h2>Full Code Listing</h2>
+<pre class="code prettyprint"><div id="demo">
+ <p>Step 1. <button type="button" id="attach" tabindex="1">subscribe</button> to the <code>arrow</code> event.<br>
+ <input type="checkbox" id="delegate" value="1" tabindex="1">
+ <label for="delegate">Use a delegated subscription</label></p>
+ <p>Step 2. Click on a toaster-bot and move it around with the arrow keys.</p>
+
+ <div id="homebase">
+ <img id="A" class="robot" tabindex="3" src="../assets/event/toast-8b-left.png" />
+ <img id="B" class="robot" tabindex="3" src="../assets/event/toast-8b-right.png" />
+ </div>
+
+ <button type="button" id="detach" tabindex="4">Detach subscriptions</button>
+</div>
+
+<script>
+YUI({ filter: 'raw' }).use('node', 'event-synthetic', 'transition', function (Y) {
+ Y.Event.define("arrow", {
+ // Webkit and IE repeat keydown when you hold down arrow keys.
+ // Opera links keypress to page scroll; others keydown.
+ // Firefox prevents page scroll via preventDefault() on either
+ // keydown or keypress.
+ _event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress',
+
+ _keys: {
+ '37': 'left',
+ '38': 'up',
+ '39': 'right',
+ '40': 'down'
+ },
+
+ _keyHandler: function (e, notifier) {
+ if (this._keys[e.keyCode]) {
+ e.direction = this._keys[e.keyCode];
+ notifier.fire(e);
+ }
+ },
+
+ on: function (node, sub, notifier) {
+ sub._detacher = node.on(this._event, this._keyHandler,
+ this, notifier);
+ },
+
+ detach: function (node, sub, notifier) {
+ sub._detacher.detach();
+ },
+
+ delegate: function (node, sub, notifier, filter) {
+ sub._delegateDetacher = node.delegate(this._event, this._keyHandler,
+ filter, this, notifier);
+ },
+
+ detachDelegate: function (node, sub, notifier) {
+ sub._delegateDetacher.detach();
+ }
+ });
+
+
+ var robotA = Y.one('#A'),
+ robotB = Y.one('#B'),
+ subs,
+ moving = false;
+
+ robotA.setData('x', parseInt(robotA.getStyle('left'), 10));
+ robotA.setData('y', parseInt(robotA.getStyle('top'), 10));
+ robotB.setData('x', parseInt(robotB.getStyle('left'), 10));
+ robotB.setData('y', parseInt(robotB.getStyle('top'), 10));
+
+ // create variables for image path/filenames
+ // Use 8bit pngs for IE
+ var imgBits = (Y.UA.ie && Y.UA.ie < 9) ? '-8b-' : '-24b-',
+ imgNamePre = '../assets/event/toast' + imgBits,
+
+ imgUp = imgNamePre + 'up.png',
+ imgDown = imgNamePre + 'down.png',
+ imgLeft = imgNamePre + 'left.png',
+ imgRight = imgNamePre + 'right.png';
+
+ Y.one('#A').setAttribute('src', imgLeft);
+ Y.one('#B').setAttribute('src', imgRight);
+
+ function move(e) {
+ // to prevent page scrolling
+ e.preventDefault();
+ if(moving){
+ return; // Don't move during a transition (a move)
+ }else{
+ moving = true; // During moving, block other arrow keys from moving
+ }
+
+ var xy = this.getData(),
+ imgWidth,
+ imgHeight,
+ // var scale is used to make the image size and distance moved
+ // proportional to the Y position of the image
+ scale = (150 + xy.y) / 150,
+ moveXDistance = 40,
+ moveYDistance = 20;
+
+ switch (e.direction) {
+ case 'up':
+ if(xy.y < -100){
+ moving = false;
+ return; // Stop moving when image gets too small
+ }
+ xy.y -= Math.round(moveYDistance * scale);
+ e.target.setAttribute('src', imgUp);
+ break;
+ case 'down':
+ if(xy.y > 90){
+ moving = false;
+ return; // Stop moving when image gets too big
+ }
+ xy.y += Math.round(moveYDistance * scale);
+ e.target.setAttribute('src', imgDown);
+ break;
+ case 'left':
+ xy.x -= Math.round(moveXDistance * scale);
+ e.target.setAttribute('src', imgLeft);
+ break;
+ case 'right':
+ xy.x += Math.round(moveXDistance * scale);
+ e.target.setAttribute('src', imgRight);
+ break;
+ }
+ scale = 150 / (150 - xy.y); // calculate scale with new Y dimentions
+ imgWidth = Math.round(scale * 180) + 'px';
+ imgHeight = Math.round(scale * 210) + 'px';
+ this.transition({
+ top : (xy.y + 'px'),
+ left: (xy.x + 'px'),
+ width: imgWidth,
+ height: imgHeight,
+ duration: .8
+ }, function(){
+ moving = false; // now that move is done, allow arrow keys to move again
+ });
+
+ this.setData('x', xy.x);
+ this.setData('y', xy.y);
+ }
+
+ function detachSubs() {
+ if (subs) {
+ subs.detach();
+ subs = null;
+ Y.all('.robot').removeClass('yui3-focused');
+ }
+ }
+
+ Y.one("#attach").on("click", function (e) {
+ detachSubs();
+
+ if (Y.one("#delegate").get('checked')) {
+ subs = Y.one('#demo').delegate('arrow', move, '.robot');
+ } else {
+ subs = new Y.EventHandle([
+ robotA.on("arrow", move),
+ robotB.on("arrow", move)
+ ]);
+ }
+ });
+
+ Y.one("#detach").on("click", detachSubs);
+ Y.all('.robot').on('focus', function(e){
+ if (subs) {
+ Y.all('.robot').removeClass('yui3-focused');
+ e.target.addClass('yui3-focused');
+ }
+ });
+
+ Y.all('.robot').on('click', function(e){
+ e.target.focus();
+ });
+
+});
+</script></pre>
+
+
+</div>
+ </div>
+ </div>
+
+ <div class="yui3-u-1-4">
+ <div class="sidebar">
+
+
+
+ <div class="sidebox">
+ <div class="hd">
+ <h2 class="no-toc">Examples</h2>
+ </div>
+
+ <div class="bd">
+ <ul class="examples">
+
+
+ <li data-description="Use the Event Utility to attach simple DOM event handlers.">
+ <a href="basic-example.html">Simple DOM Events</a>
+ </li>
+
+
+
+ <li data-description="Using the synthetic event API to create a DOM event that fires in response to arrow keys being pressed.">
+ <a href="synth-example.html">Creating an Arrow Event for DOM Subscription</a>
+ </li>
+
+
+
+ <li data-description="Supporting cross-device swipe gestures, using the event-move gesture events">
+ <a href="swipe-example.html">Supporting A Swipe Left Gesture</a>
+ </li>
+
+
+
+
+
+
+
+
+
+
+
+
+ </ul>
+ </div>
+ </div>
+
+
+
+ <div class="sidebox">
+ <div class="hd">
+ <h2 class="no-toc">Examples That Use This Component</h2>
+ </div>
+
+ <div class="bd">
+ <ul class="examples">
+
+
+
+
+
+
+
+
+ <li data-description="Creating an accessible menu button using the Focus Manager Node Plugin, Event's delegation support and mouseenter event, along with the Overlay widget and Node's support for the WAI-ARIA Roles and States.">
+ <a href="../node-focusmanager/node-focusmanager-button.html">Accessible Menu Button</a>
+ </li>
+
+
+
+ <li data-description="Shows how to extend the base widget class, to create your own Widgets.">
+ <a href="../widget/widget-extend.html">Extending the Base Widget Class</a>
+ </li>
+
+
+
+ <li data-description="Example Photo Browser application.">
+ <a href="../dd/photo-browser.html">Photo Browser</a>
+ </li>
+
+
+
+ <li data-description="Portal style example using Drag & Drop Event Bubbling and Animation.">
+ <a href="../dd/portal-drag.html">Portal Style Example</a>
+ </li>
+
+
+
+ <li data-description="Use IO to request data over HTTP.">
+ <a href="../io/get.html">HTTP GET to request data</a>
+ </li>
+
+
+ </ul>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div>
+</div>
+
+<script src="../assets/vendor/prettify/prettify-min.js"></script>
+<script>prettyPrint();</script>
+
+<script>
+YUI.Env.Tests = {
+ examples: [],
+ project: '../assets',
+ assets: '../assets/event',
+ name: 'synth-example',
+ title: 'Creating an Arrow Event for DOM Subscription',
+ newWindow: '',
+ auto: false
+};
+YUI.Env.Tests.examples.push('basic-example');
+YUI.Env.Tests.examples.push('synth-example');
+YUI.Env.Tests.examples.push('swipe-example');
+YUI.Env.Tests.examples.push('node-focusmanager-button');
+YUI.Env.Tests.examples.push('widget-extend');
+YUI.Env.Tests.examples.push('photo-browser');
+YUI.Env.Tests.examples.push('portal-drag');
+YUI.Env.Tests.examples.push('get');
+
+</script>
+<script src="../assets/yui/test-runner.js"></script>
+
+
+
+</body>
+</html>