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

Blog: Archive for August, 2010

« Older Entries

YUI Theater — Douglas Crockford: “Crockford on JavaScript — Scene 6: Loopage” (52 min.)

Douglas Crockford speaking at Yahoo! on August 27, 2010, as part of his Crockford on JavaScript lecture series.

Douglas Crockford’s latest installment in the “Crockford on JavaScript” series, a talk in which he covers the role of event loops and the importance of server-side JavaScript, is now available on video. Flash video is embedded below, or you can download the HD video (480p ~370MB). Video from the first five lectures is available on the Crockford on JavaScript page.

  • Download HD video (480p ~370MB)
  • Download video (m4v)
  • Download slides

Other Recent YUI Theater Videos:

  • Nicholas Zakas and Victor Tsaran: Accessibility on the Yahoo Homepage — Nicholas Zakas, a principal developer of the Yahoo! homepage, and Victor Tsaran’s, Yahoo!’s senior accessibility manager, discuss the strategies and methods that made one of the most visited websites in the world fully accessible. The talk took place at the June 2010 BayJax meetup at Yahoo.
  • Dennis Lembree: Making JavaScript Accessible — Dennis Lembree, an accessibility expert and the creator of AccessibleTwitter discusses the challenges of making JS-enabled sites accessible. The talk took place at the June 2010 BayJax meetup at Yahoo.
  • Ryan Dahl: Introduction to NodeJS — Ryan Dahl, the creator of NodeJS, introduces the project and talks about performance improvements and new architecture. The talk took place at the May 2010 BayJax meetup at Yahoo.
  • Elijah Insua: jsdom: a CommonJS Implementation of the DOM — Elijah Insua introduces a server-side implementation of the JavaScript DOM at the May 2010 BayJax meetup at Yahoo.
  • Nicholas Zakas, Stoyan Stefanov, Ross Harmes, Julien Lecomte, Matt Sweeney: High Performance JavaScript — Five contributors to O’Reilly’s High Performance JavaScript discuss advanced JavaScript and DOM scripting optimizations at the April 2010 BayJax meetup at Yahoo.

Subscribing to YUI Theater:

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

Introducing Yeti: The YUI Easy Testing Interface

Welcome to Yeti

Testing JavaScript is an important but often overlooked part of web development. One reason is because developing for the web means targeting more than one browser. YUI currently classifies 11 different environments that enjoy our highest support level. In addition, we also test YUI on emerging X-grade environments like mobile devices. When you have so many different environments to support, it’s tempting to just pick a couple important ones to develop with locally and hope for the best.

At YUI, we use Selenium and Hudson for running YUI Test-based unit tests on various browser and operating system configurations as part of our continuous integration strategy. This is great for catching problems that result from integrating your work with the rest of a complex software stack. It comes with a price: CI tools like these are complicated to setup and maintain. In any case, they don’t help you while you’re developing code and testing before you commit.

Today, I’m excited to release Yeti 0.1.0, an experimental command-line tool designed to make cross-browser testing easier before you commit a line of code.

Yeti automatically launches JavaScript unit tests in a browser and reports the results without leaving your terminal. It’s very simple to use: Just run yeti test.html to get the results of the YUI Test-based test in test.html. You can pass multiple HTML documents to test multiple components at once.

$ yeti dom/tests/dom.html attribute/tests/attribute.html json/tests/json.html 
✔  DOM Tests from Safari (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16)
  20 passed
  0 failed

✔  Y.JSON (JavaScript implementation) from Safari (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16)
  68 passed
  0 failed

✔  Attribute Unit Tests from Safari (Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16)
  106 passed
  0 failed

194 tests passed! (3217ms)

The real power of Yeti is running tests in multiple browsers simultaneously. Although Yeti can open your tests one-by-one on your computer, Yeti allows you to run tests on any browser on any device—all at the same time.

If you run Yeti without arguments, it will start a web server that you can access at http://localhost:8000. You can then point browsers or devices on your network to that URL and every test you run from that point will be executed on all browsers visiting the test page.

Multiple browsers with Yeti

When combined with the excellent localtunnel, firewalls between you and other computers are less painful. If you’re not working with sensitive information, it’s a simple way to make your Yeti available to the internet:

$ localtunnel 8000
   Port 8000 is now publicly accessible from http://example.localtunnel.com

You can then visit that URL to access Yeti and start running tests:

Yeti on iOS 4 Safari

This is especially useful for cellular devices: You can use your carrier’s internet connection without needing to get your device on the same network as your development computer.

