Trigger method defined in javascript object, but outside of the object itself - javascript

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.

Related

Get/Set the index of the last opened li using jquery

I am using an accordion and trying to achieve the below:
Every time there is a post back, display/expand the last opened/active li that was shown before. At the moment, the page is refreshed and go back to its initial stage (all li closed). Is it possible to achieve this ?
I tried different things but without success e.g. I tried to save the last opened/active li index into a hidden aspx text box but it didn't work. Also, I tried to save the index in a cookie but again without success.
$('#st-accordion').accordion({
open: -1
});
Can I replace the -1 with a dynamic way of getting the index of the last opened li without losing it after post back ? In addition, how can I handle situations that more than one li were opened/expanded.
Any ideas would be much appreciated.
<link rel="stylesheet" type="text/css" href="../Content/style.css" />
<script type="text/javascript" src="../Scripts/jquery.accordion.js">
</script>
<script type="text/javascript" src="../Scripts/jquery.easing.1.3.js"></script>
<asp:UpdatePanel ID="UpdatePanelForm" runat="server">
<ContentTemplate>
<h2><asp:Label ID="TitleLbl" runat="server" Text=""></asp:Label></h2>
<div class="wrapper">
<div id="st-accordion" class="st-accordion">
<ul>
<li>
Section 1<span class="st-arrow" />
<div class="st-content">
Content 1
</div>
</li>
<li>
Section 2<span class="st-arrow" />
<div class="st-content">
Content 2
</div>
</li>
<li>
Section 3<span class="st-arrow" />
<div class="st-content">
<asp:LinkButton ID="LinkButtonEdit" OnClick="LinkButtonEdit_Click" CommandName="Select" runat="server">Edit</asp:LinkButton>
</div>
</li>
</ul>
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
<script type="text/javascript">
function pageLoad(sender, args) {
$(document).ready(function () {
$('#st-accordion').accordion({
open: -1
});
});
}
</script>
(function (window, $, undefined) {
/*
* smartresize: debounced resize event for jQuery
*
*
* Copyright 2011 #louis_remi
* Licensed under the MIT license.
*/
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);
You can use sessionStorage in order to save some js variables with the last opened/expanded li, you can set it on open/expand event:
sessionStorage.SessionName = "SessionName";
sessionStorage.getItem("SessionName");
sessionStorage.setItem("SessionName","10");
Or you can use cookies (client side):
document.cookie

How Can i call from external js file

I have a javascript file that contains the following objects and functions........
;( 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 );
}
// 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();
},
// 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;
},
// add to global namespace
window.mlPushMenu = mlPushMenu;
} )( window );
The question I have is how do I call the object _resetMenu in another script. to my poor knowledge it should be ......
window.mlPushMenu._resetMenu();
that should execute that object in my mind but it isn't working so clealy I am wrong ... Any help here would be much appreciated..
this is the example of the button I have created thus far.....
$('.iconM-referrals').on('click', function () {
window.mlPushMenu._resetMenu();
$("#colorscreen").remove();
$("body").append('<div id="colorscreen" class="animated"></div>');
$("#colorscreen").addClass("fadeInUpBig");
$('.fadeInUpBig').css('background-color', 'rgba(13,135,22,0.3)');
The way you have mlPushMenu set up is as a Constructor, not as a stand-alone module. (See: Any tutorial on Object-Oriented programming) You'd need to construct an instance variable to call the function. For instance:
myInstanceOfPushMenu = new mlPushMenu();
myInstanceOfPushMenu._resetMenu();
This, however, is assuming that the script inclusion and declaration, and anything left out of your question, is all set up properly.

how do i call this javascript object from a js file

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

Target ID instead of <li>

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

How can I add a css element change to an onlick event in this jquery lib?

I've got this awesome slideshow library working just fine on my site (yoinked from codrops), but since I'm shifting between different pieces of information, I want to really call out the difference by adding a CSS change so that the background color matches the color of the content in the slide. Now, this is a library, so i figure I need to add the $('body').css call into it, and not my html doc. I'm including the code below, with a note marking where I think it's supposed to go. I'm jsut not sure what the exact phrasing would be since I've never worked inside a lib before. Any suggestions would be welcome!
;( function( $, window, undefined ) {
'use strict';
// global
var Modernizr = window.Modernizr;
$.CBPFWSlider = function( options, element ) {
this.$el = $( element );
this._init( options );
};
// the options
$.CBPFWSlider.defaults = {
// default transition speed (ms)
speed : 500,
// default transition easing
easing : 'ease'
};
$.CBPFWSlider.prototype = {
_init : function( options ) {
// options
this.options = $.extend( true, {}, $.CBPFWSlider.defaults, options );
// cache some elements and initialize some variables
this._config();
// initialize/bind the events
this._initEvents();
},
_config : function() {
// the list of items
this.$list = this.$el.children( 'ul' );
// the items (li elements)
this.$items = this.$list.children( 'li' );
// total number of items
this.itemsCount = this.$items.length;
// support for CSS Transitions & transforms
this.support = Modernizr.csstransitions && Modernizr.csstransforms;
this.support3d = Modernizr.csstransforms3d;
// transition end event name and transform name
var transProperties = {
'WebkitTransition' : { transitionEndEvent : 'webkitTransitionEnd', tranformName : '-webkit-transform' },
'MozTransition' : { transitionEndEvent : 'transitionend', tranformName : '-moz-transform' },
'OTransition' : { transitionEndEvent : 'oTransitionEnd', tranformName : '-o-transform' },
'msTransition' : { transitionEndEvent : 'MSTransitionEnd', tranformName : '-ms-transform' },
'transition' : { transitionEndEvent : 'transitionend', tranformName : 'transform' }
};
if( this.support ) {
this.transEndEventName = transProperties[ Modernizr.prefixed( 'transition' ) ].transitionEndEvent + '.cbpFWSlider';
this.transformName = transProperties[ Modernizr.prefixed( 'transition' ) ].tranformName;
}
// current and old itemĀ“s index
this.current = 0;
this.old = 0;
// check if the list is currently moving
this.isAnimating = false;
// the list (ul) will have a width of 100% x itemsCount
this.$list.css( 'width', 100 * this.itemsCount + '%' );
// apply the transition
if( this.support ) {
this.$list.css( 'transition', this.transformName + ' ' + this.options.speed + 'ms ' + this.options.easing );
}
// each item will have a width of 100 / itemsCount
this.$items.css( 'width', 100 / this.itemsCount + '%' );
// add navigation arrows and the navigation dots if there is more than 1 item
if( this.itemsCount > 1 ) {
// add navigation arrows (the previous arrow is not shown initially):
this.$navPrev = $( '<span class="cbp-fwprev"><</span>' ).hide();
this.$navNext = $( '<span class="cbp-fwnext">></span>' );
$( '<nav/>' ).append( this.$navPrev, this.$navNext ).appendTo( this.$el );
// add navigation dots
var dots = '';
for( var i = 0; i < this.itemsCount; ++i ) {
// current dot will have the class cbp-fwcurrent
var dot = i === this.current ? '<span class="cbp-fwcurrent"></span>' : '<span></span>';
dots += dot;
}
var navDots = $( '<div class="cbp-fwdots"/>' ).append( dots ).appendTo( this.$el );
this.$navDots = navDots.children( 'span' );
}
},
_initEvents : function() {
var self = this;
if( this.itemsCount > 1 ) {
this.$navPrev.on( 'click.cbpFWSlider', $.proxy( this._navigate, this, 'previous' ) );
this.$navNext.on( 'click.cbpFWSlider', $.proxy( this._navigate, this, 'next' ) );
this.$navDots.on( 'click.cbpFWSlider', function() { self._jump( $( this ).index() ); } );
}
},
_navigate : function( direction ) {
// do nothing if the list is currently moving
if( this.isAnimating ) {
return false;
}
this.isAnimating = true;
// update old and current values
this.old = this.current;
if( direction === 'next' && this.current < this.itemsCount - 1 ) {
++this.current;
//***I think maybe it goes here?!?
}
else if( direction === 'previous' && this.current > 0 ) {
--this.current;
//***I think maybe it goes here?!?
}
// slide
this._slide();
},
_slide : function() {
// check which navigation arrows should be shown
this._toggleNavControls();
// translate value
var translateVal = -1 * this.current * 100 / this.itemsCount;
if( this.support ) {
this.$list.css( 'transform', this.support3d ? 'translate3d(' + translateVal + '%,0,0)' : 'translate(' + translateVal + '%)' );
}
else {
this.$list.css( 'margin-left', -1 * this.current * 100 + '%' );
}
var transitionendfn = $.proxy( function() {
this.isAnimating = false;
}, this );
if( this.support ) {
this.$list.on( this.transEndEventName, $.proxy( transitionendfn, this ) );
}
else {
transitionendfn.call();
}
},
_toggleNavControls : function() {
// if the current item is the first one in the list, the left arrow is not shown
// if the current item is the last one in the list, the right arrow is not shown
switch( this.current ) {
case 0 : this.$navNext.show(); this.$navPrev.hide(); break;
case this.itemsCount - 1 : this.$navNext.hide(); this.$navPrev.show(); break;
default : this.$navNext.show(); this.$navPrev.show(); break;
}
// highlight navigation dot
this.$navDots.eq( this.old ).removeClass( 'cbp-fwcurrent' ).end().eq( this.current ).addClass( 'cbp-fwcurrent' );
},
_jump : function( position ) {
// do nothing if clicking on the current dot, or if the list is currently moving
if( position === this.current || this.isAnimating ) {
return false;
}
this.isAnimating = true;
// update old and current values
this.old = this.current;
this.current = position;
// slide
this._slide();
},
destroy : function() {
if( this.itemsCount > 1 ) {
this.$navPrev.parent().remove();
this.$navDots.parent().remove();
}
this.$list.css( 'width', 'auto' );
if( this.support ) {
this.$list.css( 'transition', 'none' );
}
this.$items.css( 'width', 'auto' );
}
};
var logError = function( message ) {
if ( window.console ) {
window.console.error( message );
}
};
$.fn.cbpFWSlider = function( options ) {
if ( typeof options === 'string' ) {
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function() {
var instance = $.data( this, 'cbpFWSlider' );
if ( !instance ) {
logError( "cannot call methods on cbpFWSlider prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for cbpFWSlider instance" );
return;
}
instance[ options ].apply( instance, args );
});
}
else {
this.each(function() {
var instance = $.data( this, 'cbpFWSlider' );
if ( instance ) {
instance._init();
}
else {
instance = $.data( this, 'cbpFWSlider', new $.CBPFWSlider( options, this ) );
}
});
}
return this;
};
} )( jQuery, window );
Answered my own question with a little digging.
_navigate : function( direction ) {
// do nothing if the list is currently moving
if( this.isAnimating ) {
return false;
}
this.isAnimating = true;
// update old and current values
this.old = this.current;
if( direction === 'next' && this.current < this.itemsCount - 1 ) {
++this.current;
}
else if( direction === 'previous' && this.current > 0 ) {
--this.current;
}
console.log(this.current);
if(this.current == 0)
{
$('body').css('background', '#FF6A00');
}else if(this.current == 1)
{
$('body').css('background', '#595C5A');
}else if(this.current == 2)
{
$('body').css('background', '#000000');
}
// slide //AROUND HERE?
this._slide();
},

Categories