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

Blog: Category ‘YUI 3 Gallery’

« Older Entries
|
Newer Entries »

YUI Theater — Nate Cavanaugh and Eduardo Lundgren: “A Whirlwind Tour of AlloyUI Components in the YUI 3 Gallery” (67 min.)

Liferay engineers Nate Cavanaugh and Eduardo Lundgren speak about AlloyUI at YUIConf 2010 at Yahoo! HQ in Sunnyvale, CA.

In this session from YUIConf 2010, Liferay engineers Nate Cavanaugh and Eduardo Lundgren talk about the dozens of high-quality, YUI 3-based components contributed by their AlloyUI project to the YUI 3 Gallery. You can’t appreciate the full spectrum of what YUI 3 offers without seeing what Nate and Eduardo have made available for your use.

If the video embed below doesn’t show up correctly in your RSS reader of choice, be sure to click through to watch the high-resolution version of the video on YUI Theater.

  • Download HD video (480p ~474MB)
  • Download video (m4v)

Other Recent YUI Theater Videos:

  • Ryan Dahl: Node.js Roadmap — Node.js creator Ryan Dahl delivers one of the most technical (and amusing) talks at YUIConf 2010, diving into the details of Node.js’s present state and future roadmap.
  • Nagesh Susarla: Building YQL Open Data Tables with YQL Execute — YQL engineer Nagesh Susarla explores the power of YQL execute in the creation of powerful YQL open data tables.
  • Mirek Grymuza and Josh Gordineer: YQL: An Introduction — Mirek Grymuza and Josh Gordineer are members of the team that brings you YQL, the remarkable Yahoo data service that turns the internet into a database accessible via familiar SQL-style syntax. In this talk from YUIConf 2010, they provide a baseline introduction to YQL’s history, features, and core uses.
  • Nate Koechley: A Taxonomy of Touch — YUI contributor Nate Koechley breaks down the elements of touch primitives, gestures and semantics, laying a foundation for the broader language of touch interactions that drive the emerging class of portable devices.
  • Nicholas C. Zakas: YUI Test — Yahoo! Front Page engineer, author and YUI contributor Nicholas C. Zakas talks about the new standalone YUI Test project which has been broken out from its YUI 2 and YUI 3 roots.

CC Content/Used by Kind Permission:

  • http://www.flickr.com/photos/uberlife/5161516499/
  • http://www.flickr.com/photos/uberlife/5165069249/

Subscribing to YUI Theater:

  • YUI Theater RSS feed
  • YUI Theater on iTunes
By Eric MiragliaNovember 30th, 2010

In the YUI 3 Gallery: Server-Sent Events

Push notifications on the web are increasing in popularity, as evidenced by the excitement over Web Sockets, and with good reason. The web is moving towards more accurate and up-to-date information as audiences turn to the Internet for real-time updates of stocks, news, sports, and more. While Web Sockets represents a giant leap forward in the realm of push notifications, there is a lesser-known spec that can be considered a small jump forward: Server-Sent Events.

Server-Sent Events (SSE) are also targeted at making push notifications easier by building on top of the techniques that developers are already using. As opposed to Web Sockets, SSE uses regular HTTP to communicate with the server and allows you to decide whether to use HTTP streaming, long polling, or even regular polling to retrieve new data (though this isn’t recommended).

At the heart of SSE is the EventSource object. The YUI 3 Gallery EventSource module creates a cross-browser implementation of EventSource, bringing support for Server-Sent Events to all browsers that support the XMLHttpRequest, including Internet Explorer 6, while falling back to the native implementation in browsers that have it (currently Safari 5, Chrome 7, and Opera 10.7).

The EventSource interprets a response as an event stream (signified by a content type of “text/event-stream”) and fires appropriate events. There are three predefined events:

  • open – fires when the connection with the server has been established.
  • message – fires when a new message is received from the server. The event.data property contains the new data.
  • error – fires when an error occurs in processing the event stream. Once this event fires, no further events will be processed and the server connection is permanently closed.

The event stream itself is plain text data made up of the keyword “data:” followed by some data on a single line. If you wish to have multiple lines, you must include more rows with “data:” prefixes. A empty line is considered the boundary between events. Here’s a simple example:

data: hello

data: hello
data: world

Two message events are fired with this event stream. The first has event.data set to “hello” while the second has event.data set to “hello\nworld” (note the new line).

Here’s an example of creating a new EventSource instance:

YUI({
    gallery: 'gallery-2010.11.17-21-32'
}).use('gallery-eventsource', function(Y) {
 
    var src = new Y.EventSource("stream.php");
 
    src.on("open", function(event){
        console.log("Connection opened!");
    });
 
    src.on("message", function(event){
        console.log("Data received: " + event.data);
    });
 
    src.on("error", function(event){
        console.log("Error!");
    });
 
});

The constructor accepts a single argument, which is the URL of the event stream. The interesting and useful part of EventSource is that it will automatically reconnect to the server if the connection is lost for any reason. Doing so frees developers from needing to worry about disconnecting and reconnecting, a frequent complaint when using XMLHttpRequest for push notifications.

Even though the YUI 3 Gallery EventSource module matches the specification with support for HTTP streaming, long polling, and regular polling, not all browsers support all three. Internet Explorer (up to and including version 9) does not support HTTP streaming, while it can easily handle long or regular polling. The recommended usage of this module is to build your experience with a long polling implementation for best performance and compatibility.

If you’d like to optimize for browsers that support HTTP streaming, the module sets a special X-YUIEventSource-PollOnly header when it detects a browser that can’t use HTTP streaming. You can check for this header on the server to determine the correct way to serve data. Here’s an example implementation using JSP:

