You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

451 lines
12 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*
  2. * # Semantic - Rating
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributor
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ($, window, document, undefined) {
  12. "use strict";
  13. $.fn.rating = function(parameters) {
  14. var
  15. $allModules = $(this),
  16. moduleSelector = $allModules.selector || '',
  17. time = new Date().getTime(),
  18. performance = [],
  19. query = arguments[0],
  20. methodInvoked = (typeof query == 'string'),
  21. queryArguments = [].slice.call(arguments, 1),
  22. returnedValue
  23. ;
  24. $allModules
  25. .each(function() {
  26. var
  27. settings = ( $.isPlainObject(parameters) )
  28. ? $.extend(true, {}, $.fn.rating.settings, parameters)
  29. : $.extend({}, $.fn.rating.settings),
  30. namespace = settings.namespace,
  31. className = settings.className,
  32. metadata = settings.metadata,
  33. selector = settings.selector,
  34. error = settings.error,
  35. eventNamespace = '.' + namespace,
  36. moduleNamespace = 'module-' + namespace,
  37. element = this,
  38. instance = $(this).data(moduleNamespace),
  39. $module = $(this),
  40. $icon = $module.find(selector.icon),
  41. module
  42. ;
  43. module = {
  44. initialize: function() {
  45. module.verbose('Initializing rating module', settings);
  46. if($icon.length === 0) {
  47. module.setup.layout();
  48. }
  49. if(settings.interactive) {
  50. module.enable();
  51. }
  52. else {
  53. module.disable();
  54. }
  55. if(settings.initialRating) {
  56. module.debug('Setting initial rating');
  57. module.setRating(settings.initialRating);
  58. }
  59. if( $module.data(metadata.rating) ) {
  60. module.debug('Rating found in metadata');
  61. module.setRating( $module.data(metadata.rating) );
  62. }
  63. module.instantiate();
  64. },
  65. instantiate: function() {
  66. module.verbose('Instantiating module', settings);
  67. instance = module;
  68. $module
  69. .data(moduleNamespace, module)
  70. ;
  71. },
  72. destroy: function() {
  73. module.verbose('Destroying previous instance', instance);
  74. $module
  75. .removeData(moduleNamespace)
  76. ;
  77. $icon
  78. .off(eventNamespace)
  79. ;
  80. },
  81. refresh: function() {
  82. $icon = $module.find(selector.icon);
  83. },
  84. setup: {
  85. layout: function() {
  86. var
  87. maxRating = $module.data(metadata.maxRating) || settings.maxRating
  88. ;
  89. module.debug('Generating icon html dynamically');
  90. $module
  91. .html($.fn.rating.settings.templates.icon(maxRating))
  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.getRating(),
  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.setRating( rating );
  136. }
  137. }
  138. },
  139. clearRating: function() {
  140. module.debug('Clearing current rating');
  141. module.setRating(0);
  142. },
  143. getRating: function() {
  144. var
  145. currentRating = $icon.filter('.' + className.active).length
  146. ;
  147. module.verbose('Current rating retrieved', currentRating);
  148. return currentRating;
  149. },
  150. enable: function() {
  151. module.debug('Setting rating to interactive mode');
  152. $icon
  153. .on('mouseenter' + eventNamespace, module.event.mouseenter)
  154. .on('mouseleave' + eventNamespace, module.event.mouseleave)
  155. .on('click' + eventNamespace, module.event.click)
  156. ;
  157. $module
  158. .removeClass(className.disabled)
  159. ;
  160. },
  161. disable: function() {
  162. module.debug('Setting rating to read-only mode');
  163. $icon
  164. .off(eventNamespace)
  165. ;
  166. $module
  167. .addClass(className.disabled)
  168. ;
  169. },
  170. setRating: function(rating) {
  171. var
  172. ratingIndex = (rating - 1 >= 0)
  173. ? (rating - 1)
  174. : 0,
  175. $activeIcon = $icon.eq(ratingIndex)
  176. ;
  177. $module
  178. .removeClass(className.selected)
  179. ;
  180. $icon
  181. .removeClass(className.selected)
  182. .removeClass(className.active)
  183. ;
  184. if(rating > 0) {
  185. module.verbose('Setting current rating to', rating);
  186. $activeIcon
  187. .prevAll()
  188. .andSelf()
  189. .addClass(className.active)
  190. ;
  191. }
  192. settings.onRate.call(element, rating);
  193. },
  194. setting: function(name, value) {
  195. module.debug('Changing setting', name, value);
  196. if( $.isPlainObject(name) ) {
  197. $.extend(true, settings, name);
  198. }
  199. else if(value !== undefined) {
  200. settings[name] = value;
  201. }
  202. else {
  203. return settings[name];
  204. }
  205. },
  206. internal: function(name, value) {
  207. if( $.isPlainObject(name) ) {
  208. $.extend(true, module, name);
  209. }
  210. else if(value !== undefined) {
  211. module[name] = value;
  212. }
  213. else {
  214. return module[name];
  215. }
  216. },
  217. debug: function() {
  218. if(settings.debug) {
  219. if(settings.performance) {
  220. module.performance.log(arguments);
  221. }
  222. else {
  223. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  224. module.debug.apply(console, arguments);
  225. }
  226. }
  227. },
  228. verbose: function() {
  229. if(settings.verbose && settings.debug) {
  230. if(settings.performance) {
  231. module.performance.log(arguments);
  232. }
  233. else {
  234. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  235. module.verbose.apply(console, arguments);
  236. }
  237. }
  238. },
  239. error: function() {
  240. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  241. module.error.apply(console, arguments);
  242. },
  243. performance: {
  244. log: function(message) {
  245. var
  246. currentTime,
  247. executionTime,
  248. previousTime
  249. ;
  250. if(settings.performance) {
  251. currentTime = new Date().getTime();
  252. previousTime = time || currentTime;
  253. executionTime = currentTime - previousTime;
  254. time = currentTime;
  255. performance.push({
  256. 'Name' : message[0],
  257. 'Arguments' : [].slice.call(message, 1) || '',
  258. 'Element' : element,
  259. 'Execution Time' : executionTime
  260. });
  261. }
  262. clearTimeout(module.performance.timer);
  263. module.performance.timer = setTimeout(module.performance.display, 100);
  264. },
  265. display: function() {
  266. var
  267. title = settings.name + ':',
  268. totalTime = 0
  269. ;
  270. time = false;
  271. clearTimeout(module.performance.timer);
  272. $.each(performance, function(index, data) {
  273. totalTime += data['Execution Time'];
  274. });
  275. title += ' ' + totalTime + 'ms';
  276. if(moduleSelector) {
  277. title += ' \'' + moduleSelector + '\'';
  278. }
  279. if($allModules.length > 1) {
  280. title += ' ' + '(' + $allModules.length + ')';
  281. }
  282. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  283. console.groupCollapsed(title);
  284. if(console.table) {
  285. console.table(performance);
  286. }
  287. else {
  288. $.each(performance, function(index, data) {
  289. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  290. });
  291. }
  292. console.groupEnd();
  293. }
  294. performance = [];
  295. }
  296. },
  297. invoke: function(query, passedArguments, context) {
  298. var
  299. object = instance,
  300. maxDepth,
  301. found,
  302. response
  303. ;
  304. passedArguments = passedArguments || queryArguments;
  305. context = element || context;
  306. if(typeof query == 'string' && object !== undefined) {
  307. query = query.split(/[\. ]/);
  308. maxDepth = query.length - 1;
  309. $.each(query, function(depth, value) {
  310. var camelCaseValue = (depth != maxDepth)
  311. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  312. : query
  313. ;
  314. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  315. object = object[camelCaseValue];
  316. }
  317. else if( object[camelCaseValue] !== undefined ) {
  318. found = object[camelCaseValue];
  319. return false;
  320. }
  321. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  322. object = object[value];
  323. }
  324. else if( object[value] !== undefined ) {
  325. found = object[value];
  326. return false;
  327. }
  328. else {
  329. return false;
  330. }
  331. });
  332. }
  333. if ( $.isFunction( found ) ) {
  334. response = found.apply(context, passedArguments);
  335. }
  336. else if(found !== undefined) {
  337. response = found;
  338. }
  339. if($.isArray(returnedValue)) {
  340. returnedValue.push(response);
  341. }
  342. else if(returnedValue !== undefined) {
  343. returnedValue = [returnedValue, response];
  344. }
  345. else if(response !== undefined) {
  346. returnedValue = response;
  347. }
  348. return found;
  349. }
  350. };
  351. if(methodInvoked) {
  352. if(instance === undefined) {
  353. module.initialize();
  354. }
  355. module.invoke(query);
  356. }
  357. else {
  358. if(instance !== undefined) {
  359. instance.invoke('destroy');
  360. }
  361. module.initialize();
  362. }
  363. })
  364. ;
  365. return (returnedValue !== undefined)
  366. ? returnedValue
  367. : this
  368. ;
  369. };
  370. $.fn.rating.settings = {
  371. name : 'Rating',
  372. namespace : 'rating',
  373. debug : false,
  374. verbose : true,
  375. performance : true,
  376. initialRating : 0,
  377. interactive : true,
  378. maxRating : 4,
  379. clearable : 'auto',
  380. onRate : function(rating){},
  381. error : {
  382. method : 'The method you called is not defined',
  383. noMaximum : 'No maximum rating specified. Cannot generate HTML automatically'
  384. },
  385. metadata: {
  386. rating : 'rating',
  387. maxRating : 'maxRating'
  388. },
  389. className : {
  390. active : 'active',
  391. disabled : 'disabled',
  392. selected : 'selected',
  393. loading : 'loading'
  394. },
  395. selector : {
  396. icon : '.icon'
  397. },
  398. templates: {
  399. icon: function(maxRating) {
  400. var
  401. icon = 1,
  402. html = ''
  403. ;
  404. while(icon <= maxRating) {
  405. html += '<i class="icon"></i>';
  406. icon++;
  407. }
  408. return html;
  409. }
  410. }
  411. };
  412. })( jQuery, window , document );