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.

533 lines
15 KiB

9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 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
9 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
9 years ago
9 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
10 years ago
10 years ago
10 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
10 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 2.0.0 - Checkbox
  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.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. selector = settings.selector,
  31. error = settings.error,
  32. eventNamespace = '.' + namespace,
  33. moduleNamespace = 'module-' + namespace,
  34. $module = $(this),
  35. $label = $(this).find(selector.label),
  36. $input = $(this).find(selector.input),
  37. instance = $module.data(moduleNamespace),
  38. observer,
  39. element = this,
  40. module
  41. ;
  42. module = {
  43. initialize: function() {
  44. module.verbose('Initializing checkbox', settings);
  45. module.create.label();
  46. module.add.events();
  47. module.setup();
  48. module.observeChanges();
  49. module.instantiate();
  50. },
  51. instantiate: function() {
  52. module.verbose('Storing instance of module', module);
  53. instance = module;
  54. $module
  55. .data(moduleNamespace, module)
  56. ;
  57. },
  58. destroy: function() {
  59. module.verbose('Destroying module');
  60. module.remove.events();
  61. $module
  62. .removeData(moduleNamespace)
  63. ;
  64. },
  65. setup: function() {
  66. if( module.is.checked() ) {
  67. module.debug('Setting initial value to checked');
  68. module.set.checked();
  69. if(settings.fireOnInit) {
  70. settings.onChecked.call($input.get());
  71. }
  72. }
  73. else {
  74. module.debug('Setting initial value to unchecked');
  75. module.remove.checked();
  76. if(settings.fireOnInit) {
  77. settings.onUnchecked.call($input.get());
  78. }
  79. }
  80. },
  81. refresh: function() {
  82. $label = $module.find(selector.label);
  83. $input = $module.find(selector.input);
  84. },
  85. observeChanges: function() {
  86. if('MutationObserver' in window) {
  87. observer = new MutationObserver(function(mutations) {
  88. module.debug('DOM tree modified, updating selector cache');
  89. module.refresh();
  90. });
  91. observer.observe(element, {
  92. childList : true,
  93. subtree : true
  94. });
  95. module.debug('Setting up mutation observer', observer);
  96. }
  97. },
  98. attachEvents: function(selector, event) {
  99. var
  100. $element = $(selector)
  101. ;
  102. event = $.isFunction(module[event])
  103. ? module[event]
  104. : module.toggle
  105. ;
  106. if($element.length > 0) {
  107. module.debug('Attaching checkbox events to element', selector, event);
  108. $element
  109. .on('click' + eventNamespace, event)
  110. ;
  111. }
  112. else {
  113. module.error(error.notFound);
  114. }
  115. },
  116. event: {
  117. keydown: function(event) {
  118. var
  119. key = event.which,
  120. keyCode = {
  121. enter : 13,
  122. space : 32,
  123. escape : 27
  124. }
  125. ;
  126. if( key == keyCode.escape) {
  127. module.verbose('Escape key pressed blurring field');
  128. $module
  129. .blur()
  130. ;
  131. }
  132. if(!event.ctrlKey && (key == keyCode.enter || key == keyCode.space)) {
  133. module.verbose('Enter key pressed, toggling checkbox');
  134. module.toggle.call(this);
  135. event.preventDefault();
  136. }
  137. }
  138. },
  139. get: {
  140. radios: function() {
  141. return $('input[name="' + module.get.name() + '"]').closest(selector.checkbox);
  142. },
  143. name: function() {
  144. return $input.attr('name');
  145. }
  146. },
  147. is: {
  148. radio: function() {
  149. return ($input.hasClass(className.radio) || $input.attr('type') == 'radio');
  150. },
  151. checked: function() {
  152. return $input.prop('checked') !== undefined && $input.prop('checked');
  153. },
  154. unchecked: function() {
  155. return !module.is.checked();
  156. }
  157. },
  158. can: {
  159. change: function() {
  160. return !( $module.hasClass(className.disabled) || $module.hasClass(className.readOnly) || $input.prop('disabled') );
  161. },
  162. uncheck: function() {
  163. return (typeof settings.uncheckable === 'boolean')
  164. ? settings.uncheckable
  165. : !module.is.radio()
  166. ;
  167. }
  168. },
  169. set: {
  170. checked: function() {
  171. var
  172. $radios
  173. ;
  174. if( module.is.radio() ) {
  175. $radios = module.get.radios();
  176. module.debug('Unchecking other radios', $radios);
  177. $radios.removeClass(className.checked);
  178. }
  179. $module.addClass(className.checked);
  180. },
  181. tab: function() {
  182. if( $input.attr('tabindex') === undefined) {
  183. $input
  184. .attr('tabindex', 0)
  185. ;
  186. }
  187. }
  188. },
  189. create: {
  190. label: function() {
  191. if($input.prevAll(selector.label).length > 0) {
  192. $input.prev(selector.label).detach().insertAfter($input);
  193. module.debug('Moving existing label', $label);
  194. }
  195. else if( !module.has.label() ) {
  196. $label = $('<label>').insertAfter($input);
  197. module.debug('Creating label', $label);
  198. }
  199. }
  200. },
  201. has: {
  202. label: function() {
  203. return ($label.length > 0);
  204. }
  205. },
  206. add: {
  207. events: function() {
  208. module.verbose('Attaching checkbox events');
  209. $module
  210. .on('click' + eventNamespace, module.toggle)
  211. .on('keydown' + eventNamespace, selector.input, module.event.keydown)
  212. ;
  213. }
  214. },
  215. remove: {
  216. checked: function() {
  217. $module.removeClass(className.checked);
  218. },
  219. events: function() {
  220. module.debug('Removing events');
  221. $module
  222. .off(eventNamespace)
  223. .removeData(moduleNamespace)
  224. ;
  225. $input
  226. .off(eventNamespace, module.event.keydown)
  227. ;
  228. $label
  229. .off(eventNamespace)
  230. ;
  231. }
  232. },
  233. enable: function() {
  234. module.debug('Enabling checkbox functionality');
  235. $module.removeClass(className.disabled);
  236. $input.prop('disabled', false);
  237. settings.onEnabled.call($input[0]);
  238. },
  239. disable: function() {
  240. module.debug('Disabling checkbox functionality');
  241. $module.addClass(className.disabled);
  242. $input.prop('disabled', 'disabled');
  243. settings.onDisabled.call($input[0]);
  244. },
  245. check: function() {
  246. module.debug('Enabling checkbox', $input);
  247. $input
  248. .prop('checked', true)
  249. .trigger('change')
  250. ;
  251. module.set.checked();
  252. $input.trigger('blur');
  253. settings.onChange.call($input[0]);
  254. settings.onChecked.call($input[0]);
  255. },
  256. uncheck: function() {
  257. module.debug('Disabling checkbox');
  258. $input
  259. .prop('checked', false)
  260. .trigger('change')
  261. ;
  262. module.remove.checked();
  263. $input.trigger('blur');
  264. settings.onChange.call($input[0]);
  265. settings.onUnchecked.call($input[0]);
  266. },
  267. toggle: function(event) {
  268. if( !module.can.change() ) {
  269. if(!module.is.radio()) {
  270. module.debug('Checkbox is read-only or disabled, ignoring toggle');
  271. }
  272. return;
  273. }
  274. module.verbose('Determining new checkbox state');
  275. if( module.is.unchecked() ) {
  276. module.check();
  277. }
  278. else if( module.is.checked() && module.can.uncheck() ) {
  279. module.uncheck();
  280. }
  281. },
  282. setting: function(name, value) {
  283. module.debug('Changing setting', name, value);
  284. if( $.isPlainObject(name) ) {
  285. $.extend(true, settings, name);
  286. }
  287. else if(value !== undefined) {
  288. settings[name] = value;
  289. }
  290. else {
  291. return settings[name];
  292. }
  293. },
  294. internal: function(name, value) {
  295. if( $.isPlainObject(name) ) {
  296. $.extend(true, module, name);
  297. }
  298. else if(value !== undefined) {
  299. module[name] = value;
  300. }
  301. else {
  302. return module[name];
  303. }
  304. },
  305. debug: function() {
  306. if(settings.debug) {
  307. if(settings.performance) {
  308. module.performance.log(arguments);
  309. }
  310. else {
  311. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  312. module.debug.apply(console, arguments);
  313. }
  314. }
  315. },
  316. verbose: function() {
  317. if(settings.verbose && settings.debug) {
  318. if(settings.performance) {
  319. module.performance.log(arguments);
  320. }
  321. else {
  322. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  323. module.verbose.apply(console, arguments);
  324. }
  325. }
  326. },
  327. error: function() {
  328. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  329. module.error.apply(console, arguments);
  330. },
  331. performance: {
  332. log: function(message) {
  333. var
  334. currentTime,
  335. executionTime,
  336. previousTime
  337. ;
  338. if(settings.performance) {
  339. currentTime = new Date().getTime();
  340. previousTime = time || currentTime;
  341. executionTime = currentTime - previousTime;
  342. time = currentTime;
  343. performance.push({
  344. 'Name' : message[0],
  345. 'Arguments' : [].slice.call(message, 1) || '',
  346. 'Element' : element,
  347. 'Execution Time' : executionTime
  348. });
  349. }
  350. clearTimeout(module.performance.timer);
  351. module.performance.timer = setTimeout(module.performance.display, 500);
  352. },
  353. display: function() {
  354. var
  355. title = settings.name + ':',
  356. totalTime = 0
  357. ;
  358. time = false;
  359. clearTimeout(module.performance.timer);
  360. $.each(performance, function(index, data) {
  361. totalTime += data['Execution Time'];
  362. });
  363. title += ' ' + totalTime + 'ms';
  364. if(moduleSelector) {
  365. title += ' \'' + moduleSelector + '\'';
  366. }
  367. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  368. console.groupCollapsed(title);
  369. if(console.table) {
  370. console.table(performance);
  371. }
  372. else {
  373. $.each(performance, function(index, data) {
  374. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  375. });
  376. }
  377. console.groupEnd();
  378. }
  379. performance = [];
  380. }
  381. },
  382. invoke: function(query, passedArguments, context) {
  383. var
  384. object = instance,
  385. maxDepth,
  386. found,
  387. response
  388. ;
  389. passedArguments = passedArguments || queryArguments;
  390. context = element || context;
  391. if(typeof query == 'string' && object !== undefined) {
  392. query = query.split(/[\. ]/);
  393. maxDepth = query.length - 1;
  394. $.each(query, function(depth, value) {
  395. var camelCaseValue = (depth != maxDepth)
  396. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  397. : query
  398. ;
  399. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  400. object = object[camelCaseValue];
  401. }
  402. else if( object[camelCaseValue] !== undefined ) {
  403. found = object[camelCaseValue];
  404. return false;
  405. }
  406. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  407. object = object[value];
  408. }
  409. else if( object[value] !== undefined ) {
  410. found = object[value];
  411. return false;
  412. }
  413. else {
  414. module.error(error.method, query);
  415. return false;
  416. }
  417. });
  418. }
  419. if ( $.isFunction( found ) ) {
  420. response = found.apply(context, passedArguments);
  421. }
  422. else if(found !== undefined) {
  423. response = found;
  424. }
  425. if($.isArray(returnedValue)) {
  426. returnedValue.push(response);
  427. }
  428. else if(returnedValue !== undefined) {
  429. returnedValue = [returnedValue, response];
  430. }
  431. else if(response !== undefined) {
  432. returnedValue = response;
  433. }
  434. return found;
  435. }
  436. };
  437. if(methodInvoked) {
  438. if(instance === undefined) {
  439. module.initialize();
  440. }
  441. module.invoke(query);
  442. }
  443. else {
  444. if(instance !== undefined) {
  445. instance.invoke('destroy');
  446. }
  447. module.initialize();
  448. }
  449. })
  450. ;
  451. return (returnedValue !== undefined)
  452. ? returnedValue
  453. : this
  454. ;
  455. };
  456. $.fn.checkbox.settings = {
  457. name : 'Checkbox',
  458. namespace : 'checkbox',
  459. debug : false,
  460. verbose : true,
  461. performance : true,
  462. // delegated event context
  463. uncheckable : 'auto',
  464. fireOnInit : true,
  465. onChange : function(){},
  466. onChecked : function(){},
  467. onUnchecked : function(){},
  468. onEnabled : function(){},
  469. onDisabled : function(){},
  470. className : {
  471. checked : 'checked',
  472. disabled : 'disabled',
  473. radio : 'radio',
  474. readOnly : 'read-only'
  475. },
  476. error : {
  477. method : 'The method you called is not defined'
  478. },
  479. selector : {
  480. checkbox : '.ui.checkbox',
  481. input : '> input[type="checkbox"], > input[type="radio"]',
  482. label : '> label'
  483. }
  484. };
  485. })( jQuery, window , document );