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.

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