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.

513 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. style
  182. ;
  183. if(direction !== className.bottom) {
  184. style = ''
  185. + '<style title="' + namespace + '">'
  186. + 'body.pushed {'
  187. + ' margin-' + direction + ': ' + distance + 'px !important;'
  188. + '}'
  189. + '</style>'
  190. ;
  191. }
  192. $head.append(style);
  193. module.debug('Adding body css to head', $style);
  194. }
  195. },
  196. remove: {
  197. bodyCSS: function() {
  198. module.debug('Removing body css styles', $style);
  199. module.refresh();
  200. $style.remove();
  201. },
  202. active: function() {
  203. $module.removeClass(className.active);
  204. },
  205. pushed: function() {
  206. module.verbose('Removing body push state', module.get.direction());
  207. $body
  208. .removeClass(className[ module.get.direction() ])
  209. .removeClass(className.pushed)
  210. ;
  211. }
  212. },
  213. set: {
  214. active: function() {
  215. $module.addClass(className.active);
  216. },
  217. pushed: function() {
  218. module.verbose('Adding body push state', module.get.direction());
  219. $body
  220. .addClass(className[ module.get.direction() ])
  221. .addClass(className.pushed)
  222. ;
  223. }
  224. },
  225. get: {
  226. direction: function() {
  227. if($module.hasClass(className.top)) {
  228. return className.top;
  229. }
  230. else if($module.hasClass(className.right)) {
  231. return className.right;
  232. }
  233. else if($module.hasClass(className.bottom)) {
  234. return className.bottom;
  235. }
  236. else {
  237. return className.left;
  238. }
  239. },
  240. transitionEvent: function() {
  241. var
  242. element = document.createElement('element'),
  243. transitions = {
  244. 'transition' :'transitionend',
  245. 'OTransition' :'oTransitionEnd',
  246. 'MozTransition' :'transitionend',
  247. 'WebkitTransition' :'webkitTransitionEnd'
  248. },
  249. transition
  250. ;
  251. for(transition in transitions){
  252. if( element.style[transition] !== undefined ){
  253. return transitions[transition];
  254. }
  255. }
  256. }
  257. },
  258. is: {
  259. open: function() {
  260. return $module.is(':animated') || $module.hasClass(className.active);
  261. },
  262. closed: function() {
  263. return !module.is.open();
  264. },
  265. vertical: function() {
  266. return $module.hasClass(className.top);
  267. }
  268. },
  269. setting: function(name, value) {
  270. if( $.isPlainObject(name) ) {
  271. $.extend(true, settings, name);
  272. }
  273. else if(value !== undefined) {
  274. settings[name] = value;
  275. }
  276. else {
  277. return settings[name];
  278. }
  279. },
  280. internal: function(name, value) {
  281. if( $.isPlainObject(name) ) {
  282. $.extend(true, module, name);
  283. }
  284. else if(value !== undefined) {
  285. module[name] = value;
  286. }
  287. else {
  288. return module[name];
  289. }
  290. },
  291. debug: function() {
  292. if(settings.debug) {
  293. if(settings.performance) {
  294. module.performance.log(arguments);
  295. }
  296. else {
  297. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  298. module.debug.apply(console, arguments);
  299. }
  300. }
  301. },
  302. verbose: function() {
  303. if(settings.verbose && settings.debug) {
  304. if(settings.performance) {
  305. module.performance.log(arguments);
  306. }
  307. else {
  308. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  309. module.verbose.apply(console, arguments);
  310. }
  311. }
  312. },
  313. error: function() {
  314. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  315. module.error.apply(console, arguments);
  316. },
  317. performance: {
  318. log: function(message) {
  319. var
  320. currentTime,
  321. executionTime,
  322. previousTime
  323. ;
  324. if(settings.performance) {
  325. currentTime = new Date().getTime();
  326. previousTime = time || currentTime;
  327. executionTime = currentTime - previousTime;
  328. time = currentTime;
  329. performance.push({
  330. 'Element' : element,
  331. 'Name' : message[0],
  332. 'Arguments' : [].slice.call(message, 1) || '',
  333. 'Execution Time' : executionTime
  334. });
  335. }
  336. clearTimeout(module.performance.timer);
  337. module.performance.timer = setTimeout(module.performance.display, 100);
  338. },
  339. display: function() {
  340. var
  341. title = settings.name + ':',
  342. totalTime = 0
  343. ;
  344. time = false;
  345. clearTimeout(module.performance.timer);
  346. $.each(performance, function(index, data) {
  347. totalTime += data['Execution Time'];
  348. });
  349. title += ' ' + totalTime + 'ms';
  350. if(moduleSelector) {
  351. title += ' \'' + moduleSelector + '\'';
  352. }
  353. if($allModules.size() > 1) {
  354. title += ' ' + '(' + $allModules.size() + ')';
  355. }
  356. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  357. console.groupCollapsed(title);
  358. if(console.table) {
  359. console.table(performance);
  360. }
  361. else {
  362. $.each(performance, function(index, data) {
  363. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  364. });
  365. }
  366. console.groupEnd();
  367. }
  368. performance = [];
  369. }
  370. },
  371. invoke: function(query, passedArguments, context) {
  372. var
  373. maxDepth,
  374. found,
  375. response
  376. ;
  377. passedArguments = passedArguments || queryArguments;
  378. context = element || context;
  379. if(typeof query == 'string' && instance !== undefined) {
  380. query = query.split(/[\. ]/);
  381. maxDepth = query.length - 1;
  382. $.each(query, function(depth, value) {
  383. var camelCaseValue = (depth != maxDepth)
  384. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  385. : query
  386. ;
  387. if( $.isPlainObject( instance[camelCaseValue] ) && (depth != maxDepth) ) {
  388. instance = instance[camelCaseValue];
  389. }
  390. else if( instance[camelCaseValue] !== undefined ) {
  391. found = instance[camelCaseValue];
  392. return false;
  393. }
  394. else if( $.isPlainObject( instance[value] ) && (depth != maxDepth) ) {
  395. instance = instance[value];
  396. }
  397. else if( instance[value] !== undefined ) {
  398. found = instance[value];
  399. return false;
  400. }
  401. else {
  402. module.error(error.method, query);
  403. return false;
  404. }
  405. });
  406. }
  407. if ( $.isFunction( found ) ) {
  408. response = found.apply(context, passedArguments);
  409. }
  410. else if(found !== undefined) {
  411. response = found;
  412. }
  413. if($.isArray(returnedValue)) {
  414. returnedValue.push(response);
  415. }
  416. else if(returnedValue !== undefined) {
  417. returnedValue = [returnedValue, response];
  418. }
  419. else if(response !== undefined) {
  420. returnedValue = response;
  421. }
  422. return found;
  423. }
  424. };
  425. if(methodInvoked) {
  426. if(instance === undefined) {
  427. module.initialize();
  428. }
  429. module.invoke(query);
  430. }
  431. else {
  432. if(instance !== undefined) {
  433. module.destroy();
  434. }
  435. module.initialize();
  436. }
  437. })
  438. ;
  439. return (returnedValue !== undefined)
  440. ? returnedValue
  441. : this
  442. ;
  443. };
  444. $.fn.sidebar.settings = {
  445. name : 'Sidebar',
  446. namespace : 'sidebar',
  447. verbose : true,
  448. debug : true,
  449. performance : true,
  450. useCSS : true,
  451. exclusive : true,
  452. overlay : false,
  453. duration : 300,
  454. onChange : function(){},
  455. onShow : function(){},
  456. onHide : function(){},
  457. className: {
  458. active : 'active',
  459. pushed : 'pushed',
  460. top : 'top',
  461. left : 'left',
  462. right : 'right',
  463. bottom : 'bottom'
  464. },
  465. selector: {
  466. sidebar: '.ui.sidebar'
  467. },
  468. error : {
  469. method : 'The method you called is not defined.',
  470. notFound : 'There were no elements that matched the specified selector'
  471. }
  472. };
  473. })( jQuery, window , document );