Skip to content

Yahoo! User Interface Blog
Syndicate content
News and Articles about Designing and Developing with Yahoo! Libraries.
Updated: 1 hour 35 min ago

Ask Satyam — and Be Eligible for a Free Copy of the New YUI 2.8 Book from Packt

Thu, 07/29/2010 - 18:03

Satyam (Daniel Barreiro) wrote last week about his experience writing YUI 2.8: Learning the Library, the new YUI 2 volume now available from Packt.

Packt has generously offered a few free electronic copies to YUIBlog readers. Suggest a question or tutorial you’d like to see from Satyam on a YUI 2.8-related topic as a comment on this post, and if Satyam picks your suggested topic for one of his three “Ask Satyam” blog posts Packt will make an electronic copy of Satyam’s book available for you to download.

Satyam will be posting answers to his three favorite questions here on the blog over the next month or so.

Categories: Companies

YUI 3.2.0 Preview Release 1: Touch Event Support, Gestures, Transitions, CSS Grids, ScrollView, Uploader, and More

Mon, 07/26/2010 - 22:24

The YUI contributor’s team is pleased to announce the first developer preview of the upcoming YUI 3.2.0 release. This preview provides an opportunity for developers and implementers to help test the release for potential regressions and to provide feedback on new features and components. If you have an existing YUI implementation, please exercise YUI 3.2.0pr1 in your development environment and let us know what you find.

There are three ways to get started with the preview release:

  • Use from the CDN: 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.
  • Download the release: Download YUI 3.2.0pr1 from YUILibrary.com, including source code and examples for all components — including those new to this release.
  • Explore the examples: As a convenience, we’ve posted the preview (along with the functioning examples roster) to YUIBlog. Feel free to explore the release there as a prelude to switching your CDN version reference (or downloading the preview) and testing it out in your own environment.
Noteworthy Changes Coming in YUI 3.2.0

As with all YUI development work, you can track our current plans and progress on our YUI 3 tasklist, including a comprehensive list of YUI 3.2.0 (and some upcoming 3.3.0) changes; you can also check in on our progress addressing issues in the bug database. Here are some of the new and updated components featured in the 3.2.0 developer preview:

  • Intrinsic support for touch events has been added (mynode.on("touchstart", function(e) {});). We’ve also added a Gestures module with two bundled gestures — gesture-flick and gesture-move — that work with both touch- and mouse-driven devices. Check out the API docs or the bundled sample page for ideas about how to start using Gestures.
  • YUI’s intrinsic Loader now supports capability-based loading. This allows us to segregate, for example, IE-specific code into separate submodules and allow the Loader to bundle that code only for browsers that require it. We’re leveraging this new feature to avoid shipping IE-specific code in the Dom module to non-IE browsers, a performance/k-weight boost that will benefit all users of modern browsers with no code change required.
  • YUI 3’s animation portfolio now supports transitions via the Transition module, providing browser normalization for this powerful, hardware-accelerated (where available) technique for handling transitions; check out the example for sample code. Animation, in its most basic form, has a streamlined dependency tree for modern browsers, significantly reducing the k-weight for simple animation in better browsers.
  • YUI 3.2.0 will bring with it a new beta version of YUI’s CSS Grids component, and you can begin exploring this new approach to Grids in the preview release. The examples are the best place to start.
  • We worked with Michael Johnston of the Yahoo! Mobile Engineering team to bring a new (beta) ScrollView widget to YUI 3.2.0. ScrollView provides a scrolling pane implementation familiar to users of native Apple iOS applications, emulating the elasticity of the element when scrolled to the beginning or ending limit. You’ll see in the 3.2.0pr1 examples for ScrollView that this component is device neutral, working well with a mouse as well as with touch events on your Android or iOS device.
  • The Uploader component from YUI 2 is now part of the YUI 3 family as well, debuting as a beta in 3.2.0.
  • The History module that debuted with YUI 3.0.0, which was a port of the YUI 2 version, has been deprecated (it remains available in YUI 3.2.0 as history-deprecated). A new beta History utility debuts in 3.2.0, based on Ryan Grove’s History Lite module from the YUI 3 Gallery. A preview-release example from the new component is a good starting reference.
  • The JSONP and YQL Query modules from the YUI 3 Gallery have become canonical components, debuting as beta in this release.
Feedback

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.

Categories: Companies

YUI Theater Comes to Boxee, Courtesy of Chad Auld and the Brilaps Team

Thu, 07/22/2010 - 16:15


YUI contributor and former Yahoo Chad Auld emailed us to tell us about his latest project with his Brilaps group — a project that has brought YUI Theater to the TV screen via Boxee. In Chad’s words:

Boxee is an up-and-coming cross platform application that aims to help bring web content to the TV. It is based on the open source XBMC project and allows users to write new plugins to bring in additional content. We launched a new project about three weeks ago to build our first Boxee plugin, and we selected the YUI Theater as the content we wanted to bring from the web to the TV. There are so many great videos archived there (and growing), we think it is a terrific source of content for developers to have access to from their couch (especially since most of the videos are a bit longer than someone might have time to watch comfortably from their laptop). It took us about a week to build the plugin, another week to polish it up and sort out a few bugs, and about a week to get the application approved by the Boxee QA team and pushed into the public repository. I just got word that it hit the public repository this morning and so I wanted to reach out and let you know.

This is fantastic news for anyone who has been enjoying YUI Theater content and would like to catch up on the latest from Douglas Crockford, Brendan Eich and all the other great YUI Theater speakers from the comfort of his/her couch. Check out the video above for a tour of the UI, and then go grab Boxee and get started.

Categories: Companies

Frontend Engineering Positions Available with the Yahoo! Flex Force Team

Wed, 07/21/2010 - 21:00

The Yahoo! Flex Force is currently looking to expand our team with a few talented frontend Engineers. As part of the Flex Force team, you will have the opportunity to work on multiple strategic projects of high profile and high visibility. These positions involve being an ambassador of best practices and sharing knowledge across the organization. We work closely with the different platform teams, including the YUI team, to ensure we’re using the latest strategies, techniques, and tools.

As a recent example, the Flex Force team was behind the implementation of the new Yahoo! Updates widget which is built entirely using YUI 3.

To be successful at this role, you’ll need to be a self-starter and fast learner with a positive mindset who can quickly ramp up and take on different challenges. A true passion for frontend technologies and best practices is also required.

If working with me and my colleagues on the Yahoo! Flex Force sounds interesting to you, head to the Yahoo careers site and check out the following positions:

Categories: Companies

YUI: Open Hours Wed, July 21st

Wed, 07/21/2010 - 01:07

For those of you that don’t subscribe to the YUI calendar or YUILibrary.com forum, the next installment of YUI: Open Hours will be tomorrow, July 21st.

This time we’re going to focus on a recurring theme for YUI community contributors that are just getting started building their own modules: How to build a Widget and how to build a Plugin in a YUI 3 way.