<%@page contentType="text/event-stream" buffer="none"%>
<%

    //check for poll-only header
    String header = request.getHeader("X-YUIEventSource-PollOnly");

    //check every so often to see if there's new data
    while(true) {        

        //sleep for a second - simulate waiting for data
        Thread.sleep(1000);        

        //output the current time, ensure there are two trailing newlines
        out.print("data: " + (new java.util.Date()).toString() + "x\n\n");
        out.flush();

        //if it's a poll-only request, break the loop, 
        //which ends the request - the client will reconnect
        if (header != null){
            break;
        }
    }
%>

It’s fairly easy to migrate existing long polling solutions to use SSE, provided the data format is simple. Since the format of event streams is line-based, that could mean reformatting some data to sit on a single line instead of multiple lines.

While SSE will never have the same performance characteristics as Web Sockets due to using HTTP, it does represent a logical evolution of push notifications in browsers. SSE can replace older XMLHttpRequest-based solutions with less code and better error handling, all while keeping the same authentication paradigm.

The YUI 3 Gallery EventSource module implements almost all of the SSE spec (you can see in the source code which parts are not yet implemented by searching for “TODO” comments). This is because some of the features are vaguely described. The module supports the following features:

  • Simple events (fire message event).
  • Custom events (fire an event matching the name specified in “event:”)
  • Event IDs (captured in event.lastEventId and sent to the server)

The parts that have yet to be implemented are support for reconnection times and the event.origin property. Otherwise, everything else should behave the same as the native implementation.

Further Reading

  • Introduction to Server-Sent Events
  • The Long Journey of Server-Sent Events
By Nicholas C. ZakasNovember 29th, 2010

A Status Check on the YUI 2-to-3 Transition

The YUI 2 JavaScript and CSS library has been an enormously successful product in the four-plus years since we released it in 2006. YUI 2 distributions have been downloaded more than 2 million times, and thousands of developers today use YUI without ever downloading the files, pulling instead from either the Yahoo! or Google CDN.1 YUI traffic on the Yahoo! CDN has grown steadily over the years since we made it public, and today we estimate that yui.yahooapis.com is serving about 15 billion files monthly.

It’s no secret, though, that YUI engineers at Yahoo! are spending most of their energy today working on YUI 3, the successor project to YUI 2, and one that applies many of the lessons learned by YUI engineers in the years we spent building YUI 2. YUI 3 today is robust and feature-rich. At the utility level (animation, XHR, drag and drop, etc.), it exceeds the functional level of YUI 2. At the widget level, where YUI 2 has been popular with its wide portfolio, YUI 3 is still catching up. YUI 2′s DataTable, Editor, Menu, Button and Calendar are still the standard, and YUI 3 users looking for equivalent functionality today are guided to the YUI 2-in-3 project, which allows you to easily include and utilize YUI 2 from within YUI 3 implementations. This is easy and safe, but it’s also not optimal: We’d prefer not to switch between the two APIs, and we’d prefer not to incur the runtime overhead of loading two library cores.

As we prepare for next week’s YUIConf 2010, it seemed like a good time to review the status of the YUI 2-to-YUI 3 transition. We’re a little over a year into the YUI 3 era, and not quite a year out from the YUI 3 Gallery‘s launch. Between the YUI team at Yahoo! and those of you in the YUI community contributing components (nearly 100 contribitors in total), how are we doing?

The answer may surprise you.

With projects like LifeRay’s AlloyUI and dozens of independent contributors populating the Gallery, we now have more options available even at the widget level in YUI 3 than we shipped with YUI 2. The table below matches functionality between the two libraries and gives a sense of how the two libraries compare in terms of functional categories. Caveats:

  • Few rows are 1:1 comparisons. When I say that functionality is supported, I don’t mean that it is supported in exactly the same way or at the same feature level in both codelines.
  • All unsupported features in YUI 3 can be accessed via YUI 2-in-3.
  • Where I’ve indicated that something is supported via community/Gallery, I’m not suggesting anything about the feature completeness of the Gallery content — merely that the community has responded to that need and produced and shared a solution.
  • This table includes only a fraction of the content that is in Gallery. A truer picture, including all Gallery content, would show YUI 3 dwarfing YUI 2 in terms of component options. I’ve confined myself here to the baseline functionality of YUI 2, its equivalent in YUI 3, and major new developments in the YUI 3 world (including major component categories that have emerged in Gallery).
Core Components
Component YUI 2 YUI 3 Notes
Library Core Yahoo Global Object YUI module Some of the YUI 2 functionality has moved to other modules — oop and lang.
Loader YUI Loader Loader module YUI 3′s Loader is intrinsic (will be invoked automatically) and includes support for Gallery.
DOM support DOM Collection Node module YUI 3 is “node-centric” — working via the Node API is a paradigm shift between YUI 2 and 3.
Browser and Custom Events Event Utility Event module
Component Foundation
Component YUI 2 YUI 3 Notes
Attribute management AttributeProvider Attribute module
Event management EventProvider EventTarget in the Custom Event module
Component base Base module
Extension model Base module
Plugin model Plugin and Plugin Host modules
Widget foundation Element Utility Widget module YUI 2′s Element Utility lacks the lifecycle pattern for component development contained in the YUI 3 Base/Widget system.
Utilities
Component YUI 2 YUI 3 Notes
Ajax/XHR Connection Manager Utility IO module
Animation Animation Utility
  • Animation module
  • Transition module
YUI 3 adds support for CSS transitions via the Transitions module, supporting hardware-accelerated transitions where supported.
Asset Prefetching Caridy Patiño Mayea’s Preload module
Asynchronous Queueing AsyncQueue module Support for a chain of function callbacks executed via setTimeout. YUI 2′s delivery of this functionality is not split out sufficiently for general use.
Authentication Dav Glass’s oAuth module
Cache Cache module Support for storing key/value pairs in local JS memory.
Cookie Cookie Utility Cookie module
Data Management DataSource Utility
  • DataSchema (beta)
  • DataSource (beta)
  • DataType (beta)
