rating.js 14 KB

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