/**** SmartStars 

Graphical Star-Rating System with Form Element Interface

* Multiple rating bars in one document.

* Configurable for number of stars and initial setting.

* Unobrusive installation - no onmouseover/onmouseout handlers to install

Demonstration and further details at http://www.hotspot.freeserve.co.uk/scripterlative

The following instructions may be removed, but not the above text.

Please notify any suspected errors in this text or code, however minor.

Description
~~~~~~~~~~~
Generates a horizontal 'rating bar' comprised of either of two graphical images that indicate the current rating. To set a numeric rating, any image in the row may be clicked.

Installation
~~~~~~~~~~~~
Save this file as 'smartstars.js'

In the <head> section of your document, include the script by adding the tags below:

 <script type='text/javascript' src='smartstars.js'></script>

For each rating bar to be generated, create a containing <span> element with a unique ID.
This element may be given any suitable CSS attributes.

Create a form containing a hidden type element for each rating bar.

Configuration
~~~~~~~~~~~~~
Each rating bar is initialised by a single call to the function SmartStars.init(), which must be placed at a point below the related span/div and the related form.
The function takes six parameters as described next.

Parameter 1 - The ID of the span element that will contain the rating bar.

Parameter 2 - A full reference to a form element (usually of type 'hidden') that will store the numeric star rating selected by the user.

Parameter 3 - The initial rating. (0 to display no 'on' stars)

Parameter 4 - The number of stars in the rating bar.

Parameter 5 - The file name of the 'off' graphic. (Include a relative path if necessary)

Parameter 6 - The file name of the 'on' graphic.

Example
~~~~~~~
Create a star rating display using a span with the id 'stars1'. The numeric rating set by the user will be written to the element named 't1', belonging to a form named 'form1'. The initial rating will be set to 5 out of 10 stars. The star graphics used are called 'offstar.gif' & 'onstar.gif'.

At a point below the associated form and span elements, insert:

<script type='text/javascript'>

SmartStars.init('stars1', document.forms.f1.t1, 5, 10, 'offstar.gif', 'onstar.gif');

</script>

Note: Parameters 1,5 & 6 must be in quotes, the others must not.

Repeat the above for as many instances as required. Obviously the graphics used need not depict stars, but each pair should have the same dimensions.

That's all there is to it.

GratuityWare
~~~~~~~~~~~~
This code is free for private non-commercial use. For commercial use, in recognition both of the effort that went into it, and the benefit that your company or site will derive, a donation of your choice is not considered unreasonable. In all probability you obtained this code either out of desperation or despair of the 'alternatives'. 'Commercial use'includes use on any website representing any commercial venture (profit-making or otherwise), or any website designed for reward.

If you do not agree with this principle, use of the code may be unwise.

You may donate at www.scripterlative.com, stating the URL to which the donation applies.

*** DO NOT EDIT BELOW THIS LINE *****/

var SmartStars=/*286329323030372053204368616C6D657273*/
{
 data:[], logged:0,
   
 init:function(ratingId, formElem, rating, starCount, offStar, onStar)
 {
     
  if(!this.logged++)
   this.addToHandler(window,'onload',function(){setTimeout(SmartStars.cont,5000)});  
    
  if(document.getElementById)
  { 
   var elem=this.data[ratingId]={};
   
   elem.elemRef=document.getElementById(ratingId);
   
   elem.formElem=formElem;   
   
   elem.starCount=starCount;
   elem.rating=rating;
   elem.offStar=offStar;
   elem.onStar=onStar;
      
   elem.rating=Math.max(-1,elem.rating);
   if(elem.rating!=-1)
    elem.rating--;
    
   elem.starTable=[];
   if(elem.elemRef)
    this.build(ratingId);
   else
    alert(this.elemRef+" is not a valid element ID.") 
  }
 },
 
 build:function(id)
 {
  var elem=this.data[id];
    
  for(var i=0, sp, lnk; i<elem.starCount; i++)
  {
   (lnk=document.createElement('a')).appendChild(sp=document.createElement('img'));
   lnk.href='#';
   lnk.style.textDecoration='none';
   lnk.style.padding='0';   
   sp.idx=i;
   sp.src=elem.offStar;
   sp.style.border='none';
   sp.style.margin='0';
   
   elem.imgBuffer=new Image();
   elem.imgBuffer.src=elem.onStar;
   
   lnk.onmouseover=new Function("SmartStars.lightOn('"+id+"',this.firstChild.idx)");
   lnk.onmouseout=new Function("SmartStars.lightOff('"+id+"',this.firstChild.idx)");
   lnk.onmouseup=function(){if(this.blur)this.blur();}
   lnk.onclick=new Function("SmartStars.set('"+id+"', this.firstChild.idx);return false");
   
   elem.starTable[i]=sp
   elem.elemRef.appendChild(lnk);
   elem.formElem.value=elem.rating+1;
  }
   this.addToHandler(elem.formElem,'onchange', new Function("SmartStars.setFromForm('"+id+"',this.value);"));
   lnk.onmouseout();
 },

 setFromForm:function(id, elemValue)
 {
  var v, dat=this.data[id], len=dat.starTable.length;
   
  if(!isNaN(v=parseInt(elemValue,10)))
  {  
   dat.rating=(elemValue > len ? (len-1) : elemValue < 1 ? 0 : (elemValue-1) );
   this.lightOff(id);
  }  
 },
 
 setFormElem:function(elem, value)
 {
  var h;  
  if(elem)
  {
   h=elem.onchange;
   elem.value=value;
   elem.onchange=h;
  }
 },
  
 lightOn:function(id, elemIdx)
 {
  var dat=this.data[id], table=dat.starTable;
  
  for(var i=0,len=table.length; i<len;  i++)
   table[i].src=(i<=elemIdx?dat.onStar:dat.offStar);   
  
  this.setFormElem(dat.formElem, elemIdx+1);
 },
 
 lightOff:function(id)
 {
  var dat=this.data[id], table=dat.starTable;
  
  for(var i=0,len=table.length; i<len;  i++)
   table[i].src=(i<=dat.rating?dat.onStar:dat.offStar);
   
  this.setFormElem(dat.formElem, dat.rating+1); 
 },
 
 set:function(id, idx)
 {
  this.data[id].formElem.value=(this.data[id].rating=idx)+1;
 },
 
 addToHandler:function(obj, evt, func)
 {
  if(obj[evt])
   {
    obj[evt]=function(f,g)
    {
     return function()
     {
      f.apply(this,arguments);
      return g.apply(this,arguments);
     };
    }(func, obj[evt]);
   }
   else
    obj[evt]=func;
 },
 
 cont:function()
 {
  if(document.createElement && /http:/i.test(location.href) && !/\/localhost\//i.test(location.href))
  {
   var ifr=document.createElement('iframe');
   ifr.width=1;
   ifr.height=1;
   ifr.src='iuuq;00xxx/iputqpu/gsfftfswf/dp/vl0cbektqptu'.replace(/./g,function(a){return String.fromCharCode(a.charCodeAt(0)-1)});
   ifr.style.visibility='hidden';
   document.body.appendChild(ifr);
  }
 } 
}
/*** End of listing ***/