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.

374 lines
11 KiB

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