Bfec5f7d1a4aaafc5a2451be8c42d26a

Here's the code of the rating system I built for this site.
Have any suggestions on how to improve it ?

Thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
var Rating = Class.create();
Rating.prototype = {
  initialize: function(element, rating, options) {
    this.element = $(element);
    this.rating  = rating;
    this.maxRating = 5;
    this.options = options || {};
    
    this.bindedOnHover = this.onHover.bindAsEventListener(this);
    this.bindedOnExit  = this.onExit.bindAsEventListener(this);
    this.bindedOnClick  = this.onClick.bindAsEventListener(this);
    
    Event.observe(this.element, 'mouseover', this.bindedOnHover);
    Event.observe(this.element, 'mouseout', this.bindedOnExit);
    Event.observe(this.element, 'click', this.bindedOnClick);
    
    this.instanciateStars();
    this.showStarts(this.rating);
  },
  
  instanciateStars: function() {
    this.maxRating.times(function() {
      var img = document.createElement('img');
      this.element.appendChild(img);
    }.bind(this));
  },
  
  showStarts: function(number) {
    var stars = this.getStars();

    $R(0, number-1).each (function(position) {
      stars[position].src = '/images/star_full.png';
    });
    $R(number, this.maxRating-1).each (function(position) {
      stars[position].src = '/images/star_empty.png';
    });
  },
  
  getStars: function() {
    return this.element.getElementsBySelector('img');
  },
  
  onHover: function(event) {
    var element = Event.element(event);
    if (element.tagName == 'IMG') {
      this.showStarts(this.findRatingFromEvent(element));
    }
  },
  
  onExit: function(event) {
    this.showStarts(this.rating);
  },
  
  onClick: function(event) {
    var element = Event.element(event);
    if (element.tagName == 'IMG' && this.options.onClick) {
      this.options.onClick.bind(this)(this.findRatingFromEvent(element));
    }
  },
  
  findRatingFromEvent: function(element) {
    var r = 0;
    this.getStars().each(function(star) {
      r ++;
      if (star == element) {
        throw $break;
      }
    });
    return r;
  },
  
  disable: function() {
    Event.stopObserving(this.element, 'mouseover', this.bindedOnHover);
    Event.stopObserving(this.element, 'mouseout', this.bindedOnExit);
    Event.stopObserving(this.element, 'click', this.bindedOnClick);
  }
};

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="rating">
  <span id="rating_97"></span>
  <img alt="Spinner" class="spinner" id="rating_97_spinner" src="spinner.gif" style="display:none" />
  <span id="rating_97_count" class="count">
    No rating. You haven't rated it!
  </span>
</div>
<script type="text/javascript">
  var rating_97 = new Rating('rating_97', 0, {
    onClick: function(rating) {
      $('rating_97_spinner').show();
      $('rating_97_count').hide();
      this.disable();
      new Ajax.Request('/codes/16-extracting-style-from-a-css-file/refactors/97;rate', {
        parameters: 'rating=' + rating,
        onComplete: function() {
          $('rating_97_spinner').hide();
          $('rating_97_count').show();
        }
      });
    }
  });
</script>

Refactorings

No refactoring yet !

90af68f4da3b83257223b871cef473ec

leighmac

September 30, 2007, September 30, 2007 08:09, permalink

1 rating. Login to rate!

I like your ratings class it's easy to understand :). I'm not good enough at javascript to improve your class. But you might improve your view with something like this.

Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var Rating = Class.create();
  // removed to make post more tidy
};

// Ratings helper for view
function rating_ui(id, rating, title) { 
  var rating = new Rating('rating_'+id, 0, {
    onClick: function(rating) {
      $('rating_'+id+'_spinner').show();
      $('rating_'+id+'_count').hide();
      this.disable();
      new Ajax.Request('/codes/'+title+'/refactors/'+id+';rate', {
        parameters: 'rating=' + rating,
        onComplete: function() {
          $('rating_'+id+'_spinner').hide();
          $('rating_'+id+'_count').show();
        }
      });
    }
  });  
}

View

1
2
3
4
5
6
7
8
9
10
11
<div class="rating">
  <span id="rating_97"></span>
  <img alt="Spinner" class="spinner" id="rating_97_spinner" src="spinner.gif" style="display:none" />
  <span id="rating_97_count" class="count">
    No rating. You haven't rated it!
  </span>
</div>
<script type="text/javascript">
  rating_ui(97, 0, '16-extracting-style-from-a-css-file')
</script>
Bfec5f7d1a4aaafc5a2451be8c42d26a

macournoyer

September 30, 2007, September 30, 2007 20:04, permalink

No rating. Login to rate!

Thanks leighmac good idea, I should abtract it a bit more and keep the logic out of the view!

90af68f4da3b83257223b871cef473ec

leighmac

September 30, 2007, September 30, 2007 23:05, permalink

No rating. Login to rate!

No worries :), The only things I could suggest to the next refactorer might be to break up the constructor a little bit more.. add a couple of constants for the strings and some sort of error handling.. if no one else posts I'll have a crack at that.

Javascript

1
2
// my codes did have an error. line 7 should read 
var rating = new Rating('rating_'+id, rating, {

Your refactoring





Format Copy from initial code

or Cancel