• Home
  • Quick Start
    • Configurator
    • Download YUI 3
  • Documentation
    • User Guides
    • Examples
    • Tutorials
    • API Docs
  • Community
    • Gallery
    • Blog
    • Forums
    • YUI Theater
    • Calendar
  • Contribute
    • YUI on GitHub »
    • File a Ticket
    • View Tickets
    • Dashboard
  • Other Projects
    • YUI 2
    • YUI Compressor
    • YUI Doc »
    • YUI Builder
    • YUI PHP Loader
    • YUI Test
    • YUI Website

Blog: Archive for June, 2010

« Older Entries

Mobile Browser Cache Limits: Android, iOS, and webOS

Update (July 12, 2010): While the results described in this article are accurate for HTML pages, new tests have revealed very different cache limits for CSS and JS resources. The updated results are described in Mobile Browser Cache Limits, Revisited.

In early 2008, Wayne Shea and Tenni Theurer wrote a YUI Blog post on iPhone Cacheability in which they shared the results of research into various characteristics and limitations of Mobile Safari’s cache in iPhone OS 1.x. Among other things, they found that individual components larger than 25KB were not cached, and that there was a maximum total cache size of between 475KB and 500KB.

Much has changed since then. We’ve seen two new major releases and many minor releases of the iPhone OS (now iOS), and several other mobile devices with highly capable browsers have appeared to challenge the iPhone. Stoyan Stefanov found, in late 2009, that the iPhone’s cache limits had changed (sadly, for the worse). But where do things stand now? And what about those non-iOS browsers?

Background

Browsers have two types of caches that we’re concerned with for the purposes of these tests:

  • The component cache, or object cache, stores individual files. HTML, CSS, JavaScript, and images all go into the component cache. Whenever it needs one of these components, the browser first checks the cache before making a network request.
  • The page cache, also known as the back/forward cache, stores an entire page and all of its components, as well as their current state. When you use the back or forward button, the browser will load the page from the page cache if possible.

The HTML5 application cache is another type of cache that’s widely supported by mobile browsers. Browser makers already do a good job of documenting the limits of the application cache, so I didn’t include it in my testing. More on the application cache later.

Devices Tested

I tested the following mobile browser/platform combinations:

  • Android 2.1 (Nexus One)
  • Mobile Safari on iOS 3.1.3 (1st-gen iPhone)
  • Mobile Safari on iOS 3.2 (iPad)
  • Mobile Safari on iOS 4.0 (iPhone 3GS)
  • Mobile Safari on iOS 4.0 (iPhone 4)
  • webOS 1.4.1 (Palm Pre Plus)

Note: With the exception of Mobile Safari on iOS 4.0, I tested only one device in each category. If there are variations between individual devices or differences based on installed software beyond the OS, my tests would not detect those variations. These particular devices were tested because they’re the ones I had access to, not because I consider them to be more important than other devices.

Methodology

Cache testing is tedious, but relatively simple.

I wrote a tiny Sinatra app (fork it on GitHub!) that generates a response consisting of a requested number of pseudorandom alphanumeric and whitespace bytes. The responses can be served either gzipped or uncompressed. The following far-future expiration response headers are sent to ensure that all responses are considered cacheable:

Cache-Control: max-age=315360000
Expires: Fri, 01 May 2020 03:47:24 GMT

Over my local network, I then manually performed the following steps on each device to test the component cache:

  1. Load the cache test index page.
  2. Tap on a link to a component of a particular size, ranging from 5KB to 20MB, and wait for it to finish loading.
  3. Tap the back button.
  4. Tap the same link again. Observe whether the random characters are the same, and whether the server console prints a log entry for a request, to determine whether the component was cached in step 2.
  5. Repeat and adjust component sizes as necessary to determine the maximum component size that will be cached.

To test the page cache, I performed essentially the same steps except that instead of tapping the link again in step 4, I tapped the browser’s forward button, causing it to use the page cache rather than the component cache.

Support for ETag and Last-Modified was determined by tweaking the server to send the appropriate ETag or Last-Modified response headers (in separate tests) and to omit the far-future expiration headers. I then inspected the request headers received by the server to verify that the browser sent the expected If-None-Match or If-Modified-Since headers on step 4.

Results

I tested with gzip both enabled and disabled, but I found that gzip had no effect on cacheability on any device. The uncompressed component size is what matters in all cases, regardless of whether or not that component is served gzipped. As such, all component sizes mentioned here are uncompressed sizes.

The table below illustrates my overall findings.

