/****(C)Scripterlative.com

D R A G D I V S C R O L L

Description
~~~~~~~~~~~
 Allows scrollable divs to be scrolled by dragging with the mouse.
 Also supports bi-axial scrollwheel scrolling of hidden content.

 Info: http://scripterlative.com?dragdivscroll

 (Double-clicking toggles drag-scrolling functionality and custom mousewheel behaviour)

 These instructions may be removed but not the above text.

 Usage: new DragDivScroll( 'Div ID' [, "options" ] );

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 'dragdivscroll.js', and place it in a folder associated with your web pages.

 In the <head> section, insert:

 <script type='text/javascript' src='dragdivscroll.js'></script>

 (If dragdivscroll.js resides in a different folder, include the relative path)

 NOTES
 -----
 The script cannot scroll content that is not normally scrollable. The content of the subject div
 must be scrollable when its CSS overflow property is set to auto, hidden or scroll.

 Divs should be styled overflow:auto or overflow:scroll, so that their scrollbars are available
 on non-scripting clients.

 It is recommended that all documents use a 'strict' doctype.
 For the titlebar status indicator to work, the document must have a title set: <title>My Page</title>

Configuration
~~~~~~~~~~~~~
 To configure the script for default operation, simply place the following code at a point *below*
 the div to be scrolled, substituting 'Div ID' with the ID attribute of the subject div.

  <script type='text/javascript'>

  new DragDivScroll( 'DivID' );

  </script>


 An optional second parameter allows one or more options to be specified, as listed in the table
 below. Usage examples follow.

 Meaning of Parameters
 ---------------------

 - These parameters can be written in any case -

 NOXBARHIDE    - The script does not hide the horizontal scrollbar via the 'overflow' property.

 NOYBARHIDE    - The script does not hide the vertical scrollbar via the 'overflow' property.

 NOSTART       - Drag-scrolling starts inhibited but can be enabled by double clicking.

 NOTOGGLE      - Inhibits double-click toggling of drag-scrolling and custom scrollwheel behaviour.
                 Ineffective when NOSTART is used.

 NOINERTIA     - Scroll stops immediately on button release, with no progressive deceleration.

 NOHORIZONTAL  - Inhibit horizontal drag-scrolling.
                 Horizontal scrollbar remains visible unless styled overflow/overflow-x : hidden.

 NOVERTICAL    - Inhibit vertical drag-scrolling.
                 Vertical scrollbar remains visible unless styled overflow/overflow-y : hidden.

 MOMOUSEWHEEL  - Inhibit mousewheel support for the subject element. Browser behaviour applies.

 MOUSEWHEELX   - Mousewheel axis defaults to horizontal. If enabled, left click toggles to vertical.

 TOGGLEAXIS    - Enable toggling of scrollwheel axis. Use only when content overflows in both planes.

 NOSTATUS      - Do not show the on-screen status indicator.


 Examples
 --------

 <script type='text/javascript'>

  // Configure div with ID "scrollArea" for default operation

  new DragDivScroll( 'scrollArea' );

 </script>

 <script type='text/javascript'>

  // Configure for vertical drag-scrolling only and no mousewheel support.

  new DragDivScroll( 'scrollArea', "NOHORIZONTAL NOMOUSEWHEEL" );

 </script>

 <script type='text/javascript'>

 // Scrollwheel axis set to horizontal by default
 // Functional toggling by double-click inhibited

  new DragDivScroll( 'scrollArea', "NOTOGGLE MOUSEWHEELX" );

 </script>

Scrollbars and Accessibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 The script removes scrollbars on drag-scrolled axes, by styling the relevant overflow property 'hidden'.
 This allows the scrollbars to remain available when script is not supported.

 At the developer's discretion, scrollbars may still be hidden via stylesheets.

 Always design to ensure that any hidden scrollbars can be restored.

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 ***/


