/*
Multiple background CSS Parser for IE6/7/8, Firefox <=3.5
Author: Ben Green (bgreen@chicowebdesign.com)
Date: 101117
License: Free
Usage: background: url(left.gif) no-repeat 0 0, url(right.gif) no-repeat 100% 0, url(middle.gif) repeat-x 0 0;
Also includes support for :active, :hover, and :focus psuedo classes
*/
jQuery(function($){
//conditional for which browsers you want to support (ie6/7/8,firefox<=3.5)
if(($.browser.msie && parseFloat($.browser.version)>=6 && parseFloat($.browser.version)< 9)||
($.browser.mozilla && parseInt($.browser.version.substr(0,1))<=1 && parseInt($.browser.version.substr(2,1))<=9 && parseInt($.browser.version.substr(4,1))<=1)){
//store the loaded css rules
var myCss={};
var putLayerOutside=new Array("input");
/*
Supplementary JQuery Extension:
*
* @author Terry Wooton+Ben Green
* @desc Adds a background layer to an element
* @version 2
* @example
* $("#elaement").addLayer("url('/test.gif') bottom left no-repeat");
* @license free
* @param background css
* @param outer boolean
*
@modified Ben Green to support padding correctly and took off weird extra divs...
and the ability to put extra wrappers on the outside of elements
*/
$.fn.addLayer = function(bg,outer,params) {
$(this).each(function() {
var s = $(this).extend({},params || {});
if(outer){
//put layers on outside
var $this=$(this);
$this.wrap('
');
$last=$this.parent();
$last.css({"margin":$this.css("margin"),
"display":$this.css("display"),
"position":$this.css("position"),
"top":$this.css("top"),
"left":$this.css("left"),
"right":$this.css("right"),
"bottom":$this.css("bottom"),
"float":$this.css("float"),
"clear":$this.css("clear"),
"z-index":$this.css("z-index"),
"height":parseFloat($this.css("height").replace("px",""))+parseFloat($this.css("padding-top").replace("px",""))+parseFloat($this.css("padding-bottom").replace("px","")),
"width":parseFloat($this.css("width").replace("px",""))+parseFloat($this.css("padding-left").replace("px",""))+parseFloat($this.css("padding-right").replace("px","")),
"-moz-border-radius-bottomright":$this.css("-moz-border-radius-bottomright"),
"-moz-border-radius-bottomleft":$this.css("-moz-border-radius-bottomleft"),
"-moz-border-radius-topleft":$this.css("-moz-border-radius-topleft"),
"-moz-border-radius-topright":$this.css("-moz-border-radius-topright"),
"background":bg});
$this.css({"margin":'',
"display":'',
"position":'',
"top":'',
"left":'',
"right":'',
"bottom":'',
"float":'',
"z-index":'',
"clear":'',
"height":'',
"width":'',
"-moz-border-radius-bottomright":'',
"-moz-border-radius-bottomleft":'',
"-moz-border-radius-topleft":'',
"-moz-border-radius-topright":''});
}else{
//put layers on inside
$last = ($(this).find('.add_background:last').length > 0 ? $(this).find('.add_background:last') : $(this));
var innerHtml=$last.html();
if($.browser.msie){
$last.html(''+innerHtml+'
');
}else{
//firefox will add wrapper divs when setting the innerhtml for some reason
$last.empty().append(''+innerHtml+'
');
};
$last = $(this).find('.add_background:last');
if(($.browser.msie && parseFloat($.browser.version)<8)&&($(this).css('position')=="static")){
//width/height screws up negative margin in ie6/7 on elements without position:relative?
$last.css({'background':bg});
}else{
$last.css({'background':bg,'width':'100%','height':'100%'});
};
//take care of any padding that would mess up the layout by using negative margins
var $parent=$last.parent();
var p=new Array($parent.css("padding-top"),$parent.css("padding-right"),$parent.css("padding-bottom"),$parent.css("padding-left"),$parent.css("height"));
if($.browser.msie && parseFloat($.browser.version)<6){
$parent.css("padding","0");
$last.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3]});
}else{
$last.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3], 'margin-top':'-'+p[0],'margin-right':'-'+p[1],'margin-bottom':'-'+p[2],'margin-left':'-'+p[3]});
if($.browser.msie && parseInt($.browser.version)<=7){
//ie 7 won't push everything all the way out all the time so give it a height
$last.css({'height':p[4]});
};
};
//commented out just like extra wrapper div in the constructor above
//$last = $(this).find('.add_background div:last');
if(s.insideCss){
$last.css(s.insideCss);
};
if(s.insideClass)
$last.addClass(s.insideClass);
};
});
};
//End Supplementary Extension
//remove a layer
//@param element: selector for the actual layer element, not the element with the layers
function removeLayer(element){
var $layer=$(element);
var $parent=$layer.parent();
var p=new Array($layer.css("padding-top"),$layer.css("padding-right"),$layer.css("padding-bottom"),$layer.css("padding-left"));
var innerHtml=$layer.html();
$parent.html(innerHtml);
if($.browser.msie && parseFloat($.browser.version)<6){
$parent.css({'padding-top':p[0],'padding-right':p[1],'padding-bottom':p[2],'padding-left':p[3]});
};
};
function removeOuterLayer(element){
var $layer=$(element);
var $child=$($layer.children()[0]);
$child.css({"margin":$layer.css("margin"),
"position":$layer.css("position"),
"top":$layer.css("top"),
"left":$layer.css("left"),
"right":$layer.css("right"),
"bottom":$layer.css("bottom"),
"float":$layer.css("float"),
"clear":$layer.css("clear"),
"z-index":$layer.css("z-index")});
$child.unwrap();
};
//find lower/uppercase combinations and replace with lowercase for compatability
function replaceWithLower(inStr,replaceWith){
var linStr=inStr.toLowerCase();
var pos=linStr.indexOf(replaceWith);
while(pos>-1){
inStr=inStr.substr(0,pos)+replaceWith+inStr.substr(pos+replaceWith.length);
pos=linStr.indexOf(replaceWith,pos+1);
};
return inStr;
};
//read in a selector and output and integer precedence score
function selectorScore(selector,important){
//decendents and siblings aren't any different to us
selector=selector.replace(">"," ").replace("+"," ");
var sSpl=selector.split(" ");
var score=0;
for(var i=0;i-1){
function analyzePosition(p){
var lowest=10000; /*theorical max selector length*/
var which=-1;
for(var i=0;i-1)){
lowest=p[i];
which=i;
};
};
if(lowest==10000) lowest=-1;
return {'lowest':lowest,'which':which};
};
var p=[cPart.indexOf("#",pos),cPart.indexOf(".",pos),cPart.indexOf(":",pos)];
var a=analyzePosition(p);
if(pos==0 && a.lowest>0){
//this item began with an element
score+=1;
pos++;
}else if(pos==0 && a.lowest==-1){
//this item is just an element!
score+=1;
break;
}else if(a.lowest>-1){
if(a.which==0){score+=100; /* id found */ };
if(a.which==1){score+=10; /* class found */ };
if(a.which==2){score+=10; /* psuedo-class found */ };
pos=a.lowest+1;
}else if(pos==0){
score+=1; /* element found */
}else{
break;
};
};
};
return score+(important ? 1000 : 0);
};
//in order to not get messed up on things like:
//rgba(100,100,100,0.5)
//change to:
//rgba(100##comma##100##comma##100##comma##0.5)
//will only do the change on commas inside of parentheses
function replaceInnerComma(str){
var pos=str.indexOf("(");
while(pos>-1){
var endPos=str.indexOf(")",pos+1);
var newMiddle=str.substr(pos,endPos-pos).replace(/,/g,"##comma##");
str=str.substr(0,pos)+newMiddle+str.substr(endPos);
pos=str.indexOf("(",endPos+1);
};
return str;
};
//readCSS - main function to read css
//@param: conts - chunk of css to read in
//@param: prop - which function to look for
//@param: path - path which to make the urls change to (false to disable)
function readCss(conts,prop,path){
var output={};
//get rid of comments
conts=conts.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g,'');
var pos=conts.indexOf(prop);
//loop through all backgrounds in the stylesheet
while(pos>-1){
var bgVal=replaceWithLower($.trim(conts.substr(conts.indexOf(":",pos+1)+1,conts.indexOf(";",pos+1)-conts.indexOf(":",pos+1)-1)),"url(");
//only do anything if there are actually multiple bgs in the property
bgVal=replaceInnerComma(bgVal);
if(bgVal.indexOf(",")>-1){
//make paths relative to the stylesheet work out
if(path){
var urlPos=bgVal.indexOf("url(");
while(urlPos>-1){
//don't do any working on absolute urls
if(bgVal.substr(urlPos+4,7).toLowerCase()!="http://"){
var extraSlash=(bgVal.substr(urlPos+4,1) == '/');
var domain=document.URL.substr(0,document.URL.indexOf('/',9));
bgVal=bgVal.substr(0,urlPos+4)+(extraSlash ? domain :path)+bgVal.substr(urlPos+4);
};
//seek to next
urlPos=bgVal.indexOf("url(",urlPos+1);
};
};
//determine if there was an important in this bg value
var important=bgVal.length;
bgVal=bgVal.replace("!important","");
important=(important==bgVal.length ? false : true);
var prevBrace=conts.lastIndexOf("}",pos)+1;
//Allow for charset
if(conts.lastIndexOf(";",pos)+1>prevBrace) prevBrace=conts.lastIndexOf(";",conts.lastIndexOf("{",pos))+1;
if(prevBrace==-1) prevBrace=0;
var selector = $.trim(conts.substr(prevBrace,conts.lastIndexOf("{",pos)-prevBrace));
//account for multiple selectors
var selSplit=selector.split(",");
for(var i=0;i=0;i--){
vals[i]=$.trim(vals[i].replace(/##comma##/g,","));
};
if(inArray(putLayerOutside,this.tagName.toLowerCase())){
//these layers are going on the outside so it may be an input on ie!
var curLayer=$element.parent();
while(curLayer.parent().hasClass("add_background_outer")){
curLayer=curLayer.parent();
};
for(var i=vals.length-1;i>=0;i--){
if(!curLayer.hasClass("add_background_outer")){
//not enough backgrounds! add more!
$element.addLayer(vals[i],true);
}else{
//we still have backgrounds, let's use 'em
curLayer.css('background',vals[i]);
//jump into the next layer
curLayer=$(curLayer.children()[0]);
};
};
//are there any extra backgrounds?
//if so, axe them!
while(curLayer.hasClass("add_background_outer")){
var saveLayer=curLayer;
//jump into the next layer
curLayer=$(curLayer.children()[0]);
removeOuterLayer(saveLayer);
};
}else{
//replacing current backgrounds
var count=$element.find(".add_background").length;
var curLayer=$($element.children(".add_background")[0]);
for(var i=vals.length-1;i>=0;i--){
if(curLayer.length<1){
//not enough backgrounds! add more!
$element.addLayer(vals[i],false);
}else{
//we still have backgrounds, let's use 'em
curLayer.css('background',vals[i]);
//jump into the next layer
curLayer=$(curLayer.children(".add_background")[0]);
};
};
//are there any extra backgrounds?
//if so, axe them!
while(curLayer.length){
var saveLayer=curLayer;
//jump into the next layer
curLayer=$(curLayer.children(".add_background")[0]);
removeLayer(saveLayer);
};
};
});
};
//mouseover event for elements with hover multiple bgs
function elementMouseover(e){
if($(this).attr("jQueryMultipleBgCurSelector")!=$(this).attr("jQueryMultipleBgActiveSelector")){
applyBg(this,"jQueryMultipleBgHoverSelector");
};
};
//mouseout event for elements with hover multiple bgs
function elementMouseout(e){
applyBg(this,"jQueryMultipleBgStaticSelector");
};
//mousedown event for elements with active multiple bgs
function elementMousedown(e){
applyBg(this,"jQueryMultipleBgActiveSelector");
};
//mouseup event for elements with active multiple bgs
function elementMouseup(e){
if($(this).attr("jQueryMultipleBgHoverSelector")){
applyBg(this,"jQueryMultipleBgHoverSelector");
}else{
applyBg(this,"jQueryMultipleBgStaticSelector");
};
};
//focus event for elements with focus multiple bgs
function elementFocus(e){
applyBg(this,"jQueryMultipleBgFocusSelector");
};
//blur event for elements with focus multiple bgs
function elementBlur(e){
applyBg(this,"jQueryMultipleBgStaticSelector");
};
// Returns true if the passed value is found in the
// array. Returns false if it is not.
function inArray(myArray,value,caseSensitive) {
var i;
for (i=0; i < myArray.length; i++) {
// use === to check for Matches. ie., identical (===),
if(caseSensitive){ //performs match even the string is case sensitive
if (myArray[i].toLowerCase() == value.toLowerCase()) {
return true;
};
}else{
if (myArray[i] == value) {
return true;
};
};
};
return false;
};
//apply an array of css selectors with multiple backgrounds
function applyCss(root){
if(root==undefined) root=document;
for(var sel in myCss){
var lsel=sel.toLowerCase();
if((lsel.indexOf(":hover")>-1)||(lsel.indexOf(":active")>-1)||(lsel.indexOf(":focus")>-1)){
var leftSide, rightSide;
if(lsel.indexOf(":hover")>-1){
leftSide=sel.substr(0,lsel.indexOf(":hover"));
rightSide=sel.substr(lsel.indexOf(":hover")+6);
//set the reference selector on each element
$(leftSide+rightSide,root).each(function(){
var curSelector=$(this).attr("jQueryMultipleBgHoverSelector");
//make sure the current selector still works
if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":hover").replace(/:hover/g,'')),this))) curSelector=undefined;
if((!curSelector)||(myCss[curSelector].selScore-1){
leftSide=sel.substr(0,lsel.indexOf(":active"));
rightSide=sel.substr(lsel.indexOf(":active")+7);
//set the reference selector on each element
$(leftSide+rightSide,root).each(function(){
var curSelector=$(this).attr("jQueryMultipleBgActiveSelector");
//make sure the current selector still works
if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":active").replace(/:active/g,'')),this))) curSelector=undefined;
if((!curSelector)||(myCss[curSelector].selScore-1){
leftSide=sel.substr(0,lsel.indexOf(":focus"));
rightSide=sel.substr(lsel.indexOf(":focus")+6);
//set the reference selector on each element
$(leftSide+rightSide,root).each(function(){
var curSelector=$(this).attr("jQueryMultipleBgFocusSelector");
//make sure the current selector still works
if((curSelector)&&(!inArray($(replaceWithLower(curSelector,":focus").replace(/:focus/g,'')),this))) curSelector=undefined;
if((!curSelector)||(myCss[curSelector].selScore