JQuery local variables in anonymous function lakes - javascript

I am not sure so I decide to ask here. I have a plugin which uses jquery animate function and then it call complete callback. It works pretty much with dom. After few cycles script starts to be slow. I cant find any issue only local lambda variables. But I dont know why this local variables should remain in memory. It does not make sense. Here is the code:
cEl.el.animate( { left: offset.left - state.cEl.mL, top: offset.top - state.cEl.mT }, 250,
function() // complete callback
{
tidyCurrEl( cEl );
targetEl.after( cEl.el[0] );
targetEl[0].style.display = 'none';
hintStyle.display = 'none';
hintNode.remove();
......
if ( isHintTarget )
{
// This seems to be a problem.
var paretnLi = state.placeholderNode.parent().closest( 'li' )
......
}
else
{
......
}
} );
Am I right the local variables in anonymous function is the problem? Thanks.
Here is full code example
function endDrag( e )
{
var cEl = state.cEl,
hintNode = $( '#s-l-hint', state.rootEl.el ),
hintStyle = hint[0].style,
targetEl = null, // hintNode/placeholderNode
isHintTarget = false, // if cEl will be placed to the hintNode
hintWrapperNode = $( '#s-l-hint-wrapper' );
if ( hintStyle.display == 'block' && hintNode.length && state.isAllowed )
{
targetEl = hintNode;
isHintTarget = true;
}
else
{
targetEl = state.placeholderNode;
isHintTarget = false;
}
offset = targetEl.offset();
cEl.el.animate( { left: offset.left - state.cEl.mL, top: offset.top - state.cEl.mT }, 250,
function() // complete callback
{
tidyCurrEl( cEl );
targetEl.after( cEl.el[0] );
targetEl[0].style.display = 'none';
hintStyle.display = 'none';
// This has to be document node, not hint as a part of documentFragment.
hintNode.remove();
hintWrapperNode
.removeAttr( 'id' )
.removeClass( setting.hintWrapperClass );
if ( hintWrapperNode.length )
{
hintWrapperNode.prev( 'div' ).append( opener.clone( true ) );
}
var placeholderNode = state.placeholderNode;
// Directly removed placeholder looks bad. It jumps up if the hint is below.
if ( isHintTarget )
{
placeholderNode.slideUp( 150, function()
{
var placeholderParent = placeholderNode.parent();
var placeholderParentLi = ( ! placeholderParent.is( state.rootEl.el ) ) ? placeholderParent.closest( 'li' ) : null;
placeholderNode.remove();
tidyEmptyLists();
setting.onChange( cEl.el );
setting.complete( cEl.el ); // Have to be here cause is necessary to remove placeholder before complete call.
state.isDragged = false;
if( setting.maxLevels !== false ) // Has to be after placeholder remove.
{
recountLevels( cEl.el );
if( placeholderParentLi ) recountLevels( placeholderParentLi );
}
});
}
else
{
state.placeholderNode.remove();
tidyEmptyLists();
setting.complete( cEl.el );
state.isDragged = false;
}
} );
scrollStop( state );
state.doc
.unbind( "mousemove", dragging )
.unbind( "mouseup", endDrag );
}

Related

bootstrap accordian or hide and Show is not working under dynamic creation elements in jQuery

