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.

382 lines
11 KiB

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