Yeti aims to make JavaScript testing easier; however, it’s far from being complete. (Don’t take the 0.1.0 version number lightly.) Yeti assumes you’re using YUI Test, has only been tested on Mac OS X, and may not work with some kinds of testing scenarios. Despite these shortcomings, Yeti has been so useful internally that we didn’t want to wait any longer to share it with the YUI community.

Getting the code

Yeti is available on GitHub and offered under YUI’s BSD license.

Installing

Yeti is written entirely in JavaScript and runs on top of NodeJS. If you’re already a NodeJS and npm user, installing is very simple:

$ npm install yeti@stable

If you haven’t installed NodeJS and npm and you’re on a recent Mac, you can still install Yeti with a convenient installer.

Yeti Icon Download the Yeti 0.1.0 Installer 2.7 MB
Requires Mac OS X 10.6 and a Intel Core 2 processor or better

If your computer doesn’t meet the installer’s requirements, you can still use Yeti if you’re able to install npm. More installation and usage instructions are available in Yeti’s README.

Your participation is welcome

Yeti is the first project we’ve launched in YUI Labs, an umbrella category where our new ideas and initiatives will take shape. As such, Yeti is offered without the same level of support as our other projects. We still encourage you to ask questions and give feedback in Yeti’s forums and hope Yeti makes testing easy and fun. If it doesn’t, please tell us, file a bug or consider contributing to Yeti.

Happy testing!

About the Author: Reid Burke (@reid) is the newest member of the YUI team. He loves abominable snow monsters and JavaScript.

By Reid BurkeAugust 25th, 2010

Developing an Accessible Star Ratings Widget

In a hurry? Skip to the demo page.

Many ecommerce sites, social networking services, and online communities include rating or assessment features. Soliciting people’s opinion has even become a business model; there are now sites dedicated to rating products, services, businesses, and more.

The most common interface used to display votes is the “star rating system,” in which a particular number of points (often expressed as stars) is assigned to an item by each reviewer. We find this model on many sites, from Amazon to Yelp.

Examples of star rating systems

Figure A. Star rating examples from Amazon and Yelp.

As Figure A shows, both visual interfaces are similar, but what makes these two solutions interesting is their markup base. One relies on <map>, the other on <img>.

You might think that most rating systems would be based on some markup proven to be semantic and "operational" across many User Agents — that is, that rating systems would be based on a specific set of HTML elements and attributes to which one applies behavior and style via JS and CSS. That would make sense, but it is far from the truth. When it comes to markup, authors try just about everything:

  • <a>,
  • <img>,
  • <span>,
  • <li>,
  • <map>,
  • <div>,
  • <input>,
  • and more…

The case of Microformats

Before presenting a few image-based techniques to mark up ratings, I think it is worth mentioning a basic and straightforward approach (from Microformats) that uses characters:

<abbr class="rating" title="3 stars">***</abbr>
Pros
It is straightforward and semantic.
The markup is minimal.
The method is not reliant on CSS.
The method is not reliant on images.
There is no HTTP request.
Cons
It is impossible to represent half values (i.e. 3.5 stars)
It "works" only with asterisks ("star rating").
Screen-readers, by default, do not expand abbreviations (which may not be a big deal in this case).

Note: I use "*" rather than ★ (★) because screen-readers (at least JAWS and NVDA) seem to ignore html entities.

Markup to display image-based ratings

When it comes to display images, authors have many options.

One image per rating

Using a single image:

<img src="4stars.png" alt="4 out of five">
One star
1 out of five
Two stars
2 out of five
Three stars
3 out of five
Four stars
4 out of five
Five stars
5 out of five
Pros
Using one image per rating is straightforward and semantic.
The method is not reliant on CSS.
Minimal markup.
Cons
It creates many HTTP requests as there are many different images.
On top of the performance issue, it can be a maintenance nightmare as authors have to deal with more assets (images to create, to push to a CDN, to modify when site colors change, etc.).
Text selection is not possible in Opera (at least in version 9.52) as the alternate text is ignored

One image per unit

From the whatwg‘s working draft:

<img alt="4 out of 5" src="one-star.png">
<img alt="" src="one-star.png">
<img alt="" src="one-star.png">
<img alt="" src="one-star.png">
<img alt="" src="no-star.png">
One star
1 out of five
Two stars
2 out of five
Three stars
3 out of five
Four stars
4 out of five
Five stars
5 out of five
Pros
Using two img elements per rating diminishes the number of HTTP requests.
The method is not reliant on CSS.
Cons
In Opera, when images are disabled, alternate text is not selectable, and (in small-screen view) that text is rendered with a border which makes it less legible.

