// Gallery 2
// Last Updated Jun 28, 2010

// it displays images in the same place and scrolls them in and out
// 		via a 2-image tray, one of which is visible, other is overflow
// array of source images is held in a container so all are overflow
// they are in the container with the display image but are off-screen
//	use method pointer to make state machine
// 	- put new image in offscreen part of tray, then scroll in

// scrolling requires just two CSS properties:
// the master container must have overflow:hidden
// the scrollable object must have position:relative

// for IE, the scrollable object must possess hasLayout
// this is an arcane subject; 
// we trigger hasLayout by display:inline-block
// also, this style must be specified inline, not in a CSS file!

// for IE 9 must have semicolon at end of line!

function Gallery(idslide,displaysec)
{
	// id is that of the container which holds 
    // the container (the slide strip) which holds the images 
	// most of which are overflow thus invisible
	// we will just slide this container up 1 image at a time

    // get DIV height of holder and propagate it to all images?
    // doesn't work once images loaded
    // holder = document.getElementById(idholder);
    // this.icontainer = holder.firstElementChild;
    this.icontainer = document.getElementById(idslide);
    // alert("Gallery("+idslide+")="+this.icontainer);
    if (!this.icontainer) {
        return null;
    }

	// array of images and index
	this.imglist = this.icontainer.getElementsByTagName("IMG");
    if (this.imglist.length == 0) {
        alert("Gallery: no images");
        return null;
    }
	this.im = 0;
	this.img = this.imglist[0];

	// scrolling variables
	this.top = 0;
	// scroll increment - height / time
	this.dtop = this.img.height/scrolltime;

	// end of scroll will be adjusted when changing images
	// add 1 so float compare against ~0 is certain
    this.stop0 = 1e-10;
	this.stop = this.stop0;

	// display time in seconds
	// must be converted into call intervals in milliseconds (speed)
	this.displaytime0 = displaysec *1000/speed;
	this.displaytime = this.displaytime0;

	// dispatch state machine
	this.dispatch = this.display;
}

Gallery.prototype.toString = 
function () {
    return "[Gallery: image count="+this.imglist.length+"]";
}

// scroll the image in or out
// using the standard dispatch interface
// var inscroll = 1;
Gallery.prototype.scroll = 
function () {
	// if (--inscroll == 0) alert("scroll: top="+this.otop+", stop="+this.stop);

	if (this.top <= this.stop) {
		this.dispatch = this.display;
		// inscroll = 1; // debug
		// alert("scroll: top="+this.top+", stop="+this.stop);
	}
	else {
		this.top -= this.dtop;
        // 2do: setting style may require px
		this.icontainer.style.top = this.top	
	}
}

// switch to next image
Gallery.prototype.next = 
function ()
{
	// go back to 1st image
	if (++this.im >= this.imglist.length) {

		this.im = 0;

		// set slightly > 0 so float compare works 
		// otherwise overscroll by one increment
		this.stop = this.stop0;

		// scroll 1st image from below
		this.top = this.img.height;
        // 2do: setting style may require px
		this.icontainer.style.top = this.top	

	}
	else {
		// set up to scroll out this image
		this.stop -= this.img.height;
	}

	this.dispatch = this.scroll;
}

Gallery.prototype.display = 
function ()
{
	if (--this.displaytime < 0) {

		// reset timer
		this.displaytime = this.displaytime0;

		// switch to next image
		this.next();
	}
}

// end Gallery

// Scroller scrolls links
function Scroller(idscroll,idcontainer) // ,nlinks,nlines)
{
	var sc = document.getElementById(idscroll);
    if (!sc) {
        return null;
    }

	this.sty = sc.style;

	// start should be size of container so just offscreen
	var c = document.getElementById(idcontainer);
    if (!c) {
        alert("Scroller: no container"+idcontainer);
        return null;
    }
	this.start = parseInt(c.style.height); // start;
	this.top = this.start;
    // alert("Scroller: otop="+this.otop+", style.height="+c.style.height);

    // total size of contained elements
    // to figure out when to restart scroll
	var x = sc.getElementsByTagName("A");
    if (x.length == 0) {
        alert("Scroller: no links");
        return null;
    }

    subsize = 0;
    // a = ""
	for (i=0; i < x.length; i++) {
		// a += "\nA["+i+"]="+x[i]+" HTML="+ x[i].innerHTML;
        // a += "\nheight="+ x[i].offsetHeight;
        // a += " top="+ x[i].offsetTop;
        subsize += x[i].offsetHeight;
	}
    // a += "\nlines="+x.length;
    // a += "\nDiv height="+sc.offsetHeight;
    // alert(a);

	// lowest top position, ~= when last item scrolls out of view
	this.low = -subsize;

	// alert("Scroller: start="+this.start+"\nlow="+this.low);

}

