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

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
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 UI 2.0.0 - Rating
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 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 );