/*
 * Slider v1.2
 * Control DHTML slider elements.
 * Copyright (c) 2003 Mackley F. Pexton.  All rights reserved.
 * Send correspondence and feedback to: mack_pexton[at]acmebase[dot]com.
 */

/*******************************************************************************

Slider v1.2 -- Control a slider element over a slider bar.

These routines control a slider element over a slider bar -- simply a
horizontal scroll bar. They allow the mouse to "grab" and move the slider
element and they support scroll buttons that move the slider as the mouse
is held down over the buttons.

The Slider object tracks the position of the slider over the slider bar
and it provides methods to move the slider in response to mouse clicks
and it has methods to scroll the slider when the mouse is held down over a
button. An form input field can also be specified to display the slider's
current position and to place the slider at a given position.

The following is an example how the slider methods are used in a document.

  <div id="blue_container" class="slider-container" style="position:relative;"
   onmousedown="blue_slider.move_and_turn_on(event)"
   onmouseup="blue_slider.turn_off(event)"
   onmousemove="blue_slider.track(event)"
  >
  <div id="blue_slider" style="position:absolute;"
   class="slider" style="border-color:blue;"
   onmousedown="blue_slider.turn_on(event)"
   onmouseup="blue_slider.turn_off(event)"
   onmousemove="blue_slider.track(event)"
  >&nbsp;</div>
  </div>

The slider object is setup as following:

  var blue_slider = new Slider('blue_slider',
  				255,
  				document.slider_form.blue_val,
				showSliderColor);

Only the first argument is required. It is the slider element's id.
The second is the maximum value of the slider's range. It defaults to 100
if it is not specified. The third argument is a form <input> element that
is used to display the current setting of the slider. It can also be used
to set the location of the slider if the method move() is used in the
input field's onchange event handler as demonstrated below. The last 
argument is a function that is called whenever the slider is moved.

The slider can be positioned to an absolute location by calling the move()
method. The following examples demonstrate a button the moves the slider
to the farthest left (0) position and an <input> field that sets the
slider to a user entered position.

  <a href="javascript:void 'Set blue to 0.'" onclick="blue_slider.move(0)">0</a>
  <input type="text" name="blue_val" size="4" onchange="blue_slider.move(this.value)">

Scroll buttons can be defined like the following:

  <a href="javascript:void 'Decrease blue.'"
   class="slider-scroll-button"
   onmousedown="blue_slider.scroll(-1)"
   onmouseup="blue_slider.scroll_stop()"
  >&laquo;</a></td>
  
The slider keeps moving while the mouse button is held down. Several sliders
can be moved simultaneously by using the Slider.scroll_all() method as
illustrated below. Arguments are the step interval to move followed by a
list of all the slider objects to scroll. A negative step interval moves
the slider to the left, a positive step move the slider to the right.

  <a href="javascript:void 'Lighten the color.'"
   onmousedown="Slider.scroll_all(1,red_slider,green_slider,blue_slider)"
   onmouseup="Slider.scroll_stop()"
  ><br>&gt;</a>

This software works with IE5.5+, NS6+, Opera5+, and Safari.

*******************************************************************************/

// Set Slider configuration variables to the CSS style settings of the slider.
Slider.SliderBorderWidth = 2;	// slider's border width
Slider.SliderScale = 1;		// value per pixel of slider bar

// Set Slider Scroller configuration variables.
Slider.ScrollRate  = 100;	// Rate of scroll (milliseconds between iterations)
Slider.ScrollDelay = 500;	// Initial delay before scrolling (milliseconds)
Slider.ScrollStep  = 1;		// Step of scroll

// Slider working variables.
Slider.current_slider = null;	// current activated slider control

// Slider object constructor.
function Slider(e,max,fld,callback) {

	// Parameters:
	//   e	      -- slider element (element that slides on the scale)
	//   max      -- maximum value of the slider (default is 100)
	//   fld      -- optional form field used to track slider position
	//   callback -- optional function called with slider value when slider is moved

	if (typeof e == 'string') e   = document.getElementById(e);
	if (fld == null)	  fld = new Object;
	if (max == null)	  max = 100;

	this.e = e;			// slider object
	this.fld = fld;			// field or object to record slider position
	this.max = max;			// maximum value of slider (pixels)
	this.callback = callback;	// function called when slider is moved

	this.on = false;		// flag if slider is active or not
	this.xdiff = 0;			// offset difference between slider and container

	// Copy global settings to object
	this.SliderBorderWidth	 = Slider.SliderBorderWidth;
	this.SliderScale	 = Slider.SliderScale;

	// Copy slider scroller global settings to object
	this.ScrollRate		 = Slider.ScrollRate;
	this.ScrollDelay	 = Slider.ScrollDelay;
	this.ScrollStep		 = Slider.ScrollStep;

	document.body.parentNode.onmouseup = Slider.turn_off;	// safety
}

// Class method for event handler
Slider.turn_off = function(evt) {
	if (Slider.current_slider) Slider.current_slider.turn_off(evt);
	Slider.current_slider = null;
}

Slider.prototype.track = function(evt) {

	// Track current position of slider
        if (! this.on) return;

        var pos = (evt.pageX ? evt.pageX : evt.clientX) - this.xdiff;
	this.move(pos);
}