Anthony Pipkin, aka apipkin of #yui IRC channel fame, will be the guest, guiding us through his learnings over the last year and showing how to move from copying and pasting the YUI 3 documentation examples to feeling confident that you’re making the right choices for how to approach a problem in a “YUI 3 way of thinking”.

We’ll take a look at two of his simpler Gallery modules, the Button Widget and the Node IO Plugin. He’ll discuss what they looked like originally, versus today, and why they changed.

Then we’ll play around a while, maybe build something from scratch based on what the folks on the call want to cover.

Matt Sweeney (Node, Selector, TabView, Grids, etc) and Satyen “the Guru” Desai (Widget, Plugin, Base, Attribute, etc) from the YUI team will also be on the call. So there will be best practices in the house.

For YUI 3 consumers that aren’t (yet?) contributors, this call should still be valuable for understanding the thinking behind how YUI 3 widgets and plugins are built and what sort of patterns to expect from new YUI components. And no doubt there will be other great takeaways as always.

We’ll be online from 10am to 12pm PDT. 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)

Here’s the forum thread for this Open Hours. I’ll post some of the interesting takeaways after the call.

Follow @yuilibrary on Twitter for the latest.

Hope to see you there!

Categories: Companies

Author Notes: Writing YUI 2.8: Learning the Library, the New YUI 2 Book from Packt

Tue, 07/20/2010 - 19:14

Daniel Barreiro (Satyam)About the Author: Daniel Barreiro (screen name Satyam) has been around for quite some time. The ENIAC was turned off the day before he was born, so he missed that but he hasn’t missed much since. He’s had a chance to punch cards, program 6502 chips (remember the Apple II?), own a TRS-80 and see some fantastic pieces of operating equipment in his native Argentina which might have been in museums elsewhere. When globalization opened the doors to the world, his then barely usable English (plus an Electrical Engineering degree) put him on the career path which ended in a 5-year job in the Bay Area back in the days of NCSA Mosaic. Totally intrigued by the funny squiggles a friend of his wrote in his plain text editor, full of <’s and >’s, he ended up learning quite a lot about the world of frontend engineering. It’s been a long journey since COBOL and Fortran. Now he lives quite happily semi-retired in the Mediterranean coast close to Barcelona, Spain. When he’s not basking in the Mediterranean sun, Satyam can be found among the most prolific and knowledgable participants in the YUI community on the YUI Forums.

In December 2009, editors at Packt Publishing asked me if I’d like to write the second edition of their book on the YUI Library. The original author, Dan Wellman, was engaged in other business at the time, and they needed an author who was broadly familiar with YUI 2. The first thing I thought was: aren’t you a little bit late? Much of YUI 3 was already out in GA and more was coming with every release. But the Packt team wanted to proceed, and I agreed to take on the challenge.

On July 16th, the new volume came out, YUI 2.8: Learning the Library, not as a second edition but as a new title. In the end, it wasn’t such a bad decision. While the book was going through the editing process, YUI 3 gained the ability to load YUI 2 components from the use() statement. This extends the usefulness of the extensive YUI 2 catalog while taking the pressure off developers to produce YUI 3 versions of all YUI 2 components.

The goal with this new volume was to cover all non-beta YUI 2 components. This broad vision forced me to take a deeper look at components I had barely used in their most basic forms as well as others I’d not used at all. However, in contrast to the first edition, a project that began not long after the library had been made public, I had a few years of cumulative experience with YUI — my own experience paired with that of the many users who share their experiences and advice on the forums and the blog. I was also spared from many blunders by an excellent team of reviewers, two of whom, Caridy Patiño and Iliyan Peichev, are also well known YUI contributors.

To keep the book to a manageable length, I eliminated some images, long examples, and reference material that could be found at the YUI website. While the first edition had at most two components per chapter, the new one has up to four and has a couple of new chapters. Even so, some components didn’t make the cut.

The Evolution of YUI 2

I learned a lot about the YUI Library while writing this book, and the changes I made to Dan’s text were instructive about the library’s evolution since its release in 2006.

The programming style for example code has changed in these years. Instead of creating a namespace (or using YAHOO.example, which is always available as a placeholder), we now tend to fit everything within an anonymous function created when the DOM becomes available. (This style is closer to what we see in YUI 3.) We now use namespaces when we absolutely need to create globally accessible variables (including objects) such as when we create a custom library component. Sandboxing saves us some typing, since we can define functionally-scoped aliases for the objects we use more often from YUI (Dom, Event, Lang are common shortcuts) or variables of our own. This approach also lets YUI Compressor do a far better job.

Having a panoramic view of the whole of the library allowed me to notice how it developed over time. The architecture of the components changed and it is clear how everything has converged into what is now YUI 3.

Early components, like TreeView, had few dependencies. As certain patterns started to become obvious, some basic component infrastructure started to develop. The Container family had a Config object which allowed for getter and setter methods, and so have all the components that inherit from it. It also uses the Custom Event object, which is one of the two ways to work with custom events we have available in YUI 2.

With the release of TabView came the YUI 2 Element Utility, which provided improved getters and setters (via AttributeProvider) as well as better custom events (via EventProvider). Seventeen other YUI 2 components inherit from Element. Looking at the evolution the library, it’s easy to see how the ideas behind Element, as a DOM element wrapper, came to inform YUI 3’s Node. Element’s role as a basis for other components was broken out in YUI 3’s Base and Widget, though the new components are all far more powerful and complete, each in its own area. For example, Node’s all and one methods return Node instances while Element’s getXxxx methods return plain DOM element references, not completely abstracting the DOM.

The two models, Config and CustomEvents on the one hand and AttributeProvider and EventProvider on the other are not totally incompatible. In Menu and Split Buttons both models coexist, as Button inherits from Element and it hosts a regular Menu that inherits from Container.

Undoubtedly, YUI 3 benefited from all of this experience; but YUI 2 also benefitted from YUI3. Cool stuff came from YUI 3 to enrich YUI 2, such as event-delegate and element-delegate and other new events we can listen to (focusin and focusout, mouseenter and mouseleave). This also became possible because of the way we load components, which changed during YUI 2’s lifespan — most importantly with the introduction of the YUI 2 Loader — and became formalized as intrinsic support for client-side loading in YUI 3.

Loading affected how the components got designed and how the final component files are built. In YUI 2, to minimize the number of outstanding server requests, the components had to have as much of what they needed packed together. Thus, some components got loosely related objects in them just to have them handy when and if needed, others got a bunch of objects with a whole range of features packed in one file because loading the separate parts was too costly. Then came aggregates such as yahoo-dom-events.js or reset-fonts-grids.css since they are almost invariably used together or utilities.js which gathers all the often used components in the YAHOO.util branch. But the real change came with combo-handled requests, which allowed us to pull any number of script and css files each in just one http request. That makes it less necessary to optimize the packaging of the objects in the library into component files and those into aggregates based on a hypothetical ‘average user’.

