/*

sg layout

a javascript to layout text in multiple columns in DOM compatible browsers

this system was first created for the article text on IHT.com (The International Herald Tribune)


author
- - - 
john weir
john@smokinggun.com
more info at http://www.smokinggun.com

Thanks to Juerg Lehni {www.vectorama.org} {www.scratchdisk.com} for helping me finish this, improving some methods, and testing.


copyright
- - - - - -
Copyright (C) 2001 John Weir  (www.smokinggun.com)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

A copy of the license may be found at www.smokinggun.com/perm/gnu.php
or www.fsf.org (Free Software Foundation)


Changes
- - - -
9.24	removed the ac* column, which should remove the bug for "extra" and blank pages in IE 5.0 Mac
fixed a NS/Moz bug of clicking on links resulting in a page turning
removed support for oddsized elementes, this is a future feature and this should slightly speed up setup on the Mac
created a reader_ini.js file to house the variable settings
9.19 changed the way paragraph styles are changed, should speed things up
9.19 switched onmousedown to onclick to avoid a problem with "selecting" text in Netscape 6.0


Features Added
- - - - - - - -
single column and definable column modes
seperate parser from Layout Script
Mac IE is no longer sizing text
Mac IE not detecting click
make loop to check total height/linehieght for rounding problems
non dom compatibility
added st_preload which creates styles to hide and adjust images before loading in DOM browsers


Bugs
- - - -
Moz has a 1 pixel "overhang" at cetain font sizes, but reports no rounding error
NS not detecting image offset properly
images not locating in Mozilla .9.3
single column mode not working yet


Bugs fixed
- - - - - -
netscape will not cancel next/prev page events if a link is clicked
MAC IE has empty right hand column
MAC IE had last page detection error :: 	both of these were related to creating the acN column which was a parent to the at* column, 
							i have removed the ac* column, and everything seems to be working fine, except images are now broken(9.24) in NS 6.01
1 column mode causes recurison error
MAC IE clipgs text, rounding error
Mac IE only detects click when on text
tagName not support by Mozilla (use nodeName) 
NS does not detect event clicking on text itself
going from larger font size to smaller can leave user on a page number > than total pages
IE 6.0 not getting height of window
doc type problem


Future Features
- - - - - - - - 
cookies to save preferences
CSS For Printing
add Bookmark (or page mark) to save position 
add select text inteligent detection, cancel event
Logic for displaying nearest image(s)
XMLing 
custom properties for img tags
define custom img properties : nearness | viewer pane | text | chapters
preloading of content {needs to be backwards compatible}
paragraph detection : so you don't have a blank line at the top of a column
introduce a calibrating image
support for multiple font sizes
make array of all "abnormal" sized objects


Notes
- - - - 
Pages are not the same from system to system
Copying and Pasting text is problematic

removed st_returnTextSize in this version

using a border around the articleText object will cause a recursion error

.2 seems to be a magic number for the LINE_HEIGHT_MOD value
	

Variables 
- - - - - 

please add sg_layout_ini.js before this file
reader_ini.js has all the constants and user definable variables


*/

var oddObjArray = new Array(); //tracks all child nodes in article for odd sized type and images

var line_height = font_size*LINE_HEIGHT_MOD; // column hieghts are deteremined by the line height, this is the critical variable
var column_position = 0; // page position
var column_height_total = 0; // ??

var bodyNode; // body tag id should fix this and id the body by getElementsByTagName

var viewer_height = null; // height of the text viewer
allImagePositions = new Array();
allParagraphPositions = new Array();


// short for getElementById
function gId(o)
	{
		if (o == "bodyNode"){
			return document.getElementsByTagName("BODY")[0];
		} else {
			return document.getElementById(o);
		}
	}

// this is work around a bug in early version of the Mozilla engine(in Netscape 6.0)
// the bug does not track object offsets properly
// this method should be called when the fonts are resized, or any other
// event which would affect offsets
function st_imageCount()
	{
	var obj = gId("at0");
	var allImages = obj.getElementsByTagName("img");
	
	for (var imgCounter = 0; imgCounter < allImages.length; imgCounter++)
		{
		allImagePositions[imgCounter] = Math.abs(allImages[imgCounter].offsetTop);
		}
	}

