JQuery_ Novice to Ninja - Earle Castledine [104]
Note: Conditional Assignment with Modulus
For the addClass action, we’re specifying the class name conditionally with a ternary operator (see the section called “Fading Slideshow” in Chapter 4), based on a bit of math. As we’ve done earlier in the book, we’re using the modulus (%) operator to determine whether the index is even or odd. If the index is odd, we’ll add the rating-right class; this makes the link look like the right side of a star.
Once our link is ready, we pass it to the addHandlers method—this is where we’ll attach the events it needs to work. Then, we append it to the list container. Once it’s in the container, we see if the current radio button is selected (we use the :checked form filter). If it’s checked, we want to add the rating class to this half-star, and to all of the half-stars before it. Any link with the rating class attached will be assigned the gold star image (which will allow users to see the current rating).
To select all of the elements we need to turn gold, we’re going to enlist the help of a couple of new jQuery actions: prevAll and andSelf. The prevAll action selects every sibling before the current selection (unlike the prev action, which only selects the immediately previous sibling). For our example, we want to add the class to the previous siblings and the current selection. To do so, we apply the andSelf action, which simply includes the original selection in the current selection. Now we have all of the links that will be gold, so we can add the class.
Tip: Other Traversal Methods
You might have guessed that, along with prevAll, jQuery provides us with a nextAll method, which grabs all of an element’s siblings occurring after it in the same container. jQuery 1.4 has also introduced two new companion methods: prevUntil and nextUntil. These are called with a selector, and will scan an element’s siblings (forwards or backwards, depending on which one you’re using) until they hit an element that matches the selector.
So, for example, $('h2:first').nextUntil('h2'); will give you all the elements sitting between the first h2 on the page and the following h2 in the same container element.
If you pass a second parameter to prevUntil or nextUntil, it will be used as a selector to filter the returned elements. So, for example, if we had written nextUntil('h2', 'div'), it would only return div elements between our current selection and the next h2.
After doing all this hard work, we can now add the new list of links to the control, and get rid of the original buttons. Now the user will only interact with the stars:
chapter_07/11_star_ratings/script.js (excerpt)
// Hide the original radio buttons
$(this).append($list).find('input:radio').hide();
The control looks like it’s taking shape now—but it doesn’t do anything yet. We need to attach some event handlers and add some behavior. We’re interested in three events. When users hover over a star, we want to update the CSS sprite to show the hover state; when they move away, we want to revert the CSS sprite to its original state; and when they click, we want to make the selection gold:
chapter_07/11_star_ratings/script.js (excerpt)
$(item).click(function(e) {
// React to star click
})
.hover(function() {
$(this).prevAll().andSelf().addClass('rating-over');
},function() {
$(this).siblings().andSelf().removeClass('rating-over');
});
The hover function is the easiest: when hovering over, we select all of the half-stars before—including the current half-star—and give them the rating-over class using prevAll and andSelf, just like we did in the setup. When hovering out, we cover our bases and remove the rating-over class from all of the links. That’s hovering taken care of.
Now for the click:
chapter_07/11_star_ratings/script.js (excerpt)
// Handle Star click
var $star = $(this);
var $allLinks = $(this).parent();
// Set the radio button value
$allLinks
.parent()
.find('input:radio[value=' + $star.text() + ']')
.attr('checked',