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
  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. object = instance,
  376. maxDepth,
  377. found,
  378. response
  379. ;
  380. passedArguments = passedArguments || queryArguments;
  381. context = element || context;
  382. if(typeof query == 'string' && object !== undefined) {
  383. query = query.split(/[\. ]/);
  384. maxDepth = query.length - 1;
  385. $.each(query, function(depth, value) {
  386. var camelCaseValue = (depth != maxDepth)
  387. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  388. : query
  389. ;
  390. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  391. object = object[camelCaseValue];
  392. }
  393. else if( object[camelCaseValue] !== undefined ) {
  394. found = object[camelCaseValue];
  395. return false;
  396. }
  397. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  398. object = object[value];
  399. }
  400. else if( object[value] !== undefined ) {
  401. found = object[value];
  402. return false;
  403. }
  404. else {
  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 );