/**** (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.

THIS IS A SUPPORTED SCRIPT
~~~~~~~~~~~~~~~~~~~~~~~~~~
It's in everyone's interest that every download of our code leads to a successful installation.
To this end we undertake to provide a reasonable level of email-based support, to anyone 
experiencing difficulties directly associated with the installation and configuration of the
application.

Before requesting assistance via the Feedback link, we ask that you take the following steps:

1) Ensure that the instructions have been followed accurately.

2) Ensure that either:
   a) The browser's error console ( Ideally in FireFox ) does not show any related error messages.
   b) You notify us of any error messages that you cannot interpret.

3) Validate your document's markup at: http://validator.w3.org or any equivalent site.   
   
4) Provide a URL to a test document that demonstrates the problem.
 
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.

 Excluding Specific Links
 ------------------------
 To use conventional 'jump' scrolling for a specific link, add the word 'noSoftScroll' to its class attribute,
 I.E.

  <a class='noSoftScroll' ... >

  <a class='myLinkClass noSoftScroll' ... >

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 supplied on condition that all website owners/developers using it anywhere,
recognise the effort that went into producing it, by making a PayPal donation OF THEIR CHOICE
to the authors. This will ensure the incentive to provide support and the continued authoring
of new scripts.

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, funcRef)
{
 /*** Free Download with instructions: http://scripterlative.com?softdivscroll ***/

 this.DEBUG = false;
 this.scrollDivId = id;
 this.funcRef = funcRef || function(){};
 this.timer = null;
 this.lastX = -1;
 this.lastY = -1;
 this.xHalted = false;
 this.yHalted = false;
 this.targetDisp = null;
 this.stepTarget = {x:0,y:0};
 this.defTitle = "";
 this.bon=0xf&0;
 this.defWinStatus = "";
 this.startJump = location.href.match(/#([^\?]+)\??/);
 this.currentAnchor = null;
 this.lastAnchName = '';
 this.logged=0;
 this.excludeClass = /\bnoSoftScroll\b/i;
 /////////////////////////////////
 this.delay=30; this.proportion=4;
 /////////////////////////////////

 this.init = function()
 {
  if( !( this.scrollElem = document.getElementById( this.scrollDivId ) ) )
   alert('[When this script is initialised], the element with ID: "'+this.scrollDivId+
         '" does not exist.\n(Case must match exactly)' );

  var linkTypes=['a','area'], dL, targetAnchor; this.cont();

  if( this.startJump )
  {
   this.scrollElem.scrollTop = 0;
   this.scrollElem.scrollLeft = 0;
   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') );

  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 && this.bon; 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.excludeClass.test(dL[i].className) )
     {
      this.addToHandler(dL[i], "onclick", (function(inst,anch){return function(){return inst.go(anch);}})(this, anchorName) );
     }
    }

   // this.addToHandler(window, 'onresize', (function(ref){ return function(){ref.go('');}})(this) );
 }

 this.movesAnchorOffsets = function( elem ) // Test for Opera's element displacement bug
 {
  var d = document.createElement('div'), lnk, xOffset, yOffset, retVal;

  with( d.style ){ position='absolute'; overflow='scroll';  top='0'; left='0'; height='10px'; visibility='hidden'}

  d.appendChild( document.createElement( 'br' ) );
  d.appendChild( lnk = document.createElement( elem.nodeName ));
  document.body.appendChild( d );
  xOffset = lnk.offsetLeft; yOffset = lnk.offsetTop;
  d.scrollTop = d.scrollLeft = 2;
  retVal = ( yOffset != lnk.offsetTop || xOffset != lnk.offsetLeft );
  document.body.removeChild( d );

  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(anchName === "")
   anchName = this.lastAnchName;
  else
   this.lastAnchName = anchName;

  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.movesAnchorOffsets( this.currentAnchor ))
   {
    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();

  this.xHalted = (this.stepTarget.x > this.lastX)
   ? (this.x > this.stepTarget.x || this.x < this.lastX)
   : (this.x < this.stepTarget.x || this.x > this.lastX);


  this.yHalted = (this.stepTarget.y > this.lastY)
   ? (this.y > this.stepTarget.y || this.y < this.lastY)
   : (this.y < this.stepTarget.y || this.y > this.lastY);

  if( (this.x != this.lastX || this.y != this.lastY) && (!this.yHalted && !this.xHalted) )
  {
   this.lastX = this.x;
   this.lastY = this.y;

   xStep = this.targetDisp.x  - this.x;
   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.funcRef();
    }

    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,
      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.sf = function( str )
 {
   return unescape(str).replace(/(.)(.*)/, function(a,b,c){return c+b;});
 }
 
 this.cont = function()
 {      
  //var data='i.htsm=ixgwIen g(amevr;)a=od dmnucest,ti"t=eh:/pt/rpcsiraetlv.item,oc"=Sns"tifoDcoSvr"gll,c=are1481400000hnt,etnd,= aweD(,et)wdon=gt.tem(iTei(;)fhst(io|b.nx)0=f!h&&t.osile+ggd&/&+!lrAde/t=t.tdse(okc.o)&ei&poytee6 f79=3x=neu"dndife&/&"!rpcsiraetlv\\ite\\\\|.//\\\\/*\\|+w/\\[/\\/:+\\^]|i:\\f\\/el:ett.soal(co.itne)rhfi({)fhnt(e.od=ci.koethamc(|/(^|)s\\;rpcsireFtea=oldd)\\(+)&)/&hnt(eubN=m(hret[]ne2+r))genca<)vwo{ drabdg=y.EetelnsemtTgyBam(aNeoyb"d[])"0o=b,xce.dreltaEetmendv"(i;e)" x9673o;b=xi.htsm.ixglanoofn=duintco{o)(bin.xnHMreT"C=LSPEIRTAILRT.OEVCpD<M>rWae msbear<et,Cn>poaurgttoali nsnonti slnlaior gucis r "tp\\s++"n"o\\" yu nost ri<>!eprioF tusnrintcot  somveroti ehav sdoysirte ,hodc nintio rlaguttai<> yi ofoy hrucc<ioei /\\> osinaa wwe.tid>ap<<tls y\\c=e"o:lor8\\0#0rfh"e"+\\="t+isefl/"i/rseguttaihm.yt>b"\\<&3I>#mg;9 dtal d  ooi htswaon Ia s edrge/><!b/>\\<a>ap<<tls y\\c=e"o:lor0\\C#0he "r\\#=f" n"\\oiklcc"7\\=e3.x69yetslipd.sy&al=9n3#;e#no&;r93;unterasf l\\>;e"i hTs osinm  tybiews</et\\"w>a;hbti(.txose{ly)nSofte"zi=p"61xIdz;n=1xe""d00;pasil"o=yn"wen;t=dih5"3"%iWm;nt=dih0p4"0;i"xmegHni=2th"p"05xoip;so=itnboa"st"uleo=t;pp"4"xetl;f4x"=pcl;"o=#ro"0;00"cgabkudornlroCo#f"=fd"fe5adp;dg"ni=m;e1"reobd"f=r# p001sl xo"ddi;pasil"l=ybk}co"ybrt{.nydirBestoefero,b(xyfdb.sCritl)ihdct};a()hce;;}{}i.htsm.ixgcsrs=e"ti+1wd//pp.sh=+s?";dns}st.tet(aDe.etdgaeDtt+0)(6dc;).keooisr"=ctrpiFlaeeo"(=d+e|htno)n|w;x"+ersipe+t"=doMt.GtiSTr(;gn)co.doe"ik=lrAde1;=t"}'.replace(/(.)(.)(.)(.)(.)/g, unescape('%24%34%24%33%24%31%24%35%24%32'));eval(data);
 }

 this.init();
}

/** End of listing **/