Slider.prototype.move = function(pos) {

	// Move slider to position.

	if (pos < 0)        pos = 0;
	if (pos > this.max) pos = this.max;
        this.e.style.left = (pos - this.SliderBorderWidth) + 'px';

	this.fld.value = pos * this.SliderScale;

	// Call callback function notifying that the slider has moved.
	if (this.callback) this.callback(pos * this.SliderScale);
}

Slider.prototype.turn_on = function(evt) {

	// Start tracking slider

        var pos = parseInt(this.e.style.left,10) + this.SliderBorderWidth;
	if (isNaN(pos)) pos = 0;

        this.xdiff = (evt.pageX ? evt.pageX : evt.clientX) - pos;

	this._activate(evt);
}

Slider.prototype.move_and_turn_on = function(evt) {
        evt = evt ? evt : window.event ? window.event : null;
	var target = evt.target ? evt.target : evt.srcElement ? evt.srcElement : null;

	// Note: this method is to be fired when mouse is clicked on the
	// slider-bar-top or slider-bar-bottom elements which are enclosed
	// by the slider-container element. It moves the slider to the position
	// clicked and then follows the cursor. If the target is the slider-container
	// element, it is because Netscape (v6-v7.1) fires the event when the
	// mouse is clicked outside of the element, which is wrong. (!!)
	// The problem apparently comes from Netscape keeping a flag if the mouse
	// is down and clears it only if the original element that fires a
	// mousedown fires the mouseup. Because the slider moves into place
	// on a mousedown event, it is the slider that receives the mouseup
	// and not the original element receiving the mousedown, so Netscape
	// thinks the mouse is still down until the next click.

	if (target.className == 'slider-container') return;	// Netscape workaraound

	// Move the slider to the place on the slider bar where the mouse was clicked.
	this.xdiff = target.offsetParent.offsetLeft;
	this._activate(evt);
}

Slider.prototype.turn_off = function(evt) {
        evt = evt ? evt : window.event ? window.event : null;

        this.on = false;
	if (this == Slider.current_slider) Slider.current_slider = null;

	if (evt) {
		evt.cancelBubble = true;
		if(evt.stopPropagation) evt.stopPropagation();
	}
}

Slider.prototype._activate = function(evt) {

	// Start following mouse pointer with slider.

	Slider.scroll_stop();				// safety

        this.on = true;

	Slider.current_slider = this;			// register

        this.track(evt);

	evt.cancelBubble = true;
	if(evt.stopPropagation) evt.stopPropagation();
}

/*
 * Slider Scroll Methods
 */

// Slider scroller working variables.
Slider.scroll_timer;		// setTimeOut() timer
Slider.scroll_sliders = [];	// working array    - list of sliders being scrolled
Slider.scroll_rate;		// working variable - milliseconds between scroll
Slider.scroll_dir;		// working variable - direction of scroll (-1 left, 1 right)

Slider.prototype.scroll = function(dir) {

	// Scroll slider left or right

	Slider.scroll_stop();				// safety
        document.onmouseup = Slider.scroll_stop;	// safety

	// Save arguments for next scroll in global context
	Slider.scroll_sliders = [ this ];		// one element array
	Slider.scroll_dir     = dir;
	Slider.scroll_rate    = this.ScrollRate;

	Slider.scroll_move();

	// Schedule next scroll
	Slider.scroll_timer = setTimeout('Slider.scroll_next()',this.ScrollDelay);
}

Slider.prototype.scroll_stop = function(evt) {
	// Stop scrolling
	clearTimeout(Slider.scroll_timer);

	if (evt) {
		evt.cancelBubble = true;
		if(evt.stopPropagation) evt.stopPropagation();
	}
}

// Class method
Slider.scroll_next = function() {
	Slider.scroll_move();
	Slider.scroll_timer = setTimeout('Slider.scroll_next()',Slider.scroll_rate);
}

// Class utility method to move all sliders a step.
Slider.scroll_move = function() {

	// Recover scroller arguments from saved class variables
	var dir  = Slider.scroll_dir;
	var slider;
	for (var i = 0; i < Slider.scroll_sliders.length; i++) {
		slider = Slider.scroll_sliders[i];

		var pos = parseInt('0'+slider.fld.value,10) + (dir * slider.ScrollStep);
		slider.move(pos);
	}
}

// Class method
Slider.scroll_all = function(dir) {

	// Scroll a list of sliders left or right

	Slider.scroll_stop();				// safety
        document.onmouseup = Slider.scroll_stop;	// safety

	// Save arguments for next scroll in global context
	Slider.scroll_sliders = [ ];			// initialize array
	Slider.scroll_dir     = dir;			// scroll direction
	Slider.scroll_rate    = Slider.ScrollRate;	// use global setting

	for (var i = 1; i < arguments.length; i++) {
		Slider.scroll_sliders[i-1] = arguments[i];
	}

	Slider.scroll_move();

	// Schedule next scroll
	Slider.scroll_timer = setTimeout('Slider.scroll_next()',Slider.ScrollDelay);
}

// Class method
Slider.scroll_stop = function(evt) {
	// Stop scrolling
	clearTimeout(Slider.scroll_timer);
}