Note that this is taken from a controversial working draft. In my opinion, this method is not acceptable because the alternate text does not describe the image accurately and succinctly. Besides, if the basis of this approach is that these images represent content, then why leave some of them with no alt text?

On Ajaxian, for example, the author is using alternate text with every single image, which makes a lot of sense if he considers that each one is content:

<img [snip] alt="+" src="star1.png"/>
<img [snip] alt="+" src="star1.png"/>
<img [snip] alt="+" src="star1.png"/>
<img [snip] alt="-" src="star0.png"/>
<img [snip] alt="-" src="star0.png"/>

In any case, using as many images as there are stars versus using a single element (an img or something else) has the main advantage of facilitating voting mechanisms – where a user selects one of the stars to cast his vote. So we should keep this in mind…

A sprite for background images

The following technique is a adaptation of a strategy originally implemented by developers at Yahoo! Music:

Markup
<span class="rating r1 stars">1 of 5</span>
<span class="rating r2 stars">2 of 5</span>
<span class="rating r3 stars">3 of 5</span>
<span class="rating r4 stars">4 of 5</span>
<span class="rating r5 stars">5 of 5</span>
CSS
.stars {
  background: transparent url(img/sprite.png) no-repeat; 
}
.rating {
  font-size: 0;
  height: 19px;
  overflow: hidden;
  vertical-align: middle;
  width: 96px; 
  display: block;
}
.r1 { background-position: -385px 0; }
.r2 { background-position: -288px 0; }
.r3 { background-position: -192px 0; }
.r4 { background-position: -96px 0; }
One star
1 of 5
Two stars
2 of 5
Three stars
3 of 5
Four stars
4 of 5
Five stars
5 of 5
Pros
This method requires a single HTTP request as it relies on a single sprite image.
Minimal "foot print".
Cons
Content is not revealed with images off.
Nothing shows when the page is printed (a print stylesheet could take care of this issue).
In Opera, the high contrast stylesheet makes all the stars disappear; the same is true in High Contrast Mode Optimization.
Text selection is possible, but it’s not obvious (via highlighting).

A sprite in the markup

This approach is based on the TIP method, which uses a sprite image as an <img> element rather than a background image:

Markup
<span title="1 of 5" class="rating r1"><img width="0" height="1" src="sprite.gif" alt=""/>1 out of 5</span>
<span title="2 of 5" class="rating r2"><img width="0" height="1" src="sprite.gif" alt=""/>2 out of 5</span>
<span title="3 of 5" class="rating r3"><img width="0" height="1" src="sprite.gif" alt=""/>3 out of 5</span>
<span title="4 of 5" class="rating r4"><img width="0" height="1" src="sprite.gif" alt=""/>4 out of 5</span>
<span title="5 of 5" class="rating r5"><img width="0" height="1" src="sprite.gif" alt=""/>5 out of 5</span>
CSS
.rating {
  position: relative;
  height: 1.6em;
  width: 8.1em;
  overflow: hidden;
  vertical-align: middle;
  display: block;
}
.rating img {
  position: absolute;
  width: 40.5em;
  height: 1.55em;
  top: 0;
  border: 1px solid #fff;
}
.r1 img { right: 0; }
.r2 img { left: -24.4em; }
.r3 img { left: -16.2em; }
.r4 img { left: -8.1em; }
One star
1 out of 5
Two stars
2 out of 5
Three stars
3 out of 5
Four stars
4 out of 5
Five stars
5 out of 5
Pros
This method requires a single HTTP request.
This technique is the only one of the four methods above that reveals content when Firefox users select "hide images" or "make images invisible" (from the developer’s toolbar).
When images are unavailable a red "x" appears only in the highest rating (i.e. 5 out of 5) instead of in each one as it is the case with other solutions that rely on img elements.
Cons
The display of images is reliant on CSS.

It is worth noting that unlike other Image Replacement techniques, this method allows:

  • images to scale depending on text-size settings.
  • images to be printed.
  • alternate text to be easily selected as the whole image appears highlighted (Firefox).
  • the image to not disappear in a high-contrast setting/stylesheet.
  • alternate text selection in Opera (when images are disabled).
  • borderless alternate text in Opera’s small screen view.

Markup to cast votes

Starting with a native mechanism

