Star Rating Script for YUI

I wanted to have an easy to use star rating script similar to Wil Stuckleys one for jQuery but for YUI. Because I couldn’t find one, I made it myself.

It’s very simple and fully degradable. It works without JavaScript and it notifies about the status of the submission. See example below.

Full disclosure: I’m not very experienced with JavaScript or YUI. I’m quite certain that the code below can be refined in some ways, but as for now, it works for me. If you have any suggestions or comments, please share them! Updated revisions are more than likely :)

Example

With JavaScript

Without JavaScript

Features

  • Works with or without JavaScript
  • Shows average rating
  • Shows status message during and after the submit
  • Easy to use

How to use it

Using this script is very easy. Just format your rating form like this:

<div id="ratingdiv">
<form id="rating" action="/path/to/your/controller/" method="post" title="Average: 3.4">
<label for="id_rating">Rating:</label>
<select name="rating" id="id_rating">
<option value="1">1 - Poor</option>
<option value="2">2 - Fair</option>
<option value="3">3 - Good</option>
<option value="4">4 - Very Good</option>
<option value="5">5 - Excellent</option>
</select>
<input type="submit" value=" Submit rating" />
</form>
</div>

and include necassary JavaScript to the page:

<script type="text/javascript" src="/path/to/yui/build/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="/path/to/yui/build/dom/dom-min.js"></script>
<script type="text/javascript" src="/path/to/yui/build/event/event-min.js"></script>
<script type="text/javascript" src="/path/to/yui/build/connection/connection-min.js"></script>
<script type="text/javascript" src="/path/to/yui/build/animation/animation-min.js"></script>
<script type="text/javascript" src="rating.js"></script>

For decorating the form, use CSS. This is an example:

<style type="text/css">
<!--

form.rating {
    padding: 1em;
    border: 1px solid #ccc;
}

.rating {
    cursor: pointer;
    clear: both;
    display: block;
}

.rating:after {
    content: '.';
    display: block;
    height: 0;
    width: 0;
    clear: both;
    visibility: hidden;
}

.star {
    float: left;
    width: 17px;
    height: 15px;
    overflow: hidden;
    text-indent: -999em;
    cursor: pointer;
}