Table: Mobile browser cache characteristics
Browser/OS/Device Single Component Limit Total Component Limit Page Cache Size Limit Supports Last-Modified Supports ETag Survives Power Cycle
Android 2.1 (Nexus One) ~2MB (~2,048,000b) ~2MB (~2,048,000b) ∞ 2 Yes Yes Yes
Mobile Safari, iOS 3.1.3 (1st-gen iPhone) 0b 1 0b 1 ∞ 2 No No No
Mobile Safari, iOS 3.2 (iPad) 25.6KB (26,214b) ~281.6KB (~288,354b) 25.6KB (26,214b) Yes Yes No
Mobile Safari, iOS 4.0 (iPhone 3GS) 51.199KB (52,428b) ~1.05MB (~1,100,988b) ∞ 2 Yes Yes No
Mobile Safari, iOS 4.0 (iPhone 4) 102.399KB (104,857b) ~1.9MB (~1,992,283b) ∞ 2 Yes Yes No
webOS 1.4.1 (Palm Pre Plus) 3 ~1MB (~1,048,576) ? ~1MB (~1,048,576) No No Yes

Notes:

1 Mobile Safari on iOS 3.1.3 doesn’t appear to cache any components, regardless of size, except for the page cache. It’s unclear whether this is intentional or a bug.

2 The page caches in Android 2.1, iOS 3.1.3, and iOS 4.0 (but not iOS 3.2) appear to be limited only by available RAM when it comes to individual page size. I didn’t attempt to determine exactly how many separate pages could coexist in the page cache at once.

3 webOS test results were inconsistent and at various points the cache seemed to stop working altogether until the phone was power-cycled. I don’t consider these results conclusive, or even trustworthy, but they’re listed here for the sake of comparison.

Android

The Android browser exhibited the best cache behavior of all devices tested. While it appears to impose no limit on the size of individual components, the total cache size seems to be limited to approximately 2MB, which means that individual components are effectively limited to 2MB as well.

The page cache appeared to impose no limit on the size of individual pages, happily caching every byte I threw at it until the available RAM was exhausted and the browser crashed.

I was pleasantly surprised to find that Android’s component cache survived both browser restarts and power cycles, a feat none of the iOS devices was able to match.

Possible caveat: A review of Android’s WebKit source tree leads me to believe that its cache limits may adapt based on the amount of RAM and/or flash memory available on the particular device on which it’s running. If true, these numbers may only be applicable to the Nexus One. In fact, if the cache size adapts based on unused memory rather than total memory, these numbers may only be applicable to my Nexus One.

I could be mistaken, but the differences in the iOS 4.0 test results on the iPhone 3GS and iPhone 4 support this theory. (Android and Mobile Safari are both WebKit-based browsers, so they may have this behavior in common.) If you’re familiar with the WebKit source and can shed more light on this, please get in touch with me.

iOS

Results varied wildly across the three most recent versions of iOS. Astonishingly, Mobile Safari on iOS 3.1.3 did not cache components of any size, despite having an apparently unlimited page cache size. This is troubling since it means iOS 3.1.3 users are likely getting a suboptimal browsing experience, especially if they aren’t using wifi. The unlimited page cache size does little good here, since it only comes into play for back/forward navigations. This behavior is a significant change from what others observed in previous iOS releases and I can’t imagine any good reason for it, so I suspect this may be a bug.

Mobile Safari on iOS 3.2 (which is only available on the iPad) does not exhibit this bug. Its 25.6KB component limit and ~281.6KB total cache limit are better than nothing, but they still seem paltry compared to the other devices tested. Uniquely among iOS devices, the iPad appears to limit the size of pages in the page cache to 25.6KB, the same as its component size limit.

Mobile Safari on iOS 4.0 exhibited different limits on the iPhone 3GS and on the iPhone 4, which implies that the limits adapt based on available RAM (the iPhone 3GS has 256MB while the iPhone 4 has 512MB; both devices tested had 32GB of flash memory). On the iPhone 3GS, iOS 4.0 has a 51.199KB component size limit and a ~1.05MB total component cache size.

On the iPhone 4, the component size limit was almost exactly two times the limit on the iPhone 3GS, at 102.399KB. The total component cache size was approximately 1.9MB. Perhaps because iOS 3.2 and iOS 4.0 were developed separately but branched from a common ancestor, the iOS 4.0 page cache size appears to be limited only by available RAM on both devices tested, just like iOS 3.1.3.

None of the iOS devices preserved the contents of the cache across forced browser restarts or device power cycles, although they did preserve the cache when merely switching applications without actually killing the browser.

webOS

My test results on webOS were so inconsistent that I have little confidence in them. I’ve included what little data I managed to gather purely for the sake of completeness. Please take it with a hefty grain of salt.

As near as I was able to determine, webOS might have an individual component size limit of about 1MB, with a matching page size limit in the page cache. I was unable to coax If-None-Match or If-Modified-Since request headers from webOS, which implies that it does not support ETag and Last-Modified.

On some tests, it appeared that webOS’s maximum component size was greater than 1MB, but this was inconsistent. As far as I can tell, webOS appears to have a nasty bug where, after a certain point—possibly when the maximum total cache size is reached—the cache just completely stops working altogether until the phone is power-cycled. In some cases even power cycling didn’t fix the cache breakage, so I eventually gave up trying to establish the exact cause of the problem and the exact limits of the webOS cache.

