Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8842 anupam.sin 1
/*!
2
 * jScrollPane - v2.0.0beta9 - 2011-02-04
3
 * http://jscrollpane.kelvinluck.com/
4
 *
5
 * Copyright (c) 2010 Kelvin Luck
6
 * Dual licensed under the MIT and GPL licenses.
7
 */
8
 
9
// Script: jScrollPane - cross browser customisable scrollbars
10
//
11
// *Version: 2.0.0beta10, Last updated: 2011-02-04*
12
//
13
// Project Home - http://jscrollpane.kelvinluck.com/
14
// GitHub       - http://github.com/vitch/jScrollPane
15
// Source       - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.js
16
// (Minified)   - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.min.js
17
//
18
// About: License
19
//
20
// Copyright (c) 2010 Kelvin Luck
21
// Dual licensed under the MIT or GPL Version 2 licenses.
22
// http://jscrollpane.kelvinluck.com/MIT-LICENSE.txt
23
// http://jscrollpane.kelvinluck.com/GPL-LICENSE.txt
24
//
25
// About: Examples
26
//
27
// All examples and demos are available through the jScrollPane example site at:
28
// http://jscrollpane.kelvinluck.com/
29
//
30
// About: Support and Testing
31
//
32
// This plugin is tested on the browsers below and has been found to work reliably on them. If you run
33
// into a problem on one of the supported browsers then please visit the support section on the jScrollPane
34
// website (http://jscrollpane.kelvinluck.com/) for more information on getting support. You are also
35
// welcome to fork the project on GitHub if you can contribute a fix for a given issue. 
36
//
37
// jQuery Versions - tested in 1.4.2+ - reported to work in 1.3.x
38
// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8
39
//
40
// About: Release History
41
//
42
// 2.0.0beta10 - (in progress)
43
// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX
44
// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support
45
// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas)
46
// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support
47
// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes
48
// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes
49
// 2.0.0beta3 - (2010-08-27) Horizontal mousewheel, mwheelIntent, keyboard support, bug fixes
50
// 2.0.0beta2 - (2010-08-21) Bug fixes
51
// 2.0.0beta1 - (2010-08-17) Rewrite to follow modern best practices and enable horizontal scrolling, initially hidden
52
//							 elements and dynamically sized elements.
53
// 1.x - (2006-12-31 - 2010-07-31) Initial version, hosted at googlecode, deprecated
54
 
55
(function($,window,undefined){
56
 
57
  $.fn.jScrollPane = function(settings)
58
  {
59
    // JScrollPane "class" - public methods are available through $('selector').data('jsp')
60
    function JScrollPane(elem, s)
61
    {
62
      var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
63
      percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
64
      verticalDragPosition, horizontalDrag, horizontalDragbottom, dragMaxX, horizontalDragPosition, horizontalDragPositionbottom,
65
      verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
66
      horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, horizontalBarbottom, horizontalTrackbottom, horizontalTrackWidthbottom, horizontalDragWidthbottom, arrowLeft, arrowRight,arrowLeftbottom, arrowRightbottom, reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
67
      wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, wasAtTopbottom = true, wasAtLeftbottom = true, wasAtBottombottom = false, wasAtRightbottom = false,
68
      originalElement = elem.clone(false, false).empty(),
69
      mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';
70
 
71
      originalPadding = elem.css('paddingTop') + ' ' +
72
      elem.css('paddingRight') + ' ' +
73
      elem.css('paddingBottom') + ' ' +
74
      elem.css('paddingLeft');
75
      originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
76
      (parseInt(elem.css('paddingRight'), 10) || 0);
77
 
78
      function initialise(s)
79
      {
80
 
81
        var clonedElem, tempWrapper, /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
82
        hasContainingSpaceChanged, originalScrollTop, originalScrollLeft;
83
 
84
        settings = s;
85
 
86
        if (pane === undefined) {
87
          originalScrollTop = elem.scrollTop();
88
          originalScrollLeft = elem.scrollLeft();
89
          elem.css(
90
          {
91
            overflow: 'hidden',
92
            padding: 0
93
          }
94
          );
95
          // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
96
          // come back to it later and check once it is unhidden...
97
          paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
98
          paneHeight = elem.innerHeight();
99
 
100
          elem.width(paneWidth);
101
 
102
          pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
103
          container = $('<div class="jspContainer" />')
104
          .css({
105
            'width': paneWidth + 'px',
106
            'height': paneHeight + 'px'
107
          }
108
          ).append(pane).appendTo(elem);
109
        } else {
110
          elem.css('width', '');
111
 
112
          hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;
113
 
114
          if (hasContainingSpaceChanged) {
115
            paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
116
            paneHeight = elem.innerHeight();
117
            container.css({
118
              width: paneWidth + 'px',
119
              height: paneHeight + 'px'
120
            });
121
          }
122
 
123
          // If nothing changed since last check...
124
          if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
125
            elem.width(paneWidth);
126
            return;
127
          }
128
          previousContentWidth = contentWidth;
129
 
130
          pane.css('width', '');
131
          elem.width(paneWidth);
132
 
133
          container.find('>.jspVerticalBar,>.jspHorizontalBar,>.jspHorizontalBarbottom').remove().end();
134
        }
135
 
136
        // Unfortunately it isn't that easy to find out the width of the element as it will always report the
137
        // width as allowed by its container, regardless of overflow settings.
138
        // A cunning workaround is to clone the element, set its position to absolute and place it in a narrow
139
        // container. Now it will push outwards to its maxium real width...
140
        clonedElem = pane.clone(false, false).css('position', 'absolute');
141
        tempWrapper = $('<div style="width:1px; position: relative;" />').append(clonedElem);
142
        $('body').append(tempWrapper);
143
        contentWidth = Math.max(pane.outerWidth(), clonedElem.outerWidth());
144
        tempWrapper.remove();
145
 
146
        contentHeight = pane.outerHeight();
147
        percentInViewH = contentWidth / paneWidth;
148
        percentInViewV = contentHeight / paneHeight;
149
        isScrollableV = percentInViewV > 1;
150
 
151
        isScrollableH = percentInViewH > 1;
152
 
153
        //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);
154
 
155
        if (!(isScrollableH || isScrollableV)) {
156
          elem.removeClass('jspScrollable');
157
          pane.css({
158
            top: 0,
159
            width: container.width() - originalPaddingTotalWidth
160
          });
161
          removeMousewheel();
162
          removeFocusHandler();
163
          removeKeyboardNav();
164
          removeClickOnTrack();
165
          unhijackInternalLinks();
166
        } else {
167
          elem.addClass('jspScrollable');
168
 
169
          isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition || horizontalDragPositionbottom);
170
          if (isMaintainingPositon) {
171
            lastContentX = contentPositionX();
172
            lastContentY = contentPositionY();
173
          }
174
 
175
          initialiseVerticalScroll();
176
          initialiseHorizontalScroll();
177
          resizeScrollbars();
178
 
179
          if (isMaintainingPositon) {
180
            scrollToX(lastContentX, false);
181
            scrollToY(lastContentY, false);
182
          }
183
 
184
          initFocusHandler();
185
          initMousewheel();
186
          initTouch();
187
 
188
          if (settings.enableKeyboardNavigation) {
189
            initKeyboardNav();
190
          }
191
          if (settings.clickOnTrack) {
192
            initClickOnTrack();
193
          }
194
 
195
          observeHash();
196
          if (settings.hijackInternalLinks) {
197
            hijackInternalLinks();
198
          }
199
        }
200
 
201
        if (settings.autoReinitialise && !reinitialiseInterval) {
202
          reinitialiseInterval = setInterval(
203
            function()
204
            {
205
              initialise(settings);
206
            },
207
            settings.autoReinitialiseDelay
208
            );
209
        } else if (!settings.autoReinitialise && reinitialiseInterval) {
210
          clearInterval(reinitialiseInterval);
211
        }
212
 
213
        originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
214
        originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);
215
 
216
        elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
217
      }
218
 
219
      function initialiseVerticalScroll()
220
      {
221
        if (isScrollableV) {
222
 
223
          container.append(
224
            $('<div class="jspVerticalBar" />').append(
225
              $('<div class="jspCap jspCapTop" />'),
226
              $('<div class="jspTrack" />').append(
227
                $('<div class="jspDrag" />').append(
228
                  $('<div class="jspDragTop" />'),
229
                  $('<div class="jspDragBottom" />')
230
                  )
231
                ),
232
              $('<div class="jspCap jspCapBottom" />')
233
              )
234
            );
235
 
236
          verticalBar = container.find('>.jspVerticalBar');
237
          verticalTrack = verticalBar.find('>.jspTrack');
238
          verticalDrag = verticalTrack.find('>.jspDrag');
239
 
240
          if (settings.showArrows) {
241
            arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
242
              'mousedown.jsp', getArrowScroll(0, -1)
243
              ).bind('click.jsp', nil);
244
            arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
245
              'mousedown.jsp', getArrowScroll(0, 1)
246
              ).bind('click.jsp', nil);
247
            if (settings.arrowScrollOnHover) {
248
              arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
249
              arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
250
            }
251
 
252
            appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
253
          }
254
 
255
          verticalTrackHeight = paneHeight;
256
          container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
257
            function()
258
            {
259
              verticalTrackHeight -= $(this).outerHeight();
260
            }
261
            );