To cast votes, we need a low-level voting mechanism that allows simple user selection and submission. For this, we can rely on using a form with labels and controls:

Markup
<fieldset>
  <legend>Rating</legend>
  <label><input type="radio" name="movie" value="1_5">1/5</label>
  <label><input type="radio" name="movie" value="2_5">2/5</label>
  <label><input type="radio" name="movie" value="3_5">3/5</label>
  <label><input type="radio" name="movie" value="4_5">4/5</label>
  <label><input type="radio" name="movie" value="5_5">5/5</label>
</fieldset>
Result
Rating






Adding breaks and whitespace

For better legibility, we add <br> and whitespace.

Markup
<fieldset>
<legend>Rating</legend> <label><input type="radio" name="movie" value="1_5"> 1/5</label><br> <label><input type="radio" name="movie" value="2_5"> 2/5</label><br> <label><input type="radio" name="movie" value="3_5"> 3/5</label><br> <label><input type="radio" name="movie" value="4_5"> 4/5</label><br> <label><input type="radio" name="movie" value="5_5"> 5/5</label> </fieldset>
Result
Rating






Introducing the sprite image in the markup

For this solution, we are using a smaller sprite than the one in the example above. It is now composed of two single stars (“on” and “off”).

We place img elements inside the labels. We assume they will have no value without CSS support, thus we "hide" them by setting specific dimensions via their width and height attributes. Note that using 0 with both attributes would show a broken image in some UAs.


<form ...>
  <fieldset>
    <legend>Rating</legend>
    <label class="one" title="1 out of 5"><input name="LandOf" value="1" checked="checked" type="radio"> 1/5<img src="star-sprite.gif" alt="" height="0" width="0"></label>
    <label class="two" title="2 out of 5"><input name="LandOf" value="2" type="radio"> 2/5<img src="star-sprite.gif" alt="" height="0" width="0"></label>
    <label class="three" title="3 out of 5"><input name="LandOf" value="3" type="radio"> 3/5<img src="star-sprite.gif" alt="" height="0" width="0"></label>
    <label class="four" title="4 out of 5"><input name="LandOf" value="4" type="radio"> 4/5<img src="star-sprite.gif" alt="" height="0" width="0"></label>
    <label class="five" title="5 out of 5"><input name="LandOf" value="5" type="radio"> 5/5<img src="star-sprite.gif" alt="" height="0" width="0"></label>
  </fieldset>
</form>

Note that with the above markup, we can expect (in most browsers) field selection via label selection.

Considering Accessibility

Unfortunately, as is, this markup creates issues in at least two screen-readers: JAWS and NVDA (see test case for these bugs). The problem is related to the use of a title attribute and an empty string for alternate text.

The workaround to not confuse screen-reader users is to use "stars" as alternate text (alt) and use JavaScript to insert title on mouseover.

Better Markup
<fieldset>
<legend>Rating</legend> <label><img src="img/small-sprite.gif" width="0" height="1" alt="stars"><input type="radio" name="movie" value="1_5"> 1/5</label><br> <label><img src="img/small-sprite.gif" width="0" height="1" alt="stars"><input type="radio" name="movie" value="2_5"> 2/5</label><br> <label><img src="img/small-sprite.gif" width="0" height="1" alt="stars"><input type="radio" name="movie" value="3_5"> 3/5</label><br> <label><img src="img/small-sprite.gif" width="0" height="1" alt="stars"><input type="radio" name="movie" value="4_5"> 4/5</label><br> <label><img src="img/small-sprite.gif" width="0" height="1" alt="stars"><input type="radio" name="movie" value="5_5"> 5/5</label> </fieldset>
Result
Rating






Styling

Giving dimensions to the image via CSS

We use em to allow the image to grow or shrink depending on font-size.

Markup

Unchanged

CSS
img {
  width:2.8em;
  height:1.4em;
}
Result
Rating






As you can see already, clicking on an image selects the corresponding radio button. There is no need for scripting as implicit labeling produces this behavior (except in IE).

Removing the image from the flow

Styling the label with position:relative and the image with position:absolute with top/left values is enough to hide input and text inside the labels.

Markup

Unchanged

CSS
label {
  position:relative;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
}
Result
Rating






Displaying one star per label

We style the label so its dimensions match the height and width of a single star.

Markup

Unchanged

CSS
label {
  position:relative;
  height:1.4em;
  width:1.4em;
  overflow:hidden;
  display:block;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
}
Result
Rating






Displaying the stars horizontally

We remove the brs and we float the labels.

