src/cm/media/js/lib/yui/yui_3.10.3/docs/promise/plugin-example.html
author Yves-Marie Haussonne <ymh.work+github@gmail.com>
Fri, 09 May 2014 18:35:26 +0200
changeset 656 a84519031134
parent 525 89ef5ed3c48b
permissions -rw-r--r--
add link to "privacy policy" in the header test

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Example: Creating a Node Plugin that chains transitions</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>
    
        <a href="#toc" class="jump">Jump to Table of Contents</a>
    

            <h1>Example: Creating a Node Plugin that chains transitions</h1>
    <div class="yui3-g">
        <div class="yui3-u-3-4">
            <div id="main">
                <div class="content"><style scoped>
    #square {
        width: 100px;
        height: 100px;
        background: gray;
        position: relative;
        margin: 20px;
    }
</style>


<div class="intro">
    <p>
        In order to run transitions sequentially, you would normally have to use the callback provided by <code>node.transition()</code>. This example shows how to create your own Node plugin based on promises that lets you chain CSS transitions.
    </p>
</div>

<div class="example yui3-skin-sam">
    <button id="without-plugin">Without Plugin</button>
<button id="with-plugin">With Plugin</button>
<div id="square"></div>

    <script>
YUI().use('promise', 'transition', 'node-pluginhost', function (Y) {

// NodePromise will represent a YUI Node
function NodePromise() {
    NodePromise.superclass.constructor.apply(this, arguments);
}
Y.extend(NodePromise, Y.Promise);

// This method takes the same "config" parameter as Node's transition method
// but returns a NodePromise instead
NodePromise.prototype.transition = function (config) {
    // We call this.then to ensure the promise is fulfilled.
    // Since we will be creating a chain of transitions this means we will be
    // waiting for the previous transition to end
    return this.then(function (node) {
        // As noted in the user guide, returning a promise inside the then()
        // callback causes the promise returned by then() to be synced with this
        // new promise. This is a way to control when the returned promise is
        // fulfilled
        return new Y.Promise(function (fulfill, reject) {
            node.transition(config, function () {
                // The transition is done, signal the promise that all is ready
                // by fulfilling it with the same node
                fulfill(node);
            });
        });
    });
};

function PromisePlugin(config) {
    // Create a private NodePromise instance that points to the plugin host
    this._promise = new NodePromise(function (fulfill) {
        // Since this is a Node plugin, config.host will be an instance of Node
        fulfill(config.host);
    });
}

// Set up the plugin's namespace
PromisePlugin.NS = 'promise';

PromisePlugin.prototype.transition = function (config) {
    // Simply point to the private promise's transition method
    return this._promise.transition(config);
};


var square = Y.one('#square');
square.plug(PromisePlugin);

function resetStyles() {
    square.setStyles({
        width: '100px',
        height: '100px',
        left: '0'
    });
}

Y.one('#without-plugin').on('click', function () {
    resetStyles();
    square
        .transition({width: '300px'})
        .transition({height: '300px'})
        .transition({left: '200px'});
});
Y.one('#with-plugin').on('click', function () {
    resetStyles();
    square.promise
        .transition({width: '300px'})
        .transition({height: '300px'})
        .transition({left: '200px'});
});

});
</script>

</div>

<h2 id="using-promises-to-chain-css-transitions">Using Promises to Chain CSS Transitions</h2>

<h3 id="the-plan">The plan</h3>

<p>Plugins are a way to add functionality to Node without modifying its existing methods. They also are usually subclasses of Plugin.Base that contain various methods to interact with in a different way with a node. In our case we will skip the use of Plugin.Base to focus on returning promises from a plugin method.</p>

<p>The plan is to create a Promise subclass that represents a Node and store one of these promises in the plugin instance. Then the plugin's <code>transition</code> method will return a new promise based on the one already stored.</p>

<h3 id="creating-a-promise-subclass">Creating a Promise Subclass</h3>

<p>Promises represent a value. Since we want to chain transitions on a Node we need to create a Promise sublcass that represents a Node. Promises can be extended the same way as any other YUI class by using <a href="http://yuilibrary.com/yui/docs/api//classes/YUI.html#method_extend"><code>Y.extend</code></a>.</p>

<pre class="code prettyprint">&#x2F;&#x2F; NodePromise will represent a YUI Node
function NodePromise() {
    NodePromise.superclass.constructor.apply(this, arguments);
}
Y.extend(NodePromise, Y.Promise);</pre>


