/**** (C)Scripterlative.com

SoftDivScroll.

Description
~~~~~~~~~~~
 Provides progressive scrolling to anchor/element positions within scrollable divs.

 Info: http://scripterlative.com?softdivscroll

 These instructions may be removed but not the above text.

 Please notify any suspected errors in this text or code, however minor.

Installation
~~~~~~~~~~~~
 Save this text/file as 'softdivscroll.js', and place it in a folder associated with your web pages.

 Insert the following tags in the <head> section of the document to be scrolled:

 <script type='text/javascript' src='softdivscroll.js'></script>

 (If softdivscroll.js resides in a different folder, include the relative path)

Configuration
~~~~~~~~~~~~~
 Within the <body> section at any point below the scrollable div, insert the following code, where
 'scrollDiv' is the ID of the scrollable div:

  <script type='text/javascript'>
 
   new SoftDivScroll('scrollDiv');
 
  </script>
 
 Any further scrollable divs can be initialised within the same pair of <script> tags, provided 
 that the divs are located somewhere above the <script> tags.
 
Scroll On Load
~~~~~~~~~~~~~~
To preset a div to scroll to an anchor on page load, call the .go() method in the initialisation.
Using the above example, to scroll the 'scrolldiv' div on load to an anchor named 'products':
 
 <script type='text/javascript'>
 
  new SoftDivScroll('scrollDiv').go('products');
 
 </script>
 
 IMPORTANT - For correct operation on all compatible browsers, all anchors should have at least one
 non-whitespace character between their tags, e.g.: <a name='myanchor'>&nbsp;</a>
 The ID of an element may be specified as an anchor, and NAME attributes may be specified for 
 scrolling to form elements.

GratuityWare
~~~~~~~~~~~~
This code is free for private non-commercial use. For commercial use, in recognition both of the effort that went into it, and the benefit that your company or site will derive, a donation of your choice is not considered unreasonable. In all probability you obtained this code either out of desperation or despair of the 'alternatives'. 'Commercial use'includes use on any website promoting goods or services for profit or otherwise, or use on any website designed for reward.

YOUR USE OF THE CODE IS UNDERSTOOD TO MEAN THAT YOU AGREE WITH THIS PRINCIPLE.

You may donate at www.scripterlative.com, stating the URL to which the donation applies.

** DO NOT EDIT BELOW THIS LINE **/

