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');
});
Related
Hellou guys. In this example i have an SVG animation which simulates turn the sheet of the book.
In mozilla its work fine, but in Chrome and Opera its work horrible.
Can you helpme optimize this animation for Chrome?
EXAMPLE
.js Used on EXAMPLE link:
snap.svg-min.js
classie.js
( function( window ) {
'use strict';
// class helper functions from bonzo https://github.com/ded/bonzo
function classReg( className ) {
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
}
// classList support for class management
// altho to be fair, the api sucks because it won't accept multiple classes at once
var hasClass, addClass, removeClass;
if ( 'classList' in document.documentElement ) {
hasClass = function( elem, c ) {
return elem.classList.contains( c );
};
addClass = function( elem, c ) {
elem.classList.add( c );
};
removeClass = function( elem, c ) {
elem.classList.remove( c );
};
}
else {
hasClass = function( elem, c ) {
return classReg( c ).test( elem.className );
};
addClass = function( elem, c ) {
if ( !hasClass( elem, c ) ) {
elem.className = elem.className + ' ' + c;
}
};
removeClass = function( elem, c ) {
elem.className = elem.className.replace( classReg( c ), ' ' );
};
}
function toggleClass( elem, c ) {
var fn = hasClass( elem, c ) ? removeClass : addClass;
fn( elem, c );
}
var classie = {
// full names
hasClass: hasClass,
addClass: addClass,
removeClass: removeClass,
toggleClass: toggleClass,
// short names
has: hasClass,
add: addClass,
remove: removeClass,
toggle: toggleClass
};
// transport
if ( typeof define === 'function' && define.amd ) {
// AMD
define( classie );
} else {
// browser global
window.classie = classie;
}
})( window );
svgLoader.js
;( function( window ) {
'use strict';
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function SVGLoader( el, options ) {
this.el = el;
this.options = extend( {}, this.options );
extend( this.options, options );
this._init();
}
SVGLoader.prototype.options = {
speedIn : 500,
easingIn : mina.linear
}
SVGLoader.prototype._init = function() {
var s = Snap( this.el.querySelector( 'svg' ) );
this.path = s.select( 'path' );
this.initialPath = this.path.attr('d');
var openingStepsStr = this.el.getAttribute( 'data-opening' );
this.openingSteps = openingStepsStr ? openingStepsStr.split(';') : '';
this.openingStepsTotal = openingStepsStr ? this.openingSteps.length : 0;
if( this.openingStepsTotal === 0 ) return;
// if data-closing is not defined then the path will animate to its original shape
var closingStepsStr = this.el.getAttribute( 'data-closing' ) ? this.el.getAttribute( 'data-closing' ) : this.initialPath;
this.closingSteps = closingStepsStr ? closingStepsStr.split(';') : '';
this.closingStepsTotal = closingStepsStr ? this.closingSteps.length : 0;
this.isAnimating = false;
if( !this.options.speedOut ) {
this.options.speedOut = this.options.speedIn;
}
if( !this.options.easingOut ) {
this.options.easingOut = this.options.easingIn;
}
}
SVGLoader.prototype.show = function() {
if( this.isAnimating ) return false;
this.isAnimating = true;
// animate svg
var self = this,
onEndAnimation = function() {
classie.addClass( self.el, 'pageload-loading' );
};
this._animateSVG( 'in', onEndAnimation );
classie.add( this.el, 'show' );
}
SVGLoader.prototype.hide = function() {
var self = this;
classie.removeClass( this.el, 'pageload-loading' );
this._animateSVG( 'out', function() {
// reset path
self.path.attr( 'd', self.initialPath );
classie.removeClass( self.el, 'show' );
self.isAnimating = false;
} );
}
SVGLoader.prototype._animateSVG = function( dir, callback ) {
var self = this,
pos = 0,
steps = dir === 'out' ? this.closingSteps : this.openingSteps,
stepsTotal = dir === 'out' ? this.closingStepsTotal : this.openingStepsTotal,
speed = dir === 'out' ? self.options.speedOut : self.options.speedIn,
easing = dir === 'out' ? self.options.easingOut : self.options.easingIn,
nextStep = function( pos ) {
if( pos > stepsTotal - 1 ) {
if( callback && typeof callback == 'function' ) {
callback();
}
return;
}
self.path.animate( { 'path' : steps[pos] }, speed, easing, function() { nextStep(pos); } );
pos++;
};
nextStep(pos);
}
// add to global namespace
window.SVGLoader = SVGLoader;
})( window );
and this scrypt on html file:
(function() {
var pageWrap = document.getElementById( 'pagewrap' ),
pages = [].slice.call( pageWrap.querySelectorAll( 'div.container' ) ),
currentPage = 0,
triggerLoading = [].slice.call( pageWrap.querySelectorAll( 'a.pageload-link' ) ),
loader = new SVGLoader( document.getElementById( 'loader' ), { speedIn : 400, easingIn : mina.easeinout } );
function init() {
triggerLoading.forEach( function( trigger ) {
trigger.addEventListener( 'click', function( ev ) {
ev.preventDefault();
loader.show();
// after some time hide loader
setTimeout( function() {
loader.hide();
classie.removeClass( pages[ currentPage ], 'show' );
// update..
currentPage = currentPage ? 0 : 1;
classie.addClass( pages[ currentPage ], 'show' );
}, 2000 );
} );
} );
}
init();
})();
The javascript below enables swipe left/right navigation. For some reason, I would like to call this function using URL such as <a href="javascript:function">. Certain URL will equivalent to left swipe, while another URL will equivalent to right swipe. Is this possible?
(function( window ){
var window = window,
document = window.document,
screen = window.screen,
touchSwipeListener = function( options ) {
// Private members
var track = {
startX: 0,
endX: 0
},
defaultOptions = {
moveHandler: function( direction ) {},
endHandler: function( direction ) {},
minLengthRatio: 0.3
},
getDirection = function() {
return track.endX > track.startX ? "prev" : "next";
},
isDeliberateMove = function() {
var minLength = Math.ceil( screen.width * options.minLengthRatio );
return Math.abs(track.endX - track.startX) > minLength;
},
extendOptions = function() {
for (var prop in defaultOptions) {
if ( defaultOptions.hasOwnProperty( prop ) ) {
options[ prop ] || ( options[ prop ] = defaultOptions[ prop ] );
}
}
},
handler = {
touchStart: function( event ) {
// At least one finger has touched the screen
if ( event.touches.length > 0 ) {
track.startX = event.touches[0].pageX;
}
},
touchMove: function( event ) {
if ( event.touches.length > 0 ) {
track.endX = event.touches[0].pageX;
options.moveHandler( getDirection(), isDeliberateMove() );
}
},
touchEnd: function( event ) {
var touches = event.changedTouches || event.touches;
if ( touches.length > 0 ) {
track.endX = touches[0].pageX;
isDeliberateMove() && options.endHandler( getDirection() );
}
}
};
extendOptions();
// Graceful degradation
if ( !document.addEventListener ) {
return {
on: function() {},
off: function() {}
}
}
return {
on: function() {
document.addEventListener('touchstart', handler.touchStart, false);
document.addEventListener('touchmove', handler.touchMove, false);
document.addEventListener('touchend', handler.touchEnd, false);
},
off: function() {
document.removeEventListener('touchstart', handler.touchStart);
document.removeEventListener('touchmove', handler.touchMove);
document.removeEventListener('touchend', handler.touchEnd);
}
}
}
// Expose global
window.touchSwipeListener = touchSwipeListener;
}( window ));
(function( window ){
var document = window.document,
// Element helpers
Util = {
addClass: function( el, className ) {
el.className += " " + className;
},
hasClass: function( el, className ) {
var re = new RegExp("\s?" + className, "gi");
return re.test( el.className );
},
removeClass: function( el, className ) {
var re = new RegExp("\s?" + className, "gi");
el.className = el.className.replace(re, "");
}
},
swipePageNav = (function() {
// Page sibling links like <link rel="prev" title=".." href=".." />
// See also http://diveintohtml5.info/semantics.html
var elLink = {
prev: null,
next: null
},
// Arrows, which slide in to indicate the shift direction
elArrow = {
prev: null,
next: null
},
swipeListener;
return {
init: function() {
this.retrievePageSiblings();
// Swipe navigation makes sense only if any of sibling page link available
if ( !elLink.prev && !elLink.next ) {
return;
}
this.renderArows();
this.syncUI();
},
syncUI: function() {
var that = this;
// Assign handlers for swipe "in progress" / "complete" events
swipeListener = new window.touchSwipeListener({
moveHandler: function( direction, isDeliberateMove ) {
if ( isDeliberateMove ) {
if ( elArrow[ direction ] && elLink[ direction ] ) {
Util.hasClass( elArrow[ direction ], "visible" ) ||
Util.addClass( elArrow[ direction ], "visible" );
}
} else {
Util.removeClass( elArrow.next, "visible" );
Util.removeClass( elArrow.prev, "visible" );
}
},
endHandler: function( direction ) {
that[ direction ] && that[ direction ]();
}
});
swipeListener.on();
},
retrievePageSiblings: function() {
elLink.prev = document.querySelector( "head > link[rel=prev]");
elLink.next = document.querySelector( "head > link[rel=next]");
},
renderArows: function() {
var renderArrow = function( direction ) {
var div = document.createElement("div");
div.className = "spn-direction-sign " + direction;
document.getElementsByTagName( "body" )[ 0 ].appendChild( div );
return div;
}
elArrow.next = renderArrow( "next" );
elArrow.prev = renderArrow( "prev" );
},
// When the shift (page swap) is requested, this overlay indicates that
// the current page is frozen and a new one is loading
showLoadingScreen: function() {
var div = document.createElement("div");
div.className = "spn-freezing-overlay";
document.getElementsByTagName( "body" )[ 0 ].appendChild( div );
},
// Request the previous sibling page
prev: function() {
if ( elLink.prev ) {
this.showLoadingScreen();
window.location.href = elLink.prev.href;
}
},
// Request the next sibling page
next: function() {
if ( elLink.next ) {
this.showLoadingScreen();
window.location.href = elLink.next.href;
}
}
}
}())
// Apply when document is ready
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
try {
swipePageNav.init();
} catch (e) {
alert(e);
}
}, false );
}( window ));
You cannot do that. However, if it is for organization goals why not have two JavaScript files, each one with its own namespace. If you do this, you call only that namespace expected for the link clicked.
I am working on JavaScript accordion and somehow i struck on targeting accordion ID instead of its <li>
Basically, I want below to generate two accordion if there are two markups like this
<div id="st-accordion" class="st-accordion">
<ul>
<li>
{tag_name_nolink}
<div class="st-content">
{tag_Partners Module tag}
</div>
</li>
</ul>
</div>
If there are two <div id="st-accordion" class="st-accordion">.......</div> then it should display two working accordions but it is making two working accordions when there are two <li> in the div.
Here is the JS and Fiddles
WORKING | NOT WORKING
(function( window, $, undefined ) {
var $event = $.event, resizeTimeout;
$event.special.smartresize = {
setup: function() {
$(this).bind( "resize", $event.special.smartresize.handler );
},
teardown: function() {
$(this).unbind( "resize", $event.special.smartresize.handler );
},
handler: function( event, execAsap ) {
// Save the context
var context = this,
args = arguments;
// set correct event type
event.type = "smartresize";
if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
resizeTimeout = setTimeout(function() {
jQuery.event.handle.apply( context, args );
}, execAsap === "execAsap"? 0 : 100 );
}
};
$.fn.smartresize = function( fn ) {
return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
};
$.Accordion = function( options, element ) {
this.$el = $( element );
// list items
this.$items = this.$el.children('ul').children('li');
// total number of items
this.itemsCount = this.$items.length;
// initialize accordion
this._init( options );
};
$.Accordion.defaults = {
// index of opened item. -1 means all are closed by default.
open : -1,
// if set to true, only one item can be opened. Once one item is opened, any other that is opened will be closed first
oneOpenedItem : false,
// speed of the open / close item animation
speed : 600,
// easing of the open / close item animation
easing : 'easeInOutExpo',
// speed of the scroll to action animation
scrollSpeed : 900,
// easing of the scroll to action animation
scrollEasing : 'easeInOutExpo'
};
$.Accordion.prototype = {
_init : function( options ) {
this.options = $.extend( true, {}, $.Accordion.defaults, options );
// validate options
this._validate();
// current is the index of the opened item
this.current = this.options.open;
// hide the contents so we can fade it in afterwards
this.$items.find('div.st-content').hide();
// save original height and top of each item
this._saveDimValues();
// if we want a default opened item...
if( this.current != -1 )
this._toggleItem( this.$items.eq( this.current ) );
// initialize the events
this._initEvents();
},
_saveDimValues : function() {
this.$items.each( function() {
var $item = $(this);
$item.data({
originalHeight : $item.find('a:first').height(),
offsetTop : $item.offset().top
});
});
},
// validate options
_validate : function() {
// open must be between -1 and total number of items, otherwise we set it to -1
if( this.options.open < -1 || this.options.open > this.itemsCount - 1 )
this.options.open = -1;
},
_initEvents : function() {
var instance = this;
// open / close item
this.$items.find('a:first').bind('click.accordion', function( event ) {
var $item = $(this).parent();
// close any opened item if oneOpenedItem is true
if( instance.options.oneOpenedItem && instance._isOpened() && instance.current!== $item.index() ) {
instance._toggleItem( instance.$items.eq( instance.current ) );
}
// open / close item
instance._toggleItem( $item );
return false;
});
$(window).bind('smartresize.accordion', function( event ) {
// reset orinal item values
instance._saveDimValues();
// reset the content's height of any item that is currently opened
instance.$el.find('li.st-open').each( function() {
var $this = $(this);
$this.css( 'height', $this.data( 'originalHeight' ) + $this.find('div.st-content').outerHeight( true ) );
});
// scroll to current
if( instance._isOpened() )
instance._scroll();
});
},
// checks if there is any opened item
_isOpened : function() {
return ( this.$el.find('li.st-open').length > 0 );
},
// open / close item
_toggleItem : function( $item ) {
var $content = $item.find('div.st-content');
( $item.hasClass( 'st-open' ) )
? ( this.current = -1, $content.stop(true, true).fadeOut( this.options.speed ), $item.removeClass( 'st-open' ).stop().animate({
height : $item.data( 'originalHeight' )
}, this.options.speed, this.options.easing ) )
: ( this.current = $item.index(), $content.stop(true, true).fadeIn( this.options.speed ), $item.addClass( 'st-open' ).stop().animate({
height : $item.data( 'originalHeight' ) + $content.outerHeight( true )
}, this.options.speed, this.options.easing ), this._scroll( this ) )
},
// scrolls to current item or last opened item if current is -1
_scroll : function( instance ) {
var instance = instance || this, current;
( instance.current !== -1 ) ? current = instance.current : current = instance.$el.find('li.st-open:last').index();
$('html, body').stop().animate({
scrollTop : ( instance.options.oneOpenedItem ) ? instance.$items.eq( current ).data( 'offsetTop' ) : instance.$items.eq( current ).offset().top
}, instance.options.scrollSpeed, instance.options.scrollEasing );
}
};
var logError = function( message ) {
if ( this.console ) {
console.error( message );
}
};
$.fn.accordion = function( options ) {
if ( typeof options === 'string' ) {
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function() {
var instance = $.data( this, 'accordion' );
if ( !instance ) {
logError( "cannot call methods on accordion prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for accordion instance" );
return;
}
instance[ options ].apply( instance, args );
});
}
else {
this.each(function() {
var instance = $.data( this, 'accordion' );
if ( !instance ) {
$.data( this, 'accordion', new $.Accordion( options, this ) );
}
});
}
return this;
};
})( window, jQuery );
somebody help please?
You have 2 elements with the same ID, and ID must be unique, so all you have to do is using class instead of ID :
$(function() {
$('.st-accordion').accordion({
oneOpenedItem : true
});
});
here is the jsFiddle
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 came across a situation where I need to adapt a script that works with JQuery 1.7.1 to work with JQuery 1.6.1, basically I need to convert the .on() to something that works with JQuery 1.6.1
here is the code I need it be run under JQuery 1.6.1 (change .on() functions ):
(function( $, undefined ) {
/*
* Slider object.
*/
$.Slider = function( options, element ) {
this.$el = $( element );
this._init( options );
};
$.Slider.defaults = {
current : 0, // index of current slide
bgincrement : 50, // increment the bg position (parallax effect) when sliding
autoplay : false,// slideshow on / off
interval : 4000 // time between transitions
};
$.Slider.prototype = {
_init : function( options ) {
this.options = $.extend( true, {}, $.Slider.defaults, options );
this.$slides = this.$el.children('div.da-slide');
this.slidesCount = this.$slides.length;
this.current = this.options.current;
if( this.current < 0 || this.current >= this.slidesCount ) {
this.current = 0;
}
this.$slides.eq( this.current ).addClass( 'da-slide-current' );
var $navigation = $( '<nav class="da-dots"/>' );
for( var i = 0; i < this.slidesCount; ++i ) {
$navigation.append( '<span/>' );
}
$navigation.appendTo( this.$el );
this.$pages = this.$el.find('nav.da-dots > span');
this.$navNext = this.$el.find('span.da-arrows-next');
this.$navPrev = this.$el.find('span.da-arrows-prev');
this.isAnimating = false;
this.bgpositer = 0;
this.cssAnimations = Modernizr.cssanimations;
this.cssTransitions = Modernizr.csstransitions;
if( !this.cssAnimations || !this.cssAnimations ) {
this.$el.addClass( 'da-slider-fb' );
}
this._updatePage();
// load the events
this._loadEvents();
// slideshow
if( this.options.autoplay ) {
this._startSlideshow();
}
},
_navigate : function( page, dir ) {
var $current = this.$slides.eq( this.current ), $next, _self = this;
if( this.current === page || this.isAnimating ) return false;
this.isAnimating = true;
// check dir
var classTo, classFrom, d;
if( !dir ) {
( page > this.current ) ? d = 'next' : d = 'prev';
}
else {
d = dir;
}
if( this.cssAnimations && this.cssAnimations ) {
if( d === 'next' ) {
classTo = 'da-slide-toleft';
classFrom = 'da-slide-fromright';
++this.bgpositer;
}
else {
classTo = 'da-slide-toright';
classFrom = 'da-slide-fromleft';
--this.bgpositer;
}
this.$el.css( 'background-position' , this.bgpositer * this.options.bgincrement + '% 0%' );
}
this.current = page;
$next = this.$slides.eq( this.current );
if( this.cssAnimations && this.cssAnimations ) {
var rmClasses = 'da-slide-toleft da-slide-toright da-slide-fromleft da-slide-fromright';
$current.removeClass( rmClasses );
$next.removeClass( rmClasses );
$current.addClass( classTo );
$next.addClass( classFrom );
$current.removeClass( 'da-slide-current' );
$next.addClass( 'da-slide-current' );
}
// fallback
if( !this.cssAnimations || !this.cssAnimations ) {
$next.css( 'left', ( d === 'next' ) ? '100%' : '-100%' ).stop().animate( {
left : '0%'
}, 1000, function() {
_self.isAnimating = false;
});
$current.stop().animate( {
left : ( d === 'next' ) ? '-100%' : '100%'
}, 1000, function() {
$current.removeClass( 'da-slide-current' );
});
}
this._updatePage();
},
_updatePage : function() {
this.$pages.removeClass( 'da-dots-current' );
this.$pages.eq( this.current ).addClass( 'da-dots-current' );
},
_startSlideshow : function() {
var _self = this;
this.slideshow = setTimeout( function() {
var page = ( _self.current < _self.slidesCount - 1 ) ? page = _self.current + 1 : page = 0;
_self._navigate( page, 'next' );
if( _self.options.autoplay ) {
_self._startSlideshow();
}
}, this.options.interval );
},
page : function( idx ) {
if( idx >= this.slidesCount || idx < 0 ) {
return false;
}
if( this.options.autoplay ) {
clearTimeout( this.slideshow );
this.options.autoplay = false;
}
this._navigate( idx );
},
_loadEvents : function() {
var _self = this;
this.$pages.on( 'click.cslider', function( event ) {
_self.page( $(this).index() );
return false;
});
this.$navNext.on( 'click.cslider', function( event ) {
if( _self.options.autoplay ) {
clearTimeout( _self.slideshow );
_self.options.autoplay = false;
}
var page = ( _self.current < _self.slidesCount - 1 ) ? page = _self.current + 1 : page = 0;
_self._navigate( page, 'next' );
return false;
});
this.$navPrev.on( 'click.cslider', function( event ) {
if( _self.options.autoplay ) {
clearTimeout( _self.slideshow );
_self.options.autoplay = false;
}
var page = ( _self.current > 0 ) ? page = _self.current - 1 : page = _self.slidesCount - 1;
_self._navigate( page, 'prev' );
return false;
});
if( this.cssTransitions ) {
if( !this.options.bgincrement ) {
this.$el.on( 'webkitAnimationEnd.cslider animationend.cslider OAnimationEnd.cslider', function( event ) {
if( event.originalEvent.animationName === 'toRightAnim4' || event.originalEvent.animationName === 'toLeftAnim4' ) {
_self.isAnimating = false;
}
});
}
else {
this.$el.on( 'webkitTransitionEnd.cslider transitionend.cslider OTransitionEnd.cslider', function( event ) {
if( event.target.id === _self.$el.attr( 'id' ) )
_self.isAnimating = false;
});
}
}
}
};
var logError = function( message ) {
if ( this.console ) {
console.error( message );
}
};
$.fn.cslider = function( options ) {
if ( typeof options === 'string' ) {
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function() {
var instance = $.data( this, 'cslider' );
if ( !instance ) {
logError( "cannot call methods on cslider prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for cslider instance" );
return;
}
instance[ options ].apply( instance, args );
});
}
else {
this.each(function() {
var instance = $.data( this, 'cslider' );
if ( !instance ) {
$.data( this, 'cslider', new $.Slider( options, this ) );
}
});
}
return this;
};
})( jQuery );
Since it doesn't look like there's any event delegation happening, you should be able to directly replace .on with .bind.