In YUI 3 we no longer need to load the ‘container family’ all at once. We can load the separate widget-xxxx files on top of the basic widget according to the features we need. That approach is the standard in YUI 3, but it came as one of the steps in the evolution of YUI 2. Hence, more recent YUI 2 components like event-delegate and element-delegate are packaged separately from from their base components and so is Event’s mouseenter and mouseleave. We might see further splits in library components in future releases, allowing you to choose more specifically the feature set you want and leave unneeded code off the page.

This is a story of progress, a process that necessarily went though some failed efforts. Why doesn’t TreeView inherit from Element or why hasn’t Container, and thus Menu, switched to Element or, at least, to AttributeProvider and EventProvider? Technically, the answer is ‘backward compatibility’, but in more general terms it is ‘respect’. There are thousands of websites (and tens of thousands of developers) using the the published public interface of the YUI 2 components. Making those changes would break many applications or would cut them off the upgrade path, should they want to benefit from a code fix or a new feature. Being so respectful of the installed code base is a library feature in itself. Being respectful to us, who create that code, is a feature of the people in the YUI team, and I’m very grateful it is so.

Categories: Companies

Mobile Browser Cache Limits, Revisited

Mon, 07/12/2010 - 18:45

In Mobile Browser Cache Limits: Android, iOS, and webOS, I shared the results of my attempts to determine browser cache limits on Android, iOS, and webOS devices. At the end of the article, I wrote:

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.

As it turns out, that was good advice: the day after the article was posted, Steve Souders commented that he had run tests using a different methodology that was more representative of a real-world web workflow and had gotten different results.

New Methodology

My original methodology involved navigating directly to a randomly generated page of a certain size, served with a text/html content type. The results using this methodology were reliably reproducible (except on webOS), but as Steve pointed out, users don’t navigate directly to CSS and JavaScript files. My assumption that the limits for direct navigation to an HTML resource were the same as the limits for external CSS and JavaScript was incorrect, so even though the results of my tests were valid, they weren’t widely applicable.

Over the course of many IM sessions, several emails, and a couple of phone calls, Steve and I worked out a new testing methodology. I implemented a version of it on top of my cache testing framework, then Steve implemented a version capable of publishing results to Browserscope.

In the new tests, we load an HTML page that refers to a randomly-generated CSS or JavaScript component of a certain size. Then we navigate to a second HTML page that loads the same component and checks whether or not it was loaded from the cache. To determine whether a component was loaded from the cache, we store a timestamp in a cookie on each request; if the timestamp is updated the second time we load the component, we know the request hit the server, which means the component was not loaded from the cache.

New Results

We found that all the mobile browsers we tested had significantly higher cache limits for external resources loaded by a page than they did for an HTML page itself. This is excellent news for mobile web developers.

The table below illustrates our findings:

.cachestats { font-size: 12px; }

.cachestats td, .cachestats th { margin: 2px; padding: 2px; text-align: center; font-size:12px !important; }

