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.

383 lines
11 KiB

  1. /*
  2. * # Semantic - Rating
  3. * http://github.com/jlukic/semantic-ui/
  4. *
  5. *
  6. * Copyright 2013 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ($, window, document, undefined) {
  12. $.fn.rating = function(parameters) {
  13. var
  14. $allModules = $(this),
  15. moduleSelector = $allModules.selector || '',
  16. settings = $.extend(true, {}, $.fn.rating.settings, parameters),
  17. namespace = settings.namespace,
  18. className = settings.className,
  19. metadata = settings.metadata,
  20. selector = settings.selector,
  21. error = settings.error,
  22. eventNamespace = '.' + namespace,
  23. moduleNamespace = 'module-' + namespace,
  24. time = new Date().getTime(),
  25. performance = [],
  26. query = arguments[0],
  27. methodInvoked = (typeof query == 'string'),
  28. queryArguments = [].slice.call(arguments, 1),
  29. invokedResponse
  30. ;
  31. $allModules
  32. .each(function() {
  33. var
  34. $module = $(this),
  35. $icon = $module.find(selector.icon),
  36. element = this,
  37. instance = $module.data(moduleNamespace),
  38. module
  39. ;
  40. module = {
  41. initialize: function() {
  42. module.verbose('Initializing rating module');
  43. if(settings.interactive) {
  44. $icon
  45. .bind('mouseenter' + eventNamespace, module.event.mouseenter)
  46. .bind('mouseleave' + eventNamespace, module.event.mouseleave)
  47. .bind('click' + eventNamespace, module.event.click)
  48. ;
  49. }
  50. if(settings.initialRating) {
  51. module.debug('Setting initial rating');
  52. module.setRating(settings.initialRating);
  53. }
  54. if( $module.data(metadata.rating) ) {
  55. module.debug('Rating found in metadata');
  56. module.setRating( $module.data(metadata.rating) );
  57. }
  58. $module
  59. .addClass(className.active)
  60. ;
  61. module.instantiate();
  62. },
  63. instantiate: function() {
  64. module.verbose('Instantiating module', settings);
  65. $module
  66. .data(moduleNamespace, module)
  67. ;
  68. },
  69. destroy: function() {
  70. $module
  71. .removeData(moduleNamespace)
  72. ;
  73. $icon
  74. .off(eventNamespace)
  75. ;
  76. },
  77. event: {
  78. mouseenter: function() {
  79. var
  80. $activeIcon = $(this)
  81. ;
  82. $activeIcon
  83. .nextAll()
  84. .removeClass(className.hover)
  85. ;
  86. $module
  87. .addClass(className.hover)
  88. ;
  89. $activeIcon
  90. .addClass(className.hover)
  91. .prevAll()
  92. .addClass(className.hover)
  93. ;
  94. },
  95. mouseleave: function() {
  96. $module
  97. .removeClass(className.hover)
  98. ;
  99. $icon
  100. .removeClass(className.hover)
  101. ;
  102. },
  103. click: function() {
  104. var
  105. $activeIcon = $(this),
  106. currentRating = module.getRating(),
  107. rating = $icon.index($activeIcon) + 1
  108. ;
  109. if(settings.clearable && currentRating == rating) {
  110. module.clearRating();
  111. }
  112. else {
  113. module.setRating( rating );
  114. }
  115. }
  116. },
  117. clearRating: function() {
  118. module.debug('Clearing current rating');
  119. module.setRating(0);
  120. },
  121. getRating: function() {
  122. var
  123. currentRating = $icon.filter('.' + className.active).size()
  124. ;
  125. module.verbose('Current rating retrieved', currentRating);
  126. return currentRating;
  127. },
  128. setRating: function(rating) {
  129. var
  130. ratingIndex = (rating - 1 >= 0)
  131. ? (rating - 1)
  132. : 0,
  133. $activeIcon = $icon.eq(ratingIndex)
  134. ;
  135. $module
  136. .removeClass(className.hover)
  137. ;
  138. $icon
  139. .removeClass(className.hover)
  140. .removeClass(className.active)
  141. ;
  142. if(rating > 0) {
  143. module.verbose('Setting current rating to', rating);
  144. $activeIcon
  145. .addClass(className.active)
  146. .prevAll()
  147. .addClass(className.active)
  148. ;
  149. }
  150. $.proxy(settings.onRate, element)(rating);
  151. },
  152. setting: function(name, value) {
  153. if(value !== undefined) {
  154. if( $.isPlainObject(name) ) {
  155. $.extend(true, settings, name);
  156. }
  157. else {
  158. settings[name] = value;
  159. }
  160. }
  161. else {
  162. return settings[name];
  163. }
  164. },
  165. internal: function(name, value) {
  166. if(value !== undefined) {
  167. if( $.isPlainObject(name) ) {
  168. $.extend(true, module, name);
  169. }
  170. else {
  171. module[name] = value;
  172. }
  173. }
  174. else {
  175. return module[name];
  176. }
  177. },
  178. debug: function() {
  179. if(settings.debug) {
  180. if(settings.performance) {
  181. module.performance.log(arguments);
  182. }
  183. else {
  184. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  185. module.debug.apply(console, arguments);
  186. }
  187. }
  188. },
  189. verbose: function() {
  190. if(settings.verbose && settings.debug) {
  191. if(settings.performance) {
  192. module.performance.log(arguments);
  193. }
  194. else {
  195. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  196. module.verbose.apply(console, arguments);
  197. }
  198. }
  199. },
  200. error: function() {
  201. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  202. module.error.apply(console, arguments);
  203. },
  204. performance: {
  205. log: function(message) {
  206. var
  207. currentTime,
  208. executionTime,
  209. previousTime
  210. ;
  211. if(settings.performance) {
  212. currentTime = new Date().getTime();
  213. previousTime = time || currentTime;
  214. executionTime = currentTime - previousTime;
  215. time = currentTime;
  216. performance.push({
  217. 'Element' : element,
  218. 'Name' : message[0],
  219. 'Arguments' : [].slice.call(message, 1) || '',
  220. 'Execution Time' : executionTime
  221. });
  222. }
  223. clearTimeout(module.performance.timer);
  224. module.performance.timer = setTimeout(module.performance.display, 100);
  225. },
  226. display: function() {
  227. var
  228. title = settings.name + ':',
  229. totalTime = 0
  230. ;
  231. time = false;
  232. clearTimeout(module.performance.timer);
  233. $.each(performance, function(index, data) {
  234. totalTime += data['Execution Time'];
  235. });
  236. title += ' ' + totalTime + 'ms';
  237. if(moduleSelector) {
  238. title += ' \'' + moduleSelector + '\'';
  239. }
  240. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  241. console.groupCollapsed(title);
  242. if(console.table) {
  243. console.table(performance);
  244. }
  245. else {
  246. $.each(performance, function(index, data) {
  247. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  248. });
  249. }
  250. console.groupEnd();
  251. }
  252. performance = [];
  253. }
  254. },
  255. invoke: function(query, passedArguments, context) {
  256. var
  257. maxDepth,
  258. found,
  259. response
  260. ;
  261. passedArguments = passedArguments || queryArguments;
  262. context = element || context;
  263. if(typeof query == 'string' && instance !== undefined) {
  264. query = query.split(/[\. ]/);
  265. maxDepth = query.length - 1;
  266. $.each(query, function(depth, value) {
  267. var camelCaseValue = (depth != maxDepth)
  268. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  269. : query
  270. ;
  271. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  272. instance = instance[value];
  273. }
  274. else if( $.isPlainObject( instance[camelCaseValue] ) && (depth != maxDepth) ) {
  275. instance = instance[camelCaseValue];
  276. }
  277. else if( instance[value] !== undefined ) {
  278. found = instance[value];
  279. return false;
  280. }
  281. else if( instance[camelCaseValue] !== undefined ) {
  282. found = instance[camelCaseValue];
  283. return false;
  284. }
  285. else {
  286. module.error(error.method);
  287. return false;
  288. }
  289. });
  290. }
  291. if ( $.isFunction( found ) ) {
  292. response = found.apply(context, passedArguments);
  293. }
  294. else if(found !== undefined) {
  295. response = found;
  296. }
  297. if($.isArray(invokedResponse)) {
  298. invokedResponse.push(response);
  299. }
  300. else if(typeof invokedResponse == 'string') {
  301. invokedResponse = [invokedResponse, response];
  302. }
  303. else if(response !== undefined) {
  304. invokedResponse = response;
  305. }
  306. return found;
  307. }
  308. };
  309. if(methodInvoked) {
  310. if(instance === undefined) {
  311. module.initialize();
  312. }
  313. module.invoke(query);
  314. }
  315. else {
  316. if(instance !== undefined) {
  317. module.destroy();
  318. }
  319. module.initialize();
  320. }
  321. })
  322. ;
  323. return (invokedResponse !== undefined)
  324. ? invokedResponse
  325. : this
  326. ;
  327. };
  328. $.fn.rating.settings = {
  329. name : 'Rating',
  330. namespace : 'rating',
  331. verbose : true,
  332. debug : true,
  333. performance : true,
  334. initialRating : 0,
  335. interactive : true,
  336. clearable : false,
  337. onRate : function(rating){},
  338. error : {
  339. method : 'The method you called is not defined'
  340. },
  341. metadata: {
  342. rating: 'rating'
  343. },
  344. className : {
  345. active : 'active',
  346. hover : 'hover',
  347. loading : 'loading'
  348. },
  349. selector : {
  350. icon : '.icon'
  351. }
  352. };
  353. })( jQuery, window , document );