There is not exact feature parity between the two (for example, queueing is not supported in YUI 3; YUI 3 modules remain in beta.)
Drag and Drop Drag and Drop Utility DD module
Event Extras
  • Event delegation
  • Event simulation
  • Event delegation
  • Event simulation
  • Gestures
  • Synthetic events
  • Touch events
YUI 3′s event support exceeds the YUI 2 branch, with a good abstractions for touch and gestures.
Form Validation InputEx Field/Form Framework The YUI 3 Gallery has too many form-related modules to list here — one group is from the prolific developers of AlloyUI, and there are many more from other contributors.
Geolocation Mikael Abrahamsson’s Geolocation module
Get (script/CSS loading) Get Utility Get module
History management History Utility History module YUI 3′s History module includes HTML5 support.
ImageLoader (smart deferral of image load) ImageLoader Utility ImageLoader module
Internationalization varies by component Internationalization module YUI 3′s i18n model is more robust, but there is work to do to realize all of its benefits throughout the widget system.
JSON JSON Utility JSON module YUI 3 includes the JSONP module which provides a facility for working with JSONP callbacks from within YUI 3′s sandbox patterns.
Resize Resize Utility AlloyUI Resize The AlloyUI implementation in Gallery has been adopted into the library core and will be part of the 3.3.0 release.
Storage (client-side) Storage Utility (includes Flash fallback) Storage Lite Storage Lite does not support a Flash fallback.
Stylesheet (manipulation via JS) Stylesheet Utility Stylesheet module
SWF management SWF Utility
  • SWF module
  • AlloyUI SWF (Gallery)
SVG Support
  • Vincent Hardy’s YUI SVG Extensions module
  • Matthew Taylor’s Raphael module
Undo/Redo Support Iliyan Peychev’s Undo/Redo Framework module
YQL wrapper YQL Query module
UI Widgets
Component YUI 2 YUI 3 Notes
Accordion
  • Marco van Hylckama Vlieg’s AccordionView
  • Caridy Patiño Mayea’s Accordion Manager
  • Iliyan Peychev’s Accordion
  • John Lindal’s Accordion (Horizontal/Vertical)
  • Caridy Patiño Mayea’s Node Accordion
As a YUI 2-based widget, Marco’s component is not in the YUI 3 Gallery formally.
AutoComplete AutoComplete Control
  • AlloyUI AutoComplete
  • Autocomplete v2
YUI 3 AutoComplete will ship with YUI 3.3.0. Don’t overlook the AlloyUI component here, though — it is feature rich and ready to use today.
Button Button Control Anthony Pipkin’s Button module
Calendar Calendar Control AlloyUI Calendar Calendar widget/date selection is not expected as part of the YUI 3 distribution until 3.4.0 or later; the AlloyUI implementation, however, is an excellent choice for the common use cases.
Carousel Carousel Control Gopal Venkatesan’s Carousel module Gopal has owned the YUI 2.x Carousel codebase for a long time, and his YUI 3 Gallery module will be in production Yahoo! products this year.
Charts Charts Control
  • AlloyUI Chart module (Gallery; uses YUI 3 Charts under the hood)
  • Tripp Bridges’s Charts module
Tripp is one of the authors and the maintainer of the YUI 2 Charts Control, which is Flash-based. The YUI 3 Charts work, which does not rely on Flash, is being pushed to Gallery on a regular basis and Tripp’s work to-date will ship in beta as part of YUI 3.3.0.
Color Picker Color Picker Control AlloyUI Color Picker
DataTable DataTable Control Anthony Pipkin’s Simple Datatable module Anthony’s project, which includes a few plugin modules, is not meant to have feature parity with the ambitious YUI 2 DataTable Control. The work being done by the YUI team on YUI 3 DataTable will appear in beta form in 3.3.0.
Image Cropping ImageCropper Control
Layout (full screen application management) Layout Manager
Menuing Menu Control
  • Julien Lecomte’s Simple Menu module
  • Node MenuNav (beta)
Simple Menu is not as feature rich as the comprehensive menuing support provided in YUI 2. At present, the YUI team plans work on a YUI 3 menu control for the 3.4.0 timeframe. Node MenuNav is part of the YUI 3 distribution, but it remains in beta and may be deprecated in favor of new work on a formal UI control.
Overlays Container Family
  • Overlay module
  • Anthony Pipkin’s Dialog module (Gallery)
  • AlloyUI Dialog module (Gallery)
  • AlloyUI Overlay module (Gallery)
  • Eric Ferraiuolo’s Overlay Extras module (Gallery)
  • Patrick Cavit’s Overlay Transitions module (Gallery)
Pagination Paginator Control John Lindal’s Paginator Port module
Progress Bar ProgressBar Control
  • Anthony Pipkin’s Progress Bar module
  • Satyam’s YUI 3 Progress Bar implementation
Satyam wrote the YUI 2 ProgressBar Control; his YUI 3 implementation is not in the Gallery, but it is available for use.
Ratings
  • AlloyUI Rating module
  • Peter Peterson’s Ratings module
Rich Text Editing Rich Text Editor Simple Editor Port YUI 3.3.0 will contain the base Editor content that Yahoo! is using in the new Yahoo! Mail beta — which is the most advanced Editor we’ve produced as part of YUI. However, the Editor toolbar (which is an important part of the component for most implementers) will rely on Button and Menuing functionality that won’t appear until at least 3.4.0.
ScrollView ScrollView module This is an important component for mobile development.
Slideshows
  • AlloyUI Image Viewer module
  • Andrew Bialecki’s Lightbox module
  • Jeff Craig’s Slideshow module
  • Josh Lizarraga’s YUI Slideshow module
This category is a good example of what the YUI Gallery can become. Whereas we never had a strong YUI 3 slideshow component, we already have four excellent modules to choose from in the YUI 3 world.
Sliders Slider Control
  • Slider module
  • Adam Moore’s simpleslider module (Gallery)