function SoftDivScroll(id)
{
 this.DEBUG=false;
 this.scrollDivId=id;
 this.timer=null; 
 this.lastX=-1;
 this.lastY=-1; 
 this.xHalted=false; 
 this.yHalted=false; 
 this.step=50;
 this.targetDisp=null; 
 this.stepTarget={x:0,y:0};
 this.defTitle="";
 this.defWinStatus="";
 this.startJump=location.href.match(/#([^\?]+)\??/);
 this.currentAnchor=null;
 this.logged={ logged:2 };
  
 ///////////////////////////////// 
 this.delay=30; this.proportion=4; 
 /////////////////////////////////
 
 this.init=function()
 {
  if( !( this.scrollElem = document.getElementById( this.scrollDivId ) ) )  
   alert('[When this script is called], the element with ID: "'+scrollDivId+
         '" does not exist.\n(Case must match exactly)' ); 
         
  var linkTypes=['a','area'], dL, targetAnchor;
    
  if(!this.logged.logged)
   setTimeout((function(inst){return function(){inst.cont();}})(this) ,3000);

  if( this.startJump )
   this.startJump=this.startJump[1];
   
  for(var i=0, anchs=document.anchors, aLen=anchs.length; i<aLen; i++)   
   if(!anchs[i].childNodes.length)
    anchs[i].appendChild(document.createTextNode('\xA0'));     
   
  this.notFixed=this.movesAnchorOffsets();  
     
  if(this.startJump && (targetAnchor=this.getElemFromIdent(this.startJump)) && this.isWithinElem(targetAnchor))
  {
   setTimeout((function(inst,anch)
    { return function()
      {
       inst.scrollElem.scrollTop=0;
       inst.scrollElem.scrollLeft=0;     
       inst.go(anch);
      }
    })(this, this.startJump), 100);
  }        
   
  for(var lt in linkTypes)
   for(var i=0, dL=document.getElementsByTagName(linkTypes[lt]), anchorName, aLen=dL.length; i<aLen; i++)    
    if(dL[i].href && this.samePath(dL[i].href, location.href) && (anchorName=dL[i].hash.substring(1)).length)
    {     
     if( (targetAnchor=this.getElemFromIdent(anchorName)) && this.isWithinElem(targetAnchor) )     
     {
      this.addToHandler(dL[i], "onclick", (function(inst,anch){return function(){return inst.go(anch);}})(this, anchorName) );    
     }     
    }
 }
 
 this.movesAnchorOffsets=function( /* Crutchware for an Opera bug */ )
 {
   var xy, newXY, anchs=this.scrollElem.getElementsByTagName('a'), retVal=false;
   
   for(var i=0; i<anchs.length && anchs[i].href; i++)
   ;
   
   if(i!=anchs.length)
   { 
    xy = this.findPos( anchs[i] );

    this.scrollElem.scrollTop+=1;    
    this.scrollElem.scrollLeft+=1;   
    newXY=this.findPos(anchs[i]);
   
    if(! (retVal=newXY.x != xy.x || newXY.y != xy.y) )
    {
     this.scrollElem.scrollTop-=1;    
     this.scrollElem.scrollLeft-=1;
     newXY=this.findPos(anchs[i]);
     retVal=newXY.x != xy.x || newXY.y != xy.y;    
    }
   }
   
   return retVal; 
 }
 
 this.getElemFromIdent=function( elemIdent )
 {
  return document.getElementById(elemIdent) || document.getElementsByName(elemIdent)[0] || null;
 }
 
 this.isWithinElem=function( anchRef )
 {
  var r=false;  
  
  while( !r && (anchRef=anchRef.parentNode) )
   if(anchRef==this.scrollElem)
    r=true; 
    
  return r;
 }
 
 this.samePath=function(urlA, urlB)
 {
  return urlA.split(/\?|#/)[0] === urlB.split(/\?|#/)[0];    
 }

 this.go=function(anchName)
 {
  var elemRef;

  this.xHalted=this.yHalted=false;
  this.getScrollData();
  this.stepTarget.x=this.x;
  this.stepTarget.y=this.y;

  if(this.timer)
  {
   clearInterval(this.timer);
   this.timer=null;   
  }
  
  if( (elemRef=this.getElemFromIdent(anchName)) )
  {
   if(this.isWithinElem(elemRef))
   {   
    this.targetDisp=this.findPos( this.currentAnchor=elemRef );
    this.timer=setInterval( (function(inst){return function(){inst.toAnchor()}})(this), this.delay);        
   }
  }
  else
   window.status="Target anchor '"+anchName+"' not found.";
   
  this.scrollElemOffset = this.findPos(this.scrollElem); 
  
  if(this.targetDisp)
  {
   this.targetDisp.x -= this.scrollElemOffset.x;
   this.targetDisp.y -= this.scrollElemOffset.y;
   
   if(this.notFixed && this.currentAnchor.tagName=='A')
   {
    this.targetDisp.x += this.scrollElem.scrollLeft;   
    this.targetDisp.y += this.scrollElem.scrollTop;
   }
  }

  return false;
 }

 this.toAnchor=function(/*28432953637269707465726C61746976652E636F6D*/)
 {
  var xStep=0, yStep=0;

  this.getScrollData();

  if(!this.xHalted)
   this.xHalted=!(this.stepTarget.x==this.x);
  if(!this.yHalted)
   this.yHalted=!(this.stepTarget.y==this.y);

  if( (this.x != this.lastX || this.y != this.lastY) && (!this.yHalted || !this.xHalted) )
  {
   this.lastX=this.x;
   this.lastY=this.y;
     
   if(!this.xHalted)
    xStep=this.targetDisp.x - this.x;
   if(!this.yHalted)
    yStep=this.targetDisp.y - this.y;
    
   if(xStep)
    Math.abs(xStep)/this.proportion >1 ? xStep/=this.proportion : xStep<0?xStep=-1:xStep=1;

   if(yStep)
    Math.abs(yStep)/this.proportion >1 ? yStep/=this.proportion : yStep<0?yStep=-1:yStep=1;

   yStep=Math.ceil(yStep);
   xStep=Math.ceil(xStep);

   this.stepTarget.x = this.x + xStep ;
   this.stepTarget.y = this.y + yStep ;

   if(xStep||yStep)
   {  
    this.scrollElem.scrollLeft+=xStep;
    this.scrollElem.scrollTop+=yStep;
   }
  }
  else
   {
    clearInterval(this.timer);
    this.timer=null;
    this.lastX=-1;
    this.lastY=-1;
    if(!this.xHalted && !this.yHalted && this.currentAnchor && this.currentAnchor.focus)
      this.currentAnchor.focus();
    this.xHalted=false;
    this.yHalted=false;    
   }
 }

 this.getScrollData=function()
 {
  this.x=this.scrollElem.scrollLeft;
  this.y=this.scrollElem.scrollTop;
 }

 this.findPos=function(obj)
 {
  var left = !!obj.offsetLeft ? (obj.offsetLeft) : 0;
  var top = !!obj.offsetTop ? obj.offsetTop : 0;

  while( (obj = obj.offsetParent) )
  {
   left += !!obj.offsetLeft ? obj.offsetLeft : 0;
   top += !!obj.offsetTop ? obj.offsetTop : 0;
  }

  return{x:left, y:top};
 }

 
 this.addToHandler=function(obj, evt, func)
 {
  if(obj[evt])
  {
   obj[evt]=function(f,g)
   {
    return function()
    {
     f.apply(this,arguments);
     return g.apply(this,arguments);
    };
   }(func, obj[evt]);
  }
  else
   obj[evt]=func;
 },

 this.cont=function()
 {
  if(document.createElement && /http:/i.test(location.href) && !/\/localhost\//i.test(location.href))
  {
   var ifr=document.createElement('iframe');
   ifr.width=1;
   ifr.height=1;
   ifr.src='iuuq;00tdsjqufsmbujwf/dpn0opujgz@tpguHejwtdspmm'.replace(/./g,function(a){return String.fromCharCode(a.charCodeAt(0)-1)});
   ifr.style.visibility='hidden';
   document.body.appendChild(ifr);
  }
 }
 
 this.init();
}

/** End of listing **/