//places positions of paragraphs into an array
function st_paragraphCount()
	{
	var obj = gId("at0");
	var allParagraphs = obj.getElementsByTagName("p");
	
	nsFix = 0;
	
	for (var pCounter = 0; pCounter < allParagraphs.length; pCounter++)
		{
		//Netscape 6.01(and probably lower) starts the first paragraph out at a number other than
		//0, although it should be 0, this is a fix for that problem
		if (pCounter == 0) nsFix = Math.abs(allParagraphs[pCounter].offsetTop);
		allParagraphPositions[pCounter] = Math.abs(allParagraphs[pCounter].offsetTop)-nsFix;
		}
	}	
	
	

	
// makes sure that a paragraph starts on the first line, to be flush with the top
// this currently is buggy in layouts with more than 2 columns

function st_alignParagraphs()
	{
		
	var paragraphOffset = 0;
	for (var c = 0; c < COLUMN_NUM; c++)
		{
		
		var column = gId("at"+c);
		var allParagraphs = column.getElementsByTagName("p");
		
		// offset the column for any previous out of alignment paragraphs
		column.style.top =  (parseInt(column.style.top)-paragraphOffset)+"px";
		
		var start = Math.abs(-1*(viewer_height*(c+column_position)))+1-paragraphOffset;
		var end = start+line_height;
	
		for (var pCounter = 0; pCounter < allParagraphs.length; pCounter++)
			{	
				var pTop = allParagraphPositions[pCounter]-paragraphOffset;//Math.abs(allImages[imgCounter].offsetTop);
				var imgObj = allParagraphs[pCounter];
				
				//a paragraph is within the range
				if (pTop >= start && pTop <= end)
					{
					//adjust the top of the active column
					column.style.top = ((parseInt(column.style.top)-line_height))+"px";
					
					// increase the global paragraphOffset
					paragraphOffset = paragraphOffset+line_height;
					
					// for debugging
					//allParagraphs[pCounter].style.color = "#FF0000";					
					}
			}
		}
	
		
	}

/* returns the height, in pixels of object */

function st_getHeight(o)
	{
	if (o == "w") 
		{
		o = gId("bodyNode")
		if (fixedHeight) return fixedHeight + 180;
		if (window.innerHeight) return window.innerHeight;
		else return parseInt(o.offsetHeight)
		}
	else
	{
	o = gId(o);
	if (o.offsetHeight) return o.offsetHeight
	}
	}


/* setup 
	creates the columns

*/	
	
function st_columnSetup()
	{
	p = gId(VIEWER);
	p.innerHTML = "";
	column_position = 0;
	
	for (i=0; i < COLUMN_NUM; i++)
		{
		var o = gId(CONTENTS)
		var aT = document.createElement("div");
		aT.setAttribute("id","at"+i)
		aT.setAttribute("className","stText");
		aT.setAttribute("class","stText");
		aT.innerHTML = o.innerHTML;
		
		if (document.all) var cur = "hand"
		else  var cur = "pointer"
		/*
		if (i == 0 || i == COLUMN_NUM-1)	
			{
			aT.style.cursor = cur;
			aT.onclick = st_columnClick;
			aT.onmouseover = st_columnOver;
			aT.onmouseout = st_columnOut;
			}
		*/
		aT.style.display = "block";
		p.appendChild(aT);
		}
	}



/* 
	lays out the columns 
	this is fired when ever the type faces change, "pages" turned, or window resized
*/	
	