.star,
.star a {background: url(http://media.unessa.net/django/img/projects/star-rating/star.gif) no-repeat 0 0px;}

.star a {
    display: block;
    width: 100%;
    height: 100%;
    background-position: 0 0px;
}

div.rating div.on a {
    background-position: 0 -16px;
}

div.rating div.hover a,
div.rating div a:hover {
    background-position: 0 -32px;
}

div.notifytext {
    margin-top: 5px;
    font-size: .8em;
    clear: both;
}

#ratingdiv {
    height: 35px;
}
-->
</style>
On the backend you need a script that handles the POST normally. You can separate the AJAX-posts and normal POSTs with GET-variable xhr that is set to true when the POST is done with JavaScript.

For the first displaying of the form, provide an average rating to the title-attribute of the form. The script assumes it to be in one digit accuracy.

The code

The rating.js looks like this:

var rating = {
    init: function() {
        rating.ratingform = document.getElementById('rating')
        rating.ratingdiv = document.getElementById('ratingdiv')
        rating.stardiv = document.createElement('div')
        rating.notifytext = document.createElement('div')
        rating.average = rating.ratingform.title.split(/:\s*/)[1].split(".")
        rating.submitted = false
        rating.make_stardiv()
    },

    make_stardiv: function() {
        /* Replaces original form with the star images */
        
        YAHOO.util.Dom.setStyle(rating.ratingform, 'display', 'none');
        YAHOO.util.Dom.addClass(rating.stardiv, 'rating');
                
        // make the stars
        for (var i=1; i<=5; i++) {
            // first, make a div and then an a-element in it
            var star = document.createElement('div');
            star.id = 'star' + i;
            var a = document.createElement('a');
            a.href = '#' + i;
            a.innerHTML = i;
            YAHOO.util.Dom.addClass(star, 'star');
            star.appendChild(a);
            rating.stardiv.appendChild(star);

            // add needed listeners to every star
            YAHOO.util.Event.addListener(star, 'mouseover', rating.hover_star, i);
            YAHOO.util.Event.addListener(star, 'mouseout', rating.reset_stars);
            YAHOO.util.Event.addListener(star, 'click', rating.submit_rating, i);
        }        
        rating.ratingdiv.appendChild(rating.stardiv);
        // show the average
        rating.reset_stars();
        // add the statustext div and hide it
        YAHOO.util.Dom.addClass(rating.notifytext, 'notifytext');
        YAHOO.util.Dom.setStyle(rating.notifytext, 'opacity', 0);
        rating.ratingdiv.appendChild(rating.notifytext);
    },
    
    hover_star: function(e, which_star) {
        /* hovers the selected star plus every star before it */
        for (var i=1; i<=which_star; i++) {
            var star = document.getElementById('star' + i);
            var a = star.firstChild;
            YAHOO.util.Dom.addClass(star, 'hover');
            YAHOO.util.Dom.setStyle(a, 'width', '100%');
        }
    },
    
    reset_stars: function() {
        /* Resets the status of each star */
        
        // if form is not submitted, the number of stars on depends on the 
        // given average value
        if (rating.submitted == false) {
            var stars_on = rating.average[0];
            if (rating.average[1] >= 0)
                stars_on = parseInt(rating.average[0]) + 1;
            var last_star_width = rating.average[1] + '0%';
        } else {
            // if the form is submitted, then submitted number stays on
            var stars_on = rating.submitted;
            var last_star_width = '100%';
        }

        // cycle trought 1..5 stars
        for (var i=1; i<=5; i++) {
            var star = document.getElementById('star' + i);
            var a = star.firstChild;
            
            // first, reset all stars
            YAHOO.util.Dom.removeClass(star, 'hover');
            YAHOO.util.Dom.removeClass(star, 'on');

            // for every star that should be on, turn them on
            if (i<=stars_on && !YAHOO.util.Dom.hasClass(star, 'on'))
                YAHOO.util.Dom.addClass(star, 'on');

            // and for the last one, set width if needed
            if (i == stars_on)
                YAHOO.util.Dom.setStyle(a, 'width', last_star_width);
        }
    },
    
    submit_rating: function(e, num) {
        // If the form has not been submitted yet 
        // and submission is not in progress
        if (rating.submitted == false) {
            rating.submitted = num;
            // After the form is submitted, instead of old average, show
            // submitted number of stars selected
            rating.average = [num, 0];
            
            // change the statustext div and show it
            rating.notifytext.innerHTML = 'Rating is being saved.';
            var notify_display = new YAHOO.util.Anim(rating.notifytext, { opacity: { to: 1 } }, 0.25, YAHOO.util.Easing.easeIn);
            notify_display.animate();       
            
            // change the rating-value for the form and submit the form
            var post_to = rating.ratingform.action;
            rating.ratingform.elements[0].value = num;
            YAHOO.util.Connect.setForm(rating.ratingform);
            var c = YAHOO.util.Connect.asyncRequest('POST', post_to + '?xhr=True', rating.ajax_callback);
        }
    },
    
    ajax_callback: {
        success: function(o) {
            // release the form to normal status and change the statustext
            rating.submitted = false;
            rating.notifytext.innerHTML = 'Rating saved.';
        },
        failure: function(o) { // we shouldn't ever go down this path.
            alert('Error: ' + o.status + " " + o.statusText );
        }
    }
}
YAHOO.util.Event.addListener(window, 'load', rating.init);

Download the script.

Version history

  • Version 0.1 — 2007-04-06
    • First version!
Tagged with ,

14 comments

1. beckie April 12th, 2007

great! i think the half-star display for average-rating is pretty cool! Here's another star rating using YUI I used a different approach for the rollover effect though. It'll be great if we can have both (half-star of ave. rating and CSS rollover effect) ;-)