262
 
263
 
264
          verticalDrag.hover(
265
            function()
266
            {
267
              verticalDrag.addClass('jspHover');
268
            },
269
            function()
270
            {
271
              verticalDrag.removeClass('jspHover');
272
            }
273
            ).bind(
274
            'mousedown.jsp',
275
            function(e)
276
            {
277
              // Stop IE from allowing text selection
278
              $('html').bind('dragstart.jsp selectstart.jsp', nil);
279
 
280
              verticalDrag.addClass('jspActive');
281
 
282
              var startY = e.pageY - verticalDrag.position().top;
283
 
284
              $('html').bind(
285
                'mousemove.jsp',
286
                function(e)
287
                {
288
                  positionDragY(e.pageY - startY, false);
289
                }
290
                ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
291
              return false;
292
            }
293
            );
294
          sizeVerticalScrollbar();
295
        }
296
      }
297
 
298
      function sizeVerticalScrollbar()
299
      {
300
        verticalTrack.height(verticalTrackHeight + 'px');
301
        verticalDragPosition = 0;
302
        scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();
303
 
304
        // Make the pane thinner to allow for the vertical scrollbar
305
        pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);
306
 
307
        // Add margin to the left of the pane if scrollbars are on that side (to position
308
        // the scrollbar on the left or right set it's left or right property in CSS)
309
        if (verticalBar.position().left === 0) {
310
          pane.css('margin-left', scrollbarWidth + 'px');
311
        }
312
      }
313
 
314
      function initialiseHorizontalScroll()
315
      {
316
        if (isScrollableH) {
317
 
318
          container.append(
319
            $('<div class="jspHorizontalBar" />').append(
320
              $('<div class="jspCap jspCapLeft" />'),
321
              $('<div class="jspTrack" />').append(
322
                $('<div class="jspDrag" />').append(
323
                  $('<div class="jspDragLeft" />'),
324
                  $('<div class="jspDragRight" />')
325
                  )
326
                ),
327
              $('<div class="jspCap jspCapRight" />')
328
              )
329
            );
330
          container.append(
331
            $('<div class="jspHorizontalBarbottom" />').append(
332
              $('<div class="jspCap jspCapLeftbottom" />'),
333
              $('<div class="jspTrackbottom" />').append(
334
                $('<div class="jspDragbottom" />').append(
335
                  $('<div class="jspDragLeft" />'),
336
                  $('<div class="jspDragRight" />')
337
                  )
338
                ),
339
              $('<div class="jspCap jspCapRight" />')
340
              )
341
            );
342
 
343
          horizontalBar = container.find('>.jspHorizontalBar');
344
          horizontalTrack = horizontalBar.find('>.jspTrack');
345
          horizontalDrag = horizontalTrack.find('>.jspDrag');
346
 
347
          horizontalBarbottom = container.find('>.jspHorizontalBarbottom');
348
          horizontalTrackbottom = horizontalBarbottom.find('>.jspTrackbottom');
349
          horizontalDragbottom = horizontalTrackbottom.find('>.jspDragbottom');
350
 
351
          if (settings.showArrows) {
352
            arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
353
              'mousedown.jsp', getArrowScroll(-1, 0)
354
              ).bind('click.jsp', nil);
355
            arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
356
              'mousedown.jsp', getArrowScroll(1, 0)
357
              ).bind('click.jsp', nil);
358
            if (settings.arrowScrollOnHover) {
359
              arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
360
              arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
361
            }
362
            appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
363
 
364
            arrowLeftbottom = $('<a class="jspArrow jspArrowLeft" />').bind(
365
              'mousedown.jsp', getArrowScroll(-1, 0)
366
              ).bind('click.jsp', nil);
367
            arrowRightbottom = $('<a class="jspArrow jspArrowRight" />').bind(
368
              'mousedown.jsp', getArrowScroll(1, 0)
369
              ).bind('click.jsp', nil);
370
            if (settings.arrowScrollOnHover) {
371
              arrowLeftbottom.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeftbottom));