YUI 3.3.0 will contain an interesting new addition to the slider interaction pattern, courtesy of Yahoo! designer and engineer Jeff Conniff. Stay tuned for more on this as 3.3.0 preview releases appear.
Tabs TabView Control TabView module
Trees TreeView Control
  • AlloyUI Tree
  • Matt Parker’s TreeviewLite module
  • Adam Moore’s YUI 2 treeview port module
Yahoo! engineer Gonzalo Cordero is currently working on a YUI 3 TreeView implementation. While it will not be ready for 3.3.0, it is expected to be available in the Gallery after the 3.3.0 release and be a candidate for the distribution as early as 3.4.0.
Uploader (multi-file uploading with progress tracking) Uploader Control Uploader module Both YUI 2 and YUI 3 implementations require Flash.
Video (HTML5)
  • Josh Brickner’s HTML5 Player module
  • Greg Hinch’s Video module
CSS Components
Component YUI 2 YUI 3 Notes
Reset CSS Reset CSS Reset
Base CSS Base CSS Base
Fonts CSS Fonts CSS Fonts
Grids CSS Grids CSS Grids The new, more flexible YUI 3 CSS Grids package was released in 3.2.0.

Notes:

  1. The YUI 2 Dependency Configurator can help you design your script and css includes for either Yahoo! or Google CDNs.
By Eric MiragliaNovember 5th, 2010

In the YUI 3 Gallery: Extensions for SVG, Created for SVG Wow!

Introduction

SVG (Scalable Vector Graphics) provides a declarative syntax for
interactive, animated 2D graphics: shapes, images and text.
SVG support is
part of the
HTML 5

specification and SVG is
implemented by all major browsers, including Microsoft’s Internet
Explorer in version 9.

The svg-wow.org web site showcases
what can be done with SVG today. The demos on this web site were created for
the SVG Open conference, where the SVG Wow! sessions have been
a tradition for several years. The SVG Wow! sessions were started by
Dean Jackson, then in collaboration with myself and then continued by
Erik Dahlstrom.
Erik and I have collorated on the session for the
2009
and 2010 editions of the conference.

For the past two years, the demos have increasingly used AJAX frameworks,
applying their features to SVG instead of (or in addition to) HTML. YUI is
the most widely used framework on the web site, which uses both YUI 2 and
YUI 3.

I’ll start with a quick SVG overview and then discuss the type of
demos that YUI supported and the extensions I’ve added to the YUI 3 Gallery to make it
work with SVG. (These extensions are now free to use under the terms of YUI’s BSD license.)

SVG overview

Like HTML, SVG is a W3C specification. It provides a syntax for describing
basic shapes (rectangles, circles, lines, polygons, ellipses, polylines),
arbitrary shapes (described in terms of path segments which can be lines,
quadratic or cubic Bezier curves), text and images.

The following image is a screen capture of the
alternate stylesheet example on svg-wow.org and shows
some SVG features at play: rich rendering (shadow effects,
gradients, patterns) and simple and complex shapes.

Because SVG images are defined in terms of geometry and rendering
attributes, it is possible to render them at any resolution. As
a result, SVG images can be scaled to any size while retaining a
high rendering quality, for example when printing (no more jagged
edges).

The following zoomed-in view shows the same SVG image
shown earlier but rendered at a
higher resolution while preserving the high quality.

Just like HTML, SVG supports interactivity: it is possible to
add event listeners on graphic objects for mouse or keyboard interactions.
Of course, SVG supports the Document
Object Model, which makes it easy to manipulate the
different properties of graphical objects, such as their geometry or
rendering style.

There is a lot to the SVG specification:
advanced rendering styles (stroking, filling,
patterns, gradients), filter effects (blurs, shadows,
color matrices), CSS styling, advanced text features
(such as text on a path) and declarative
animation.
You can check out the references at the
end of this post to learn more about the SVG format features.

SVG and HTML

With HTML5, SVG can be inlined in HTML documents without further ado.
Browsers are starting to support that feature (e.g., Firefox 4).
For the time being, all major browsers support SVG inlined in XHTML, which
provides the same functionality. SVG in XHTML just requires that namespaces are
properly declared.

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        ....
    </head>
    <body>
        <h1>Inline SVG</h1>

        <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         width="100%" height="100%" id="backgroundSVG">
            <!-- svg content here -->
        </svg>
    </body>
</html>
        

All the code samples on this page use this way of inlining SVG in
XHTML.

SVG and YUI

SVG supports declarative animation. For example, you can animate
the radius of a <circle> element like this:

<circle cx="50" cy="100" r="40">
    <animate attributeName="r" values="40,60,20,40" dur="1.5s" />
</circle>
       

The <animate> tag is borrowed from the
SMIL specification and, along with the other
animation elements, it provides a very powerful animation engine
to SVG.

Unfortunately, until recently, browser support for SVG animation
was sparse. It has improved over the past two years, but Microsoft
has made it clear
it will not support declarative SVG animation in IE 9.

As a result, most of the demos on the svg-wow.org web site use
scripted animation instead of declarative animations. On one hand,
this is unfortunate because declarative animations are more
efficient than scripted animations. On the upside, scripted animations
can be very flexible, and they work across implementations very well.

The need for a good scripted animation solution is what drove the
usage of YUI on the svg-wow demos. However, the demos also use
other YUI features, in particular the
Loader and
Node modules.

Animating SVG with YUI

The demos on svg-wow use YUI to create
elastic drum beats,
morphing shapes or
rotating text and shapes for
example. Using YUI with SVG
required a few YUI extensions; I’ll describe these in just a moment.

rotating text and shapes morphing shapes
elastic drum beats

The following illustrates how YUI comes
in handy to simply animate and manipulate SVG graphics.