<p>The next step is to add the <code>transition()</code> method to this promise and have it return a promise that is fulfilled when the transition is completed.</p>

<pre class="code prettyprint">&#x2F;&#x2F; This method takes the same &quot;config&quot; parameter as Node&#x27;s transition method
&#x2F;&#x2F; but returns a NodePromise instead
NodePromise.prototype.transition = function (config) {
    &#x2F;&#x2F; We call this.then to ensure the promise is fulfilled.
    &#x2F;&#x2F; Since we will be creating a chain of transitions this means we will be
    &#x2F;&#x2F; waiting for the previous transition to end
    return this.then(function (node) {
        &#x2F;&#x2F; As noted in the user guide, returning a promise inside the then()
        &#x2F;&#x2F; callback causes the promise returned by then() to be synced with this
        &#x2F;&#x2F; new promise. This is a way to control when the returned promise is
        &#x2F;&#x2F; fulfilled
        return new Y.Promise(function (fulfill, reject) {
            node.transition(config, function () {
                &#x2F;&#x2F; The transition is done, signal the promise that all is ready
                &#x2F;&#x2F; by fulfilling it with the same node
                fulfill(node);
            });
        });
    });
};</pre>


<h3 id="creating-the-plugin">Creating the Plugin</h3>

<p>Our plugin is a very simple class that contains a NodePromise. In order for it to let us write chains of transitions like <code>node.promise.transition(config1).transition(config2)</code> we will add a <code>transition</code> method to it that simply points to the NodePromise's same method.</p>

<pre class="code prettyprint">function PromisePlugin(config) {
    &#x2F;&#x2F; Create a private NodePromise instance that points to the plugin host
    this._promise = new NodePromise(function (fulfill) {
        &#x2F;&#x2F; Since this is a Node plugin, config.host will be an instance of Node
        fulfill(config.host);
    });
}

&#x2F;&#x2F; Set up the plugin&#x27;s namespace
PromisePlugin.NS = &#x27;promise&#x27;;

PromisePlugin.prototype.transition = function (config) {
    &#x2F;&#x2F; Simply point to the private promise&#x27;s transition method
    return this._promise.transition(config);
};</pre>


<h3 id="using-the-plugin">Using the Plugin</h3>

<p>Now that we have the plugin ready, we can easily chain transitions from the plugin instance:</p>