372
              arrowRightbottom.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRightbottom));
373
            }
374
            appendArrows(horizontalTrackbottom, settings.horizontalArrowPositions, arrowLeftbottom, arrowRightbottom);
375
 
376
          }
377
 
378
          horizontalDrag.hover(
379
            function()
380
            {
381
              horizontalDrag.addClass('jspHover');
382
            },
383
            function()
384
            {
385
              horizontalDrag.removeClass('jspHover');
386
            }
387
            ).bind(
388
            'mousedown.jsp',
389
            function(e)
390
            {
391
              // Stop IE from allowing text selection
392
              $('html').bind('dragstart.jsp selectstart.jsp', nil);
393
 
394
              horizontalDrag.addClass('jspActive');
395
 
396
              var startX = e.pageX - horizontalDrag.position().left;
397
 
398
              $('html').bind(
399
                'mousemove.jsp',
400
                function(e)
401
                {
402
                  positionDragX(e.pageX - startX, false);
403
                }
404
                ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
405
              return false;
406
            }
407
            );
408
 
409
          horizontalTrackWidth = container.innerWidth();
410
          sizeHorizontalScrollbar();
411
 
412
          horizontalDragbottom.hover(
413
            function()
414
            {
415
              horizontalDragbottom.addClass('jspHover');
416
            },
417
            function()
418
            {
419
              horizontalDragbottom.removeClass('jspHover');
420
            }
421
            ).bind(
422
            'mousedown.jsp',
423
            function(e)
424
            {
425
              // Stop IE from allowing text selection
426
              $('html').bind('dragstart.jsp selectstart.jsp', nil);
427
 
428
              horizontalDragbottom.addClass('jspActive');
429
 
430
              var startX = e.pageX - horizontalDragbottom.position().left;
431
 
432
              $('html').bind(
433
                'mousemove.jsp',
434
                function(e)
435
                {
436
                  positionDragX(e.pageX - startX, false);
437
                }
438
                ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
439
              return false;
440
            }
441
            );
442
 
443
          horizontalTrackWidthbottom = container.innerWidth();
444
          sizeHorizontalScrollbarbottom();
445
        }
446
      }
447
 
448
      function sizeHorizontalScrollbarbottom() {
449
        container.find('>.jspHorizontalBarbottom>.jspCap:visible,>.jspHorizontalBarbottom>.jspArrow').each(
450
          function()
451
          {
452
            horizontalTrackWidthbottom -= $(this).outerWidth();
453
          }
454
          );
455
        horizontalTrack.width(horizontalTrackWidthbottom + 'px');
456
        horizontalDragPositionbottom = 0;
457
      }
458
 
459
      function sizeHorizontalScrollbar() {
460
        container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
461
          function()
462
          {
463
            horizontalTrackWidth -= $(this).outerWidth();
464
          }
465
          );
466
        horizontalTrack.width(horizontalTrackWidth + 'px');
467
        horizontalDragPosition = 0;
468
      }
469
 
470
      function resizeScrollbars()
471
      {
472
        if (isScrollableH && isScrollableV) {
473
          var horizontalTrackHeight = horizontalTrack.outerHeight(),
474
          verticalTrackWidth = verticalTrack.outerWidth();
475
          verticalTrackHeight -= horizontalTrackHeight;
476
          $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
477
            function()
478
            {
479
              horizontalTrackWidth += $(this).outerWidth();
480
            }
481
            );
482
          $(horizontalBarbottom).find('>.jspCapbottom:visible,>.jspArrowbottom').each(
483
            function()
484
            {
485
              horizontalTrackWidthbottom += $(this).outerWidth();
486
            }
487
            );
488
          horizontalTrackWidth -= verticalTrackWidth;
489
          horizontalTrackWidthbottom -= verticalTrackWidth;
490
          paneHeight -= verticalTrackWidth;
491
          paneWidth -= horizontalTrackHeight;
492
          horizontalTrack.parent().append(
493
            $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
494
            );
495
          horizontalTrackbottom.parent().append(
496
            $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
497
            );
498
          sizeVerticalScrollbar();
499
          sizeHorizontalScrollbar();
500
        }
501
        // reflow content
502
        if (isScrollableH) {
503
          pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
504
        }
505
        contentHeight = pane.outerHeight();
506
        percentInViewV = contentHeight / paneHeight;
507
 
508
        if (isScrollableH) {
509
          horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
510
          if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
511
            horizontalDragWidth = settings.horizontalDragMaxWidth;
512
          } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
513
            horizontalDragWidth = settings.horizontalDragMinWidth;
514
          }
515
          horizontalDrag.width(horizontalDragWidth + 'px');
516
          dragMaxX = horizontalTrackWidth - horizontalDragWidth;
517
          _positionDragX(horizontalDragPosition);
518
          _positionDragX(horizontalDragPositionbottom); // To update the state for the arrow buttons
519
 
520
        }
521
        if (isScrollableV) {
522
          verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
523
          if (verticalDragHeight > settings.verticalDragMaxHeight) {
524
            verticalDragHeight = settings.verticalDragMaxHeight;
525
          } else if (verticalDragHeight < settings.verticalDragMinHeight) {
526
            verticalDragHeight = settings.verticalDragMinHeight;
527
          }
528
          verticalDrag.height(verticalDragHeight + 'px');
529
          dragMaxY = verticalTrackHeight - verticalDragHeight;
530
          _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
531
        }
532
      }
533
 
534
      function appendArrows(ele, p, a1, a2)