Scroller.prototype.toString = 
function () {
    return "[Scroller at "+this.start+"]";
}

// the dispatch is always to scroll
Scroller.prototype.dispatch = 
function () {
	if (this.top > this.low) {
		this.top--;
	}
	else {
		this.top = this.start;
	}

    // 2do: setting style may require px
	this.sty.top=this.top+"px";
}

// expandable menu
// calculates (expanded) height 
// by number of links and multi-line labels
function Expander(mdiv,isIE) {
	var ex = document.getElementById(mdiv)
    if (!ex)
        return null;

	this.s = ex.style;

    // get location of last child node to figure out size 
	x = ex.getElementsByTagName("A");
    if (x.length == 0) {
        alert("Expander control: no Anchor elements");
        return null;
    }

	i = x.length-1;
    ht = x[i].offsetTop-x[0].offsetTop+x[i].offsetHeight;

    // set pop height to bottom of last element
	this.htpop = ht;
    // fix for IE - add padding
    if (isIE)
        this.htpop += x[0].offsetTop * 2;

    // set original height to 1st element (header)
    this.ht = x[0].offsetHeight;

    // doesn't work in IE, so average the first 2 elements
    if (isIE)
        this.ht = (this.ht + x[1].offsetTop)/2;

    // initial height is unpopped
	this.s.height = this.ht; 

	// alert("Expander("+mdiv+"), ht="+this.ht+",htpop="+this.htpop);
}

Expander.prototype.show =
function () {
	this.s.height = this.htpop;
}

Expander.prototype.hide =
function () {
	this.s.height = this.ht;
}

/* popup menu (v2)
// calculates location of popup to right 
// by using offsets - assumes both visible link and pop are same width
// idiv is ID of main DIV containing both visible link and popup
function Popper(idiv,isIE) {
    var d = document.getElementById(idiv);
    if (!d)
        return null;

    // gets the item to pop up
	// alert("Popper("+idiv+") width="+d.offsetWidth);
    this.idiv = idiv;

    // get the 2 child DIVs
	var v = d.getElementsByTagName("DIV");
	// alert("Popper("+idiv+") v.length="+v.length);
    if (v.length < 2) {
        alert("Popper("+idiv+"): no menu");
        return null;
    }

    // calculate offset from width of 1st DIV
    this.offset = v[0].offsetWidth;
    // alert("Popper("+v[0].className+") offset="+this.offset);

    // get style of 2nd DIV
    this.s = v[1].style;
    this.s.left = this.offset;
    // alert("Popper("+v[1].className+") display="+this.s.display);

    // for some reason, this hides entire DIV
	// this.s.display = "none";

}

// show is instance method
Popper.prototype.show =
function () {
	this.s.display = "block";
    // debug("Popper.show("+this.idiv+"),s="+this.s.display+") left="+this.s.left);
}

Popper.prototype.hide =
function () {
	this.s.display = "none";
}

// end popup v2
*/

debug = function (log_txt) {
    if (window.console != undefined) {
            console.log(log_txt);
    }
}

// popup v3
// requires no hardcoded mouse handler code in the HTML
// finds all subsidiary popups and sets up mouse events for them
// idl is the top container for all the popups
// much more convenient when tweaking canned code such as Drupal
function Poppers(idl,isIE) {

    // loop through lists
    var d = document.getElementById(idl);
    if (!d)
        return null;

    // now get all the subsidiary popup lists
    // 2do: will just be LI elements, no class necessary
	var v = d.getElementsByTagName("DIV");
    
    // assign the properties to the HTML object
    // var ipop = 1;
    for (var i = 0; i < v.length; i++) {
        // alert("v["+(i)+"] class="+v[i].className);
        if (v[i].className == "sidepop") {
            fixPop(v[i]);
        }
    }
}

// fixes up popup mouse events
// by examining the secondary popup elements
function fixPop(p) {

    // get the 2 children 
    // 2do: visible link is LI, popup is UL under it
	var v2 = p.getElementsByTagName("DIV");
    if (v2.length < 2) {
        // ok if no menu - it is just a single link
        // alert("fixPop("+p+"): no menu");
        return null;
    }

    // calculate offset from visible link
    offset = v2[0].offsetWidth;
    otop = v2[0].offsetTop;
    // alert("fixPop("+v2[0].className+") offset="+offset+", top="+otop);

    // get style of popup link list
    // and assign it to a custom property pops
    p.pops = v2[1].style;
    p.pops.left = offset;
    p.pops.top = otop;
    // alert("fixPop("+v2[1].className+") display="+p.pops.display);

    // now fix up mouse events
    p.onmouseover = function() {
            this.pops.display = "block";
        }
    p.onmouseout = function() {
            this.pops.display = "none";
        }
}

