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.

463 lines
13 KiB

9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*!
  2. * # Semantic UI x.x - Rating
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2015 Contributors
  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.remove.events();
  75. $module
  76. .removeData(moduleNamespace)
  77. ;
  78. },
  79. refresh: function() {
  80. $icon = $module.find(selector.icon);
  81. },
  82. setup: {
  83. layout: function() {
  84. var
  85. maxRating = $module.data(metadata.maxRating) || settings.maxRating
  86. ;
  87. module.debug('Generating icon html dynamically');
  88. $module
  89. .html($.fn.rating.settings.templates.icon(maxRating))
  90. ;
  91. module.refresh();
  92. }
  93. },
  94. event: {
  95. mouseenter: function() {
  96. var
  97. $activeIcon = $(this)
  98. ;
  99. $activeIcon
  100. .nextAll()
  101. .removeClass(className.selected)
  102. ;
  103. $module
  104. .addClass(className.selected)
  105. ;
  106. $activeIcon
  107. .addClass(className.selected)
  108. .prevAll()
  109. .addClass(className.selected)
  110. ;
  111. },
  112. mouseleave: function() {
  113. $module
  114. .removeClass(className.selected)
  115. ;
  116. $icon
  117. .removeClass(className.selected)
  118. ;
  119. },
  120. click: function() {
  121. var
  122. $activeIcon = $(this),
  123. currentRating = module.getRating(),
  124. rating = $icon.index($activeIcon) + 1,
  125. canClear = (settings.clearable == 'auto')
  126. ? ($icon.length === 1)
  127. : settings.clearable
  128. ;
  129. if(canClear && currentRating == rating) {
  130. module.clearRating();
  131. }
  132. else {
  133. module.setRating( rating );
  134. }
  135. }
  136. },
  137. clearRating: function() {
  138. module.debug('Clearing current rating');
  139. module.setRating(0);
  140. },
  141. getRating: function() {
  142. var
  143. currentRating = $icon.filter('.' + className.active).length
  144. ;
  145. module.verbose('Current rating retrieved', currentRating);
  146. return currentRating;
  147. },
  148. bind: {
  149. events: function() {
  150. module.verbose('Binding events');
  151. $module
  152. .on('mouseenter' + eventNamespace, selector.icon, module.event.mouseenter)
  153. .on('mouseleave' + eventNamespace, selector.icon, module.event.mouseleave)
  154. .on('click' + eventNamespace, selector.icon, module.event.click)
  155. ;
  156. }
  157. },
  158. remove: {
  159. events: function() {
  160. module.verbose('Removing events');
  161. $module
  162. .off(eventNamespace)
  163. ;
  164. }
  165. },
  166. enable: function() {
  167. module.debug('Setting rating to interactive mode');
  168. module.bind.events();
  169. $module
  170. .removeClass(className.disabled)
  171. ;
  172. },
  173. disable: function() {
  174. module.debug('Setting rating to read-only mode');
  175. module.remove.events();
  176. $module
  177. .addClass(className.disabled)
  178. ;
  179. },
  180. setRating: function(rating) {
  181. var
  182. ratingIndex = (rating - 1 >= 0)
  183. ? (rating - 1)
  184. : 0,
  185. $activeIcon = $icon.eq(ratingIndex)
  186. ;
  187. $module
  188. .removeClass(className.selected)
  189. ;
  190. $icon
  191. .removeClass(className.selected)
  192. .removeClass(className.active)
  193. ;
  194. if(rating > 0) {
  195. module.verbose('Setting current rating to', rating);
  196. $activeIcon
  197. .prevAll()
  198. .andSelf()
  199. .addClass(className.active)
  200. ;
  201. }
  202. settings.onRate.call(element, rating);
  203. },
  204. setting: function(name, value) {
  205. module.debug('Changing setting', name, value);
  206. if( $.isPlainObject(name) ) {
  207. $.extend(true, settings, name);
  208. }
  209. else if(value !== undefined) {
  210. settings[name] = value;
  211. }
  212. else {
  213. return settings[name];
  214. }
  215. },
  216. internal: function(name, value) {
  217. if( $.isPlainObject(name) ) {
  218. $.extend(true, module, name);
  219. }
  220. else if(value !== undefined) {
  221. module[name] = value;
  222. }
  223. else {
  224. return module[name];
  225. }
  226. },
  227. debug: function() {
  228. if(settings.debug) {
  229. if(settings.performance) {
  230. module.performance.log(arguments);
  231. }
  232. else {
  233. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  234. module.debug.apply(console, arguments);
  235. }
  236. }
  237. },
  238. verbose: function() {
  239. if(settings.verbose && settings.debug) {
  240. if(settings.performance) {
  241. module.performance.log(arguments);
  242. }
  243. else {
  244. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  245. module.verbose.apply(console, arguments);
  246. }
  247. }
  248. },
  249. error: function() {
  250. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  251. module.error.apply(console, arguments);
  252. },
  253. performance: {
  254. log: function(message) {
  255. var
  256. currentTime,
  257. executionTime,
  258. previousTime
  259. ;
  260. if(settings.performance) {
  261. currentTime = new Date().getTime();
  262. previousTime = time || currentTime;
  263. executionTime = currentTime - previousTime;
  264. time = currentTime;
  265. performance.push({
  266. 'Name' : message[0],
  267. 'Arguments' : [].slice.call(message, 1) || '',
  268. 'Element' : element,
  269. 'Execution Time' : executionTime
  270. });
  271. }
  272. clearTimeout(module.performance.timer);
  273. module.performance.timer = setTimeout(module.performance.display, 500);
  274. },
  275. display: function() {
  276. var
  277. title = settings.name + ':',
  278. totalTime = 0
  279. ;
  280. time = false;
  281. clearTimeout(module.performance.timer);
  282. $.each(performance, function(index, data) {
  283. totalTime += data['Execution Time'];
  284. });
  285. title += ' ' + totalTime + 'ms';
  286. if(moduleSelector) {
  287. title += ' \'' + moduleSelector + '\'';
  288. }
  289. if($allModules.length > 1) {
  290. title += ' ' + '(' + $allModules.length + ')';
  291. }
  292. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  293. console.groupCollapsed(title);
  294. if(console.table) {
  295. console.table(performance);
  296. }
  297. else {
  298. $.each(performance, function(index, data) {
  299. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  300. });
  301. }
  302. console.groupEnd();
  303. }
  304. performance = [];
  305. }
  306. },
  307. invoke: function(query, passedArguments, context) {
  308. var
  309. object = instance,
  310. maxDepth,
  311. found,
  312. response
  313. ;
  314. passedArguments = passedArguments || queryArguments;
  315. context = element || context;
  316. if(typeof query == 'string' && object !== undefined) {
  317. query = query.split(/[\. ]/);
  318. maxDepth = query.length - 1;
  319. $.each(query, function(depth, value) {
  320. var camelCaseValue = (depth != maxDepth)
  321. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  322. : query
  323. ;
  324. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  325. object = object[camelCaseValue];
  326. }
  327. else if( object[camelCaseValue] !== undefined ) {
  328. found = object[camelCaseValue];
  329. return false;
  330. }
  331. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  332. object = object[value];
  333. }
  334. else if( object[value] !== undefined ) {
  335. found = object[value];
  336. return false;
  337. }
  338. else {
  339. return false;
  340. }
  341. });
  342. }
  343. if ( $.isFunction( found ) ) {
  344. response = found.apply(context, passedArguments);
  345. }
  346. else if(found !== undefined) {
  347. response = found;
  348. }
  349. if($.isArray(returnedValue)) {
  350. returnedValue.push(response);
  351. }
  352. else if(returnedValue !== undefined) {
  353. returnedValue = [returnedValue, response];
  354. }
  355. else if(response !== undefined) {
  356. returnedValue = response;
  357. }
  358. return found;
  359. }
  360. };
  361. if(methodInvoked) {
  362. if(instance === undefined) {
  363. module.initialize();
  364. }
  365. module.invoke(query);
  366. }
  367. else {
  368. if(instance !== undefined) {
  369. instance.invoke('destroy');
  370. }
  371. module.initialize();
  372. }
  373. })
  374. ;
  375. return (returnedValue !== undefined)
  376. ? returnedValue
  377. : this
  378. ;
  379. };
  380. $.fn.rating.settings = {
  381. name : 'Rating',
  382. namespace : 'rating',
  383. debug : false,
  384. verbose : false,
  385. performance : true,
  386. initialRating : 0,
  387. interactive : true,
  388. maxRating : 4,
  389. clearable : 'auto',
  390. onRate : function(rating){},
  391. error : {
  392. method : 'The method you called is not defined',
  393. noMaximum : 'No maximum rating specified. Cannot generate HTML automatically'
  394. },
  395. metadata: {
  396. rating : 'rating',
  397. maxRating : 'maxRating'
  398. },
  399. className : {
  400. active : 'active',
  401. disabled : 'disabled',
  402. selected : 'selected',
  403. loading : 'loading'
  404. },
  405. selector : {
  406. icon : '.icon'
  407. },
  408. templates: {
  409. icon: function(maxRating) {
  410. var
  411. icon = 1,
  412. html = ''
  413. ;
  414. while(icon <= maxRating) {
  415. html += '<i class="icon"></i>';
  416. icon++;
  417. }
  418. return html;
  419. }
  420. }
  421. };
  422. })( jQuery, window , document );