In one of my sample application, when click the particular items, it will show the pop up with description of the particular items. When I tried to put the bootstrap accordion or hide and show nothing works here, except jQuery delegate event handlers.
In grid.js is a third party plugins provide the dynamic element creation.
This is an li and a class called portfolio_description. Inside the class nothing gets triggered click event, hide or show, toggle etc, except delegate handler.
<ul>
<li>
<a data-description="data-description" data-largesrc="~/Content/example/gallery/intro_img4.jpg" data-title="Project Name 1" href="#"><img alt="" src="~/Content/example/gallery/intro_img4.jpg"></a>
<div class="portfolio_description">
<div class="block">
<div class="container">
<h2>Simple Collapsible</h2>
<p>Click on the button to toggle between showing and hiding content.</p>
<button class="btn btn-info" data-target="#demo" data-toggle="collapse" type="button">Simple collapsible</button>
<div class="collapse" id="demo">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>
</div>
</div>
</li>
</ul>
Here is an plunker demo.
https://plnkr.co/edit/XY7A3D3YO7hoF8AulZpR?p=preview
output:
problem with collection :
Before and after removal of class portfolio description:
because of conflicting ID for accordion elements , Please update your code with unique id.
Same id exist in "portfolio_description" AND "gallery-expander" DIV.
Updated :
Please update your grid.js with below,
/*
* debouncedresize: special jQuery event that happens once after a window resize
*
* latest version and complete README available on Github:
* https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js
*
* Copyright 2011 #louis_remi
* Licensed under the MIT license.
*/
var $event = $.event,
$special,
resizeTimeout,
previousItem,
accordionHTML;
$special = $event.special.debouncedresize = {
setup: function() {
$( this ).on( "resize", $special.handler );
},
teardown: function() {
$( this ).off( "resize", $special.handler );
},
handler: function( event, execAsap ) {
// Save the context
var context = this,
args = arguments,
dispatch = function() {
// set correct event type
event.type = "debouncedresize";
$event.dispatch.apply( context, args );
};
if ( resizeTimeout ) {
clearTimeout( resizeTimeout );
}
execAsap ?
dispatch() :
resizeTimeout = setTimeout( dispatch, $special.threshold );
},
threshold: 250
};
// ======================= imagesLoaded Plugin ===============================
// https://github.com/desandro/imagesloaded
// $('#my-container').imagesLoaded(myFunction)
// execute a callback when all images have loaded.
// needed because .load() doesn't work on cached images
// callback function gets image collection as argument
// this is the container
// original: MIT license. Paul Irish. 2010.
// contributors: Oren Solomianik, David DeSandro, Yiannis Chatzikonstantinou
// blank image data-uri bypasses webkit log warning (thx doug jones)
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
$.fn.imagesLoaded = function( callback ) {
var $this = this,
deferred = $.isFunction($.Deferred) ? $.Deferred() : 0,
hasNotify = $.isFunction(deferred.notify),
$images = $this.find('img').add( $this.filter('img') ),
loaded = [],
proper = [],
broken = [];
// Register deferred callbacks
if ($.isPlainObject(callback)) {
$.each(callback, function (key, value) {
if (key === 'callback') {
callback = value;
} else if (deferred) {
deferred[key](value);
}
});
}
function doneLoading() {
var $proper = $(proper),
$broken = $(broken);
if ( deferred ) {
if ( broken.length ) {
deferred.reject( $images, $proper, $broken );
} else {
deferred.resolve( $images );
}
}
if ( $.isFunction( callback ) ) {
callback.call( $this, $images, $proper, $broken );
}
}
function imgLoaded( img, isBroken ) {
// don't proceed if BLANK image, or image is already loaded
if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) {
return;
}
// store element in loaded images array
loaded.push( img );
// keep track of broken and properly loaded images
if ( isBroken ) {
broken.push( img );
} else {
proper.push( img );
}
// cache image and its state for future calls
$.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } );
// trigger deferred progress method if present
if ( hasNotify ) {
deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] );
}
// call doneLoading and clean listeners if all images are loaded
if ( $images.length === loaded.length ){
setTimeout( doneLoading );
$images.unbind( '.imagesLoaded' );
}
}
// if no images, trigger immediately
if ( !$images.length ) {
doneLoading();
} else {
$images.bind( 'load.imagesLoaded error.imagesLoaded', function( event ){
// trigger imgLoaded
imgLoaded( event.target, event.type === 'error' );
}).each( function( i, el ) {
var src = el.src;
// find out if this image has been already checked for status
// if it was, and src has not changed, call imgLoaded on it
var cached = $.data( el, 'imagesLoaded' );
if ( cached && cached.src === src ) {
imgLoaded( el, cached.isBroken );
return;
}
// if complete is true and browser supports natural sizes, try
// to check for image status manually
if ( el.complete && el.naturalWidth !== undefined ) {
imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 );
return;
}
// cached images don't fire load sometimes, so we reset src, but only when
// dealing with IE, or image is complete (loaded) and failed manual check
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
if ( el.readyState || el.complete ) {
el.src = BLANK;
el.src = src;
}
});
}
return deferred ? deferred.promise( $this ) : $this;
};
var Grid = (function() {
// list of items
var $grid = $( '#gallery-grid' ),
// the items
$items = $grid.children( 'li' ),
// current expanded item's index
current = -1,
// position (top) of the expanded item
// used to know if the preview will expand in a different row
previewPos = -1,
// extra amount of pixels to scroll the window
scrollExtra = 0,
// extra margin when expanded (between preview overlay and the next items)
marginExpanded = 10,
$window = $( window ), winsize,
$body = $( 'html, body' ),
// transitionend events
transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
// support for csstransitions
support = Modernizr.csstransitions,
// default settings
settings = {
minHeight : 500,
speed : 350,
easing : 'ease'
};
function init( config ) {
// the settings..
settings = $.extend( true, {}, settings, config );
// preload all images
$grid.imagesLoaded( function() {
// save item´s size and offset
saveItemInfo( true );
// get window´s size
getWinSize();
// initialize some events
initEvents();
} );
}
// add more items to the grid.
// the new items need to appended to the grid.
// after that call Grid.addItems(theItems);
function addItems( $newitems ) {
$items = $items.add( $newitems );
$newitems.each( function() {
var $item = $( this );
$item.data( {
offsetTop : $item.offset().top,
height : $item.height()
} );
} );
initItemsEvents( $newitems );
}
// saves the item´s offset top and height (if saveheight is true)
function saveItemInfo( saveheight ) {
$items.each( function() {
var $item = $( this );
$item.data( 'offsetTop', $item.offset().top );
if( saveheight ) {
$item.data( 'height', $item.height() );
}
} );
}
function initEvents() {
// when clicking an item, show the preview with the item´s info and large image.
// close the item if already expanded.
// also close if clicking on the item´s cross
initItemsEvents( $items );
// on window resize get the window´s size again
// reset some values..
$window.on( 'debouncedresize', function() {
scrollExtra = 0;
previewPos = -1;
// save item´s offset
saveItemInfo();
getWinSize();
var preview = $.data( this, 'preview' );
if( typeof preview != 'undefined' ) {
hidePreview();
}
} );
}
function initItemsEvents( $items ) {
$items.on( 'click', 'span.gallery-close', function() {
hidePreview();
return false;
} ).children( 'a' ).on( 'click', function(e) {
var $item = $( this ).parent();
// check if item already opened
current === $item.index() ? hidePreview() : showPreview( $item );
return false;
} );
}
function getWinSize() {
winsize = { width : $window.width(), height : $window.height() };
}
function showPreview( $item ) {
var preview = $.data( this, 'preview' ),
// item´s offset top
position = $item.data( 'offsetTop' );
scrollExtra = 0;
// if a preview exists and previewPos is different (different row) from item´s top then close it
if( typeof preview != 'undefined' ) {
// not in the same row
if( previewPos !== position ) {
// if position > previewPos then we need to take te current preview´s height in consideration when scrolling the window
if( position > previewPos ) {
scrollExtra = preview.height;
}
hidePreview();
}
// same row
else {
preview.update( $item );
return false;
}
}
// update previewPos
previewPos = position;
// initialize new preview for the clicked item
preview = $.data( this, 'preview', new Preview( $item ) );
// expand preview overlay
preview.open();
}
function hidePreview() {
current = -1;
var preview = $.data( this, 'preview' );
preview.close();
$.removeData( this, 'preview' );
}
// the preview obj / overlay
function Preview( $item ) {
this.$item = $item;
this.expandedIdx = this.$item.index();
this.create();
this.update();
}
Preview.prototype = {
create : function() {
if(typeof previousItem != 'undefined' || previousItem){
previousItem.append('<div class="portfolio_description">'+accordionHTML+'</div>')
}
// create Preview structure:
//this.$title = $( '<h3></h3>' );
this.$description = $( '<div></div>' );
//this.$href = $( 'Visit website' );
//this.$details = $( '<div class="gallery-details"></div>' ).append( this.$title, this.$description, this.$href );
this.$details = $( '<div class="gallery-details"></div>' ).append( this.$description );
//console.log(this);
this.$loading = $( '<div class="gallery-loading"></div>' );
this.$fullimage = $( '<div class="gallery-fullimg"></div>' ).append( this.$loading );
this.$closePreview = $( '<span class="gallery-close"></span>' );
this.$previewInner = $( '<div class="gallery-expander-inner"></div>' ).append( this.$closePreview, this.$fullimage, this.$details );
this.$previewEl = $( '<div class="gallery-expander"></div>' ).append( this.$previewInner );
// append preview element to the item
this.$item.append( this.getEl() );
// set the transitions for the preview and the item
if( support ) {
this.setTransition();
}
},
update : function( $item ) {
if(typeof previousItem != 'undefined' || previousItem){
previousItem.append('<div class="portfolio_description">'+accordionHTML+'</div>')
}
if( $item ) {
this.$item = $item;
}
// if already expanded remove class "gallery-expanded" from current item and add it to new item
if( current !== -1 ) {
var $currentItem = $items.eq( current );
$currentItem.removeClass( 'gallery-expanded' );
this.$item.addClass( 'gallery-expanded' );
// position the preview correctly
this.positionPreview();
}
// update current value
current = this.$item.index();
// update preview's content
var $itemEl = this.$item.children( 'a' ),
eldata = {
// href : $itemEl.attr( 'href' ),
// largesrc : $itemEl.data( 'largesrc' ),
largesrc : $itemEl.find('img').attr('src'),
// title : $itemEl.data( 'title' ),
// description : $itemEl.data( 'description' ),
description : $itemEl.parent().find('.portfolio_description').html()
//description : 'test'
};
//this.$title.html( eldata.title );
this.$description.html( eldata.description );
accordionHTML =eldata.description;
previousItem = this.$item;
this.$item.children( 'a' ).parent().find('.portfolio_description').remove();
//this.$href.attr( 'href', eldata.href );
var self = this;
// remove the current image in the preview
if( typeof self.$largeImg != 'undefined' ) {
self.$largeImg.remove();
}
// preload large image and add it to the preview
// for smaller screens we don´t display the large image (the media query will hide the fullimage wrapper)
if( self.$fullimage.is( ':visible' ) ) {
this.$loading.show();
$( '<img/>' ).load( function() {
var $img = $( this );
if( $img.attr( 'src' ) === self.$item.children('a').data( 'largesrc' ) ) {
self.$loading.hide();
self.$fullimage.find( 'img' ).remove();
self.$largeImg = $img.fadeIn( 350 );
self.$fullimage.append( self.$largeImg );
}
} ).attr( 'src', eldata.largesrc );
}
},
open : function() {
setTimeout( $.proxy( function() {
// set the height for the preview and the item
this.setHeights();
// scroll to position the preview in the right place
this.positionPreview();
}, this ), 25 );
},
close : function() {
var self = this,
onEndFn = function() {
if( support ) {
$( this ).off( transEndEventName );
}
self.$item.removeClass( 'gallery-expanded' );
self.$previewEl.remove();
self.$item.append('<div id="ss" class="portfolio_description">'+accordionHTML+'</div>')
};
setTimeout( $.proxy( function() {
if( typeof this.$largeImg !== 'undefined' ) {
this.$largeImg.fadeOut( 'fast' );
}
this.$previewEl.css( 'height', 0 );
// the current expanded item (might be different from this.$item)
var $expandedItem = $items.eq( this.expandedIdx );
$expandedItem.css( 'height', $expandedItem.data( 'height' ) ).on( transEndEventName, onEndFn );
if( !support ) {
onEndFn.call();
}
}, this ), 25 );
return false;
},
calcHeight : function() {
var heightPreview = winsize.height - this.$item.data( 'height' ) - marginExpanded,
itemHeight = winsize.height;
if( heightPreview < settings.minHeight ) {
heightPreview = settings.minHeight;
itemHeight = settings.minHeight + this.$item.data( 'height' ) + marginExpanded;
}
this.height = heightPreview;
this.itemHeight = itemHeight;
},
setHeights : function() {
var self = this,
onEndFn = function() {
if( support ) {
self.$item.off( transEndEventName );
}
self.$item.addClass( 'gallery-expanded' );
};
this.calcHeight();
this.$previewEl.css( 'height', this.height );
this.$item.css( 'height', this.itemHeight ).on( transEndEventName, onEndFn );
if( !support ) {
onEndFn.call();
}
},
positionPreview : function() {
// scroll page
// case 1 : preview height + item height fits in window´s height
// case 2 : preview height + item height does not fit in window´s height and preview height is smaller than window´s height
// case 3 : preview height + item height does not fit in window´s height and preview height is bigger than window´s height
var position = this.$item.data( 'offsetTop' ),
previewOffsetT = this.$previewEl.offset().top - scrollExtra,
scrollVal = this.height + this.$item.data( 'height' ) + marginExpanded <= winsize.height ? position : this.height < winsize.height ? previewOffsetT - ( winsize.height - this.height ) : previewOffsetT;
$body.animate( { scrollTop : scrollVal }, settings.speed );
},
setTransition : function() {
this.$previewEl.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing );
this.$item.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing );
},
getEl : function() {
return this.$previewEl;
}
}
return {
init : init,
addItems : addItems
};
})();

