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.

445 lines
13 KiB

  1. /* ******************************
  2. Semantic Module: Dropdown
  3. Author: Jack Lukic
  4. Notes: First Commit May 25, 2013
  5. ****************************** */
  6. ;(function ( $, window, document, undefined ) {
  7. $.fn.sidebar = function(parameters) {
  8. var
  9. $allModules = $(this),
  10. settings = ( $.isPlainObject(parameters) )
  11. ? $.extend(true, {}, $.fn.sidebar.settings, parameters)
  12. : $.fn.sidebar.settings,
  13. selector = settings.selector,
  14. className = settings.className,
  15. namespace = settings.namespace,
  16. error = settings.error,
  17. eventNamespace = '.' + namespace,
  18. moduleNamespace = 'module-' + namespace,
  19. moduleSelector = $allModules.selector || '',
  20. time = new Date().getTime(),
  21. performance = [],
  22. query = arguments[0],
  23. methodInvoked = (typeof query == 'string'),
  24. queryArguments = [].slice.call(arguments, 1),
  25. invokedResponse
  26. ;
  27. $allModules
  28. .each(function() {
  29. var
  30. $module = $(this),
  31. $body = $('body'),
  32. $head = $('head'),
  33. $style = $('style[title=' + namespace + ']'),
  34. element = this,
  35. instance = $module.data(moduleNamespace),
  36. module
  37. ;
  38. module = {
  39. initialize: function() {
  40. module.debug('Initializing sidebar', $module);
  41. module.instantiate();
  42. },
  43. instantiate: function() {
  44. module.verbose('Storing instance of module', module);
  45. instance = module;
  46. $module
  47. .data(moduleNamespace, module)
  48. ;
  49. },
  50. destroy: function() {
  51. module.verbose('Destroying previous module for', $module);
  52. $module
  53. .off(eventNamespace)
  54. .removeData(moduleNamespace)
  55. ;
  56. },
  57. refresh: function() {
  58. module.verbose('Refreshing selector cache');
  59. $style = $('style[title=' + namespace + ']');
  60. },
  61. attach: {
  62. events: function(selector, event) {
  63. var
  64. $toggle = $(selector)
  65. ;
  66. event = $.isFunction(module[event])
  67. ? module[event]
  68. : module.toggle
  69. ;
  70. if($toggle.size() > 0) {
  71. module.debug('Attaching sidebar events to element', selector, event);
  72. $toggle
  73. .off(eventNamespace)
  74. .on('click' + eventNamespace, event)
  75. ;
  76. }
  77. else {
  78. module.error(error.notFound);
  79. }
  80. }
  81. },
  82. show: function() {
  83. module.debug('Showing sidebar');
  84. if(module.is.closed()) {
  85. module.set.active();
  86. if(!settings.overlay) {
  87. module.add.bodyCSS();
  88. module.set.pushed();
  89. }
  90. }
  91. else {
  92. module.debug('Sidebar is already visible');
  93. }
  94. },
  95. hide: function() {
  96. if(module.is.open()) {
  97. module.remove.active();
  98. if(!settings.overlay) {
  99. module.remove.bodyCSS();
  100. module.remove.pushed();
  101. }
  102. }
  103. },
  104. toggle: function() {
  105. if(module.is.closed()) {
  106. module.show();
  107. }
  108. else {
  109. module.hide();
  110. }
  111. },
  112. add: {
  113. bodyCSS: function() {
  114. var
  115. style = '',
  116. direction = module.get.direction(),
  117. moduleSize = (module.is.vertical())
  118. ? $module.outerHeight()
  119. : $module.outerWidth()
  120. ;
  121. style = ''
  122. + '<style type="text/css" title="' + namespace + '">'
  123. + 'body.pushed {'
  124. + ' padding-' + direction + ': ' + moduleSize + 'px !important;'
  125. + '}'
  126. + '</style>'
  127. ;
  128. $head.append(style);
  129. module.refresh();
  130. module.debug('Adding body css to head', $style);
  131. $style[0].disabled = false;
  132. }
  133. },
  134. remove: {
  135. bodyCSS: function() {
  136. module.debug('Removing body css styles', $style);
  137. $style.remove();
  138. },
  139. active: function() {
  140. $module.removeClass(className.active);
  141. },
  142. pushed: function() {
  143. module.verbose('Removing body push state', module.get.direction());
  144. $body
  145. .removeClass(className[ module.get.direction() ])
  146. .removeClass(className.pushed)
  147. ;
  148. }
  149. },
  150. set: {
  151. active: function() {
  152. $module.addClass(className.active);
  153. },
  154. pushed: function() {
  155. module.verbose('Adding body push state', module.get.direction());
  156. $body
  157. .addClass(className[ module.get.direction() ])
  158. .addClass(className.pushed)
  159. ;
  160. }
  161. },
  162. get: {
  163. direction: function() {
  164. if($module.hasClass('top')) {
  165. return 'top';
  166. }
  167. else if($module.hasClass('right')) {
  168. return 'right';
  169. }
  170. else if($module.hasClass('bottom')) {
  171. return 'bottom';
  172. }
  173. else {
  174. return 'left';
  175. }
  176. },
  177. transitionEvent: function() {
  178. var
  179. element = document.createElement('element'),
  180. transitions = {
  181. 'transition' :'transitionend',
  182. 'OTransition' :'oTransitionEnd',
  183. 'MozTransition' :'transitionend',
  184. 'WebkitTransition' :'webkitTransitionEnd'
  185. },
  186. transition
  187. ;
  188. for(transition in transitions){
  189. if( element.style[transition] !== undefined ){
  190. return transitions[transition];
  191. }
  192. }
  193. }
  194. },
  195. is: {
  196. open: function() {
  197. return $module.is(':animated') || $module.hasClass(className.active);
  198. },
  199. closed: function() {
  200. return !module.is.open();
  201. },
  202. vertical: function() {
  203. return $module.hasClass(className.top);
  204. }
  205. },
  206. setting: function(name, value) {
  207. if(value !== undefined) {
  208. if( $.isPlainObject(name) ) {
  209. $.extend(true, settings, name);
  210. }
  211. else {
  212. settings[name] = value;
  213. }
  214. }
  215. else {
  216. return settings[name];
  217. }
  218. },
  219. internal: function(name, value) {
  220. if(value !== undefined) {
  221. if( $.isPlainObject(name) ) {
  222. $.extend(true, module, name);
  223. }
  224. else {
  225. module[name] = value;
  226. }
  227. }
  228. else {
  229. return module[name];
  230. }
  231. },
  232. debug: function() {
  233. if(settings.debug) {
  234. if(settings.performance) {
  235. module.performance.log(arguments);
  236. }
  237. else {
  238. module.debug = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  239. module.debug.apply(console, arguments);
  240. }
  241. }
  242. },
  243. verbose: function() {
  244. if(settings.verbose && settings.debug) {
  245. if(settings.performance) {
  246. module.performance.log(arguments);
  247. }
  248. else {
  249. module.verbose = Function.prototype.bind.call(console.info, console, settings.moduleName + ':');
  250. module.verbose.apply(console, arguments);
  251. }
  252. }
  253. },
  254. error: function() {
  255. module.error = Function.prototype.bind.call(console.error, console, settings.moduleName + ':');
  256. module.error.apply(console, arguments);
  257. },
  258. performance: {
  259. log: function(message) {
  260. var
  261. currentTime,
  262. executionTime,
  263. previousTime
  264. ;
  265. if(settings.performance) {
  266. currentTime = new Date().getTime();
  267. previousTime = time || currentTime;
  268. executionTime = currentTime - previousTime;
  269. time = currentTime;
  270. performance.push({
  271. 'Element' : element,
  272. 'Name' : message[0],
  273. 'Arguments' : [].slice.call(message, 1) || '',
  274. 'Execution Time' : executionTime
  275. });
  276. }
  277. clearTimeout(module.performance.timer);
  278. module.performance.timer = setTimeout(module.performance.display, 100);
  279. },
  280. display: function() {
  281. var
  282. title = settings.moduleName + ':',
  283. totalTime = 0
  284. ;
  285. time = false;
  286. clearTimeout(module.performance.timer);
  287. $.each(performance, function(index, data) {
  288. totalTime += data['Execution Time'];
  289. });
  290. title += ' ' + totalTime + 'ms';
  291. if(moduleSelector) {
  292. title += ' \'' + moduleSelector + '\'';
  293. }
  294. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  295. console.groupCollapsed(title);
  296. if(console.table) {
  297. console.table(performance);
  298. }
  299. else {
  300. $.each(performance, function(index, data) {
  301. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  302. });
  303. }
  304. console.groupEnd();
  305. }
  306. performance = [];
  307. }
  308. },
  309. invoke: function(query, passedArguments, context) {
  310. var
  311. maxDepth,
  312. found,
  313. response
  314. ;
  315. passedArguments = passedArguments || queryArguments;
  316. context = element || context;
  317. if(typeof query == 'string' && instance !== undefined) {
  318. query = query.split(/[\. ]/);
  319. maxDepth = query.length - 1;
  320. $.each(query, function(depth, value) {
  321. var camelCaseValue = (depth != maxDepth)
  322. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  323. : query
  324. ;
  325. if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  326. instance = instance[value];
  327. }
  328. else if( $.isPlainObject( instance[camelCaseValue] ) && (depth != maxDepth) ) {
  329. instance = instance[camelCaseValue];
  330. }
  331. else if( instance[value] !== undefined ) {
  332. found = instance[value];
  333. return false;
  334. }
  335. else if( instance[camelCaseValue] !== undefined ) {
  336. found = instance[camelCaseValue];
  337. return false;
  338. }
  339. else {
  340. module.error(error.method);
  341. return false;
  342. }
  343. });
  344. }
  345. if ( $.isFunction( found ) ) {
  346. response = found.apply(context, passedArguments);
  347. }
  348. else if(found !== undefined) {
  349. response = found;
  350. }
  351. if($.isArray(invokedResponse)) {
  352. invokedResponse.push(response);
  353. }
  354. else if(typeof invokedResponse == 'string') {
  355. invokedResponse = [invokedResponse, response];
  356. }
  357. else if(response !== undefined) {
  358. invokedResponse = response;
  359. }
  360. return found;
  361. }
  362. };
  363. if(methodInvoked) {
  364. if(instance === undefined) {
  365. module.initialize();
  366. }
  367. module.invoke(query);
  368. }
  369. else {
  370. if(instance !== undefined) {
  371. module.destroy();
  372. }
  373. module.initialize();
  374. }
  375. })
  376. ;
  377. return (invokedResponse !== undefined)
  378. ? invokedResponse
  379. : this
  380. ;
  381. };
  382. $.fn.sidebar.settings = {
  383. moduleName : 'Sidebar',
  384. namespace : 'sidebar',
  385. verbose : true,
  386. debug : true,
  387. performance : true,
  388. overlay : false,
  389. side : 'left',
  390. duration : 500,
  391. onChange : function(){},
  392. onShow : function(){},
  393. onHide : function(){},
  394. className: {
  395. active : 'active',
  396. pushed : 'pushed',
  397. top : 'top',
  398. left : 'left',
  399. right : 'right',
  400. bottom : 'bottom'
  401. },
  402. error : {
  403. method : 'The method you called is not defined.',
  404. notFound : 'There were no elements that matched the specified selector'
  405. }
  406. };
  407. })( jQuery, window , document );