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.

343 lines
9.5 KiB

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