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.

345 lines
10 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. className = settings.className,
  16. namespace = settings.namespace,
  17. error = settings.error,
  18. eventNamespace = '.' + namespace,
  19. moduleNamespace = 'module-' + namespace,
  20. moduleSelector = $allModules.selector || '',
  21. time = new Date().getTime(),
  22. performance = [],
  23. query = arguments[0],
  24. methodInvoked = (typeof query == 'string'),
  25. queryArguments = [].slice.call(arguments, 1),
  26. invokedResponse
  27. ;
  28. $allModules
  29. .each(function() {
  30. var
  31. $module = $(this),
  32. $label = $(this).next(settings.selector.label).first(),
  33. $input = $(this).find(settings.selector.input),
  34. selector = $module.selector || '',
  35. instance = $module.data(moduleNamespace),
  36. element = this,
  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(eventNamespace)
  71. .removeData(moduleNamespace)
  72. ;
  73. },
  74. is: {
  75. radio: function() {
  76. return $module.hasClass(className.radio);
  77. }
  78. },
  79. can: {
  80. disable: function() {
  81. return (typeof settings.required === 'boolean')
  82. ? settings.required
  83. : !module.is.radio()
  84. ;
  85. }
  86. },
  87. enable: function() {
  88. module.debug('Enabling checkbox');
  89. $input
  90. .prop('checked', true)
  91. ;
  92. $.proxy(settings.onChange, $input.get())();
  93. $.proxy(settings.onEnable, $input.get())();
  94. },
  95. disable: function() {
  96. module.debug('Disabling checkbox');
  97. $input
  98. .prop('checked', false)
  99. ;
  100. $.proxy(settings.onChange, $input.get())();
  101. $.proxy(settings.onDisable, $input.get())();
  102. },
  103. toggle: function(event) {
  104. module.verbose('Determining new checkbox state', $(event.target));
  105. if($input.prop('checked') === undefined || !$input.prop('checked')) {
  106. module.enable();
  107. }
  108. else if( module.can.disable() ) {
  109. module.disable();
  110. }
  111. },
  112. setting: function(name, value) {
  113. if(value !== undefined) {
  114. if( $.isPlainObject(name) ) {
  115. $.extend(true, settings, name);
  116. }
  117. else {
  118. settings[name] = value;
  119. }
  120. }
  121. else {
  122. return settings[name];
  123. }
  124. },
  125. internal: function(name, value) {
  126. if(value !== undefined) {
  127. if( $.isPlainObject(name) ) {
  128. $.extend(true, module, name);
  129. }
  130. else {
  131. module[name] = value;
  132. }
  133. }
  134. else {
  135. return module[name];
  136. }
  137. },
  138. debug: function() {
  139. if(settings.debug) {
  140. if(settings.performance) {
  141. module.performance.log(arguments);
  142. }
  143. else {
  144. module.debug = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  145. module.debug.apply(console, arguments);
  146. }
  147. }
  148. },
  149. verbose: function() {
  150. if(settings.verbose && settings.debug) {
  151. if(settings.performance) {
  152. module.performance.log(arguments);
  153. }
  154. else {
  155. module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  156. module.verbose.apply(console, arguments);
  157. }
  158. }
  159. },
  160. error: function() {
  161. module.error = Function.prototype.bind.call(console.error, console, settings.moduleName + ':');
  162. module.error.apply(console, arguments);
  163. },
  164. performance: {
  165. log: function(message) {
  166. var
  167. currentTime,
  168. executionTime,
  169. previousTime
  170. ;
  171. if(settings.performance) {
  172. currentTime = new Date().getTime();
  173. previousTime = time || currentTime;
  174. executionTime = currentTime - previousTime;
  175. time = currentTime;
  176. performance.push({
  177. 'Element' : element,
  178. 'Name' : message[0],
  179. 'Arguments' : [].slice.call(message, 1) || '',
  180. 'Execution Time' : executionTime
  181. });
  182. }
  183. clearTimeout(module.performance.timer);
  184. module.performance.timer = setTimeout(module.performance.display, 100);
  185. },
  186. display: function() {
  187. var
  188. title = settings.moduleName + ':',
  189. totalTime = 0
  190. ;
  191. time = false;
  192. clearTimeout(module.performance.timer);
  193. $.each(performance, function(index, data) {
  194. totalTime += data['Execution Time'];
  195. });
  196. title += ' ' + totalTime + 'ms';
  197. if(moduleSelector) {
  198. title += ' \'' + moduleSelector + '\'';
  199. }
  200. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  201. console.groupCollapsed(title);
  202. if(console.table) {
  203. console.table(performance);
  204. }
  205. else {
  206. $.each(performance, function(index, data) {
  207. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  208. });
  209. }
  210. console.groupEnd();
  211. }
  212. performance = [];
  213. }
  214. },
  215. invoke: function(query, passedArguments, context) {
  216. var
  217. maxDepth,
  218. found,
  219. response
  220. ;
  221. passedArguments = passedArguments || queryArguments;
  222. context = element || context;
  223. if(typeof query == 'string' && instance !== undefined) {
  224. query = query.split(/[\. ]/);
  225. maxDepth = query.length - 1;
  226. $.each(query, function(depth, value) {
  227. var camelCaseValue = (depth != maxDepth)
  228. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  229. : query
  230. ;
  231. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  232. instance = instance[value];
  233. }
  234. else if( $.isPlainObject( instance[camelCaseValue] ) && (depth != maxDepth) ) {
  235. instance = instance[camelCaseValue];
  236. }
  237. else if( instance[value] !== undefined ) {
  238. found = instance[value];
  239. return false;
  240. }
  241. else if( instance[camelCaseValue] !== undefined ) {
  242. found = instance[camelCaseValue];
  243. return false;
  244. }
  245. else {
  246. module.error(error.method);
  247. return false;
  248. }
  249. });
  250. }
  251. if ( $.isFunction( found ) ) {
  252. response = found.apply(context, passedArguments);
  253. }
  254. else if(found !== undefined) {
  255. response = found;
  256. }
  257. if($.isArray(invokedResponse)) {
  258. invokedResponse.push(response);
  259. }
  260. else if(typeof invokedResponse == 'string') {
  261. invokedResponse = [invokedResponse, response];
  262. }
  263. else if(response !== undefined) {
  264. invokedResponse = response;
  265. }
  266. return found;
  267. }
  268. };
  269. if(methodInvoked) {
  270. if(instance === undefined) {
  271. module.initialize();
  272. }
  273. module.invoke(query);
  274. }
  275. else {
  276. if(instance !== undefined) {
  277. module.destroy();
  278. }
  279. module.initialize();
  280. }
  281. })
  282. ;
  283. return (invokedResponse !== undefined)
  284. ? invokedResponse
  285. : this
  286. ;
  287. };
  288. $.fn.checkbox.settings = {
  289. moduleName : 'Checkbox',
  290. namespace : 'checkbox',
  291. verbose : true,
  292. debug : true,
  293. performance : true,
  294. // delegated event context
  295. context : false,
  296. required : 'auto',
  297. onChange : function(){},
  298. onEnable : function(){},
  299. onDisable : function(){},
  300. error : {
  301. method : 'The method you called is not defined.'
  302. },
  303. selector : {
  304. input : 'input',
  305. label : 'label'
  306. },
  307. className : {
  308. radio : 'radio'
  309. }
  310. };
  311. })( jQuery, window , document );