source: trunk/prototype/plugins/jq-raty/js/jquery.raty.js @ 6528

Revision 6528, 12.3 KB checked in by gustavo, 12 years ago (diff)

Ticket #2766 - Merge do branch das novas funcionalidaes para o trunk

  • Property svn:executable set to *
Line 
1/*!
2 * jQuery Raty - A Star Rating Plugin - http://wbotelhos.com/raty
3 * -------------------------------------------------------------------
4 *
5 * jQuery Raty is a plugin that generates a customizable star rating.
6 *
7 * Licensed under The MIT License
8 *
9 * @version        2.4.5
10 * @since          2010.06.11
11 * @author         Washington Botelho
12 * @documentation  wbotelhos.com/raty
13 * @twitter        twitter.com/wbotelhos
14 *
15 * Usage:
16 * -------------------------------------------------------------------
17 * $('#star').raty();
18 *
19 * <div id="star"></div>
20 *
21 */
22
23;(function($) {
24
25        var methods = {
26                init: function(settings) {
27                        return this.each(function() {
28                                var self        = this,
29                                        $this   = $(self).empty();
30       
31                                self.opt = $.extend(true, {}, $.fn.raty.defaults, settings);
32
33                                $this.data('settings', self.opt);
34
35                                self.opt.number = methods.between(self.opt.number, 0, 20);
36
37                                if (self.opt.path.substring(self.opt.path.length - 1, self.opt.path.length) != '/') {
38                                        self.opt.path += '/';
39                                }
40
41                                if (typeof self.opt.score == 'function') {
42                                        self.opt.score = self.opt.score.call(self);
43                                }
44
45                                if (self.opt.score) {
46                                        self.opt.score = methods.between(self.opt.score, 0, self.opt.number);                                   
47                                }
48
49                                for (var i = 1; i <= self.opt.number; i++) {
50                                        $('<img />', {
51                                                src             : self.opt.path + ((!self.opt.score || self.opt.score < i) ? self.opt.starOff : self.opt.starOn),
52                                                alt             : i,
53                                                title   : (i <= self.opt.hints.length && self.opt.hints[i - 1] !== null) ? self.opt.hints[i - 1] : i
54                                        }).appendTo(self);
55
56                                        if (self.opt.space) {
57                                                $this.append((i < self.opt.number) ? '&#160;' : '');
58                                        }
59                                }
60
61                                self.stars = $this.children('img:not(".raty-cancel")');
62                                self.score = $('<input />', { type: 'hidden', name: self.opt.scoreName }).appendTo(self);
63
64                                if (self.opt.score && self.opt.score > 0) {
65                                        self.score.val(self.opt.score);
66                                        methods.roundStar.call(self, self.opt.score);
67                                }
68
69                                if (self.opt.iconRange) {
70                                        methods.fill.call(self, self.opt.score);       
71                                }
72
73                                methods.setTarget.call(self, self.opt.score, self.opt.targetKeep);
74
75                                var space       = self.opt.space ? 4 : 0,
76                                        width   = self.opt.width || (self.opt.number * self.opt.size + self.opt.number * space);
77
78                                if (self.opt.cancel) {
79                                        self.cancel = $('<img />', { src: self.opt.path + self.opt.cancelOff, alt: 'x', title: self.opt.cancelHint, 'class': 'raty-cancel' });
80
81                                        if (self.opt.cancelPlace == 'left') {
82                                                $this.prepend('&#160;').prepend(self.cancel);
83                                        } else {
84                                                $this.append('&#160;').append(self.cancel);
85                                        }
86
87                                        width += (self.opt.size + space);
88                                }
89
90                                if (self.opt.readOnly) {
91                                        methods.fixHint.call(self);
92
93                                        if (self.cancel) {
94                                                self.cancel.hide();
95                                        }
96                                } else {
97                                        $this.css('cursor', 'pointer');
98
99                                        methods.bindAction.call(self);
100                                }
101
102                                $this.css('width', width);
103                        });
104                }, between: function(value, min, max) {
105                        return Math.min(Math.max(parseFloat(value), min), max);
106                }, bindAction: function() {
107                        var self        = this,
108                                $this   = $(self);
109
110                        $this.mouseleave(function() {
111                                var score = self.score.val() || undefined;
112
113                                methods.initialize.call(self, score);
114                                methods.setTarget.call(self, score, self.opt.targetKeep);
115
116                                if (self.opt.mouseover) {
117                                        self.opt.mouseover.call(self, score);
118                                }
119                        });
120
121                        var action = self.opt.half ? 'mousemove' : 'mouseover';
122
123                        if (self.opt.cancel) {
124                                self.cancel.mouseenter(function() {
125                                        $(this).attr('src', self.opt.path + self.opt.cancelOn);
126
127                                        self.stars.attr('src', self.opt.path + self.opt.starOff);
128
129                                        methods.setTarget.call(self, null, true);
130
131                                        if (self.opt.mouseover) {
132                                                self.opt.mouseover.call(self, null);
133                                        }
134                                }).mouseleave(function() {
135                                        $(this).attr('src', self.opt.path + self.opt.cancelOff);
136
137                                        if (self.opt.mouseover) {
138                                                self.opt.mouseover.call(self, self.score.val() || null);
139                                        }
140                                }).click(function(evt) {
141                                        self.score.removeAttr('value');
142
143                                        if (self.opt.click) {
144                                  self.opt.click.call(self, null, evt);
145                                }
146                                });
147                        }
148
149                        self.stars.bind(action, function(evt) {
150                                var value = parseInt(this.alt, 10);
151
152                                if (self.opt.half) {
153                                        var position    = parseFloat((evt.pageX - $(this).offset().left) / self.opt.size),
154                                                diff            = (position > .5) ? 1 : .5;
155
156                                        value = parseFloat(this.alt) - 1 + diff;
157
158                                        methods.fill.call(self, value);
159
160                                        if (self.opt.precision) {
161                                                value = value - diff + position;
162                                        }
163
164                                        methods.showHalf.call(self, value);
165                                } else {
166                                        methods.fill.call(self, value);
167                                }
168
169                                $this.data('score', value);
170
171                                methods.setTarget.call(self, value, true);
172
173                                if (self.opt.mouseover) {
174                                        self.opt.mouseover.call(self, value, evt);
175                                }
176                        }).click(function(evt) {
177                                self.score.val((self.opt.half || self.opt.precision) ? $this.data('score') : this.alt);
178
179                                if (self.opt.click) {
180                                        self.opt.click.call(self, self.score.val(), evt);
181                                }
182                        });
183                }, cancel: function(isClick) {
184                        return $(this).each(function() {
185                                var self        = this,
186                                        $this   = $(self);
187
188                                if ($this.data('readonly') === true) {
189                                        return this;
190                                }
191
192                                if (isClick) {
193                                        methods.click.call(self, null);
194                                } else {
195                                        methods.score.call(self, null);
196                                }
197
198                                self.score.removeAttr('value');
199                        });
200                }, click: function(score) {
201                        return $(this).each(function() {
202                                if ($(this).data('readonly') === true) {
203                                        return this;
204                                }
205
206                                methods.initialize.call(this, score);
207
208                                if (this.opt.click) {
209                                        this.opt.click.call(this, score);
210                                } else {
211                                        methods.error.call(this, 'you must add the "click: function(score, evt) { }" callback.');
212                                }
213
214                                methods.setTarget.call(this, score, true);
215                        });
216                }, error: function(message) {
217                        $(this).html(message);
218
219                        $.error(message);
220                }, fill: function(score) {
221                        var self        = this,
222                                number  = self.stars.length,
223                                count   = 0,
224                                $star   ,
225                                star    ,
226                                icon    ;
227
228                        for (var i = 1; i <= number; i++) {
229                                $star = self.stars.eq(i - 1);
230
231                                if (self.opt.iconRange && self.opt.iconRange.length > count) {
232                                        star = self.opt.iconRange[count];
233
234                                        if (self.opt.single) {
235                                                icon = (i == score) ? (star.on || self.opt.starOn) : (star.off || self.opt.starOff);
236                                        } else {
237                                                icon = (i <= score) ? (star.on || self.opt.starOn) : (star.off || self.opt.starOff);
238                                        }
239
240                                        if (i <= star.range) {
241                                                $star.attr('src', self.opt.path + icon);
242                                        }
243
244                                        if (i == star.range) {
245                                                count++;
246                                        }
247                                } else {
248                                        if (self.opt.single) {
249                                                icon = (i == score) ? self.opt.starOn : self.opt.starOff;
250                                        } else {
251                                                icon = (i <= score) ? self.opt.starOn : self.opt.starOff;
252                                        }
253
254                                        $star.attr('src', self.opt.path + icon);
255                                }
256                        }
257                }, fixHint: function() {
258                        var $this       = $(this),
259                                score   = parseInt(this.score.val(), 10),
260                                hint    = this.opt.noRatedMsg;
261
262                        if (!isNaN(score) && score > 0) {
263                                hint = (score <= this.opt.hints.length && this.opt.hints[score - 1] !== null) ? this.opt.hints[score - 1] : score;
264                        }
265
266                        $this.data('readonly', true).css('cursor', 'default').attr('title', hint);
267
268                        this.score.attr('readonly', 'readonly');
269                        this.stars.attr('title', hint);
270                }, getScore: function() {
271                        var score       = [],
272                                value   ;
273
274                        $(this).each(function() {
275                                value = this.score.val();
276
277                                score.push(value ? parseFloat(value) : undefined);
278                        });
279
280                        return (score.length > 1) ? score : score[0];
281                }, readOnly: function(isReadOnly) {
282                        return this.each(function() {
283                                var $this = $(this);
284
285                                if ($this.data('readonly') === isReadOnly) {
286                                        return this;
287                                }
288
289                                if (this.cancel) {
290                                        if (isReadOnly) {
291                                                this.cancel.hide();
292                                        } else {
293                                                this.cancel.show();
294                                        }
295                                }
296
297                                if (isReadOnly) {
298                                        $this.unbind();
299
300                                        $this.children('img').unbind();
301
302                                        methods.fixHint.call(this);
303                                } else {
304                                        methods.bindAction.call(this);
305                                        methods.unfixHint.call(this);
306                                }
307
308                                $this.data('readonly', isReadOnly);
309                        });
310                }, reload: function() {
311                        return methods.set.call(this, {});
312                }, roundStar: function(score) {
313                        var diff = (score - Math.floor(score)).toFixed(2);
314
315                        if (diff > this.opt.round.down) {
316                                var icon = this.opt.starOn;                                                             // Full up: [x.76 .. x.99]
317
318                                if (diff < this.opt.round.up && this.opt.halfShow) {    // Half: [x.26 .. x.75]
319                                        icon = this.opt.starHalf;
320                                } else if (diff < this.opt.round.full) {                                // Full down: [x.00 .. x.5]
321                                        icon = this.opt.starOff;
322                                }
323
324                                this.stars.eq(Math.ceil(score) - 1).attr('src', this.opt.path + icon);
325                        }                                                                                                                       // Full down: [x.00 .. x.25]
326                }, score: function() {
327                        return arguments.length ? methods.setScore.apply(this, arguments) : methods.getScore.call(this);
328                }, set: function(settings) {
329                        this.each(function() {
330                                var $this       = $(this),
331                                        actual  = $this.data('settings'),
332                                        clone   = $this.clone().removeAttr('style').insertBefore($this);
333
334                                $this.remove();
335
336                                clone.raty($.extend(actual, settings));
337                        });
338
339                        return $(this.selector);
340                }, setScore: function(score) {
341                        return $(this).each(function() {
342                                if ($(this).data('readonly') === true) {
343                                        return this;
344                                }
345
346                                methods.initialize.call(this, score);
347                                methods.setTarget.call(this, score, true);
348                        });
349                }, setTarget: function(value, isKeep) {
350                        if (this.opt.target) {
351                                var $target = $(this.opt.target);
352
353                                if ($target.length == 0) {
354                                        methods.error.call(this, 'target selector invalid or missing!');
355                                }
356
357                                var score = value;
358
359                                if (!isKeep || score === undefined) {
360                                        score = this.opt.targetText;
361                                } else {
362                                        if (this.opt.targetType == 'hint') {
363                                                score = (score === null && this.opt.cancel)
364                                                                ? this.opt.cancelHint
365                                                                : this.opt.hints[Math.ceil(score - 1)];
366                                        } else {
367                                                score = this.opt.precision
368                                                                ? parseFloat(score).toFixed(1)
369                                                                : parseInt(score, 10);
370                                        }
371                                }
372
373                                if (this.opt.targetFormat.indexOf('{score}') < 0) {
374                                        methods.error.call(this, 'template "{score}" missing!');
375                                }
376
377                                if (value !== null) {
378                                        score = this.opt.targetFormat.toString().replace('{score}', score);
379                                }
380
381                                if ($target.is(':input')) {
382                                        $target.val(score);
383                                } else {
384                                        $target.html(score);
385                                }
386                        }
387                }, showHalf: function(score) {
388                        var diff = (score - Math.floor(score)).toFixed(1);
389
390                        if (diff > 0 && diff < .6) {
391                                this.stars.eq(Math.ceil(score) - 1).attr('src', this.opt.path + this.opt.starHalf);
392                        }
393                }, initialize: function(score) {
394                        score = !score ? 0 : methods.between(score, 0, this.opt.number);
395
396                        methods.fill.call(this, score);
397
398                        if (score > 0) {
399                                if (this.opt.halfShow) {
400                                        methods.roundStar.call(this, score);
401                                }
402
403                                this.score.val(score);
404                        }
405                }, unfixHint: function() {
406                        for (var i = 0; i < this.opt.number; i++) {
407                                this.stars.eq(i).attr('title', (i < this.opt.hints.length && this.opt.hints[i] !== null) ? this.opt.hints[i] : i);
408                        }
409
410                        $(this).data('readonly', false).css('cursor', 'pointer').removeAttr('title');
411
412                        this.score.attr('readonly', 'readonly');
413                }
414        };
415
416        $.fn.raty = function(method) {
417                if (methods[method]) {
418                        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
419                } else if (typeof method === 'object' || !method) {
420                        return methods.init.apply(this, arguments);
421                } else {
422                        $.error('Method ' + method + ' does not exist!');
423                }
424        };
425
426        $.fn.raty.defaults = {
427                cancel                  : false,
428                cancelHint              : 'cancel this rating!',
429                cancelOff               : 'cancel-off.png',
430                cancelOn                : 'cancel-on.png',
431                cancelPlace             : 'left',
432                click                   : undefined,
433                half                    : false,
434                halfShow                : true,
435                hints                   : ['bad', 'poor', 'regular', 'good', 'gorgeous'],
436                iconRange               : undefined,
437                mouseover               : undefined,
438                noRatedMsg              : 'not rated yet',
439                number                  : 5,
440                path                    : 'img/',
441                precision               : false,
442                round                   : { down: .25, full: .6, up: .76 },
443                readOnly                : false,
444                score                   : undefined,
445                scoreName               : 'score',
446                single                  : false,
447                size                    : 16,
448                space                   : true,
449                starHalf                : 'star-half.png',
450                starOff                 : 'star-off.png',
451                starOn                  : 'star-on.png',
452                target                  : undefined,
453                targetFormat    : '{score}',
454                targetKeep              : false,
455                targetText              : '',
456                targetType              : 'hint',
457                width                   : undefined
458        };
459
460})(jQuery);
Note: See TracBrowser for help on using the repository browser.