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.

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