Recommendations

Based on these results, I offer the following recommendations to anyone developing web applications for the tested devices:

  • Use far-future cache expiration headers. This will prevent the browser from having to send a conditional GET request and will improve cacheability in webOS, which doesn’t support ETag or Last-Modified.
  • At least until iOS 4.0 arrives on the iPad, try to limit individual component sizes to 25.6KB or less, uncompressed. And urge your iPhone users to upgrade to iOS 4.0 as soon as possible.
  • If your website must support iOS 3.1.3 users (which is likely), if it requires components larger than 25.6KB, or if the total size of all your components is larger than 281.6KB, consider using the HTML5 application cache, localStorage, or database storage to store your components. Alex Kessinger’s recent YUI Blog post, An Introduction to Using YUI 3 in Offline Applications, might be of interest for YUI 3 developers considering this approach.
  • Do your own testing. Don’t assume that these results apply to any future version of any of the tested browsers or devices. Use these results as a starting point, but verify them yourself before you make major decisions based on assumptions about mobile cache limitations. The mobile browser world changes at a lightning pace, so this research will have a very short shelf life.

I’ve made my test code available on GitHub and I encourage you to use it, fork it, and share what you learn.

Call for Documentation

Browser makers, please consider documenting and publishing your browser’s cache limits. In the desktop world where these limits are typically so high as to be a non-issue, documentation wasn’t needed. In the mobile world, browser cache limits are vital information that web developers must have in order to create performant websites with compelling features.

The limits of new features like localStorage and the application cache are typically well-documented. Please extend this level of documentation to the component cache as well.

By Ryan GroveJune 28th, 2010

In the Wild for June 25, 2010

As always, let us know in the comments or @yuilibrary if we missed something important.

  • YUI 3-based Alloy UI Formally Announced at Liferay Conference: From the press release: ‘As part of this effort, Liferay also announced the immediate availability of Liferay Alloy UI. Developed in collaboration with Yahoo’s YUI project, Alloy UI provides a set of rich user interface components for quickly creating user-friendly portlets, widgets, and web applications. Alloy UI deals with the complexities of CSS, HTML, and Javascript, freeing developers to focus on business requirements and functionality. Alloy UI also helps solve some common cross-browser compatibility issues that typically consume project resources. The new library does not require a portal and can be used to develop components for any web application. Liferay Portal will standardize its front-end framework around Alloy UI, expanding the simplicity and capabilities of modern portal-based enterprise solutions. ‘Alloy UI represents a new capability for web developers to simplify the development of rich UIs,’ said Brian Chan, Liferay Portal’s creator and Chief Software Architect. ‘We are happy to have worked on this with the Yahoo team and feel it will be a great asset to help developers with their solutions.’‘ All Alloy UI components are now freely available to the YUI community in the YUI 3 Gallery.
  • AutoFusion’s CarPrices.com Launches Using YUI 3.1.1: YUI 3 Gallery contributor Josh Lizarraga has been working with Autofusion Inc. on the new CarPrices.com project, built using a host of YUI 3.1.1 utilities and widgets.  Josh will have more on this project in a future YUIBlog post.
  • Download Squad’s Erez Zukerman Advises JS Devs to Watch Crockford on YUI Theater: Writes Erez: “Douglas Crockford is a genius. Seriously – the guy is brilliant. He’s currently serving as Yahoo!’s chief JavaScript architect, he invented JSON (a widely used data interchange format), he’s part of the ECMAScript committee (the guys setting the JavaScript standard) and has a very broad understanding of the general history of programming languages and computer science. Recently, Crockford gave five talks about JavaScript as part of Yahoo!’s YUI Theater. These are all available for free, and they’re over five hours in length (more like six to seven hours in total, I think). What’s so cool about these talks is that Crockford really gives you a bird’s-eye view of the subject; the first hour is just history, and it’s really fascinating. It’s all over the place, starting with the Jackquad loom, through why we have both a Delete and a Backspace key on our keyboards, all the way to modern programming languages and JavaScript.” For more of Erez’s favorite JavaScript resources, check out his post; or head over to the Crockford on JavaScript page for Douglas’s latest videos (with many more filling the second column of YUI Theater).
  • Congrats to Matt Snider & Friends at YUI 2-based Mint.com, Winners of a 2010 Webby: Congratulations to Matt Snider and the other outstanding frontend engineers at Mint.com for their well-deserved 2010 Webby award in the Financial Services category.  Mint has been YUI 2-based since the beginning, and Matt continues to be a big contributor to the YUI project. You can see Matt’s five-word acceptance speech over on YouTube.
  • Ajaxian’s Dion Almaer Reviews Caridy Patiño Mayea’s Preload Gallery Module for YUI 3: Dion has a nice post up on Ajaxian reviewing Caridy Patiño Mayea’s Preload module for prefetching and caching assets, a YUI 3 Gallery entry that he wrote about recently on YUIBlog.
  • Using YUI Grids with Movable Type (by @foxxtrot): YUI contributor Jeff Craig wrote about his experience converting a Movable Type blog to YUI 2 Grids: “So, as anyone who’s ever read my blog before, you’ll see that over the weekend I upgraded my blog template to use YUI Grids and YUI3 for the JavaScript. By switching away from the MT templates (or, the templates that were standard when I installed the first versions of MTOS 4), I was able to reduce the HTML pageweight by damn near half. The old templates were really div-heavy, and had a ton of extra markup. Mostly, the decision was driven by a desire to redo the visual feel of my blog, and I felt that I may as well rewrite under YUI Grids while I do it.”
  • Nate Schutta Compares YUI and Dojo for IBM DevelperWorks: Nate Schutta writing for IBM developerWorks compares YUI 2.x and Dojo in a new post. While we’re focused more on the YUI 3.x codeline these days, Nate’s article has some useful guidelines for those thinking about JavaScript libraries and making a decision for their business or project. First — why YUI or Dojo?

    With so many excellent choices at your disposal, why would you consider YUI or Dojo? In a word: completeness. Unlike other solutions that involve additional libraries or plug-ins, Dojo and YUI have everything (and more) that today’s front-end engineer could want. While that is both a blessing and a curse, if you’re in the market for a one-stop shop for your Ajax needs, these are two powerful contenders. In addition to a wealth of JavaScript helpers and utilities, both offer top-notch widgets and controls—far beyond the limited palette of the standard browser.

    Nate’s advice on general library selection criteria is useful:

    • What do you want out of it? Are you looking for a complete replacement of nearly all UI elements on your page, or are you just looking for something to take a bit of the pain out of JavaScript programming?
    • How easy is the code to read? Despite massive improvements in documentation over the past few years, odds are you will have to dig into the code at some point. Before committing to a library, spend some time knee-deep in the source. Is it easy to understand, or does even the original author have trouble with it?
    • How good is the documentation? Clean and readable code can make up for less-than-stellar documents, but nothing helps you get started quite like tutorials and examples. Poke around the wiki or the website, and see what they have to offer. Are the examples clear and easy to follow? Does a quick Google search bring you to the proper part of their material?
    • What’s the community like that surrounds the library? Check out the mailing lists. Is there a lot of traffic? Are new people treated with respect or derision? Has the code been updated recently, or was the last release several years ago?
    • Can you get help? Although this is related to the previous bits about community, it’s always valuable to look around the development community and see who’s using what. Check out the job boards to get a sense of which libraries are showing up frequently on resumes.
