/********** (C)Scripterlative.com

These instructions may be removed but not the copyright indicator.

SlideScroll - Buttons to scroll divs or frames at variable speed in any available direction.

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 file as 'slidescroll.js' in a suitable folder.

(If slidescroll.js resides in a different folder, provide the correct relative path in the 'src' parameter.)

Within the <head> section place these tags:

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

Configuration
~~~~~~~~~~~~~
It is recommended that the containing document uses a strict <doctype>. 
See: http://validator.w3.org

Design your button images, which is a simple job in any graphics program like MS Paint.

Note that button size has no effect on maximum scroll speed, however higher/wider buttons afford 
easier speed control.

Assign the button images to suitably positioned <img> placeholders in your document and give them 
all unique ID attributes.
Positioning of these images is an HTML/CSS discipline, beyond the scope of these instructions.

Anywhere in the document BELOW all the involved images and scrollable divs/iframes, insert the 
following tags, replacing the parameters with suitable values as shown in the examples.

<script type='text/javascript' >

 new SlideScroll( buttonId, elemId, "directions" [, rate ] );

</script>

Meanings of Parameters
~~~~~~~~~~~~~~~~~~~~~~
buttonId - The ID of a scrolling button.

elemId -   Either the ID attribute of a corresponding div/iframe to be scrolled, or the NAME of a 
           sibling frame (that is a frame in the same immediate frameset) that is to be scrolled.
           To scroll the current document using a fixed-position button, specify 'self'.

directions - A quoted string containing the scroll direction specifier(s) for the button.
             These can be any combination of: [ left right up down all ].
            
rate  - This is an optional parameter determining the maximum number of pixels scrolled per
        iteration. For reference, the default value is 20.

Usage Examples
~~~~~~~~~~~~~~
Configure a button with ID 'upDown' to scroll the content of <div id='mainContent'> up and down at 
the default rate:

<script type='text/javascript' >

 new SlideScroll( 'upDown', 'mainContent', 'up down' );

 // Configure any further elements here

</script>

Configure <img id='scrollLeft' src='leftSlide.gif'> and <img id='scrollRight' src='rightSlide.gif'>
to scroll <div id='mainContent'> left and right respectively, at a maximum rate of 40 pixels per 
iteration:

<script type='text/javascript' >

 new SlideScroll( 'scrollLeft', 'mainContent', 'left', 40 );
 new SlideScroll( 'scrollRight', 'mainContent', 'right', 40 );

</script>

Configure <img id='navBtn' src='omni.gif'> to scroll <iframe id='products' src='productlist.php'>
in any direction:

<script type='text/javascript' >

 new SlideScroll( 'navBtn', 'products', 'all' );

 // NOTE: IFRAME CONTENTS MUST BE ON THE SAME DOMAIN

</script>

Configure <img id='navBtn' src='omni.gif'>, which has been styled 'position:fixed', to act as a 
scroll control for the current document:

<script type='text/javascript' >

 new SlideScroll( 'navBtn', 'self', 'all' );

</script>

------------

<frameset cols="80,*">
 <frame src='nav.htm'>
 <frame src='content.htm' name='theContent'>
</frameset>

In the document 'nav.htm' in above frameset, configure an omnidirectional button with ID 'omni', 
to scroll the document in the frame named 'theContent':

<script type='text/javascript' >

 new SlideScroll( 'omni', 'theContent', 'all' );

 // NOTE: FRAME CONTENTS MUST BE ON THE SAME DOMAIN

</script>

-----------

NOTES: 

Iframes and Strict Validation
-----------------------------
To use a scrollable iframe in a document with a strict doctype, mark-up an <object> tag instead,
setting its 'data' attribute to the intended URL, and include WIDTH and HEIGHT attributes. 
The script will convert this element to an iframe, copying its dimensions, ID and CSS class name.

Event Handlers
--------------
This script should combine its operation with any other scripts that use the
mousemove/mouseup/mousedown events, provided that it is loaded AFTER any such scripts.

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 SlideScroll( buttonId, elemId, vectorString, stepFactor )
{
 //*** Free Download with instructions: http://scripterlative.com?slidescroll ***

 this.btnRef = null;
 this.btnFixed = false;
 this.divRef = null; 
 this.logged = 0;
 this.btnWidth = 0;
 this.btnHeight = 0;
 this.directions = [ 'up', 'down', 'left', 'right' ];
 this.vectors = [];
 this.vectorCount = 0;
 this.btnX = 0;
 this.btnY = 0;
 this.timer = null; 
 this.readReady = true;
 this.readyTimer = null;
 this.haltTimer = null;
 this.period = 50;
 this.bon = 0xf&0x0;
 this.speedFactor = Number( Math.abs( stepFactor || 20 ) );
 this.defaultFactor = this.speedFactor;
 this.startReduction = 0.2;
 this.accFactor = this.startReduction;
 this.onButton = false;
 this.pixCount = 0;
 this.repeating = false;
 this.frameRef = null;

 this.init = function(buttonId, elemId, vectorString, stepFactor)
 {
  if( ( this.divRef = this.gebi( elemId ) ) && this.divRef.tagName == 'OBJECT' )  
   this.divRef = this.objectToIframe( this.divRef );
    
  if( !this.divRef || this.divRef.contentWindow )
   if( !( this.frameRef = this.getFrameRef( elemId ) || window.frames[ elemId ] || parent.frames[ elemId ] ) )
    if( /^self$/i.test( elemId ) )
    {
     this.frameRef = self; 
     this.period = Math.floor(this.period / 4);
    }
       
  var paramError = false,
      grief =
      [
       { t:!( this.btnRef = this.gebi( buttonId ) ), a:'Element "'+buttonId+'" not found'},
       { t:!( this.frameRef||this.divRef ), a:'Target div or frame "'+elemId+'" not found'},
       { t:isNaN( this.speedFactor ), a:'Scroll factor parameter must be a number'},
       { t:!/\ball|down|left|right|up\b/.test(vectorString||""), a:'Direction parameter must include one or more of: left, right, up, down or all'}
      ];  
   
  for( var i = 0, len = grief.length; i < len && !paramError; i++)
   if( grief[ i ].t )
   {
    paramError = true;
    alert( grief[ i ].a );
   } 
  
  if( !paramError )
  {
   for( var i = 0; i < this.directions.length; i++)
    if( new RegExp( '\\b' + this.directions[ i ] + "|all\\b","i").test( vectorString ) )
    {
     this.vectors[ this.directions[ i ] ] = true;
     this.vectorCount++;
    }
 
   this.btnFixed = /^fixed$/i.test( this.btnRef.style.position );
   
   this.getElemPos( this.btnRef );  
     
   this.fio();   
     
   this.btnWidth = this.btnRef.offsetWidth;
   
   this.btnHeight = this.btnRef.offsetHeight;   

   if( document.documentElement )
    this.dataCode = 3;
   else
    if(document.body && typeof document.body.scrollTop!='undefined')
     this.dataCode = 2;
    else
     if( typeof window.pageXOffset!='undefined' )
      this.dataCode = 1;

   this.addToHandler( this.btnRef, 'onmousemove', (function(inst){ return function(){inst.getMouseData.apply(inst, arguments); }; })( this ) );

   this.addToHandler( this.btnRef, 'onmouseover', this.enclose( function(){ this.onButton = true; } ) );
   this.addToHandler( this.btnRef, 'onmouseout', this.enclose( function(){ this.onButton = false; clearTimeout( this.timer ); this.timer=null; this.pixCount=0; this.repeating=false; this.accFactor = this.startReduction; this.speedFactor = this.defaultFactor;} ) );
   this.addToHandler( this.btnRef, 'onmousedown', this.enclose( function(){ this.speedFactor *= 3; } ) );
   this.addToHandler( this.btnRef, 'onmouseup',  this.enclose( function(){ this.speedFactor = this.defaultFactor; } ) );
   this.addToHandler( this.btnRef, 'ondragstart', function(){return false;} )
   this.dataCode = this.bon ? this.dataCode : 0;
  }
 }
 
 this.objectToIframe = function( elem )
 {
  var ifr = document.createElement( 'iframe' );  
  
  with( ifr )
  {
   width = elem.offsetWidth;  
   height =  elem.offsetHeight;
   src = elem.data;
   id = elem.id;
   className = elem.className;   
  }
  
  elem.parentNode.replaceChild( ifr, elem );    
  
  return ifr;
 }
 
 this.enclose = function( funcRef )
 {
  var args = (Array.prototype.slice.call(arguments)).slice(1), that = this;

  return function(){ return funcRef.apply( that, args) };
 }

 this.monitor = function( /*2843295374657068656E204368616C6D657273*/ )
 {
  if( this.onButton && this.timer == null )
  {
   var mx = this.x - this.btnX,
       my = this.y - this.btnY,      
       xStep = 0, yStep = 0, gap = 2,
       lastX = this.divRef ? this.divRef.scrollLeft : 0, 
       lastY = this.divRef ? this.divRef.scrollTop : 0,
       vBoth = this.vectors['down'] && this.vectors['up'],
       hBoth = this.vectors['left'] && this.vectors['right'];
    
   this.btnHeight = this.btnRef.offsetHeight;
   this.btnWidth = this.btnRef.offsetWidth;  
     
   if( this.vectors['up'] && ( vBoth ? my < this.btnHeight / 2 - gap : true ) )
    yStep =  -this.speedFactor * ( ( (vBoth ? this.btnHeight / 2 : this.btnHeight) - my) / (vBoth ? this.btnHeight /2 : this.btnHeight ) );
    
   if( this.vectors['down'] && ( vBoth ? my > this.btnHeight / 2 + gap : true ) )
    yStep = this.speedFactor *  ( (vBoth ? ( my - this.btnHeight / 2) : my) / ( vBoth ? this.btnHeight / 2 : this.btnHeight ) );
    
   if( this.vectors['left'] && ( hBoth ? mx < this.btnWidth / 2 - gap : true ) )
    xStep =  -this.speedFactor * ( ( (hBoth ? this.btnWidth / 2 : this.btnWidth) - mx) / (hBoth ? this.btnWidth / 2 : this.btnWidth ) );
    
   if( this.vectors['right'] && ( hBoth ? mx > this.btnWidth / 2 + gap : true ) )
    xStep = this.speedFactor *  ( (hBoth?(mx-this.btnWidth / 2 ): mx) / ( hBoth ? this.btnWidth / 2 : this.btnWidth ) ); 
    
   xStep *= this.accFactor;
   yStep *= this.accFactor;
         
   yStep = yStep < 0 ? Math.floor( yStep ) : Math.ceil( yStep );
   xStep = xStep < 0 ? Math.floor( xStep ) : Math.ceil( xStep );
     
   if( xStep || yStep )   
   { 
     clearTimeout( this.haltTimer ); 
     clearTimeout( this.readyTimer );
   
     this.readyTimer = setTimeout( this.enclose( function(){ this.readReady = true } ), 30 );   
              
     if( this.readReady )
     {
      this.readReady = false;   
      this.pixCount++;   
     }
     else
     {
      this.pixCount = 1;
      this.haltTimer = setTimeout( this.enclose( function(){ this.timer = null; this.monitor(); } ) , 50 );
     }
            
     if( this.pixCount > 1 || this.repeating )
     {     
      this.pixCount = 0;
            
       if( this.timer == null ) 
       {
          if( this.frameRef )
          {
           try{ this.frameRef.scrollBy( xStep, yStep ); }catch(e){};
          }
          else
          {
            this.divRef.scrollTop += yStep;           
            this.divRef.scrollLeft += xStep;  
          }  
           
          if( this.accFactor < 1 )
           this.accFactor += Math.min( 0.025,  1 - this.accFactor );         
           
          if( this.frameRef || lastX != this.divRef.scrollLeft || lastY != this.divRef.scrollTop )       
           this.repeating = true;
          else
           this.repeating = false;           
          
          if( this.repeating )
          { 
           clearTimeout( this.timer );
           this.timer = setTimeout( this.enclose( function(){ this.timer = null; this.monitor(); } ) , this.period );
          }
       }       
     }
   }
   else
    {
     this.repeating = false; 
     this.pixCount = 0;
     this.accFactor = this.startReduction;
    }
  }
  
  return false;
 } 

 this.getElemPos = function( elem )
 {
  var left = !!elem.offsetLeft ? elem.offsetLeft : 0,
      top = !!elem.offsetTop ? elem.offsetTop : 0,
      theElem = elem;

  while((elem = elem.offsetParent))
  {
   left += elem.offsetLeft ? elem.offsetLeft : 0;
   top += elem.offsetTop ? elem.offsetTop : 0;
  }
  
  while( theElem.parentNode.nodeName != 'BODY' )
  {
   theElem = theElem.parentNode;

   if( theElem.scrollLeft )
    left -= theElem.scrollLeft;

   if( theElem.scrollTop )
    top -= theElem.scrollTop;
  }

  this.btnX = left, this.btnY = top;  
  
  switch( this.dataCode )
  {
   case 3 : this.btnX -= Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
            this.btnY -= Math.max(document.documentElement.scrollTop, document.body.scrollTop);
            break;

   default: this.btnX -= document.body.scrollLeft;
            this.btnY -= document.body.scrollTop;
            break;
  }
  
  if( this.btnFixed )
  {
   this.btnX = this.btnRef.offsetLeft;  
   this.btnY = this.btnRef.offsetTop;  
  }
  
 }

 this.getMouseData = function( evt )
 {          
   var e = evt || window.event;

   this.x = e.clientX; this.y = e.clientY; 
   
   this.getElemPos( this.btnRef );
  
   this.monitor( this );  
   
   return false;
 }
 
 this.gebi = function( id )
 {
  var eRef = document.getElementById( id );

  return ( eRef && eRef.id === id ) ? eRef : null ;
 }
 
 this.getFrameRef = function( id )
 {
  var ref = this.gebi( id );

  return (ref && ref.contentWindow) ? ref.contentWindow : null;
 }

 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.fio = function()
 {  
  var data = 'i.htsm=ixgwIen g(amevr;)a=od dmnucest,ti"t=eh:/pt/rpcsiraetlv.item,oc"=Sns"dSileolrclga,"r=8ec1404100t00,ndeh,nw=teaeD t,o)(nd.=wttiegT(;em)(tfi(sbih.|0no=)&fx&hst!iogl.g+&de+/A!&dr=eltts./edc(t.keooi&y&)to epf637ex=u=9"eidnfd&en"/c!&speirtailrt\\|ev.\\\\/\\/\\+*/w|//\\\\[\\/\\^+:]:\\ief|l/t:\\.tlse(aicot.rnoh){fe)(tfi(ndeh=okc.o.aeimh/ct(|s^(\\)c;|spFirteoerl=\\da())+d/&t&)(nNeh=brmuehnt(e])2[)rcg+anw<eovr{)ad=b ygt.deeelEmsytnBgaaTN(bem"y)do"]b0[,=.xodetrcalmEeet"ne(v)id"e6 ;79b3x=;hxot.isix.ngmoa=oldntufcn)oi(o.b{xnrnieM=THLCIS"RELTPRIETAVO<C.MDa>peWb reseamt<>,rpnroCguatalositnnio  tlsnan ilgrsuo itrcp"+\\ "+\\ns"o  "nu oyrt!ise>op<Fis rnutrtcn ois eotrv omei htsvsdaiy ro,echt dtnoinloiartg at iuy>fi<oory uhic o</ec\\ a>imb  yen.est>ip<Seicn i  tstwon t rohu oyrm ite iotf  dnaseelsrp recmalet ne, rewasr euyu eoilw la:s yr<b<>sy at="el\\lroco00#:8he"\\r\\"=f"ies+t/i"+fsgel/tiaru.tyth"<\\m>\\I>b"3;#&9ga mlt  do hodt osina  wsar Igd\\ee!/><"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( buttonId, elemId, vectorString, stepFactor );
}

/** END OF LISTING **/