function st_columnLayout(st_columnLayout)
	{	
	viewer_height = st_getHeight(VIEWER);
		
	for (var i = 0; i < COLUMN_NUM; i++)
		{				
		o = gId("at"+i);
		
		st_moveColumnLeftPosition(i);
		if (viewer_height > 2*line_height) o.style.top = -1*(viewer_height*(i+column_position))+"px";
		}
		
	tC = column_height_total/viewer_height; 
	tP = Math.ceil(tC); 
	tPos = (column_position+COLUMN_NUM)/COLUMN_NUM; 
	o = gId("P")
	o2 = gId("P2")

	//RMSI code for top navigation
	prevObj=gId("prev");
	nextObj=gId("next");

	prevObjGR=gId("prevGR");
	nextObjGR=gId("nextGR");

	prevObjFR=gId("prevFR");
	nextObjFR=gId("nextFR");
	
	//RMSI code for bottom pagination
	prevObjb=gId("prevb");
	nextObjb=gId("nextb");

	prevObjGRb=gId("prevGRb");
	nextObjGRb=gId("nextGRb");

	prevObjFRb=gId("prevFRb");
	nextObjFRb=gId("nextFRb");

	st_alignParagraphs();
	
	// if the current page is > than the total pages
	if ((Math.round(tPos)) > (Math.ceil(tP/COLUMN_NUM)))
	{
		st_screenPrevious();
	}
		
	//customize you page number here
	//alert(Math.round(tPos)+"::::"+Math.ceil(tP/COLUMN_NUM))
	if (o) o.innerHTML = ""+(Math.round(tPos))+pageDiv+(Math.ceil(tP/COLUMN_NUM));
	if (o2) o2.innerHTML = ""+(Math.round(tPos))+pageDiv+(Math.ceil(tP/COLUMN_NUM));

	

	
	//alert(prevObj+"::::"+Math.round(tPos)+"::::"+Math.ceil(tP/COLUMN_NUM))
	if((Math.round(tPos)==Math.ceil(tP/COLUMN_NUM)) && (Math.ceil(tP/COLUMN_NUM)==1))
		{
			//for top navigation
			if (prevObjGR==null && prevObjFR==null)
			{
			prevObj.innerHTML = "";
			nextObj.innerHTML = "";
			}

			if (prevObj==null && prevObjFR==null)
			{
			prevObjGR.innerHTML = "";
			nextObjGR.innerHTML = "";
			}

			if (prevObj==null && prevObjGR==null)
			{
			prevObjFR.innerHTML = "";
			nextObjFR.innerHTML = "";
			}

			//for bottom navigation
			if (prevObjGRb==null && prevObjFRb==null)
			{
			prevObjb.innerHTML = "";
			nextObjb.innerHTML = "";
			}

			if (prevObjb==null && prevObjFRb==null)
			{
			prevObjGRb.innerHTML = "";
			nextObjGRb.innerHTML = "";
			}

			if (prevObjb==null && prevObjGRb==null)
			{
			prevObjFRb.innerHTML = "";
			nextObjFRb.innerHTML = "";
			}
		}
		else if( (Math.round(tPos)==1) && (Math.ceil(tP/COLUMN_NUM) > 1) )
		{
			//for top navigation
			if (prevObjGR==null && prevObjFR==null)
			{
			prevObj.innerHTML = "";
			nextObj.innerHTML = "next >";
			}

			if (prevObj==null && prevObjFR==null)
			{
			prevObjGR.innerHTML = "";
			nextObjGR.innerHTML = "Weiter >";
			}

			if (prevObj==null && prevObjGR==null)
			{
			prevObjFR.innerHTML = "";
			nextObjFR.innerHTML = "après >";
			}

			//for bottom navigation
			if (prevObjGRb==null && prevObjFRb==null)
			{
			prevObjb.innerHTML = "";
			nextObjb.innerHTML = "next >";
			}

			if (prevObjb==null && prevObjFRb==null)
			{
			prevObjGRb.innerHTML = "";
			nextObjGRb.innerHTML = "Weiter >";
			}

			if (prevObjb==null && prevObjGRb==null)
			{
			prevObjFRb.innerHTML = "<";
			nextObjFRb.innerHTML = "après >";
			}
		}
		else if( Math.round(tPos)==Math.ceil(tP/COLUMN_NUM) ) 
		{
			//for top navigation
			if (prevObjGR==null && prevObjFR==null)
			{
			prevObj.innerHTML = "< previous  ";
			nextObj.innerHTML = "";
			}

			if (prevObj==null && prevObjFR==null)
			{
			prevObjGR.innerHTML = "< Zur&uuml;ck  ";
			nextObjGR.innerHTML = "";
			}

			if (prevObj==null && prevObjGR==null)
			{
			prevObjFR.innerHTML = "< précédent  ";
			nextObjFR.innerHTML = "";
			}

			//for bottom navigation
			if (prevObjGRb==null && prevObjFRb==null)
			{
			prevObjb.innerHTML = "< previous  ";
			nextObjb.innerHTML = "";
			}

			if (prevObjb==null && prevObjFRb==null)
			{
			prevObjGRb.innerHTML = "< Zur&uuml;ck  ";
			nextObjGRb.innerHTML = "";
			}

			if (prevObjb==null && prevObjGRb==null)
			{
			prevObjFRb.innerHTML = "< précédent  ";
			nextObjFRb.innerHTML = "";
			}
		}
		else
		{
			//for top navigation
			if (prevObjGR==null && prevObjFR==null)
			{
			prevObj.innerHTML = "< previous  ";
			nextObj.innerHTML = "next >";
			}

			if (prevObj==null && prevObjFR==null)
			{
			prevObjGR.innerHTML = "< Zur&uuml;ck  ";
			nextObjGR.innerHTML = "Weiter >";
			}

			if (prevObj==null && prevObjGR==null)
			{
			prevObjFR.innerHTML = "< précédent  ";
			nextObjFR.innerHTML = "après >";
			}

			//for bottom navigation
			if (prevObjGRb==null && prevObjFRb==null)
			{
			prevObjb.innerHTML = "< previous  ";
			nextObjb.innerHTML = "next >";
			}

			if (prevObjb==null && prevObjFRb==null)
			{
			prevObjGRb.innerHTML = "< Zur&uuml;ck  ";
			nextObjGRb.innerHTML = "Weiter >";
			}

			if (prevObjb==null && prevObjGRb==null)
			{
			prevObjFRb.innerHTML = "< précédent  ";
			nextObjFRb.innerHTML = "après >";
			}
		}
	


	}
	