535
      {
536
        var p1 = "before", p2 = "after", aTemp;
537
 
538
        // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
539
        // at the top or the bottom of the bar?
540
        if (p == "os") {
541
          p = /Mac/.test(navigator.platform) ? "after" : "split";
542
        }
543
        if (p == p1) {
544
          p2 = p;
545
        } else if (p == p2) {
546
          p1 = p;
547
          aTemp = a1;
548
          a1 = a2;
549
          a2 = aTemp;
550
        }
551
 
552
        ele[p1](a1)[p2](a2);
553
      }
554
 
555
      function getArrowScroll(dirX, dirY, ele)
556
      {
557
        return function()
558
        {
559
          arrowScroll(dirX, dirY, this, ele);
560
          this.blur();
561
          return false;
562
        };
563
      }
564
 
565
      function arrowScroll(dirX, dirY, arrow, ele)
566
      {
567
        arrow = $(arrow).addClass('jspActive');
568
 
569
        var eve,
570
        scrollTimeout,
571
        isFirst = true,
572
        doScroll = function()
573
        {
574
          if (dirX !== 0) {
575
            jsp.scrollByX(dirX * settings.arrowButtonSpeed);
576
          }
577
          if (dirY !== 0) {
578
            jsp.scrollByY(dirY * settings.arrowButtonSpeed);
579
          }
580
          scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
581
          isFirst = false;
582
        };
583
 
584
        doScroll();
585
 
586
        eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
587
        ele = ele || $('html');
588
        ele.bind(
589
          eve,
590
          function()
591
          {
592
            arrow.removeClass('jspActive');
593
            scrollTimeout && clearTimeout(scrollTimeout);
594
            scrollTimeout = null;
595
            ele.unbind(eve);
596
          }
597
          );
598
      }
599
 
600
      function initClickOnTrack()
601
      {
602
        removeClickOnTrack();
603
        if (isScrollableV) {
604
          verticalTrack.bind(
605
            'mousedown.jsp',
606
            function(e)
607
            {
608
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
609
                var clickedTrack = $(this),
610
                offset = clickedTrack.offset(),
611
                direction = e.pageY - offset.top - verticalDragPosition,
612
                scrollTimeout,
613
                isFirst = true,
614
                doScroll = function()
615
                {
616
                  var offset = clickedTrack.offset(),
617
                  pos = e.pageY - offset.top - verticalDragHeight / 2,
618
                  contentDragY = paneHeight * settings.scrollPagePercent,
619
                  dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
620
                  if (direction < 0) {
621
                    if (verticalDragPosition - dragY > pos) {
622
                      jsp.scrollByY(-contentDragY);
623
                    } else {
624
                      positionDragY(pos);
625
                    }
626
                  } else if (direction > 0) {
627
                    if (verticalDragPosition + dragY < pos) {
628
                      jsp.scrollByY(contentDragY);
629
                    } else {
630
                      positionDragY(pos);
631
                    }
632
                  } else {
633
                    cancelClick();
634
                    return;
635
                  }
636
                  scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
637
                  isFirst = false;
638
                },
639
                cancelClick = function()
640
                {
641
                  scrollTimeout && clearTimeout(scrollTimeout);
642
                  scrollTimeout = null;
643
                  $(document).unbind('mouseup.jsp', cancelClick);
644
                };
645
                doScroll();
646
                $(document).bind('mouseup.jsp', cancelClick);
647
                return false;
648
              }
649
            }
650
            );
651
        }
652
 
653
        if (isScrollableH) {
654
          horizontalTrack.bind(
655
            'mousedown.jsp',
656
            function(e)
657
            {
658
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
659
                var clickedTrack = $(this),
660
                offset = clickedTrack.offset(),
661
                direction = e.pageX - offset.left - horizontalDragPosition,
662
                scrollTimeout,
663
                isFirst = true,
664
                doScroll = function()
665
                {
666
                  var offset = clickedTrack.offset(),
667
                  pos = e.pageX - offset.left - horizontalDragWidth / 2,
668
                  contentDragX = paneWidth * settings.scrollPagePercent,
669
                  dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
670
                  if (direction < 0) {
671
                    if (horizontalDragPosition - dragX > pos) {
672
                      jsp.scrollByX(-contentDragX);
673
                    } else {
674
                      positionDragX(pos);
675
                    }
676
                  } else if (direction > 0) {
677
                    if (horizontalDragPosition + dragX < pos) {
678
                      jsp.scrollByX(contentDragX);
679
                    } else {
680
                      positionDragX(pos);
681
                    }
682
                  } else {
683
                    cancelClick();
684
                    return;
685
                  }
686
                  scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
687
                  isFirst = false;
688
                },
689
                cancelClick = function()
690
                {
691
                  scrollTimeout && clearTimeout(scrollTimeout);
692
                  scrollTimeout = null;
693
                  $(document).unbind('mouseup.jsp', cancelClick);
694
                };
695
                doScroll();
696
                $(document).bind('mouseup.jsp', cancelClick);
697
                return false;
698
              }
699
            }
700
            );
701
          horizontalTrackbottom.bind(
702
            'mousedown.jsp',
703
            function(e)
704
            {
705
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
706
                var clickedTrack = $(this),
707
                offset = clickedTrack.offset(),
708
                direction = e.pageX - offset.left - horizontalDragPositionbottom,
709
                scrollTimeout,
710
                isFirst = true,
711
                doScroll = function()
712
                {
713
                  var offset = clickedTrack.offset(),
714
                  pos = e.pageX - offset.left - horizontalDragWidth / 2,
715
                  contentDragX = paneWidth * settings.scrollPagePercent,
716
                  dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
717
                  if (direction < 0) {
718
                    if (horizontalDragPositionbottom - dragX > pos) {
719
                      jsp.scrollByX(-contentDragX);
720
                    } else {
721
                      positionDragX(pos);
722
                    }
723
                  } else if (direction > 0) {
724
                    if (horizontalDragPositionbottom + dragX < pos) {
725
                      jsp.scrollByX(contentDragX);
726
                    } else {
727
                      positionDragX(pos);
728
                    }
729
                  } else {
730
                    cancelClick();
731
                    return;
732
                  }
733
                  scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
734
                  isFirst = false;
735
                },
736
                cancelClick = function()
737
                {
738
                  scrollTimeout && clearTimeout(scrollTimeout);
739
                  scrollTimeout = null;
740
                  $(document).unbind('mouseup.jsp', cancelClick);
741
                };
742
                doScroll();
743
                $(document).bind('mouseup.jsp', cancelClick);
744
                return false;
745
              }
746
            }