By Eric MiragliaJune 25th, 2010

YUI: Open Hours Friday June 25th

The latest installment of YUI: Open Hours will be this Friday, June 25th.

Last week, Eduardo Lundgren introduced us to some of the great AlloyUI modules recently added to the Gallery. The discussion covered instantiation, configuration, development decisions, and some history of their TreeView module. But that was just the beginning. We also explored their IO, Node, and form validation modules and spent some time on some of the visual styles available. Eduardo even gave us a sneak preview of the new Liferay, Inc. portal, powered by all this hard work. Really top notch work.

All that said, it’s hard to say if the show-and-tell or the conversation was the real headliner. Great code related content aside, there was a lot of good feedback and discussion about community collaboration, the nature of the Gallery, and how we can make it and YUI better. So a big thanks to everybody on the call!

This week, we’re going to dabble a bit in both the raw developer world as well as the designer world. Caridy Patiño is back with us to talk about his Event Binder module that was featured here just this morning. We’ll do a code review and discuss the configuration step that has to be done before YUI is even loaded. That’s right: pure, unadulterated DOM scripting. You might want to wear a helmet.

Then we’ll move on to the equally nuanced skin design process with Jeff Conniff, the yahoo responsible for the current variety of Slider look-and-feels. He’ll walk us through his process of building the visual assets and show how you can take the same PSDs and easily create color themed assets that fit in your site palette. Here are the Photoshop files if you want to play along. I’ll also talk about some of the decisions made in constructing the CSS and DOM structure of Slider.

We’re back to the usual day and time this week: Friday from 10am to 12pm PDT. There’s a new attendee code for the conference call, but otherwise, the connection details are the same as usual.

  1. Dial in to 1-888-371-8922 (non-US participants, email me for a local number)
  2. Enter the attendee code 47188953#
  3. Join the screen sharing session (this will prompt you to install the Adobe Connect plugin if this is your first time using it)

I’ve also created a forum thread for this Open Hours so we can start the discussion early!

Also, as always, you can keep up to date with the upcoming schedule and topics by following @yuilibrary on Twitter or subscribing to the YUI Event Calendar.

Hope to see you there!

By Luke SmithJune 23rd, 2010

In the YUI 3 Gallery: Caridy Patiño Mayea’s Event Binder Module Provides Support for Early Event Binding and Event-driven Module Loading

This article introduces my Event Binder module, recently released in the YUI 3 Gallery.