.cachestats th { background: #efefef; font-weight: bold; padding: 4px; }

.cachestats .browser { text-align: left; } .cachestats .doubtful { background-color: #fff0db; } .cachestats .no { background-color: #ff5f5f; } .cachestats .yes { background-color: #b3ffaf; } Table: Mobile browser external resource cache characteristics
Browser/OS/Device Single Component Limit Survives Power Cycle Android 2.2 (Nexus One) 2MB Yes Mobile Safari, iOS 3.1.3 (1st-gen iPhone) 4MB+ No Mobile Safari, iOS 3.2 (iPad) 4MB+ No Mobile Safari, iOS 4.0 (iPhone 3GS) 4MB+ No Mobile Safari, iOS 4.0 (iPhone 4) 4MB+ No webOS 1.4.1 (Palm Pre Plus) ~0.99MB (1,023KB) Yes

Note that 4MB was the largest size we tested, and all the iOS devices cached 4MB components. The actual cache limit for those devices may be larger than 4MB. Also, webOS on the Palm Pre Plus gave consistent results in this test, whereas it had some problems in the previous test.

It’s possible that the much lower limits my previous test showed for HTML components on iOS may indicate the use of a RAM cache for those components, while the much higher limits for CSS/JS components in this test may indicate the use of a disk cache, but this is just conjecture. Android, at least, does appear to use a disk cache in both cases, since its cache survives power cycles.

New Recommendations

Based on these new results, coupled with the results from my previous tests, I offer the following updated set of recommendations:

  • Use far-future cache expiration headers. This will prevent the browser from having to send a conditional GET request.
  • Try to limit HTML pages to 25.6KB or less if you want them to be cached, since the previous tests showed that this limit—imposed by iOS 3.2 on the iPad—was the lowest HTML resource limit of the devices tested.
  • Keep CSS and JS components under 1MB. Of course, 1MB is enormous and your components should be much smaller than this, but don’t bother splitting a component into separate requests for the sake of cacheability unless its size approaches 1MB.
  • Consider using the HTML5 application cache if it’s important that your components persist in the cache for a long time, or across power cycles.
  • Do your own testing. I stressed the importance of this in my previous article and I’ll stress it again here. Use these results as a starting point, but verify them yourself before you make important decisions based on them.
Categories: Companies

In the YUI 3 Gallery: Base64 and Y64 encoding

Tue, 07/06/2010 - 19:39

Nicholas C. Zakas (@slicknet on Twitter) is the lead frontend engineer on the Yahoo! homepage, a YUI contributor, and author of Professional JavaScript for Web Developers and the newly-released, High Performance JavaScript.

Base64 encoding was originally designed to allow lossless data passing between 8-bit and 7-bit systems. The primary example of its usage is in email, which traditionally used 7-bit systems to transfer the email while those of us at home on our computers were using 8-bit systems. This became especially important with non-text email attachments, which would be encoded into MIME base64 and sent along to the destination.

More recently, base64 encoding has gained popularity for its usage in data URIs. For those unaware, data URIs are a way of embedding files inside of HTML and CSS. One of the supported data URI formats is base64.

Base64 encoding is still used frequently in programming, primarily for obfuscation but also for safe data transport. While some browsers have native base64 encoding and decoding, this functionality isn’t defined in any standard nor commonly available in all browsers. The YUI 3 Gallery Base64 module provides a common implementation of base64 encoding that can be used across all A-grade browsers. To use the Base64 module, include the following on your page:

<script src="http://yui.yahooapis.com/3.1.0/build/yui/yui-min.js"></script>
<script>
YUI({
    gallery: 'gallery-2010.06.16-19-51'
}).use('gallery-base64', function(Y) {

    //your code here
});
</script>

The Base64 module exposes a Base64 object with two methods: encode() and decode(). The methods are used as follows:

var decodedText = Y.Base64.decode(encodedText);
var encodedText2 = Y.Base64.encode(rawText);

Along with the Base64 module, I also wrote a Y64 module. Y64 is a base64 variant used at Yahoo! when base64 information needs to be transmitted as part of a GET request. Regular base64 has three characters that aren’t URL-safe: plus (+), slash (/), and equals (=). Y64 encoding replaces these with dot (.), underscore (_), and dash (-), respectively. This allows Y64-encoded strings to be placed in URLs without worrying about URL escaping of the characters.

The Y64 module requires the Base64 module, which is automatically pulled in when you include the following code:

YUI({
    gallery: 'gallery-2010.06.16-19-51'
}).use('gallery-y64', function(Y) {
    //your code here
});

The Y64 module exposes a Y64 object with encode() and decode() methods, so it usage is the same as with the Base64 object:

var decodedText = Y.Y64.decode(encodedText);
var encodedText2 = Y.Y64.encode(rawText);

If you’re planning on passing base64-encoded data in a URL string, you may want to consider Y64 as an alternative.

Please keep in mind that base64 and Y64 are not encryption algorithms. Encryption algorithms are designed to secure data from prying eyes. Base64 and Y64 are encoding algorithms designed to transmit data without the risk of data corruption – the type of corruption that happens when data is transferred from one system to the next and may be encoded and decoded in many different formats before arriving at the final destination.

A good example of this is link-sharing functionality. Suppose that you’re sharing a link by passing it to an entrypoint, such as http://www.example.com?share=<url>. The url needs to be URL-encoded for safe transmission, but that URL itself may also contain URL-encoded data. And believe it or not, sometimes browsers can mis-encoded URLs before transmission (it’s rare, but not unheard of). For a higher level of confidence that the data will arrive in good shape, you can use Y64 encoding:

var destination = "http://www.example.com?share=" + Y.Y64.encode(url);

The destination would then decode the URL value. Because this value won’t require URL-encoding, the chances of the data becoming corrupted during transmission are lessened.

Not everyone will need to use base64 or Y64 encoding in their web applications, but these can be very powerful tools to keep in your back pocket.

Further Reading:
Categories: Companies

Mobile Browser Cache Limits: Android, iOS, and webOS

Mon, 06/28/2010 - 18:45
.cachenotes, .cachestats { font-size: 12px; }

.cachenotes { margin: 0.5em auto 1.5em; } .cachenotes p { margin: 0 auto 0.4em; }

.cachestats td, .cachestats th { padding: 2px; text-align: center; font-size:12px !important; }

.cachestats th { background: #efefef; font-weight: bold; }

.cachestats .browser { text-align: left; } .cachestats .doubtful { background-color: #fff0db; } .cachestats .no { background-color: #ff5f5f; } .cachestats .yes { background-color: #b3ffaf; }

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.

Categories: Companies

In the Wild for June 25, 2010

Fri, 06/25/2010 - 20:10

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.
Categories: Companies

YUI: Open Hours Friday June 25th

Thu, 06/24/2010 - 01:07

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!

Categories: Companies

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

Wed, 06/23/2010 - 19:25

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:

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.

Categories: Companies

Using the YUI 3 Calendar Date Selector from Alloy

Fri, 06/18/2010 - 20:46

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.

Categories: Companies

Implementation Focus: YUI 3 Powering Autofusion’s ResearchPro

Fri, 06/18/2010 - 19:00

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.

Categories: Companies

YUI: Open Hours, Wed June 16th

Tue, 06/15/2010 - 10:26

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!

Categories: Companies

In the YUI 3 Gallery: The Preload Module

Thu, 06/10/2010 - 17:23

A few weeks ago, Stoyan Stefanov (@stoyanstefanov) published the result of his research about preloading components in advance without executing them. This technique can help improve the performance of successive pages that make use of the cached resources.

To leverage these results, we decided to port it to YUI 3 with a new module called "gallery-preload", which is now available through the YUI Loader.

Let’s see a preload example:

YUI({
    //Last Gallery Build of this module
    gallery: 'gallery-2010.05.05-19-39'
}).use('gallery-preload', function(Y) {
  Y.preload ([
    'http://tools.w3clubs.com/pagr2/1.sleep.expires.png',
    'http://tools.w3clubs.com/pagr2/1.sleep.expires.js',
    'http://tools.w3clubs.com/pagr2/1.sleep.expires.css'
  ]);
});

How does this module improve the user experience?

Nowadays, web applications have a large footprint in terms of JavaScript, CSS and images. Most of files in each of these categories are static and can be served through a CDN for cacheability. Once any of these files gets downloaded and cached, the browser doesn’t need to download the same file in successive requests for the same page. But still, we have a big impact in the initial page request.

Recent studies suggest that 0.1 second [100ms] is about the limit for having the user feel that the system is reacting instantaneously; more than that will make the user impatient (Jakob Nielsen). The same is true for the loading process. We need or make our applications run fast in order to stay ahead of our user’s expectations.

With web applications like Facebook or Gmail, the user usually has to log-in first. This is a classic scenario in which “preloading” makes sense. We can estimate that every user will spend between 5 and 10 seconds interacting with a form. During this time, our application is doing nothing. If we can use this time to load cacheable files in background, those files will be available in cache when the user completes the login process — because we know where s/he is going next, we know exactly what s/he will need. In general, any web application with predictable user paths (including form workflows) can leverage this technique.

This technique is not a new one, but, as Stoyan pointed out, it’s hard to do it without executing the scripts or injecting the CSS or displaying the images themselves; there is a cost associated with these post-load steps, and we should avoid paying that cost. Also, in some cases, these files will not play nicely with the initial page. In order to avoid conflicts and minimize the time to put a solution in place, we would need to guarantee that these files get included in the cache without using them in the current page.

This process needs to be completely harmless, and even if the user navigates or stops the loading process before the files get downloaded and cached, the fallback is always in place — the destination page will try to load the file directly.

The following code shows how to implement this approach using the gallery-preload module:

YUI({
    //Last Gallery Build of this module
    gallery: 'gallery-2010.05.05-19-39'
}).use('event-focus', 'gallery-preload', function(Y) {
  // waiting until the user focuses on an input element to start loading assets
  Y.on("focus", function() {
    Y.preload ([
      'http://tools.w3clubs.com/pagr2/2.sleep.expires.png',
      'http://tools.w3clubs.com/pagr2/2.sleep.expires.js',
      'http://tools.w3clubs.com/pagr2/2.sleep.expires.css'
    ]);
  }, ".myform input.query");
});

In this example, the script waits until the user focuses on one of the form input elements to start loading assets that will be used in the form’s target page. This will improve the loading time of the page once the user submits the form.

Check the differences between accessing a page directly, and preloading a set of YUI 2/YUI 3 components ahead of time:

Including few lines of codes to preload this set of components allows this page to load four times faster. No changes are required in the logic of your application, and no change is required in the target page…an inexpensive and effective performance tweak.

One more feature:

We also included a more advanced feature for those who want to be less aggressive. The module includes a built-in integration with Nicholas Zakas’ Idle Timer module; Idle Timer allows us to preload files only if the user is inactive for a given period of time. Here is an example:

YUI({
    //Last Gallery Build of this module
    gallery: 'gallery-2010.05.05-19-39'
}).use('gallery-preload', function(Y) {
  // preload files only when the user is idle for at least 100ms
  Y.preloadOnIdle ([
    'http://tools.w3clubs.com/pagr2/3.sleep.expires.png',
    'http://tools.w3clubs.com/pagr2/3.sleep.expires.js',
    'http://tools.w3clubs.com/pagr2/3.sleep.expires.css'
  ], 100);
});
Conclusions:

It’s important to be ahead of our users. Knowing the workflow of our web applications, and leveraging this preloading technique will help us improve overall user experience. It’s also important to do it without increasing the complexity of our applications. This new component (gallery-preload) delivers on both of these goals.

Categories: Companies

Join Us for BayJax on June 15 with a Special Focus on Accessibility

Wed, 06/09/2010 - 20:53

June BayJax is is almost here, so mark your calendars for June 15 at 5:30 p.m. For this occasion, we’ve invited three industry experts on accessibility to share their experiences with us. Nicholas Zakas and Victor Tsaran will give us an insider’s view into the work they’ve done for the newest Yahoo! homepage, while Dirk Ginader will be talking about “The Five Layers of Web Accessibility.”

Head over to the Meetup page to RSVP.

Accessibility on the Yahoo! Homepage by Nicholas Zakas and Victor Tsaran

Accessibility isn’t hard and, contrary to popular belief, it doesn’t take a lot of extra effort. Learn how the Yahoo! homepage team built accessibility into the product development cycle with the goal of providing the best possible user experience to everyone. Using a combination of progressive enhancement, ARIA, and a little ingenuity, even the most complex and dynamic features on the new Yahoo! homepage are available to everyone in interesting and fun ways.

The Five Layers of Web Accessibility by Dirk Ginader

Dirk Ginader, part of the Yahoo! Accessibility Taskforce, will talk about the “5 Layers of Web Accessibility.” He extends the traditional three-layer web development model (HTML, CSS and JavaScript) with two new layers for accessibility. He shows how easy it can be to make a website or web application more accessible by following a set of simple rules.

Details:

Agenda:

  • 5:30pm-6:00pm: Pizza, Drinks, Networking
  • 6:00pm-8:00pm: Talks on Accessibility

When: June 15

Where: Yahoo! HQ (URLs Café, Building C), 701 1st Ave, Sunnyvale, California 94089

Categories: Companies

Implementation Focus: Demeter

Mon, 06/07/2010 - 18:21

Niko Ni of GenMC Demeter Niko Ni is an experienced Frontend Engineer with over 5 years of web development experience located in Shanghai, China. He is currently working for Genesys Conferencing (now part of InterCall). He has been concentrating on building Ajax apps based on JavaEE or LAMP and contributing to some open source projects during his free time.

Tell us a little about your project.

“Demeter” is the codename for a recent web 2.0 application we built which provides powerful solutions to web conferencing, ad hoc meeting, and account management. Currently we have two major product suites: “Meeting Center” and “Admin Module”.

Although it’s still in RC phrase with no public access to view it, I have extracted a prototype of the Admin Module that demonstrates the management of portal properties.

Which components of the YUI Library are used in your project?

When we were initially trying to decide which JS framework and UI library to use, there were three things that sold us on YUI: the great documentation, the wide variety of mature widgets, and the BSD license, so I introduced YUI to my company. The following modules are used in our project:

  • CSS: Reset, Fonts
  • Core: YAHOO, Dom, Event
  • Utilities: Connection Manager, DataSource, Element, JSON
  • Widgets: Calendar, Container, DataTable
  • Tools: Logger, Test
Admin module implementation overview

Our main requirements for the Admin module included:

  • datatable with a customized editor popup
  • theme/skin customization
  • browser compatibility

Here is the simple markup that sets up the UI:

    <div id="datatable-ux">
		<div id="datatable-ux-hd"></div>

		<div id="datatable-ux-bd">
			<div id="node-depths" style="display: none">root  > Testing  > 5_Dev Testing BA  > 80000_1010</div>

			<div id="output"></div>
			<div id="yui-datatable" class="yui-dt">
			  <img src="images/icon-loading.gif" alt="loading" align="absmiddle" style="margin: 30px 0;" /> loading data...
			</div>
		</div>

		<div id="datatable-ux-ft"></div>
    </div>

	<div id="node-apply-wrap" style="display: none;">
		<fieldset>
			<legend>Apply to</legend>

			<input type="radio" name="node-apply" checked="checked" />Current node only<br />
			<input type="radio" name="node-apply" />Current node and child nodes<br />
			<input type="radio" name="node-apply" />Child nodes only
		</fieldset>
	</div>

Here is a code snippet of the simple extension I built for DataTable TextboxCellEditor:

   // simple example to extend the CellEditor Classes
   // short alias
   var lang = YAHOO.lang,
	  util = YAHOO.util,
	  widget = YAHOO.widget,
	  Dom = util.Dom,
	  Event = util.Event;

   // extend TextboxCellEditor
   Gcc.admin.TextboxCellEditor = function(config) {
	   Gcc.admin.TextboxCellEditor.superclass.constructor.call(this, config);
   };
   lang.extend(Gcc.admin.TextboxCellEditor, widget.TextboxCellEditor, {
	   renderForm : function() {
		   Gcc.admin.TextboxCellEditor.superclass.renderForm.call(this);

		   var oHd = document.createElement('DIV');
		   this.getContainerEl().insertBefore(oHd, this.textbox);
		   oHd.id = container.id + '-admin-editor-head';
		   Dom.addClass(oHd, 'admin-editor-hd');

		   var oCurrNode = document.createElement('DIV');
		   this.getContainerEl().insertBefore(oCurrNode, this.textbox);
		   oCurrNode.innerHTML = 'Current node: ' + Dom.get('node-depths').innerHTML;
		   Dom.addClass(oCurrNode, 'admin-editor-pd');

		   var oApply = document.createElement('DIV');
		   this.getContainerEl().appendChild(oApply);
		   oApply.innerHTML = Dom.get('node-apply-wrap').innerHTML;
		   Dom.addClass(oApply, 'admin-editor-fieldset');
	   },

	   move : function() {
		   Gcc.admin.TextboxCellEditor.superclass.move.call(this);
		   Dom.addClass(this.textbox, 'admin-editor-pd');
	   }
   });

Then a cellClickEvent handler detects the underlying type of data value being edited and calls one of the customized cell editors.

With our server architecture consisting of the Apache Struts framework and the application container Weblogic, we found that YUI plays a good companion role as the “Clientside-Controller” and works well with Struts action results as a dynamic datasource.

<%@ page pageEncoding="UTF-8" contentType="application/json; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
{"PropertySet":{
"Property":[
<s:iterator value="displayPropertyResultList" status="index">;
    {
    "Id":"<s:property value="id" />",
    "Name":"<s:property value="name" />",
    "Type":"<s:property value="type" />",
    "Value":"<s:if test="%{value != null}"><s:property value="value" /></s:if>",
    "ApplyFrom":"<s:property value="applyFrom" />",
    "ApplyTo":"<s:property value="applyTo" />",
    "Readable":"<s:property value="readable" />",
    "Writable":"<s:property value="writable" />"
    }
    <s:if test="%{!#index.last}">,</s:if>

</s:iterator>
]}
}

More details and source code are available on GitHub, where I have extracted a prototype of the Admin UI using a local datasource as a simple demonstration.

What have been the challenges of using YUI in this project?

The main challenges have been around the fact that most of our developers are in fact not frontend engineers. They don’t always have quite as much experience dealing with cross-browser issues or JavaScript-specific tricks. Fortunately YUI helps us a lot to make good code structures and to smooth out most browser compatibility issues.

What’s next for Demeter? What are some upcoming features you are tackling with YUI?

One of the upcoming features we are working on is a reporting module that will make heavy use of YUI Charts. And we are also planning to use TreeView widget to refactor our addressbook module.

We are still using YUI 2, but if more and more official widgets based on YUI 3 come out, we will consider totally moving to YUI 3 in the future.

Categories: Companies

In the Wild for June 4, 2010

Fri, 06/04/2010 - 22:05

We may be in the midst of the NBA finals, but In the Wild leads off this week with an item that gets us thinking about August. And football, in turn, gets us thinking about marriage, and in particular about the first known use of YUI in a marriage proposal. Let us know in the comments or on Twitter if we missed anything important.

  • YUI 3.1.1 on NFL.com: NFL.com’s fantasy portal employs YUI 3.1.1 Overlay, Anim, History, and more.
  • Free CMS Onpub Built with YUI 2: “Onpub is a PHP/MySQL web content management system. Onpub tightly bundles [the] Yahoo! User Interface Library [YUI 2] and CKEditor to enable the creation of standards-compliant, cross-browser, dynamic HTML websites. Onpub is designed to provide a base of well integrated components that have a proven track-record for helping web developers build websites that are easy to update, reliable and good looking.” (Original source.)
  • The Big Question (with YUI CSS Reset): Paul Irish asked on Twitter if this was the first marriage proposal aided by YUI?  I’m not sure, but on some level having a reset of all quirky, inherited, upstream style rules seems like a good metaphor for what you do when you tie the knot.  Congrats to the couple; I’m assuming that Carrie said yes! (Original source.)
  • Juego De Snake Built with YUI 3 by @jldorta: Caridy pointed out this nice snake game built on YUI 3.  Note the Twitter status rotator at the top of the page, also built with custom YUI controls (on the YUI 2 codeline). (Original source.)
  • Matt Snider’s Mac-style Radio Button Preferences As a YUI 3 Module: Writes Matt: “One of my favorite UI features of the Mac OS, both OSX and the iPhone, is the way it handles radio inputs. Instead of having small, hard to click little round circle (like the web), there are large buttons that are obviously grouped by use of a connecting bar. The best place to see this is in the system preferences on OSX. Today’s article, introduces a widget that will do the same, by converting existing radio buttons into a Mac Preference Radio.”
  • New Landscapes and Interiors Site Built by @joedag32 with YUI 2 JS and CSS Tools: Writes developer joedag32: “We…relied on the Yahoo! YUI Library to build the site as well. The site makes use of the following YUI components: CSS Reset, CSS Fonts, CSS Grids, Yahoo Global Object, DOM Collection, [and] Event Utility.  YUI really helped us to work faster and knowing that their library is used and tested by Yahoo! for A-Grade Browser support is a real time saver.” (Original source.)
  • Bryon Wyly on Secure (YUI 2-based) Pie Charts for SharePoint: Bryon Wyly writes on endusersharepoint.com: ‘I have done several blogs on how to use the google apis to create dynamic pie charts of lists in SharePoint based on code written by Claudio Cabaleyro and published at endusersharepoint.com. Perhaps the biggest request I have heard is, “How can I use these charts on my secure intranet?” Since Google Apps is an image that is shipped back to you after sending the required data and since SSL is not an option, Google Apps are useless for lists that use secure and sensitive data…  A recent comment on my blog suggested I look at…YUI as a possible solution. After a few hours work, I was able to marry a YUI pie chart with the JQuerry SharePoint List parser and create a Pie Chart generated by your SharePoint List, that does NOT send you data outside the network.’  Check out his post for full details.
  • Integrating YUI with Wicket: Mo Hammer has written up a tutorial on using the YUI Rich Text Editor with Wicket: “I was searching for a good rich-text editor for a Wicket project for some time, and eventually decided to use the YUI editor. It looks fairly nice, and can be configured quite well. Here, I’ll demonstrate how to use it with an HTML code editing button, as described in this example.”
  • Selenium and YUI Buttons (by @adamgoucher): Adam Goucher has written a tutorial on how to work with YUI 2 Buttons in the context of Selenium tests.
  • Nagare IDE Using YUI 2 (via @jlcarre): From the Nagare wiki: “Nagare IDE is a pure Web Integrated Development Environment dedicated to the
    Nagare Web framework. Using YUI, the Bespin editor, ajax and comet communications, it offers the browsing of your projects, the edition of the sources, the debugging of the raised exceptions and the consultation in real-time of the applications logs.” Nagare is “an Open-Source Python framework dedicated to web applications development. Its set of advanced features as continuation, direct callbacks registration, programmatic HTML generation, combined with its strong components model allow [you] to quickly and easily build highly complex and reusable applications.” (Original source.)
  • Free YUI 2.x API Documentation Dictionary for Mac OS X 10.5 Users: (Note: I haven’t confirmed whether this works on more recent versions of Mac OS X.) From the product page: “In addition to using Dictionary.app it is also possible to find a definition through the ‘Look up in Dictionary’ context menu shortcut (works in Safari, Mail.app and any other application that supports it) or even from a Dashboard widget for Dictionary.”
Categories: Companies

An Introduction to Using YUI 3 in Offline Applications

Thu, 05/27/2010 - 23:53

About the author: Alex Kessinger works as a front-end engineer at Yahoo! Past working as a front-end, he enjoys working on the entire stack. He also spends a lot of time reading, curating, and writing about the internet, social media, and building websites. You can find all of it at his website alexkessinger.net. You can also find him on twitter @voidfiles.

I could say that HTML5 is building steam, but that time is passed: HTML5 is here. Mobile is already huge, WebKit is growing rapidly, and the number of people who will have an HTML5-capable browser on their phone and/or laptop over the next few years will create a “new normal” in which HTML5 capabilities are the standard.

One of the awesome features in HTML5 is the Application Cache, which gives websites the ability to tell the browser which files to cache and to use the cached files when the browser doesn’t have a network connection. You can use the Application Cache to ensure that a user will be able to access at least part of your app while he is offline. In the case of devices like phones or tablets (or even old-fashioned devices like laptops), this could mean that your users are able to use your app while on an airplane. Meanwhile, you get to continue building your app with web technologies rather than learning Objective-C.

Besides the Application Cache, there are also other APIs available in HTML5 that give web developers the tools to create useful offline experiences. There are two persistent storage APIs available in most newer browsers. One is a simple key/value data store, called localStorage. The second is a SQL database. Both can be leveraged while the user is offline.

With these concepts in mind, I’m going to explore the evergreen “To Do list” application, using it as a springboard to look at how we can leverage the Application Cache and persistent storage in an app that builds upon everything we love about YUI 3, including the YUI 3 Gallery.

Markup

Markup is always a great place to start when building anything related to the web. The basic shell of our HTML5 page:

<!DOCTYPE HTML>
<html
<head>
    <title>YUI ToDo</title>
    <link rel="stylesheet" href="base.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body class="yui-skin-sam">
    <script src="yui-min.js"></script>
    <script src="base.js"></script>
</body>
</html>

Although we’re building an offline-ready application, follow best practice but putting CSS in the head, and Javascript just before the closing body tag. Even if your page is going to be available offline, the initial page load should be responsive. (Note that we’re using the awesomely simple HTML5 doctype here.)

The app needs some placeholder markup:

<!DOCTYPE HTML>
<html>
<head>
   <title>YUI ToDo</title>
   <link rel="stylesheet" href="base.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body class="yui-skin-sam">
    <div id="doc3">
        <div class="hd">
            <h1>ToDo App</h1>
            <a class="callout" href="http://alexkessinger.net" target="_blank">by Alex Kessinger</a>
            <div class="item_entry">
                <form class="entry_form">
                    <input type="text" name="todo_item_input" class="todo_item_input">
                    <p class="toRight"><a class="addItem" href="#add">Add</a></p>
                </form>
            </div>
        </div>
        <div class="bd">
            <div class="yui-main">
                <div class="yui-b">
                    <div class="todo_items">
                        <h2>Todo Items</h2>
                        <ul>
                            <li class="no_items">Fetching ToDo Items ...</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
        <div id="debug"></div>
        <!-- Initialization process //-->
        <script src="yui-min.js"></script>
        <script src="base.js"></script>
    </div>
</body>
</html>

This will let the user know we’re planning on getting some data for them when they first load the app. It also sets up our stage, a DOM structure for our Javascript to start working with.

A Note About Progressive Enhancement

There is no reason that an application can’t be built with principles of progressive enhancement and still made available for offline use. In this exploration, I’m omitting the additional complexity that would be involved in PE in order to focus as much as possible on the techniques required for offline support. Some might criticize that approach, and I’m sympathetic to that argument.

Additional Properties for Handling mobile devices

iPhoneOS and Android browsers can handle most webpages without any special attention, but when dealing with mobile devices it’s worth investigating how the content gets squeezed to fit on the smaller screen. Quirksmode has not one but two in-depth articles on viewport that are well worth your time.

Briefly, there is a meta tag, called viewport. It looks something like this:

<meta name="viewport" value="">

The goal of the viewport tag is to help mobile browsers figure out how to display a really big webpage on a small screen. Mobile devices need help because most devices try to squeeze 700-1100px of content onto a 300-500px screen. Also, when we set our widths at 100%, the browser takes its best guess at how big the webpage should be, and then scales it from that big to fit inside the size of the device.

To help we could set the viewport to this.

<meta name="viewport" value="width=device-width">

This will tell the device to set the width of our page to the width of the device’s screen. If we make sure our page is fluid, then our page will fill the screen on most mobile devices. This also means that if the phone has a landscape mode the page will expand to fill the extra space.

There are other things we can do to the viewport as well. If you have worked with mobile browsers, you know they allow you to zoom. If you are taking to time to build a website to fill the whole screen you may not want a user to be able to zoom. If we set our viewport to be something like the following, the user won’t be able to zoom in, or out. On a device like the iPhone this may make it feel more native. But if you do this, make sure that the content of your app gives the user no reason to ever want to zoom (e.g., small text); otherwise, this will be a frustrating usability constraint.

<meta name="viewport" value="width=device-width,user-scalable=no">

The viewport is not a W3C standard, but is a common convention. It’s currently supported by WebKit browsers on the iPhone and Android operating systems. Fennec, the Mozilla mobile browser, will probably also support this convention.

CSS

More then ever, using CSS’s ability to be fluid and dynamic is important. When looking at the broad range of phones, tablets, and other small screens, developers of applications need to be aware that our apps are going to be used on a plethora of devices. Even though there is no magic wand we can wave to make everything just work, for most applications we may not need to be pixel perfect on every device. Just following best practices can take us most of the way to support the most devices.

Starting with setting the width of our app at its base in % is a great start. Using em’s to set font-sizes is also helpful because ems are calculated based on the rendered webpage. Another thing that helps is to make sure that you base column widths on percentages as well. Even column gutters can be set in em’s.

A great place to start, without having to do a lot of work is a CSS framework. YUI 2 Grids CSS is naturally one of our favorites, and it helps us think of our page in terms of ratios instead static-width blocks.

So building off YUI 2 CSS Grids here is the starting CSS for my app.

.todo_items {
    padding-top:1em;
}

.todo_items ul{
    padding:0;
    margin:0;
}
.todo_items ul li {
    margin:.125em 0 .5em 0;
    padding:.125em 0 0 0;
    border-top:1px solid #ccc;
    list-style:none;
    display:block;
    word-wrap: break-word;
    text-wrap: suppress;
}

.toRight{
     text-align:right;
}

.yui3-console {
     text-align:left;
     margin-left:10px;
}

body h1 {font-size:200%;}
body h2 {font-size:150%;}
Javascript

Next up for our offline to-do application is the JavaScript. First download yui_min.js to your document root, and add it to the markup like we have above. Then put this in your base.js file:

YUI().use('node', function (Y) {
    Y.one(".todo_items h2").setContent("I am flying");
});

Besides Node, I am also going to include the YUI 3 CSS Reset and YUI 2 CSS Grids. I’m going to include a module from the YUI 3 Gallery, Ryan Grove’s excellent Storage Lite, that will wrap all the possible local data storage methods in to one easy-to-use API.

YUI().use('cssreset','yui2-grids','gallery-storage-lite','node', function (Y) {

  // TO-DO LIST APPLICATION CODE

});

Note: I’m not going to dive into the to-do list code, nor into some of the techniques I’d use to make it easier to debug this sort of project on mobile devices. You can find all of that on github: yui3-todo. Inside base.js you’ll find the entirety of the app. You can also see the app up and running at http://html5.alexkessinger.net/yui/ytodo/. Here, I’m going to focus on the steps necessary to enhance this simple app with offline capabilities.

Cache Manifest

The first step to taking a web app offline is the Application Cache. The Application Cache can tell your browser what files you want to download and keep offline. In this example, I know I want to keep my JavaScript and my CSS offline, as well as the main HTML page for the app. With that in mind, my cache manifest will look like this:

CACHE MANIFEST

index.html
base.css
yui_min.js
base.js

Some things to note about the cache manifest.

  • It must start with the line CACHE MANIFEST.
  • You must serve it with a Content-Type header of text/cache-manifest

If you are on Apache, you can add the following snippet to .htaccess to get the right content type.

AddType text/cache-manifest .manifest

With that in place, any file with a .manifest suffix will be served with the text/cache-manifest Content-Type header.

Next we need to inform the browser of the cache manifest, to do that we add an attribute to our HTML tag:

<html manifest="todo.manifest">

Now if you go to your page in a browser that supports offline apps you will probably see a notification stating that this webpage is requesting offline access.

Offline / Online

With the manifest in place telling our browser what resources to cache, we’re ready to think about what happens in online mode versus offline mode. There are now two “boot sequences,” the first being the full online sequence that we already have (and during which resources are cached for offline use). This online sequence uses the Yahoo CDN to load the files, and the files are combo-handled so we have only a few HTTP requests.

But we are also building an offline boot procedure. We need to be able to detect the fact that the browser is offline and then initialize YUI properly to draw from cached resources.

var online = (navigator.onLine) ? true : false;

Now, we just need to choose a configuration object based on being offline, or online.

var YUI_ONLINE_CONF = {},
    YUI_OFFLINE_CONF = {
        base: "yui3/build/",
        combine:0,
        groups: {
            gallery: {
                base:'yui3-gallery/build/',
                patterns:  { 'gallery-': {} }
            },
            yui2: {
                base: '2in3/dist/2.8.0/build/',
                patterns:  {
                    'yui2-': {
                        configFn: function(me) {
                            if(/-skin|reset|fonts|grids|base/.test(me.name)) {
                                me.type = 'css';
                                me.path = me.path.replace(/\.js/, '.css');
                                me.path = me.path.replace(/\/yui2-skin/, '/assets/skins/sam/yui2-skin');
                            }
                        }
                    }
                }
            }
        }
     },
     ONLINE = (navigator.online) ? true : false;
     CURRENT_CONF = (ONLINE) ? YUI_ONLINE_CONF : YUI_OFFLINE_CONF;

YUI(CURRENT_CONF).use('cssreset','yui2-grids','gallery-storage-lite','node', function (Y) {
    ...
});

The YUI_OFFLINE_CONF configuration might need some explanation. First, I am changing the base to my document root + yui3/build/. I have posted the full distribution of YUI 3 to my server because the W3C spec states that the offline cache has a strict single origin policy. All cached resources must come from the same domain as does the manifest. As a result, I can’t rely on Yahoo! or Google or any other CDN to serve my files — all of them must be available for caching from my server.

The next part, combine:0, tells the YUI loader to not automatically combo the files, because I don’t have a combo-handler installed on my own server.

Finally, I want to mention the groups config. Groups is a new feature in YUI 3.1.1 that allows you define whole groups of files that come from the same place. You can also configure them to be combo’d from the source. I set up the YUI 3 Gallery here to load from a local copy I have of the yui3-gallery repository on GitHub.

When we are online, we can bootstrap from the Yahoo CDN, but offline we need to have local copies of the files. This is easy to do. You can either download the files needs in a big zip file to your directory:

cd docroot;
wget http://yuilibrary.com/downloads/yui3/yui_3.1.0.zip;
unzip yui_3.1.0.zip;
mv yui yui3;
wget http://download.github.com/yui-yui3-gallery-gallery-2010.05.19-19-08-0-g2a49f06.zip;
unzip yui-yui3-gallery-gallery-2010.05.19-19-08-0-g2a49f06.zip;
mv yui-yui3-gallery-2a49f06 yui3-gallery;
wget http://download.github.com/yui-2in3-yui-2in3.3-0-gdf09025.zip;
mv yui-2in3-yui-2in3.3-0-gdf09025 2in3;

Or you can clone the git repositories from github directly if git is installed on your machine:

cd docroot;
git clone git://github.com/yui/yui3.git yui3;
git clone git://github.com/yui/yui3-gallery.git yui3-gallery;
git clone git://github.com/yui/2in3.git 2in3;

For testing purposes. I will sometimes set ONLINE = false and check how my site loads. If you do that, and then visit your app in a normal browser, you can see each file that needs to be included individually. To properly fill out our cache manifest, you need to take note of each file being pulled in, using something like Firebug. Then in your cache manifest you will list each file one by one. It will look something like this.

CACHE MANIFEST
# A comment
index.html
base.css
base.js
yui-min.js
yui3/build/loader/loader-min.js
yui3/build/widget/assets/skins/sam/widget.css
yui3/build/console/assets/skins/sam/console.css
yui3/build/oop/oop-min.js
yui3/build/event-custom/event-custom-min.js
yui3/build/intl/intl-min.js
yui3/build/console/lang/console.js
yui3/build/attribute/attribute-min.js
yui3/build/event/event-base-min.js
yui3/build/pluginhost/pluginhost-min.js
yui3/build/dom/dom-min.js
yui3/build/node/node-min.js
yui3/build/event/event-delegate-min.js
yui3/build/event/event-focus-min.js
yui3/build/base/base-min.js
yui3/build/classnamemanager/classnamemanager-min.js
yui3/build/widget/widget-min.js
yui3/build/substitute/substitute-min.js
yui3/build/console/console-min.js
yui3/build/cssreset/reset-min.css
2in3/dist/2.8.0/build/yui2-grids/yui2-grids-min.css
yui3-gallery/build/gallery-storage-lite/gallery-storage-lite-min.js
yui3/build/json/json-min.js
startup.png
icon.png

At this point we can go all the way offline. If you have an iPhoneOS or Android device (or any HTML5-capable browser) you can now visit your webpage, let it finish loading, and then reload the page with the device’s internet access disabled.

iPhone-Specific Goodies

The iPhone affords the WebApp developer the ability to give your app some space on the home screen just like all other apps. You can even have a glossy icon and startup screen as you’d have with a “native” application. First, you need to follow the specs for the icon and startup screen. And then you can add the following meta tags:

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
<link rel="apple-touch-icon" href="icon.png"/>
<link rel="apple-touch-startup-image" href="startup.png" />

The first two tags tell mobile Safari that your web page is a HTML5 WebApp and that you wan the color of the status bar at the top to be white. This will also remove all the navigation chrome around browser window. The second two tags point to the files you want to use for your icon and startup screen.

What’s Next

The HTML5 spec is still a moving target. Keep an eye out for new developments. That said, even today there are fantastic new capabilities in modern browsers. As you can see from this tutorial, it’s not hard to take a web application offline, dramatically increasing it’s potential usefulness. And, when you go offline, don’t hesitate to take YUI 3 with you, along with all the power you’re accustomed to from the YUI 3 Gallery and the YUI 2 widget family.

Categories: Companies