2. MasterVision April 14th, 2007

Hello guys, I want to add a star rating to my forum site, is it possible to install this codes and.. can you assist me on how this star rating script works.

Thank you.. I'll pay if this star rating works for my site.

here is my site www.jappinoy.com

3. Ignasi April 29th, 2007

Hi! I sow your star rating sistem, and is easy!

I have a blog (http://ignasitrochut.blogspot.com) and I want to put this sistem but I have one question.

The results of rating, is posible to show in one place the best post and add one link show it?

It's possible?

Thank you!

4. MasterVision May 5th, 2007

Is the author of this site still alive?

hueueueueuehooooooo

5. Uninen May 25th, 2007

Ignasi: i think your question is not related to this javascript rating system but more to the backend code that you are using.

MasterVision: Yes, I'm still alive, just very busy with Real Work ;) I'm afraid I'm not able to help you with this, sorry. I'm sure there are plenty of eager PHP-developers who can assist you, though. Good luck!

6. Rolle May 31th, 2007

Muuten loistava, MUTTA samalle sivulle ei voi laittaa kuin yhden äänestyksen, sillä jos laittaa monta vain ensimmäinen niistä näkyy graafisena. Käytän tällähetkellä tuota jQuery-versiota, harmi vain kun siinä ei ole tuota mahtavaa ajax-tallennusta... kiitos kuitenkin. Olisi täydellistä jos jaksaisit vaikkapa vaihtaa tuon id:n class-määritelmään, id:tä kun voi käyttää vain kerran samalla sivulla. Tai no mitäpä minä näistä mitään tiedän.

7. Uninen May 31th, 2007

Rolle: firstly, please keep your comments in English! Vast majority of the readers of this blog don't understand Finnish very well :) (For comments in Finnish, feel free to use my contact form)

As for the current limitations of this script, yes, it's currently possible to include only one rating per page. This shouldn't be too hard to fix, though. There are also some other minor tweaks that I'd like to make for version 0.2.

Hopefully I'll get a new version out soon. Subscribe to the RSS-feed to keep informed of the changes!

8. Rolle June 1st, 2007

Sorry about that (posting in finnish). I do like your script so I don't use jQuery-version any longer because I'm not happy without the AJAX-saving. I'm a real amateur in JavaScript so I guess I have to try to modify the script to my needs (to get more ratings per page) while waiting new version. I look forward to see the changes. Keep up the good work!

I use former phpsoft's (today it's borget.info) rating-script for rating-functions and -saving: http://borget.info/?page_id=18 and the page where I'm using the stars is http://rolleweb.net/pelisivu/index.ph...

9. Pamela July 11th, 2007

Great script.

Has anyone implement it with multiple items that need to be rated?

I'm working on such a page and only the first rating item shows up as stars, others show up as regular forms. I think it has something to do with the init function in rating.js and was wondering if anyone has done modifications to make it work.

Thanks,

10. Jack April 3rd, 2008

Dear this is good but can you send me full code for javascripts . really oblige. Please send me on

reachtojack@gmail.com

thanks Jack

11. Uninen April 3rd, 2008

Jack, the full code is shown above. All of it. (Also available via the download link provided.)

12. Sankar May 14th, 2008

HI,

Do u have the all js files, because, i downloaded the all linked js files. But its not working.

13. Ramin siahcheshmi August 10th, 2008

Hello Friend, Nice job. have you seen fisheye component like the one in macX ? how do u think it could be implemented in YUI ?

14. adm90 August 11th, 2008

cooooooooool!!!!!!!!! I love you!!!!!!!! XD

Comment

Use Markdown for markup. (» Open syntax in new window)

 

Proudly Powered by Django
Unessa.net © 2000-2010 Ville Säävuori. All lefts reversed. | Contact information