Animating the SVG transform attribute

All SVG graphical elements have a
transform attribute.
That attribute specifies a 2D affine transformation on
elements, which can be used to scale, skew, rotate or translate.

The svg-wow.org YUI extensions for SVG allow animating the
transform attribute like this:

var anim = new Y.Animate({
    node: '#circleA',
    from: {
        transform: {tx: 0, ty: 0, sx: 2, sy: 2}
    },
    to: {
        transform: {tx: 20, ty: 20, sx: 1, sy: 1}
    },
    transformTemplate: "translate(#tx, #ty) scale(#sx, #sy)",
    duration: 1
});
        

See the transform animations tests.

You’ll note that the transform values are defined in terms of
“components” (such as tx or ty) which
are combined to form a value using the transformTemplate
found on the animation configuration object.

The template is a flexible mechanism for building
transform values while separate components make it easy to
compute the animated values. This is an example where the YUI
animation model allowed more flexibility (and more expressive power)
than SVG’s SMIL animation element
(animateTransform).
In order to create the animation described above, the equivalent
SMIL declaration would have been:

<circle ...>
    <animateTransform attributeName="transform" type="translate"
                      from="0,0" to="20,20" dur="1s" begin="scaleAnim.begin"/>
    <animateTransform id="scaleAnim" attributeName="transform" type="scale"
                      from="2,2" to="1,1"  dur="1s" begin="indefinite"/>
</circle>
        

Note how the above snippet requires multiple animateTransform elements
which have to be synchronized: the begin attribute of the
first animation is set to scaleAnim.begin to synchronize the start of the
two animations. A nice feature of the YUI animation engine is that the timing of an
animation (i.e., start, end and duration) can be shared to apply to multiple element
properties.

The YUI extension for animating SVG transforms is used
extensively, such as in the
camera
and
animated lyrics examples.
The former uses an extension of YUI 3 while the latter uses an extension of YUI 2.

Animating geometry
Basic Geometry

Animating SVG geometry with YUI is quite simple. The following
example animates a <rect> element’s width,
height and corner radii:

var anim = new Y.Animate({
    node: '#rectA',
    from: {
        width: 200,
        height: 100,
        rx: 5,
        ry: 5
    },
    to: {
        width: 300,
        height: 100,
        rx: 10,
        ry: 10;
    },
    duration: 2,
    easing: Y.Easing.elasticOut
});
        

See the shape animations

tests.

As discussed later on, some changes under the
YUI hood made this work. But from a developer’s perspective,
this animation works the exact same way as the animation of any other HTML
attribute or CSS property.

The <path>‘s d attribute

One geometry attribute is a little special: the
d attribute on
the <path> element. The
<path> element is used for arbitrarily
complex geometry. A <path> can describe any shape. Its
d attribute describes its geometry in terms of
path segments which can be lines, arcs, quadratic or
cubic Bezier curves
(there are a few more commands, but they all map to Bezier curves).

Animating the d attribute also required a bit of
extension to YUI’s animation engine, but with that extension, the
d attribute can be animated like any other, as shown
below.

var anim = new Y.Animate({
    node: "#pathA",
    from: {d: "M 0 0 C 50 0 100 50 100 100 C 50 100 0 50 0 0 Z"},
    to: {d: "M 0 0 C 100 0 100 0 100 100 C 0 100 0 100 0 0 Z"},
    duration 1s,
    easing: Y.Easing.bounceBack
});
        

See the paths animations
tests, which shows, among other things, a check mark morphing into
a cross over time, as represented in the following images.

The Gandhi quotes demo uses this technique of
animating the d attribute to morph shapes into
Gandhi’s figure.

Animating other SVG attributes

Of course, the YUI animations are not limited to geometry attributes.
Any SVG attribute can be animated. For example, the following
animation animates the blur radius on a horizontal blur filter.

// SVG snippet
<filter ..
    <feGaussianBlur id="blurFilter" stdDeviation="10 10" ... />
</filter>

// JavaScript animation
var anim = new Y.Animate({
    node: '#blurFilter',
    from: {stdDeviation: [0, 20]},
    to: {stdDeviation: [0, 0]}
});
        

See the filter animations
tests. The following image shows how animating a
Gaussian blur can be used to transition between button states.

This type of effect is used in the
fast blur effect demo,
even though that demo does not use YUI animation but declarative SMIL
animation elements (at the expense of only running in browsers supporting
that feature, as explained earlier).

Animating CSS properties

Like HTML, SVG elements have attributes and also CSS properties.
SVG has some
specific CSS properties.
These properties can be animated, sometimes to create surprising
effects. For example, the
stroke-dashoffset property can
be used to simulate drawing a shape.

// SVG snippet
<rect id="rectA" width="100" height="50" stroke-dasharray="300 300" stroke-dashoffset="300" />

// JavaScript
var anim = new Y.Animate({
    node: "#rectA",
    to: {'stroke-dashoffset': 0},
    duration: 0.25
});
        

See the stroke animations
tests.

The graffitis demo
uses this technique (even though without YUI animation) and so does the
camera demo (this time with YUI animation).

YUI and SVG: Under the hood

The svg-wow.org web site uses both YUI 2 and YUI 3 and has SVG-specific
extensions for both. The following section of this article focuses on the YUI 3 extensions.

Extensions were needed to:

  • make YUI work with SVG’s DOM specificities
  • account for implementation differences
  • add support for new attribute types such as SVG transforms
  • add additional animation timing and synchronization features

Accounting for SVG DOM Specificities

As described earlier, SVG attributes can be animated with declarative
elements such as <animate>. To support SVG’s
animation model, SVG
attribute values hold both an animated and a
base value. For example, the r attribute on a
<circle>

element is an
SVGAnimatedLength
defined as follows:

