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.

259 lines
7.5 KiB

  1. /*
  2. * Sidr
  3. * https://github.com/artberri/sidr
  4. *
  5. * Copyright (c) 2013 Alberto Varela
  6. * Licensed under the MIT license.
  7. */
  8. ;(function( $ ){
  9. var sidrMoving = false,
  10. sidrOpened = false;
  11. // Private methods
  12. var privateMethods = {
  13. // Check for valids urls
  14. // From : http://stackoverflow.com/questions/5717093/check-if-a-javascript-string-is-an-url
  15. isUrl: function (str) {
  16. var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
  17. '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
  18. '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
  19. '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
  20. '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
  21. '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  22. if(!pattern.test(str)) {
  23. return false;
  24. } else {
  25. return true;
  26. }
  27. },
  28. // Loads the content into the menu bar
  29. loadContent: function($menu, content) {
  30. $menu.html(content);
  31. },
  32. // Add sidr prefixes
  33. addPrefix: function($element) {
  34. var elementId = $element.attr('id'),
  35. elementClass = $element.attr('class');
  36. if(typeof elementId === 'string' && '' !== elementId) {
  37. $element.attr('id', elementId.replace(/([A-Za-z0-9_.\-]+)/g, 'sidr-id-$1'));
  38. }
  39. if(typeof elementClass === 'string' && '' !== elementClass && 'sidr-inner' !== elementClass) {
  40. $element.attr('class', elementClass.replace(/([A-Za-z0-9_.\-]+)/g, 'sidr-class-$1'));
  41. }
  42. $element.removeAttr('style');
  43. },
  44. execute: function(action, name, callback) {
  45. // Check arguments
  46. if(typeof name === 'function') {
  47. callback = name;
  48. name = 'sidr';
  49. }
  50. else if(!name) {
  51. name = 'sidr';
  52. }
  53. // Declaring
  54. var $menu = $('#' + name),
  55. $body = $($menu.data('body')),
  56. $html = $('html'),
  57. menuWidth = $menu.outerWidth(true),
  58. speed = $menu.data('speed'),
  59. side = $menu.data('side'),
  60. bodyAnimation,
  61. menuAnimation,
  62. scrollTop;
  63. // Open Sidr
  64. if('open' === action || ('toogle' === action && !$menu.is(':visible'))) {
  65. // Check if we can open it
  66. if( $menu.is(':visible') || sidrMoving ) {
  67. return;
  68. }
  69. // If another menu opened close first
  70. if(sidrOpened !== false) {
  71. methods.close(sidrOpened, function() {
  72. methods.open(name);
  73. });
  74. return;
  75. }
  76. // Lock sidr
  77. sidrMoving = true;
  78. // Left or right?
  79. if(side === 'left') {
  80. bodyAnimation = {left: menuWidth + 'px'};
  81. menuAnimation = {left: '0px'};
  82. }
  83. else {
  84. bodyAnimation = {right: menuWidth + 'px'};
  85. menuAnimation = {right: '0px'};
  86. }
  87. // Prepare page
  88. scrollTop = $html.scrollTop();
  89. $html.css('overflow-x', 'hidden').scrollTop(scrollTop);
  90. // Open menu
  91. $body.css({
  92. position: 'absolute',
  93. width: $body.width()
  94. }).animate(bodyAnimation, speed);
  95. $menu.css('display', 'block').animate(menuAnimation, speed, function() {
  96. sidrMoving = false;
  97. sidrOpened = name;
  98. // Callback
  99. if(typeof callback === 'function') {
  100. callback(name);
  101. }
  102. });
  103. }
  104. // Close Sidr
  105. else {
  106. // Check if we can close it
  107. if( !$menu.is(':visible') || sidrMoving ) {
  108. return;
  109. }
  110. // Lock sidr
  111. sidrMoving = true;
  112. // Right or left menu?
  113. if(side === 'left') {
  114. bodyAnimation = {left: 0};
  115. menuAnimation = {left: '-' + menuWidth + 'px'};
  116. }
  117. else {
  118. bodyAnimation = {right: 0};
  119. menuAnimation = {right: '-' + menuWidth + 'px'};
  120. }
  121. // Close menu
  122. scrollTop = $html.scrollTop();
  123. $html.removeAttr('style').scrollTop(scrollTop);
  124. $body.animate(bodyAnimation, speed);
  125. $menu.animate(menuAnimation, speed, function() {
  126. $menu.removeAttr('style');
  127. $body.removeAttr('style');
  128. $('html').removeAttr('style');
  129. sidrMoving = false;
  130. sidrOpened = false;
  131. // Callback
  132. if(typeof callback === 'function') {
  133. callback(name);
  134. }
  135. });
  136. }
  137. }
  138. };
  139. // Sidr public methods
  140. var methods = {
  141. open: function(name, callback) {
  142. privateMethods.execute('open', name, callback);
  143. },
  144. close: function(name, callback) {
  145. privateMethods.execute('close', name, callback);
  146. },
  147. toogle: function(name, callback) {
  148. privateMethods.execute('toogle', name, callback);
  149. }
  150. };
  151. $.sidr = function( method ) {
  152. if ( methods[method] ) {
  153. return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
  154. } else if ( typeof method === 'function' || typeof method === 'string' || ! method ) {
  155. return methods.toogle.apply( this, arguments );
  156. } else {
  157. $.error( 'Method ' + method + ' does not exist on jQuery.sidr' );
  158. }
  159. };
  160. $.fn.sidr = function( options ) {
  161. var settings = $.extend( {
  162. name : 'sidr', // Name for the 'sidr'
  163. speed : 200, // Accepts standard jQuery effects speeds (i.e. fast, normal or milliseconds)
  164. side : 'left', // Accepts 'left' or 'right'
  165. source : null, // Override the source of the content.
  166. renaming : true, // The ids and classes will be prepended with a prefix when loading existent content
  167. body : 'body' // Page container selector,
  168. }, options);
  169. var name = settings.name,
  170. $sideMenu = $('#' + name);
  171. // If the side menu do not exist create it
  172. if( $sideMenu.length === 0 ) {
  173. $sideMenu = $('<div />')
  174. .attr('id', name)
  175. .appendTo($('body'));
  176. }
  177. // Adding styles and options
  178. $sideMenu
  179. .addClass('sidr')
  180. .addClass(settings.side)
  181. .data({
  182. speed : settings.speed,
  183. side : settings.side,
  184. body : settings.body
  185. });
  186. // The menu content
  187. if(typeof settings.source === 'function') {
  188. var newContent = settings.source(name);
  189. privateMethods.loadContent($sideMenu, newContent);
  190. }
  191. else if(typeof settings.source === 'string' && privateMethods.isUrl(settings.source)) {
  192. $.get(settings.source, function(data) {
  193. privateMethods.loadContent($sideMenu, data);
  194. });
  195. }
  196. else if(typeof settings.source === 'string') {
  197. var htmlContent = '',
  198. selectors = settings.source.split(',');
  199. $.each(selectors, function(index, element) {
  200. htmlContent += '<div class="sidr-inner">' + $(element).html() + '</div>';
  201. });
  202. // Renaming ids and classes
  203. if(settings.renaming) {
  204. var $htmlContent = $('<div />').html(htmlContent);
  205. $htmlContent.find('*').each(function(index, element) {
  206. var $element = $(element);
  207. privateMethods.addPrefix($element);
  208. });
  209. htmlContent = $htmlContent.html();
  210. }
  211. privateMethods.loadContent($sideMenu, htmlContent);
  212. }
  213. else if(settings.source !== null) {
  214. $.error('Invalid Sidr Source');
  215. }
  216. return this.each(function(){
  217. var $this = $(this),
  218. data = $this.data('sidr');
  219. // If the plugin hasn't been initialized yet
  220. if ( ! data ) {
  221. $this.data('sidr', name);
  222. $this.click(function(e) {
  223. e.preventDefault();
  224. methods.toogle(name);
  225. });
  226. }
  227. });
  228. };
  229. })( jQuery );