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.

492 lines
14 KiB

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