interface SVGAnimatedLength {
  readonly attribute SVGLength baseVal;
  readonly attribute SVGLength animVal;
};

As a result, even in implementations that do not support declarative
animation, we need to reach down to the baseVal to
read an attribute’s value:

var circle = document.getElementById('#myCircle');
var rValue = circle.getAttribute('r').baseVal.value;

Extensions were needed to allow the animation engine to account for
the SVG attributes’ unusual value model. Thankfully, YUI 3 has a concept of
animation behaviors.
Behaviors are essentially attribute-specific hooks, and it was fairly
easy to add support to handle SVG attribute values. For example,
SVGAnimatedLength attributes are handled like so:

var lengthBehavior = {
    set: function (anim, att, from, to, elapsed, duration, fun) {
        // SVG specific handling
    },

    get: function (anim, attr) {
        // SVG specific handling
    }
};

// Handle <circle>'s r attribute
Y.Animate.behaviors.r = lengthBehavior;

There are more extensions for other SVG attributes values such as the
transform attribute, color attribute values
(like fill, stroke or
stop-color) and attributes such as stdDeviation
mentioned earlier.

A few similar tweaks were required, for example in the
Y.Node.prototype.toString method, again to account
for SVG’s baseVal (this time on the className
node property). Another example is the default node setter in the
Node module.

Accounting for browser differences

While the previous extensions are required because of specification
differences between HTML and SVG, the following are required because
of implementation variations between browsers.

SVG has a special
category of attributes called

presentation attributes
. In implementations also supporting
CSS styling (which all browsers support), these presentation attributes
are really just another way to specify a CSS property with a
low specificity.
From the SVG specification:

The presentation attributes thus will participate in the CSS2 cascade
as if they were replaced by corresponding CSS style rules placed at
the start of the author style sheet with a specificity of zero.
In general, this means that the presentation attributes have lower
priority than other CSS style rules specified in author style sheets
or ‘style’ attributes.

Unfortunately, some browsers do not implement the specification
correctly and window.getComputedStyle does not always
account for all possible sources for setting the SVG CSS properties:
CSS selectors, style attribute and presentation attributes.

YUI came to the rescue thanks to the Node module which
could be extended to hide these browser differences. The
Y.DOM.CUSTOM_STYLES and the
Y.Node.prototype.getComputedStyle could be extended to offer a
uniform way to read SVG style properties.

Extending Y.DOM

YUI wraps all DOM access through the Node interface.
As a result, some SVG specific DOM methods, such as
getBBox (used to compute the bounds of an SVG
element), are not accessible on the wrapped object.

