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.

393 lines
11 KiB

10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
  1. /*
  2. * # Semantic - Checkbox
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2014 Contributor
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ( $, window, document, undefined ) {
  12. "use strict";
  13. $.fn.checkbox = 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 = $.extend(true, {}, $.fn.checkbox.settings, parameters),
  28. className = settings.className,
  29. namespace = settings.namespace,
  30. error = settings.error,
  31. eventNamespace = '.' + namespace,
  32. moduleNamespace = 'module-' + namespace,
  33. $module = $(this),
  34. $label = $(this).next(settings.selector.label).first(),
  35. $input = $(this).find(settings.selector.input),
  36. selector = $module.selector || '',
  37. instance = $module.data(moduleNamespace),
  38. element = this,
  39. module
  40. ;
  41. module = {
  42. initialize: function() {
  43. module.verbose('Initializing checkbox', settings);
  44. if(settings.context && selector !== '') {
  45. module.verbose('Adding delegated events');
  46. $(element, settings.context)
  47. .on(selector, 'click' + eventNamespace, module.toggle)
  48. .on(selector + ' + ' + settings.selector.label, 'click' + eventNamespace, module.toggle)
  49. ;
  50. }
  51. else {
  52. $module
  53. .on('click' + eventNamespace, module.toggle)
  54. .data(moduleNamespace, module)
  55. ;
  56. $input
  57. .on('keydown' + eventNamespace, module.event.keydown)
  58. ;
  59. $label
  60. .on('click' + eventNamespace, module.toggle)
  61. ;
  62. }
  63. if(settings.fireOnInit) {
  64. $.proxy(settings.onChange, $input.get())();
  65. if( module.is.checked() ) {
  66. $.proxy(settings.onChecked, $input.get())();
  67. }
  68. else {
  69. $.proxy(settings.onUnchecked, $input.get())();
  70. }
  71. }
  72. module.instantiate();
  73. },
  74. instantiate: function() {
  75. module.verbose('Storing instance of module', module);
  76. instance = module;
  77. $module
  78. .data(moduleNamespace, module)
  79. ;
  80. },
  81. destroy: function() {
  82. module.verbose('Destroying previous module');
  83. $module
  84. .off(eventNamespace)
  85. .removeData(moduleNamespace)
  86. ;
  87. $input
  88. .off(eventNamespace, module.event.keydown)
  89. ;
  90. $label
  91. .off(eventNamespace)
  92. ;
  93. },
  94. event: {
  95. keydown: function(event) {
  96. var
  97. key = event.which,
  98. keyCode = {
  99. enter : 13,
  100. escape : 27
  101. }
  102. ;
  103. if( key == keyCode.escape) {
  104. module.verbose('Escape key pressed blurring field');
  105. $module
  106. .blur()
  107. ;
  108. }
  109. if(!event.ctrlKey && key == keyCode.enter) {
  110. module.verbose('Enter key pressed, toggling checkbox');
  111. $.proxy(module.toggle, this)();
  112. event.preventDefault();
  113. }
  114. }
  115. },
  116. is: {
  117. radio: function() {
  118. return $module.hasClass(className.radio);
  119. },
  120. checked: function() {
  121. return $input.prop('checked') !== undefined && $input.prop('checked');
  122. },
  123. unchecked: function() {
  124. return !module.is.checked();
  125. }
  126. },
  127. can: {
  128. uncheck: function() {
  129. return (typeof settings.required === 'boolean')
  130. ? settings.required
  131. : !module.is.radio()
  132. ;
  133. }
  134. },
  135. check: function() {
  136. module.debug('Enabling checkbox', $input);
  137. $input
  138. .prop('checked', true)
  139. .trigger('change')
  140. ;
  141. $.proxy(settings.onChange, $input.get())();
  142. $.proxy(settings.onChecked, $input.get())();
  143. },
  144. uncheck: function() {
  145. module.debug('Disabling checkbox');
  146. $input
  147. .prop('checked', false)
  148. .trigger('change')
  149. ;
  150. $.proxy(settings.onChange, $input.get())();
  151. $.proxy(settings.onUnchecked, $input.get())();
  152. },
  153. toggle: function(event) {
  154. module.verbose('Determining new checkbox state');
  155. if( module.is.unchecked() ) {
  156. module.check();
  157. }
  158. else if( module.is.checked() && module.can.uncheck() ) {
  159. module.uncheck();
  160. }
  161. },
  162. setting: function(name, value) {
  163. module.debug('Changing setting', name, value);
  164. if( $.isPlainObject(name) ) {
  165. $.extend(true, settings, name);
  166. }
  167. else if(value !== undefined) {
  168. settings[name] = value;
  169. }
  170. else {
  171. return settings[name];
  172. }
  173. },
  174. internal: function(name, value) {
  175. if( $.isPlainObject(name) ) {
  176. $.extend(true, module, name);
  177. }
  178. else if(value !== undefined) {
  179. module[name] = value;
  180. }
  181. else {
  182. return module[name];
  183. }
  184. },
  185. debug: function() {
  186. if(settings.debug) {
  187. if(settings.performance) {
  188. module.performance.log(arguments);
  189. }
  190. else {
  191. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  192. module.debug.apply(console, arguments);
  193. }
  194. }
  195. },
  196. verbose: function() {
  197. if(settings.verbose && settings.debug) {
  198. if(settings.performance) {
  199. module.performance.log(arguments);
  200. }
  201. else {
  202. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  203. module.verbose.apply(console, arguments);
  204. }
  205. }
  206. },
  207. error: function() {
  208. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  209. module.error.apply(console, arguments);
  210. },
  211. performance: {
  212. log: function(message) {
  213. var
  214. currentTime,
  215. executionTime,
  216. previousTime
  217. ;
  218. if(settings.performance) {
  219. currentTime = new Date().getTime();
  220. previousTime = time || currentTime;
  221. executionTime = currentTime - previousTime;
  222. time = currentTime;
  223. performance.push({
  224. 'Element' : element,
  225. 'Name' : message[0],
  226. 'Arguments' : [].slice.call(message, 1) || '',
  227. 'Execution Time' : executionTime
  228. });
  229. }
  230. clearTimeout(module.performance.timer);
  231. module.performance.timer = setTimeout(module.performance.display, 100);
  232. },
  233. display: function() {
  234. var
  235. title = settings.name + ':',
  236. totalTime = 0
  237. ;
  238. time = false;
  239. clearTimeout(module.performance.timer);
  240. $.each(performance, function(index, data) {
  241. totalTime += data['Execution Time'];
  242. });
  243. title += ' ' + totalTime + 'ms';
  244. if(moduleSelector) {
  245. title += ' \'' + moduleSelector + '\'';
  246. }
  247. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  248. console.groupCollapsed(title);
  249. if(console.table) {
  250. console.table(performance);
  251. }
  252. else {
  253. $.each(performance, function(index, data) {
  254. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  255. });
  256. }
  257. console.groupEnd();
  258. }
  259. performance = [];
  260. }
  261. },
  262. invoke: function(query, passedArguments, context) {
  263. var
  264. object = instance,
  265. maxDepth,
  266. found,
  267. response
  268. ;
  269. passedArguments = passedArguments || queryArguments;
  270. context = element || context;
  271. if(typeof query == 'string' && object !== undefined) {
  272. query = query.split(/[\. ]/);
  273. maxDepth = query.length - 1;
  274. $.each(query, function(depth, value) {
  275. var camelCaseValue = (depth != maxDepth)
  276. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  277. : query
  278. ;
  279. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  280. object = object[camelCaseValue];
  281. }
  282. else if( object[camelCaseValue] !== undefined ) {
  283. found = object[camelCaseValue];
  284. return false;
  285. }
  286. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  287. object = object[value];
  288. }
  289. else if( object[value] !== undefined ) {
  290. found = object[value];
  291. return false;
  292. }
  293. else {
  294. return false;
  295. }
  296. });
  297. }
  298. if ( $.isFunction( found ) ) {
  299. response = found.apply(context, passedArguments);
  300. }
  301. else if(found !== undefined) {
  302. response = found;
  303. }
  304. if($.isArray(returnedValue)) {
  305. returnedValue.push(response);
  306. }
  307. else if(returnedValue !== undefined) {
  308. returnedValue = [returnedValue, response];
  309. }
  310. else if(response !== undefined) {
  311. returnedValue = response;
  312. }
  313. return found;
  314. }
  315. };
  316. if(methodInvoked) {
  317. if(instance === undefined) {
  318. module.initialize();
  319. }
  320. module.invoke(query);
  321. }
  322. else {
  323. if(instance !== undefined) {
  324. module.destroy();
  325. }
  326. module.initialize();
  327. }
  328. })
  329. ;
  330. return (returnedValue !== undefined)
  331. ? returnedValue
  332. : this
  333. ;
  334. };
  335. $.fn.checkbox.settings = {
  336. name : 'Checkbox',
  337. namespace : 'checkbox',
  338. debug : false,
  339. verbose : true,
  340. performance : true,
  341. // delegated event context
  342. context : false,
  343. required : 'auto',
  344. fireOnInit : true,
  345. onChange : function(){},
  346. onChecked : function(){},
  347. onUnchecked : function(){},
  348. error : {
  349. method : 'The method you called is not defined.'
  350. },
  351. selector : {
  352. input : 'input[type=checkbox], input[type=radio]',
  353. label : 'label'
  354. },
  355. className : {
  356. radio : 'radio'
  357. }
  358. };
  359. })( jQuery, window , document );