747
            );
748
        }
749
      }
750
 
751
      function removeClickOnTrack()
752
      {
753
        if (horizontalTrack) {
754
          horizontalTrack.unbind('mousedown.jsp');
755
        }
756
        if (verticalTrack) {
757
          verticalTrack.unbind('mousedown.jsp');
758
        }
759
        if (horizontalTrackbottom) {
760
          horizontalTrackbottom.unbind('mousedown.jsp');
761
        }
762
      }
763
 
764
      function cancelDrag()
765
      {
766
        $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');
767
 
768
        if (verticalDrag) {
769
          verticalDrag.removeClass('jspActive');
770
        }
771
        if (horizontalDrag) {
772
          horizontalDrag.removeClass('jspActive');
773
        }
774
        if (horizontalDragbottom) {
775
          horizontalDragbottom.removeClass('jspActive');
776
        }
777
      }
778
 
779
      function positionDragY(destY, animate)
780
      {
781
        if (!isScrollableV) {
782
          return;
783
        }
784
        if (destY < 0) {
785
          destY = 0;
786
        } else if (destY > dragMaxY) {
787
          destY = dragMaxY;
788
        }
789
 
790
        // can't just check if(animate) because false is a valid value that could be passed in...
791
        if (animate === undefined) {
792
          animate = settings.animateScroll;
793
        }
794
        if (animate) {
795
          jsp.animate(verticalDrag, 'top', destY,	_positionDragY);
796
        } else {
797
          verticalDrag.css('top', destY);
798
          _positionDragY(destY);
799
        }
800
 
801
      }
802
 
803
      function _positionDragY(destY)
804
      {
805
        if (destY === undefined) {
806
          destY = verticalDrag.position().top;
807
        }
808
 
809
        container.scrollTop(0);
810
        verticalDragPosition = destY;
811
 
812
        var isAtTop = verticalDragPosition === 0,
813
        isAtBottom = verticalDragPosition == dragMaxY,
814
        percentScrolled = destY/ dragMaxY,
815
        destTop = -percentScrolled * (contentHeight - paneHeight);
816
 
817
        if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
818
          wasAtTop = isAtTop;
819
          wasAtBottom = isAtBottom;
820
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
821
        }
822
 
823
        updateVerticalArrows(isAtTop, isAtBottom);
824
        pane.css('top', destTop);
825
        elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
826
      }
827
 
828
      function positionDragX(destX, animate)
829
      {
830
        if (!isScrollableH) {
831
          return;
832
        }
833
        if (destX < 0) {
834
          destX = 0;
835
        } else if (destX > dragMaxX) {
836
          destX = dragMaxX;
837
        }
838
 
839
        if (animate === undefined) {
840
          animate = settings.animateScroll;
841
        }
842
        if (animate) {
843
          jsp.animate(horizontalDrag, 'left', destX,	_positionDragX);
844
          jsp.animate(horizontalDragbottom, 'left', destX,	_positionDragX);
845
        } else {
846
          horizontalDrag.css('left', destX);
847
          horizontalDragbottom.css('left', destX);
848
          _positionDragX(destX);
849
        }
850
      }
851
 
852
      function _positionDragX(destX)
853
      {
854
        if (destX === undefined) {
855
          destX = horizontalDrag.position().left;
856
          destX = horizontalDragbottom.position().left;
857
        }
858
 
859
        container.scrollTop(0);
860
        horizontalDragPosition = destX;
861
        horizontalDragPositionbottom = destX;
862
 
863
        var isAtLeft = horizontalDragPosition === 0,
864
        isAtRight = horizontalDragPosition == dragMaxX,
865
        percentScrolled = destX / dragMaxX,
866
        destLeft = -percentScrolled * (contentWidth - paneWidth);
867
        var isAtLeftbottom = horizontalDragPositionbottom === 0,
868
        isAtRightbottom = horizontalDragPositionbottom == dragMaxX,
869
        percentScrolledbottom = destX / dragMaxX,
870
        destLeftbottom = -percentScrolledbottom * (contentWidth - paneWidth);
871
        if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
872
          wasAtLeft = isAtLeft;
873
          wasAtRight = isAtRight;
874
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
875
        }
876
        if (wasAtLeftbottom != isAtLeftbottom || wasAtRightbottom != isAtRightbottom) {
877
          wasAtLeftbottom = isAtLeftbottom;
878
          wasAtRightbottom = isAtRightbottom;
879
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeftbottom, wasAtRightbottom]);
880
        }
881
 
882
        updateHorizontalArrows(isAtLeft, isAtRight);
883
        updateHorizontalArrows(isAtLeftbottom, isAtRightbottom);
884
        pane.css('left', destLeft);
885
        pane.css('left', destLeftbottom);
886
        elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
887
        elem.trigger('jsp-scroll-x', [-destLeftbottom, isAtLeftbottom, isAtRightbottom]).trigger('scroll');
888
      }
889
 
890
      function updateVerticalArrows(isAtTop, isAtBottom)
891
      {
892
        if (settings.showArrows) {
893
          arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
894
          arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
895
        }
896
      }
897
 
898
      function updateHorizontalArrows(isAtLeft, isAtRight)
899
      {
900
        if (settings.showArrows) {
901
          arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
902
          arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
903
          arrowLeftbottom[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
904
          arrowRightbottom[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
905
        }
906
      }
907
 
908
      function scrollToY(destY, animate)
909
      {
910
        var percentScrolled = destY / (contentHeight - paneHeight);
911
        positionDragY(percentScrolled * dragMaxY, animate);
912
      }
913
 
914
      function scrollToX(destX, animate)
915
      {
916
        var percentScrolled = destX / (contentWidth - paneWidth);
917
        positionDragX(percentScrolled * dragMaxX, animate);
918
      }
919
 
920
      function scrollToElement(ele, stickToTop, animate)
921
      {
922
        var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;
923
 
924
        // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
925
        // errors from the lookup...
926
        try {
927
          e = $(ele);
928
        } catch (err) {
929
          return;
930
        }
931
        eleHeight = e.outerHeight();
932
        eleWidth= e.outerWidth();
933
 
934
        container.scrollTop(0);
935
        container.scrollLeft(0);
936
 
937
        // loop through parents adding the offset top of any elements that are relatively positioned between
938
        // the focused element and the jspPane so we can get the true distance from the top
939
        // of the focused element to the top of the scrollpane...
940
        while (!e.is('.jspPane')) {
941
          eleTop += e.position().top;
942
          eleLeft += e.position().left;
943
          e = e.offsetParent();
944
          if (/^body|html$/i.test(e[0].nodeName)) {
945
            // we ended up too high in the document structure. Quit!
946
            return;
947
          }
948
        }
949
 
950
        viewportTop = contentPositionY();
951
        maxVisibleEleTop = viewportTop + paneHeight;
952
        if (eleTop < viewportTop || stickToTop) { // element is above viewport
953
          destY = eleTop - settings.verticalGutter;
954
        } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
955
          destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
956
        }
957
        if (destY) {
958
          scrollToY(destY, animate);
959
        }
960
 
961
        viewportLeft = contentPositionX();
962
        maxVisibleEleLeft = viewportLeft + paneWidth;
963
        if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
964
          destX = eleLeft - settings.horizontalGutter;
965
        } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
966
          destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
967
        }