To make things easier to program for SVG, extensions to the default
Y.DOM module (which Node uses) were added to either
expose SVG DOM features or add convenience methods, commonly needed
when manipulating content:

  • firstElement/lastElement/prevElement/nextElement/removeAllChildren (not SVG specific)
  • getMatrix/setMatrix. Provides an easy way to manipulate transforms on
    SVG elements, something notoriously difficult with the standard SVG DOM
  • getBBox/getViewportBBox provide simple ways to access bounding box
    in the element’s coordinate system or in viewport space.
  • loadContent. A utility to insert a DOM fragment described using a
    JavaScript object literal. For example:

    myNode.loadContent({
        tag: 'g',
        fill: 'red',
        stroke: 'none',
        children: [{
            tag: "rect",
            x: 10,
            y: 10,
            width: 200,
            height: 300
        }, {
            tag: 'circle',
            r: 10,
            cx: 105,
            cy: 155
        }, {
            tag: 'image',
            'xlink:href': 'images/photo.png',
            width: 200,
            height: '300px'
        }, prevSibling);
            

    is a shorthand for making various DOM calls (such as
    createElementNS, setAttributeNS and
    appendChild) to create a g element and
    its children and inserting it before prevSibling
    under myNode. The utility deals with namespaces
    for attributes and elements.

Additions to the Animation engine for timing and synchronization

Many, if not most effects involving animation require multiple
choreographed animation instances. Typically, several animations are required
to create a desired effect, and the start or end of animations
depend on each other, sometimes with a time offset: animations need to
be synchronized.

For example,
if you have a set of shapes which need to fade in one after the
other, you will need to create a fade animation for each element
and then chain their start time with a slight offset.

var chained = Y.all('#chained circle'),
    firstAnim, previousAnim;

chained.each(function (circle) {
    var anim = new Y.Animate({
        node: circle,
        from: {'fill': 'white'},
        to: {'fill': 'gray'},
        duration: 0.25
    });
    if (previousAnim !== undefined) {
        // Synchrnoize the start of anim to be 0.15 seconds after the begining
        // of the previous circle's animation (previousAnim).
        previousAnim.onBegin(anim, 0.15);
    } else {
        firstAnim = anim;
    }
    previousAnim = anim;
});

// Start the first animation 1s after a click on any of the circles.
// Note that this is an extension to the default YUI run method which does not
// take a time offset.
chained.on('click', function () {
    firstAnim.run(1);
});

See the time offsets
tests.

The method onBegin makes it easy to synchronize the start
of two animations, with an optional time offset. Actually,
onBegin can also invoke a function with a time offset.
Likewise, the onEnd extension makes it easy to synchronize with
the end of an animation.

By default, YUI animations have events which provide a way to
synchronize. The onBegin and
onEnd methods express the synchronization more concisely (a similar
example of conciseness is shown below).

In addition, it is sometime necessary to synchronize an animation
with an event, again with a time offset. The beginOn
and endOn extensions allow us to express that. For
example:

anim.beginOn(Y.one('#button'), 'click', 0.5);

will start the animation 0.5s after the element with id ‘button’ was
clicked. This is a short-hand for:

Y.one('#button').on('click', function () {
    setTimeout(500 /* ms */, function () {anim.run();});
});

A final extension made to the animation class was the ability to
make an animation object apply its first frame’s state before it
was actually started. This is often needed when creating animation
effects involving multiple animations which start at different time
offsets.

var anim = new Y.Animate({
    node: Y.one('#button'),
    from: {r: 30, 'fill-opacity': 0, color: 'crimson'},
    to: {r: 80, 'fill-opacity': 1, color: 'gold'},
    duration: 0.25
});

// the following will set the desired state on the target object prior to
// actually starting the animation.
anim.applyStartFrame();
anim.run(2);

The picture shuffle demo uses animation offsets for the
effect that spreads the stack of pictures or puts the pictures back in a stack.

Conclusion

Working with SVG and YUI, and in particular YUI 3, has been a very enjoyable
experience: a lot of the YUI functionality applies to SVG right out
of the box and YUI’s extensible architecture made it possible to
work around occasional issues and to add desired functionality.

Of course, increased standard support for SVG in YUI would be helpful,
in particular making YUI work with stand alone SVG documents and
making the Node class wrap SVG elements without
workarounds.

There are also a few enhancements that would be helpful. For example,
it would help if animations could target multiple elements. Likewise,
supporting multiple values
(as in the
<animate>
SVG element for example) would be helpful to create more sophisticated
effects.

The demos on svg-wow.org were written for YUI 3.1 and ported to 3.2 for
the purpose of this blog. In 3.2, transitions were introduced
which make use of native CSS transitions
if available in the browser. It
might be possible for the YUI animation engine to similarly leverage SMIL
animation where available (Opera, Firefox and WebKit at the time of this
writing) which should also yield performance improvements.

The SVG extensions on the svg-wow.org web site are available as a YUI 3 Gallery module for those who want to enjoy the fun of working with YUI
and SVG.

References

  • SVG Wow!
  • SVG Specification
  • SVG Tutorial
  • Adobe’s SVG Zone(a little dated, but still has good examples)
  • carto.net examples
  • KevLinDev
By Vincent HardyOctober 18th, 2010

In the YUI 3 Gallery: Matt Taylor’s RaphaelJS Module



Matt Taylor (@rhyolight, blog) works for Yahoo! on an internal browser-side JavaScript framework. He enjoys working with graphics, and he’s worked with drawings and animations before using Java2d libraries. Before moving to Silicon Valley to work for Yahoo!, Matt worked in the St. Louis area as a software contractor. He’s also worked extensively with Groovy and Grails technologies for SpringSource. He was the original lead programmer for the YUI2-based GrailsUI plugin for the Grails web framework.

RaphaelJS is a powerful JavaScript library that manages SVG drawings and animations. It allows you to easily create SVG canvases and draw basic shapes and paths very easily, even grouping them into sets and applying transformations to one or many vectors. You can draw shapes, manipulate images, and animate everything. RaphaelJS provides a nice API to create and modify SVG elements with ease.

While the library is impressive, but I’ve found that I can add some important features to elements of the RaphaelJS library with YUI3. I’ve started off these efforts with the new RaphaelJS Gallery Module.

Lazy Loading RaphaelJS and Plugins

The first feature is the lazy-loading of not only the RaphaelJS library, but any RaphaelJS plugins you might need. The RaphaelJS Gallery Module will only load these files when you declare you’ll be using them within a YUI sandbox. For example:

 
YUI({gallery: 'gallery-2010.09.22-20-15'}).use('gallery-raphael', function(Y) {
 
	Y.Raphael().use(function(Raphael) {
		
		// use Raphael here just like you would outside YUI
		var paper = Raphael('myPaper', 500, 500);
 
	});
 
});

If you are using RaphaelJS plugins, specify their paths in an array and send that as the first parameter in the Y.Raphael().use() function:

 
YUI({gallery: 'gallery-2010.09.22-20-15'}).use('gallery-raphael', function(Y) {
 
	var myPlugins = ['plugins/raphael.awesomePlugin.js', 'plugins/raphael.wickedPlugin.js'];
 
	Y.Raphael().use(myPlugins, function(Raphael) {
 
		// use Raphael here just like you would outside YUI
		var paper = Raphael('myPaper', 500, 500);
		// the 'paper' will have any new functions added by your plugins now
	});
 
});

The RaphaelJS library is loaded first, then any specified plugins are loaded before your callback function is executed with the Raphael object as the only parameter.

Custom Events

Once you’ve created a drawing space with the Raphael object, then you can immediately get down to the drawing. When you call methods like rect, circle, and path on the drawing space, you’ll receive back objects representing SVG vectors. Normally, you’ll have access to their corresponding DOM elements through the node property. For example:

 
var paper = Raphael('myPaper', 500, 500);
var square = paper.rect(0, 0, 100, 100);

This creates a rectangular vector object at coordinates [0,0] with a width and height of 100 pixels. You have access to the underlying DOM element (which is an SVG rect element) like so:

 
var rectNode = square.node;
rectNode.onclick = function() {
	alert('Congratulations, you clicked a square!');
};

If you are an avid YUI user, you’d probably like something more than this. How about a built in Y.Node as well? Just like the node property refers to the HTMLElement behind the SVG object, the $node property refers to the Y.Node wrapper for that element. So you can do things like this:

 
square.$node.on('mouseover', function() {
	alert('Congratulations, you can move a mouse!');
});

Let’s try something more complex now. An interaction with one vector should be able to cause other drawn vectors to update their styles, right? How about we create some bars that all render their colors dependent on where a the mouse is located on a circle on the page:

 
var paper = Raphael('rcanvas', 600, 800);
 
var circ = paper.circle(350, 200, 100).attr({fill: 'pink', stroke: 'black'});
 
// pushing a bunch of rectangles into an array
var i=0; rectangles = [];
for (; i<10; i++) {
	rectangles.push(paper.rect(0, 40*i, 200, 20).attr({fill: 'red', stroke: 'yellow'}));
}
 
// looping through the rectangles, adding specific circle mousemove handlers for each
Y.Array.each(rectangles, function(rect, index) {
	var i = index + 1;
	circ.$node.on('mousemove', function(evt) {
		// the fill color is dynamic, dependent on the location of this rectangle
		// in the array as well as the location of the mouse
		var lf = circ.attrs.cx - circ.attrs.r,
			rt = 2 * circ.attrs.r + lf,
			x = evt.clientX - lf,
			top = circ.attrs.cy - circ.attrs.r,
			btm = 2 * circ.attrs.r + top,
			y = evt.clientY - top;
			red = (((128 * x) / (2 * circ.attrs.r))-1) * i/6,
			green = 256 - ((((128 * x) / (2 * circ.attrs.r))-1) * i/6),
			blue = (((128 * y) / (2 * circ.attrs.r))-1) * i/6;
		rect.attr('fill', 'rgb(' + red + ', ' + green + ', ' + blue + ')');
	});
});

This example is running here, but as you can see in the snapshots below, the color of each bar is dependent on the mouse location over the circle as well as the order of the bar.





Depending on where your mouse cursor is located over the circle, the bar colors change individually.

So you can see that $node is a useful shortcut, but nothing spectacular. It would really be fantastic if each SVG object you create with RaphaelJS could fire custom events. That would allow your individual drawing elements to fire custom events, and anything on the page could listen and respond. This can be useful in many ways. For starters, it provides rich interactions between your drawings. User interactions with one vector can now notify any other vectors of the interaction on demand. This means you can programatically fire events from your drawings when certain conditions are met. Not only does this allow your drawings to notify other vectors, but anything on the page can listen in.

 
var paper = Raphael('rcanvas', 600, 800);
 
var circ = paper.circle(350, 200, 100).attr({fill: 'pink', stroke: 'black'});
 
// making arrays of rectangles and circles
var i=0, rectangles = [], circles = [];
for (; i<10; i++) {
	rectangles.push(paper.rect(0, 40*i, 40*i, 20).attr({fill: 'red', stroke: 'yellow'}));
	circles.push(paper.circle(0,0,20).hide());
}
Y.Array.each(rectangles, function(rect, index) {
	var i = index + 1;
	circ.$node.on('mousemove', function(evt) {
		var lf = circ.attrs.cx - circ.attrs.r,
			rt = 2 * circ.attrs.r + lf,
			x = evt.clientX - lf,
			top = circ.attrs.cy - circ.attrs.r,
			btm = 2 * circ.attrs.r + top,
			y = evt.clientY - top;
			newWidth = (((256 * x) / (2 * circ.attrs.r))-1) * i/6,
			red = (((128 * x) / (2 * circ.attrs.r))-1) * i/6,
			green = 256 - ((((128 * x) / (2 * circ.attrs.r))-1) * i/6),
			blue = (((128 * y) / (2 * circ.attrs.r))-1) * i/6;
		// this time, not only changing the color, but also the rectangle width
		rect.attr({
			width: newWidth,
			fill: 'rgb(' + red + ', ' + green + ', ' + blue + ')'
		});
		// firing custom event to notify that this rectangle width has changed
		rect.fire('width-changed', {width:newWidth, source: rect, order: index});
	});
	
	// each rectangle gets a listener that fires on width-changed
	rect.on('width-changed', function(evt) {
		var attrs = evt.source.attrs;
		// get the corresponding circle and move it to the right end of the rectangle
		circles[evt.order].attr({
			cx: attrs.x + attrs.width,
			cy: attrs.y,
			fill: 'cornflowerblue'
		}).show();
		
	});
	
});

Take a look at this running example here. You can also see from the snapshot below that circles are being drawn on the right ends of the rectangles. This is occuring in response to each individual rectangle’s custom event firing, being caught by a handler that moves the circle to a position relative to the current attributes of the rectangle.

This opens up some interesting possiblities for RaphaelJS within YUI3. For example, what if we could create a group of vector shapes with the group itself being the entity that fires events to the outside world? Internally, each vector drawing could communicate with its container via custom events, and the container would make decisions about what data it fires to the outside world. This opens up the idea of fully encapsulated, interactive SVG controls.

Summary

With the ascendance of HTML5 and its satellite technologies, there are so many more options other than Flash for rich interactions. Ideally, any vectored elements on the page should be fully accessible and standardized. This opens up wonderful possiblities for us to create accessible, standard web controls without resorting to Flash. SVG is an appealing option because every vector drawn on the page is backed up by a DOM node that we can modify with YUI just like any other DOM node. That’s what allows the RaphaelJS Gallery Module to augment all SVG objects being created by RaphaelJS, and that is a key to rich interaction with these elments from elsewhere on the page.

By Matthew TaylorSeptember 27th, 2010

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

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

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

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

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

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

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

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

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

Capturing early user interactions

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

Let’s see an event binder example:

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

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

The configuration

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

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

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

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

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

How does this feature work?

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

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

Facilitating the on-demand nature of some user interactions

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

Here’s another event binder example:

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

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

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

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

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

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

A more advanced configuration

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

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

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

Conclusion:

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

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

By Caridy PatinoJune 23rd, 2010

Using the YUI 3 Calendar Date Selector from Alloy

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

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

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

...

	</select>

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

...

	</select>

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

...

	</select>
</div>

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

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

</script>

Here’s a live version of this simple example.

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

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

By Eric MiragliaJune 18th, 2010
« Older Entries
|
Newer Entries »

Pages

  • About
  • Contribute
  • YUI Jobs

Recent Posts

  • YUI Weekly for June 14th, 2013
  • Pure 0.2.0 Released
  • YUI Weekly for June 7th, 2013
  • YUI 3.10.3 Released to Fix Reintroduced SWF Vulnerability
  • YUI 3.10.2 Released

Archives

Categories

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

Meta

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