YUI 3 is getting good traction in the developer community, with significant adoption of the latest 3.1.1 release and a huge infusion of new, innovative projects in the YUI 3 Gallery. Many developers are getting their heads around the on-demand nature of YUI 3 and starting to leverage those capabilities in their designs. This approach has big advantages, but it also can present some challenges.

One of these challenges is to catch user interactions early. Even as the browser starts rendering the page, we want the user to be able to start interacting with page elements. In many cases, those interactions might happen before the JavaScript initialization process (including the attachment of event listeners) has completed.

In many cases you can streamline your initialization code by setting only your event listeners and then adding the logic for loading the pieces that you need for every user interaction. Recently, engineers at Facebook talked about a similar approach to improve the loading process — see the interview from Rey Bango at JSConf. Here is an example of how this technique might work in YUI 3:

 <script src="http://yui.yahooapis.com/combo?3.1.1/build/yui/yui-min.js&
 
	3.1.1/build/oop/oop-min.js&3.1.1/build/event-custom/event-custom-base-min.js&
	3.1.1/build/event/event-base-min.js&3.1.1/build/dom/dom-base-min.js&
	3.1.1/build/dom/selector-native-min.js&3.1.1/build/dom/selector-css2-min.js&
	3.1.1/build/node/node-base-min.js"></script>
 
YUI().use('event-base', function(Y) {
    // wait until the user focuses on an input element to start loading assets
    Y.on("click", function(e) {
 
      Y.use ('anim', 'io', function() {
          // load a remote content and display it using an animation here
      });
 
      e.halt(); // stop the propagation
    }, "#demo");
});

This introduces some complexity in your code because listeners not only have to deal with the user interaction but also with some loading logic. Another downside to this approach is that you still have to load some JavaScript code at the top (in this case YUI seed, the Event Utility, and some dependencies) in order to define at least the listener and the loading logic to catch early actions. So, let’s consider this as two separate use-cases:

  • Capturing early user interactions
  • Facilitating the on-demand nature of some user interactions

To address these needs I’ve created a new module for YUI 3. My main focus has been to create a component that works without affecting your application logic. This new module is called "gallery-event-binder" and is now available through the YUI Loader.

Capturing early user interactions

The main goal of this feature is to guarantee that user interactions are queuing until event listeners are initialized.

Let’s see an event binder example:

YUI({
    //Last Gallery Build of this module
    gallery: 'gallery-2010.06.07-17-52'
}).use('gallery-event-binder', 'event', function(Y) {
 
    Y.on('click', function(e) {
 
        // do your stuff here
        e.halt(); // stop the event propagation if you want...
 
    }, '#demo');
 
    // flush early user interactions
    Y.EventBinder.flush('click');
 
});

In this example, YUI Loader will try to load the gallery-event-binder and event modules on-demand, and once they’re both ready along with their dependencies, the code within the callback function (third argument) will be executed. During execution, a listener is set for an element with id=demo. The trick here is that once Y.EventBinder.flush('click') gets called, the system will flush some of the click events that might have happened before this initialization code gets executed.

The configuration

This technique requires some extra configuration, specifically the definition of YUI_config as a global variable to tweak the YUI execution. Don’t worry, it’s very simple. Let’s see an example in details:

 
YUI_config = {
    // standard YUI_config configuration
    combine: true,
    filter: 'min',
 
    // event binder configuration starts here
    eventbinder: {
        // Event handler to store events that you want to redispatch.
        fn: function(e) {
            var binder = YUI_config.eventbinder,
                filter = /yui3-event-binder/,
                container = (e.target || e.srcElement),
                info = {
                    target: container,
                    type : e.type
                };
 
            // look for an element with the class yui3-event-binder
            while (container && !filter.test(container.className)) {
                container = container.parentNode;
            }
 
            if (container) {
                (binder.q = binder.q || []).push(info);
 
                // prevent the default browser action for this event
                if (e.preventDefault) {
                    e.preventDefault();
                }
                return (e.returnValue = false);
            }
        },
        // interface to listen for specific events
        listenFor: function(type) {
            var d = document;
            // Before the library loads, we have to deal with browser inconsistencies
            if (d.addEventListener) {
                d.addEventListener(type, this.fn, false);
            } else {
                d.attachEvent('on' + type, this.fn);
            }
 
            return this;
        }
    }
};
// add events to the monitoring process
YUI_config.eventbinder.listenFor('click');

This code should be included at the very top of the page. It will be just a few bites once you minify this configuration object. I recommend using a cacheable (external) file for production and including it in the head section in your pages. You can read more about YUI_config and the different configurations that you can tweak through this object in the official API documentation.

You can modify this configuration to suit you best, and define events that you care about as well. In the above example, we added ‘click’ to the monitoring list (last line). You can add multiple events to the monitoring list using chaining:

YUI_config.eventbinder.listenFor('click').listenFor('keyup').listenFor('mouseover');

How does this feature work?

