// JavaScript Document
//JS Functions for compare
function goto(card1,card2,server){
	
	var url = 'http://'+server+'/compare/'+card1+'-vs-'+card2;
	window.location=url;
}
function gotocu(cu,card1,card2,server,card_url){
	
	var url = 'http://'+server+'/credit-union/'+cu+'|'+card1+'|'+card2+'|'+card_url;
	window.location=url;
}
//JS functions for Star Rating System
function getCookie(c_name)
{
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
  {
  x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
  y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
  x=x.replace(/^\s+|\s+$/g,"");
  if (x==c_name)
    {
    return unescape(y);
    }
  }
}
function cookieExists(cookiename)
{
	var cookie=getCookie(cookiename);
	if (cookie!=null && cookie!="")
	  {
		 return 1;
	  }
	else return 0;
}


//JS functions for Google Maps Interface
function showMap(state){	
	var show = false;
    cu_el = document.getElementById('credit_union');
	if(cu_el && (state==1 || state==4)) {
            if(document.getElementById('credit_union').checked) show = true;
        }
	return show;
}
function showSlider(state){
	var show = false;
	if(document.getElementById('credit_union').checked){
       show = true;
	}
	
	return show;

}
function verifyZipRange(id,fallback){
        var valid = false;
        var zipCodePattern = /^\d{5}$/;
	var object = document.getElementById(id);
	if(zipCodePattern.test(object.value)) {
            valid=true;
            indicateValidZipRange(id);
        } else {
            object.value=fallback;
            indicateInvalidZipRange(id);
        }
        return valid;
}
function indicateInvalidZipRange(id){	
	var object = document.getElementById(id);
	object.className='credit_union_form_invalid';
}
function indicateValidZipRange(id){
	var object = document.getElementById(id);
	object.className='credit_union_form_valid';
}
function followLink(searchFormID,path){ // Used in search box
	var searchValue=String(document.getElementById(searchFormID).value);
	searchValue2=searchValue.replace(/\s/gi,"-");
	searchValue2=searchValue2.replace("%","");
        searchValue2=encodeURIComponent(escape(searchValue2));
	window.location=path+'category/'+searchValue2;

}
function replaceall(text, strA, strB){
	while ( text.indexOf(strA) != -1)
    {
        text = text.replace(strA,strB);
    }
    return text;
}
function addslashes(str) {
str=str.replace(/\\/g,'\\\\');
str=str.replace(/\'/g,'\\\'');
str=str.replace(/\"/g,'\\"');
str=str.replace(/\0/g,'\\0');
return str;
}
function stripslashes(str) {
str=str.replace(/\\'/g,'\'');
str=str.replace(/\\"/g,'"');
str=str.replace(/\\0/g,'\0');
str=str.replace(/\\\\/g,'\\');
return str;
}
//XML parsing functions
function downloadURL(url, callback) {
    var request = window.ActiveXObject ?
            new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest;

    request.onreadystatechange = function() {
        if (request.readyState == 4) {
            request.onreadystatechange = doNothing;
            
            callback(request.responseText, request.status);
        }
    };
    request.open('GET', url, true);
    request.send(null);
}
function parseXml(str) {
  if (window.ActiveXObject) {
    var doc = new ActiveXObject('Microsoft.XMLDOM');
    doc.loadXML(str);
    return doc;
  } else if (window.DOMParser) {
    return (new DOMParser).parseFromString(str, 'text/xml');
  }
}
function doNothing() {}

//The following 2 functions are progress indicators for ajax loads.
function showProgress(objectID,object2ID) {
	var obj = document.getElementById(objectID); //progress
	var obj2= document.getElementById(object2ID); //content
	obj.style.display="inline";
	obj.innerHTML="<h3>Nerding... Please Wait</h3><br /><img src='http://cdn.nerdwallet.com/site/ajax-loader-nerd.gif' /><br /><p><img src='http://cdn.nerdwallet.com/nerds/nerd"+String(Math.floor(Math.random()*15)+1)+"_blur.jpg' /></p>";
	obj2.style.display="none";
}
function hideProgress(objectID,object2ID) {
	var agent=navigator.userAgent.toLowerCase();
	var is_iphone = ((agent.indexOf('iphone')!=-1));

	if (!is_iphone){
		if(document.getElementById('content')){unobscureField('content');}
	}
	var obj = document.getElementById(objectID);
	var obj2= document.getElementById(object2ID);
	
	obj.style.display="none";
	obj.innerHTML="";
	obj2.style.display = "inline";
	

}
function request_handler(pageRequest){

	if (pageRequest.readyState == 4){ // if state = 4 (the operation is completed)  
		if (pageRequest.status == 200){ // and the HTTP status is OK  
			// get progress from the XML node and set progress bar width and innerHTML  
			setTimeout("hideProgress('progress','content')",2000);
		}  
		else{ // if request status is different then 200  
			document.getElementById("progress").innerHTML="Error, Please Try Again";
		}  
	}
}
function changeClass(objectID, newClass){
	var object=document.getElementById(objectID);
	object.className=newClass;

}
function toggleClass(objectID){
	$('objectID').css('color','red');
	
	var object=document.getElementById(objectID);
	//var slider=document.getElementById(sliderID);
	
	if(object.className=="hiddenmenu"){
		object.className="showmenu";
		object.style.visibility="visible";
	}
	else if(object.className=="showmenu"){
		object.className="hiddenmenu";
		object.style.visibility="hidden";
	}
	else if(object.className=="hiddenmenu2"){
		object.className="showmenu2";		
		object.style.visibility="visible";	
	}
	else if(object.className=="showmenu2"){
		object.className="hiddenmenu2";
		object.style.visibility="hidden";
	}
}
/*function toggleTextAPR(objectID){
        toggleTextGeneric(objectID, "<a>Show Details</a>", "<a>Hide Details</a>");
}

function toggleText(objectID){
        toggleTextGeneric(objectID, "<img src=\"http://cdn.nerdwallet.com/site/details-downarrow.png\"><a> See Offer Details </a><img src=\"http://cdn.nerdwallet.com/site/details-downarrow.png\">", "<img src=\"http://cdn.nerdwallet.com/site/details-uparrow.png\"><a> Hide Offer Details </a><img src=\"http://cdn.nerdwallet.com/site/details-uparrow.png\">");
}
function toggleTextGeneric(objectID, showText, hideText) {
    var object=document.getElementById(objectID);
	if(object.innerHTML == hideText ){
		object.innerHTML = showText;
	}
	else{
            object.innerHTML = hideText;
	}
}*/
var jobViewSliderBufferTimer;

function getbuffer(url,formID,sessionState,objectID){
	if (jobViewSliderBufferTimer) {
    	clearTimeout(jobViewSliderBufferTimer); //set new timeout
	
	}
	jobViewSliderBufferTimer = setTimeout(function(){get(url,formID,sessionState,objectID);}, 500);
	
}
function retrieveSendData(formID, sessionState){
		var obj=document.getElementById(formID);
		var sendData="";

		for (i=0; i<obj.getElementsByTagName("input").length; i++){
			var id=obj.getElementsByTagName("input")[i].name;
			if((id=="balance")||(id=="underpay")||(id=="spend")||(id=="fico")||(id=="duration")||(id=="cat1_spend")||(id=="cat2_spend")||(id=="cat3_spend")||(id=="maxfee")||(id=="maxapr")||(id=="income")||(id=="graceperiod")||(id=="zip_code")||(id=="user_type")){
				//Values
				sendData+= (id + "=" + obj.getElementsByTagName("input")[i].value.replace(",","") + "&");
			} else if((id=="country")||(id=="military_base")||(id=="other_name")) {
                                sendData+= (id + "=" + obj.getElementsByTagName("input")[i].value + "&");
                        }
			else if(id=="radio_group"||id=="search_sort"){
																													  
				if(obj.getElementsByTagName("input")[i].checked||obj.getElementsByTagName("input")[i].type=="hidden"){
					var type=obj.getElementsByTagName("input")[i].value;
					sendData+=(id+"="+type+"&");
				}
			}
			else if(id=="mile_rate"){
				sendData+= obj.getElementsByTagName("input")[i].name + "=" + 
                   (obj.getElementsByTagName("input")[i].value*100) + "&";
			}
			
			else{
                sendData+= obj.getElementsByTagName("input")[i].name + "=";
				if(obj.getElementsByTagName("input")[i].checked==true||obj.getElementsByTagName("input")[i].value=='yes'){
                    sendData+=("on"+"&");
                }
                else{
                   sendData+=("off"+"&");
                }             
			}
			
		}
        sendData+="sessionState="+sessionState;
		return sendData;
	
}
function get(theurl, formID, sessionState, objectID){
	if(formID){
   		var sendData =  retrieveSendData(formID, sessionState);
		if(theurl.indexOf("creditunionresults.php")==-1)showProgress('progress','content');
	}
	$.ajax({
		url: theurl,
		type: 'POST',
		data: sendData,
		error: function(){
			//setTimeout("hideProgress('progress','content')",0);
			hideProgress('progress','content');
			//alert('We seem to be having a problem with our website. Please try again later.');
		},
	success: function(data){
			
			$('#'+objectID).html(data);
            $('.slidearea').hide();
			
			//setTimeout("hideProgress('progress','content')",1000);
			hideProgress('progress','content');
			if(showMap(sessionState))updateMap();
			
		}
	});
}
function getgas(theurl, formID, sessionState, objectID){
	if(formID){
   		var sendData =  retrieveSendData(formID, sessionState);
	}
	$.ajax({
		url: theurl,
		type: 'POST',
		data: sendData,
		error: function(){
			alert('We seem to be having a problem with our website. Please try again later.');
		},
	success: function(data){
			$('#'+objectID).html(data);			
			loadMarkers();
		}
	});
}
function getCardDetails(theurl, formID, sessionState, objectID){
	showProgress('progress','content');
	if(formID){
   		var sendData =  retrieveSendData(formID, sessionState);
	}
	$.ajax({
		url: theurl,
		type: 'POST',
		data: sendData,
		error: function(){
			alert('failure');
		},
		success: function(data){
			//showProgress('progress','content');
			//setTimeout("hideProgress('progress','content')",500);
			hideProgress('progress','content');
			$('#'+objectID).html(data);

		}
	});
}
function hideField(objectID){
	if(objectID=='credit_union_slider'){
		$('#'+objectID).hide();
	}
	else{
		var object=document.getElementById(objectID);
		if(object){
			object.style.height=0;
			object.style.overflow="hidden";
			object.style.visibility="hidden";
		}
	}
}
function showField(objectID){
	if(objectID=='credit_union_slider'){
		$('#'+objectID).slideDown('slow');
	}
	else{
		var object=document.getElementById(objectID);
		if(object){
			object.style.height="100%";
			object.style.visibility="visible";
		}
	}
}
/*function darkenSession(controlField,root){
    // only way for the navbar to know which page is currently being displayed,
    // so that links are displayed appropriately
	for (i=0; i<=8; i++){
    	document.getElementById('control' + i).className = "off_page";
		
	}
	document.getElementById(controlField).className = "on_page";
}*/
function submitForm(formID, formelementID, state, postField){
	var form=document.getElementById(formID);
	var session = document.getElementById(formelementID);
	session.value=state;
	form.submit();
}
function obscureField(objectID){

	FadeOpacity(objectID,100,20,200,10);

}
function unobscureField(objectID){

	FadeOpacity(objectID,20,100,200,10);
	
}
function SetOpacity(elem, opacityAsInt)
{
	var opacityAsDecimal = opacityAsInt;
	if (opacityAsInt > 100) opacityAsInt = opacityAsDecimal = 100; 
	else if (opacityAsInt < 0) opacityAsInt = opacityAsDecimal = 0; 
	opacityAsDecimal /= 100;
	if (opacityAsInt < 1) opacityAsInt = 1; // IE7 bug, text smoothing cuts out if 0
	elem.style.opacity = (opacityAsDecimal);
	elem.style.filter  = "alpha(opacity=" + opacityAsInt + ")";
}

function FadeOpacity(elemId, fromOpacity, toOpacity, time, fps){
	var steps = Math.ceil(fps * (time / 1000));
	var delta = (toOpacity - fromOpacity) / steps;
	FadeOpacityStep(elemId, 0, steps, fromOpacity, delta, (time / steps));
}
function FadeOpacityStep(elemId, stepNum, steps, fromOpacity, delta, timePerStep){
	SetOpacity(document.getElementById(elemId),Math.round(parseInt(fromOpacity) + (delta * stepNum)));
	if (stepNum < steps) setTimeout("FadeOpacityStep('" + elemId + "', " + (stepNum+1) + ", " + steps + ", " + fromOpacity + ", " + delta + ", " + timePerStep + ");", timePerStep);
}
function checkPlural(elemId,val){
	var object = document.getElementById(elemId);
        if (val!=1)object.innerHTML="s";
        else object.innerHTML="";
	//if (val!=1)object.innerHTML="s per mile";
	//else object.innerHTML=" per mile";
}
function verifyRange(objectID,min_num,max_num,fallback){
	var object=document.getElementById(objectID);
	var min_num2=parseInt(parseFloat(min_num));
	var max_num2=parseInt(parseFloat(max_num));
	var value2=parseInt(parseFloat(object.value.replace(",",""))).toFixed(0);
	if(isNaN(value2)){
		
		if(object.value=="")fallback=0;
		setVal(objectID,fallback,false);
		updateSpendPie(getVal('spend'),objectID);	
	}
	if(value2<min_num2){
		setVal(objectID,min_num2,false);
	}
	if(value2>max_num2){
		setVal(objectID,max_num2,false);
	}

	return true;
}
function updateInnerHTML(objectID,newInner,roundToOne){
	var object = document.getElementById(objectID);
	if(roundToOne){
		newInner=newInner.toFixed(1);
	}
	if (object.id=='SpendPieOther'){
		newInner=addCommas(newInner);
	}
	object.innerHTML = newInner;
}
function updateSpendPie(sourceID){
	
	var s3 = document.getElementById('s3')
	var cat1 = parseInt(parseFloat(getVal('cat1')));
	var cat2 = parseInt(parseFloat(getVal('cat2')));
	var cat3 = parseInt(parseFloat(getVal('cat3')));
	var spend = parseInt(parseFloat(getVal('spend')));
	//range checking for slider 3
	if(sourceID=='slider-3'||sourceID=='spend'){
		if(parseInt(spend)>=0&&parseInt(spend)<(parseInt(cat1)+parseInt(cat2)+parseInt(cat3))){
			if(spend<(cat1+cat2)){
				if(spend<cat1){		
					cat3=0;
					cat2 = 0;
					if(spend>=0)cat1 = spend;
					else cat1=0;
				}
				else{
					
					cat3=0;
					cat2 = spend - cat1;
				}
			}
			else{
				
				cat3 = spend-cat1-cat2;
			}
		}
	}
	else if(sourceID=='cat1'){
		if(spend>=0&&spend<(cat1+cat2+cat3)){
			if(spend<(cat1+cat2)){	
					cat3=0;
					cat2 = spend - cat1;
			}
			else{
				
				cat3 = spend-cat1-cat2;
			}
		}
		
	}
	else if(sourceID=='cat2'){
		if(spend>=0&&spend<(cat1+cat2+cat3)){
			if(spend<(cat1+cat2)){	
				
					cat3=0;
					cat1 = spend - cat2;
			}
			else{
				
				cat3 = spend-cat1-cat2;
			}
		}
	}
	else if(sourceID=='cat3'){
		if(spend>=0&&spend<(cat1+cat2+cat3)){

			if(spend<(cat1+cat3)){	
					cat2=0;
					cat1 = spend - cat3;
			}
			else{
				
				cat2 = spend-cat1-cat3;
			}
		}

	}

	setVal('cat1',cat1,false);
	setVal('cat2',cat2,false);
	setVal('cat3',cat3,false);
	
	updateInnerHTML('SpendPieOther',(spend-cat1-cat2-cat3).toFixed(0),0);
	setVal('cat1_spend',cat1,false);
	setVal('cat2_spend',cat2,false);
	setVal('cat3_spend',cat3,false);
	if(sourceID=='spend'){setVal('spend',spend);}//only necessary for comma formatting
	
}
function addCommas(nStr) 
{ 
	nStr += ''; 
	x = nStr.split('.'); 
	x1 = x[0]; 
	x2 = x.length > 1 ? '.' + x[1] : ''; 
	var rgx = /(\d+)(\d{3})/; 
	while (rgx.test(x1)) { 
		x1 = x1.replace(rgx, '$1' + ',' + '$2'); 
	} 
	return x1 + x2; 
}
function getVal(elemId){
	var object = document.getElementById(elemId);
	return object.value.replace(",","");
}
function setVal(elemId,newval,leaveoutcomma){
	var object = document.getElementById(elemId);
	newval=parseInt(newval).toFixed(0);
	if(!leaveoutcomma)object.value=addCommas(newval);
	else object.value=newval;

}
function checkCR(evt) {
    var evt  = (evt) ? evt : ((event) ? event : null);
    var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
    if ((evt.keyCode == 13) && (node.type=="text")) {return false;}
}

/*----------------------------------------------------------------------------\
|                                Range Class                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| Used to  model the data  used  when working  with  sliders,  scrollbars and |
| progress bars.  Based  on  the  ideas of  the javax.swing.BoundedRangeModel |
| interface  defined  by  Sun  for  Java;   http://java.sun.com/products/jfc/ |
| swingdoc-api-1.0.3/com/sun/java/swing/BoundedRangeModel.html                |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2005, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2005-10-27 | Use Math.round instead of Math.floor                           |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/


function Range() {
	this._value = 0;
	this._minimum = 0;
	this._maximum = 100;
	this._extent = 0;

	this._isChanging = false;
}

Range.prototype.setValue = function (value) {
	value = Math.round(parseFloat(value));
	if (isNaN(value)) return;
	if (this._value != value) {
		if (value + this._extent > this._maximum)
			this._value = this._maximum - this._extent;
		else if (value < this._minimum)
			this._value = this._minimum;
		else
			this._value = value;
		if (!this._isChanging && typeof this.onchange == "function")
			 this.onchange();
	}
};

Range.prototype.getValue = function () {
	return this._value;
};

Range.prototype.setExtent = function (extent) {
	if (this._extent != extent) {
		if (extent < 0)
			this._extent = 0;
		else if (this._value + extent > this._maximum)
			this._extent = this._maximum - this._value;
		else
			this._extent = extent;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getExtent = function () {
	return this._extent;
};

Range.prototype.setMinimum = function (minimum) {
	if (this._minimum != minimum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._minimum = minimum;

		if (minimum > this._value)
			this.setValue(minimum);
		if (minimum > this._maximum) {
			this._extent = 0;
			this.setMaximum(minimum);
			this.setValue(minimum)
		}
		if (minimum + this._extent > this._maximum)
			this._extent = this._maximum - this._minimum;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMinimum = function () {
	return this._minimum;
};

Range.prototype.setMaximum = function (maximum) {
	if (this._maximum != maximum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._maximum = maximum;

		if (maximum < this._value)
			this.setValue(maximum - this._extent);
		if (maximum < this._minimum) {
			this._extent = 0;
			this.setMinimum(maximum);
			this.setValue(this._maximum);
		}
		if (maximum < this._minimum + this._extent)
			this._extent = this._maximum - this._minimum;
		if (maximum < this._value + this._extent)
			this._extent = this._maximum - this._value;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMaximum = function () {
	return this._maximum;
};
/*----------------------------------------------------------------------------\
|                                 Timer Class                                 |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| Object Oriented Encapsulation  of setTimeout  fires ontimer when the  timer |
| is triggered. Does not work in IE 5.00                                      |
|-----------------------------------------------------------------------------|
|                   Copyright (c) 2002, 2006 Erik Arvidsson                   |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/

function Timer(nPauseTime) {
	this._pauseTime = typeof nPauseTime == "undefined" ? 1000 : nPauseTime;
	this._timer = null;
	this._isStarted = false;
}

Timer.prototype.start = function () {
	if (this.isStarted())
		this.stop();
	var oThis = this;
	this._timer = window.setTimeout(function () {
		if (typeof oThis.ontimer == "function")
			oThis.ontimer();
	}, this._pauseTime);
	this._isStarted = false;
};

Timer.prototype.stop = function () {
	if (this._timer != null)
		window.clearTimeout(this._timer);
	this._isStarted = false;
};

Timer.prototype.isStarted = function () {
	return this._isStarted;
};

Timer.prototype.getPauseTime = function () {
	return this._pauseTime;
};

Timer.prototype.setPauseTime = function (nPauseTime) {
	this._pauseTime = nPauseTime;
};
/*----------------------------------------------------------------------------\
|                                Slider 1.02                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A  slider  control that  degrades  to an  input control  for non  supported |
| browsers.                                                                   |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2003, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| Dependencies: timer.js - an OO abstraction of timers                        |
|               range.js - provides the data model for the slider             |
|               winclassic.css or any other css file describing the look      |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2003-03-27 | Added a test in the constructor for missing oElement arg       |
| 2003-11-27 | Only use mousewheel when focused                               |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/



Slider.isSupported = typeof document.createElement != "undefined" &&
	typeof document.documentElement != "undefined" &&
	typeof document.documentElement.offsetWidth == "number";


function Slider(oElement, oInput, sOrientation) {
	if (!oElement) return;
	this._orientation = sOrientation || "horizontal";
	this._range = new Range();
	this._range.setExtent(0);
	this._blockIncrement = 10;
	this._unitIncrement = 1;
	this._timer = new Timer(100);


	if (Slider.isSupported && oElement) {

		this.document = oElement.ownerDocument || oElement.document;

		this.element = oElement;
		this.element.slider = this;
		this.element.unselectable = "on";

		// add class name tag to class name
		this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;

		// create line
		this.line = this.document.createElement("DIV");
		this.line.className = "line";
		this.line.unselectable = "on";
		this.line.appendChild(this.document.createElement("DIV"));
		this.element.appendChild(this.line);

		// create handle
		this.handle = this.document.createElement("DIV");
		this.handle.className = "handle";
		this.handle.unselectable = "on";
		this.handle.appendChild(this.document.createElement("DIV"));
		this.handle.firstChild.appendChild(
			this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.handle);
        
	}

	this.input = oInput;

	// events
	var oThis = this;
	this._range.onchange = function () {
		oThis.recalculate();
		if (typeof oThis.onchange == "function")
			oThis.onchange();
	};

	if (Slider.isSupported && oElement) {
		this.element.onfocus		= Slider.eventHandlers.onfocus;
		this.element.onblur			= Slider.eventHandlers.onblur;
		this.element.onmousedown	= Slider.eventHandlers.onmousedown;
		this.element.onmouseover	= Slider.eventHandlers.onmouseover;
		this.element.onmouseout		= Slider.eventHandlers.onmouseout;
		this.element.onkeydown		= Slider.eventHandlers.onkeydown;
		this.element.onkeypress		= Slider.eventHandlers.onkeypress;
		this.element.onmousewheel	= Slider.eventHandlers.onmousewheel;
		this.handle.onselectstart	=
		this.element.onselectstart	= function () { return false; };

		this._timer.ontimer = function () {
			oThis.ontimer();
		};

		// extra recalculate for ie
		window.setTimeout(function() {
			oThis.recalculate();
		}, 1);
	}
	else {
		this.input.onchange = function (e) {
			oThis.setValue(oThis.input.value);
		};
	}
}

Slider.eventHandlers = {

	// helpers to make events a bit easier
	getEvent:	function (e, el) {
		if (!e) {
			if (el)
				e = el.document.parentWindow.event;
			else
				e = window.event;
		}
		if (!e.srcElement) {
			var el = e.target;
			while (el != null && el.nodeType != 1)
				el = el.parentNode;
			e.srcElement = el;
		}
		if (typeof e.offsetX == "undefined") {
			e.offsetX = e.layerX;
			e.offsetY = e.layerY;
		}

		return e;
	},

	getDocument:	function (e) {
		if (e.target)
			return e.target.ownerDocument;
		return e.srcElement.document;
	},

	getSlider:	function (e) {
        var el = e.target || e.srcElement;
		while (el != null && el.slider == null)	{
			el = el.parentNode;
		}
		if (el)
			return el.slider;
		return null;
	},

	getLine:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.className != "line")	{
			el = el.parentNode;
		}
		return el;

	},

	getHandle:	function (e) {
		var el = e.target || e.srcElement;
		var re = /handle/;
		while (el != null && !re.test(el.className))	{
			el = el.parentNode;
		}
		return el;

	},
	// end helpers

	onfocus:	function (e) {

		var s = this.slider;
		s._focused = true;
		s.handle.className = "handle hover";
	},

	onblur:	function (e) {
		var s = this.slider
		s._focused = false;
		s.handle.className = "handle";
	},

	onmouseover:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle)
			s.handle.className = "handle hover";
	},

	onmouseout:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle && !s._focused)
			s.handle.className = "handle";
	},

	onmousedown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s.element.focus)
			s.element.focus();

		Slider._currentInstance = s;
		var doc = s.document;

		if (doc.addEventListener) {
			doc.addEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.addEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.attachEvent) {
			doc.attachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.attachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.attachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
			s.element.setCapture();
		}

		if (Slider.eventHandlers.getHandle(e)) {	// start drag
			Slider._sliderDragData = {
				screenX:	e.screenX,
				screenY:	e.screenY,
				dx:			e.screenX - s.handle.offsetLeft,
				dy:			e.screenY - s.handle.offsetTop,
				startValue:	s.getValue(),
				slider:		s
			};
		}
		else {
			var lineEl = Slider.eventHandlers.getLine(e);
			s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
			s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			s._increasing = null;
			s.ontimer();
		}
	},

	onmousemove:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);

		if (Slider._sliderDragData) {	// drag
			var s = Slider._sliderDragData.slider;

			var boundSize = s.getMaximum() - s.getMinimum();
			var size, pos, reset;

			if (s._orientation == "horizontal") {
				size = s.element.offsetWidth - s.handle.offsetWidth;
				pos = e.screenX - Slider._sliderDragData.dx;
				reset = Math.abs(e.screenY - Slider._sliderDragData.screenY) > 100;
			}
			else {
				size = s.element.offsetHeight - s.handle.offsetHeight;
				pos = s.element.offsetHeight - s.handle.offsetHeight -
					(e.screenY - Slider._sliderDragData.dy);
				reset = Math.abs(e.screenX - Slider._sliderDragData.screenX) > 100;
			}
			s.setValue(reset ? Slider._sliderDragData.startValue :
						s.getMinimum() + boundSize * pos / size);
			return false;
		}
		else {
			var s = Slider._currentInstance;
			if (s != null) {
				var lineEl = Slider.eventHandlers.getLine(e);
				s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
				s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			}
		}

	},

	onmouseup:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = Slider._currentInstance;
		var doc = s.document;
		if (doc.removeEventListener) {
			doc.removeEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.removeEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.detachEvent) {
			doc.detachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.detachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.detachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
			s.element.releaseCapture();
		}

		if (Slider._sliderDragData) {	// end drag
			Slider._sliderDragData = null;
		}
		else {
			s._timer.stop();
			s._increasing = null;
		}
		Slider._currentInstance = null;
	},

	onkeydown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		//var s = Slider.eventHandlers.getSlider(e);
		var s = this.slider;
		var kc = e.keyCode;
		switch (kc) {
			case 33:	// page up
				s.setValue(s.getValue() + s.getBlockIncrement());
				break;
			case 34:	// page down
				s.setValue(s.getValue() - s.getBlockIncrement());
				break;
			case 35:	// end
				s.setValue(s.getOrientation() == "horizontal" ?
					s.getMaximum() :
					s.getMinimum());
				break;
			case 36:	// home
				s.setValue(s.getOrientation() == "horizontal" ?
					s.getMinimum() :
					s.getMaximum());
				break;
			case 38:	// up
			case 39:	// right
				s.setValue(s.getValue() + s.getUnitIncrement());
				break;

			case 37:	// left
			case 40:	// down
				s.setValue(s.getValue() - s.getUnitIncrement());
				break;
		}

		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onkeypress:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var kc = e.keyCode;
		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onmousewheel:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s._focused) {
			s.setValue(s.getValue() + e.wheelDelta / 120 * s.getUnitIncrement());
			// windows inverts this on horizontal sliders. That does not
			// make sense to me
			return false;
		}
	}
};



Slider.prototype.classNameTag = "dynamic-slider-control",

Slider.prototype.toggleVisibility = function(){
	if(this.line.className=="invisiline"){
		this.line.className="line";
		this.handle.className="handle";
	}
	else{
		this.handle.className="invisihandle";
		this.line.className="invisiline";
	}
	
}

Slider.prototype.makeVisible = function(){
	this.line.className="line";
	this.handle.className="handle";
	
}

Slider.prototype.makeInvisible = function(){
	this.handle.className="invisihandle";
	this.line.className="invisiline";

}

Slider.prototype.setValue = function (v) {
	this._range.setValue(v);
	this.input.value = this.getValue();
};

Slider.prototype.getValue = function () {
	return this._range.getValue();
};

Slider.prototype.setMinimum = function (v) {
	this._range.setMinimum(v);
	this.input.value = this.getValue();
};

Slider.prototype.getMinimum = function () {
	return this._range.getMinimum();
};

Slider.prototype.setMaximum = function (v) {
	this._range.setMaximum(v);
	this.input.value = this.getValue();
};

Slider.prototype.getMaximum = function () {
	return this._range.getMaximum();
};

Slider.prototype.setUnitIncrement = function (v) {
	this._unitIncrement = v;
};

Slider.prototype.getUnitIncrement = function () {
	return this._unitIncrement;
};

Slider.prototype.setBlockIncrement = function (v) {
	this._blockIncrement = v;
};

Slider.prototype.getBlockIncrement = function () {
	return this._blockIncrement;
};

Slider.prototype.getOrientation = function () {
	return this._orientation;
};

Slider.prototype.setOrientation = function (sOrientation) {
	if (sOrientation != this._orientation) {
		if (Slider.isSupported && this.element) {
			// add class name tag to class name
			this.element.className = this.element.className.replace(this._orientation,
									sOrientation);
		}
		this._orientation = sOrientation;
		this.recalculate();

	}
};

Slider.prototype.recalculate = function() {
    
	if (!Slider.isSupported || !this.element) return;

	var w = this.element.offsetWidth;
	var h = this.element.offsetHeight;
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var lw = this.line.offsetWidth;
	var lh = this.line.offsetHeight;
    
	// this assumes a border-box layout
    
	if (this._orientation == "horizontal") {
		this.handle.style.left = (w - hw) * (this.getValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum()) + "px";
		this.handle.style.top = (h - hh) / 2 + "px";

		this.line.style.top = (h - lh) / 2 + "px";
		this.line.style.left = hw / 2 + "px";
		//this.line.style.right = hw / 2 + "px";
		this.line.style.width = Math.max(0, w - hw - 2)+ "px";
		this.line.firstChild.style.width = Math.max(0, w - hw - 4)+ "px";
	}
	else {
		this.handle.style.left = (w - hw) / 2 + "px";
		this.handle.style.top = h - hh - (h - hh) * (this.getValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum()) + "px";

		this.line.style.left = (w - lw) / 2 + "px";
		this.line.style.top = hh / 2 + "px";
		this.line.style.height = Math.max(0, h - hh - 2) + "px";	//hard coded border width
		//this.line.style.bottom = hh / 2 + "px";
		this.line.firstChild.style.height = Math.max(0, h - hh - 4) + "px";	//hard coded border width
	}
};

Slider.prototype.ontimer = function () {
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var hl = this.handle.offsetLeft;
	var ht = this.handle.offsetTop;

	if (this._orientation == "horizontal") {
		if (this._mouseX > hl + hw &&
			(this._increasing == null || this._increasing)) {
			this.setValue(this.getValue() + this.getBlockIncrement());
			this._increasing = true;
		}
		else if (this._mouseX < hl &&
			(this._increasing == null || !this._increasing)) {
			this.setValue(this.getValue() - this.getBlockIncrement());
			this._increasing = false;
		}
	}
	else {
		if (this._mouseY > ht + hh &&
			(this._increasing == null || !this._increasing)) {
			this.setValue(this.getValue() - this.getBlockIncrement());
			this._increasing = false;
		}
		else if (this._mouseY < ht &&
			(this._increasing == null || this._increasing)) {
			this.setValue(this.getValue() + this.getBlockIncrement());
			this._increasing = true;
		}
	}

	this._timer.start();
};
