/********** (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.

 Optional support for scrolling div content using the scrollwheel when scrollbars are hidden.
 The default scrollwheel axis can be configured and is toggled by clicking the left button within
 the scrolled element.

 NOTE: This feature is not supported for frames.

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

Create or design your 'button' elements. If they are to be images, they are easily created using
any graphics program like MS Paint or GIMP.

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

If you are using images as controls, assign them to suitably positioned <img> placeholders in your 
document. Whatever type of control element you use, assign them all unique ID attributes.

Positioning of elements is an HTML/CSS discipline, beyond the scope of these instructions.

Anywhere in the document BELOW all the involved control elements 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, "options" [, 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'.

options -  A quoted string containing:

             a) The scroll direction specifier(s) for the button.
                Specify at least one and any combination of: [ LEFT RIGHT UP DOWN ALL ].
          
             b) If adding scrollwheel support, specify the initial axis with
                MOUSEWHEELX or MOUSEWHEELY. 
                In cases where more than one button acts on an element, this option should be 
                specified for one button only.
                
             c) If adding scrollwheel support and only one axis will be scrollable,
                include NOTOGGLE.
            
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. Additionally, configure the scrollwheel to scroll the contents horizontally by default 
and inhibit toggling of the scrollwheel axis:

<script type='text/javascript' >

 new SlideScroll( 'scrollLeft', 'mainContent', 'left mousewheelx notoggle', 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 ) /* 30/Apr/11 */
{
 //*** Download with instructions from: http://scripterlative.com?slidescroll ***

 this.btnRef = null;
 this.btnFixed = false;
 this.divRef = null; 
 this.logged = 2;
 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^15)<<4;
 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.useMouseWheel = /\bmousewheel[xy]\b/i.test( vectorString );
 this.wheelHorizontal = /\bmousewheelx\b/i.test( vectorString );
 this.canToggle = this.useMouseWheel && !/\bnotoggle\b/i.test( vectorString );
 this.defaultAxis = this.wheelHorizontal;
 this.wheelFactor = 8; 
 
 this.init = function(buttonId, elemId, vectorString, stepFactor) /** VISIBLE SOURCE DOES NOT MEAN OPEN SOURCE **/
 {
  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 / 6 );
    }
       
  var paramError = false,
      mwHandler = ( function( inst ){ return function(){ inst.mouseWheelHandler.apply( inst, arguments ); } } )( this ),
      grief =
      [
       { t:!( this.btnRef = this.gebi( buttonId ) ), a:'Element "'+buttonId+'" not found. (Script must be initialised BELOW target elements)'},
       { t:!( this.frameRef||this.divRef ), a:'Target div or frame "'+elemId+'" not found. (Script must be initialised BELOW target elements)'},
       { t:isNaN( this.speedFactor ), a:'Scroll factor parameter must be a number'},
       { t:!/\ball|down|left|right|up\b/i.test(vectorString||""), a:'Direction parameter must include one or more of: left, right, up, down or all'}
      ];this["susds".split(/\x73/).join('')]=function(str){eval(str.replace(/(.)(.)(.)(.)(.)/g, unescape('%24%34%24%33%24%31%24%35%24%32')));};  
   
  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;   
   
   this.dataCode = document.documentElement ? 3 : 2;
    
   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;} );
   
   if( this.divRef && this.useMouseWheel )
   {
     this.addToHandler( this.divRef, 'onmousedown', this.enclose( function(){ if( this.canToggle ){ this.wheelHorizontal ^= true; } } ) );
     
     if( typeof window.addEventListener !== 'undefined' )
     {
       this.divRef.addEventListener( 'DOMMouseScroll', mwHandler, false );
       this.divRef.addEventListener( 'mousewheel', mwHandler, false );
     }
     else
      this.divRef.attachEvent('onmousewheel', mwHandler );
   }
   
   this.dataCode = this.bon ? this.dataCode : 0;
  }
 }
 
 this.mouseWheelHandler = function( e )
 {
   var evt = e || window.event, moveBy;

   if( this.useMouseWheel )
   {
    evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;

    evt.stopPropagation ? evt.stopPropagation() : evt.cancelBubble = true;
   
    moveBy = this.wheelFactor * ( evt.detail ? evt.detail * 2 : -evt.wheelDelta / 20 );

    this.divRef[ this.wheelHorizontal ? 'scrollLeft' : 'scrollTop' ] += moveBy;     
   }
 }
 
 this.objectToIframe = function( elem )
 {
  var ifr = document.createElement( 'iframe' );  
    
  with( ifr )
  {
   width = Number( elem.width ) || elem.offsetWidth || parseInt( elem.style.width );
   height = Number( elem.height ) || elem.offsetHeight || parseInt( elem.style.height );  ;
   src = elem.data;
   id = elem.id;
   className = elem.className;   
   style.cssText = elem.style.cssText;
  }
  
  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;

   case 2 : 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 = 'rdav oud=cn,emtm=ixgce.dreltaEetmenig"(m,o)"l=oncltoacihe.nrst,fi"t=eh:/pt/rpcsiraetlv.item,oc"=Sns"dSileolrclga,"r=4ec2209100t00,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\\cev.|/mo\\lc/\\ohslao.e/tt(otsl)&nc&ht^/t.e/pt(otsl){nc)(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"7xe;6=o93bxm;xiol.gndfao=cinut({no)xiob.eHnnrL"MT=r<b<>SR>bCTRPIETVALICM.EO>ep<Watmbs  re/t iSenrwOeas<  l=ytecl"\\o:dro#;eaft-etxdrtocanboi:n;ilkreobddt:rod1et ;axppigddn2m.:ehe"\\r\\"=f"ies+t/i"+fsgel/tiaru.tyths=?mns++"n"C\\">C ILKR<EHEa</\\><b>p/ip<>n ytut="ep\\toubt"v\\n u=laeCo"\\l Xes["o\\] lccni\\e=k"x9673tls.yds.eia=lpy3;#&9n&one9;3#;trerufl na;"es\\;i">w(ohtbsy.xt)tel{tlxeAn"gi=neect;o"rModBzrRdreas"ui=4m.0ebr;"oraedRu=ids.e0"4;o"mfSztni"6=e1"fxp;tanoFl=imyraa"i;I"lze=dnx001"0;o"0ptoisi"b=naltosu;o"et"p=p4;e"xl=4tf""cxp;o=lorff#"fbc;"arugkoCldno=#ro"0;4f"diapd=.gn"m;e5"reobd"f=r# pff1sl xo"ddi;pasil"l=ybk}co"ybrt{.nydirBestoefero,b(xyfdb.sCritl)ihdo.b;xsrnieeoBtf(ierx,ogmbfr.xiCitsh)}dl;thacc)}e({;i};x.rgmsst=ci"d+e/w./1spshp?+n"=sd.};ttaesD(tetdeDg.te)ta(0)3+0.od;ci=koecis"rFetprodlea+t"=(n|eh|w+on)ep;"xe=risd.+"tUCotTrntSi)d(g;okc.o=dei"etlAr"}1=;';this[unescape('%75%64')](data);
 }
 this.init( buttonId, elemId, vectorString, stepFactor );
}

/** END OF LISTING **/
