/* * 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 );