UNPKG

14.9 kBJavaScriptView Raw
1/*!
2 * # Semantic UI 2.7.2 - Rating
3 * http://github.com/semantic-org/semantic-ui/
4 *
5 *
6 * Released under the MIT license
7 * http://opensource.org/licenses/MIT
8 *
9 */
10
11;(function ($, window, document, undefined) {
12
13'use strict';
14
15$.isFunction = $.isFunction || function(obj) {
16 return typeof obj === "function" && typeof obj.nodeType !== "number";
17};
18
19window = (typeof window != 'undefined' && window.Math == Math)
20 ? window
21 : (typeof self != 'undefined' && self.Math == Math)
22 ? self
23 : Function('return this')()
24;
25
26$.fn.rating = function(parameters) {
27 var
28 $allModules = $(this),
29 moduleSelector = $allModules.selector || '',
30
31 time = new Date().getTime(),
32 performance = [],
33
34 query = arguments[0],
35 methodInvoked = (typeof query == 'string'),
36 queryArguments = [].slice.call(arguments, 1),
37 returnedValue
38 ;
39 $allModules
40 .each(function() {
41 var
42 settings = ( $.isPlainObject(parameters) )
43 ? $.extend(true, {}, $.fn.rating.settings, parameters)
44 : $.extend({}, $.fn.rating.settings),
45
46 namespace = settings.namespace,
47 className = settings.className,
48 metadata = settings.metadata,
49 selector = settings.selector,
50
51 eventNamespace = '.' + namespace,
52 moduleNamespace = 'module-' + namespace,
53
54 element = this,
55 instance = $(this).data(moduleNamespace),
56
57 $module = $(this),
58 $icon = $module.find(selector.icon),
59
60 initialLoad,
61 module
62 ;
63
64 module = {
65
66 initialize: function() {
67 module.verbose('Initializing rating module', settings);
68
69 if($icon.length === 0) {
70 module.setup.layout();
71 }
72
73 if(settings.interactive && !module.is.disabled()) {
74 module.enable();
75 }
76 else {
77 module.disable();
78 }
79 module.set.initialLoad();
80 module.set.rating( module.get.initialRating() );
81 module.remove.initialLoad();
82 module.instantiate();
83 },
84
85 instantiate: function() {
86 module.verbose('Instantiating module', settings);
87 instance = module;
88 $module
89 .data(moduleNamespace, module)
90 ;
91 },
92
93 destroy: function() {
94 module.verbose('Destroying previous instance', instance);
95 module.remove.events();
96 $module
97 .removeData(moduleNamespace)
98 ;
99 },
100
101 refresh: function() {
102 $icon = $module.find(selector.icon);
103 },
104
105 setup: {
106 layout: function() {
107 var
108 maxRating = module.get.maxRating(),
109 icon = module.get.icon(),
110 html = $.fn.rating.settings.templates.icon(maxRating, icon)
111 ;
112 module.debug('Generating icon html dynamically');
113 $module
114 .html(html)
115 ;
116 module.refresh();
117 }
118 },
119
120 event: {
121 mouseenter: function() {
122 var
123 $activeIcon = $(this)
124 ;
125 $activeIcon
126 .nextAll()
127 .removeClass(className.selected)
128 ;
129 $module
130 .addClass(className.selected)
131 ;
132 $activeIcon
133 .addClass(className.selected)
134 .prevAll()
135 .addClass(className.selected)
136 ;
137 },
138 mouseleave: function() {
139 $module
140 .removeClass(className.selected)
141 ;
142 $icon
143 .removeClass(className.selected)
144 ;
145 },
146 click: function() {
147 var
148 $activeIcon = $(this),
149 currentRating = module.get.rating(),
150 rating = $icon.index($activeIcon) + 1,
151 canClear = (settings.clearable == 'auto')
152 ? ($icon.length === 1)
153 : settings.clearable
154 ;
155 if(canClear && currentRating == rating) {
156 module.clearRating();
157 }
158 else {
159 module.set.rating( rating );
160 }
161 }
162 },
163
164 clearRating: function() {
165 module.debug('Clearing current rating');
166 module.set.rating(0);
167 },
168
169 bind: {
170 events: function() {
171 module.verbose('Binding events');
172 $module
173 .on('mouseenter' + eventNamespace, selector.icon, module.event.mouseenter)
174 .on('mouseleave' + eventNamespace, selector.icon, module.event.mouseleave)
175 .on('click' + eventNamespace, selector.icon, module.event.click)
176 ;
177 }
178 },
179
180 remove: {
181 events: function() {
182 module.verbose('Removing events');
183 $module
184 .off(eventNamespace)
185 ;
186 },
187 initialLoad: function() {
188 initialLoad = false;
189 }
190 },
191
192 enable: function() {
193 module.debug('Setting rating to interactive mode');
194 module.bind.events();
195 $module
196 .removeClass(className.disabled)
197 ;
198 },
199
200 disable: function() {
201 module.debug('Setting rating to read-only mode');
202 module.remove.events();
203 $module
204 .addClass(className.disabled)
205 ;
206 },
207
208 is: {
209 initialLoad: function() {
210 return initialLoad;
211 },
212 disabled: function() {
213 return $module.hasClass(className.disabled);
214 }
215 },
216
217 get: {
218 icon: function(){
219 var icon = $module.data(metadata.icon);
220 if (icon) {
221 $module.removeData(metadata.icon);
222 }
223 return icon || settings.icon;
224 },
225 initialRating: function() {
226 if($module.data(metadata.rating) !== undefined) {
227 $module.removeData(metadata.rating);
228 return $module.data(metadata.rating);
229 }
230 return settings.initialRating;
231 },
232 maxRating: function() {
233 if($module.data(metadata.maxRating) !== undefined) {
234 $module.removeData(metadata.maxRating);
235 return $module.data(metadata.maxRating);
236 }
237 return settings.maxRating;
238 },
239 rating: function() {
240 var
241 currentRating = $icon.filter('.' + className.active).length
242 ;
243 module.verbose('Current rating retrieved', currentRating);
244 return currentRating;
245 }
246 },
247
248 set: {
249 rating: function(rating) {
250 var
251 ratingIndex = (rating - 1 >= 0)
252 ? (rating - 1)
253 : 0,
254 $activeIcon = $icon.eq(ratingIndex)
255 ;
256 $module
257 .removeClass(className.selected)
258 ;
259 $icon
260 .removeClass(className.selected)
261 .removeClass(className.active)
262 ;
263 if(rating > 0) {
264 module.verbose('Setting current rating to', rating);
265 $activeIcon
266 .prevAll()
267 .addBack()
268 .addClass(className.active)
269 ;
270 }
271 if(!module.is.initialLoad()) {
272 settings.onRate.call(element, rating);
273 }
274 },
275 initialLoad: function() {
276 initialLoad = true;
277 }
278 },
279
280 setting: function(name, value) {
281 module.debug('Changing setting', name, value);
282 if( $.isPlainObject(name) ) {
283 $.extend(true, settings, name);
284 }
285 else if(value !== undefined) {
286 if($.isPlainObject(settings[name])) {
287 $.extend(true, settings[name], value);
288 }
289 else {
290 settings[name] = value;
291 }
292 }
293 else {
294 return settings[name];
295 }
296 },
297 internal: function(name, value) {
298 if( $.isPlainObject(name) ) {
299 $.extend(true, module, name);
300 }
301 else if(value !== undefined) {
302 module[name] = value;
303 }
304 else {
305 return module[name];
306 }
307 },
308 debug: function() {
309 if(!settings.silent && settings.debug) {
310 if(settings.performance) {
311 module.performance.log(arguments);
312 }
313 else {
314 module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
315 module.debug.apply(console, arguments);
316 }
317 }
318 },
319 verbose: function() {
320 if(!settings.silent && settings.verbose && settings.debug) {
321 if(settings.performance) {
322 module.performance.log(arguments);
323 }
324 else {
325 module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
326 module.verbose.apply(console, arguments);
327 }
328 }
329 },
330 error: function() {
331 if(!settings.silent) {
332 module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
333 module.error.apply(console, arguments);
334 }
335 },
336 performance: {
337 log: function(message) {
338 var
339 currentTime,
340 executionTime,
341 previousTime
342 ;
343 if(settings.performance) {
344 currentTime = new Date().getTime();
345 previousTime = time || currentTime;
346 executionTime = currentTime - previousTime;
347 time = currentTime;
348 performance.push({
349 'Name' : message[0],
350 'Arguments' : [].slice.call(message, 1) || '',
351 'Element' : element,
352 'Execution Time' : executionTime
353 });
354 }
355 clearTimeout(module.performance.timer);
356 module.performance.timer = setTimeout(module.performance.display, 500);
357 },
358 display: function() {
359 var
360 title = settings.name + ':',
361 totalTime = 0
362 ;
363 time = false;
364 clearTimeout(module.performance.timer);
365 $.each(performance, function(index, data) {
366 totalTime += data['Execution Time'];
367 });
368 title += ' ' + totalTime + 'ms';
369 if(moduleSelector) {
370 title += ' \'' + moduleSelector + '\'';
371 }
372 if($allModules.length > 1) {
373 title += ' ' + '(' + $allModules.length + ')';
374 }
375 if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
376 console.groupCollapsed(title);
377 if(console.table) {
378 console.table(performance);
379 }
380 else {
381 $.each(performance, function(index, data) {
382 console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
383 });
384 }
385 console.groupEnd();
386 }
387 performance = [];
388 }
389 },
390 invoke: function(query, passedArguments, context) {
391 var
392 object = instance,
393 maxDepth,
394 found,
395 response
396 ;
397 passedArguments = passedArguments || queryArguments;
398 context = element || context;
399 if(typeof query == 'string' && object !== undefined) {
400 query = query.split(/[\. ]/);
401 maxDepth = query.length - 1;
402 $.each(query, function(depth, value) {
403 var camelCaseValue = (depth != maxDepth)
404 ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
405 : query
406 ;
407 if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
408 object = object[camelCaseValue];
409 }
410 else if( object[camelCaseValue] !== undefined ) {
411 found = object[camelCaseValue];
412 return false;
413 }
414 else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
415 object = object[value];
416 }
417 else if( object[value] !== undefined ) {
418 found = object[value];
419 return false;
420 }
421 else {
422 return false;
423 }
424 });
425 }
426 if ( $.isFunction( found ) ) {
427 response = found.apply(context, passedArguments);
428 }
429 else if(found !== undefined) {
430 response = found;
431 }
432 if(Array.isArray(returnedValue)) {
433 returnedValue.push(response);
434 }
435 else if(returnedValue !== undefined) {
436 returnedValue = [returnedValue, response];
437 }
438 else if(response !== undefined) {
439 returnedValue = response;
440 }
441 return found;
442 }
443 };
444 if(methodInvoked) {
445 if(instance === undefined) {
446 module.initialize();
447 }
448 module.invoke(query);
449 }
450 else {
451 if(instance !== undefined) {
452 instance.invoke('destroy');
453 }
454 module.initialize();
455 }
456 })
457 ;
458
459 return (returnedValue !== undefined)
460 ? returnedValue
461 : this
462 ;
463};
464
465$.fn.rating.settings = {
466
467 name : 'Rating',
468 namespace : 'rating',
469
470 icon : 'star',
471
472 silent : false,
473 debug : false,
474 verbose : false,
475 performance : true,
476
477 initialRating : 0,
478 interactive : true,
479 maxRating : 4,
480 clearable : 'auto',
481
482 fireOnInit : false,
483
484 onRate : function(rating){},
485
486 error : {
487 method : 'The method you called is not defined',
488 noMaximum : 'No maximum rating specified. Cannot generate HTML automatically'
489 },
490
491
492 metadata: {
493 rating : 'rating',
494 maxRating : 'maxRating',
495 icon : 'icon'
496 },
497
498 className : {
499 active : 'active',
500 disabled : 'disabled',
501 selected : 'selected',
502 loading : 'loading'
503 },
504
505 selector : {
506 icon : '.icon'
507 },
508
509 templates: {
510 icon: function(maxRating, iconClass) {
511 var
512 icon = 1,
513 html = ''
514 ;
515 while(icon <= maxRating) {
516 html += '<i class="'+iconClass+' icon"></i>';
517 icon++;
518 }
519 return html;
520 }
521 }
522
523};
524
525})( jQuery, window, document );