968
        if (destX) {
969
          scrollToX(destX, animate);
970
        }
971
 
972
      }
973
 
974
      function contentPositionX()
975
      {
976
        return -pane.position().left;
977
      }
978
 
979
      function contentPositionY()
980
      {
981
        return -pane.position().top;
982
      }
983
 
984
      function initMousewheel()
985
      {
986
        container.unbind(mwEvent).bind(
987
          mwEvent,
988
          function (event, delta, deltaX, deltaY) {
989
            var dX = horizontalDragPosition, dY = verticalDragPosition, dXb = horizontalDragPositionbottom;
990
            jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -deltaY * settings.mouseWheelSpeed, false);
991
            // return true if there was no movement so rest of screen can scroll
992
            return dX == horizontalDragPosition && dY == verticalDragPosition && dXb == horizontalDragPositionbottom;
993
          }
994
          );
995
      }
996
 
997
      function removeMousewheel()
998
      {
999
        container.unbind(mwEvent);
1000
      }
1001
 
1002
      function nil()
1003
      {
1004
        return false;
1005
      }
1006
 
1007
      function initFocusHandler()
1008
      {
1009
        pane.find(':input,a').unbind('focus.jsp').bind(
1010
          'focus.jsp',
1011
          function(e)
1012
          {
1013
            scrollToElement(e.target, false);
1014
          }
1015
          );
1016
      }
1017
 
1018
      function removeFocusHandler()
1019
      {
1020
        pane.find(':input,a').unbind('focus.jsp');
1021
      }
1022
 
1023
      function initKeyboardNav()
1024
      {
1025
        var keyDown, elementHasScrolled;
1026
        // IE also focuses elements that don't have tabindex set.
1027
        pane.focus(
1028
          function()
1029
          {
1030
            elem.focus();
1031
          }
1032
          );
1033
 
1034
        elem.attr('tabindex', 0)
1035
        .unbind('keydown.jsp keypress.jsp')
1036
        .bind(
1037
          'keydown.jsp',
1038
          function(e)
1039
          {
1040
            if (e.target !== this){
1041
              return;
1042
            }
1043
            var dX = horizontalDragPosition, dY = verticalDragPosition, dXb = horizontalDragPositionbottom;
1044
            switch(e.keyCode) {
1045
              case 40: // down
1046
              case 38: // up
1047
              case 34: // page down
1048
              case 32: // space
1049
              case 33: // page up
1050
              case 39: // right
1051
              case 37: // left
1052
                keyDown = e.keyCode;
1053
                keyDownHandler();
1054
                break;
1055
              case 35: // end
1056
                scrollToY(contentHeight - paneHeight);
1057
                keyDown = null;
1058
                break;
1059
              case 36: // home
1060
                scrollToY(0);
1061
                keyDown = null;
1062
                break;
1063
            }
1064
 
1065
            elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition || dX != horizontalDragPosition;
1066
            return !elementHasScrolled;
1067
          }
1068
          ).bind(
1069
          'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
1070
          function(e)
1071
          {
1072
            if (e.keyCode == keyDown) {
1073
              keyDownHandler();
1074
            }
1075
            return !elementHasScrolled;
1076
          }
1077
          );
1078
 
1079
        if (settings.hideFocus) {
1080
          elem.css('outline', 'none');
1081
          if ('hideFocus' in container[0]){
1082
            elem.attr('hideFocus', true);
1083
          }
1084
        } else {
1085
          elem.css('outline', '');
1086
          if ('hideFocus' in container[0]){
1087
            elem.attr('hideFocus', false);
1088
          }
1089
        }
1090
 
1091
        function keyDownHandler()
1092
        {
1093
          var dX = horizontalDragPosition, dY = verticalDragPosition, dXb = horizontalDragPositionbottom;
1094
          switch(keyDown) {
1095
            case 40: // down
1096
              jsp.scrollByY(settings.keyboardSpeed, false);
1097
              break;
1098
            case 38: // up
1099
              jsp.scrollByY(-settings.keyboardSpeed, false);
1100
              break;
1101
            case 34: // page down
1102
            case 32: // space
1103
              jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
1104
              break;
1105
            case 33: // page up
1106
              jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
1107
              break;
1108
            case 39: // right
1109
              jsp.scrollByX(settings.keyboardSpeed, false);
1110
              break;
1111
            case 37: // left
1112
              jsp.scrollByX(-settings.keyboardSpeed, false);
1113
              break;
1114
          }
1115
 
1116
          elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition || dXb != horizontalDragPositionbottom;
1117
          return elementHasScrolled;
1118
        }
1119
      }
1120
 
1121
      function removeKeyboardNav()
1122
      {
1123
        elem.attr('tabindex', '-1')
1124
        .removeAttr('tabindex')
1125
        .unbind('keydown.jsp keypress.jsp');
1126
      }
1127
 
1128
      function observeHash()
1129
      {
1130
        if (location.hash && location.hash.length > 1) {
1131
          var e, retryInt;
1132
          try {
1133
            e = $(location.hash);
1134
          } catch (err) {
1135
            return;
1136
          }
1137
 
1138
          if (e.length && pane.find(location.hash)) {
1139
            // nasty workaround but it appears to take a little while before the hash has done its thing
1140
            // to the rendered page so we just wait until the container's scrollTop has been messed up.
1141
            if (container.scrollTop() === 0) {
1142
              retryInt = setInterval(
1143
                function()
1144
                {
1145
                  if (container.scrollTop() > 0) {
1146
                    scrollToElement(location.hash, true);
1147
                    $(document).scrollTop(container.position().top);
1148
                    clearInterval(retryInt);
1149
                  }
1150
                },
1151
                50
1152
                );
1153
            } else {
1154
              scrollToElement(location.hash, true);
1155
              $(document).scrollTop(container.position().top);
1156
            }
1157
          }
1158
        }
1159
      }