Call Javascript Function from URL

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.

Responsive Multi-Level Menu - How to close menu when link is clicked?

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');
});

Morphing buttons concept not working in internet explorer IE 9

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

Background switcher

Hi everyone I'm having an issue that I can't seem to wrap my head around. I'll try to keep this as brief as possible.
I'm attempting to set and get cookies in the background switcher I'm using. The switcher works well... It iterates through 7 background themes on click and the cookies seem to be working as well, but still on page refresh it reverts back to to the default "theme". I don't think it's a problem with the cookies because according to the alerts I attached to the cookies, it's returning the correct background (in the alert). It's just not loading the correct theme even though the cookie says it is.
I believe I narrowed it down to a bit of code in my javascript that might be responsible for the wrong background, however I don't know how to adjust it to make it do what I want.
The background (on refresh) will be whatever var current says it will be. Values of 0-6 will be a new background (on refresh) depending on what value it is. But it doesn't remember the user's selection on refresh. I've tried making var current into an array var current = [0,1,2,3,4,5,6],, but that didn't seem to help. When I did that it didn't show any of my 7 themes, and only showed the default color in body tag css.
When I tried the array, I changed this:
if( current < pagesCount - 1 ) {
++current;
alert($.cookie('style', current, { expires: 365, path: '/' }));
}
else {
current = 0;
}
to this:
for(var i = 0; i < current.length; i++){
if( current < pagesCount - 1 ) {
++current;
alert($.cookie('style', current, { expires: 365, path: '/' }));
}
else {
current = 0;
}
}
This is the click function, but I didn't change anything here
$iterate.on( 'click', function() {
if( isAnimating ) {
return false;
}
nextPage( animcursor);
++animcursor;
} );
I'm still pretty inexperienced with javascript so I'm sure there's a better way to do what I'm trying for. Any help would be appreciated! Thanks in advance.
The entire code block:
var changeTheme = (function() {
var $main = $( '#bg-main' ),
$pages = $main.children( 'div.bg-page' ),
$iterate = $( '#iterateEffects' ),
animcursor = 1,
pagesCount = $pages.length,
current = 0,
isAnimating = false,
endCurrPage = false,
endNextPage = false,
animEndEventNames = {
'WebkitAnimation' : 'webkitAnimationEnd',
'OAnimation' : 'oAnimationEnd',
'msAnimation' : 'MSAnimationEnd',
'animation' : 'animationend'
},
// animation end event name
animEndEventName = animEndEventNames[ Modernizr.prefixed( 'animation' ) ],
// support css animations
support = Modernizr.cssanimations;
function init() {
$pages.each( function() {
var $page = $( this );
$page.data( 'originalClassList', $page.attr( 'class' ) );
} );
$pages.eq( current ).addClass( 'bg-page-current' );
$iterate.on( 'click', function() {
if( isAnimating ) {
return false;
}
nextPage( animcursor);
++animcursor;
} );
}
function nextPage( animation ) {
if( isAnimating ) {
return false;
}
isAnimating = true;
var $currPage = $pages.eq( current );
if( current < pagesCount - 1 ) {
++current;
alert($.cookie('style', current, { expires: 365, path: '/' }));
}
else {
current = 0;
}
var $nextPage = $pages.eq( current ).addClass( 'bg-page-current' ),
outClass = '', inClass = '';
outClass = 'bg-page-scaleDown';
inClass = 'bg-page-scaleUpDown bg-page-delay300';
var classes = ['bg-page-0 bg-page-current','bg-page-1 bg-page-current', 'bg-page-2 bg-page-current', 'bg-page-3 bg-page-current', 'bg-page-4 bg-page-current', 'bg-page-5 bg-page-current', 'bg-page-6 bg-page-current'];
$currPage.addClass( outClass ).on( animEndEventName, function() {
$currPage.off( animEndEventName );
endCurrPage = true;
if( endNextPage ) {
onEndAnimation( $currPage, $nextPage );
}
} );
$nextPage.addClass( inClass ).on( animEndEventName, function() {
$nextPage.off( animEndEventName );
endNextPage = true;
if( endCurrPage ) {
onEndAnimation( $currPage, $nextPage );
}
} );
if( !support ) {
onEndAnimation( $currPage, $nextPage );
}
}
function onEndAnimation( $outpage, $inpage ) {
endCurrPage = false;
endNextPage = false;
resetPage( $outpage, $inpage );
isAnimating = false;
}
function resetPage( $outpage, $inpage ) {
$outpage.attr( 'class', $outpage.data( 'originalClassList' ) );
$inpage.attr( 'class', $inpage.data( 'originalClassList' ) + ' bg-page-current' );
}
//Cookies
window.onload = function(e) {
if($.cookie('style') == undefined) {
alert($.cookie('style', current, { expires: 365, path: '/' }));
current = 0;
} else {
current = current;
alert($.cookie('style'));
}
}
init();
return { init : init };
})();
If this hits the 'else' portion of the if statement, current is not defined on page load. I think you'd need do do something like
current = $.cookie('style');
Or is it always reporting as undefined on page load?
I'd just of made a comment, but lack of rep points prevents this.
//Cookies
window.onload = function(e) {
if($.cookie('style') == undefined) {
alert($.cookie('style', current, { expires: 365, path: '/' }));
current = 0;
} else {
current = current;
alert($.cookie('style'));
}
}

Categories