PageSourceSearch

https://www.euroforum.nl/static/assets/js/jquery.raty.js

js euroforum.nl collected 2026-09-30 14:40:16 UTC 19,914 bytes, 770 lines download raw bytes

1/*!
2 * Raty - A Star Rating Plugin
3 *
4 * The MIT License
5 *
6 * author:  Washington Botelho
7 * github:  wbotelhos/raty
8 * version: 3.0.0
9 *
10 */
11
12(function(root, factory) {
13  if (typeof define === 'function' && define.amd) {
14    define(['jquery'], factory);
15  } else if (typeof module === 'object' && module.exports) {
16    module.exports = factory(require('jquery'));
17  } else {
18    factory(root.jQuery);
19  }
20}(this, function($) {
21  'use strict';
22
23  $.raty = {
24    cancelButton: false,
25    cancelClass:  'raty-cancel',
26    cancelHint:   'Cancel this rating!',
27    cancelOff:    'cancel-off.png',
28    cancelOn:     'cancel-on.png',
29    cancelPlace:  'left',
30    click:        undefined,
31    half:         false,
32    halfShow:     true,
33    hints:        ['bad', 'poor', 'regular', 'good', 'gorgeous'],
34    iconRange:    undefined,
35    mouseout:     undefined,
36    mouseover:    undefined,
37    noRatedMsg:   'Not rated yet!',
38    number:       5,
39    numberMax:    20,
40    path:         undefined,
41    precision:    false,
42    readOnly:     false,
43    round:        { down: 0.25, full: 0.6, up: 0.76 },
44    score:        undefined,
45    scoreName:    'score',
46    single:       false,
47    space:        true,
48    starHalf:     'star-half.png',
49    starOff:      'star-off.png',
50    starOn:       'star-on.png',
51    starType:     'img',
52    target:       undefined,
53    targetFormat: '{score}',
54    targetKeep:   false,
55    targetScore:  undefined,
56    targetText:   '',
57    targetType:   'hint'
58  };
59
60  $.fn.raty = function(options) {
61    return this.each(function() {
62      var instance = new $.raty.Raty(this, options);
63
64      return instance._create();
65    });
66  };
67
68  $.raty.Raty = (function() {
69    var Raty = function(element, options) {
70      this.element = element;
71      this.self    = $(element);
72      this.opt     = $.extend(true, {}, $.raty, options, this.self.data());
73    };
74
75    Raty.prototype = {
76      _create: function() {
77        this._executeCallbacks();
78        this._adjustNumber();
79        this._adjustHints();
80
81        this.opt.score = this._adjustedScore(this.opt.score);
82
83        if (this.opt.starType !== 'img') {
84          this._adjustStarName();
85        }
86
87        this._setPath();
88        this._createStars();
89
90        if (this.opt.cancelButton) {
91          this._createCancel();
92        }
93
94        if (this.opt.precision) {
95          this._adjustPrecision();
96        }
97
98        this._createScore();
99
100        this._apply(this.opt.score);
101        this._setTitle(this.opt.score);
102        this._target(this.opt.score);
103
104        if (this.opt.readOnly) {
105          this._lock();
106        } else {
107          this.element.style.cursor = 'pointer';
108
109          this._binds();
110        }
111
112        this.self.data('raty', this);
113      },
114
115      // TODO: model spec
116      _adjustedScore: function(score) {
117        if (score || score === 0) {
118          return this._between(score, 0, this.opt.number);
119        }
120      },
121
122      _adjustHints: function() {
123        if (!this.opt.hints) {
124          this.opt.hints = [];
125        }
126
127        if (!this.opt.halfShow && !this.opt.half) {
128          return;
129        }
130
131        var steps = this.opt.precision ? 10 : 2;
132
133        for (var i = 0; i < this.opt.number; i++) {
134          var group = this.opt.hints[i];
135
136          if (Object.prototype.toString.call(group) !== '[object Array]') {
137            group = [group];
138          }
139
140          this.opt.hints[i] = [];
141
142          for (var j = 0; j < steps; j++) {
143            var hint = group[j];
144            var last = group[group.length - 1];
145
146            if (last === undefined) {
147              last = null;
148            }
149
150            this.opt.hints[i][j] = hint === undefined ? last : hint;
151          }
152        }
153      },
154
155      _adjustNumber: function() {
156        this.opt.number = this._between(this.opt.number, 1, this.opt.numberMax);
157      },
158
159      _adjustPrecision: function() {
160        this.opt.half = true;
161      },
162
163      _adjustStarName: function() {
164        var replaces = ['cancelOff', 'cancelOn', 'starHalf', 'starOff', 'starOn'];
165
166        this.opt.path = '';
167
168        for (var i = 0; i < replaces.length; i++) {
169          this.opt[replaces[i]] = this.opt[replaces[i]].replace('.', '-');
170        }
171      },
172
173      // TODO: model spec
174      _apply: function(score) {
175        this._fill(score);
176
177        if (score) {
178          if (score > 0) {
179            this.scoreField.val(score);
180          }
181
182          this._roundStars(score);
183        }
184      },
185
186      _attributesForIndex: function(i) {
187        var name       = this._nameForIndex(i);
188        var attributes = { alt: i, src: this.opt.path + this.opt[name] };
189
190        if (this.opt.starType !== 'img') {
191          attributes = { 'data-alt': i, 'class': this.opt[name] };
192        }
193
194        attributes.title = this._getHint(i);
195
196        return attributes;
197      },
198
199      _between: function(value, min, max) {
200        return Math.min(Math.max(parseFloat(value), min), max);
201      },
202
203      // TODO: model spec
204      _binds: function() {
205        if (this.cancelButton) {
206          this._bindOverCancel();
207          this._bindClickCancel();
208          this._bindOutCancel();
209        }
210
211        this._bindOver();
212        this._bindClick();
213        this._bindOut();
214      },
215
216      // TODO: model spec
217      _bindClick: function() {
218        var that = this;
219
220        this.stars.on('click.raty', function(evt) {
221          if (that.self.data('readonly')) {
222            return;
223          }
224
225          var execute = true;
226          var score   = (that.opt.half || that.opt.precision) ? that.self.data('score') : (this.alt || $(this).data('alt'));
227
228          if (that.opt.half && !that.opt.precision) {
229            score = that._roundHalfScore(score);
230          }
231
232          if (that.opt.click) {
233            execute = that.opt.click.call(that.element, +score, evt);
234          }
235
236          if (execute || execute === undefined) {
237            that._apply(+score);
238          }
239        });
240      },
241
242      // TODO: model spec
243      _bindClickCancel: function() {
244        this.cancelButton.on('click.raty', function(evt) {
245          this.scoreField.removeAttr('value');
246
247          if (this.opt.click) {
248            this.opt.click.call(this.element, null, evt);
249          }
250        }.bind(this));
251      },
252
253      // TODO: model spec
254      _bindOut: function() {
255        this.self.on('mouseleave.raty', function(evt) {
256          var score = +this.scoreField.val() || undefined;
257
258          this._apply(score);
259          this._target(score, evt);
260          this._resetTitle();
261
262          if (this.opt.mouseout) {
263            this.opt.mouseout.call(this.element, score, evt);
264          }
265        }.bind(this));
266      },
267
268      // TODO: model spec
269      _bindOutCancel: function() {
270        var that = this;
271
272        this.cancelButton.on('mouseleave.raty', function(evt) {
273          var icon = that.opt.cancelOff;
274
275          if (that.opt.starType !== 'img') {
276            icon = that.opt.cancelClass + ' ' + icon;
277          }
278
279          that._setIcon(this, icon);
280
281          if (that.opt.mouseout) {
282            var score = +that.scoreField.val() || undefined;
283
284            that.opt.mouseout.call(that.element, score, evt);
285          }
286        });
287      },
288
289      // TODO: model spec
290      _bindOver: function() {
291        var that   = this;
292        var action = that.opt.half ? 'mousemove.raty' : 'mouseover.raty';
293
294        this.stars.on(action, function(evt) {
295          var score = that._getScoreByPosition(evt, this);
296
297          that._fill(score);
298
299          if (that.opt.half) {
300            that._roundStars(score, evt);
301            that._setTitle(score, evt);
302
303            that.self.data('score', score);
304          }
305
306          that._target(score, evt);
307
308          if (that.opt.mouseover) {
309            that.opt.mouseover.call(that.element, score, evt);
310          }
311        });
312      },
313
314      // TODO: model spec
315      _bindOverCancel: function() {
316        var that = this;
317
318        this.cancelButton.on('mouseover.raty', function(evt) {
319          if (that.self.data('readonly')) {
320            return;
321          }
322
323          var starOff = that.opt.path + that.opt.starOff;
324          var icon    = that.opt.cancelOn;
325
326          if (that.opt.starType === 'img') {
327            that.stars.attr('src', starOff);
328          } else {
329            icon = that.opt.cancelClass + ' ' + icon;
330
331            that.stars.attr('class', starOff);
332          }
333
334          that._setIcon(this, icon);
335          that._target(null, evt);
336
337          if (that.opt.mouseover) {
338            that.opt.mouseover.call(that.element, null);
339          }
340        });
341      },
342
343      // TODO: model spec
344      _buildScoreField: function() {
345        return $('<input />', { name: this.opt.scoreName, type: 'hidden' }).appendTo(this.self);
346      },
347
348      // TODO: model spec
349      _createCancel: function() {
350        var icon   = this.opt.path + this.opt.cancelOff;
351        var button = $('<' + this.opt.starType + ' />', { title: this.opt.cancelHint, 'class': this.opt.cancelClass });
352
353        if (this.opt.starType === 'img') {
354          button.attr({ src: icon, alt: 'x' });
355        } else {
356          // TODO: use $.data
357          button.attr('data-alt', 'x').addClass(icon);
358        }
359
360        if (this.opt.cancelPlace === 'left') {
361          this.self.prepend('&#160;').prepend(button);
362        } else {
363          this.self.append('&#160;').append(button);
364        }
365
366        this.cancelButton = button;
367      },
368
369      // TODO: model spec
370      _createScore: function() {
371        var score = $(this.opt.targetScore);
372
373        this.scoreField = score.length ? score : this._buildScoreField();
374      },
375
376      _createStars: function() {
377        for (var i = 1; i <= this.opt.number; i++) {
378          var attributes = this._attributesForIndex(i);
379
380          $('<' + this.opt.starType + ' />', attributes).appendTo(this.element);
381
382          if (this.opt.space && i < this.opt.number) {
383            this.self.append('&#160;');
384          }
385        }
386
387        this.stars = this.self.children(this.opt.starType);
388      },
389
390      // TODO: model spec
391      _error: function(message) {
392        $(this).text(message);
393
394        $.error(message);
395      },
396
397      _executeCallbacks: function() {
398        var options = ['number', 'readOnly', 'score', 'scoreName', 'target', 'path'];
399
400        for (var i = 0; i < options.length; i++) {
401          if (typeof this.opt[options[i]] === 'function') {
402            var value = this.opt[options[i]].call(this.element);
403
404            if (value) {
405              this.opt[options[i]] = value;
406            } else {
407              delete this.opt[options[i]];
408            }
409          }
410        }
411      },
412
413      // TODO: model spec
414      _fill: function(score) {
415        var hash = 0;
416
417        for (var i = 1; i <= this.stars.length; i++) {
418          var icon;
419          var star   = this.stars[i - 1];
420          var turnOn = this._turnOn(i, score);
421
422          if (this.opt.iconRange && this.opt.iconRange.length > hash) {
423            var irange = this.opt.iconRange[hash];
424
425            icon = this._getRangeIcon(irange, turnOn);
426
427            if (i <= irange.range) {
428              this._setIcon(star, icon);
429            }
430
431            if (i === irange.range) {
432              hash++;
433            }
434          } else {
435            icon = this.opt[turnOn ? 'starOn' : 'starOff'];
436
437            this._setIcon(star, icon);
438          }
439        }
440      },
441
442      _getDecimal: function(number, fractions) {
443        var decimal = number.toString().split('.')[1];
444        var result  = 0;
445
446        if (decimal) {
447          result = parseInt(decimal.slice(0, fractions), 10);
448
449          if (decimal.slice(1, 5) === '9999') {
450            result++;
451          }
452        }
453
454        return result;
455      },
456
457      // TODO: model spec
458      _getRangeIcon: function(irange, turnOn) {
459        return turnOn ? irange.on || this.opt.starOn : irange.off || this.opt.starOff;
460      },
461
462      // TODO: model spec
463      _getScoreByPosition: function(evt, icon) {
464        var score = parseInt(icon.alt || icon.getAttribute('data-alt'), 10);
465
466        if (this.opt.half) {
467          var size    = this._getWidth();
468          var percent = parseFloat((evt.pageX - $(icon).offset().left) / size);
469
470          score = score - 1 + percent;
471        }
472
473        return score;
474      },
475
476      // TODO: model spec
477      _getHint: function(score, evt) {
478        if (score !== 0 && !score) {
479          return this.opt.noRatedMsg;
480        }
481
482        var decimal = this._getDecimal(score, 1);
483        var integer = Math.ceil(score);
484        var group   = this.opt.hints[(integer || 1) - 1];
485        var hint    = group;
486        var set     = !evt || this.isMove;
487
488        if (this.opt.precision) {
489          if (set) {
490            decimal = decimal === 0 ? 9 : decimal - 1;
491          }
492
493          hint = group[decimal];
494        } else if (this.opt.halfShow || this.opt.half) {
495          decimal = set && decimal === 0 ? 1 : decimal > 5 ? 1 : 0;
496
497          hint = group[decimal];
498        }
499
500        return hint === '' ? '' : hint || score;
501      },
502
503      // TODO: model spec
504      _getWidth: function() {
505        var width = this.stars[0].width || parseFloat(this.stars.eq(0).css('font-size'));
506
507        if (!width) {
508          this._error('Could not get the icon width!');
509        }
510
511        return width;
512      },
513
514      // TODO: model spec
515      _lock: function() {
516        var hint = this._getHint(this.scoreField.val());
517
518        this.element.style.cursor = '';
519        this.element.title        = hint;
520
521        this.scoreField.prop('readonly', true);
522        this.stars.prop('title', hint);
523
524        if (this.cancelButton) {
525          this.cancelButton.hide();
526        }
527
528        this.self.data('readonly', true);
529      },
530
531      _nameForIndex: function(i) {
532        return this.opt.score && this.opt.score >= i ? 'starOn' : 'starOff';
533      },
534
535      // TODO: model spec
536      _resetTitle: function() {
537        for (var i = 0; i < this.opt.number; i++) {
538          this.stars[i].title = this._getHint(i + 1);
539        }
540      },
541
542      // TODO: model spec
543      _roundHalfScore: function(score) {
544        var integer = parseInt(score, 10);
545        var decimal = this._getDecimal(score, 1);
546
547        if (decimal !== 0) {
548          decimal = decimal > 5 ? 1 : 0.5;
549        }
550
551        return integer + decimal;
552      },
553
554      // TODO: model spec
555      _roundStars: function(score, evt) {
556        var name = this._starName(score, evt);
557
558        if (name) {
559          var icon = this.opt[name];
560          var star = this.stars[Math.ceil(score) - 1];
561
562          this._setIcon(star, icon);
563        } // Full down: [x.00 .. x.25]
564      },
565
566      // TODO: model spec
567      _setIcon: function(star, icon) {
568        star[this.opt.starType === 'img' ? 'src' : 'className'] = this.opt.path + icon;
569      },
570
571      _setPath: function() {
572        this.opt.path = this.opt.path || '';
573
574        if (this.opt.path && this.opt.path.slice(-1)[0] !== '/') {
575          this.opt.path += '/';
576        }
577      },
578
579      // TODO: model spec
580      _setTarget: function(target, score) {
581        if (score) {
582          score = this.opt.targetFormat.toString().replace('{score}', score);
583        }
584
585        if (target.is(':input')) {
586          target.val(score);
587        } else {
588          target.html(score);
589        }
590      },
591
592      // TODO: model spec
593      _setTitle: function(score, evt) {
594        if (score) {
595          var integer = parseInt(Math.ceil(score), 10);
596          var star    = this.stars[integer - 1];
597
598          star.title = this._getHint(score, evt);
599        }
600      },
601
602      _starName: function(score, evt) {
603        var decimal = +(score % 1).toFixed(2);
604
605        if (evt || this.isMove) {
606          return decimal > 0.5 ? 'starOn' : 'starHalf';
607        }
608
609        if (decimal <= this.opt.round.down) { // Down: [x.00 ... x.25]
610          return;
611        }
612
613        if (this.opt.halfShow && decimal < this.opt.round.up) { // Half: [x.26 ... x.75]
614          return 'starHalf';
615        }
616
617        if (decimal < this.opt.round.full) { // Off: [x.26 .. x.6]
618          return 'starOff';
619        }
620
621        return 'starOn'; // Up: [x.26 ...] || [x.6 ...]
622      },
623
624      // TODO: model spec
625      _target: function(score, evt) {
626        if (this.opt.target) {
627          var target = $(this.opt.target);
628
629          if (!target.length) {
630            this._error('Target selector invalid or missing!');
631          }
632
633          var mouseover = evt && evt.type === 'mouseover';
634
635          if (score === undefined) {
636            score = this.opt.targetText;
637          } else if (score === null) {
638            score = mouseover ? this.opt.cancelHint : this.opt.targetText;
639          } else {
640            if (this.opt.targetType === 'hint') {
641              score = this._getHint(score, evt);
642            } else if (this.opt.precision) {
643              score = parseFloat(score).toFixed(1);
644            }
645
646            var mousemove = evt && evt.type === 'mousemove';
647
648            if (!mouseover && !mousemove && !this.opt.targetKeep) {
649              score = this.opt.targetText;
650            }
651          }
652
653          this._setTarget(target, score);
654        }
655      },
656
657      // TODO: model spec
658      _turnOn: function(i, score) {
659        return this.opt.single ? (i === score) : (i <= score);
660      },
661
662      // TODO: model spec
663      _unlock: function() {
664        this.element.style.cursor = 'pointer';
665        this.element.removeAttribute('title');
666
667        this.scoreField.removeAttr('readonly');
668
669        this.self.data('readonly', false);
670
671        this._resetTitle();
672
673        if (this.cancelButton) {
674          this.cancelButton.css('display', '');
675        }
676      },
677
678      // TODO: model spec
679      cancel: function(click) {
680        if (this.self.data('readonly') !== true) {
681          this[click ? 'click' : 'score'].call(this, null);
682
683          this.scoreField.removeAttr('value');
684        }
685      },
686
687      // TODO: model spec
688      click: function(score) {
689        if (this.self.data('readonly') !== true) {
690          score = this._adjustedScore(score);
691
692          this._apply(score);
693
694          if (this.opt.click) {
695            this.opt.click.call(this.element, score, $.Event('click'));
696          }
697
698          this._target(score);
699        }
700      },
701
702      // TODO: model spec
703      getScore: function() {
704        var score = [];
705        var value ;
706
707        value = this.scoreField.val();
708
709        score.push(value ? +value : undefined);
710
711        return (score.length > 1) ? score : score[0];
712      },
713
714      // TODO: model spec
715      move: function(score) {
716        var integer  = parseInt(score, 10);
717        var decimal  = this._getDecimal(score, 1);
718
719        if (integer >= this.opt.number) {
720          integer = this.opt.number - 1;
721          decimal = 10;
722        }
723
724        var width   = this._getWidth();
725        var steps   = width / 10;
726        var star    = $(this.stars[integer]);
727        var percent = star.offset().left + steps * decimal;
728        var evt     = $.Event('mousemove', { pageX: percent });
729
730        this.isMove = true;
731
732        star.trigger(evt);
733
734        this.isMove = false;
735      },
736
737      // TODO: model spec
738      readOnly: function(readonly) {
739        if (this.self.data('readonly') !== readonly) {
740          if (readonly) {
741            this.self.off('.raty').children(this.opt.starType).off('.raty');
742
743            this._lock();
744          } else {
745            this._binds();
746            this._unlock();
747          }
748
749          this.self.data('readonly', readonly);
750        }
751      },
752
753      // TODO: model spec
754      score: function() {
755        return arguments.length ? this.setScore.apply(this, arguments) : this.getScore();
756      },
757
758      setScore: function(score) {
759        if (this.self.data('readonly') !== true) {
760          score = this._adjustedScore(score);
761
762          this._apply(score);
763          this._target(score);
764        }
765      }
766    };
767
768    return Raty;
769  })();
770}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.