Once the configuration (i.e., YUI_config) logic is executed, along with the call to YUI_config.eventbinder.listenFor, a listener for a specific event type will be defined. Only events that bubble up will be monitored as the listener will be defined for the document element. When a user interaction is caught at this level, it will be analyzed, specifically checking if the target element or any of its ancestors has classname yui3-event-binder. If so, the event will be added to a queue and the default behavior for that event will be prevented. This technique provides an easy way to monitor specific types of interaction in specific areas of the page.

When this code is executed, listeners for events of the specified type or types are added to the document, so when those events occur and bubble up (this only monitors events that bubble), they will be stopped and their information stored in a processing queue. Later, in your use() callback when your initialization is finished, simply call Y.EventBinder.flush to redispatch all the stored click events as if they happened just then—courtesy of the event-simulate module.

Facilitating the on-demand nature of some user interactions

The main goal of this feature is to help developers to define loading logic based on user interactions.

Here’s another event binder example:

 
YUI({
  modules: {
    'my-custom-module': {
      fullpath: './my-custom-module.js'
    }
  }
}).use('gallery-event-binder', 'node', function(Y) {
 
  // set a listener for '#demo a' and rely on 'my-custom-module' 
  // to handle that particular event.
  Y.EventBinder.on('click', 'my-custom-module', '#demo a');
 
  // set a delegate listener for all the anchors in a list and rely  
  // on 'my-custom-module' and 'my-another-module' to handle those particular events
  Y.EventBinder.delegate('click', ['my-another-module'], '#mylist', 'li a');
 
});

Here we use Y.EventBinder.on and Y.EventBinder.delegate to define some listeners. These two methods wrap Y.on and Y.delegate to drive loading logic through a user interaction. This lets us defer loading of specific functionality on a page until the user tries to use a particular feature.

In this case, when a user clicks on one of the elements, we load one or more custom YUI modules that implement all the features associated with that particular click. Once those modules become available (and new listeners are set), the binder will flush the event that was on hold during the loading process to preserve the state of the action.

This feature doesn’t require any initial configuration. Both of Event Binder’s features can be used at the same time to cover early and on-demand user-interactions. In this case, you need to define the configuration, then set the on-demand listeners, and finally flush the early events.

Here’s an end-to-end event binder example:

 
// configuration
YUI_config = { /* your custom event-binder configuration here */ };
YUI_config.eventbinder.listenFor('click')
 
// initialization
YUI({
  modules: {
    'my-custom-module': {
      fullpath: './my-custom-module.js'
    }
  }
}).use('gallery-event-binder', function(Y) {
  
  Y.EventBinder.delegate('click', ['my-custom-module'], '#doc', '.yui3-event-binder a');
  Y.EventBinder.flush('click');
 
});

A more advanced configuration

You can modify the fn function in your configuration to be more selective about which events to queue and you can store more information about the events. Additionally adds a yui3-waiting class to the click target which we style in CSS to display a loading spinner:

 
YUI_config = {
    // standard YUI_config configuration
    combine: true,
    filter: 'min',
 
    // event binder configuration starts here
    eventbinder: {
        // set of options that should be preserved for every event (all optional)
        eventProperties: [
            "ctrlKey", "altKey",
            "shiftKey", "metaKey",
            "keyCode", "charCode",
            "screenX", "screenY",
            "clientX", "clientY",
            "button",
            "relatedTarget"
        ],
 
        // listener callback function
        fn: function(e) {
            var binder = YUI_config.eventbinder,
                props = binder.eventProperties,
                filter = /yui3-event-binder/,
                target = (e.target || e.srcElement),
                container = target,
                info = {
                    target: target,
                    type : e.type
                },
                i;
 
            if (target.nodeType === 3) {
                // target is a text node, so use its parent element
                target = target.parentNode;
            }
 
            // look for an element with the class yui3-event-binder
            while (container && !filter.test(container.className)) {
                container = container.parentNode;
            }
 
            if (container) {
                target.className += ' yui3-waiting';
 
                // back up the event properties to simulate the event later on
                for (i = props.length - 1; i >= 0; --i) {
                    info[props[i]] = e[props[i]];
                }
 
                (binder.q = binder.q || []).push(info);
 
                // prevent the default browser action for this event
                if (e.preventDefault) {
                    e.preventDefault();
                }
                return (e.returnValue = false);
            }
        },
 
        listenFor: function(type) {
            var d = document;
 
            if (d.addEventListener) {
                d.addEventListener(type, this.fn, false);
            } else {
                d.attachEvent('on' + type, this.fn);
            }
 
            return this;
        }
    }
};
// add events to the monitoring process
YUI_config.eventbinder.listenFor('click');

Check out this event binder example to see this advanced configuration in action.

Conclusion:

For high performance web applications, it’s important for pages to load and become responsive quickly. To accomplish this, we have to rely on on-demand loading techniques. Once you start using them, it’s equally important to control user interactions that can happen before the corresponding code for an action become available.