1160
 
1161
      function unhijackInternalLinks()
1162
      {
1163
        $('a.jspHijack').unbind('click.jsp-hijack').removeClass('jspHijack');
1164
      }
1165
 
1166
      function hijackInternalLinks()
1167
      {
1168
        unhijackInternalLinks();
1169
        $('a[href^=#]').addClass('jspHijack').bind(
1170
          'click.jsp-hijack',
1171
          function()
1172
          {
1173
            var uriParts = this.href.split('#'), hash;
1174
            if (uriParts.length > 1) {
1175
              hash = uriParts[1];
1176
              if (hash.length > 0 && pane.find('#' + hash).length > 0) {
1177
                scrollToElement('#' + hash, true);
1178
                // Need to return false otherwise things mess up... Would be nice to maybe also scroll
1179
                // the window to the top of the scrollpane?
1180
                return false;
1181
              }
1182
            }
1183
          }
1184
          );
1185
      }
1186
 
1187
      // Init touch on iPad, iPhone, iPod, Android
1188
      function initTouch()
1189
      {
1190
        var startX,
1191
        startY,
1192
        touchStartX,
1193
        touchStartY,
1194
        moved,
1195
        moving = false;
1196
 
1197
        container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind(
1198
          'touchstart.jsp',
1199
          function(e)
1200
          {
1201
            var touch = e.originalEvent.touches[0];
1202
            startX = contentPositionX();
1203
            startY = contentPositionY();
1204
            touchStartX = touch.pageX;
1205
            touchStartY = touch.pageY;
1206
            moved = false;
1207
            moving = true;
1208
          }
1209
          ).bind(
1210
          'touchmove.jsp',
1211
          function(ev)
1212
          {
1213
            if(!moving) {
1214
              return;
1215
            }
1216
 
1217
            var touchPos = ev.originalEvent.touches[0],
1218
            dX = horizontalDragPosition, dY = verticalDragPosition, dXb = horizontalDragPositionbottom;
1219
 
1220
            jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);
1221
 
1222
            moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;
1223
 
1224
            // return true if there was no movement so rest of screen can scroll
1225
            return dX == horizontalDragPosition && dY == verticalDragPosition && dXb == horizontalDragPositionbottom;
1226
          }
1227
          ).bind(
1228
          'touchend.jsp',
1229
          function(e)
1230
          {
1231
            moving = false;
1232
          }
1233
          ).bind(
1234
          'click.jsp-touchclick',
1235
          function(e)
1236
          {
1237
            if(moved) {
1238
              moved = false;
1239
              return false;
1240
            }
1241
          }
1242
          );
1243
      }
1244
 
1245
      function destroy(){
1246
        var currentY = contentPositionY(),
1247
        currentX = contentPositionX();
1248
        elem.removeClass('jspScrollable').unbind('.jsp');
1249
        elem.replaceWith(originalElement.append(pane.children()));
1250
        originalElement.scrollTop(currentY);
1251
        originalElement.scrollLeft(currentX);
1252
      }
1253
 
1254
      // Public API
