/* * jQuery mmenu offCanvas addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ (function( $ ) { var _PLUGIN_ = 'mmenu', _ADDON_ = 'offCanvas'; $[ _PLUGIN_ ].addons[ _ADDON_ ] = { // setup: fired once per menu setup: function() { if ( !this.opts[ _ADDON_ ] ) { return; } var that = this, opts = this.opts[ _ADDON_ ], conf = this.conf[ _ADDON_ ]; glbl = $[ _PLUGIN_ ].glbl; // Add methods to api this._api = $.merge( this._api, [ 'open', 'close', 'setPage' ] ); // Debug positioning if ( opts.position == 'top' || opts.position == 'bottom' ) { opts.zposition = 'front'; } // Extend configuration if ( typeof conf.pageSelector != 'string' ) { conf.pageSelector = '> ' + conf.pageNodetype; } glbl.$allMenus = ( glbl.$allMenus || $() ).add( this.$menu ); // Setup the menu this.vars.opened = false; var clsn = [ _c.offcanvas ]; if ( opts.position != 'left' ) { clsn.push( _c.mm( opts.position ) ); } if ( opts.zposition != 'back' ) { clsn.push( _c.mm( opts.zposition ) ); } this.$menu .addClass( clsn.join( ' ' ) ) .parent() .removeClass( _c.wrapper ); // Setup the page this.setPage( glbl.$page ); // Setup the UI blocker and the window this._initBlocker(); this[ '_initWindow_' + _ADDON_ ](); // Append to the body this.$menu[ conf.menuInjectMethod + 'To' ]( conf.menuWrapperSelector ); }, // add: fired once per page load add: function() { _c = $[ _PLUGIN_ ]._c; _d = $[ _PLUGIN_ ]._d; _e = $[ _PLUGIN_ ]._e; _c.add( 'offcanvas slideout modal background opening blocker page' ); _d.add( 'style' ); _e.add( 'resize' ); }, // clickAnchor: prevents default behavior when clicking an anchor clickAnchor: function( $a, inMenu ) { if ( !this.opts[ _ADDON_ ] ) { return false; } // Open menu var id = this.$menu.attr( 'id' ); if ( id && id.length ) { if ( this.conf.clone ) { id = _c.umm( id ); } if ( $a.is( '[href="#' + id + '"]' ) ) { this.open(); return true; } } // Close menu if ( !glbl.$page ) { return; } var id = glbl.$page.first().attr( 'id' ); if ( id && id.length ) { if ( $a.is( '[href="#' + id + '"]' ) ) { this.close(); return true; } } return false; } }; // Default options and configuration $[ _PLUGIN_ ].defaults[ _ADDON_ ] = { position : 'left', zposition : 'back', modal : false, moveBackground : true }; $[ _PLUGIN_ ].configuration[ _ADDON_ ] = { pageNodetype : 'div', pageSelector : null, wrapPageIfNeeded : true, menuWrapperSelector : 'body', menuInjectMethod : 'prepend' }; // Methods $[ _PLUGIN_ ].prototype.open = function() { if ( this.vars.opened ) { return; } var that = this; this._openSetup(); // Without the timeout, the animation won't work because the element had display: none; setTimeout( function() { that._openFinish(); }, this.conf.openingInterval ); this.trigger( 'open' ); }; $[ _PLUGIN_ ].prototype._openSetup = function() { var that = this; // Close other menus this.closeAllOthers(); // Store style and position glbl.$page.each( function() { $(this).data( _d.style, $(this).attr( 'style' ) || '' ); } ); // Trigger window-resize to measure height glbl.$wndw.trigger( _e.resize + '-offcanvas', [ true ] ); var clsn = [ _c.opened ]; // Add options if ( this.opts[ _ADDON_ ].modal ) { clsn.push( _c.modal ); } if ( this.opts[ _ADDON_ ].moveBackground ) { clsn.push( _c.background ); } if ( this.opts[ _ADDON_ ].position != 'left' ) { clsn.push( _c.mm( this.opts[ _ADDON_ ].position ) ); } if ( this.opts[ _ADDON_ ].zposition != 'back' ) { clsn.push( _c.mm( this.opts[ _ADDON_ ].zposition ) ); } if ( this.opts.extensions ) { clsn.push( this.opts.extensions ); } glbl.$html.addClass( clsn.join( ' ' ) ); // Open setTimeout(function(){ that.vars.opened = true; },this.conf.openingInterval); this.$menu.addClass( _c.current + ' ' + _c.opened ); }; $[ _PLUGIN_ ].prototype._openFinish = function() { var that = this; // Callback this.__transitionend( glbl.$page.first(), function() { that.trigger( 'opened' ); }, this.conf.transitionDuration ); // Opening glbl.$html.addClass( _c.opening ); this.trigger( 'opening' ); }; $[ _PLUGIN_ ].prototype.close = function() { if ( !this.vars.opened ) { return; } var that = this; // Callback this.__transitionend( glbl.$page.first(), function() { that.$menu .removeClass( _c.current ) .removeClass( _c.opened ); glbl.$html .removeClass( _c.opened ) .removeClass( _c.modal ) .removeClass( _c.background ) .removeClass( _c.mm( that.opts[ _ADDON_ ].position ) ) .removeClass( _c.mm( that.opts[ _ADDON_ ].zposition ) ); if ( that.opts.extensions ) { glbl.$html.removeClass( that.opts.extensions ); } // Restore style and position glbl.$page.each( function() { $(this).attr( 'style', $(this).data( _d.style ) ); } ); that.vars.opened = false; that.trigger( 'closed' ); }, this.conf.transitionDuration ); // Closing glbl.$html.removeClass( _c.opening ); this.trigger( 'close' ); this.trigger( 'closing' ); }; $[ _PLUGIN_ ].prototype.closeAllOthers = function() { glbl.$allMenus .not( this.$menu ) .each( function() { var api = $(this).data( _PLUGIN_ ); if ( api && api.close ) { api.close(); } } ); } $[ _PLUGIN_ ].prototype.setPage = function( $page ) { var that = this, conf = this.conf[ _ADDON_ ]; if ( !$page || !$page.length ) { $page = glbl.$body.find( conf.pageSelector ); if ( $page.length > 1 && conf.wrapPageIfNeeded ) { $page = $page.wrapAll( '<' + this.conf[ _ADDON_ ].pageNodetype + ' />' ).parent(); } } $page.each( function() { $(this).attr( 'id', $(this).attr( 'id' ) || that.__getUniqueId() ); } ); $page.addClass( _c.page + ' ' + _c.slideout ); glbl.$page = $page; this.trigger( 'setPage', $page ); }; $[ _PLUGIN_ ].prototype[ '_initWindow_' + _ADDON_ ] = function() { // Prevent tabbing glbl.$wndw .off( _e.keydown + '-offcanvas' ) .on( _e.keydown + '-offcanvas', function( e ) { if ( glbl.$html.hasClass( _c.opened ) ) { if ( e.keyCode == 9 ) { e.preventDefault(); return false; } } } ); // Set page min-height to window height var _h = 0; glbl.$wndw .off( _e.resize + '-offcanvas' ) .on( _e.resize + '-offcanvas', function( e, force ) { if ( glbl.$page.length == 1 ) { if ( force || glbl.$html.hasClass( _c.opened ) ) { var nh = glbl.$wndw.height(); if ( force || nh != _h ) { _h = nh; glbl.$page.css( 'minHeight', nh ); } } } } ); }; $[ _PLUGIN_ ].prototype._initBlocker = function() { var that = this; if ( !glbl.$blck ) { glbl.$blck = $( '
' ); } glbl.$blck .appendTo( glbl.$body ) .off( _e.touchstart + '-offcanvas ' + _e.touchmove + '-offcanvas' ) .on( _e.touchstart + '-offcanvas ' + _e.touchmove + '-offcanvas', function( e ) { e.preventDefault(); e.stopPropagation(); glbl.$blck.trigger( _e.mousedown + '-offcanvas' ); } ) .off( _e.mousedown + '-offcanvas' ) .on( _e.mousedown + '-offcanvas', function( e ) { e.preventDefault(); if ( !glbl.$html.hasClass( _c.modal ) ) { that.closeAllOthers(); that.close(); } } ); }; var _c, _d, _e, glbl; })( jQuery );