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
10 years ago
9 years ago
10 years ago
10 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
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
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 );