// adjust the column height to the line height to avoid cropping a column mid line

function st_columnSnapHeight(m) 
	{
	if (m == null) m =0;
	s = line_height*Math.round((st_getHeight("w")-m)/line_height)
	
	if (s < line_height*1) s = line_height*1
	return s;
	}
	
	
function st_columnSetHeight()
	{
	if (COLUMN_NUM > 1)
	{
	if (gId(CONTENTS) != null)
		{
		gId(VIEWER).style.height = st_columnSnapHeight(NAVIGATION_AREA)+"px";
		column_height_total = st_getHeight("at1");	viewer_height = st_getHeight(CONTENTS)
		while ((viewer_height*(column_position+COLUMN_NUM-1)) > column_height_total && column_position > 0)column_position= column_position-1
			st_columnLayout()
			}
	}}
	
	
function st_screenNext()
	{
	viewer_height = st_getHeight(VIEWER)
	if ((viewer_height*(column_position+COLUMN_NUM)) < column_height_total)column_position= column_position+COLUMN_NUM;
	st_columnLayout();
	}
	
function st_screenPrevious()
	{
	column_position= column_position-COLUMN_NUM;
	if (column_position < 0) column_position = 0
	st_columnLayout()
	}

//returns the event object
function st_getEventObj(e) {
	if (e == null) e = event;
	if (e.srcElement) obj = e.srcElement;
	else obj = e.target;

	var count = 0;
	do {
	obj = obj.parentNode;
	} 
	while ((obj.id == null || obj.id == "") && count++ < 2); //work around for Moz
	 
	return obj;
	}


// for interface highlighting
// you will want to customize these two method
function st_over(direction)
	{
	obj = document.getElementById("page"+direction);
	obj.style.color = "#FF0000"
	}
	
function st_out(direction)
	{
	obj = document.getElementById("page"+direction);
	obj.style.color = "#000000"
	
	}

