I am trying to switch OVERLAY on button click.
After adding these 2 buttons under same class, and calling this function, JS simply won't get it done.
I am not sure what is the problem in :
document.getElementsByClassName( 'trigger-overlay' )
or somewhere else?
If I leave it as document.getElementById( 'trigger-overlay' ) and in html switch to id instead of class, it works only for 1 element.
Kinda stucked here.
Thanks,
Michael
<p><button class="trigger-overlay" type="button">Open Overlay</button></p>
<p><button class="trigger-overlay" type="button">Open Overlay2</button></p>
and js fucntion:
(function() {
var triggerBttn = document.getElementsByClassName( 'trigger-overlay' ),
overlay = document.querySelector( 'div.overlay' ),
closeBttn = overlay.querySelector( 'button.overlay-close' );
transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
support = { transitions : Modernizr.csstransitions };
function toggleOverlay() {
if( classie.has( overlay, 'open' ) ) {
classie.remove( overlay, 'open' );
classie.add( overlay, 'close' );
var onEndTransitionFn = function( ev ) {
if( support.transitions ) {
if( ev.propertyName !== 'visibility' ) return;
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
classie.remove( overlay, 'close' );
};
if( support.transitions ) {
overlay.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
}
else if( !classie.has( overlay, 'close' ) ) {
classie.add( overlay, 'open' );
}
}
triggerBttn.addEventListener( 'click', toggleOverlay );
closeBttn.addEventListener( 'click', toggleOverlay );
})();
triggerBttn is an array. Here you need to use it like an array...like below
var triggerBttn = document.getElementsByClassName( 'trigger-overlay' ),
for(var i=0; i < triggerBttn.length ; i++)
{
triggerBttn[i].addEventListener( 'click', toggleOverlay );
}
Related
I have a very simple menu, no sub menus and was curious how I would get the menu to close when I click on one of the links?
Plugin Home Page ->
Here is the code directly out of the .js file that comes in the zip when you download this menu. I really need to know what code to add and where to add it so that when I click a link it closes the menu.
;( function( $, window, undefined ) {
'use strict';
// global
var Modernizr = window.Modernizr, $body = $( 'body' );
$.DLMenu = function( options, element ) {
this.$el = $( element );
this._init( options );
};
// the options
$.DLMenu.defaults = {
// classes for the animation effects
animationClasses : { classin : 'dl-animate-in-1', classout : 'dl-animate-out-1' },
// callback: click a link that has a sub menu
// el is the link element (li); name is the level name
onLevelClick : function( el, name ) { return false; },
// callback: click a link that does not have a sub menu
// el is the link element (li); ev is the event obj
onLinkClick : function( el, ev ) { return false; }
};
$.DLMenu.prototype = {
_init : function( options ) {
// options
this.options = $.extend( true, {}, $.DLMenu.defaults, options );
// cache some elements and initialize some variables
this._config();
var animEndEventNames = {
'WebkitAnimation' : 'webkitAnimationEnd',
'OAnimation' : 'oAnimationEnd',
'msAnimation' : 'MSAnimationEnd',
'animation' : 'animationend'
},
transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
};
// animation end event name
this.animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ] + '.dlmenu';
// transition end event name
this.transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ] + '.dlmenu',
// support for css animations and css transitions
this.supportAnimations = Modernizr.cssanimations,
this.supportTransitions = Modernizr.csstransitions;
this._initEvents();
},
_config : function() {
this.open = false;
this.$trigger = this.$el.children( '.dl-trigger' );
this.$menu = this.$el.children( 'ul.dl-menu' );
this.$menuitems = this.$menu.find( 'li:not(.dl-back)' );
this.$el.find( 'ul.dl-submenu' ).prepend( '<li class="dl-back">BACK</li>' );
this.$back = this.$menu.find( 'li.dl-back' );
},
_initEvents : function() {
var self = this;
this.$trigger.on( 'click.dlmenu', function() {
if( self.open ) {
self._closeMenu();
}
else {
self._openMenu();
}
return false;
} );
this.$menuitems.on( 'click.dlmenu', function( event ) {
event.stopPropagation();
var $item = $(this),
$submenu = $item.children( 'ul.dl-submenu' );
if( $submenu.length > 0 ) {
var $flyin = $submenu.clone().css( 'opacity', 0 ).insertAfter( self.$menu ),
onAnimationEndFn = function() {
self.$menu.off( self.animEndEventName ).removeClass( self.options.animationClasses.classout ).addClass( 'dl-subview' );
$item.addClass( 'dl-subviewopen' ).parents( '.dl-subviewopen:first' ).removeClass( 'dl-subviewopen' ).addClass( 'dl-subview' );
$flyin.remove();
};
setTimeout( function() {
$flyin.addClass( self.options.animationClasses.classin );
self.$menu.addClass( self.options.animationClasses.classout );
if( self.supportAnimations ) {
self.$menu.on( self.animEndEventName, onAnimationEndFn );
}
else {
onAnimationEndFn.call();
}
self.options.onLevelClick( $item, $item.children( 'a:first' ).text() );
} );
return false;
}
var link = $item.find('a').attr('href');
var hash = link.substring(link.indexOf('#')+1);
if( hash != "" ){
var elem = jQuery('div[data-anchor="'+hash+'"]');
autoScroll(elem);
self._closeMenu();
}else{
self.options.onLinkClick( $item, event );
}
} );
this.$back.on( 'click.dlmenu', function( event ) {
var $this = $( this ),
$submenu = $this.parents( 'ul.dl-submenu:first' ),
$item = $submenu.parent(),
$flyin = $submenu.clone().insertAfter( self.$menu );
var onAnimationEndFn = function() {
self.$menu.off( self.animEndEventName ).removeClass( self.options.animationClasses.classin );
$flyin.remove();
};
setTimeout( function() {
$flyin.addClass( self.options.animationClasses.classout );
self.$menu.addClass( self.options.animationClasses.classin );
if( self.supportAnimations ) {
self.$menu.on( self.animEndEventName, onAnimationEndFn );
}
else {
onAnimationEndFn.call();
}
$item.removeClass( 'dl-subviewopen' );
var $subview = $this.parents( '.dl-subview:first' );
if( $subview.is( 'li' ) ) {
$subview.addClass( 'dl-subviewopen' );
}
$subview.removeClass( 'dl-subview' );
} );
return false;
} );
},
closeMenu : function() {
if( this.open ) {
this._closeMenu();
}
},
_closeMenu : function() {
var self = this,
onTransitionEndFn = function() {
self.$menu.off( self.transEndEventName );
self._resetMenu();
};
this.$menu.removeClass( 'dl-menuopen' );
this.$menu.addClass( 'dl-menu-toggle' );
this.$trigger.removeClass( 'dl-active' );
if( this.supportTransitions ) {
this.$menu.on( this.transEndEventName, onTransitionEndFn );
}
else {
onTransitionEndFn.call();
}
this.open = false;
},
openMenu : function() {
if( !this.open ) {
this._openMenu();
}
},
_openMenu : function() {
var self = this;
// clicking somewhere else makes the menu close
$body.off( 'click' ).on( 'click.dlmenu', function() {
self._closeMenu() ;
} );
this.$menu.addClass( 'dl-menuopen dl-menu-toggle' ).on( this.transEndEventName, function() {
$( this ).removeClass( 'dl-menu-toggle' );
} );
this.$trigger.addClass( 'dl-active' );
this.open = true;
},
// resets the menu to its original state (first level of options)
_resetMenu : function() {
this.$menu.removeClass( 'dl-subview' );
this.$menuitems.removeClass( 'dl-subview dl-subviewopen' );
}
};
var logError = function( message ) {
if ( window.console ) {
window.console.error( message );
}
};
$.fn.dlmenu = function( options ) {
if ( typeof options === 'string' ) {
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function() {
var instance = $.data( this, 'dlmenu' );
if ( !instance ) {
logError( "cannot call methods on dlmenu prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for dlmenu instance" );
return;
}
instance[ options ].apply( instance, args );
});
}
else {
this.each(function() {
var instance = $.data( this, 'dlmenu' );
if ( instance ) {
instance._init();
}
else {
instance = $.data( this, 'dlmenu', new $.DLMenu( options, this ) );
}
});
}
return this;
};
} )( jQuery, window );
After looking at their demo, it seems you can call method plugins. Replace dl-menu with the id of your menu.
$('#dl-menu a').click(function(e) {
$('#dl-menu').dlmenu('closeMenu');
});
this code constitutes a page included in my index.html file for a sidebarmenu
/**
* mlpushmenu.js v1.0.0
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2013, Codrops
* http://www.codrops.com
*/
;( function( window ) {
'use strict';
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
// taken from https://github.com/inuyaksa/jquery.nicescroll/blob/master/jquery.nicescroll.js
function hasParent( e, id ) {
if (!e) return false;
var el = e.target||e.srcElement||e||false;
while (el && el.id != id) {
el = el.parentNode||false;
}
return (el!==false);
}
// returns the depth of the element "e" relative to element with id=id
// for this calculation only parents with classname = waypoint are considered
function getLevelDepth( e, id, waypoint, cnt ) {
cnt = cnt || 0;
if ( e.id.indexOf( id ) >= 0 ) return cnt;
if( classie.has( e, waypoint ) ) {
++cnt;
}
return e.parentNode && getLevelDepth( e.parentNode, id, waypoint, cnt );
}
// http://coveroverflow.com/a/11381730/989439
function mobilecheck() {
var check = false;
(function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
return check;
}
// returns the closest element to 'e' that has class "classname"
function closest( e, classname ) {
if( classie.has( e, classname ) ) {
return e;
}
return e.parentNode && closest( e.parentNode, classname );
}
function mlPushMenu( el, trigger, options ) {
this.el = el;
this.trigger = trigger;
this.options = extend( this.defaults, options );
// support 3d transforms
this.support = Modernizr.csstransforms3d;
if( this.support ) {
this._init();
}
}
mlPushMenu.prototype = {
defaults : {
// overlap: there will be a gap between open levels
// cover: the open levels will be on top of any previous open level
type : 'overlap', // overlap || cover
// space between each overlaped level
levelSpacing : 40,
// classname for the element (if any) that when clicked closes the current level
backClass : 'mp-back'
},
_init : function() {
// if menu is open or not
this.open = false;
// level depth
this.level = 0;
// the moving wrapper
this.wrapper = document.getElementById( 'mp-pusher' );
// the mp-level elements
this.levels = Array.prototype.slice.call( this.el.querySelectorAll( 'div.mp-level' ) );
// save the depth of each of these mp-level elements
var self = this;
this.levels.forEach( function( el, i ) { el.setAttribute( 'data-level', getLevelDepth( el, self.el.id, 'mp-level' ) ); } );
// the menu items
this.menuItems = Array.prototype.slice.call( this.el.querySelectorAll( 'li' ) );
// if type == "cover" these will serve as hooks to move back to the previous level
this.levelBack = Array.prototype.slice.call( this.el.querySelectorAll( '.' + this.options.backClass ) );
// event type (if mobile use touch events)
this.eventtype = mobilecheck() ? 'touchstart' : 'click';
// add the class mp-overlap or mp-cover to the main element depending on options.type
classie.add( this.el, 'mp-' + this.options.type );
// initialize / bind the necessary events
this._initEvents();
},
_initEvents : function() {
var self = this;
// the menu should close if clicking somewhere on the body
var bodyClickFn = function( el ) {
self._resetMenu();
el.removeEveentListener( self.eventtype, bodyClickFn );
};
// open (or close) the menu
this.trigger.addEventListener( this.eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
if( self.open ) {
self._resetMenu();
}
else {
self._openMenu();
// the menu should close if clicking somewhere on the body (excluding clicks on the menu)
document.addEventListener( self.eventtype, function( ev ) {
if( self.open && !hasParent( ev.target, self.el.id ) ) {
bodyClickFn( this );
}
} );
}
} );
// opening a sub level menu
this.menuItems.forEach( function( el, i ) {
// check if it has a sub level
var subLevel = el.querySelector( 'div.mp-level' );
if( subLevel ) {
el.querySelector( 'a' ).addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
classie.add( closest( el, 'mp-level' ), 'mp-level-overlay' );
self._openMenu( subLevel );
}
} );
}
} );
// closing the sub levels :
// by clicking on the visible part of the level element
this.levels.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.stopPropagation();
var level = el.getAttribute( 'data-level' );
if( self.level > level ) {
self.level = level;
self._closeMenu();
}
} );
} );
// by clicking on a specific element
this.levelBack.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
self.level = closest( el, 'mp-level' ).getAttribute( 'data-level' ) - 1;
self.level === 0 ? self._resetMenu() : self._closeMenu();
}
} );
} );
},
_openMenu : function( subLevel ) {
// increment level depth
++this.level;
// move the main wrapper
var levelFactor = ( this.level - 1 ) * this.options.levelSpacing,
translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + levelFactor : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );
if( subLevel ) {
// reset transform for sublevel
this._setTransform( '', subLevel );
// need to reset the translate value for the level menus that have the same level depth and are not open
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl != subLevel && !classie.has( levelEl, 'mp-level-open' ) ) {
this._setTransform( 'translate3d(-100%,0,0) translate3d(' + -1*levelFactor + 'px,0,0)', levelEl );
}
}
}
// add class mp-pushed to main wrapper if opening the first time
if( this.level === 1 ) {
classie.add( this.wrapper, 'mp-pushed' );
this.open = true;
}
// add class mp-level-open to the opening level element
classie.add( subLevel || this.levels[0], 'mp-level-open' );
},
// close the menu
_resetMenu : function() {
this._setTransform('translate3d(0,0,0)');
this.level = 0;
// remove class mp-pushed from main wrapper
classie.remove( this.wrapper, 'mp-pushed' );
this._toggleLevels();
this.open = false;
},
// close sub menus
_closeMenu : function() {
var translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + ( this.level - 1 ) * this.options.levelSpacing : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );
this._toggleLevels();
},
// translate the el
_setTransform : function( val, el ) {
el = el || this.wrapper;
el.style.WebkitTransform = val;
el.style.MozTransform = val;
el.style.transform = val;
},
// removes classes mp-level-open from closing levels
_toggleLevels : function() {
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl.getAttribute( 'data-level' ) >= this.level + 1 ) {
classie.remove( levelEl, 'mp-level-open' );
classie.remove( levelEl, 'mp-level-overlay' );
}
else if( Number( levelEl.getAttribute( 'data-level' ) ) == this.level ) {
classie.remove( levelEl, 'mp-level-overlay' );
}
}
}
}
// add to global namespace
window.mlPushMenu = mlPushMenu;
} )( window );
how to i reuse specifically and only the close object in a line of code somewhere else ?
.... I am just trying to append the close object defined in the above code somewhere else so i can use it with some other code.
the example of where i am trying to use it .....
$('.iconM-referrals').on('click', function () {
$("#colorscreen").remove()
$("body").append('<div id="colorscreen" class="animated"></div>')
$("#colorscreen").addClass("fadeInUpBig");
$('.fadeInUpBig').css('background-color', 'rgba(13,135,22,0.3)');
$(".tile-group.main").css({ width: "720px"}).load("musability-musictherapy-company-overview.html");
$window.mlPushMenu._closeMenu;
});
as i see you can use window.mlPushMenu in any where you want in your html document cause this was set as global in window object.
and if you want to use close function you can call window.mlPushMenu._closeMenu
hope it helps.
At the end is this:
// add to global namespace
window.mlPushMenu = mlPushMenu;
Use window.mlPushMenu
I suspect my question may be a bit obtuse, and I apologize. Here is what I am trying to achieve:
I am using this multi-level push menu, and it works fine out of the box. However, I would like the multi-level menu to close after a modal is submitted and closed. I am having a difficult time figuring out how to trigger this menu to close.
So, on to some code. Up first, the Javascript that runs the menu itself.
mlPushMenu.prototype = {
defaults : {
// overlap: there will be a gap between open levels
// cover: the open levels will be on top of any previous open level
type : 'overlap', // overlap || cover
// space between each overlaped level
levelSpacing : 40,
// classname for the element (if any) that when clicked closes the current level
backClass : 'mp-back'
},
_init : function() {
// if menu is open or not
this.open = false;
// level depth
this.level = 0;
// the moving wrapper
this.wrapper = document.getElementById( 'mp-pusher' );
// the mp-level elements
this.levels = Array.prototype.slice.call( this.el.querySelectorAll( 'div.mp-level' ) );
// save the depth of each of these mp-level elements
var self = this;
this.levels.forEach( function( el, i ) { el.setAttribute( 'data-level', getLevelDepth( el, self.el.id, 'mp-level' ) ); } );
// the menu items
this.menuItems = Array.prototype.slice.call( this.el.querySelectorAll( 'li' ) );
// if type == "cover" these will serve as hooks to move back to the previous level
this.levelBack = Array.prototype.slice.call( this.el.querySelectorAll( '.' + this.options.backClass ) );
// event type (if mobile use touch events)
this.eventtype = mobilecheck() ? 'touchstart' : 'click';
// add the class mp-overlap or mp-cover to the main element depending on options.type
classie.add( this.el, 'mp-' + this.options.type );
// initialize / bind the necessary events
this._initEvents();
},
_initEvents : function() {
var self = this;
// the menu should close if clicking somewhere on the body
var bodyClickFn = function( el ) {
self._resetMenu();
el.removeEventListener( self.eventtype, bodyClickFn );
};
// open (or close) the menu
this.trigger.addEventListener( this.eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
if( self.open ) {
self._resetMenu();
}
else {
self._openMenu();
// the menu should close if clicking somewhere on the body (excluding clicks on the menu)
document.addEventListener( self.eventtype, function( ev ) {
if( self.open && !hasParent( ev.target, self.el.id ) ) {
bodyClickFn( this );
}
} );
}
} );
// opening a sub level menu
this.menuItems.forEach( function( el, i ) {
// check if it has a sub level
var subLevel = el.querySelector( 'div.mp-level' );
if( subLevel ) {
el.querySelector( 'a' ).addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
classie.add( closest( el, 'mp-level' ), 'mp-level-overlay' );
self._openMenu( subLevel );
}
} );
}
} );
// closing the sub levels :
// by clicking on the visible part of the level element
this.levels.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.stopPropagation();
var level = el.getAttribute( 'data-level' );
if( self.level > level ) {
self.level = level;
self._closeMenu();
}
} );
} );
// by clicking on a specific element
this.levelBack.forEach( function( el, i ) {
el.addEventListener( self.eventtype, function( ev ) {
ev.preventDefault();
var level = closest( el, 'mp-level' ).getAttribute( 'data-level' );
if( self.level <= level ) {
ev.stopPropagation();
self.level = closest( el, 'mp-level' ).getAttribute( 'data-level' ) - 1;
self.level === 0 ? self._resetMenu() : self._closeMenu();
}
} );
} );
},
_openMenu : function( subLevel ) {
// increment level depth
++this.level;
// move the main wrapper
var levelFactor = ( this.level - 1 ) * this.options.levelSpacing,
translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + levelFactor : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );
if( subLevel ) {
// reset transform for sublevel
this._setTransform( '', subLevel );
// need to reset the translate value for the level menus that have the same level depth and are not open
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl != subLevel && !classie.has( levelEl, 'mp-level-open' ) ) {
this._setTransform( 'translate3d(-100%,0,0) translate3d(' + -1*levelFactor + 'px,0,0)', levelEl );
}
}
}
// add class mp-pushed to main wrapper if opening the first time
if( this.level === 1 ) {
classie.add( this.wrapper, 'mp-pushed' );
this.open = true;
}
// add class mp-level-open to the opening level element
classie.add( subLevel || this.levels[0], 'mp-level-open' );
},
// close the menu
_resetMenu : function() {
this._setTransform('translate3d(0,0,0)');
this.level = 0;
// remove class mp-pushed from main wrapper
classie.remove( this.wrapper, 'mp-pushed' );
this._toggleLevels();
this.open = false;
},
// close sub menus
_closeMenu : function() {
var translateVal = this.options.type === 'overlap' ? this.el.offsetWidth + ( this.level - 1 ) * this.options.levelSpacing : this.el.offsetWidth;
this._setTransform( 'translate3d(' + translateVal + 'px,0,0)' );
this._toggleLevels();
},
// translate the el
_setTransform : function( val, el ) {
el = el || this.wrapper;
el.style.WebkitTransform = val;
el.style.MozTransform = val;
el.style.transform = val;
},
// removes classes mp-level-open from closing levels
_toggleLevels : function() {
for( var i = 0, len = this.levels.length; i < len; ++i ) {
var levelEl = this.levels[i];
if( levelEl.getAttribute( 'data-level' ) >= this.level + 1 ) {
classie.remove( levelEl, 'mp-level-open' );
classie.remove( levelEl, 'mp-level-overlay' );
}
else if( Number( levelEl.getAttribute( 'data-level' ) ) == this.level ) {
classie.remove( levelEl, 'mp-level-overlay' );
}
}
}
}
The method I would like to invoke would be _resetMenu. I have tried this a couple of ways. The primary was trying to trigger the click event of the button that opens the menu:
<i class="fa fa-reorder"></i>
However:
$('#trigger').trigger('click');
does not work as expected. I would expect this to be fired:
// open (or close) the menu
this.trigger.addEventListener( this.eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
if( self.open ) {
self._resetMenu();
}
else {
self._openMenu();
// the menu should close if clicking somewhere on the body (excluding clicks on the menu)
document.addEventListener( self.eventtype, function( ev ) {
if( self.open && !hasParent( ev.target, self.el.id ) ) {
bodyClickFn( this );
}
} );
}
} );
In this case, this.eventtype is 'click'.
I suspect this may have something to do with how this functionality is coded with an object. While I have decent Javascript skills, I have not had much exposure to using it in this manner.
I am instantiating the menu thusly:
new mlPushMenu(document.getElementById('mp-menu'), document.getElementById('trigger'));
I realize I could extract this method, but that seems to violate some best practices in general.
Any suggestions will be most appreciated!
You can't use this module as-is to do this. The only event types it supports are "click" and "touchstart" and its mobilecheck() method determines which one of the two it uses.
You'll either have to fake a click on a trigger element or you'll have to modify this module. You can do this with the .click() method of a DOM element. .trigger.click() probably won't do it; you would probably be better off just getting the element (via $('#trigger') or document.getElementById()) and then calling the .click() method of that.
I just tried this in Chrome with an <a> with style display:none and it followed the link so it may work for another hidden element set to trigger. It's hacky but it might be preferable to changing the module.
Im using the "morphing buttons concept" from here http://tympanus.net/codrops/2014/05/12/morphing-buttons-concept/
The problem is that its not working in IE9. The error says:
if( ev.target !== this )
{exception} undefined or null
I found this on stackoverflow https://stackoverflow.com/a/1143236/3310123
But i cant seem to implement it to the uiMorphingButton_fixed.js that comes with "morphing buttons"
Does anyone know what to change to make it work in IE 9 (its working in 10 and 11)?
The if( ev.target !== this ) can be found on line 90 in uiMorphingButton_fixed.js:
var self = this,
onEndTransitionFn = function( ev ) {
if( ev.target !== this ) return false;
if( support.transitions ) {
// open: first opacity then width/height/left/top
// close: first width/height/left/top then opacity
if( self.expanded && ev.propertyName !== 'opacity' || !self.expanded && ev.propertyName !== 'width' && ev.propertyName !== 'height' && ev.propertyName !== 'left' && ev.propertyName !== 'top' ) {
return false;
}
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
self.isAnimating = false;
// callback
if( self.expanded ) {
// remove class active (after closing)
classie.removeClass( self.el, 'active' );
self.options.onAfterClose();
}
else {
self.options.onAfterOpen();
}
self.expanded = !self.expanded;
};
if( support.transitions ) {
this.contentEl.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
The problem seems to be here:
support.transitions is returning false, so onEndTransitionFn() is run (in the else at the end).
That sends no params to the onEndTransitionFn function.
But that function expects a parameter, and expects that parameter to have a target attribute. So calling it with no params will create the error you are seeing.
Maybe remove the else after the last if statement. But there's no way round the fact that support.transitions will still be false, so the morphing probably still won't work.
I got the .js updated so it now works on IE9 aswell. Replace the whole uiMorphingButton_fixed.js with this:
Hope this help someone :)
/**
* uiMorphingButton_fixed.js v1.0.0
* http://www.codrops.com
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2014, Codrops
*/
;( function( window ) {
'use strict';
var transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
support = { transitions : Modernizr.csstransitions };
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function UIMorphingButton( el, options ) {
this.el = el;
this.options = extend( {}, this.options );
extend( this.options, options );
this._init();
}
UIMorphingButton.prototype.options = {
closeEl : '',
onBeforeOpen : function() { return false; },
onAfterOpen : function() { return false; },
onBeforeClose : function() { return false; },
onAfterClose : function() { return false; }
}
UIMorphingButton.prototype._init = function() {
// the button
this.button = this.el.querySelector( 'button' );
// state
this.expanded = false;
// content el
this.contentEl = this.el.querySelector( '.morph-content' );
// init events
this._initEvents();
}
UIMorphingButton.prototype._initEvents = function() {
var self = this;
// open
this.button.addEventListener( 'click', function() {
if(support.transitions) {
self.toggle();
} else {
classie.addClass( self.el, 'active open' );
}
} );
// close
if( this.options.closeEl !== '' ) {
var closeEl = this.el.querySelector( this.options.closeEl );
if( closeEl ) {
closeEl.addEventListener( 'click', function() {
if(support.transitions) {
self.toggle();
} else {
classie.removeClass( self.el, 'active open' );
}
} );
}
}
}
UIMorphingButton.prototype.toggle = function() {
if( this.isAnimating ) return false;
// callback
if( this.expanded ) {
this.options.onBeforeClose();
}
else {
// add class active (solves z-index problem when more than one button is in the page)
classie.addClass( this.el, 'active' );
this.options.onBeforeOpen();
}
this.isAnimating = true;
var self = this,
onEndTransitionFn = function( ev ) {
if( ev.target !== this ) return false;
if( support.transitions ) {
// open: first opacity then width/height/left/top
// close: first width/height/left/top then opacity
if( self.expanded && ev.propertyName !== 'opacity' || !self.expanded && ev.propertyName !== 'width' && ev.propertyName !== 'height' && ev.propertyName !== 'left' && ev.propertyName !== 'top' ) {
return false;
}
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
self.isAnimating = false;
// callback
if( self.expanded ) {
// remove class active (after closing)
classie.removeClass( self.el, 'active' );
self.options.onAfterClose();
}
else {
self.options.onAfterOpen();
}
self.expanded = !self.expanded;
};
if( support.transitions ) {
this.contentEl.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
// set the left and top values of the contentEl (same like the button)
var buttonPos = this.button.getBoundingClientRect();
// need to reset
classie.addClass( this.contentEl, 'no-transition' );
this.contentEl.style.left = 'auto';
this.contentEl.style.top = 'auto';
// add/remove class "open" to the button wraper
setTimeout( function() {
self.contentEl.style.left = buttonPos.left + 'px';
self.contentEl.style.top = buttonPos.top + 'px';
if( self.expanded ) {
classie.removeClass( self.contentEl, 'no-transition' );
classie.removeClass( self.el, 'open' );
}
else {
setTimeout( function() {
classie.removeClass( self.contentEl, 'no-transition' );
classie.addClass( self.el, 'open' );
}, 25 );
}
}, 25 );
}
// add to global namespace
window.UIMorphingButton = UIMorphingButton;
})( window );
I found interesting article here http://vk.com/away.php?utf=1&to=http%3A%2F%2Ftympanus.net%2FTutorials%2FAnimatedBorderMenus%2Findex3.html and tried to apply it on my site.
I found problem in conficting modernize + classie vs jquery
so I decided to convert code like that:
before:
function init() {
var menu = document.getElementById( 'bt-menu' ),
trigger = menu.querySelector( 'a.bt-menu-trigger' ),
// triggerPlay only for demo 6
triggerPlay = document.querySelector( 'a.bt-menu-trigger-out' ),
// event type (if mobile use touch events)
eventtype = mobilecheck() ? 'touchstart' : 'click',
resetMenu = function() {
classie.remove( menu, 'bt-menu-open' );
classie.add( menu, 'bt-menu-close' );
},
closeClickFn = function( ev ) {
resetMenu();
overlay.removeEventListener( eventtype, closeClickFn );
};
var overlay = document.createElement('div');
overlay.className = 'bt-overlay';
menu.appendChild( overlay );
trigger.addEventListener( eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
if( classie.has( menu, 'bt-menu-open' ) ) {
resetMenu();
}
else {
classie.remove( menu, 'bt-menu-close' );
classie.add( menu, 'bt-menu-open' );
overlay.addEventListener( eventtype, closeClickFn );
}
});
if( triggerPlay ) {
triggerPlay.addEventListener( eventtype, function( ev ) {
ev.stopPropagation();
ev.preventDefault();
classie.remove( menu, 'bt-menu-close' );
classie.add( menu, 'bt-menu-open' );
overlay.addEventListener( eventtype, closeClickFn );
});
}
}
init();
after:
function init() {
var $menu = $( 'bt-menu' ),
eventtype = mobilecheck() ? 'touchstart' : 'click',
resetMenu = function() {
$menu.removeClass('bt-menu-open' );
$menu.addClass('bt-menu-close' );
},
closeClickFn = function( ev ) {
resetMenu();
$overlay.unbind( eventtype, closeClickFn );
};
var $overlay = $("<div class='bt-overlay'/>");
$menu.append( $overlay );
$('bt-menu a.bt-menu-trigger').bind( eventtype, function( ev ) {
alert('hi');
ev.stopPropagation();
ev.preventDefault();
if( $menu.hasClass('bt-menu-open' ) ) {
resetMenu();
}
else {
$menu.removeClass('bt-menu-close' );
$menu.addClass('bt-menu-open' );
$overlay.bind( eventtype, closeClickFn );
}
});
}
init();
But it doesnt work and I don't know where is my error.
Can anybody help?
The var $menu = $( 'bt-menu' ) should be var $menu = $( '#bt-menu' ).