/* * Sidr * https://github.com/artberri/sidr * * Copyright (c) 2013 Alberto Varela * Licensed under the MIT license. */ ;(function( $ ){ var sidrMoving = false, sidrOpened = false; // Private methods var privateMethods = { // Check for valids urls // From : http://stackoverflow.com/questions/5717093/check-if-a-javascript-string-is-an-url isUrl: function (str) { var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string '(\\#[-a-z\\d_]*)?$','i'); // fragment locator if(!pattern.test(str)) { return false; } else { return true; } }, // Loads the content into the menu bar loadContent: function($menu, content) { $menu.html(content); }, // Add sidr prefixes addPrefix: function($element) { var elementId = $element.attr('id'), elementClass = $element.attr('class'); if(typeof elementId === 'string' && '' !== elementId) { $element.attr('id', elementId.replace(/([A-Za-z0-9_.\-]+)/g, 'sidr-id-$1')); } if(typeof elementClass === 'string' && '' !== elementClass && 'sidr-inner' !== elementClass) { $element.attr('class', elementClass.replace(/([A-Za-z0-9_.\-]+)/g, 'sidr-class-$1')); } $element.removeAttr('style'); }, execute: function(action, name, callback) { // Check arguments if(typeof name === 'function') { callback = name; name = 'sidr'; } else if(!name) { name = 'sidr'; } // Declaring var $menu = $('#' + name), $body = $($menu.data('body')), $html = $('html'), menuWidth = $menu.outerWidth(true), speed = $menu.data('speed'), side = $menu.data('side'), displace = $menu.data('displace'), onOpen = $menu.data('onOpen'), onClose = $menu.data('onClose'), bodyAnimation, menuAnimation, scrollTop, bodyClass = (name === 'sidr' ? 'sidr-open' : 'sidr-open ' + name + '-open'); // Open Sidr if('open' === action || ('toggle' === action && !$menu.is(':visible'))) { // Check if we can open it if( $menu.is(':visible') || sidrMoving ) { return; } // If another menu opened close first if(sidrOpened !== false) { methods.close(sidrOpened, function() { methods.open(name); }); return; } // Lock sidr sidrMoving = true; // Left or right? if(side === 'left') { bodyAnimation = {left: menuWidth + 'px'}; menuAnimation = {left: '0px'}; } else { bodyAnimation = {right: menuWidth + 'px'}; menuAnimation = {right: '0px'}; } // Prepare page if container is body if($body.is('body')){ scrollTop = $html.scrollTop(); $html.css('overflow-x', 'hidden').scrollTop(scrollTop); } // Open menu if(displace){ $body.addClass('sidr-animating').css({ width: $body.width(), position: 'absolute' }).animate(bodyAnimation, speed, function() { $(this).addClass(bodyClass); }); } else { setTimeout(function() { $(this).addClass(bodyClass); }, speed); } $menu.css('display', 'block').animate(menuAnimation, speed, function() { sidrMoving = false; sidrOpened = name; // Callback if(typeof callback === 'function') { callback(name); } $body.removeClass('sidr-animating'); }); // onOpen callback onOpen(); } // Close Sidr else { // Check if we can close it if( !$menu.is(':visible') || sidrMoving ) { return; } // Lock sidr sidrMoving = true; // Right or left menu? if(side === 'left') { bodyAnimation = {left: 0}; menuAnimation = {left: '-' + menuWidth + 'px'}; } else { bodyAnimation = {right: 0}; menuAnimation = {right: '-' + menuWidth + 'px'}; } // Close menu if($body.is('body')){ scrollTop = $html.scrollTop(); $html.removeAttr('style').scrollTop(scrollTop); } $body.addClass('sidr-animating').animate(bodyAnimation, speed).removeClass(bodyClass); $menu.animate(menuAnimation, speed, function() { $menu.removeAttr('style').hide(); $body.removeAttr('style'); $('html').removeAttr('style'); sidrMoving = false; sidrOpened = false; // Callback if(typeof callback === 'function') { callback(name); } $body.removeClass('sidr-animating'); }); // onClose callback onClose(); } } }; // Sidr public methods var methods = { open: function(name, callback) { privateMethods.execute('open', name, callback); }, close: function(name, callback) { privateMethods.execute('close', name, callback); }, toggle: function(name, callback) { privateMethods.execute('toggle', name, callback); }, // I made a typo, so I mantain this method to keep backward compatibilty with 1.1.1v and previous toogle: function(name, callback) { privateMethods.execute('toggle', name, callback); } }; $.sidr = function( method ) { if ( methods[method] ) { return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof method === 'function' || typeof method === 'string' || ! method ) { return methods.toggle.apply( this, arguments ); } else { $.error( 'Method ' + method + ' does not exist on jQuery.sidr' ); } }; $.fn.sidr = function( options ) { var settings = $.extend( { name : 'sidr', // Name for the 'sidr' speed : 200, // Accepts standard jQuery effects speeds (i.e. fast, normal or milliseconds) side : 'left', // Accepts 'left' or 'right' source : null, // Override the source of the content. renaming : true, // The ids and classes will be prepended with a prefix when loading existent content body : 'body', // Page container selector, displace: true, // Displace the body content or not onOpen : function() {}, // Callback when sidr opened onClose : function() {} // Callback when sidr closed }, options); var name = settings.name, $sideMenu = $('#' + name); // If the side menu do not exist create it if( $sideMenu.length === 0 ) { $sideMenu = $('
') .attr('id', name) .appendTo($('body')); } // Adding styles and options $sideMenu .addClass('sidr') .addClass(settings.side) .data({ speed : settings.speed, side : settings.side, body : settings.body, displace : settings.displace, onOpen : settings.onOpen, onClose : settings.onClose }); // The menu content if(typeof settings.source === 'function') { var newContent = settings.source(name); privateMethods.loadContent($sideMenu, newContent); } else if(typeof settings.source === 'string' && privateMethods.isUrl(settings.source)) { $.get(settings.source, function(data) { privateMethods.loadContent($sideMenu, data); }); } else if(typeof settings.source === 'string') { var htmlContent = '', selectors = settings.source.split(','); $.each(selectors, function(index, element) { htmlContent += '
' + $(element).html() + '
'; }); // Renaming ids and classes if(settings.renaming) { var $htmlContent = $('
').html(htmlContent); $htmlContent.find('*').each(function(index, element) { var $element = $(element); privateMethods.addPrefix($element); }); htmlContent = $htmlContent.html(); } privateMethods.loadContent($sideMenu, htmlContent); } else if(settings.source !== null) { $.error('Invalid Sidr Source'); } return this.each(function(){ var $this = $(this), data = $this.data('sidr'); // If the plugin hasn't been initialized yet if ( ! data ) { $this.data('sidr', name); if('ontouchstart' in document.documentElement) { $this.bind('touchstart', function(e) { var theEvent = e.originalEvent.touches[0]; this.touched = e.timeStamp; }); $this.bind('touchend', function(e) { var delta = Math.abs(e.timeStamp - this.touched); if(delta < 200) { e.preventDefault(); methods.toggle(name); } }); } else { $this.click(function(e) { e.preventDefault(); methods.toggle(name); }); } } }); }; })( jQuery );