// called when the mouse is over the column
// add events like navigation button changes here
function st_columnOver(e)
	{
	// if there is more than one column
	if (COLUMN_NUM > 1)
		{
		var cur = document.all ? "hand" : "pointer";
		obj = st_getEventObj(e);
		if (obj.id.indexOf("0") > -1) // if the first column is moused over
			{
			var hilite = (column_position > 0);
			obj.style.cursor = hilite ? cur : "default";
			if (hilite) 
				try {st_over("previous");}
				catch(error){}
			}

		if (obj.id.indexOf(COLUMN_NUM-1) > -1) //if the last column is moused over
			{
			var hilite = ((viewer_height*(column_position+COLUMN_NUM)) <
			column_height_total);
			obj.style.cursor = hilite ? cur : "default";
			if (hilite) 
				try {st_over("next");}
				catch(error){};
			}
		}
	}
	
	
function st_columnOut(e)
	{
	// if there is more than one column
	if (COLUMN_NUM > 1)
		{
		
		obj = st_getEventObj(e);
		if (obj.id.indexOf("0") > -1) // if the first column is moused out
			{
			try {st_out("previous");}
				catch(error){}
			}

		if (obj.id.indexOf(COLUMN_NUM-1) > -1) //if the last column is moused out
			{
	   		try {st_out("next");}
				catch(error){}
	   		}
  		}
	}






//moves the column into horizontal position
function st_moveColumnLeftPosition(i)
	{
	o = gId("at"+i)
	o.style.left = (i*(parseInt(o.offsetWidth)+10))+"px"
	}



var loop_counter = 0; //used to check for possible infinite loop 

function st_fontSetSize(TEMP_LINE_HEIGHT_MOD)
	{
	line_height = Math.round(font_size+(LINE_HEIGHT_MOD*font_size));
	
	// st_getHeight("aT0")/line_height should be an integer
	// otherwise you will get an offset error	
	
	for (var i = 0; i < COLUMN_NUM; i++) 
		{ 
		o = gId("at"+i);
		o.style.fontSize = "1em";//font_size+"px";
		o.style.lineHeight = line_height+"px" 
		}
	
	//set paragraph margins
	tObject = gId(VIEWER);
	
	
	//ie version
	if (document.styleSheets[0].addRule != null)
		{
		document.styleSheets[1].rules.item(0).style.marginBottom =  line_height+"px";
		}
	
	var o = gId("stStyle");
	if (o.sheet != null)
		{
		o.sheet.cssRules[0].style.marginBottom = line_height+"px";
		}
		
	// if there is a rounding error in the line height then adjust the LINE_HEIGHT_MOD

	while ((st_getHeight("at0")/line_height) - Math.round(st_getHeight("at0")/line_height) != 0)
		{
		loop_counter++;
		if (loop_counter > 10) 
			{
			//alert("loop_error");
			break;
			}
	
		LINE_HEIGHT_MOD = LINE_HEIGHT_MOD+.1;
		if (LINE_HEIGHT_MOD > MAX_LINE_HEIGHT) LINE_HEIGHT_MOD = ORIGINAL_LINE_HEIGHT_MOD;
		st_fontSetSize();
		}
		
	st_paragraphCount();		
	st_imageCount();

	st_columnSetHeight();
	}
	


function st_init()
	{		
	
		//st_displayImages("pageContents");

		if(gId("paginationTop")!=null)	gId("paginationTop").style.visibility="visible";
		if(gId("paginationBottom")!=null)	gId("paginationBottom").style.visibility="visible";
			
		st_fixParaBug();
		
	if (document.createElement != null)
		{
		bodyNode = gId("bodyNode");
	
		if (gId(CONTENTS) != null)
			{
			//Mac IE like CONTESTS to have the stText style
			gId(CONTENTS).setAttribute("class","stText");
			gId(CONTENTS).setAttribute("className","stText");
			
			st_columnSetup();
			st_columnSetHeight(); 
			st_fontSetSize(); 
			
			st_columnLayout();
			
			gId(CONTENTS).style.display = "none";
			
			}
		
		document.onmousemove = st_NetscapeFix;
		
		st_displayImages("at0");
		st_displayImages("at1");
		// window.onresize = st_columnSetHeight; // pc 
		
		
		}
	try	
		{
		try {
		gID("navbar").onmouseover = showHomePage;
		gID("navbar").onmouseout = hideHomePage;
		gID("navbar").onclick = goNavLink;
		}
	catch(err){}
	
		}
	catch(error)
		{
		}
		
		
		
	}
	