Markup

Unchanged

CSS
br {
  display:none;
}
label {
  position:relative;
  height:1.4em;
  width:1.4em;
  overflow:hidden;
  display:block;
  float:left;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
}
Result
Rating






Displaying the sprite image depending on rating

To set a "3 out of 5" rating, we apply the same class to the last two labels. This class will shift the position of the image inside the label.

Markup
<fieldset>
<legend>Rating</legend>
<label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="1_5"> 1/5</label><br>
<label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="2_5"> 2/5</label><br>
<label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="3_5"> 3/5</label><br>
<label class="no_star"><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="4_5"> 4/5</label><br>
<label class="no_star"><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="5_5"> 5/5</label>
</fieldset>
CSS
br {
  display:none;
}
label {
  position:relative;
  height:1.4em;
  width:1.4em;
  overflow:hidden;
  float:left;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
}
.no_star img {
  left:-1.4em;
}
Result
Rating






Not relying on image alone to display information

It’s important to offer an alternative to the display of stars in case images are not available. This is because labels and radio buttons are styled to be on top of each other. A simple solution is to move input and text off-screen (i.e. using text-indent:-999em) and apply a background color to the labels.

Markup

No change

CSS
br {
  display:none;
}
label {
  position:relative;
  height:1.4em;
  width:1.4em;
  overflow:hidden;
  float:left;
  background:teal;
  margin-right:1px;
  text-indent:-999em;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
}
.no_star {
  background:#ccc;
}
.no_star img {
  left:-1.4em;
}

Note:

  • text-indent also fixes a upwards jump of the image each time the controls get focus.
  • the right margin is to make sure background colors create squares and not rectangles (which would happen with adjacent labels sharing the same background color).
Result
Rating






Finishing touch

  • We use the pseudo-class :hover to create some rollover effect,
  • We hide the fieldset border,
  • We hide the legend,
  • We style the cursor.
Markup

Unchanged

CSS
br {
  display:none;
}
label {
  position:relative;
  height:1.4em;
  width:1.4em;
  overflow:hidden;
  float:left;
  background:teal;
  margin-right:1px;
  text-indent:-999em;
}
input {
  position:absolute;
  left:-999em;
  top:.5em;
}
img {
  width:2.8em;
  height:1.4em;
  position:absolute;
  top:0;
  left:0;
  cursor: pointer;
}
.no_star {
  background:#ccc;
}
.no_star img {
  left:-1.4em;
}
label:hover {
  opacity:.5;
  filter:alpha(opacity=50);
}
fieldset {
  border:0;
}
legend {
  text-indent:-999em;
}

Note: label:hover is ignored by IE6 and in Opera the background color bleeds through the images. In the demo page, instead of using opacity, I am using a different sprite that shows four states.

Result

Rating






Displaying the ratings without allowing user interaction

We can make the ratings "read-only" by adding disabled and checked attributes in the appropriate input fields.

Markup

<fieldset>
  <legend>Rating</legend>
  <label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="1_5" disabled> 1/5</label><br>
  <label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="2_5" disabled> 2/5</label><br>
  <label><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="3_5" checked="checked"> 3/5</label><br>
  <label class="no_star"><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="4_5" disabled> 4/5</label><br>
  <label class="no_star"><img src="img/small-sprite.gif"  width="0" height="1" alt="stars"><input type="radio" name="movie" value="5_5" disabled> 5/5</label>
</fieldset> 

CSS

The rule using :hover has been removed

h4>Result

Rating






Giving more thought to the process

At this point, it is possible to cast votes without script support, but sighted users have no clue about their selection. So we use JavaScript to:

  • give feedback to the user regarding his selection,
  • give keyboard users a visual clue while they navigate through the radio buttons.

At the same time, we take advantage of using a script to insert title attributes that will create "tooltips" when users hover over the labels/stars.

Because of the lack of feedback regarding selection without JavaScript, we style labels and form controls only if there is script support. To do so we use JavaScript to set a flag on the html element and then we create a rule based on descendant selectors containing that hook. If the flag is missing, that rule does not apply and elements are not styled.

This is the demo page, the final product. To see how this solution behaves according to various settings, you may want to use your favorite developer tools to increase text-size, break image paths, disable JavaScript, turn CSS off, and more…

Wrap up

Coming up with a "acceptable" solution requires to identify users’ needs, User Agents’ peculiarities, User Agents’ settings and more – which means extensive testing.