1255
      $.extend(
1256
        jsp,
1257
        {
1258
          // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
1259
          // was initialised). The settings object which is passed in will override any settings from the
1260
          // previous time it was initialised - if you don't pass any settings then the ones from the previous
1261
          // initialisation will be used.
1262
          reinitialise: function(s)
1263
          {
1264
            s = $.extend({}, settings, s);
1265
            initialise(s);
1266
          },
1267
          // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
1268
          // that it can be seen within the viewport. If stickToTop is true then the element will appear at
1269
          // the top of the viewport, if it is false then the viewport will scroll as little as possible to
1270
          // show the element. You can also specify if you want animation to occur. If you don't provide this
1271
          // argument then the animateScroll value from the settings object is used instead.
1272
          scrollToElement: function(ele, stickToTop, animate)
1273
          {
1274
            scrollToElement(ele, stickToTop, animate);
1275
          },
1276
          // Scrolls the pane so that the specified co-ordinates within the content are at the top left
1277
          // of the viewport. animate is optional and if not passed then the value of animateScroll from
1278
          // the settings object this jScrollPane was initialised with is used.
1279
          scrollTo: function(destX, destY, animate)
1280
          {
1281
            scrollToX(destX, animate);
1282
            scrollToY(destY, animate);
1283
          },
1284
          // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
1285
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
1286
          // object this jScrollPane was initialised with is used.
1287
          scrollToX: function(destX, animate)
1288
          {
1289
            scrollToX(destX, animate);
1290
          },
1291
          // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
1292
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
1293
          // object this jScrollPane was initialised with is used.
1294
          scrollToY: function(destY, animate)
1295
          {
1296
            scrollToY(destY, animate);
1297
          },
1298
          // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
1299
          // is optional and if not passed then the value of animateScroll from the settings object this
1300
          // jScrollPane was initialised with is used.
1301
          scrollToPercentX: function(destPercentX, animate)
1302
          {
1303
            scrollToX(destPercentX * (contentWidth - paneWidth), animate);
1304
          },
1305
          // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
1306
          // is optional and if not passed then the value of animateScroll from the settings object this
1307
          // jScrollPane was initialised with is used.
1308
          scrollToPercentY: function(destPercentY, animate)
1309
          {
1310
            scrollToY(destPercentY * (contentHeight - paneHeight), animate);
1311
          },
1312
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1313
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1314
          scrollBy: function(deltaX, deltaY, animate)
1315
          {
1316
            jsp.scrollByX(deltaX, animate);
1317
            jsp.scrollByY(deltaY, animate);
1318
          },
1319
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1320
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1321
          scrollByX: function(deltaX, animate)
1322
          {
1323
            var destX = contentPositionX() + deltaX,
1324
            percentScrolled = destX / (contentWidth - paneWidth);
1325
            positionDragX(percentScrolled * dragMaxX, animate);
1326
          },
1327
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1328
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1329
          scrollByY: function(deltaY, animate)
1330
          {
1331
            var destY = contentPositionY() + deltaY,
1332
            percentScrolled = destY / (contentHeight - paneHeight);
1333
            positionDragY(percentScrolled * dragMaxY, animate);
1334
          },
1335
          // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
1336
          // this). animate is optional and if not passed then the value of animateScroll from the settings
1337
          // object this jScrollPane was initialised with is used.
1338
          positionDragX: function(x, animate)
1339
          {
1340
            positionDragX(x, animate);
1341
          },
1342
          // Positions the vertical drag at the specified y position (and updates the viewport to reflect
1343
          // this). animate is optional and if not passed then the value of animateScroll from the settings
1344
          // object this jScrollPane was initialised with is used.
1345
          positionDragY: function(y, animate)
1346
          {
1347
            positionDragX(y, animate);
1348
          },
1349
          // This method is called when jScrollPane is trying to animate to a new position. You can override
1350
          // it if you want to provide advanced animation functionality. It is passed the following arguments:
1351
          //  * ele          - the element whose position is being animated
1352
          //  * prop         - the property that is being animated
1353
          //  * value        - the value it's being animated to
1354
          //  * stepCallback - a function that you must execute each time you update the value of the property
1355
          // You can use the default implementation (below) as a starting point for your own implementation.
1356
          animate: function(ele, prop, value, stepCallback)
1357
          {
1358
            var params = {};
1359
            params[prop] = value;
1360
            ele.animate(
1361
              params,
1362
              {
1363
                'duration'	: settings.animateDuration,
1364
                'ease'		: settings.animateEase,
1365
                'queue'		: false,
1366
                'step'		: stepCallback
1367
              }
1368
              );
1369
          },
1370
          // Returns the current x position of the viewport with regards to the content pane.
1371
          getContentPositionX: function()
1372
          {
1373
            return contentPositionX();
1374
          },
1375
          // Returns the current y position of the viewport with regards to the content pane.
1376
          getContentPositionY: function()
1377
          {
1378
            return contentPositionY();
1379
          },
1380
          // Returns the width of the content within the scroll pane.
1381
          getContentWidth: function()
1382
          {
1383
            return contentWidth();
1384
          },
1385
          // Returns the height of the content within the scroll pane.
1386
          getContentHeight: function()
1387
          {
1388
            return contentHeight();
1389
          },
1390
          // Returns the horizontal position of the viewport within the pane content.
1391
          getPercentScrolledX: function()
1392
          {
1393
            return contentPositionX() / (contentWidth - paneWidth);
1394
          },
1395
          // Returns the vertical position of the viewport within the pane content.
1396
          getPercentScrolledY: function()
1397
          {
1398
            return contentPositionY() / (contentHeight - paneHeight);
1399
          },
1400
          // Returns whether or not this scrollpane has a horizontal scrollbar.
1401
          getIsScrollableH: function()
1402
          {
1403
            return isScrollableH;
1404
          },
1405
          // Returns whether or not this scrollpane has a vertical scrollbar.
1406
          getIsScrollableV: function()
1407
          {
1408
            return isScrollableV;
1409
          },
1410
          // Gets a reference to the content pane. It is important that you use this method if you want to
1411
          // edit the content of your jScrollPane as if you access the element directly then you may have some
1412
          // problems (as your original element has had additional elements for the scrollbars etc added into
1413
          // it).
1414
          getContentPane: function()
1415
          {
1416
            return pane;
1417
          },
1418
          // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
1419
          // animateScroll value from settings is used instead.
1420
          scrollToBottom: function(animate)
1421
          {
1422
            positionDragY(dragMaxY, animate);
1423
          },
1424
          // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
1425
          // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
1426
          // contents of your scroll pane will work then call this function.
1427
          hijackInternalLinks: function()
1428
          {
1429
            hijackInternalLinks();
1430
          },
1431
          // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
1432
          // initialised.
1433
          destroy: function()
1434
          {
1435
            destroy();
1436
          }
1437
        }
1438
        );
1439
 
1440
      initialise(s);
1441
    }
1442
 
1443
    // Pluginifying code...
1444
    settings = $.extend({}, $.fn.jScrollPane.defaults, settings);
1445
 
1446
    // Apply default speed
1447
    $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() {
1448
      settings[this] = settings[this] || settings.speed;
1449
    });
1450
 
1451
    var ret;
1452
    this.each(
1453
      function()
1454
      {
1455
        var elem = $(this), jspApi = elem.data('jsp');
1456
        if (jspApi) {
1457
          jspApi.reinitialise(settings);
1458
        } else {
1459
          jspApi = new JScrollPane(elem, settings);
1460
          elem.data('jsp', jspApi);
1461
        }
1462
        ret = ret ? ret.add(elem) : elem;
1463
      }
1464
      );
1465
    return ret;
1466
  };
1467
 
1468
  $.fn.jScrollPane.defaults = {
1469
    showArrows			: false,
1470
    maintainPosition		: true,
1471
    clickOnTrack		: true,
1472
    autoReinitialise		: false,
1473
    autoReinitialiseDelay	: 500,
1474
    verticalDragMinHeight	: 0,
1475
    verticalDragMaxHeight	: 99999,
1476
    horizontalDragMinWidth	: 0,
1477
    horizontalDragMaxWidth	: 99999,
1478
    animateScroll		: false,
1479
    animateDuration		: 300,
1480
    animateEase			: 'linear',
1481
    hijackInternalLinks		: false,
1482
    verticalGutter		: 4,
1483
    horizontalGutter		: 4,
1484
    mouseWheelSpeed		: 0,
1485
    arrowButtonSpeed		: 0,
1486
    arrowRepeatFreq		: 50,
1487
    arrowScrollOnHover		: false,
1488
    trackClickSpeed		: 0,
1489
    trackClickRepeatFreq	: 70,
1490
    verticalArrowPositions	: 'split',
1491
    horizontalArrowPositions	: 'split',
1492
    enableKeyboardNavigation	: true,
1493
    hideFocus			: false,
1494
    keyboardSpeed		: 0,
1495
    initialDelay                : 300,        // Delay before starting repeating
1496
    speed			: 30,		// Default speed when others falsey
1497
    scrollPagePercent		: .8		// Percent of visible area scrolled when pageUp/Down or track area pressed
1498
  };
1499
 
1500
})(jQuery,this);
1501