// controls display of images	
function st_displayImages(container)
	{
	//var imgOut = ""; //this string contains the HTML the be written out to create the images
	
	var obj = gId(container);
	if (obj==null) return;
	var allImages = obj.getElementsByTagName("img");
	
		
	var start = Math.abs(-1*(viewer_height*(column_position)));
	var end = Math.abs((viewer_height*(COLUMN_NUM+column_position)));
	var imgOut = "";//start+" | "+end+"<br><br>";
	
	for (var imgCounter = 0; imgCounter < allImages.length; imgCounter++)
		{	
			var tempTop = allImagePositions[imgCounter];
			var imgObj = allImages[imgCounter];
			
			/*
			This is a fix for mozilla, but appears to have been fixed in Mozilla version .9.4 (or earlier)
			Since the offsetTop seems to be adjusted based also on the parent's position
			*/
			
			var comment = start+" | "+end+" | "+tempTop;
			
			// window.status = comment +" "+(tempTop >= start && tempTop <= end); 
			
			//an image has been found
			if (tempTop >= start && tempTop <= end)
				{
			
				if (!IMG_INLINE)
					{
					//you will want to alter this to fit your layout needs
					imgOut += "<div><img src=\""+allImages[imgCounter].src+"\"><br>"+allImages[imgCounter].getAttribute('alt')+"</div>";
					//imgOut =imgOut+ "<div><br>"+allImages[imgCounter].getAttribute('custom')+" "+tempTop+" | "+imgCounter+"</div>";
					}
				if (IMG_INLINE)
					{
					 allImages[imgCounter].style.width="";
					 allImages[imgCounter].style.height="";
					 
					}
				}
				
				if(IMG_INLINE)
				{
				
					if(imgObj.src.indexOf("showimage")!=-1)
					{
						handleHeight(imgObj)
						
						
					}
				}
		}
	// draw the images
	if (!IMG_INLINE)
		{
		gId(IMG_VIEWER).style.display = "none"
		gId(IMG_VIEWER).innerHTML = imgOut;
		//alert(gId(IMG_VIEWER).innerHTML);
		gId(IMG_VIEWER).style.display = "block"
		}
	
	}

	
	function handleHeight(e)
	{
		return;
			// get image height and compensate for non integer line height
			//Commented out because it was messing with the display of text (cutting off, etc)
			//var imgObj=e;
			//var imgHeight = imgObj.height;
			//var remainder= imgHeight % 20;
			
			//var topMargin= parseInt(remainder /2);
			//var bottomMargin = parseInt(remainder /2) + remainder % 2
		
			//imgObj.style.marginTop=topMargin +"px";
			//imgObj.style.marginBottom=bottomMargin +"px";
					
	
	}
	
/* netscape fix  */	
	
function st_NetscapeFix()
	{
	st_columnSetHeight();
	document.onmousemove = null;
	}


// adds a new style to hide the source text
function st_preload()
	{
	document.writeln("<style type=\"text/css\">");
	document.writeln("#"+CONTENTS+" {display:none}");
	//set images to 0 in size in the VIEWER
	document.writeln("#"+VIEWER+" img {	display:inline;");
	document.writeln("</style>");
	}

	
	function st_fixParaBug()
	{
		obj = gId("pageContents");
		if(obj!=null)
		{
			var arrP= obj.getElementsByTagName("p");
			for (var i=0;i<arrP.length;i++)
			{	
				//obj.insertBefore(document.createElement("<br />"),arrP[i]);
				//arrP[i].innerHTML+="<br/><br/>"
			}
			//alert(obj.innerHTML)
			//obj.innerHTML=obj.innerHTML.replace(/<\/[pP]>[\t\r\n]*<[pP]>/g,"&nbsp;<br/>&nbsp;<br/></p><p>");	
			//alert(obj.innerHTML)
		}
	}
	
st_preload();

window.onload = st_init; 
