/**
* jquery.LavaLamp v1.4 - light up your menus with fluid, jQuery powered animations.
*
* Requires jQuery v1.2.3 or better from http://jquery.com
* Tested on jQuery 1.4.4, 1.3.2 and 1.2.6
*
* http://nixbox.com/projects/jquery-lavalamp/
*
* Copyright (c) 2008, 2009, 2010, 2012 Jolyon Terwilliger, jolyon@nixbox.com
* Source code Copyright (c) 2008, 2009, 2010, 2012
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* credits to Guillermo Rauch and Ganeshji Marwaha (gmarwaha.com) for previous editions
*
* Version: 1.0 - adapted for jQuery 1.2.x series
* Version: 1.1 - added linum parameter
* Version: 1.2 - modified to support vertical resizing of elements
* Version: 1.3 - enhanced automatic
item hi-lighting - will attempt to
* lock onto li > a element with href closest to selected
* window.location
* - click always returns 'true' by default, for standard link follow through.
*
* Version: 1.3.1 - verified for use with jQuery 1.3 - should still work with 1.2.x series
* - changed linum parameter to startItem for clarity
* - improved slide-in accuracy for .back elements with borders
* - changed .current class to .selectedLava for clarity and improved
* support
* - appended 'Lava' to all internal class names to avoid conflicts
* - fixed bug applying selectedLava class to elements with matching
* location.hash
* - now supports jquery.compat plugin for cross-library support
* - performance improvements
* - added new options:
* autoReturn: true - if set to false, hover will not return to last selected
* item upon list mouseout.
* returnDelay: 0 - if set, will delay auto-return feature specified # of
* milliseconds.
* setOnClick: true - if set to false, hover will return to default element
* regardless of click event.
* homeLeft: 0, homeTop: 0 - if either set to non zero value, absolute
* positioned li element with class .homeLava is
* prepended to list for homing feature.
* homeWidth: 0, homeHeight: 0 - if set, are used for creation of li.homeLava
* element.
* returnHome: false - if set along with homeLeft or homeTop, lavalamp hover
* will always return to li.home after click.
*
* Version: 1.3.2 - fixed: stray $ references inside the plugin to work with
* jQuery.noConflict() properly - thanks Colin.
*
* Version: 1.3.3 - fixed: added closure with null passed argument for move() command in
* returnDelay to fix errors some were seeing - thanks to Michel and
* Richard for noticing this.
*
* fixed: changed mouseover/out events to mouseenter/leave to fix jerky
* animation problem when using excessive margins instead of padding.
* Thanks to Thomas for the solution and Chris for demonstrating the problem.
* * requires jQuery 1.3 or better
*
* enhanced: added 'noLava' class detection to prevent LavaLamp effect
* application to LI elements with this class. This feature allows you to
* create submenus - for details, see examples at
* http://nixboxdesigns.com/demos/jquery-lavalamp-demos.html
*
* enhanced: modified to better automatically find default location for
* relative links. Thanks to Harold for testing and finding this bug.
*
* Version: 1.3.4 - major overhaul on practically everything:
* enhanced: added autoResize option; see examples below.
* enhanced: better automatic default item selection and URI resolution,
* better support for returnHome and returnDelay, refined internal variable
* usage and test to be as lean as possible
* fixed: backLava hover element now exactly covers the destination LI dimensions.
* fixed: changed use of mouseleave/mouseenter to bind events so will work with
* jQuery 1.2.2 onward.
* fixed: proper closure on instance - should finally play nice with other libraries
* fixed: proper quotes around all object element labels.
* enhanced: behaves more like a plugin should and now automatically adds proper
* position and display CSS tags to the backLava element and parent container
* if absent.
*
* Version: 1.3.5 - new options:
* target: 'li' - plain element to target to receive hover events.
* container: '' - plain element to create for the hover .backLava and .homeLava
* elements. If left blank (default) same value as target option is used.
* includeMargins: false - set to true to expand the hover element dimensions to
* include the margins of the target element.
* changed: the backLava hover element now has all margins and padding manually set to
* zero to allow proper resizing of hover when used with custom target, container
* and includeMargins options. While this workaround has no effect with the site
* demos, it potentially may affect your current implementation. If you do
* experience problems try re-adjusting the CSS padding and margins for
* your target elements.
*
* Version: 1.4 - new options:
* hoverStart, hoverFinish, returnStart, returnFinish - callbacks for different stages
* of the hover process.
* selectClass, homeClass, skipClass - optional overrides for internally used classes
* 'selectedLava', 'homeLava' and 'noLava'
* fixed: improved check for skipClass (noLava)
* enhanced: lava animations now trigger on focusin and focusout to support keyboard usage
*
* thanks to: MoOx for the customizable class and keyboard support suggestion
* many people who identified the noLava bug
*
*
* Examples and usage:
*
* The HTML markup used to build the menu can be as simple as...
*
*
*
* Additional Styles must be added to make the LavaLamp perform properly, to wit:
*
*
*
* Once you have included the basic styles above, you will need to include
* the jQuery library, easing plugin (optional) and the this LavaLamp plugin.
*
* jQuery Easing Library 1.3 available here: http://plugins.jquery.com/project/Easing
*
* Example LavaLamp initializing statement:
* $(function() { $("ul.lavaLamp").lavaLamp({ fx: "easeOutBack", speed: 700}) });
* finds all UL elements in the document with the class of 'lavaLamp' and attaches the
* LavaLamp plugin using an easing library fx of OutBack and an animate speed of
* 700 milliseconds or 7/10ths of a second.
*
*
* List of Parameters
*
* @param target - default: 'li'
* valid selector for target elements to receive hover effect.
*
* Example:
* jQuery("div#article").lavaLamp({ target:'p' });
* assigns all p elements under div#article to receive lavaLamp hover events.
*
* @param container - default: '' (empty string)
* DOM element to create for the hover element. If container is empty, LavaLamp
* will assume it is the same as the target option.
*
* Example:
* jQuery("div#article").lavaLamp({ container:'p' });
* creates a p element under div#article to act as the animated hover container, and optionally the
* home container, if homing options are enabled
* use in combination with 'target' option for best results (see above)
*
* @param fx - default: 'swing'
* selects the easing formula for the animation - requires the jQuery Easing library
* to be loaded for additional effects
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ fx: "easeOutElastic" });
* animates the backLava element using the OutElastic formula
*
* @param speed - default: 500
* sets animation speed in milliseconds
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ speed: 1000 });
* sets the animation speed to one second.
*
* @param click - default: function() { return true; }
* Callback to be executed when the menu item is clicked. The 'event' object and source target
* DOM element will be passed in as arguments so you can use them in your function.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ click: function(event, menuItem) {
* alert(event+el);
* return false;
* } });
*
* causes the browser to display an alert message of the variables passed and
* return false aborts any other click events on child items, including not
* following any links contained within the target
*
* @param startItem - default: 'no'
* specifies the number target element as default, starting with 0 for the first element
* Used to manually set the default lavaLamp hi-light on load.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ startItem: 2 });
* selects the third element in the list as default location for backLava
*
* @param includeMargins - default: false
* expands the hover .backLava element to include the margins of the target element.
* Best used in combination with the target and container options.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ includeMargins: true });
* expands the hover .backLava element dimentions to include the margins of all
* target elements inside ul.lavaLamp.
*
* @param autoReturn - default: true
* defines whether the backLava hover should return to the last selectedClass element
* upon mouseleave.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ autoReturn: false });
* turns off the autoReturn feature - backLava element will stay on the last element
* that you hovered over.
*
* @param returnDelay - default: 0
* how many milliseconds to wait before returning the backLava element to the last
* selected element. Only works if autoReturn is set to true (default setting)
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ returnDelay: 1000 });
* waits one second after mouseleave event before returning to the last selected
* element.
*
* @param setOnClick - default: true
* defines whether a clicked element should receive the selectLava class and become the
* most recently selected element
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ setOnClick:false });
* disables selecting of elements once clicked - after you leave the parent list element
* the backLava will return to the original default element the page was loaded with.
*
* @param homeTop - default: 0
* @param homeLeft - default: 0
* @param homeHeight - default: 0
* @param homeWidth - default: 0
* allows you to define an independent 'home' element where the backLava defaults to or can
* be sent to. This can be used to define a unique starting and/or resting place for the
* backLava upon leaving the parent element.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ homeTop:-100, homeLeft:0, homeHeight:20, homeWidth:600 });
* creates a home element 100 pixels above the parent container with a height of 20px and
* width of 600px. If the parent element has CSS of overflow:hidden, this can provide
* an interesting fly-in effect
*
* @param returnHome - default:false
* adjusts behavior of the backLava element when the mouse leaves the parent container.
* the default behavior of 'false' causes the backLava element to stay on the active menu
* items after it is first triggered. this feature respects the returnDelay parameter, if set.
* this feature overrides the autoReturn parameter.
*
* Example:
* jQuery("ul.lavaLamp").lavaLamp({ returnHome:true });
* causes the backLava element to always return to the homeLava position after
* mouse leaves the parent container. this can be manually triggered by running
* the command jQuery("ul.lavaLamp").mouseover();
*
* @param autoResize - default:false
* triggers the selectedClass mouseenter event when the window is resized
* setting autoResize to true causes the backLava element to reposition and change dimensions
* if the resizing the screen changes the shape of the lavaLamp. Default is false for efficiency
* as this feature is new and seldom needed for stock installs.
*
* Example:
* jQuery('div#articles').lavaLamp({target:'p',autoSize:true});
* causes the backLava element to resize and reposition to the p.`selectedClass` position
* and dimensions when the window resizes.
*
* @param selectClass - default: 'selectedLava'
* @param homeClass - default: 'homeLava'
* @param skipClass - default: 'noLava'
* Overrides for internally used classes
* note: changing these options will break some of the demos
*
* @param hoverStart - default: empty function
* A method to be called when a new target hover animation starts
* The method is called with target element as the only parameter
*
* Example:
* jQuery("div#articles").lavaLamp({hoverStart: function() { alert('new target hover started'); }});
* Triggers an alert message when LavaLamp hover starts moving to a new target element.
*
* @param hoverFinish - default: empty function
* A method to be called when a new target hover animation finishes
* The method is called with target element as the only parameter
*
* Example:
* jQuery("div#articles").lavaLamp({hoverFinish: function() { alert('new target hover finished'); }});
* Triggers an alert message when LavaLamp hover finishes returning to the home element.
*
* @param returnStart - default: empty function
* A method to be called when the hover return animation starts
* The method is called with home element as the only parameter
*
* Example:
* jQuery("div#articles").lavaLamp({returnStart: function() { alert('return hover started'); }});
* Triggers an alert message when LavaLamp hover starts returning to the home element.
*
* @param returnFinish - default: empty function
* A method to be called when the hover return animation finishes
* The method is called with home element as the only parameter
*
* Example:
* jQuery("div#articles").lavaLamp({returnFinish: function() { alert('return hover finished'); }});
* Triggers an alert message when LavaLamp hover finishes returning to the home element.
*/
//console.log();
(function($) {
jQuery.fn.lavaLamp = function(o) {
o = $.extend({
'target': 'li',
'container': '',
'fx': 'swing',
'speed': 500,
'click': function(){return true},
'startItem': '',
'includeMargins': false,
'autoReturn': true,
'returnDelay': 0,
'setOnClick': true,
'homeTop':0,
'homeLeft':0,
'homeWidth':0,
'homeHeight':0,
'returnHome':false,
'autoResize':false,
'selectClass': 'selectedLava',
'homeClass': 'homeLava',
'skipClass': 'noLava',
'returnStart': function(){},
'returnFinish': function(){},
'hoverStart': function(){},
'hoverFinish': function(){}
},
o || {});
// parseInt for easy mathing
function getInt(arg) {
var myint = parseInt(arg);
return (isNaN(myint)? 0: myint);
}
if (o.container == '')
o.container = o.target;
if (o.autoResize)
$(window).resize(function(){
$(o.target+'.'+o.selectClass).trigger('mouseenter');
});
return this.each(function() {
// ensures parent UL or OL element has some positioning
if ($(this).css('position')=='static')
$(this).css('position','relative');
// create homeLava element if origin dimensions set
if (o.homeTop || o.homeLeft) {
var $home = $('<'+o.container+' class="'+o.homeClass+'">'+o.container+'>').css({ 'left':o.homeLeft, 'top':o.homeTop, 'width':o.homeWidth, 'height':o.homeHeight, 'position':'absolute','display':'block' });
$(this).prepend($home);
}
var path = location.pathname + location.search + location.hash, $selected, $back, $lt = $(o.target, this).not('.'+o.skipClass), delayTimer, bx=0, by=0, mh=0, mw=0, ml=0, mt=0;
// start $selected default with CSS `selectedClass`
$selected = $(o.target + '.' + o.selectClass, this);
// override $selected if startItem is set
if (o.startItem != '')
$selected = $lt.eq(o.startItem);
// default to $home element
if ((o.homeTop || o.homeLeft) && $selected.length<1)
$selected = $home;
// loop through all the target element a href tags and
// the longest href to match the location path is deemed the most
// accurate and selected as default
if ($selected.length<1) {
var pathmatch_len=0, $pathel;
$lt.each(function(){
var thishref = $('a:first',this).attr('href');
//console.log(thishref+' size:'+thishref.length);
if (path.indexOf(thishref)>-1 && thishref.length > pathmatch_len )
{
$pathel = $(this);
pathmatch_len = thishref.length;
}
});
if (pathmatch_len>0) {
//console.log('found match:'+$('a:first',$pathel).attr('href'));
$selected = $pathel;
}
//else
//console.log('no match!');
}
// if still no matches, default to the first element
if ( $selected.length<1 )
$selected = $lt.eq(0);
// make sure we only have one element as $selected and apply selectedClass
$selected = $($selected.eq(0).addClass(o.selectClass));
// add mouseover event for every sub element
$lt.bind('mouseenter focusin', function() {
//console.log('mouseenter');
// help backLava behave if returnDelay is set
if(delayTimer) {clearTimeout(delayTimer);delayTimer=null;}
move($(this));
}).click(function(e) {
if (o.setOnClick) {
$selected.removeClass(o.selectClass);
$selected = $(this).addClass(o.selectClass);
}
return o.click.apply(this, [e, this]);
});
// creates and adds to the container a backLava element with absolute positioning
$back = $('<'+o.container+' class="backLava">'+o.container+'>').css({'position':'absolute','display':'block','margin':0,'padding':0}).prependTo(this);
// setting css height and width actually sets the innerHeight and innerWidth, so
// compute border and padding differences on styled backLava element to fit them in also.
if (o.includeMargins) {
mh = getInt($selected.css('marginTop')) + getInt($selected.css('marginBottom'));
mw = getInt($selected.css('marginLeft')) + getInt($selected.css('marginRight'));
}
bx = getInt($back.css('borderLeftWidth'))+getInt($back.css('borderRightWidth'))+getInt($back.css('paddingLeft'))+getInt($back.css('paddingRight'))-mw;
by = getInt($back.css('borderTopWidth'))+getInt($back.css('borderBottomWidth'))+getInt($back.css('paddingTop'))+getInt($back.css('paddingBottom'))-mh;
// set the starting position for the lavalamp hover element: .back
if (o.homeTop || o.homeLeft)
$back.css({ 'left':o.homeLeft, 'top':o.homeTop, 'width':o.homeWidth, 'height':o.homeHeight });
else
{
if (!o.includeMargins) {
ml = (getInt($selected.css('marginLeft')));
mt = (getInt($selected.css('marginTop')));
}
$back.css({ 'left': $selected.position().left+ml, 'top': $selected.position().top+mt, 'width': $selected.outerWidth()-bx, 'height': $selected.outerHeight()-by });
}
// after we leave the container element, move back to default/last clicked element
$(this).bind('mouseleave focusout', function() {
//console.log('mouseleave');
var $returnEl = null;
if (o.returnHome)
$returnEl = $home;
else if (!o.autoReturn)
return true;
if (o.returnDelay) {
if(delayTimer) clearTimeout(delayTimer);
delayTimer = setTimeout(function(){move($returnEl, 'return');},o.returnDelay);
}
else {
move($returnEl, 'return');
}
return true;
});
function move($el, cbType) {
if (cbType == 'return') {
o.returnStart($el);
} else {
o.hoverStart($el);
}
if (!$el) $el = $selected;
if (!o.includeMargins) {
ml = (getInt($el.css('marginLeft')));
mt = (getInt($el.css('marginTop')));
}
var dims = {
'left': $el.position().left+ml,
'top': $el.position().top+mt,
'width': $el.outerWidth()-bx,
'height': $el.outerHeight()-by
};
$back.stop().animate(dims, o.speed, o.fx, function () {
if (cbType == 'return') {
o.returnFinish($el);
} else {
o.hoverFinish($el);
}
});
};
});
};
})(jQuery);