
// IFRAME HISTORY (C)2004 Stephen Chalmers 
// Maintains an independent history of any number of inline frames in a 
// containing page. **ALL PAGES DISPLAYED MUST BE ON THE SAME DOMAIN**

// Demo at http://www.hotspot.freeserve.co.uk/ifh

/****|These instructions may be removed|********

--Installation--

Note:
There is no need to add any code to the files that are displayed
within the iframe(s), other than the inclusion of an optional [Back]
link.

1) Copy this file (fhistory.js) into the same folder as the HTML file 
that creates the iframe(s).

2) In the <head> section of the HTML file, insert this line:
<SCRIPT TYPE=TEXT/JavaScript SRC=fhistory.js>

3)Inside the <BODY> tag, insert the statement: ONLOAD="startHistory()";

-- Setup --

Functions are available to provide stepping of iframe histories by any
number of possible increments, rewinding and unwinding; both individually
and collectively.
In practice it's probable one would choose not to provide all functions.

In the containing document, you must create links to step the iframe 
histories you wish to control. Iframes are indexed (numbered) in the
order they were created, starting with 0. 
Below are some syntax examples for possible controls. 

To step the history of the first iframe (0):
<A HREF='#' onclick='return fHist(0,-1)'>Back</A>
<A HREF='#' onclick='return fHist(0,1)'>Forward</A>
 
To step all iframe histories simultaneously:
<A HREF='#' onclick='return fHistAll(-1)'>All Frames Back</A>
<A HREF='#' onclick='return fHistAll(1)'>All Frames Forward</A>

To rewind the history of a second iframe (1):
<A HREF='#' onclick="return fHistRewind(1)">REWIND</A>&nbsp;

To rewind all histories:
<A HREF='#' onclick="return fHistRewindAll()">REWIND ALL</A>&nbsp;

To unwind (jump to the end of) the first iframe's history:
<A HREF='#' onclick="return fHistUnwind(0)">UNWIND</A>&nbsp;

To unwind all iframe histories:
<A HREF='#' onclick="return fHistUnwindAll()">UNWIND ALL</A>&nbsp;

Optionally, the content pages of inline frames may contain their own [Back]
links, which if used should appear in all pages except the first displayed. 
The content of such links can be anything, but the HREF parameter must be
set to '#ifh-back', i.e.:

<A HREF='#ifh-back'>[This frame back]</A>

The presence of these links is detected automatically by the script in the
parent page.

--Notes for Advanced Users--

The parameter 'frameIndex' refers to the zero-based index of the target
iframe. 
'vector' is the step size and direction; i.e. -1=back 1 item, 1=forward 1 item.
If a specified step size is out of range, the biggest step possible is made.

Uses of Available Functions:

fHist(frameIndex, vector) - Step the history of an iframe in the page. 

fHistAll(vector) - Step all iframe histories simultaneously from their 
current positions,

fHistRewind(frameIndex) - Rewind an individual history.

fHistRewindAll() - Rewind all histories together.

showHist(frameIndex) - Display the current content and position of an 
individual history. (Best used only for development purposes)

Links used to call these functions, should appear only when JavaScript
support is available; thus it is preferable that they be generated or 
made visible by script statements.

*** DO NOT EDIT BELOW THIS LINE.******/
 
function ifHist(objName,frameIndex)
{//(C)Stephen Chalmers
 this.mustUpdate=false;
 this.isUpdating=false;
 this.isStepping=false;
 this.objName=objName;
 this.frame=frameIndex;
 this.hStep=false;
 this.index=0;
 this.locn=""
 this.fHistory=new Array();

 this.hUpdate();
}

ifHist.prototype.hUpdate=function()
{
 this.isUpdating=true;
 var lRef=window.frames[this.frame].document.links
 this.locn=window.frames[this.frame].location.href;

 for(var i=0; i<lRef.length; i++)   //scan for [Back] links
  if( lRef[i].href.toLowerCase().indexOf('#ifh-back') > -1 )    
   lRef[i].onclick=new Function(this.objName+"["+this.frame+"].stepHist(-1);return false");
 
 if(this.hStep==false)//last change not due to history step
 {
//Enabled=If not at history end on change of page, 
//new page becomes history end.

//if(this.fHistory.length>0 && this.index!=this.fHistory.length-1)
// this.fHistory.length=this.index+1;     
  this.fHistory[this.fHistory.length]=window.frames[this.frame].location.href;
  this.index=this.fHistory.length-1;
 } 
 this.hStep=false;

 this.isUpdating=false;
}

