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.

321 lines
9.0 KiB

  1. /* ******************************
  2. Semantic Module: Checkbox
  3. Author: Jack Lukic
  4. Notes: First Commit March 25, 2013
  5. Simple plug-in which maintains the state for ui checkbox
  6. This can be done without javascript, only in instances
  7. where each checkbox is assigned a unique ID. This provides a separate
  8. programmatic option when that is not possible.
  9. ****************************** */
  10. ;(function ( $, window, document, undefined ) {
  11. $.fn.checkbox = function(parameters) {
  12. var
  13. $allModules = $(this),
  14. settings = $.extend(true, {}, $.fn.checkbox.settings, parameters),
  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. invokedResponse
  22. ;
  23. $allModules
  24. .each(function() {
  25. var
  26. $module = $(this),
  27. $label = $(this).next(settings.selector.label).first(),
  28. $input = $(this).find(settings.selector.input),
  29. eventNamespace = '.' + settings.namespace,
  30. moduleNamespace = 'module-' + settings.namespace,
  31. selector = $module.selector || '',
  32. element = this,
  33. instance = $module.data(moduleNamespace),
  34. className = settings.className,
  35. namespace = settings.namespace,
  36. errors = settings.errors,
  37. module
  38. ;
  39. module = {
  40. initialize: function() {
  41. module.verbose('Initializing checkbox');
  42. if(settings.context && selector !== '') {
  43. module.verbose('Adding delegated events');
  44. $(element, settings.context)
  45. .on(selector, 'click' + eventNamespace, module.toggle)
  46. .on(selector + ' + ' + settings.selector.label, 'click' + eventNamespace, module.toggle)
  47. ;
  48. }
  49. else {
  50. $module
  51. .on('click' + eventNamespace, module.toggle)
  52. .data(moduleNamespace, module)
  53. ;
  54. $label
  55. .on('click' + eventNamespace, module.toggle)
  56. ;
  57. }
  58. module.instantiate();
  59. },
  60. instantiate: function() {
  61. module.verbose('Storing instance of module', module);
  62. instance = module;
  63. $module
  64. .data(moduleNamespace, module)
  65. ;
  66. },
  67. destroy: function() {
  68. module.verbose('Destroying previous module');
  69. $module
  70. .off(namespace)
  71. ;
  72. },
  73. is: {
  74. radio: function() {
  75. return $module.hasClass(className.radio);
  76. }
  77. },
  78. can: {
  79. disable: function() {
  80. return (typeof settings.required === 'boolean')
  81. ? settings.required
  82. : !module.is.radio()
  83. ;
  84. }
  85. },
  86. enable: function() {
  87. module.debug('Enabling checkbox');
  88. $module
  89. .addClass(className.active)
  90. ;
  91. $input
  92. .prop('checked', true)
  93. ;
  94. $.proxy(settings.onChange, $input.get())();
  95. $.proxy(settings.onEnable, $input.get())();
  96. },
  97. disable: function() {
  98. module.debug('Disabling checkbox');
  99. $module
  100. .removeClass(className.active)
  101. ;
  102. $input
  103. .prop('checked', false)
  104. ;
  105. $.proxy(settings.onChange, $input.get())();
  106. $.proxy(settings.onDisable, $input.get())();
  107. },
  108. toggle: function(event) {
  109. module.verbose('Determining new checkbox state', $(event.target));
  110. if($input.prop('checked') === undefined || !$input.prop('checked')) {
  111. module.enable();
  112. }
  113. else if( module.can.disable() ) {
  114. module.disable();
  115. }
  116. },
  117. setting: function(name, value) {
  118. if(value !== undefined) {
  119. if( $.isPlainObject(name) ) {
  120. $.extend(true, settings, name);
  121. }
  122. else {
  123. settings[name] = value;
  124. }
  125. }
  126. else {
  127. return settings[name];
  128. }
  129. },
  130. internal: function(name, value) {
  131. if(value !== undefined) {
  132. if( $.isPlainObject(name) ) {
  133. $.extend(true, module, name);
  134. }
  135. else {
  136. module[name] = value;
  137. }
  138. }
  139. else {
  140. return module[name];
  141. }
  142. },
  143. debug: function() {
  144. if(settings.debug) {
  145. if(settings.performance) {
  146. module.performance.log(arguments);
  147. }
  148. else {
  149. module.debug = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  150. }
  151. }
  152. },
  153. verbose: function() {
  154. if(settings.verbose && settings.debug) {
  155. if(settings.performance) {
  156. module.performance.log(arguments);
  157. }
  158. else {
  159. module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  160. }
  161. }
  162. },
  163. error: function() {
  164. module.error = Function.prototype.bind.call(console.warn, console, settings.moduleName + ':');
  165. },
  166. performance: {
  167. log: function(message) {
  168. var
  169. currentTime,
  170. executionTime,
  171. previousTime
  172. ;
  173. if(settings.performance) {
  174. currentTime = new Date().getTime();
  175. previousTime = time || currentTime;
  176. executionTime = currentTime - previousTime;
  177. time = currentTime;
  178. performance.push({
  179. 'Element' : element,
  180. 'Name' : message[0],
  181. 'Arguments' : [].slice.call(message, 1) || '',
  182. 'Execution Time' : executionTime
  183. });
  184. }
  185. clearTimeout(module.performance.timer);
  186. module.performance.timer = setTimeout(module.performance.display, 100);
  187. },
  188. display: function() {
  189. var
  190. title = settings.moduleName + ':',
  191. totalTime = 0
  192. ;
  193. time = false;
  194. clearTimeout(module.performance.timer);
  195. $.each(performance, function(index, data) {
  196. totalTime += data['Execution Time'];
  197. });
  198. title += ' ' + totalTime + 'ms';
  199. if(moduleSelector) {
  200. title += ' \'' + moduleSelector + '\'';
  201. }
  202. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  203. console.groupCollapsed(title);
  204. if(console.table) {
  205. console.table(performance);
  206. }
  207. else {
  208. $.each(performance, function(index, data) {
  209. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  210. });
  211. }
  212. console.groupEnd();
  213. }
  214. performance = [];
  215. }
  216. },
  217. invoke: function(query, passedArguments, context) {
  218. var
  219. maxDepth,
  220. found
  221. ;
  222. passedArguments = passedArguments || queryArguments;
  223. context = element || context;
  224. if(typeof query == 'string' && instance !== undefined) {
  225. query = query.split(/[\. ]/);
  226. maxDepth = query.length - 1;
  227. $.each(query, function(depth, value) {
  228. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  229. instance = instance[value];
  230. }
  231. else if( instance[value] !== undefined ) {
  232. found = instance[value];
  233. }
  234. else {
  235. module.error(errors.method);
  236. }
  237. });
  238. }
  239. if ( $.isFunction( found ) ) {
  240. return found.apply(context, passedArguments);
  241. }
  242. return found || false;
  243. }
  244. };
  245. if(methodInvoked) {
  246. if(instance === undefined) {
  247. module.initialize();
  248. }
  249. invokedResponse = module.invoke(query);
  250. }
  251. else {
  252. if(instance !== undefined) {
  253. module.destroy();
  254. }
  255. module.initialize();
  256. }
  257. })
  258. ;
  259. return (invokedResponse)
  260. ? invokedResponse
  261. : this
  262. ;
  263. };
  264. $.fn.checkbox.settings = {
  265. moduleName : 'Checkbox',
  266. namespace : 'checkbox',
  267. verbose : true,
  268. debug : true,
  269. performance : true,
  270. // delegated event context
  271. context : false,
  272. required : 'auto',
  273. onChange : function(){},
  274. onEnable : function(){},
  275. onDisable : function(){},
  276. errors : {
  277. method : 'The method you called is not defined.'
  278. },
  279. selector : {
  280. input : 'input',
  281. label : 'label'
  282. },
  283. className : {
  284. active : 'active',
  285. radio : 'radio'
  286. }
  287. };
  288. })( jQuery, window , document );