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.

516 lines
15 KiB

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