/*
* jquery mmenu v4.1.1
* @requires jquery 1.7.0 or later
*
* mmenu.frebsite.nl
*
* copyright (c) fred heusschen
* www.frebsite.nl
*
* dual licensed under the mit and gpl licenses.
* http://en.wikipedia.org/wiki/mit_license
* http://en.wikipedia.org/wiki/gnu_general_public_license
*/
(function( $ ) {
var _plugin_ = 'mmenu',
_version_ = '4.1.1';
// plugin already excists
if ( $[ _plugin_ ] )
{
return;
}
// global variables
var glbl = {
$wndw: null,
$html: null,
$body: null,
$page: null,
$blck: null,
$allmenus: null,
$scrolltopnode: null
};
var _c = {}, _e = {}, _d = {},
_serialnr = 0;
$[ _plugin_ ] = function( $menu, opts, conf )
{
glbl.$allmenus = glbl.$allmenus.add( $menu );
this.$menu = $menu;
this.opts = opts
this.conf = conf;
this.serialnr = _serialnr++;
this._init();
return this;
};
$[ _plugin_ ].prototype = {
open: function()
{
this._opensetup();
this._openfinish();
return 'open';
},
_opensetup: function()
{
// find scrolltop
var _scrolltop = findscrolltop();
// set opened
this.$menu.addclass( _c.current );
// close others
glbl.$allmenus.not( this.$menu ).trigger( _e.close );
// store style and position
glbl.$page
.data( _d.style, glbl.$page.attr( 'style' ) || '' )
.data( _d.scrolltop, _scrolltop )
.data( _d.offetleft, glbl.$page.offset().left );
// resize page to window width
var _w = 0;
glbl.$wndw.off( _e.resize )
.on( _e.resize,
function( e, force )
{
if ( glbl.$html.hasclass( _c.opened ) || force )
{
var nw = glbl.$wndw.width();
if ( nw != _w )
{
_w = nw;
glbl.$page.width( nw - glbl.$page.data( _d.offetleft ) );
}
}
}
)
.trigger( _e.resize, [ true ] );
// prevent tabbing out of the menu
if ( this.conf.preventtabbing )
{
glbl.$wndw.off( _e.keydown )
.on( _e.keydown,
function( e )
{
if ( e.keycode == 9 )
{
e.preventdefault();
return false;
}
}
);
}
// add options
if ( this.opts.modal )
{
glbl.$html.addclass( _c.modal );
}
if ( this.opts.movebackground )
{
glbl.$html.addclass( _c.background );
}
if ( this.opts.position != 'left' )
{
glbl.$html.addclass( _c.mm( this.opts.position ) );
}
if ( this.opts.zposition != 'back' )
{
glbl.$html.addclass( _c.mm( this.opts.zposition ) );
}
if ( this.opts.classes )
{
glbl.$html.addclass( this.opts.classes );
}
// open
glbl.$html.addclass( _c.opened );
this.$menu.addclass( _c.opened );
// scroll page to scrolltop
glbl.$page.scrolltop( _scrolltop );
// scroll menu to top
this.$menu.scrolltop( 0 );
},
_openfinish: function()
{
var that = this;
// callback
transitionend( glbl.$page,
function()
{
that.$menu.trigger( _e.opened );
}, this.conf.transitionduration
);
// opening
glbl.$html.addclass( _c.opening );
this.$menu.trigger( _e.opening );
// scroll window to top
window.scrollto( 0, 1 );
},
close: function()
{
var that = this;
// callback
transitionend( glbl.$page,
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.position ) )
.removeclass( _c.mm( that.opts.zposition ) );
if ( that.opts.classes )
{
glbl.$html.removeclass( that.opts.classes );
}
glbl.$wndw
.off( _e.resize )
.off( _e.keydown );
// restore style and position
glbl.$page.attr( 'style', glbl.$page.data( _d.style ) );
if ( glbl.$scrolltopnode )
{
glbl.$scrolltopnode.scrolltop( glbl.$page.data( _d.scrolltop ) );
}
// closed
that.$menu.trigger( _e.closed );
}, this.conf.transitionduration
);
// closing
glbl.$html.removeclass( _c.opening );
this.$menu.trigger( _e.closing );
return 'close';
},
_init: function()
{
this.opts = extendoptions( this.opts, this.conf, this.$menu );
this.direction = ( this.opts.slidingsubmenus ) ? 'horizontal' : 'vertical';
// init page & menu
this._initpage( glbl.$page );
this._initmenu();
this._initblocker();
this._initpanles();
this._initlinks();
this._initopenclose();
this._bindcustomevents();
if ( $[ _plugin_ ].addons )
{
for ( var a = 0; a < $[ _plugin_ ].addons.length; a++ )
{
if ( typeof this[ '_addon_' + $[ _plugin_ ].addons[ a ] ] == 'function' )
{
this[ '_addon_' + $[ _plugin_ ].addons[ a ] ]();
}
}
}
},
_bindcustomevents: function()
{
var that = this;
this.$menu
.off( _e.open + ' ' + _e.close + ' ' + _e.setpage+ ' ' + _e.update )
.on( _e.open + ' ' + _e.close + ' ' + _e.setpage+ ' ' + _e.update,
function( e )
{
e.stoppropagation();
}
);
// menu-events
this.$menu
.on( _e.open,
function( e )
{
if ( $(this).hasclass( _c.current ) )
{
e.stopimmediatepropagation();
return false;
}
return that.open();
}
)
.on( _e.close,
function( e )
{
if ( !$(this).hasclass( _c.current ) )
{
e.stopimmediatepropagation();
return false;
}
return that.close();
}
)
.on( _e.setpage,
function( e, $p )
{
that._initpage( $p );
that._initopenclose();
}
);
// panel-events
var $panels = this.$menu.find( this.opts.ismenu && this.direction != 'horizontal' ? 'ul, ol' : '.' + _c.panel );
$panels
.off( _e.toggle + ' ' + _e.open + ' ' + _e.close )
.on( _e.toggle + ' ' + _e.open + ' ' + _e.close,
function( e )
{
e.stoppropagation();
}
);
if ( this.direction == 'horizontal' )
{
$panels
.on( _e.open,
function( e )
{
return opensubmenuhorizontal( $(this), that.$menu );
}
);
}
else
{
$panels
.on( _e.toggle,
function( e )
{
var $t = $(this);
return $t.triggerhandler( $t.parent().hasclass( _c.opened ) ? _e.close : _e.open );
}
)
.on( _e.open,
function( e )
{
$(this).parent().addclass( _c.opened );
return 'open';
}
)
.on( _e.close,
function( e )
{
$(this).parent().removeclass( _c.opened );
return 'close';
}
);
}
},
_initblocker: function()
{
var that = this;
if ( !glbl.$blck )
{
glbl.$blck = $( '
' ).appendto( glbl.$body );
}
click( glbl.$blck,
function()
{
if ( !glbl.$html.hasclass( _c.modal ) )
{
that.$menu.trigger( _e.close );
}
}, true, true
);
},
_initpage: function( $p )
{
if ( !$p )
{
$p = $(this.conf.pageselector, glbl.$body);
if ( $p.length > 1 )
{
$[ _plugin_ ].debug( 'multiple nodes found for the page-node, all nodes are wrapped in one <' + this.conf.pagenodetype + '>.' );
$p = $p.wrapall( '<' + this.conf.pagenodetype + ' />' ).parent();
}
}
$p.addclass( _c.page );
glbl.$page = $p;
},
_initmenu: function()
{
var that = this;
// clone if needed
if ( this.conf.clone )
{
this.$menu = this.$menu.clone( true );
this.$menu.add( this.$menu.find( '*' ) ).filter( '[id]' ).each(
function()
{
$(this).attr( 'id', _c.mm( $(this).attr( 'id' ) ) );
}
);
}
// strip whitespace
this.$menu.contents().each(
function()
{
if ( $(this)[ 0 ].nodetype == 3 )
{
$(this).remove();
}
}
);
// prepend to body
this.$menu
.prependto( 'body' )
.addclass( _c.menu );
// add direction class
this.$menu.addclass( _c.mm( this.direction ) );
// add options classes
if ( this.opts.classes )
{
this.$menu.addclass( this.opts.classes );
}
if ( this.opts.ismenu )
{
this.$menu.addclass( _c.ismenu );
}
if ( this.opts.position != 'left' )
{
this.$menu.addclass( _c.mm( this.opts.position ) );
}
if ( this.opts.zposition != 'back' )
{
this.$menu.addclass( _c.mm( this.opts.zposition ) );
}
},
_initpanles: function()
{
var that = this;
// refactor list class
this.__refactorclass( $('.' + this.conf.listclass, this.$menu), 'list' );
// add list class
if ( this.opts.ismenu )
{
$('ul, ol', this.$menu)
.not( '.mm-nolist' )
.addclass( _c.list );
}
var $lis = $('.' + _c.list + ' > li', this.$menu);
// refactor selected class
this.__refactorclass( $lis.filter( '.' + this.conf.selectedclass ), 'selected' );
// refactor label class
this.__refactorclass( $lis.filter( '.' + this.conf.labelclass ), 'label' );
// refactor spacer class
this.__refactorclass( $lis.filter( '.' + this.conf.spacerclass ), 'spacer' );
// setselected-event
$lis
.off( _e.setselected )
.on( _e.setselected,
function( e, selected )
{
e.stoppropagation();
$lis.removeclass( _c.selected );
if ( typeof selected != 'boolean' )
{
selected = true;
}
if ( selected )
{
$(this).addclass( _c.selected );
}
}
);
// refactor panel class
this.__refactorclass( $('.' + this.conf.panelclass, this.$menu), 'panel' );
// add panel class
this.$menu
.children()
.filter( this.conf.panelnodetype )
.add( this.$menu.find( '.' + _c.list ).children().children().filter( this.conf.panelnodetype ) )
.addclass( _c.panel );
var $panels = $('.' + _c.panel, this.$menu);
// add an id to all panels
$panels
.each(
function( i )
{
var $t = $(this),
id = $t.attr( 'id' ) || _c.mm( 'm' + that.serialnr + '-p' + i );
$t.attr( 'id', id );
}
);
// add open and close links to menu items
$panels
.find( '.' + _c.panel )
.each(
function( i )
{
var $t = $(this),
$u = $t.is( 'ul, ol' ) ? $t : $t.find( 'ul ,ol' ).first(),
$l = $t.parent(),
$a = $l.find( '> a, > span' ),
$p = $l.closest( '.' + _c.panel );
$t.data( _d.parent, $l );
if ( $l.parent().is( '.' + _c.list ) )
{
var $btn = $( '' ).insertbefore( $a );
if ( !$a.is( 'a' ) )
{
$btn.addclass( _c.fullsubopen );
}
if ( that.direction == 'horizontal' )
{
$u.prepend( '' + $a.text() + '' );
}
}
}
);
// link anchors to panels
var evt = this.direction == 'horizontal' ? _e.open : _e.toggle;
$panels
.each(
function( i )
{
var $opening = $(this),
id = $opening.attr( 'id' );
click( $('a[href="#' + id + '"]', that.$menu),
function( e )
{
$opening.trigger( evt );
}
);
}
);
if ( this.direction == 'horizontal' )
{
// add opened-classes
var $selected = $('.' + _c.list + ' > li.' + _c.selected, this.$menu);
$selected
.add( $selected.parents( 'li' ) )
.parents( 'li' ).removeclass( _c.selected )
.end().each(
function()
{
var $t = $(this),
$u = $t.find( '> .' + _c.panel );
if ( $u.length )
{
$t.parents( '.' + _c.panel ).addclass( _c.subopened );
$u.addclass( _c.opened );
}
}
)
.closest( '.' + _c.panel ).addclass( _c.opened )
.parents( '.' + _c.panel ).addclass( _c.subopened );
}
else
{
// replace selected-class with opened-class in parents from .selected
$('li.' + _c.selected, this.$menu)
.addclass( _c.opened )
.parents( '.' + _c.selected ).removeclass( _c.selected );
}
// set current opened
var $current = $panels.filter( '.' + _c.opened );
if ( !$current.length )
{
$current = $panels.first();
}
$current
.addclass( _c.opened )
.last()
.addclass( _c.current );
// rearrange markup
if ( this.direction == 'horizontal' )
{
$panels.find( '.' + _c.panel ).appendto( this.$menu );
}
},
_initlinks: function()
{
var that = this;
var $a = $('.' + _c.list + ' > li > a', this.$menu)
.not( '.' + _c.subopen )
.not( '.' + _c.subclose )
.not( '[rel="external"]' )
.not( '[target="_blank"]' );
$a.off( _e.click )
.on( _e.click,
function( e )
{
var $t = $(this),
href = $t.attr( 'href' );
// set selected item
if ( that.__valueorfn( that.opts.onclick.setselected, $t ) )
{
$t.parent().trigger( _e.setselected );
}
// prevent default / don't follow link. default: false
var preventdefault = that.__valueorfn( that.opts.onclick.preventdefault, $t, href.slice( 0, 1 ) == '#' );
if ( preventdefault )
{
e.preventdefault();
e.stoppropagation();
}
// block ui. default: false if preventdefault, true otherwise
if ( that.__valueorfn( that.opts.onclick.blockui, $t, !preventdefault ) )
{
glbl.$html.addclass( _c.blocking );
}
// close menu. default: true if preventdefault, false otherwise
if ( that.__valueorfn( that.opts.onclick.close, $t, preventdefault ) )
{
that.$menu.triggerhandler( _e.close );
}
}
);
},
_initopenclose: function()
{
var that = this;
// toggle menu
var id = this.$menu.attr( 'id' );
if ( id && id.length )
{
if ( this.conf.clone )
{
id = _c.umm( id );
}
click( $('a[href="#' + id + '"]'),
function()
{
that.$menu.trigger( _e.open );
}
);
}
// close menu
var id = glbl.$page.attr( 'id' );
if ( id && id.length )
{
click( $('a[href="#' + id + '"]'),
function()
{
that.$menu.trigger( _e.close );
}, false, true
);
}
},
__valueorfn: function( o, $e, d )
{
if ( typeof o == 'function' )
{
return o.call( $e[ 0 ] );
}
if ( typeof o == 'undefined' && typeof d != 'undefined' )
{
return d;
}
return o;
},
__refactorclass: function( $e, c )
{
$e.removeclass( this.conf[ c + 'class' ] ).addclass( _c[ c ] );
}
};
$.fn[ _plugin_ ] = function( opts, conf )
{
// first time plugin is fired
if ( !glbl.$wndw )
{
_initplugin();
}
// extend options
opts = extendoptions( opts, conf );
conf = extendconfiguration( conf );
return this.each(
function()
{
var $menu = $(this);
if ( $menu.data( _plugin_ ) )
{
return;
}
$menu.data( _plugin_, new $[ _plugin_ ]( $menu, opts, conf ) );
}
);
};
$[ _plugin_ ].version = _version_;
$[ _plugin_ ].defaults = {
position : 'left',
zposition : 'back',
movebackground : true,
slidingsubmenus : true,
modal : false,
classes : '',
onclick : {
// close : true,
// blockui : null,
// preventdefault : null,
setselected : true
}
};
$[ _plugin_ ].configuration = {
preventtabbing : true,
panelclass : 'panel',
listclass : 'list',
selectedclass : 'selected',
labelclass : 'label',
spacerclass : 'spacer',
pagenodetype : 'div',
panelnodetype : 'ul, ol, div',
transitionduration : 400
};
/*
support
*/
(function() {
var wd = window.document,
ua = window.navigator.useragent;
var _touch = 'ontouchstart' in wd,
_overflowscrolling = 'webkitoverflowscrolling' in wd.documentelement.style,
_transition = (function() {
var s = document.createelement( 'div' ).style;
if ( 'webkittransition' in s )
{
return 'webkittransition';
}
return 'transition' in s;
})(),
_oldandroidbrowser = (function() {
if ( ua.indexof( 'android' ) >= 0 )
{
return 2.4 > parsefloat( ua.slice( ua.indexof( 'android' ) +8 ) );
}
return false;
})();
$[ _plugin_ ].support = {
touch: _touch,
transition: _transition,
oldandroidbrowser: _oldandroidbrowser,
overflowscrolling: (function() {
if ( !_touch )
{
return true;
}
if ( _overflowscrolling )
{
return true;
}
if ( _oldandroidbrowser )
{
return false;
}
return true;
})()
};
})();
/*
browser specific fixes
*/
$[ _plugin_ ].useoverflowscrollingfallback = function( use )
{
if ( glbl.$html )
{
if ( typeof use == 'boolean' )
{
glbl.$html[ use ? 'addclass' : 'removeclass' ]( _c.nooverflowscrolling );
}
return glbl.$html.hasclass( _c.nooverflowscrolling );
}
else
{
_useoverflowscrollingfallback = use;
return use;
}
};
/*
debug
*/
$[ _plugin_ ].debug = function( msg ) {};
$[ _plugin_ ].deprecated = function( depr, repl )
{
if ( typeof console != 'undefined' && typeof console.warn != 'undefined' )
{
console.warn( 'mmenu: ' + depr + ' is deprecated, use ' + repl + ' instead.' );
}
};
// global vars
var _useoverflowscrollingfallback = !$[ _plugin_ ].support.overflowscrolling;
function extendoptions( o, c, $m )
{
if ( typeof o != 'object' )
{
o = {};
}
if ( $m )
{
if ( typeof o.ismenu != 'boolean' )
{
var $c = $m.children();
o.ismenu = ( $c.length == 1 && $c.is( c.panelnodetype ) );
}
return o;
}
// extend onclick
if ( typeof o.onclick != 'object' )
{
o.onclick = {};
}
// deprecated
if ( typeof o.onclick.setlocationhref != 'undefined' )
{
$[ _plugin_ ].deprecated( 'onclick.setlocationhref option', '!onclick.preventdefault' );
if ( typeof o.onclick.setlocationhref == 'boolean' )
{
o.onclick.preventdefault = !o.onclick.setlocationhref;
}
}
// /deprecated
// extend from defaults
o = $.extend( true, {}, $[ _plugin_ ].defaults, o );
// degration
if ( $[ _plugin_ ].useoverflowscrollingfallback() )
{
switch( o.position )
{
case 'top':
case 'right':
case 'bottom':
$[ _plugin_ ].debug( 'position: "' + o.position + '" not supported when using the overflowscrolling-fallback.' );
o.position = 'left';
break;
}
switch( o.zposition )
{
case 'front':
case 'next':
$[ _plugin_ ].debug( 'z-position: "' + o.zposition + '" not supported when using the overflowscrolling-fallback.' );
o.zposition = 'back';
break;
}
}
return o;
}
function extendconfiguration( c )
{
if ( typeof c != 'object' )
{
c = {};
}
// deprecated
if ( typeof c.panelnodetype != 'undefined' )
{
$[ _plugin_ ].deprecated( 'panelnodetype configuration option', 'panelnodetype' );
c.panelnodetype = c.panelnodetype;
}
// /deprecated
c = $.extend( true, {}, $[ _plugin_ ].configuration, c )
// set pageselector
if ( typeof c.pageselector != 'string' )
{
c.pageselector = '> ' + c.pagenodetype;
}
return c;
}
function _initplugin()
{
glbl.$wndw = $(window);
glbl.$html = $('html');
glbl.$body = $('body');
glbl.$allmenus = $();
// classnames, datanames, eventnames
$.each( [ _c, _d, _e ],
function( i, o )
{
o.add = function( c )
{
c = c.split( ' ' );
for ( var d in c )
{
o[ c[ d ] ] = o.mm( c[ d ] );
}
};
}
);
// classnames
_c.mm = function( c ) { return 'mm-' + c; };
_c.add( 'menu ismenu panel list subtitle selected label spacer current highest hidden page blocker modal background opened opening subopened subopen fullsubopen subclose nooverflowscrolling' );
_c.umm = function( c )
{
if ( c.slice( 0, 3 ) == 'mm-' )
{
c = c.slice( 3 );
}
return c;
};
// datanames
_d.mm = function( d ) { return 'mm-' + d; };
_d.add( 'parent style scrolltop offetleft' );
// eventnames
_e.mm = function( e ) { return e + '.mm'; };
_e.add( 'toggle open opening opened close closing closed update setpage setselected transitionend touchstart touchend click keydown keyup resize' );
if ( !$[ _plugin_ ].support.touch )
{
_e.touchstart = _e.mm( 'mousedown' );
_e.touchend = _e.mm( 'mouseup' );
}
$[ _plugin_ ]._c = _c;
$[ _plugin_ ]._d = _d;
$[ _plugin_ ]._e = _e;
$[ _plugin_ ].glbl = glbl;
$[ _plugin_ ].useoverflowscrollingfallback( _useoverflowscrollingfallback );
}
function opensubmenuhorizontal( $opening, $m )
{
if ( $opening.hasclass( _c.current ) )
{
return false;
}
var $panels = $('.' + _c.panel, $m),
$current = $panels.filter( '.' + _c.current );
$panels
.removeclass( _c.highest )
.removeclass( _c.current )
.not( $opening )
.not( $current )
.addclass( _c.hidden );
if ( $opening.hasclass( _c.opened ) )
{
$current
.addclass( _c.highest )
.removeclass( _c.opened )
.removeclass( _c.subopened );
}
else
{
$opening
.addclass( _c.highest );
$current
.addclass( _c.subopened );
}
$opening
.removeclass( _c.hidden )
.removeclass( _c.subopened )
.addclass( _c.current )
.addclass( _c.opened );
return 'open';
}
function findscrolltop()
{
if ( !glbl.$scrolltopnode )
{
if ( glbl.$html.scrolltop() != 0 )
{
glbl.$scrolltopnode = glbl.$html;
}
else if ( glbl.$body.scrolltop() != 0 )
{
glbl.$scrolltopnode = glbl.$body;
}
}
return ( glbl.$scrolltopnode ) ? glbl.$scrolltopnode.scrolltop() : 0;
}
function transitionend( $e, fn, duration )
{
var s = $[ _plugin_ ].support.transition;
if ( s == 'webkittransition' )
{
$e.one( 'webkittransitionend', fn );
}
else if ( s )
{
$e.one( _e.transitionend, fn );
}
else
{
settimeout( fn, duration );
}
}
function click( $b, fn, ontouchstart, add )
{
if ( typeof $b == 'string' )
{
$b = $( $b );
}
var event = ( ontouchstart )
? _e.touchstart
: _e.click;
if ( !add )
{
$b.off( event );
}
$b.on( event,
function( e )
{
e.preventdefault();
e.stoppropagation();
fn.call( this, e );
}
);
}
})( jquery );