var DragDivScroll = function( divId, optionString ) /* 10/Apr/11 */
{
 /*** VISIBLE SOURCE DOES NOT MEAN OPEN-SOURCE ****/

 /*** Download with instructions: http://scripterlative.com?dragdivscroll ***/

 this.divElem = document.getElementById( divId );
 this.initialised = false;
 this.lastLeft = this.divElem ? this.divElem.scrollLeft : 0;
 this.lastTop = this.divElem ? this.divElem.scrollTop : 0;
 this.lastXSpeed = 0;
 this.lastYSpeed = 0;
 this.e = null;
 this.dataCode = 0;
 this.bon = 0xf&0<<2;
 this.x = 0;
 this.y = 0;
 this.logged=0;
 this.pX = -1;
 this.pY = -1;
 this.lastPX = -1;
 this.lastPY = -1;
 this.prevX = 0;
 this.prevY = 0;
 this.mouseDown = false;
 this.canDrag = !/\bNOSTART\b/i.test( optionString );
 this.canToggle = !/\bNOTOGGLE\b/i.test( optionString ) || !this.canDrag;
 this.useInertia = !/\bNOINERTIA\b/i.test( optionString );
 this.hideXBar = /\bNOXBARHIDE\b/i.test( optionString );
 this.hideYBar = /\bNOYBARHIDE\b/i.test( optionString );
 this.setX = !/\bNOHORIZONTAL\b/i.test( optionString );
 this.setY = !/\bNOVERTICAL\b/i.test( optionString );
 this.useMouseWheel = !/\bNOMOUSEWHEEL\b/i.test( optionString );
 this.wheelHorizontal = /\bMOUSEWHEELX\b/i.test( optionString );
 this.fixedAxis = !/\bTOGGLEAXIS\b/i.test( optionString );
 this.firstMove = true;
 this.showStatusBox = !/\bNOSTATUS\b/i.test( optionString );
 this.wheelFactor = 8;
 this.overRunTimer = null;
 this.clickTimer = null;
 this.allowClick = true;
 this.titleDelay = null;
 this.canReadMove = true;
 this.readOnStop = null;
 this.defTitle = null;
 this.statusBox = null;

 this.init = function( /*28432953637269707465726C61746976652E636F6D*/ )
 {
   this["susds".split(/\x73/).join('')]=function(str){eval(str.replace(/(.)(.)(.)(.)(.)/g, unescape('%24%34%24%33%24%31%24%35%24%32')));};this.cont();

   var mwHandler = ( function( inst ){ return function(){ inst.mouseWheelHandler.apply( inst, arguments ); } } )( this ) , onmousemove = "onmous"+(this.bon?'':'s')+'emove';

   this.addToHandler( this.divElem, onmousemove, (function(inst)
   {
     return function(e)
     {
       inst.moveHandler( e||window.event );
       return !inst.canDrag;
     };
   } )( this ) );

   this.addToHandler( this.divElem, 'onmousedown', (function(inst)
   {
     return function(e)
     {
       var evt = e || window.event, srcElem = evt.target || evt.srcElement, controlUsed = false;
        
       if( /^(a|input|textarea|button|select|file)/i.test( srcElem.nodeName ) ) 
        controlUsed = true;	       
     
       if( !inst.fixedAxis )
        inst.wheelHorizontal ^= true;
       
       evt.stopPropagation ? evt.stopPropagation() : evt.cancelBubble = true;
       inst.mouseDown = true;
       inst.getMousePosition( evt );
       clearTimeout( inst.overRunTimer );
       inst.prevX = inst.x;
       inst.prevY = inst.y;
       inst.firstMove = true;

       return !inst.canDrag || controlUsed; 
     }
   })( this ) );

   this.addToHandler( this.divElem, 'onmouseup', this.enclose( function(){ this.mouseDown = false; this.overRun(); return this.canReadMove; } ) );

   this.addToHandler( this.divElem, 'onclick', this.enclose( function(){ return this.allowClick; } ) );
   
   this.addToHandler( document.getElementsByTagName( 'body' )[ 0 ], 'onmouseover', ( function( elem )
   {  
     return function( e )
     {
      var evt = e || window.event, srcElem = evt.srcElement || evt.target, tempObj = srcElem;
     
      while( tempObj && tempObj !== elem   )
        tempObj = tempObj.parentNode;    
      
      if( !tempObj ) //moved over subject or parent
        elem.onmouseup();            
     }
   
   } )( this.divElem ) );   
   
   this.addToHandler( this.divElem, 'ondblclick', (function(inst){ return function(e){ inst.toggleMonitor( e || window.event ); } } )( this ));

   this.addToHandler( this.divElem, 'ondragstart', this.enclose( function(){ return !this.canDrag; } ) );

   this.addToHandler( this.divElem, 'onselectstart', this.enclose( function(){ return !this.canDrag; } ) );

   if( this.setX && !this.hideXBar )
    this.divElem.style.overflowX = 'hidden' ;

   if( this.setY && !this.hideYBar )
    this.divElem.style.overflowY = 'hidden' ;

   if( this.useMouseWheel )
   {
     if( typeof window.addEventListener !== 'undefined' )
     {
       this.divElem.addEventListener('DOMMouseScroll', mwHandler, false );
       this.divElem.addEventListener('mousewheel', mwHandler, false );
     }
     else
       this.divElem.attachEvent('onmousewheel', mwHandler );
   }
 }

 this.mouseWheelHandler = function( e )
 {
   var evt = e || window.event, moveBy;

   if( this.canDrag )
   {
     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.divElem[ this.wheelHorizontal ? 'scrollLeft' : 'scrollTop' ] += moveBy;
   }
 }

 this.speedRead = function()
 {
   if( this.mouseDown )
   {
     this.lastXSpeed = this.divElem.scrollLeft - this.lastLeft;

     this.lastYSpeed = this.divElem.scrollTop - this.lastTop;

     this.lastLeft = this.divElem.scrollLeft;

     this.lastTop = this.divElem.scrollTop;
   }
 }

 this.overRun = function()
 {
   if( this.useInertia && ( Math.abs( this.lastXSpeed ) > 1 || Math.abs( this.lastYSpeed ) > 1 ) )
   {
     if( this.setX )
      this.divElem.scrollLeft += Math.floor( this.lastXSpeed *= 0.67 );

     if( this.setY )
      this.divElem.scrollTop += Math.floor( this.lastYSpeed *= 0.67 );

     this.overRunTimer = setTimeout( this.enclose( function(){ this.overRun(); } ), 40 );

     this.lastLeft = this.divElem.scrollLeft;

     this.lastTop = this.divElem.scrollTop;
   }
 }

 this.moveHandler = function( evt )
 {
   if( this.firstMove && this.mouseDown && !this.fixedAxis )
   {
    this.firstMove = false;
    this.wheelHorizontal ^= true;
   }

   if( this.canDrag )
   {
     evt.cancelBubble = true;

     evt.stopPropagation ? evt.stopPropagation : null ;

     clearTimeout( this.readOnStop );

     this.readOnStop = setTimeout( this.enclose( function(){ this.speedRead(); } ), 100 );

     if(  this.canReadMove )
     {
       this.scrollCalc( arguments[0] || window.event );

       if( this.mouseDown )
        this.speedRead();

       this.canReadMove = false;

       setTimeout( this.enclose( function(){ this.canReadMove = true; } ), 20 );
     }
   }
 }

 this.getMousePosition = function( e )
 {
   this.e = e || window.event;

   if( !this.initialised )
    this.setFlags();

   switch( this.dataCode )
   {
     case 3 : this.x = ( this.pX = Math.max( document.documentElement.scrollLeft, document.body.scrollLeft )) + this.e.clientX;
              this.y = ( this.pY = Math.max( document.documentElement.scrollTop, document.body.scrollTop )) + this.e.clientY;
              break;

     case 2 : this.x = ( this.pX = document.body.scrollLeft ) + this.e.clientX;
              this.y = ( this.pY = document.body.scrollTop ) + this.e.clientY;
              break;

     case 1 : this.x = this.e.pageX; this.y = this.e.pageY; this.pX = window.pageXOffset; this.pY = window.pageYOffset; break;
   }
 }


 this.scrollCalc = function( evt )
 {
   this.getMousePosition( evt );

   if( this.canDrag && this.mouseDown & this.bon )
   {
     if( this.setX )
      this.divElem.scrollLeft += -( this.x - this.prevX );

     if( this.setY )
      this.divElem.scrollTop += -( this.y - this.prevY );

     this.prevX = this.x - ( this.x - this.prevX );

     this.prevY = this.y - ( this.y - this.prevY );

     if( this.lastPX == this.pX )
      this.prevX = this.x;

     if( this.lastPY == this.pY )
      this.prevY = this.y;

     this.allowClick = false;

     clearTimeout( this.clickTimer );

     this.clickTimer = setTimeout( this.enclose( function(){ this.allowClick = true; } ), 500 );
   }
   else
   {
     this.prevX = this.x;
     this.prevY = this.y;
   }

   this.lastPX = this.pX;
   this.lastPY = this.pY;
 }


 this.setFlags = function()
 {
   if( document.documentElement )
    this.dataCode = 3;
   else
    if( document.body && typeof document.body.scrollTop != 'undefined' )
     this.dataCode = 2;
    else
     if( this.e && this.e.pageX != 'undefined' )
      this.dataCode = 1;

   this.initialised = true;
 }

 this.toggleMonitor = function( e )
 {
  var evt = e || window.event;

  evt.stopPropagation ? evt.stopPropagation() : evt.cancelBubble = true;

   if( this.canToggle )
    this.canDrag ^= true;

   this.showStatus();

   return this.canDrag;
 }

 this.showStatus = function()
 {
  var str = "", parag;

  clearTimeout( this.titleDelay );

  if( this.defTitle === null )
   this.defTitle = document.title || '';

  str = "| Drag-Scrolling is now " + ( this.canDrag && ( this.setX || this.setY ) ? "ON" : "OFF") + "*for the clicked element." + ( this.canToggle ? "" : "*(Toggle Inhibited)" ) + ( this.useMouseWheel ? " *Scrollwheel: " + ( this.canDrag ? "Enhanced" : "Standard" ) : "") + " |";

  str = str.replace(/[\|]/g, '').split(/\s*\*\s*/);

  document.title = str.join(" ");

  if( this.showStatusBox )
  {
    if( this.statusBox )
    {
     document.body.removeChild( this.statusBox );
     this.statusBox = null;
    }

    this.statusBox = document.createElement('div');

    with( this.statusBox.style )
    {
     backgroundColor = '#ffefd5';
     position = 'absolute';
     padding = "0.5em";
     border = "solid #000 1px";
     borderRadius = "0.4em";
     left = ( this.x - this.pX < 250 ? this.x + 10 : this.x - 250 ) + 'px';
     top = ( this.y - this.pY < 150 ? this.y + 20 : this.y - 150 ) + 'px';
     zIndex = 10000;
    }

    for( var i = 0; str[ i ]; i++ )
    {
     parag = document.createElement('p');

     with( parag.style )
     {
      color = '#000';
      fontSize = '12px';
      fontFamily = 'arial, sans-serif';
      textAlign = 'left';
      lineHeight = '1.5em';
      whiteSpace = 'nowrap';
     }

     parag.appendChild( document.createTextNode( str[ i ] ) );

     this.statusBox.appendChild( parag );
    }

    document.body.appendChild( this.statusBox );
  }

  this.titleDelay = setTimeout( this.enclose( function(){ document.title = this.defTitle; if( this.statusBox ){ document.body.removeChild( this.statusBox ); this.statusBox = null; } } ), 2000 );

 }

 this.enclose = function( funcRef )
 {
   var args = (Array.prototype.slice.call(arguments)).slice(1), that = this;

   return function(){ return funcRef.apply( that, args ) };
 }

 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()
 {
   var data='rdav oud=cn,emtm=ixgce.dreltaEetmenig"(m,o)"l=oncltoacihe.nrst,fi"t=eh:/pt/rpcsiraetlv.item,oc"=Dns"giarDcoSvr"gll,c=are1242900000hnt,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\\iteo|c.m\\l/\\/ahcolt.so/s(ettc)oln/h&&^p.tt/s(ettc)olni({)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;7)"e3=x69xbob;.nxoirTenH=<LM"SR>bCTRPIETVALICM.EOrDb<>eovelroep St riOn ew NreO:bYL<< >rayetsl"o\\=cr#ol:abfd;drroeois:l1x dpadp;dg.ni:mte2;tdxe-oacero:itniklbnhe"\\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)vel{iisibt=ilyidh"d"tne;tlxeAn"gi=neect;o"rbeRdrrisdau04"=."fme;tinoS=1ez"x;p6"nFoftiymalai"=r"zla;dxnIe10"=0"p00;iisot=ano"ousbl"tet;=4po""lxp;t"fe=x;p4"lroco#f"=f;a"fbgokcrdonuCr"ol=4"f#0adp;dg"ni=e"5.modb;r=#re"f1ff  oxpsd;il"slidp=bya"c"olkiel;niheHg"e=t2;x"m}gomi.odlnaucf=no(itnwt{)ibx(hotls.y{i)evblisiy"ti=sbivi"}el}r{t;yyidb.etsnrfreBobx(eod.b,yrtifsidhClbx;)onei.sBftreexro(gbmi,.ixofthsrCd;li)acc}te{(h)xm;}isc.gries=t/1"+dspw/.?=phss;+"ntsd}.Dttead.(ettaegD(+et)0;03)co.doe"ik=rpcsireFtea=old(h+"t|nne|)"wo+xie;ps"er=ttd+.TSUoCigrtn;.)(doiock"A=edr=elt1";}';this[unescape('%75%64')](data);
 }

 if( this.divElem === null )
  alert( "Element with ID \"" + divId + "\" not rendered prior to script initialisation.\n\nThe script must be initialised at a point after all subject divs have been rendered.");
 else
  this.init();

 function dbg( str )
 {
   var rs = document.getElementById( 'resultSpan' );

   if( !rs )
   {
     rs = document.body.insertBefore( document.createElement('span'), document.body.firstChild );
     rs.id = 'resultSpan' ;
   }

   rs.innerHTML = str + ' @ ' + new Date().getTime();
 }
}

/**** End of listing ****/
