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.

358 lines
10 KiB

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