<pre class="code prettyprint">var square = Y.one(&#x27;#square&#x27;);
square.plug(PromisePlugin);

&#x2F;&#x2F; run a sequence of transitions
square.promise
    .transition({width: &#x27;300px&#x27;})
    .transition({height: &#x27;300px&#x27;})
    .transition({left: &#x27;200px&#x27;});</pre>


<h3 id="fullcode">Full Code Listing</h3>
<h4 id="html">HTML</h4>
<pre class="code prettyprint">&lt;button id=&quot;without-plugin&quot;&gt;Without Plugin&lt;&#x2F;button&gt;
&lt;button id=&quot;with-plugin&quot;&gt;With Plugin&lt;&#x2F;button&gt;
&lt;div id=&quot;square&quot;&gt;&lt;&#x2F;div&gt;</pre>


<h4 id="css">CSS</h4>
<pre class="code prettyprint">&lt;style scoped&gt;
    #square {
        width: 100px;
        height: 100px;
        background: gray;
        position: relative;
        margin: 20px;
    }
&lt;&#x2F;style&gt;</pre>


<h4 id="javascript">JavaScript</h4>
<pre class="code prettyprint">&lt;script&gt;
YUI().use(&#x27;promise&#x27;, &#x27;transition&#x27;, &#x27;node-pluginhost&#x27;, function (Y) {

&#x2F;&#x2F; NodePromise will represent a YUI Node
function NodePromise() {
    NodePromise.superclass.constructor.apply(this, arguments);
}
Y.extend(NodePromise, Y.Promise);

&#x2F;&#x2F; This method takes the same &quot;config&quot; parameter as Node&#x27;s transition method
&#x2F;&#x2F; but returns a NodePromise instead
NodePromise.prototype.transition = function (config) {
    &#x2F;&#x2F; We call this.then to ensure the promise is fulfilled.
    &#x2F;&#x2F; Since we will be creating a chain of transitions this means we will be
    &#x2F;&#x2F; waiting for the previous transition to end
    return this.then(function (node) {
        &#x2F;&#x2F; As noted in the user guide, returning a promise inside the then()
        &#x2F;&#x2F; callback causes the promise returned by then() to be synced with this
        &#x2F;&#x2F; new promise. This is a way to control when the returned promise is
        &#x2F;&#x2F; fulfilled
        return new Y.Promise(function (fulfill, reject) {
            node.transition(config, function () {
                &#x2F;&#x2F; The transition is done, signal the promise that all is ready
                &#x2F;&#x2F; by fulfilling it with the same node
                fulfill(node);
            });
        });
    });
};

function PromisePlugin(config) {
    &#x2F;&#x2F; Create a private NodePromise instance that points to the plugin host
    this._promise = new NodePromise(function (fulfill) {
        &#x2F;&#x2F; Since this is a Node plugin, config.host will be an instance of Node
        fulfill(config.host);
    });
}

&#x2F;&#x2F; Set up the plugin&#x27;s namespace
PromisePlugin.NS = &#x27;promise&#x27;;

PromisePlugin.prototype.transition = function (config) {
    &#x2F;&#x2F; Simply point to the private promise&#x27;s transition method
    return this._promise.transition(config);
};


var square = Y.one(&#x27;#square&#x27;);
square.plug(PromisePlugin);

function resetStyles() {
    square.setStyles({
        width: &#x27;100px&#x27;,
        height: &#x27;100px&#x27;,
        left: &#x27;0&#x27;
    });
}

Y.one(&#x27;#without-plugin&#x27;).on(&#x27;click&#x27;, function () {
    resetStyles();
    square
        .transition({width: &#x27;300px&#x27;})
        .transition({height: &#x27;300px&#x27;})
        .transition({left: &#x27;200px&#x27;});
});
Y.one(&#x27;#with-plugin&#x27;).on(&#x27;click&#x27;, function () {
    resetStyles();
    square.promise
        .transition({width: &#x27;300px&#x27;})
        .transition({height: &#x27;300px&#x27;})
        .transition({left: &#x27;200px&#x27;});
});

});
&lt;&#x2F;script&gt;</pre>

</div>
            </div>
        </div>

        <div class="yui3-u-1-4">
            <div class="sidebar">
                
                    <div id="toc" class="sidebox">
                        <div class="hd">
                            <h2 class="no-toc">Table of Contents</h2>
                        </div>

                        <div class="bd">
                            <ul class="toc">
<li>
<a href="#using-promises-to-chain-css-transitions">Using Promises to Chain CSS Transitions</a>
<ul class="toc">
<li>
<a href="#the-plan">The plan</a>
</li>
<li>
<a href="#creating-a-promise-subclass">Creating a Promise Subclass</a>
</li>
<li>
<a href="#creating-the-plugin">Creating the Plugin</a>
</li>
<li>
<a href="#using-the-plugin">Using the Plugin</a>
</li>
<li>
<a href="#fullcode">Full Code Listing</a>
<ul class="toc">
<li>
<a href="#html">HTML</a>
</li>
<li>
<a href="#css">CSS</a>
</li>
<li>
<a href="#javascript">JavaScript</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
                        </div>
                    </div>
                

                
                    <div class="sidebox">
                        <div class="hd">
                            <h2 class="no-toc">Examples</h2>
                        </div>

                        <div class="bd">
                            <ul class="examples">
                                
                                    
                                        <li data-description="Wrapping async transactions with promises">
                                            <a href="basic-example.html">Wrapping async transactions with promises</a>
                                        </li>
                                    
                                
                                    
                                        <li data-description="Extend Y.Promise to create classes that encapsulate standard transaction logic in descriptive method names">
                                            <a href="subclass-example.html">Subclassing Y.Promise</a>
                                        </li>
                                    
                                
                                    
                                        <li data-description="Extend the Promise class to create your own Node plugin that chains transitions">
                                            <a href="plugin-example.html">Creating a Node Plugin that chains transitions</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/promise',
    name: 'plugin-example',
    title: 'Creating a Node Plugin that chains transitions',
    newWindow: '',
    auto:  false 
};
YUI.Env.Tests.examples.push('basic-example');
YUI.Env.Tests.examples.push('subclass-example');
YUI.Env.Tests.examples.push('plugin-example');

</script>
<script src="../assets/yui/test-runner.js"></script>



</body>
</html>