In this process, users’ feedback is essential because following best practices is not always a sure thing. For example, as mentioned earlier, setting no value for the alt attribute of the images within the labels seem to be the safe thing to do, but it turns out that it creates issues with at least two screenreaders (see test case).

Also, feedback from assistive devices’ users allows to ignore some validation error messages – as the one that the Firefox Accessibility Toolbar reports (according to http://bestpractices.cita.uiuc.edu/html/nav/form/).

The goal here was not to fix everything, though. Being able to cast votes without a pointing device was one of my priorities, but improving the look and feel of the solution in Opera when images are disabled is not something I consider essential.

The most interesting part of this "journey" was to make the solution accessible to many users under various conditions, addressing issues such as:

  • images off,
  • javascript off,
  • CSS off,
  • a combination of the above.

It is also nice to know that this technique relies on img elements rather than background images, which allows the stars to:

  • resize themselves according to the user’s settings,
  • show in high contrast mode,
  • be printed by default (unlike background images).

All of this comes without sacrificing performance, as this solution relies on this single sprite: stars

Late finding

I recently discovered the system Amazon has built for its voting page. It is quite interesting as they serve a different solution depending on script support. If there is script support, they use an image <map> (interesting approach), if there is no script support they use radio buttons. In both cases, the solution is accessible to keyboard users, and this helps to maximize access to a feature that is a core differentiator for the Amazon platform.

Note that they do not use JavaScript to replace the radio buttons with a image <map>; instead, they use noscript elements in which table markup contains radio buttons.

"Out of the box" solutions

Dreamweaver®
Spry Rating Widget
YUI
Star Rating Script for YUI
Star Rating script with YUI
JQuery
Half-Star Rating Plugin
jQuery Ajax Rater
Simple Star Rating System
5 star rating system in PHP, MySQL and jQuery
WordPress
GD Star Rating System for WordPress
GD Star Rating
Star Rating for Reviews
Flash
5 Star rating system component
Misc.
How a star rating should be
Starry widget 2

Special thanks

Special thanks to Victor Tsaran and Todd Kloots for their valuable feedback.

By Thierry KoblentzAugust 24th, 2010

Announcing YUI 3.1.2: Critical Security Update for All YUI 3.1.x/3.2.0pr1 Users

The YUI team released YUI 3.1.2 today. This is an important security update for all users of YUI 3.1.x and 3.2.0pr1. If you are hosting YUI 3.1.x or 3.2.0pr1 on your site, or if you use YUI 3.1.x/3.2.0pr1 IO’s cross-domain functionality, you are affected.

XDR in YUI’s IO utility implements a Flash transport as a fallback for browsers that don’t support native XDR. An error in our implementation of the Flash fallback in YUI versions 3.1.x and 3.2.0pr1 allows the io.swf file to operate unsafely whether served from the Yahoo! CDN or from your own server. The remedy for this problem is twofold:

  • If you have deployed the full YUI 3.1.x/3.2.0pr1 build directory to your server, replace build/io/io.swf in the affected version with the version included in YUI 3.1.2. Do so whether or not you are using the IO utility or its XDR feature.
  • If you are using IO’s XDR feature, upgrading to the 3.1.2 version of io-swf addresses the security problem. Host version 3.1.2 of io.swf on your own server (this file cannot operate safely from a CDN; it is not included on the CDN as of 3.1.2). If you have been drawing io.swf from http://yui.yahooapis.com, remove this domain from your crossdomain.xml file.

More details about this issue can be found in the IO utility documentation.

By Eric MiragliaAugust 19th, 2010

Quick Edit mode for YUI 2 DataTable

YUI 2 DataTable provides slick inline editing. When disableBtns is turned on in the column configuration, editing simple values like strings or numbers feels just like Excel. However, the experience cannot be as responsive as a desktop application because each change typically requires an XHR call to the server to store (or reject!) the new value. If the user needs to change many of the displayed values, it can be a slow and frustrating experience. To solve this, I developed QuickEditDataTable. This extends DataTable to add Quick Edit mode, which allows all editable values to be changed in one bulk operation:

(Click the screenshot to play with this example.)

Overview

To enter Quick Edit mode, call startQuickEdit(). To exit Quick Edit mode, call cancelQuickEdit().

It is your responsibility to save the changes before calling cancelQuickEdit(). To simplify this task, QuickEditDataTable provides getQuickEditChanges(). This returns an array of objects, one for each row. Each object contains only the values that were changed in that row, keyed off the column id’s. For example, if the table has 4 columns (title, author, year, quantity), and the user only changed the quantity in one row to 20, then the object for that row would be {quantity:20}. The other values would be omitted.

QuickEditDataTable can easily extend YAHOO.widget.ScrollingDataTable if you need that functionality. If you need this, simply make a copy of the source file and change the base class.

Configuration

Quick Edit is a modal state in which the cell formatters for editable columns are swapped out and replaced with special formatters that generate input, textarea, or select elements. Only columns that have quickEdit configuration will be editable. The configuration options are:

copyDown

If true, the top cell in the column will have a button to copy the value down to the rest of the rows.

formatter

The cell formatter which will render an appropriate form field: <input type=”text”>, <textarea>, or <select>. By default, the cell formatter YAHOO.widget.QuickEditDataTable.textQuickEditFormatter is used for all cells to produce input elements. To get a textarea element, configure a column to use YAHOO.widget.QuickEditDataTable.textareaQuickEditFormatter instead. You can also write a custom quick edit formatter — see below.

validation

Validation configuration for every field in the column.

css

CSS classes encoding basic validation rules:

yiv-required

Value must not be empty.

yiv-length:[x,y]

String must be at least x characters and at most y characters. At least one of x and y must be specified.

yiv-integer:[x,y]

The integer value must be at least x and at most y. x and y are both optional.

yiv-decimal:[x,y]

The decimal value must be at least x and at most y. Exponents are not allowed. x and y are both optional.

fn

A function that will be called with the DataTable as its scope and the cell’s form element as the argument. Return true if the value is valid. Otherwise, call this.displayQuickEditMessage(...) to display an error and then return false.

msg

A map of types to messages that will be displayed when a basic or regex validation rule fails. The valid types are: required, min_length, max_length, integer, decimal, and regex. There is no default for type regex, so you must specify a message if you configure a regex validation. The default error messages for the other types are stored in YAHOO.widget.QuickEditDataTable.Strings and can be overridden and/or localized.

regex

Regular expression that the value must satisfy in order to be considered valid.

Sometimes, a non-editable column must be rendered differently during Quick Edit mode. The best example is a column containing a link, since navigating away from the page while in Quick Edit mode can be disastrous. To remove the link during Quick Edit, configure qeFormatter for the column to be YAHOO.widget.QuickEditDataTable.readonlyLinkQuickEditFormatter. For email addresses, use YAHOO.widget.QuickEditDataTable.readonlyEmailQuickEditFormatter. You can also write you own custom, read-only formatter. Simply follow the normal rules for constructing a DataTable cell formatter.

Custom Quick Edit Formatters

To write a custom cell formatter for QuickEdit mode, you must structure the function as follows:

function myQuickEditFormatter(el, oRecord, oColumn, oData) {
  var markup =
    '<input type="text" class="{yiv} yui-quick-edit yui-quick-edit-key:{key}"/>' +
    YAHOO.widget.QuickEditDataTable.MARKUP_QE_ERROR_DISPLAY;
    el.innerHTML = lang.substitute(markup, {
      key: oColumn.key,
      yiv: oColumn.quickEdit.validation ? (oColumn.quickEdit.validation.css || '') : ''
    });
    el.firstChild.value = extractMyEditableValue(oData);
    YAHOO.widget.QuickEditDataTable.copyDownFormatter.apply(this, arguments);
};

You can use textarea or select instead of input, but you can only create a single field.

extractMyEditableValue() does not have to be a separate function nor must it be limited to using only oData. The work should normally be done inline in the formatter function, but the name of the sample function makes the point clear.

About the author: John Lindal (@jafl5272 on Twitter) is one of the lead engineers constructing the foundation on which Yahoo! APT is built. Previously, he worked on the Yahoo! Publisher Network.

By John LindalAugust 19th, 2010

Using YUI 2 on the DuckDuckGo Search Engine

DuckDuckGo is a search engine that uses YUI extensively. Here’s what it uses in particular:

  • ImageLoader. Matt Mlinac’s YUI 2 ImageLoader was the first thing I implemented and what originally hooked me on YUI for this project. DuckDuckGo has favicons next to results and often has “Zero-click Info” above results that usually includes an image. I didn’t want these images to compete with the results when loading, as getting results as fast as possible is the ultimate goal.

    The ImageLoader Utility handles this well by loading the images after the page load. DDG also auto-loads the next page of results when you scroll down. Sometimes the favicons icons are therefore hidden, and with ImageLoader their load is delayed (sometimes indefinitely) until necessary. To accomplish this, there is a different image group per (internal) page, each with its own custom trigger.

    div.event=new YAHOO.util.CustomEvent('it');
        var ig1=new YAHOO.util.ImageLoader.group(div,'click');
        ig1.addCustomTrigger(div.event);
        div.ig = ig1;
    
  • Cookie. DuckDuckGo has a lot of settings, which are stored via cookies and alternately via URL params. When cookies are used, I use Nicholas Zakas’s YUI 2 Cookie Utility to easily get and set the values.

      YAHOO.util.Cookie.set(cookie, value, { expires: new Date("January 12, 2025") });
      x=ki||YAHOO.util.Cookie.get("i");
  • StyleSheet. Some DDG settings change the look and feel of the site. These changes are actually accomplished after page load via Luke Smith’s YUI 2 StyleSheet Utility. Some of these changes are straightforward and I can just use the setStyle Dom function.

    YAHOO.util.Dom.setStyle('b2','display','block');

    Others require actual class changes, which I use the utility to do.

    YAHOO.util.StyleSheet('DDG').set('.ci', {display: "block"}).
                set('.cid', {display: "block"}).
                set('.ci2', {display: "block"}).
                enable();
  • Dom. I also use some functions in Matt Sweeney’s base YUI 2 Dom component. I referenced setStyle above, and I also use the related getStyle, addClass and removeClass functions. In addition, I find the getViewportHeight, getViewportWidth, getX and getY functions to be incredibly useful to make things work cross-browser, and now on mobile screens as well.

  • KeyListener. DDG has a bunch of keyboard shortcuts that let you navigate results without the mouse. I use the YUI 2 KeyListener component to enable these shortcuts.

    kl14 = new YAHOO.util.KeyListener(document, { keys:[70] }, { fn:not } );kl14.enable();
  • AutoComplete. I’m currently working on adding search suggestions to the search engine, and will be using Jenny Donnelly’s YUI 2 AutoComplete component for the front-end. I understand that AutoComplete is getting introduced in YUI 3 soon. Everything else I use has already been introduced in YUI 3, though I still use YUI 2. However, I will be exploring the migration to YUI 3 soon.

About the author: Gabriel Weinberg is the founder of the DuckDuckGo search engine, based out of Valley Forge, PA. Gabriel has been a startup founder for over ten years, and his last company was sold in 2006. Gabriel holds degrees from MIT in Physics and the Technology and Policy Program.

By Gabriel WeinbergAugust 19th, 2010

Implementing YUI on the Assembla.com Agile Planner

Fast and fun – that was the user requirement for the new Assembla.com Agile Planner – an AJAX interface for adding development tasks, building story/feature outlines, and scheduling them into releases. We were lucky to have YUI 3 to make it fast and fun to implement as well.

I had used YUI 2 for a number of prior projects and I had been impressed by the engineering of the UI components and the underlying library infrastructure. I wanted to learn more about YUI 3, with its compact syntax and deeper focus on DOM manipulation and CSS3-style selectors. This project, with a low dependence on ‘prebuilt widgets,’ was a perfect opportunity to get my feet wet with YUI 3. The facilities for ‘large app’ implementation via custom modules and integration with YUI loader made it a natural choice.

The Agile Planner supports a number of drag and drop user interactions with multiple interaction groups and context based behaviors. At the same time, it handles a complex set of interactions with the server, including merging in new data from the server, and propagating changes to the server.

We improved on the existing Planner which was based on Rails handlers and Prototype.js. YUI’s sandbox philosophy and strong OOP facilities made coexisting with Prototype.js a breeze.

We used a large number of YUI components, including:

  • Async-Queue to offer a responsive experience on a page that can involve 1000+ simultaneous tickets
  • Drag and Drop with interaction groups.
  • IO as a connection manager to queue and massage server interaction.
  • Event-delegate to allow simply hydrating html templates and forgetting about them.
  • Event-key for keyboard interaction and navigation.
  • Collection for giving us a consistent implementation experience across browsers.
  • Cookie for easy short-term UI persistence.
  • Profiler to find the biggest speed gains
  • YUI Doc to leave information for the rest of the team

Working with YUI 3 on an app like this has been fun, and I am looking forward to hearing what our users will urge us to do next!

About the author: Joachim Larsen is a frontend engineer with Assembla.com.

By Joachim LarsenAugust 18th, 2010
« Older Entries

Pages

  • About
  • Contribute
  • YUI Jobs

Recent Posts

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

Archives

Categories

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

Meta

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