Event Binder (gallery-event-binder) provides friendly APIs to deal with both use-cases without you having to change your application logic. It can be applied to any YUI 3 application without introducing extra complexity to your code.

By Caridy PatinoJune 23rd, 2010

Using the YUI 3 Calendar Date Selector from Alloy

The Alloy components (contributed by Nate Cavanaugh and Eduardo Lundgren from Liferay) in the YUI 3 Gallery are simple to use. This example illustrates the use of the Alloy calendar to progressively enhance a set of select elements for date selection.

Let’s start with the markup — the HTML that will be on the page and functioning regardless of whether JavaScript is enabled. Alloy’s Calendar module does not require this markup; you can feed it an empty element and it will create the select elements for you in the event that your use case would not benefit from progressive enhancement.

<div id="calendar">
	<select class="yui3-datepicker-month" name="month" id="monthselect">
		<option value="0">
			January
		</option>
		<option value="1">
			February
		</option>

...

	</select>

        <select class="yui3-datepicker-day" name="day" id="dayselect">
		<option value="1">
			1
		</option>
		<option value="2">
			2
		</option>

...

	</select>

        <select class="yui3-datepicker-year" name="year" id="yearselect">
		<option value="2009">
			2009
		</option>

...

	</select>
</div>

With this markup in place (or with just an empty root element if we aren’t progressively enhancing existing form fields), we bring in the Alloy Calendar module with datepicker selection support from the YUI 3 Gallery. This requires us to have YUI 3 on the page and then to follow the configuration step outlined on the module’s Gallery page.

<script src="http://yui.yahooapis.com/3.1.1/build/yui/yui-min.js"></script>
<script>
YUI({
	// All of this configuration information can be cut-and-pasted from the Gallery entry for
	// this module: http://yuilibrary.com/gallery/show/aui-calendar-datepicker-select
    gallery: 'gallery-2010.06.07-17-52',
    modules: {
        'gallery-aui-skin-base': {
            fullpath: 'http://yui.yahooapis.com/gallery-2010.06.07-17-52/build/gallery-aui-skin-base/css/
							gallery-aui-skin-base-min.css',
            type: 'css'
        },
        'gallery-aui-skin-classic': {
            fullpath: 'http://yui.yahooapis.com/gallery-2010.06.07-17-52/build/
							gallery-aui-skin-classic/css/
							gallery-aui-skin-classic-min.css',
            type: 'css',
            requires: ['gallery-aui-skin-base']
        }
    }
}).use('gallery-aui-calendar-datepicker-select', function(Y) {
    var datePickerSelect = new Y.DatePickerSelect({
		displayBoundingBox: '#calendar',
		dateFormat: '%m/%d/%y',
		yearRange: [ 2009, 2012 ],
		dayField: Y.one("#dayselect"),
		dayFieldName: "day",
		monthField: Y.one("#monthselect"),
		monthFieldName: "month",
		yearField: Y.one("#yearselect"),
		yearFieldName: "year"
	}).render();
});

</script>

Here’s a live version of this simple example.

It’s as simple as that. The configuration properties for datePickerSelect are lucidly defined in the Alloy documentation. In this example, the properties are used to set the root element, format the date, set the date range, and then wire up our existing select elements to the widget instance so that it knows which form fields to use for progressive enhancement. In practice, only the root element (displayBondingBox) is a required property.

Check out the YUI 3 Gallery roster for a full list of the Alloy UI contributions.

By Eric MiragliaJune 18th, 2010

Implementation Focus: YUI 3 Powering Autofusion’s ResearchPro

About the author:Josh LizarragaJosh Lizarraga is a YUI Contributor and frontend developer located in San Diego, California. He uses YUI to build rich frontend interfaces and Ajax applications for Autofusion, Inc., a San Diego firm that offers web solutions to the automotive industry in the United States and Canada. When he’s not on the clock, Josh enjoys contributing to the YUI project with test cases and Gallery modules.

ResearchPro Home Screen

About the Project

In addition to serving industry professionals, Autofusion provides end-user information resources via our CarPrices.com sister-site. “ResearchPro” is the name we’ve bestowed on our brand new car research application, which allows the user to quickly and easily find everything there is to know about a potential new car purchase.

Researching a new car before you buy is typically a daunting yet necessary experience, and the current options available to consumers are not very user-friendly. ResearchPro attempts to remedy these issues with a simple, guided approach to car research. We also take the experience one step further, allowing customers to receive a free quote on their dream car from local dealers.

Why YUI?

We started using YUI 2 for all of our frontend development about two years ago, and haven’t looked back. YUI’s focus on application development makes it a no-brainer for Autofusion, as we provide many embeddable web apps and widgets to our customers.

Over the years we have used just about every YUI 2 component there is in both our client web properties and our internal tools. YUI’s proven track record and incredible documentation really set it apart from the other libraries we’ve worked with. The refinements to the library offered by YUI 3 made it an easy choice for this project.

How YUI is Utilized in the Project