ifHist.prototype.stepHist=function(vector)
{
 if(!this.isStepping)
 {
  this.isStepping=true;
  if(vector<0 && this.index+vector<0)
   vector = this.index ? -this.index : 0;
  else
   if(vector>0 && this.index+vector >= this.fHistory.length)
    vector=this.fHistory.length-this.index-1;

  if(vector!=0)
  {
   this.hStep=true;
   this.index+=vector; 
   window.frames[this.frame].location=this.fHistory[this.index];
  }
 }

 this.isStepping=false;

 return false;
}

ifHist.prototype.sh=function()//displays history
{
 var l=this.fHistory.length,
     h="History of frame "+this.frame+'.\n\n';
 for(var i=0; i<this.fHistory.length; i++)
  h+=(this.index==i?'\xbb':'  ') + this.fHistory[i]+'\n';

  h+="\n("+l+" "+"location"+(l>1?"s":"")+")\n";

 if(l>1)
  h+="\nCurrent offset: "+this.index; 

 alert(h);
}

function scanLocs(set)
{
 for(var i=0; i<set.length; i++)
  if( this.mustUpdate || set[i].locn != window.frames[set[i].frame].location.href)
   if(!set[i].isUpdating)
    {
     set[i].hUpdate();
     this.mustUpdate=false;
    }
   else
    this.mustUpdate=true;
}

///User Interfaces///

function showHist(frameIndex)
{
 if(!isNaN(frameIndex)&& typeof(ifh)!="undefined" && frameIndex>-1 && ifh.length>frameIndex)
  ifh[frameIndex].sh();

 return false;
}

function fHist(frameIndex, step)
{
 if(!isNaN(step) && !isNaN(frameIndex)
    && typeof(ifh)!="undefined" && ifh.length>frameIndex)
  ifh[frameIndex].stepHist(step);

 return false;
}

function fHistAll(vector)
{
 if(!isNaN(vector) && typeof(ifh)!="undefined")
  for(var i=0; i<ifh.length; i++)
   ifh[i].stepHist(vector);

 return false;
}

function fHistRewind(frameIndex)
{
 if(typeof(ifh)!="undefined" && !isNaN(frameIndex) && frameIndex<ifh.length)
  if(ifh[frameIndex].index!=0)
   {
    ifh[frameIndex].hStep=true;
    ifh[frameIndex].index=0;
    window.frames[ifh[frameIndex].frame].location=ifh[frameIndex].fHistory[ifh[frameIndex].index];
   }   

 return false;
}

function fHistRewindAll()
{
 if(typeof(ifh)!="undefined")
  for(var i=0; i<ifh.length; i++)
   fHistRewind(i);

 return false;
}


function fHistUnwind(frameIndex)
{
 if(typeof(ifh)!="undefined" && !isNaN(frameIndex) && frameIndex<ifh.length)
  if(ifh[frameIndex].index < ifh[frameIndex].fHistory.length-1)
   {
    ifh[frameIndex].hStep=true;
    ifh[frameIndex].index=ifh[frameIndex].fHistory.length-1;
    window.frames[ifh[frameIndex].frame].location=ifh[frameIndex].fHistory[ifh[frameIndex].index];
   }   

 return false;
}

function fHistUnwindAll()
{
 if(typeof(ifh)!="undefined")
  for(var i=0; i<ifh.length; i++)
   fHistUnwind(i);

 return false;
}

////////////////////

function initIfHistory() //Do not call directly
{
 if(window.frames && window.frames.length>0)
 {
  ifh=new Array();  

  for(var i=0; i<window.frames.length; i++)
  {
   ifh[i]=new ifHist("ifh",i);
   window.frames[i].name=i+"ifh";
  }
  setInterval("scanLocs(ifh)",200);
 }
}

function startHistory() //Call with <BODY ONLOAD=startHistory()>
{
  setTimeout("initIfHistory()",10);
}

//--End of listing