Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

January 03 2012

22:30

Create a Scalable Widget Using YUI3: Part 4

Welcome to the last part in the YUI3 widget tutorial; although we’ve actually finished building the widget, we’re going to look at how easy it is to add extra functionality to a widget without having to re-write it.

Let’s get started right away!

If the functionality is required for a particular module it’s an extension. Otherwise, it’s a plugin.

There are two ways of adding functionality – extensions and plugins. The difference between them is subtle but essentially boils down to whether or not the functionality is required or optional. If the functionality is required for a particular module it’s an extension, if the functionality is optional, it’s a plugin.

The plugin that we’ll add will handle the paging functionality for our widget; maybe not all developers will want to add paging, or some may want to add it to some instances of the widget but not others. Adding the functionality makes sense when viewed in this way – if the developer wants to make use of paging, they can use the plugin, but we don’t force developers to run all the extra code that is required if they aren’t going to use it.


Creating a Plugin

The process for creating a plugin is similar to that for creating a widget, so many of the constructs that we’ll use here should be familiar from the previous parts of this tutorial. Just like when creating a widget, we use YUI’s add() method as a wrapper for our code:

YUI.add("tweet-search-paging", function (Y) {

},
  • The name of the plugin (the name that developers will use to initialize the plugin) is the first argument of the method
  • an anonymous callback function is the second parameter. The function receives a reference to the current YUI instance.
  • the third argument is the version number of the plugin and
  • the fourth is an object listing any dependencies required by the plugin.

The Constructor and Namespace

Just like with our widget, we need to add a constructor for our plugin so that it can initialised and set the namespace for it. Unlike our plugin, setting the namespace is required. Add the following code within the anonymous function we just added:

var Node = Y.Node;

function TweetSearchPaging(config) {
    TweetSearchPaging.superclass.constructor.apply(this, arguments);
}

Y.namespace("Plugin.DW").TweetSearchPaging = TweetSearchPaging;

We start by caching references to any frequently used YUI resources, which in this case is just the Node utility. We add the constructor for the plugin in the same way as before; the TweetSearchPaging plugin method is defined as a function that accepts a configuration object. The class is initialized using the apply() method of the superclass’s constructor.

We set a namespace for our plugin, but this time the namespace is attached to the Plugin namespace as opposed to the YUI object.


Static Properties

As before there are some static properties we should set for our plugin, these are as follows:

TweetSearchPaging.NAME = "tweetsearch-paging";

TweetSearchPaging.NS = "paging";

TweetSearchPaging.ATTRS = {

    origShowUIValue: null,

    strings: {
        value: {
            nextLink: "Next Page",
            prevLink: "Previous Page"
        }
    }
};

TweetSearchPaging.PAGING_CLASS = Y.ClassNameManager.getClassName(TweetSearchPaging.NAME, "link");

TweetSearchPaging.LINK_TEMPLATE = "<a class={linkclass} href={url}>{linktext}</a>";

The name of the plugin is set with the NAME property, and also the NS property, which can be used to refer to the plugin from the host (the host is the widget or module that the plugin is connected to) class.

We can also use the ATTRS property to set any configuration attributes for the plugin. These attributes also use the YUI3 Attributes module, just like the widget attributes, and can be used in the same way. The attributes we define are the origShowUIValue attribute, which the plugin will set to store whether the search UI was initially displayed in the widget when the plugin is initialized. We also store the text strings used by the plugin, again for easy internationalization.

We manually generate a class name for the elements that we’ll create using the classNameManager, and define the template that our paging links will be created with. As there is only a single class name and template we don’t need to worry about using a for loop.


Extending the Plugin Base Class

Just like we did when creating the class for our widget, we use YUI’s extend() method to extend an underlying module. In the case of a plugin, it’s the Plugin.Base class that we’re extending. The extend() method should appear as follows:

Y.extend(TweetSearchPaging, Y.Plugin.Base, {

});

We pass in our plugin as the first argument to the extend() method, the class we’re extending as the second method and an object literal containing the functionality we’re adding.


Life Cycle Methods

Plugins also get access to several life-cycle methods that can be overridden to add custom code that the plugin will execute for us at appropriate times. We can make use of use the initializer and destructor life-cycle methods:

initializer: function () {

    Y.StyleSheet("tweetSearchPagingBase").set(".yui3-tweetsearch-paging-link", { float: "right" });

    if (Y.one(".yui3-skin-sam")) {
        Y.StyleSheet("tweetSearchPagingSkin").set(".yui3-skin-sam .yui3-tweetsearch-paging-link", { marginLeft: "2%" });
    }

    var widget = this.get("host");

    if (!widget.get("showUI")) {
        this.set("_origShowUIValue", false);
        widget.set("showUI", true);
    } else {
        this.set("_origShowUIValue", true);
    }

    this.afterHostEvent("tweetsChange", this._afterHostTweetsChange);
},

destructor: function () {
    Y.StyleSheet("tweetSearchPagingBase").unset(".yui3-tweetsearch-paging-link", "float");

    if (Y.one(".yui3-skin-sam")) {
        Y.StyleSheet("tweetSearchPagingSkin").unset(".yui3-skin-sam .yui3-tweetsearch-paging-link", "marginLeft");
    }

    if (!this.get("_origShowUIValue")) {
        this.get("host").set("showUI", false);
        Y.one(".yui3-tweetsearch-ui").remove();
    }
},

The initializer method will be executed when the plugin is initialized; in this method we first create the base style sheet our plugin needs. We could just include a separate CSS file, but as we only need a single style rule it makes sense to cut down on the number of files that any implementing developer needs to manage.

We use YUI’s StyleSheet() method to create our new style sheet. This method accepts a single argument which is the name of the new style sheet. We then use the set() method to set the styles that we require. The set() method takes two arguments; the first is the selector we wish to target and the second is an object literal containing the styles that should be applied to the selector, which in this case is simply float: right.

We then check whether the .yui3-sam-skin selector exists in the document; if it does, we then go ahead and create a skin style sheet for the plugin. If the sam skin is not in use, it is not worth creating any skin styles as the implementing developer will no doubt have custom styles that they may wish to apply.

Next, we need to check whether the showUI attribute of the widget is enabled. We can get access to the host class that the plugin is attached to using the built-in host attribute, which we get using the get() method just like any other attribute. The showUI attribute of the widget must be enabled if the plugin is used, so if the attribute is not set originally we set it here.

When using plugins we have the ability to detect and react to any of the host’s attributes changing. We add an attribute change-handler for the when the tweets attribute of our widget changes using the afterHostEvent() method. This method accepts two arguments; the first is the attribute to monitor, the second is the method to execute when the attribute changes.

The destructor function is called when the plugin is destroyed; this method is used to tidy up after the plugin. Any changes to the page should be reversed, as well as any changes we make to the widget. The changes we make to the page that we have to undo are the addition of the style sheets, so this is what we do first. The style sheet styles can be removed using the unset() method; this method takes the selector to unset as the first argument and the styles to unset as the second argument.

We then check whether the _origShowUiValue variable is set to true or false; if the variable is set to false we know we have to revert its value, so we set the attribute of the host back to false. If the value was changed and the UI was shown by the plugin, we hide it so that the widget is returned to its original state.


Attribute Change-Handlers

We only use a single attribute change-handling method in this plugin; the one that is called when the tweet attribute of the host changes. This method should appear as follows:

_afterHostTweetsChange: function () {

    var widget = this.get("host");

    if (widget.get("tweets").next_page) {
        var nextPageUrl = widget.get("tweets").next_page,
            nextLink = Node.create(Y.substitute(TweetSearchPaging.LINK_TEMPLATE, {
            linkclass: TweetSearchPaging.PAGING_CLASS, url: ["http://search.twitter.com/search.json", nextPageUrl, "&callback={callback}"].join(""), linktext: this.get("strings").nextLink }));

        if (this._nextLinkNode) {
            this._nextLinkNode.remove();
        }

        this._nextLinkNode = widget._uiNode.appendChild(nextLink);

        Y.on("click", Y.bind(this._getPage, this), this._nextLinkNode);
    }

    if (widget.get("tweets").previous_page) {
        var prevPageUrl = widget.get("tweets").previous_page,
            prevLink = Node.create(Y.substitute(TweetSearchPaging.LINK_TEMPLATE, {
            linkclass: TweetSearchPaging.PAGING_CLASS, url: ["http://search.twitter.com/search.json", prevPageUrl, "&callback={callback}"].join(""), linktext: this.get("strings").prevLink }));

        if (this._prevLinkNode) {
            this._prevLinkNode.remove();
        }
        this._prevLinkNode = widget._uiNode.appendChild(prevLink);
        Y.on("click", Y.bind(this._getPage, this), this._prevLinkNode);
    }
},

We first store a reference to the host class once more as we’ll need to refer to it several times. We now need to determine whether or not there are paged results in the response from Twitter and whether there are previous or next pages of results. The cool thing about the response from twitter is that it will automatically maintain which page of results we are viewing if there are more results than the configured number of results per page.

If there is another page of results after the current page, there will be a property in the JSON response object called next_page. Similarly, if there is a previous page of results, there will be a previous_page property. All we need to do is check for the presence of these properties and create next page and previous page links.

The links are created using the template we stored earlier in the plugin class, and are given the generated CLASS_NAME. The next_page and previous_page response objects are obtained from Twitter using a URL with a special ID in the query string. When we create these new nodes, the URL provided in these properties is added to each link respectively. The links are appended to the searchUI node of the host, and click handlers are added for them. These click handlers point to a utility method called _getPage(). We’ll add this method next.


Custom Prototype Methods

Just like when creating the widget, we can add any number of custom prototype methods that are used to execute any custom code required by our plugin in response to user interaction or state changes. In this plugin, we only need to add a single method, which should appear as follows:

_getPage: function (e) {
    var widget = this.get("host");

    e.preventDefault();

    widget._viewerNode.empty().hide();
    widget._loadingNode.show();

    widget.set("baseURL", e.target.get("href")),

    widget._retrieveTweets();

    Y.all(".yui3-tweetsearch-paging-link").remove();
}

First, we store a reference to the host class, and then prevent the paging link that was clicked being followed. We then remove any existing tweets in the widget’s viewer and show the loading node. Remember, each paging link (or whichever link exists if we are on the first or last page) will have the URL that retrieves the next (or previous) page of results, so we retrieve this URL from the link’s href and set the baseURL attribute of the widget. One this is done, we call the _retrieveTweets() method of our widget to request the next page. Finally, we remove the current paging links as they will be recreated if there are next or previous pages included in the new response object.


Using the Plugin

Now that we’ve created our plugin we can see how easy it is to use with our widget. We need to update our use() method to use our plugin, and call the plug() method before the widget is rendered:

YUI().use("tweet-search", "tweet-search-paging", function (Y) {
    var myTweetSearch = new Y.DW.TweetSearch({
        srcNode: "#ts"
    });
    myTweetSearch.plug(Y.Plugin.DW.TweetSearchPaging);
    myTweetSearch.render();
});

The plug() method connects our plugin, which is accessible via the Plugin namespace and whatever namespace we specified when defining the plugin’s class. Now when we run the page, we should have paging links at the bottom of the widget:

Nettuts+

One of the features of our plugin (just like our widget) is easy internationalization; in order to provide strings for the plugin in another language (or override any attributes if a plugin), we can simply provide the configuration object as the second argument to the plug() method, e.g.:

myTweetSearch.plug(Y.Plugin.DW.TweetSearchPaging, {
    strings: {
        nextLink: "Página Siguiente",
        prevLink: "Página Anterior"
    }
});

The paging link should now appear like so:

Nettuts+

Wrapping Up

In this part of the tutorial, we looked at how easy it is to create a plugin that can be used to enhance existing widgets or other modules. This is a great way of providing extra functionality that is not essential, which developers can choose to include if they wish. We saw that the structure of a plugin is similar to that of a widget on a smaller scale.

In this example, the plugin was very tightly coupled to our widget; it wouldn’t be possible to use the plugin with a different widget for example. This does not have to be the case and plugins, as well as extensions can be much more loosely coupled to add or enhance functionality for a range of different modules.

This now brings us to the end of the series on YUI3 widgets; I hope I’ve given some insight into the powerful mechanisms put in place by the library that enable us to easily create scalable and robust widgets that leverage the strengths of the library.

Let us know what you think in the comments section below and thank you so much for reading!


December 28 2011

22:00

Create a Scalable Widget Using YUI3: Part 3

In the last part of this series, we looked at the life-cycle methods, automatic methods and the custom methods that our widget requires or can make use of. In this part, we’re going to finish defining the widget’s class by adding the attribute change-handling methods that we attached in the bindUI() life-cycle method.

Let’s get started right away!


Attribute Change Handlers

The attribute change-handling group of methods are called when some of our attributes change values. We’ll start by adding the method that is called when the showTitle attribute changes; add the following code directly after the _uiSetTitle() method:

_afterShowTitleChange: function () {
    var contentBox = this.get("contentBox"),
        title = contentBox.one(".yui3-tweetsearch-title");

    if (title) {
        title.remove();
        this._titleNode = null;
    } else {
        this._createTitle();
    }
},

We first get a reference to the contentBox, and then use this to select the title node. Remember this is the container in which reside the title and subtitle in the header of the widget.

If the title node already exists, we remove it using YUI’s remove() method. We also set the _titleNode of the widget to null. If the node doesn’t exist, we simple call the _createTitle() method of our widget to generate and display it.

Next we can handle the showUI attribute changing:

_afterShowUIChange: function () {
    var contentBox = this.get("contentBox"),
        ui = contentBox.one(".yui3-tweetsearch-ui");

    if (ui) {
        ui.remove();
        this._uiNode = null;
    } else {
        this._createSearchUI();
    }
},

This method is almost identical to the last one — all that changes is that we are looking for the change of a different attribute, and either removing or creating a different group of elements. Again, we set the _uiNode property of our widget to null, so that the widget is aware of the latest state of its UI.

Our next method is called after the term attribute changes:

_afterTermChange: function () {
    this._viewerNode.empty().hide();
    this._loadingNode.show();

    this._retrieveTweets();
    if (this._titleNode) {
        this._uiSetTitle(this.get("term"));
	}
},

When the term attribute changes, we first remove any previous search results from the viewer by calling YUI’s (specifically the Node module’s) empty() method followed by the hide() method. We also show our loader node for some visual feedback that something is happening.

We then call our _retrieveTweets() method to initiate a new request to Twitter’s search API. This will trigger a cascade of additional methods to be called, that result ultimately in the viewer being updated with a new set of tweets. Finally, we check whether the widget currently has a _titleNode, and if so we call the _uiSetTitle() method in order to update the subtitle with the new search term.

Our last attribute change-handler is by far the largest and deals with the tweets attribute changes, which will occur as a result of the request to Twitter being made:

_afterTweetsChange: function () {
    var x,
        results = this.get("tweets").results,
        not = this.get("numberOfTweets"),
        limit = (not > results.length - 1) ? results.length : not;

    if (results.length) {

        for (x = 0; x < limit; x++) {
            var tweet = results[x],
                text = this._formatTweet(tweet.text),
                tweetNode = Node.create(Y.substitute(TweetSearch.TWEET_TEMPLATE, {
                    userurl: "http://twitter.com/" + tweet.from_user, avatar: tweet.profile_image_url,
                    username: tweet.from_user, text: text
                }));

            if (this.get("showUI") === false && x === limit - 1) {
                tweetNode.addClass("last");
            }
            this._viewerNode.appendChild(tweetNode);
        }

        this._loadingNode.hide();
        this._viewerNode.show();
    } else {
        var errorNode = Node.create(Y.substitute(TweetSearch.ERROR_TEMPLATE, {
	        errorclass: TweetSearch.ERROR_CLASS,
            message: this.get("strings").errorMsg
        }));

        this._viewerNode.appendChild(errorNode);
        this._loadingNode.hide();
        this._viewerNode.show();
    }
},

First up, we set the variables we’ll need within the method including a counter variable for use in the for loop, the results array from the response that is stored in the tweets attribute, the value of the numberOfTweets attribute and the limit, which is either the number of results in the results array, or the configured number of tweets if there are fewer items in the array than the number of tweets.

The remaining code for this method is encased within an if conditional which checks to see if there are actually results, which may not be the case if there were no tweets containing the search term. If there are results in the array, we iterate over each of them using a for loop. On each iteration, we get the current tweet and pass it to a _formatTweet() utility method that will add any links, usernames or hash tags found within the text, and then create a new node for the tweet using the same principles that we looked at in the last part of this tutorial.

When the searchUI is not visible, we should alter the styling of the widget slightly to prevent a double border at the bottom of the widget. We check whether the showUI attribute is set to false, and is the last tweet being processed, and if so add the class name last to the tweet using YUI’s addClass() method. We then add the newly created node to the viewer node to display it in the widget.

After the for loop has completed, we hide the loading node, which will at this point be visible having already been displayed earlier on, and then show the viewer node.

If the results array does not have a length, it means that the search did not return any results. In this case, we create an error node to display to the user and append it to the viewer node, then hide the loading node and show the viewer node as before.


A Final Utility Method

We’ve added all of the methods that support changing attribute values. At this point, we have just one further method to add; the _formatTweet() method that we reference from the within the for loop of the method we just added. This method is as follows:

_formatTweet: function (text) {

    var linkExpr = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
        atExpr = /(@[\w]+)/g,
        hashExpr = /[#]+[A-Za-z0-9-_]+/g,
        string = text.replace(linkExpr, function (match) {
            return match.link(match);
        });

    string = string.replace(atExpr, function (match) {
        return match.link("http://twitter.com/" + match.substring(1));
    });
    string = string.replace(hashExpr, function (match) {
        return match.link("http://twitter.com/search?q=" + encodeURI(match));
    });

    return string;
}

This method accepts a single argument, which is the text from the ‘current’ item of the results array that we want to linkify/atify/hashify. We start by defining three regular expressions, the first will match any links within the text that start with http, https or ftp and contain any characters that are allowed within URLs. The second will match any Twitter usernames (any strings that start with the @ symbol), and the last will match any strings that start with the # symbol.

We then set a variable called string which is used to contain the transformed text. First, we add the links. JavaScript’s replace() function accepts the regular expression for matching links as the first argument and a function as the second argument — the function will be executed each time a match is found and is passed the matching text as an argument. The function then returns the match having converted it to a link element using JavaScript’s link() function. This function accepts a URL that is used for the href of the resulting link. The matching text is used for the href.

We then use the replace() function on the string once again, but this time we pass in the @ matching regular expression as the first argument. This function works in the same way as before, but also adds Twitter’s URL to the start of the href that is used to wrap the matching text. The string variable is then operated on in the same way to match and convert any hashed words, but this time Twitter’s search API URL is used to create the link(s). After the text has been operated on, we return the resulting string.

This brings us to the end of our widget’s class; at this point we should have an almost fully functioning widget (we haven’t yet added the paging, this will be the subject of the next and final instalment in this series). We should be able to run the page and get results:

Nettuts+ Image

Styling the Widget

We should provide at least 2 style sheets for our widget; a base style sheet that contains the basic styles that the widget requires in order to display correctly, and a theme style sheet that controls how the widget appears visually. We’ll look at the base style sheet first; add the following code to a new file:

.yui3-tweetsearch-title { padding:1%; }
.yui3-tweetsearch-title h1, .yui3-tweetsearch-title h2 { margin:0; float:left; }
.yui3-tweetsearch-title h1 { padding-left:60px; margin-right:1%; background:url(/img/logo.png) no-repeat 0 50%; }
.yui3-tweetsearch-title h2 { padding-top:5px; float:right; font-size:100%; }
.yui3-tweetsearch-content { margin:1%; }
.yui3-tweetsearch-viewer article, .yui3-tweetsearch-ui { padding:1%; }
.yui3-tweetsearch-viewer img { width:48px; height:48px; margin-right:1%; float:left; }
.yui3-tweetsearch-viewer h1 { margin:0; }
.yui3-tweetsearch-label { margin-right:1%; }
.yui3-tweetsearch-input { padding:0 0 .3%; margin-right:.5%; }
.yui3-tweetsearch-title:after, .yui3-tweetsearch-viewer article:after,
.yui3-tweetsearch-ui:after { content:""; display:block; height:0; visibility:hidden; clear:both; }

Save this style sheet as tweet-search-base.css in the css folder. As you can see, we target all of the elements within the widget using the class names we generated in part one. There may be multiple instances of the widget on a single page and we don’t want our styles to affect any other elements on the page outside of our widget, so using class names in this way is really the only reliable solution.

The styling has been kept as light as possible, using only the barest necessary styles. The widget has no fixed width and uses percentages for things like padding and margins so that it can be put into any sized container by the implementing developer.

Next, we can add the skin file; add the following code in another new file:

.yui3-skin-sam .yui3-tweetsearch-content { border:1px solid #A3A3A3; border-radius:7px; }
.yui3-skin-sam .yui3-tweetsearch-title { border-bottom:1px solid #A3A3A3; border-top:1px solid #fff; background-color:#EDF5FF; }
.yui3-skin-sam .yui3-tweetsearch-title span { color:#EB8C28; }
.yui3-skin-sam .yui3-tweetsearch-loader, .yui3-skin-sam .yui3-tweetsearch-error { padding-top:9%; margin:2% 0; color:#EB8C28; font-weight:bold; text-align:center; background:url(/img/ajax-loader.gif) no-repeat 50% 0; }
.yui3-skin-sam .yui3-tweetsearch-error { background-image:url(/img/error.png); }
.yui3-skin-sam .yui3-tweetsearch article { border-bottom:1px solid #A3A3A3; border-top:2px solid #fff; background:#f9f9f9; background:-moz-linear-gradient(top, #f9f9f9 0%, #f3f3f3 100%, #ffffff 100%); background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f9f9f9), color-stop(100%,#f3f3f3), color-stop(100%,#ffffff)); background:-webkit-linear-gradient(top, #f9f9f9 0%,#f3f3f3 100%,#ffffff 100%); background:-o-linear-gradient(top, #f9f9f9 0%,#f3f3f3 100%,#ffffff 100%); background:-ms-linear-gradient(top, #f9f9f9 0%,#f3f3f3 100%,#ffffff 100%); background:linear-gradient(top, #f9f9f9 0%,#f3f3f3 100%,#ffffff 100%); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#ffffff',GradientType=0); }
.yui3-skin-sam .yui3-tweetsearch article.last { border-bottom:none; }
.yui3-skin-sam .yui3-tweetsearch a { color:#356DE4; }
.yui3-skin-sam .yui3-tweetsearch a:hover { color:#EB8C28; }
.yui3-skin-sam .yui3-tweetsearch-ui { border-top:1px solid #fff; background-color:#EDF5FF; }

Save this file as tweet-search-skin.css in the css folder. Although we also use our generated class names here, each rule is prefixed with the yui3-skin-sam class name so that the rules are only applied when the default Sam theme is in use. This makes it very easy for the overall look of the widget to be changed. This does mean however that the implementing developer will need to add the yui3-skin-sam class name to an element on the page, usually the , but this is likely to be in use already if other modules of the library are being used.

Like before, we’ve added quite light styling, although we do have a little more freedom of expression with a skin file, hence the subtle niceties such as the rounded-corners and css-gradients. We should also recommended that the css-reset, css-fonts and css-base YUI style sheets are also used when implementing our widget, as doing so is part of the reason the custom style sheets used by the widget are nice and small.


Implementing the Widget

Our work as widget builders is complete (for now), but we should spend a little while looking at how the widget is actually used. Create the following HTML page in your text editor:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>YUI3 Twitter Search Client</title>
        <link rel="stylesheet" href="http://yui.yahooapis.com/combo?3.4.1/build/cssreset/cssreset-min.css&3.4.1/build/cssfonts/cssfonts-min.css&3.4.1/build/cssbase/cssbase-min.css">
        <link rel="stylesheet" href="css/tweet-search-base.css" />
        <link rel="stylesheet" href="css/tweet-search-skin.css" />
    </head>
    <body class="yui3-skin-sam">
        <div id="ts"></div>
        <script src="//yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>
        <script src="js/tweet-search.js"></script>
        <script>
            YUI().use("tweet-search", function (Y) {
                var myTweetSearch = new Y.DW.TweetSearch({
                    srcNode: "#ts"
                });
                myTweetSearch.render();
            });
        </script>
    </body>
</html>

The only YUI script file we need to link to is the YUI seed file which sets up the YUI global object and loads the required modules.

Save this file in the root project directory. First of all we link to the CDN hosted YUI reset, base and fonts combined style sheet, as well as our two custom style sheets that we just created. We also add the yui3-skin-sam class name to the of the page to pick up the theme styling for our widget. On the page, we add a container for our widget and give it an id attribute for easy selecting.

The only YUI script file we need to link to is the YUI seed file; this file sets up the YUI global object and contains the YUI loader which dynamically loads the modules required by the page. We also link to our plugin’s script file, of course.

Within the final script element we instantiate the YUI global object and call the use() method specifying our widget’s name (not the static NAME used internally by our widget, but the name specified in the add() method of our widget’s class wrapper) as the first argument.

Each YUI instance is a self-contained sandbox in which only the named modules are accessible.

The second argument is an anonymous function in which the initialisation code for our widget is added. This function accepts a single argument which refers to the current YUI instance. We can use any number of YUI objects on the page, each with its own modules. Each YUI instance is a self-contained sandbox in which only the named modules (and their dependencies) are accessible. This means we can have any number of self-contained blocks of code, all independent from each other on the same page.

Within the callback function, we create a new instance of our widget stored in a variable. Our widget’s constructor is available via the namespace we specified in the widget’s class, which is attached to the YUI instance as a property. Our widget’s constructor accepts a configuration object as an argument; we use this to specify the container that we want to render our widget into, in this case the empty

we added to the page. The specified element will become the contentBox of our widget. Finally, we call the render() method on the variable our widget instance is stored in, which renders the HTML for our widget into the specified container.

In the configuration object, we can override any of the default attributes of our widget, so if we wanted to disable the title of the widget and the search UI, we could pass the following configuration object into our widget’s constructor:

{
    srcNode: "#ts",
    showTitle: false,
    showUI: false
}

I mentioned in an earlier part of the widget that by including all of the text strings used by the widget in an attribute, we could easily enable extremely easy internationalization. To render the widget in Spanish, for example, all we need to do is override the strings attribute, like this:

{
    srcNode: "#ts",
    strings: {
        title: "Twitter Search Widget",
        subTitle: "Mostrando resultados de:",
        label: "Término de búsqueda",
        button: "Búsqueda",
        errorMsg: "Lo siento, ese término de búsqueda no ha obtenido ningún resultado. Por favor, intente un término diferente"
    }
}

Now when we run the widget, all of the visible text (aside from the tweets of course) for the widget is in Spanish:

Nettuts+ Image

Summary

In this part of the tutorial, we completed our widget by adding the attribute change-handling methods and a small utility method for formatting the flat text of each tweet into mark-up. We also looked at the styling required by our widget and how the styles should be categorized, i.e. whether they are base styles or skin styles.

We also saw how easy it is to initialise and configure the widget and how it can easily be converted into display in another language. In the next part of this tutorial, we’ll look at a close relative to the widget – the plugin and add a paging feature to our widget.


Sponsored post
feedback2020-admin
04:05

December 21 2011

04:17

Create a Scalable Widget Using YUI3: Part 2

In part one of this series, we reviewed some of the necessary constructs to use when creating a widget with YUI3. We looked at the static properties we needed to set, the class constructor and namespacing, and briefly looked at the extend() method.

In this part of the tutorial, we’ll review the prototype methods we can override or create in order to make our widget function.

Before we begin, let’s just remind ourselves of the method now, as this method houses all the code below:

TweetSearch = Y.extend(TweetSearch, Y.Widget, {

});

The third argument is what we are interested in, in this part of the tutorial. All of the functionality we add that is specific to our widget will be within functions that are added as values to different properties of the object passed to the extend() method. Some of these methods are added automatically for us –we just need to override them with custom functionality. We’ll look at these methods first.


Lifecycle Methods

Several methods executed at different points in the widget instances life cycle. The first of these is an initializer method (remember to add this code within the extend() method shown above):

initializer: function () {
    this._retrieveTweets();
},

The underscore convention to indicate the method should be treated as private, and not called directly by any implementing developer.

The initializer method is provided to allow us to do any tasks that are required as soon as the widget is initialized. Within any prototype methods we attach to our widget, whether inherited or created ourselves, the value of this is set to the widget instance.

All our widget needs to do at this point is retrieve the search results from Twitter. We package this up as a separate function (which we’ll look at in more detail a little later), instead of just retrieving the results directly within initializer so that we can reuse the functionality and retrieve search results any time we wish. The _retrieveTweets() method uses the underscore convention to indicate the method should be treated as private, and not called directly by any implementing developer. It can be called directly of course, but may result in weirdness.

The next life-cycle method inherited from Widget is renderUI(), which we can use to perform any necessary setup, the creation and insertion of new elements, etc, our widget requires. Add this code directly after that shown above:

renderUI: function () {
    var contentBox = this.get("contentBox"),
        strings = this.get("strings"),
        viewer = Node.create(Y.substitute(TweetSearch.VIEWER_TEMPLATE, { viewerclass: TweetSearch.VIEWER_CLASS })),
        loadingNode = Node.create(Y.substitute(TweetSearch.LOADER_TEMPLATE, { loaderclass: TweetSearch.LOADER_CLASS }));

    if (this.get("showTitle")) {
        this._createTitle();
    }
    this._loadingNode = contentBox.appendChild(loadingNode);
    this._viewerNode = contentBox.appendChild(viewer);

    if (this.get("showUI")) {
        this._createSearchUI();
    }

    contentBox.addClass("yui3-widget-content");
},

When a widget is initialised, YUI will automatically create a wrapper element for the element that was passed to the constructor.

Within the renderUI() method, we first store a reference to the contentBox attribute of the widget. The contentBox represents the inner container of the widget and is one of the attributes automatically inherited from Widget, like the srcNode attribute that we saw briefly in part 1. When a widget is initialised, YUI will automatically create a wrapper element for the element that was passed to the constructor, with the inner element becoming the contentBox. The wrapper is known as the bounding box (available as the boundingBox attribute).

We also get a reference to the strings attribute that contains the localizable strings used by elements created by the widget. We then create two new elements; the viewer which will be used to contain the list of tweets returned by Twitter’s search API, and a loading element that will be displayed while the request is in progress.

We use the create() method of the YUI Node module to create our new elements. This element can accept the string representation of an element, which it will then create. Instead of passing it a string directly however, we use YUI’s substitute() method to replace the tokenised templates that we created in part one of this tutorial.

The substitute() method takes two arguments;

  • the first is the string to perform substitution on.
  • the second is an object whose keys map directly to the tokens within the string.

The values of each property are swapped into the string, so for example, our viewer template will be stored like this:

"<div class={viewerclass}></div>"

The object passed as the second argument to the substitute() method used to create the viewer node contains a key called viewerclass, so the value of this key will be swapped with the matching token in the source string. In this case, we use the stored class name as the substitution, so the viewer will be given the class name yui3-tweetsearch-viewer (the class names were all created and stored on our widget instance in part one).

We then check whether the showTitle attribute of our widget is set to true, which it is by default, but may be disabled by the implementing developer. If the attribute is set to true we call the custom (i.e. not inherited) _createTitle() method. The reason we package this up as a separate unit of code, instead of just creating the widget is because the showTitle attribute may be set at any time by someone implementing our widget, so it can’t just reside within a life-cycle method. We will look at our custom methods in detail after looking at the inherited life-cycle methods.

After we do or do not (depending on configuration) create the title node, we then insert the new elements into the DOM by adding them as child nodes of the contentBox. Note that we also store the new elements on the widget instance so that we can easily refer to them later on.

We then check whether the showUI attribute is enabled (again, it is by default, but it could be changed in the configuration), and if so call the _createSearchUI() method. This is a separate method for the same reason as last time – so that it can be reused throughout the widget instance’s life.

Finally, we add the class name yui3-widget-content to the contentBox. This isn’t strictly necessary, as the implementing developer may not be using any of the YUI’s style sheets (base, fonts, reset, etc), but as the class name isn’t added for us automatically, we should include in case the developer does wish to pick up some of the styling provided by the library.

The final life-cycle method we are going to use is bindUI(), which allows us to hook up any handlers that should be called when an attribute changes value, or an event occurs. Add the following code directly after the renderUI() method:

bindUI: function () {
    if (this.get("showUI")) {

        Y.on("click", Y.bind(this._setTerm, this), this._buttonNode);
        this.after("termChange", this._afterTermChange);
    }

    this.after("showTitleChange", this._afterShowTitleChange);
    this.after("showUIChange", this._afterShowUIChange);
    this.after("tweetsChange", this._afterTweetsChange);
},

The first thing we do is check whether the showUI attribute is enabled; if it has been disabled we don’t need to worry about adding event handlers for it. If it is enabled, we use YUI’s on() method to add a click-handler bound to the custom _setTerm() method. We ensure the widget instance remains bound to the this keyword within the event handler by passing this (which at this point refers to the widget instance) as the second argument to the bind() method.

We also use the after() method that is automatically attached to our widget instance by the library to add a listener that reacts to the term attribute changing. A listener can be bound to any of our custom attributes by simply suffixing After to any attribute name. The term attribute will only change if the search UI is enabled. We then add listeners for each of the other attributes we need to monitor; showTitle, showUI and tweets, hooking these up with the relevant handlers.

Note: There is another life cycle method provided by the Widget class, but in this particular example we don’t need to make use of it. This method is the destructor, which will be called just before the widget is destroyed. It is used to tidy up after the widget, but only needs to be used if elements are added to the DOM outside of the boundingBox (the outer wrapper) of the widget.


Automated Prototype Methods

Remember the validator we specified as part of the ATTRS object in the first part of this tutorial? The method that we set as the value of this property will be called automatically whenever an attempt is made to update the attribute. Let’s take a look at it now; add the following code directly after bindUI():

_validateTerm: function (val) {
    return val !== this.get("term");
},

The method must return true or false and automatically receives the new value (that is, the value that may become the new value if it passes validation) as the first argument; if true is returned, the attribute is updated with the new value, if false is returned the attribute is not updated.

The logic we supply is pretty simple in this example – we simply check that the new value is not the same as the old value. There’s no point after all in making another AJAX call only to receive exactly the same set of results.


Non-Inherited Prototype Methods

Next we can start adding our custom methods that will add more functionality to our widget. The first function we referenced within the initializer method was _retrieveTweets(), so we’ll look at that first:

_retrieveTweets: function () {
    var that = this,
        url = [this.get("baseURL"), "&q=", encodeURI(this.get("term")), "&rpp=", this.get("numberOfTweets")].join(""),
        handler = function (data) {
        that.set("tweets", data);
    },
    request = new Y.JSONPRequest(url, handler);

    request.send();
},

We first set a few variables; the this keyword will no longer point to our widget instance inside the success callback that we’ll specify when we make the request to Twitter, so we store a reference to this in a variable called that, as convention dictates.

We also create the request URL; we retrieve the baseURL, the term and the numberOfTweets attributes, storing each as an item in an array and then using JavaScript’s join() function to concatenate them all into a string. Using an array and the join() method is way faster than concatenating strings with the + operator.

Next we define our success callback; all this simple function needs to do is set the widget’s tweets attribute to the response received from the request. The response will be automatically passed to the callback function.

The last variable we define is for the request itself, which is initialised using YUI’s JSONPRequest() method. This method accepts two arguments; the first is the URL to make the request to and the second is the callback function to invoke on success. Finally, to initiate the request we simply call the send() method.

Our next custom method is _createTitle(), which we call from the renderUI() method:

_createTitle: function () {
    var strings = this.get("strings"),
        titleNode = Node.create(Y.substitute(TweetSearch.TITLE_TEMPLATE, {
	        titleclass: TweetSearch.TITLE_CLASS,
            title: strings.title,
            subtitle: strings.subTitle,
            term: this.get("term")
        }));

    this._titleNode = this.get("contentBox").prepend(titleNode);
},

We also store a reference to the strings attribute for use within the function. A title is created using the same principles as before, although this time we have a few more tokens to replace in our substitute() method. This method is only called if the showTitle attribute is set to true. Note that the get() method is chainable, so we can call the prepend() method to insert the title directly after it.

The code here is very similar to what has been used before, as is the case for our next method, _createSearchUI():

_createSearchUI: function () {

        var contentBox = this.get("contentBox"),
            strings = this.get("strings"),
            ui = Node.create(Y.substitute(TweetSearch.UI_TEMPLATE, { uiclass: TweetSearch.UI_CLASS })),
            label = Node.create(Y.substitute(TweetSearch.LABEL_TEMPLATE, { labelclass: TweetSearch.LABEL_CLASS, labeltext: strings.label })),
            input = Node.create(Y.substitute(TweetSearch.INPUT_TEMPLATE, { inputclass: TweetSearch.INPUT_CLASS })),
            button = Node.create(Y.substitute(TweetSearch.BUTTON_TEMPLATE, { buttonclass: TweetSearch.BUTTON_CLASS, buttontext: strings.button }));

        this._uiNode = ui;

        this._labelNode = this._uiNode.appendChild(label);
        this._inputNode = this._uiNode.appendChild(input);
        this._buttonNode = this._uiNode.appendChild(button);

        this._uiNode.appendTo(contentBox);
    },

Again, very similar to what we have seen before. Remember, the only reason this is in a separate function is so that the UI can be switched on or off at any point during the widget’s life-cycle. This method is only called if the showUI attribute is set to true.

Next up is the _setTerm() method, which is called by the event listener attached to the _buttonNode when the button is clicked:

_setTerm: function () {
        this.set("term", this._inputNode.get("value"));
    },

In this simple method, we just try to set the term attribute to the string entered into the <input>. In trying to set the attribute, our validator will be called and will only update the attribute if the value is different to the attribute’s current value.

The last of our custom methods is another simple method used to update the subtitle in the header of the widget to the new search term; add the following code:

_uiSetTitle: function (val) {
        this._titleNode.one("h2 span").setContent(val);
        },

This method will receive the new value as an argument (we’ll call this method manually from an attribute change-handling method that we’ll look at in the next part of this series). We call YUI’s one() method on our title node to select the <span> within the subtitle, and then use the setContent() method to update its inner-text.


Summary

In this part of the tutorial, we first looked at the life-cycle methods that we get as a result of extending the Widget superclass. These methods are called automatically for us by the library at different points in the widget’s life-cycle.

Although the methods that we’ve added all look similar in structure, there are distinctions between the two; for example, the life-cycle methods receive more ‘protection’ than those methods we add ourselves, hence why these methods are not prefixed with an underscore. These methods, unlike our custom ones, can’t be called directly by the implementing developer.

We also took a look at a validator method; these methods will also be called by the library automatically when appropriate which makes them incredibly useful for ensuring data is in a particular format, or meets a particular requirement before an attribute is updated.

Lastly, we looked at the custom prototype methods that we need in order to make our widget function. We saw that we can easily use the built-in get() and set() methods to get and set attributes, and that within each method the this keyword Is helpfully set to our widget’s instance, so that we can easily obtain and manipulate different aspects of the widget.

In the next part of this tutorial, we’ll look at the attribute change-handling methods that need to be added in order to make our widget respond to user interaction or changes in the page’s state. We can also look at the CSS we need to provide for our widget, and how the widget is initialized and used.

If you have any questions, please let me know in the comments section below. Thank you so much for reading!


December 13 2011

21:30

Create a Scalable Widget Using YUI3: Part 1

In this tutorial, we’re going to look at how easy it is to create scalable, robust and portable widgets using the latest version of the Yahoo User Interface library. YUI3 provides a Widget class for us to extend in order to create widgets in a consistent way that leverage the power of the library.

The widget that we’ll create today is a Twitter search client that will query Twitter’s search API and consume the JSON response in order to display tweets that contain the configured search term. We can also add additional functionality such as allowing the visitor to choose another term and do a new search, and viewing paged results. Join me after the jump!


Getting Started

All required YUI modules will be retrieved dynamically when the page running our widget is loade

We’ll need the usual css, img and js folders created within a project folder for us to store our various resources in. The images our widget will use can be found in the code download. We don’t need to worry about downloading a copy of the YUI library itself as all required YUI modules will be retrieved dynamically when the page running our widget is loaded (we’ll look at this in more detail later).


The Widget Wrapper

Create a new script file and add to it the following code:

YUI.add("tweet-search", function (Y) {

}, "0.0.1", { requires: ["widget", "substitute", "jsonp"] });

This is the outer wrapper for our widget; all of the code we write will reside within the function passed as the second argument to YUI’s add() method. The add() method of the YUI object allows us to add a new module to the library, which could be a simple function or class, a widget, an extension or a plugin.

  • The first argument we provide is the name of our widget. This name is used in the use() method when implementing the widget.
  • The second argument is an anonymous function that is used to define the widget’s class. The argument accepted by this function is the instance of YUI that the widget is attached to.
  • The third argument is used to specify the version number of the widget.
  • The fourth and final argument is an object that we can use to supply additional configuration for the widget.

In this example, we use the requires property to specify an array of other YUI components that are required for our widget to function. There are other properties that can be used here, but they aren’t required for this example.

As you can see, one of the required components is the Widget component. When creating a custom widget the Widget component of the library should be extended to make use of the powerful constructs that Widget sets up. We also use the Substitute component for doing some simple string substitution when building the required HTML elements, and the JSONP component in order to interact with Twitter’s search API.


Top Level Variables, the Constructor and Namespacing

Now we can begin adding some of the variables our widget will require, as well as adding the class constructor and namespace. Add the following code within the anonymous function:

var Node = Y.Node,
    getClassName = Y.ClassNameManager.getClassName,
    i, j,
    baseClasses = ["_CLASS", "title", "loader", "viewer", "tweet", "ui", "label", "input", "button", "error"],
    templates = ["_TEMPLATE", "&lt;hgroup class={titleclass}>&lt;h1>{title}&lt;/h1>&lt;h2>{subtitle}&lt;span>{term}&lt;/span>&lt;/h2>&lt;/hgroup>", "&lt;div class={loaderclass}>loading...&lt;/div>", "&lt;div class={viewerclass}>&lt;/div>", "&lt;article>&lt;a href={userurl} title={username}>&lt;img src={avatar} alt={username} />&lt;h1>{username}&lt;/h1>&lt;/a>&lt;p>{text}&lt;/p>&lt;/article>", "&lt;div class={uiclass}>&lt;/div>", "&lt;label class={labelclass}>{labeltext}&lt;/label>", "&lt;input class={inputclass} />", "&lt;button class={buttonclass}>{buttontext}&lt;/button>", "&lt;p class={errorclass}>{message}&lt;/p>"];

function TweetSearch(config) {
    TweetSearch.superclass.constructor.apply(this, arguments);
}

Y.namespace("DW").TweetSearch = TweetSearch;

The name of our widget has the first letter of its name capitalized, as is the convention for naming constructors.

First up, we cache references to the Y.Node component and the Y.ClassNameManager.getClassName() method as we’ll be using these frequently. We also define a couple of variables for use in the for loop, and create two new arrays; the first containing a series of strings that will form part of the class names added to the HTML elements our widget will create, and the second containing the HTML templates, also in string format, that will be used to create the elements themselves.

Next we add the constructor function for our widget; this is the function that developers implementing our widget will call. The function can accept a single argument which will take the form of an object that sets configuration attributes exposed by our widget. The name of our widget has the first letter of its name capitalized, as is the convention for naming constructors. Within this function our widget’s class is initialised by using the apply() method of the superclass's (Widget) constructor. The value of this is set to our widget instance.

We can also create a namespace for our widget using YUI’s namespace() method; this isn’t mandatory but it is a very good practice to run code within a namespace in order to minimize the possibility of naming collisions when code is used in the wild. The namespace() method accepts a string which represents the namespace, to which is attached the widget name as a property and the widget as the value.

I’ve set the namespace to equal my initials but this can be anything you require; you may already have a namespace that all of your web apps reside in, or it could be the name of your company, the name of your client, or anything else that makes sense. This widget will be accessible via Y.DW.TweetSearch


Static Properties

Next, we can define the static constants required when extending the Widget class. Add the following code directly after the namespace() method:

TweetSearch.NAME = "tweetsearch";

for (i = 1, j = baseClasses.length; i < j; i++) {
    var current = baseClasses[i].toUpperCase(),
        prop1 = current + baseClasses[0],
        prop2 = current + templates[0];

    TweetSearch[prop1] = getClassName(TweetSearch.NAME, baseClasses[i]);
    TweetSearch[prop2] = templates[i];
}

First, we set the NAME property of our widget; the all-caps naming convention here signifies a value that will be constant throughout the life-cycle of our widget instance. The name we set is used by the widget as a prefix when firing events and creating class names for HTML elements.

Next is the for loop we use to add the required class names and mark-up templates to our widget. We initialize the i and j variables that we declare at the top of the function; the i variable that is used as the counter is initially set to 1 instead of 0 as would usually be the case (you’ll see why in just a moment) and the j variable is set to the length of our baseClasses array (the baseClasses and templates arrays are both the same length as every element we create is given a class name. This may not always be the case).

Within the loop we cache a reference to the current item from the baseClasses array and in upper case, and then create two new strings called prop1 and prop2. These strings consist of the variable we just created and the first item in our baseClasses array, so on the first iteration for example, this string will equal TITLE_CLASS for prop1 and TITLE_TEMPLATE for prop2.

We then add these new properties to our widget instance; the first property is set to the result of calling the getClassName() method (remember, we’re using the cached short-cut we created earlier which points to Y.ClassNameManager.getClassName). We pass in the name of our widget as the first argument to this method, and the current item from the baseClasses array. This will result in generated class names such as yui3-tweetsearch-title, available fom the TweetSearch.TITLE_CLASS property for example.

The second property we add is the current item from the templates array. Continuing with the title example this gives us a property name of TweetSearch.TITLE_TEMPLATE with a value of <hgroup class={titleclass}><h1>{title}</h1><h2>{subtitle} <span>{term}</span></h2></hgroup>. The purpose of the for loop is simply so that we don’t have to attach all of the classes and templates to our instance manually.


Configurable Attributes with Sensible Defaults

Now we can define the configurable attributes that our widget will have, which will enable developers implementing the widget to enable or disable different features. Add the following code directly after the for loop:

TweetSearch.ATTRS = {
    term: {
        value: "yui3",
        validator: "_validateTerm"
    },
    numberOfTweets: {
        value: 5
    },
    baseURL: {
        value: "http://search.twitter.com/search.json?&with_twitter_user_id=true&include_entities=true&callback={callback}"
    },
    tweets: {
        value: null
    },
    showTitle: {
        value: true
    },
    showUI: {
        value: true
    },

    strings: {
        value: {
            title: "Twitter Search Widget",
            subTitle: "Showing results for:",
            label: "Search Term",
            button: "Search",
		errorMsg: "I'm sorry, that search term did not return any results. Please try a different term"
        }
    }
};

The YUI library adds a consistent way to add attributes to any class or module.

The ATTRS constant is used to store the configurable attributes that the implementing developer can set when creating an instance of the widget. The YUI library adds a consistent way to add attributes to any class or module, and this mechanism is automatically available when extending Widget.

Instead of setting the value of each attribute to a simple native value like a sting or a Boolean, an object is used. The default for each attribute is set using the value property of this object. In the first attribute, we also make use of the validator property, which allows us to specify a function that will be automatically called whenever the value is updated. This enables us to check that the value is in a particular format, or matches other custom criteria. There are also a range of other properties we can set for each attribute including; custom get and set methods, whether the attribute is read-only, and more.

The attributes used by our widget include the search term, the number of tweets to display, the baseURL of the request sent to Twitter, whether to show a title for the widget and whether to show the search UI. There are a number of other attributes our widget will automatically get, and which we can use. We’ll look at these in more detail later on in the tutorial.

The final attribute we define is the strings attribute, which is available to all modules that subclass Widget. The value of this attribute is also an object and within this we add all of the text strings that our widget will display. Using an attribute to define any words that the widget needs to display in this way makes our widget super easy to internationalize; implementing developers need only to override the strings attribute with their own collection of strings in whichever language they choose.


Built-in Support for Progressive Enhancement

The Widget superclass furnishes us with the HTML_PARSER static property that can retrieve values from any HTML elements that are present within the widget’s container and use these values as attributes, which makes it incredibly easy for us to create widgets that transform underlying mark-up into something more functional and/or pretty.

We don’t really need to worry about this for our widget; if JavaScript is disabled, no AJAX request will be made to Twitter’s search API and there will be no data to display in any case. However, they give implementing developers more ways of instantiating the widget and configuring attributes, we can make the provision that if a text <input> is present within the widget’s container, the value of the field will be used as the search term instead of the default attribute value. In order to retrieve this value we can make use of the HTML_PARSER; add the following code directly after the ATTRS definition:

TweetSearch.HTML_PARSER = {
    term: function (srcNode) {
        var input = srcNode.one("input");

        if (input) {
            var val = input.get("value");
                input.remove();
            }

            return val;
        }
    };

The HTML_PARSER property is an object literal where each property within this object maps directly to an attribute. The only attribute that we wish to add progressive-enhancement support for is the term attribute, the value of which is set to a functional that will automatically be called when our widget is initialized.

This function receives a single argument which is a referece to the srcNode attribute. This is one of the built-in attributes that all widgets automatically get access to and refers explicitly to the element that was passed into the constructor for our widget. This element becomes the content box for the widget.

The first thing we do is try to select an <input> element from the srcNode using YUI’s one() method, which selects a single matching element from the DOM. If an element is retrieved, we store its value in a variable called val, and then remove the element from the page (we’ll create an alternative <input> element for when the search UI is enabled later). We then return val. If val is not set, i.e. if there wasn’t an <input> in the srcNode, underfined will be returned, and the term attribute will stay set to its configured value. If val does contain a value, it will become the value for the term attribute.


Extending the Widget Class

Before we end this part of the tutorial, we’ll take a look at the method we use to extend the Widget class with the functionality specific to our widget. This method will form the bulk of our widget. Directly after the HTML_PARSER add the following:

TweetSearch = Y.extend(TweetSearch, Y.Widget, {

});

The YUI extend() method takes three arguments:

  • The first is the object to extend, which in this example is our widget’s class.
  • The second argument is the object we are extending, in this case the Widget class.
  • The third argument is an object containing prototype methods to add or override to our widget. The object passed as the third argument will be the wrapper for the remainder of our code, which we’ll come to in the next part of this tutorial.

Save this file in the js folder as tweet-search.js.


Summary

In this part of the tutorial we setup some of the required scaffolding for our new widget. Although the widget won’t actually do anything at this stage, it can still be initialised and we can see some of the container that is automatically added by the YUI library, and look in the DOM tab of Firebug to see the attributes it has inherited.

After defining some top-level variables, we first saw how to define the constructor function for our widget so that the widget can be initialized by the library, as well as seeing how easy it is to namespace our widget. We then looked at the static constants that are inherited from the underlying Widget class that we are extending. These included the NAME of the widget, the _CLASS and _TEMPLATE collections and the ATTRS object, the latter of which allowed us to set the attributes that an implementing developer can override if they so wish.

We also looked momentarily at the extend() method which is used to add the prototype methods to our widget’s class in order to implement that custom functionality it provides. This custom functionality will be the subject of the next part of this tutorial.

Stay tuned and thank you so much for reading!


March 29 2011

14:30

December 21 2010

15:30

December 15 2010

21:37

Quick Tip: An Introduction to YUI


With jQuery dominating the JavaScript framework landscape, many newcomers aren’t exposed to other JavaScript frameworks. The truth is that there are many good JavaScript frameworks like MooTools, Prototype, Ext JS, and…YUI. While not as well known as some of the other libraries, YUI provides a wealth of tools for the web developer. Today we’re going to take a quick tour of some of its features.


What is YUI?

YUI (short for Yahoo User Interface and pronounced Y-U-I) is an open source JavaScript and CSS library developed primarily by Yahoo.com. YUI includes JavaScript utiltiies, a CSS framework (reset, grid, and fonts), JavaScript widgets and tools to help include and manage your modules.

There are currently two supported versions of YUI. YUI 2, which was launched in 2006, contains the lion’s share of the YUI widgets. YUI 3 was released in 2009 and has a completely new syntax, greatly improving its ease of use (especially in event handling and DOM traversal).


Why YUI?

So you may be wondering, why should I even consider learning another JavaScript framework? Every framework has its strengths, so the one you choose will depend on your needs. Here’s a couple of things that YUI really has going for it:

  • An enormous library of widgets, including one of the most feature-complete datatables out there.
  • Stellar documentation – each component and widget has detailed instructions, examples, and api documentation.
  • Development Tools – YUI has a number of cool development tools including a profiler, in-browser console, and testing framework.
  • Flexible event handling with built-in support for touch and gesture events.

Ok, now that you’ve heard a little about YUI, let’s start looking at some code!


Including the Library

YUI allows for a lot of flexibility when it comes to loading the library; let’s look at a couple ways you can do it.

Method 1: YUI 3 Seed File

The seed file is the preferred way for getting YUI on your page. Just include the YUI seed file (only ~6KB), then include the modules you want via JavaScript. Let’s look at an example:

<script src="http://yui.yahooapis.com/3.2.0/build/yui/yui-min.js"></script>
<script>
YUI().use('node', 'anim','yui2-calendar', function(Y) {
    var YAHOO = Y.YUI2;
    Y.one('#test');
});
</script>

YUI.use() will make a request to get the required modules, and will pass you a YUI instance in the callback that has all of the required modules. YUI 2 components can also be included by passing in the module name, prepended by yui2-. If you include a YUI 2 component, then you can access the YUI 2 instance via Y.YUI2.

Method 2: YUI 3 Configurator

This web based tool allows you to pick the modules you need and allows you to download or link to a minified file with all of those dependencies (this is similar to the jQuery UI tool). It also provides stats as to how the files will affect page loads.

Method 3: SimpleYUI

SimpleYUI is a recently released tool that simplifies YUI inclusion for those who are used to just including a JavaScript library and having access to everything. Just include the SimpleYUI file and you’ll get a global YUI instance mapped to the Y variable with DOM manipulation, AJAX, and UI effects modules available.

<script type="text/javaScript"
 src="http://yui.yahooapis.com/3.2.0pr2/build/simpleyui/simpleyui-min.js"></script>

<script>
 //Y is a global variable set up by the SimpleYUI script.
 Y.one("#test").addClass("my class");
</script>

With SimpleYUI you can still use all of the other YUI modules dynamically by loading them with the YUI.use method.

Y.use('dd-drag', function(Y) {
    // set up drag and drop
});

SimpleYUI has the potential to really help YUI adoption because it makes it much more accessible and familiar to programmers coming from libraries like jQuery.


DOM Manipulation

DOM manipulation is very easy in YUI 3 and the syntax should be fairly familiar if you’ve used jQuery in the past.

YUI provides two methods for getting DOM nodes, via its Node module.

  1. Y.one(‘selecter’) – returns a YUI Node representing a DOM Node.
  2. Y.all(‘selecter’) – returns a YUI NodeList of all matches

Here’s an example.

// Y.one
var node = Y.one('#test-div'); // get me the node with the id test-div
var node2 = Y.one(document.body);  // Y.one also accepts a DOM element
Y.one('#my-list').get('id'); // my-list

// Y.all
var nodes = Y.all('#my-list li'); // all of my-list's list items

// chaining
var nodes2 = Y.one('#my-list').all('li'); // all of my-list's list items
var parent = Y.one('#my-list').get('parentNode'); // returns parent of my-list (as a YUI Node object)

YUI also provides a ‘test‘ method to see if an element matches a selector

var node = Y.one('#test-div');
// if node has the primary class
if(node.test('.primary')) {
	doSomething();
}

YUI also provides get and set methods to manipulate Node attributes, and convenience functions like addClass and removeClass.

// get and set
Y.one('#test-div').get('id');
Y.one('#test-div').set('innerHTML', 'Test Content');

// addClass, removeClass
Y.one('#test-div').addClass('highlighted'); // adds class to one div
Y.all('p').removeClass('highlighted'); // removes class from all p elements

Events

Events are attached using YUI’s on method. You can either call this method on a Node or on the YUI instance. For example:

// called on YUI instance
// myevent|click namespaces this onclick handler to myevent (used for removal later)
Y.on("myevent|click", function() { // do something }, "#test p"); 

// called on NodeList
Y.all("#test p").on("myevent|click", function() { // do something });

One interesting feature of YUI is that if you use the method from the first example, the selector does not need to immediately have a match. YUI will continue to poll for a match for up to 15 seconds after the page has finished loading, which means that you don’t have to wait for the document to be loaded to use it (you don’t have to wrap your event handlers in a document.load function).

Also notice that we prepended the event type with an optional string that namespaces the event. You can use this to later detach the event if you so desire.

Y.all("#test p").detach("myevent|click");

You can also simulate events…

Y.one("#test").simulate("click");

…and fire custom events.

Y.one("#test").fire("myevents:custom_event_one");

YUI 3 also supports touch events which allows you to add support to your JavaScript application for mobile devices. One potential gotcha is that you need to include the “event-touch” module using YUI.on in order for touch events to work.

Y.one("#test").on('touchstart', function() {
	// a touch event started
});

AJAX

AJAX requests are handled through YUI 3′s IO module. An AJAX call is made using the io function, as demonstrated below.

Y.io('/url/to/call', {
	// this is a post
    method: 'POST',
	// serialize the form
    form: {
        id: "my_form",
        useDisabled: true
    },
	// ajax lifecycle event handlers
    on: {
        complete: function (id, response) {
            var data = response.responseText; // Response data.
        }
    }
});

The IO method accepts a URL and a configuration object as parameters. The configuration object is highly configurable, but I’ve included a couple of the most common options in the above example.

  1. method – what HTTP method to use
  2. form – if this option is specified, the form with the given id will be serialized and passed with the request.
  3. on – this object sets up event handlers for various stages in the request lifecycle.

YUI’s io module also allows you to send cross domain requests using a Flash based file provided by Yahoo. There are some caveats, however. First, you must have a copy of the YUI flash file on your server to actually make the request, and second, the domain you are accessing must have a cross-domain policy file that grants you access.

Y.io('http://www.somedomain/web/service/', {
    method: 'POST',
    data: 'data=123',
	// use flash
	xdr: {
		use: 'flash',
		dataType: 'xml'
	}
	// ajax lifecycle event handlers
    on: {
        complete: function (id, response) {
            var data = response.responseText; // Response data.
        }
    }
});

JSONP is also supported, but through the YUI JSONP module, not the IO module.

Y.jsonp(someurl, function(response) {
	// handle jsonp response
});

One more module that is quite useful in conjunction with AJAX is the JSON module. This allows you to easily parse AJAX request which return JSON. JSON can be parsed using the JSON.parse method

var obj= Y.JSON.parse(response.responseText);

Animation

YUI 3 contains an animation module that can be used to perform pretty much any kind of animation. The syntax is a good bit different than jQuery’s, so let’s take a look.

Animations occur in a couple of steps in YUI. First, you set up a new animation object that describes your animation, then you run it.

    // animate a div from no size to a height and width of 100
	var animation = new Y.Anim({
	   node: '#my-div',  // selector to the node you want to animate.
	   // values to animate from (optional)
	   from: {
	      height: 0,
		  width: 0
	   },
	   // values to animate too
	   to: {
	      height: 100,
		  width: 100
	   },
	   duration: 0.5, // set duration
	   easing: Y.Easing.easeOut // set easing
	});

	animation.run();

All of the properties can be changed using .get() and .set() on the animation object, allowing you to change the animation or the DOM elements to animate. Animations also fire events that can be listened too.

	// animation is a Y.Anim object
	animation.on('end', function() {
		// fired after animation finishes
	});

Taken together, the YUI animation object can be used to create all kinds of animations in you application.


Widgets

One of the nicest features of YUI is its widgets. YUI 3 currently has a limited set of widgets (tabs, a slider, and an overlay to name a few), but provides a powerful framework for creating your own YUI 3 widgets. YUI 2, on the other hand, has an enormous library of widgets. Here are a few:

  • DataTable – a complete data table widget with ajax loading and pagination, editable cell support, resizable columns, and progressive enhancement.
  • ImageCropper – a widget that helps with image cropping.
  • LayoutManager – widget to make complex layouts via JavaScript.
  • Calendar – a popup calendar widget.

There are many more widgets that you can use, and you can find them all at the YUI 2 developer website

.


CSS Libraries

The last component that we’re going to take a quick look at is the YUI CSS libraries. YUI 3 provides four CSS resources.

  • CSS Reset – basic CSS reset rules. Everyone has their own idea of what a reset file should do, so you may or may not like this one.
  • CSS Base – these styles build on the Reset styles to provide consistent rendering across all supported browsers. This file provides things like input styles, header sizes, and table styles.
  • CSS Fonts – normalizes font sizes across all supported files. Once this stylesheet is applied, font-sizes are changed using percentages according to a table YUI provides. The YUI CSS Fonts resource is used by the popular HTML5Boilerplate.
  • CSS Grids – a CSS grid framework to help with layout. I’m not a fan of grids in general, but if you’d like to learn more, Andrew Burgess has a nice writeup of this one on Nettuts+.

Conclusion

This was only a quick look at a few of the components and modules that YUI offers. If this article has piqued your interest, I recommend that you head over to the YUI developer documentation and find what else YUI offers. What are your impressions? If you’ve used YUI in the past, what do you think of it?

November 03 2010

18:20

October 06 2010

14:18

Crash Course: YUI Grids CSS


The Yahoo User Interface Library is a rather extensive set of JavaScript tools for developers. Often left unnoticed are a few other useful components of the library that will speed up your coding: some CSS libraries. Today, I’d like to give you a tour of the YUI Grids CSS library.


Why?

Why should you even consider using the YUI Grids CSS library (hereafter referred to a “YUI grids”)? What makes it stand out? I haven’t looked extensively at other grids libraries, but I find these things compelling:

  • Good naming conventions

    YUI grids uses easy-to-remember ids and classes, and clean markup; once you learn it, you could come back to your code in a month and know which parts are from YUI and what each piece does.

  • Free file hosting

    This reduces your load twice: no need to host the file on your server, as well as faster page loading if the client has the file cached.

  • Compatibility with common ad sizes

    Yahoo has baked in sidebar widths that correspond with the Interactive Advertising Bureau’s ad guidelines.

  • Many layout options

    With multiple templates and the ability to nest page regions, Yahoo claims to offer over 1000 layout combination . . . all in less than 5kb.

Of course, YUI grids isn’t perfect. It’s a bit limiting when it comes to the pre-baked sidebar widths; however, if they suits your needs, you’ll save plenty of time, coding, and headaches when laying out your site.


Resources

As we begin, here are a few resources that will be of help.


Building Blocks

Before we get into the nitty griddy, let’s look at the building blocks of YUI grids. There are five different structures that you will work with to develop your layout; each of these structures is defined by either an id or a class (usually a class). They are as follows:

  1. Document
  2. Template
  3. Blocks
  4. Grids
  5. Units

Document

Obviously, your whole HTML file is the document, but in our case, it’s also the div immediately inside the body — the div that holds it all. This is where you define the width of your site. YUI grids gives you 4 width options: 750px, 950px, 100%, or 974px. These widths aren’t actually hardcoded pixels; they’re ems, so the page will adjust fluidly when your user adjusts their font size. If these don’t cut it, Yahoo has made defining a custom width a breeze. Here’s the code to create a document 800px wide:

#custom-doc
{
	margin:auto;     /* these two values are required, as  */
	text-align:left; /* they help YUI grids center the page */
	width: 61.54em; /* 800px / 13 = em-value for most browsers */
	*width: 60.00em; /* 800px / 13.333 = em-value for IE */
	min-width: 800px; /* optional, but recommended*/
}
	

To set the width, simply use id of doc, doc2, doc3, or doc4, respective to the values given above.


Template

There are seven templates to choose from. The first six define a two column layout; each one has a different width or orientation for the sidebar, with the main content column taking up the rest of the width of the doc. The templates are 1) 160px on the left, 2) 180px on the left, 3) 300px on the left, 4) 180px on the right, 5) 240px on the right, and 6) 300px on the right. To get the template of your desiring, simple add a class of yui-t# to the same div that you defined your doc on (replace the # with the numbers above). As I mentioned above, these sidebars are standard web-ad widths, so any advertising should fit comfortably inside them.

The seventh template—yui-t7—isn’t as well documented (oddly, it’s not on the cheat sheet I linked to above, but it is on this older version). It subtracts the sidebar, simply giving you one full width column (which can be divided into columns later).


Blocks

The blocks are the actual manifestation of the columns you defined in the template. They’re simply two divs within the doc div, both classed with yui-b. Happily, they don’t have to be immediate children of the main div; Yahoo gives this example:

<body>
  <div id="doc" class="yui-t1">
    <div id="hd">
      <-- Header Content -->
    </div>
    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <-- Main Content -->
        </div>
      </div>
      <div class="yui-b">
        <-- Sidebar Content -->
      </div>
    </div>
    <div id="ft">
      <-- Footer Content -->
    </div>
  </div>
</body>
	

You can see from the example that you don’t need to put the blocks directly inside the root div. This allows you to have a full-width header and footer, which is generally a nice idea. You’ll notice that the main content block is inside a div with an id of yui-main; YUI grids does this to give you the ability to have either your sidebar or your main column first in your code, which can be an advantage when you’re considering SEO or accessibility.


Grids & Units

I’ve grouped grids and units together because they’re really quite similar; both are divs. A grid (defined with class yui-g) basically tells 2 children (usually units) to split its width evenly. A unit (class yui-u) should always be the child of a grid and the parent of your content.

So, what’s the difference between a block and a grid?

  • Blocks
    • Are only used to define overall page columns
    • Are only used if you use templates 1 – 6
    • Are only used once (so you should never have more than 2 divs.yui-b on one page)
  • Grids
    • Are used to divide areas (such as your main block, or another grid) into columns
    • Are used on any template
    • Are nestable

Also, whenever you have multiple grids or units within a grid, it’s necessary to give the first one a class of first. This is because not every browser offers the pseudo-class :first-child.

But what if you want to divide a grid unevenly? Life isn’t always fair, is it? Fortunately, YUI offers a number of alternative choices to the yui-g class. Here’s a list of the others:

  • yui-gb : Takes 3 units and divides equally
  • yui-gc : Takes 2 units and divides as 2/3 and 1/3
  • yui-gd : Takes 2 units and divides as 1/3 and 2/3
  • yui-ge : Takes 2 units and divides as 3/4 and 1/4
  • yui-gf : Takes 2 units and divides as 1/4 and 3/4

That’s all of them; just slap 2 or 3 units in each of the above grids, and you’ll have unequal columns.


Basic Example

Well, now that you know the ropes, let’s go over a basic example. Let’s say we want the standard site layout—you know, main content column with a sidebar on the right—with a bit of a twist: we’ll divide the main column into two smaller ones, and divide one of those further into two.

As I mentioned, Yahoo offers hosting for this framework, and it’s usually a good idea to take advantage of that. Also, Yahoo recommend the HTML 4.01 strict Doctype, so that’s what I’ve put in. Here’s what we start with:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
  <html>
    <head>
      <title>A Simple YUI Grids CSS Example</title>
      <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/grids/grids-min.css">
    </head>
    <body>
    </body>
  </head>
</html>
  

Step 1 : Docs and Blocks

The first step is to set up our document div and blocks. We can stick with the first doc width (750px), and go with template 6, which gives us a 300px right sidebar.

<body>
  <div id="doc" class="yui-t6">
  </div>
</body>
		

For the two blocks of content, we need to add two divs.yui-b. We’ll make the top one the larger column, by wrapping it with div#yui-main.

<div id="doc" class="yui-t6">
  <div id="yui-main">
    <div class="yui-b">
      MY MAIN CONTENT DIV
    </div>
  </div>
  <div class="yui-b">
    MY SIDEBAR DIV
  </div>
</div>
		

Super! So, here’s what we have so far: I’ve taken the liberty of styling it a bit, so you can see what’s going on.


Step 2 : Grids and Units

It’s not too impressive yet, but we’ll get there. Now let’s divide the larger column into two. We can achieve this by putting a div.yui-g (that’s parenting two units) inside it:

<div id="yui-main">
  <div class="yui-b">
    <div class="yui-g">
      <div class="yui-u first">
        First sub-column
      </div>
      <div class="yui-u">
        Second sub-column
      </div>
    </div>
  </div>
</div>
		

This gives us two columns on the left; not bad; let’s divide the second of those columns into two. To do this, we have to change it to a grid, and put two units into it.

<div class="yui-u first">
  First sub-column
</div>
<div class="yui-g">
  <div class="yui-u first">
    First sub-sub-column
  </div>
  <div class="yui-u">
    Second sub-sub-column
  </div>
</div>

This is a great example of the fact that grids and units are of equal rank and can stand side by side: they only differ in usage.


A Gotcha

This brings me to a padding gotcha (which will segue to a big benefit of YUI grids). First, look at the code we’ve written so far, with some filler text:

Your good taste should notice the lack of padding around the edges of our columns. But that can be easily fixed with some padding—say, 0.5em—on .yui-u, right?

Yikes! YUI grids has set the widths for these divs, and because padding adds to the width of div, we’ve got an overflow problem. An easy solution to this is to add the padding to the immediate children of the .yui-u.

To keep our columns in line and easily readable, we’ll put the padding on the paragraphs within the .yui-u. But I don’t have to show you an image of that for you to figure out that our narrow columns just got narrower. This is where we can take advantage of a strong point of YUI grids. Let’s change the id on our root div from doc to doc2. Here’s a before and after:

By adding one character to our HTML, we can easily experiment with a wider layout; that’s the beauty of YUI grids. #doc2 is 200px wider than #doc, so now our narrow paragraphs are a comfortable width.


Complex Example

That’s a pretty simple example; let’s look at a more complex one . . . that’s really not any harder to create. We’ll start with the seventh template—a single column—with a 750px wide document (#doc) and slice it differently over multiple rows. Here’s what we begin with:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title>A Complex YUI Grids CSS Example</title>
    <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/grids/grids-min.css">
  </head>
  <body>
    <div id="doc" class="yui-t7">
    </div>
  </body>
</html>
		

Because we are not using templates 1 – 6 (which have sidebars), we don’t need to have any divs.yui-b. We can start right in with a few divs.yui-g; we’ll add 4:

<div id="doc" class="yui-t7">
  <class="yui-g">
  </div>
  <class="yui-g">
  </div>
  <class="yui-g">
  </div>
  <class="yui-g">
  </div>
</div>
		

Row 1

Let’s divide the top grid into three parts; to achieve this, we’ll need to change the class to .yui-gb. Then, we simply put three divs.yui-u inside, and give the first one the first class.

<class="yui-gb">
  <class="yui-u first">
  </div>
  <class="yui-u">
  </div>
  <class="yui-u">
  </div>
</div>
		

A quick preview at what we’ve got so far (again, I’ve applied minimal styling for clarity and thrown in some filler text):


Row 2

For the second row, we can try the .yui-gc, which gives us two columns; one will take up 2/3 and the other 1/3.

<class="yui-gc">
  <class="yui-u first">
  </div>
  <class="yui-u">
  </div>
</div>
		

The minimal styling on this shows a small flaw in the system: the second row doesn’t line up with the first row perfectly; In my opinion, this is a worthwhile trade-off, since a misalignment this tiny would be relatively easy to mask.


Row 3

For grid 3, we’ll do something a bit more advanced: four columns. This requires nesting two grids within a grid, like so:

<div class="yui-g">
  <div class="yui-g first">
    <div class="yui-u first">
    </div>
    <div class="yui-u">
    </div>
  </div>
  <div class="yui-g">
    <div class="yui-u first">
    </div>
    <div class="yui-u">
    </div>
  </div>
</div>
		

Notice that we still follow the “.first to the first” rule, on both the second-level grid and the third-level units. That’s really the only rule you have to remember; even this “advanced” work is pretty simple. Here’s what we’ve got so far.

For the final grid, we’ll do a simple split: two columns.

<div class="yui-g">
  <div class="yui-u first">
  </div>
  <div class="yui-u">
  </div>
</div>
		

And that’s it! For the final shot, I’ll add a bit of margin between rows.

It’s obvious that this isn’t entirely pretty, but the potential for it should be just as obvious: I haven’t had to write any layout styling. With the YUI Grids CSS framework, it’s easy to quickly layout your websites and be confident that they’ll be consistent across all major browsers.

Used YUI grids in a project and have an opinion about it? Prefer a different grids library? Let me know in the comment!

This article was originally posted on the ThemeForest blog. We are currently porting over some of the more popular articles to Nettuts+.

September 17 2010

18:06

Progressive enhancement using nothing but JavaScript?

Progressive enhancement is still a confusing matter for a lot of people who are very excited about the capabilities of JavaScript in modern browser environments. It can feel anachronistic to write your solutions for a non-JS environment and then once more enhances in JavaScript. I grew up like that so for me it is a simple matter of doing the right thing but with today’s world of JavaScript libraries and out-of-the-box widgets it can seem a drag.

Enter Dav Glass of the YUI team. He’s been turning the concept of progressive enhancement around in his head and as a JS lover and backend code “endurer” he set out to solve this issue once and for all in a pure JavaScript way.

Here’s the issue: you cannot assume JS to be available on the client side as your visitors might be on a slow mobile connection or are paranoid enough to turn off JS or actually have it turned off for them by company policy or many other cases.

So in order to use pure JavaScript to render a solution that works for everybody the natural thing was to move the JS solution to the server side and re-use it on the client when it is possible.

If you say server-side JavaScript you end up quickly talking about Node.js and so did Dav.

Check out the following demo:

Express.js, Node and YUI3 for progressive enhancement by photo

All of what you see is driven by JavaScript – there is no server-side PHP fallback. Yet if you turn off JavaScript in your browser, you get the same experience.

The reason is that Dav uses Express.js and Node to render the HTML of the application server-side with JavaScript and YUI3. The code is available on GitHub and a video of him giving a talk about this is available soon on the YUI blog.

This is an exciting concept as it means that we can build progressively enhancing solutions using any widget library if we just think of the server-side case, too. This can mean a lot less code and easier maintenance as the only skill needed to build bullet-proof solutions is JavaScript.

The missing piece to the puzzle though is a fully fledged DOM renderer on the server side. DOMJS works but a C++ version would be much better in terms of performance and have all the features of DOM-2.

September 03 2010

12:00

The Quick & Easy Way of Getting into YUI: SimpleYUI

The Yahoo! YUI is an incredibly feature-rich JavaScript library with a LOT of functionality but getting your head around all of those features can be tough. The YUI team wants to help developers get up and running more quickly and announced yesterday the release of SimpleYUI; a basic and more streamlined version of the YUI library.

SimpleYUI will contain basic DOM access and manipulation including support for CSS 3 selectors in the selector engine, animations via the new transition module, the event system, Ajax and JSON support.

The great thing is that when you're ready to leverage more advanced features like managed attributes and custom events, you still have the ability to do on-demand loading just like you'd expect from the full-featured version of YUI. This includes any YUI 2 or 3 component or YUI 3 Gallery module.

JAVASCRIPT:
<script type="text/javascript" src="http://yui.yahooapis.com/3.2.0pr2/build/quickyui/quickyui-min.js"></script>

<script>
Y.use('dd-drag','yui2-datatable', 'gallery-accordion', function(Y) {
     
      // here you can use YUI 3 Drag and drop, YUI 2 DataTable, Accordian or any other control contributed to the gallery by the community   

});
</script>
 

YUI team member Eric Miraglia put up a nice post about SimpleYUI which shows you some of the goodness include.

Tags: Front Page YUI

July 27 2010

18:34

YUI 3.2.0 preview release 1 – touch events support, transitions and browser-specific loading

Over at the the YUI blog the team just announced the preview release of YUI 3.2.0. YUI3 now has some interesting new features that the team wants you to try and tell them if they work out for you. The changes to the already very powerful library are quite ambitious:

  • Touch event support for mobile interfaces including flick and move gestures
  • Browser capability loading – which means that every browser gets the least amount of code necessary to make it work
  • Transition support for the animation module – meaning only browsers that don’t support CSS3 transitions get the JavaScript animation fallback
  • An update to the CSS grids to allow for more flexible layouts
  • A ScrollView widget similar to the one in Apple iOS
  • The uploader has been transitioned over from YUI2 to YUI3

So check out what is on offer and give the YUI team feedback on what would be nice to have and what is broken. In their own words:

The goal of a preview release is to make it as easy as possible for all of us in the community to evaluate progress of the upcoming release and provide feedback. Please take some time to test 3.2.0pr1 and let us know what you find by filing tickets in the YUI 3 bug database marked as “Observed in version” 3.2.0pr1. We’ll do our best to address preview-release questions on the YUI 3 Forums, too.

There are three ways to get started with the preview release: YUI 3.2.0pr1 is available on the CDN via the 3.2.0pr1 version tag — so you can reference preview-release files like http://yui.yahooapis.com/combo?3.2.0pr1/build/yui/yui-min.js. If you switch to this seed file for the preview release, all subsequent use() statements will continue to load YUI 3.2.0pr1. Or You can download the full YUI 3.2.0pr1 from YUILibrary.com, including source code and examples for all components. Or you can simply explore the functioning examples roster.

June 10 2010

17:40

April 20 2010

11:19

Server side rendering with YUI on Node.js

Dav Glass did some cool work with YUI and the server when he got it running on Node.js and then got the DOM working.

Having the DOM available is important as it allows you to do interesting things. You can take the same code and render on either client OR server side. NoScript turned on? Still works.

Aptana Jaxer pioneered this (running on a headless Firefox, giving them ALL of the APIs of a browser.... including XUL etc). This time around we are on node, with jsdom++:

To support this work, I’ve created a new YUI 3 module called nodejs-dom. This module will include the proper libraries, if available, and set up the YUI instance with a document and window reference. Along with the configuration, it will create a new object on the instance called Browser. Since all YUI 3 module use Node and Node uses Y.config.doc, you shouldn’t need to do anything else to make YUI 3 code work on the server. But if you’re working with older JavaScript and need to access the document, window, location or navigator objects, they’re all available on the Browser object.

Try an example such as this calendar. View source, and it is just HTML. In practice some logic could detect behaviour and enable client side in some situations, server side in others.

Oh, and YUI3 is looking really nice these days. A nice balance between a nice API + really nice looking widgets + a crockfords-worth of security care.

JAVASCRIPT:
  1.  
  2. YUI().use('json', 'base', 'io-nodejs', function(Y) {
  3.     var url = 'http:/'+'/yuilibrary.com/gallery/api/user/davglass';
  4.     Y.io(url, {
  5.         xdr: {
  6.             use: 'nodejs'
  7.         },
  8.         on: {
  9.             start: function() {
  10.                 Y.log('Start IO', 'info', 'TEST');
  11.             },
  12.             success: function(id, o) {
  13.                 Y.log(Y.JSON.parse(o.responseText).userinfo);
  14.             }
  15.         }
  16.     });
  17.  

April 08 2010

14:00

POC Photo App Using YUI 3 & Geolocation APIs

Geolocation functionality is hot. Every app you see now wants to ID where you're at and help you find cool things around you. The great thing is that building this functionality into your applications is getting easier and easier. For example, Eric Ferraiuolo wanted to create an app that showed off the features in YUI 3.1 and with a little help from the JSONIP Google App Engine app, YQL, the W3C Geolocation API, Flickr Photos Search API , & CSS3, he built a Photos Around You, an app which finds geo-tagged photos based on your estimated location.

photos_around_you-450x311

The post does a great job of breaking down the YUI modules used for building out the app and showing plenty of code samples for leveraging the various APIs. Here's the code that handles the IP-based lookup via YQL or the browser's geolocation capabilities:

JAVASCRIPT:
  1.  
  2. locFromIP = function (ip, callback) {
  3.     var query = 'select * from geo.places where woeid in ' +
  4.                 '(select place.woeid from flickr.places where (lat, lon) in ' +
  5.                 '(select Latitude, Longitude from ip.location where ip="{ip}"));';
  6.  
  7.     new Y.yql(Y.substitute(query, { ip: ip }), function(r){
  8.         callback(r.query && r.query.results ? r.query.results.place : null);
  9.     });
  10. };
  11.  
  12. locFromPos = function (pos, callback) {
  13.     var pos = { lat: pos.coords.latitude, lon: pos.coords.longitude },
  14.         query = 'select * from geo.places where woeid in ' +
  15.                 '(select place.woeid from flickr.places where lat={lat} and lon={lon});';
  16.  
  17.     new Y.yql(Y.substitute(query, pos), function(r){
  18.         callback(r.query && r.query.results ? r.query.results.place : null);
  19.     });
  20. };
  21.  
  22. if (navigator.geolocation) {
  23.     navigator.geolocation.getCurrentPosition(
  24.         Y.rbind(locFromPos, this, callback),
  25.         Y.bind(getIP, this, Y.rbind(locFromIP, this, callback))
  26.     );
  27. } else {
  28.     getIP(Y.rbind(locFromIP, this, callback));
  29. }
  30.  

What I really like about Eric's code is his decision to leverage Christian Heilmann's YQL Geo Library as a failover for those browsers that currently don't support the W3C Geolocation API for IP-based location identification. I wasn't quite able to get the YQL version to function for me. It did find my location but wouldn't correctly display any geo-tagged pictures. Firefox's geolocation implementation, which uses Google Location Services as its service provider, worked great though and that in itself is a big win. When Firefox first debuted the feature, the results seemed frequently off but it looks like the data is becoming more consistent.

Coming in at about ~180 lines of code, it's a great tutorial app that demonstrates some nice power features of YUI 3.1 and the referenced APIs. Check it out.

March 05 2010

13:52

Friday fun: Let’s translate YUI3 to jQuery

I just came across this wonderful Gist on gitHub:

JAVASCRIPT:
  1.  
  2. var $;
  3. YUI().use('*', function(Y){
  4.   $ = Y.get;
  5.   for(var p in Y) {
  6.       $[p] = Y[p];
  7.   }
  8. });
  9.  
  10. // test
  11. $('body').append("boo!");
  12.  

In case you want to use YUI3 but really really like jQuery syntax :) OK, it breaks the whole sandboxing idea of YUI3, but that's a small price to pay, right?

December 09 2009

17:44

Three search engines, one interface – 25 minutes live code

It is amazing how much easier it is these days to build pretty sweet mashups by using hosted services. Here’s a screencast of using Yahoo, Bing and Google to build a search interface in under 25 minutes without having to read any API docs or installing SDKs by using YQL:

Building a search mashup with YQL using Google, Yahoo and Bing – live :) from Christian Heilmann on Vimeo.

Give it a lick of paint and you have a pretty sweet little tool:

GooHooBi - search Google, Yahoo and Bing in one go!

All the source code is available on GitHub.

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...