ResearchPro makes use of several YUI 3 components, namely IO, JSON, Node, Event, Animation, and even the beta Slider widget. We’re also using the selector-css3 and event-mouseenter modules, as well as a custom module that handles the JSON communication with the backend.

ResearchPro YUI 3 Slider Usage

Challenges and Benefits of Using YUI 3

Migrating from YUI 2 to YUI 3 was both the largest challenge and the largest benefit during ResearchPro’s development. Working with Node instances instead of DOM nodes directly can take some adjusting to at first, but we quickly found that this excellent abstraction greatly reduces the amount and complexity of the code for a given task. Likewise, the chainability of YUI 3 methods offers some great syntactic sugar that is hard to live without.

The primary challenge of the YUI 3 migration was and continues to be beta bugs. The first YUI 3 beta was released a few months before we started development, and we took that opportunity to start this project with the new codeline. We wanted to be familiar with YUI 3 once it replaces YUI 2 in our workflow down the road. During development, we discovered and reported several bugs, some of which are still being worked out today.

What’s Next for Autofusion?

We are always developing new products with YUI and revising our existing offerings to incorporate YUI on the frontend. Our online inventory solution is powered by YUI 2, and we’re currently planning a refined version of the product that will use YUI 3 in its place.

Our inventory interface makes heavy use of the Container module family, so hopefully by the time we start development YUI 3 will have implementations of Panel and Dialog. We’ve been very pleased with the rapid growth of features, and expect YUI to be our frontend toolkit of choice for years to come.

By Josh LizarragaJune 18th, 2010

YUI: Open Hours, Wed June 16th

It’s time again for YUI: Open Hours! A change of schedule this week, though. The call will be on Wednesday.

I want to start by sending a huge thanks to Iliyan Peychev, Andrew Bialecki, Matt Snider, and Jacob Fogg for featuring their Gallery widgets in the last Open Hours. From Matt’s game UI inspired Radial Menu to Iliyan’s full featured Accordion, it was a great exploration of the types of UI tools you can find (or create) in the Gallery today as well as a study in different ways to use YUI 3 to solve UI challenges. You can find links to the modules in the May 21st Open Hours post, and a sampling of some of the interesting points from the discussion in the comments.

This week, hot on the heels of their huge YUI 3 Gallery contribution, Nate Cavanaugh and Eduardo Lundgren of Liferay, Inc. will be joining us to introduce us to some of the new AlloyUI modules. This is a pretty big deal. We’ve been working with these guys for months to get their 65 modules into the Gallery. That’s right, 65 modules! All created by just Nate and Eduardo. Talk about productive.

Obviously we’ll barely have time to scratch the surface of all the AlloyUI modules, but we will do a quick overview of some of the most interesting or popular ones and cover some “Getting started” code. There’s such a variety of modules, there will be something for everyone.

  • For YUI 3 newcomers or folks that have been waiting for the YUI 2 widgets to be migrated, there are now a lot more options to check out.
  • For people wanting to take those first steps creating something in YUI 3, there are now more things to write plugins for, patch, or extend.
  • For seasoned component developers, there’s now a lot more implementation code to reference for evolving conventions and components to collaborate on.
  • For more complex app developers, you can get a sense of one team’s strategy for code submodularization and approach for building and packaging modules in a larger or more complex application.

Nate and Eduardo are open to whatever questions you have, so the conversation can go however deep, and in whichever direction you want. If you have any questions about a particular module or about anything else, ask away.

We’re changing up a little this week and moving Open Hours to Wednesday. The time will be the same as before, though (10am – 12pm PDT), and the connection details are also the same:

  1. Dial in to 1-888-371-8922 (non-US participants, email me for a local number)
  2. Enter the attendee code 4718 8953#
  3. Join the screen sharing session (this will prompt you to install the Adobe Connect plugin if this is your first time using it)

And as always, you can keep up to date with the upcoming schedule and topics by following @yuilibrary on Twitter or subscribing to the YUI Event Calendar.

Hope to see you there!

By Luke SmithJune 15th, 2010
« Older Entries

Pages

  • About
  • Contribute
  • YUI Jobs

Recent Posts

  • YUI Weekly for May 17th, 2013
  • Yahoo’s International Team Is Hiring!
  • YUICompressor 2.4.8 Released
  • YUI 3.10.1 Released to Fix SWF Vulnerability
  • YUI Weekly for May 10th, 2013

Archives

Categories

  • Accessibility (25)
  • CSS 101 (6)
  • Design (51)
  • Development (590)
  • Frontend Jobs at Yahoo (13)
  • Graded Browser Support (8)
  • In the Wild (63)
  • Miscellany (11)
  • Open Hours (44)
  • Performance (23)
  • Releases (25)
  • Target Environments (11)
  • Yeti (3)
  • YUI 3 Gallery (29)
  • YUI Events (45)
  • YUI Implementations (55)
  • YUI Theater (146)
  • YUI Weekly (37)

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
© 2013 YUI Blog