Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / new_ui / ui / javascripts / jquery.jscrollpane.js @ 0d264436

History | View | Annotate | Download (45.7 kB)

1
/*!
2
 * jScrollPane - v2.0.17 - 2013-08-17
3
 * http://jscrollpane.kelvinluck.com/
4
 *
5
 * Copyright (c) 2013 Kelvin Luck
6
 * Dual licensed under the MIT or GPL licenses.
7
 */
8

    
9
// Script: jScrollPane - cross browser customisable scrollbars
10
//
11
// *Version: 2.0.17, Last updated: 2013-08-17*
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) 2013 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.17 - (2013-08-17) Working correctly when box-sizing is set to border-box (thanks @pieht)
43
// 2.0.16 - (2013-07-30) Resetting left position when scroll is removed. Fixes #189
44
// 2.0.15 - (2013-07-29) Fixed issue with scrollToElement where the destX and destY are undefined.
45
// 2.0.14 - (2013-05-01) Updated to most recent mouse wheel plugin (see #106) and related changes for sensible scroll speed
46
// 2.0.13 - (2013-05-01) Switched to semver compatible version name
47
// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+
48
// 2.0.0beta11 - (2012-05-14)
49
// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes
50
// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX
51
// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support
52
// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas)
53
// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support
54
// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes
55
// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes
56
// 2.0.0beta3 - (2010-08-27) Horizontal mousewheel, mwheelIntent, keyboard support, bug fixes
57
// 2.0.0beta2 - (2010-08-21) Bug fixes
58
// 2.0.0beta1 - (2010-08-17) Rewrite to follow modern best practices and enable horizontal scrolling, initially hidden
59
//                                                         elements and dynamically sized elements.
60
// 1.x - (2006-12-31 - 2010-07-31) Initial version, hosted at googlecode, deprecated
61

    
62
(function($,window,undefined){
63

    
64
        $.fn.jScrollPane = function(settings)
65
        {
66
                // JScrollPane "class" - public methods are available through $('selector').data('jsp')
67
                function JScrollPane(elem, s)
68
                {
69
                        var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
70
                                percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
71
                                verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
72
                                verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
73
                                horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
74
                                reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
75
                                wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
76
                                originalElement = elem.clone(false, false).empty(),
77
                                mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';
78

    
79
                        if (elem.css('box-sizing') === 'border-box') {
80
                                originalPadding = 0;
81
                                originalPaddingTotalWidth = 0;
82
                        } else {
83
                                originalPadding = elem.css('paddingTop') + ' ' +
84
                                                                        elem.css('paddingRight') + ' ' +
85
                                                                        elem.css('paddingBottom') + ' ' +
86
                                                                        elem.css('paddingLeft');        
87
                                originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
88
                                                                                        (parseInt(elem.css('paddingRight'), 10) || 0);
89
                        }
90

    
91
                        function initialise(s)
92
                        {
93

    
94
                                var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
95
                                                hasContainingSpaceChanged, originalScrollTop, originalScrollLeft,
96
                                                maintainAtBottom = false, maintainAtRight = false;
97

    
98
                                settings = s;
99

    
100
                                if (pane === undefined) {
101
                                        originalScrollTop = elem.scrollTop();
102
                                        originalScrollLeft = elem.scrollLeft();
103

    
104
                                        elem.css(
105
                                                {
106
                                                        overflow: 'hidden',
107
                                                        padding: 0
108
                                                }
109
                                        );
110
                                        // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
111
                                        // come back to it later and check once it is unhidden...
112
                                        paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
113
                                        paneHeight = elem.innerHeight();
114

    
115
                                        elem.width(paneWidth);
116
                                        
117
                                        pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
118
                                        container = $('<div class="jspContainer" />')
119
                                                .css({
120
                                                        'width': paneWidth + 'px',
121
                                                        'height': paneHeight + 'px'
122
                                                }
123
                                        ).append(pane).appendTo(elem);
124

    
125
                                        /*
126
                                        // Move any margins from the first and last children up to the container so they can still
127
                                        // collapse with neighbouring elements as they would before jScrollPane 
128
                                        firstChild = pane.find(':first-child');
129
                                        lastChild = pane.find(':last-child');
130
                                        elem.css(
131
                                                {
132
                                                        'margin-top': firstChild.css('margin-top'),
133
                                                        'margin-bottom': lastChild.css('margin-bottom')
134
                                                }
135
                                        );
136
                                        firstChild.css('margin-top', 0);
137
                                        lastChild.css('margin-bottom', 0);
138
                                        */
139
                                } else {
140
                                        elem.css('width', '');
141

    
142
                                        maintainAtBottom = settings.stickToBottom && isCloseToBottom();
143
                                        maintainAtRight  = settings.stickToRight  && isCloseToRight();
144

    
145
                                        hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;
146

    
147
                                        if (hasContainingSpaceChanged) {
148
                                                paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
149
                                                paneHeight = elem.innerHeight();
150
                                                container.css({
151
                                                        width: paneWidth + 'px',
152
                                                        height: paneHeight + 'px'
153
                                                });
154
                                        }
155

    
156
                                        // If nothing changed since last check...
157
                                        if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
158
                                                elem.width(paneWidth);
159
                                                return;
160
                                        }
161
                                        previousContentWidth = contentWidth;
162
                                        
163
                                        pane.css('width', '');
164
                                        elem.width(paneWidth);
165

    
166
                                        container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
167
                                }
168

    
169
                                pane.css('overflow', 'auto');
170
                                if (s.contentWidth) {
171
                                        contentWidth = s.contentWidth;
172
                                } else {
173
                                        contentWidth = pane[0].scrollWidth;
174
                                }
175
                                contentHeight = pane[0].scrollHeight;
176
                                pane.css('overflow', '');
177

    
178
                                percentInViewH = contentWidth / paneWidth;
179
                                percentInViewV = contentHeight / paneHeight;
180
                                isScrollableV = percentInViewV > 1;
181

    
182
                                isScrollableH = percentInViewH > 1;
183

    
184
                                //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);
185

    
186
                                if (!(isScrollableH || isScrollableV)) {
187
                                        elem.removeClass('jspScrollable');
188
                                        pane.css({
189
            top: 0,
190
            left: 0,
191
                                                width: container.width() - originalPaddingTotalWidth
192
                                        });
193
                                        removeMousewheel();
194
                                        removeFocusHandler();
195
                                        removeKeyboardNav();
196
                                        removeClickOnTrack();
197
                                } else {
198
                                        elem.addClass('jspScrollable');
199

    
200
                                        isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
201
                                        if (isMaintainingPositon) {
202
                                                lastContentX = contentPositionX();
203
                                                lastContentY = contentPositionY();
204
                                        }
205

    
206
                                        initialiseVerticalScroll();
207
                                        initialiseHorizontalScroll();
208
                                        resizeScrollbars();
209

    
210
                                        if (isMaintainingPositon) {
211
                                                scrollToX(maintainAtRight  ? (contentWidth  - paneWidth ) : lastContentX, false);
212
                                                scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false);
213
                                        }
214

    
215
                                        initFocusHandler();
216
                                        initMousewheel();
217
                                        initTouch();
218
                                        
219
                                        if (settings.enableKeyboardNavigation) {
220
                                                initKeyboardNav();
221
                                        }
222
                                        if (settings.clickOnTrack) {
223
                                                initClickOnTrack();
224
                                        }
225
                                        
226
                                        observeHash();
227
                                        if (settings.hijackInternalLinks) {
228
                                                hijackInternalLinks();
229
                                        }
230
                                }
231

    
232
                                if (settings.autoReinitialise && !reinitialiseInterval) {
233
                                        reinitialiseInterval = setInterval(
234
                                                function()
235
                                                {
236
                                                        initialise(settings);
237
                                                },
238
                                                settings.autoReinitialiseDelay
239
                                        );
240
                                } else if (!settings.autoReinitialise && reinitialiseInterval) {
241
                                        clearInterval(reinitialiseInterval);
242
                                }
243

    
244
                                originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
245
                                originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);
246

    
247
                                elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
248
                        }
249

    
250
                        function initialiseVerticalScroll()
251
                        {
252
                                if (isScrollableV) {
253

    
254
                                        container.append(
255
                                                $('<div class="jspVerticalBar" />').append(
256
                                                        $('<div class="jspCap jspCapTop" />'),
257
                                                        $('<div class="jspTrack" />').append(
258
                                                                $('<div class="jspDrag" />').append(
259
                                                                        $('<div class="jspDragTop" />'),
260
                                                                        $('<div class="jspDragBottom" />')
261
                                                                )
262
                                                        ),
263
                                                        $('<div class="jspCap jspCapBottom" />')
264
                                                )
265
                                        );
266

    
267
                                        verticalBar = container.find('>.jspVerticalBar');
268
                                        verticalTrack = verticalBar.find('>.jspTrack');
269
                                        verticalDrag = verticalTrack.find('>.jspDrag');
270

    
271
                                        if (settings.showArrows) {
272
                                                arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
273
                                                        'mousedown.jsp', getArrowScroll(0, -1)
274
                                                ).bind('click.jsp', nil);
275
                                                arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
276
                                                        'mousedown.jsp', getArrowScroll(0, 1)
277
                                                ).bind('click.jsp', nil);
278
                                                if (settings.arrowScrollOnHover) {
279
                                                        arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
280
                                                        arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
281
                                                }
282

    
283
                                                appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
284
                                        }
285

    
286
                                        verticalTrackHeight = paneHeight;
287
                                        container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
288
                                                function()
289
                                                {
290
                                                        verticalTrackHeight -= $(this).outerHeight();
291
                                                }
292
                                        );
293

    
294

    
295
                                        verticalDrag.hover(
296
                                                function()
297
                                                {
298
                                                        verticalDrag.addClass('jspHover');
299
                                                },
300
                                                function()
301
                                                {
302
                                                        verticalDrag.removeClass('jspHover');
303
                                                }
304
                                        ).bind(
305
                                                'mousedown.jsp',
306
                                                function(e)
307
                                                {
308
                                                        // Stop IE from allowing text selection
309
                                                        $('html').bind('dragstart.jsp selectstart.jsp', nil);
310

    
311
                                                        verticalDrag.addClass('jspActive');
312

    
313
                                                        var startY = e.pageY - verticalDrag.position().top;
314

    
315
                                                        $('html').bind(
316
                                                                'mousemove.jsp',
317
                                                                function(e)
318
                                                                {
319
                                                                        positionDragY(e.pageY - startY, false);
320
                                                                }
321
                                                        ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
322
                                                        return false;
323
                                                }
324
                                        );
325
                                        sizeVerticalScrollbar();
326
                                }
327
                        }
328

    
329
                        function sizeVerticalScrollbar()
330
                        {
331
                                verticalTrack.height(verticalTrackHeight + 'px');
332
                                verticalDragPosition = 0;
333
                                scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();
334

    
335
                                // Make the pane thinner to allow for the vertical scrollbar
336
                                pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);
337

    
338
                                // Add margin to the left of the pane if scrollbars are on that side (to position
339
                                // the scrollbar on the left or right set it's left or right property in CSS)
340
                                try {
341
                                        if (verticalBar.position().left === 0) {
342
                                                pane.css('margin-left', scrollbarWidth + 'px');
343
                                        }
344
                                } catch (err) {
345
                                }
346
                        }
347

    
348
                        function initialiseHorizontalScroll()
349
                        {
350
                                if (isScrollableH) {
351

    
352
                                        container.append(
353
                                                $('<div class="jspHorizontalBar" />').append(
354
                                                        $('<div class="jspCap jspCapLeft" />'),
355
                                                        $('<div class="jspTrack" />').append(
356
                                                                $('<div class="jspDrag" />').append(
357
                                                                        $('<div class="jspDragLeft" />'),
358
                                                                        $('<div class="jspDragRight" />')
359
                                                                )
360
                                                        ),
361
                                                        $('<div class="jspCap jspCapRight" />')
362
                                                )
363
                                        );
364

    
365
                                        horizontalBar = container.find('>.jspHorizontalBar');
366
                                        horizontalTrack = horizontalBar.find('>.jspTrack');
367
                                        horizontalDrag = horizontalTrack.find('>.jspDrag');
368

    
369
                                        if (settings.showArrows) {
370
                                                arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
371
                                                        'mousedown.jsp', getArrowScroll(-1, 0)
372
                                                ).bind('click.jsp', nil);
373
                                                arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
374
                                                        'mousedown.jsp', getArrowScroll(1, 0)
375
                                                ).bind('click.jsp', nil);
376
                                                if (settings.arrowScrollOnHover) {
377
                                                        arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
378
                                                        arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
379
                                                }
380
                                                appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
381
                                        }
382

    
383
                                        horizontalDrag.hover(
384
                                                function()
385
                                                {
386
                                                        horizontalDrag.addClass('jspHover');
387
                                                },
388
                                                function()
389
                                                {
390
                                                        horizontalDrag.removeClass('jspHover');
391
                                                }
392
                                        ).bind(
393
                                                'mousedown.jsp',
394
                                                function(e)
395
                                                {
396
                                                        // Stop IE from allowing text selection
397
                                                        $('html').bind('dragstart.jsp selectstart.jsp', nil);
398

    
399
                                                        horizontalDrag.addClass('jspActive');
400

    
401
                                                        var startX = e.pageX - horizontalDrag.position().left;
402

    
403
                                                        $('html').bind(
404
                                                                'mousemove.jsp',
405
                                                                function(e)
406
                                                                {
407
                                                                        positionDragX(e.pageX - startX, false);
408
                                                                }
409
                                                        ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
410
                                                        return false;
411
                                                }
412
                                        );
413
                                        horizontalTrackWidth = container.innerWidth();
414
                                        sizeHorizontalScrollbar();
415
                                }
416
                        }
417

    
418
                        function sizeHorizontalScrollbar()
419
                        {
420
                                container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
421
                                        function()
422
                                        {
423
                                                horizontalTrackWidth -= $(this).outerWidth();
424
                                        }
425
                                );
426

    
427
                                horizontalTrack.width(horizontalTrackWidth + 'px');
428
                                horizontalDragPosition = 0;
429
                        }
430

    
431
                        function resizeScrollbars()
432
                        {
433
                                if (isScrollableH && isScrollableV) {
434
                                        var horizontalTrackHeight = horizontalTrack.outerHeight(),
435
                                                verticalTrackWidth = verticalTrack.outerWidth();
436
                                        verticalTrackHeight -= horizontalTrackHeight;
437
                                        $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
438
                                                function()
439
                                                {
440
                                                        horizontalTrackWidth += $(this).outerWidth();
441
                                                }
442
                                        );
443
                                        horizontalTrackWidth -= verticalTrackWidth;
444
                                        paneHeight -= verticalTrackWidth;
445
                                        paneWidth -= horizontalTrackHeight;
446
                                        horizontalTrack.parent().append(
447
                                                $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
448
                                        );
449
                                        sizeVerticalScrollbar();
450
                                        sizeHorizontalScrollbar();
451
                                }
452
                                // reflow content
453
                                if (isScrollableH) {
454
                                        pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
455
                                }
456
                                contentHeight = pane.outerHeight();
457
                                percentInViewV = contentHeight / paneHeight;
458

    
459
                                if (isScrollableH) {
460
                                        horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
461
                                        if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
462
                                                horizontalDragWidth = settings.horizontalDragMaxWidth;
463
                                        } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
464
                                                horizontalDragWidth = settings.horizontalDragMinWidth;
465
                                        }
466
                                        horizontalDrag.width(horizontalDragWidth + 'px');
467
                                        dragMaxX = horizontalTrackWidth - horizontalDragWidth;
468
                                        _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons
469
                                }
470
                                if (isScrollableV) {
471
                                        verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
472
                                        if (verticalDragHeight > settings.verticalDragMaxHeight) {
473
                                                verticalDragHeight = settings.verticalDragMaxHeight;
474
                                        } else if (verticalDragHeight < settings.verticalDragMinHeight) {
475
                                                verticalDragHeight = settings.verticalDragMinHeight;
476
                                        }
477
                                        verticalDrag.height(verticalDragHeight + 'px');
478
                                        dragMaxY = verticalTrackHeight - verticalDragHeight;
479
                                        _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
480
                                }
481
                        }
482

    
483
                        function appendArrows(ele, p, a1, a2)
484
                        {
485
                                var p1 = "before", p2 = "after", aTemp;
486
                                
487
                                // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
488
                                // at the top or the bottom of the bar?
489
                                if (p == "os") {
490
                                        p = /Mac/.test(navigator.platform) ? "after" : "split";
491
                                }
492
                                if (p == p1) {
493
                                        p2 = p;
494
                                } else if (p == p2) {
495
                                        p1 = p;
496
                                        aTemp = a1;
497
                                        a1 = a2;
498
                                        a2 = aTemp;
499
                                }
500

    
501
                                ele[p1](a1)[p2](a2);
502
                        }
503

    
504
                        function getArrowScroll(dirX, dirY, ele)
505
                        {
506
                                return function()
507
                                {
508
                                        arrowScroll(dirX, dirY, this, ele);
509
                                        this.blur();
510
                                        return false;
511
                                };
512
                        }
513

    
514
                        function arrowScroll(dirX, dirY, arrow, ele)
515
                        {
516
                                arrow = $(arrow).addClass('jspActive');
517

    
518
                                var eve,
519
                                        scrollTimeout,
520
                                        isFirst = true,
521
                                        doScroll = function()
522
                                        {
523
                                                if (dirX !== 0) {
524
                                                        jsp.scrollByX(dirX * settings.arrowButtonSpeed);
525
                                                }
526
                                                if (dirY !== 0) {
527
                                                        jsp.scrollByY(dirY * settings.arrowButtonSpeed);
528
                                                }
529
                                                scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
530
                                                isFirst = false;
531
                                        };
532

    
533
                                doScroll();
534

    
535
                                eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
536
                                ele = ele || $('html');
537
                                ele.bind(
538
                                        eve,
539
                                        function()
540
                                        {
541
                                                arrow.removeClass('jspActive');
542
                                                scrollTimeout && clearTimeout(scrollTimeout);
543
                                                scrollTimeout = null;
544
                                                ele.unbind(eve);
545
                                        }
546
                                );
547
                        }
548

    
549
                        function initClickOnTrack()
550
                        {
551
                                removeClickOnTrack();
552
                                if (isScrollableV) {
553
                                        verticalTrack.bind(
554
                                                'mousedown.jsp',
555
                                                function(e)
556
                                                {
557
                                                        if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
558
                                                                var clickedTrack = $(this),
559
                                                                        offset = clickedTrack.offset(),
560
                                                                        direction = e.pageY - offset.top - verticalDragPosition,
561
                                                                        scrollTimeout,
562
                                                                        isFirst = true,
563
                                                                        doScroll = function()
564
                                                                        {
565
                                                                                var offset = clickedTrack.offset(),
566
                                                                                        pos = e.pageY - offset.top - verticalDragHeight / 2,
567
                                                                                        contentDragY = paneHeight * settings.scrollPagePercent,
568
                                                                                        dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
569
                                                                                if (direction < 0) {
570
                                                                                        if (verticalDragPosition - dragY > pos) {
571
                                                                                                jsp.scrollByY(-contentDragY);
572
                                                                                        } else {
573
                                                                                                positionDragY(pos);
574
                                                                                        }
575
                                                                                } else if (direction > 0) {
576
                                                                                        if (verticalDragPosition + dragY < pos) {
577
                                                                                                jsp.scrollByY(contentDragY);
578
                                                                                        } else {
579
                                                                                                positionDragY(pos);
580
                                                                                        }
581
                                                                                } else {
582
                                                                                        cancelClick();
583
                                                                                        return;
584
                                                                                }
585
                                                                                scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
586
                                                                                isFirst = false;
587
                                                                        },
588
                                                                        cancelClick = function()
589
                                                                        {
590
                                                                                scrollTimeout && clearTimeout(scrollTimeout);
591
                                                                                scrollTimeout = null;
592
                                                                                $(document).unbind('mouseup.jsp', cancelClick);
593
                                                                        };
594
                                                                doScroll();
595
                                                                $(document).bind('mouseup.jsp', cancelClick);
596
                                                                return false;
597
                                                        }
598
                                                }
599
                                        );
600
                                }
601
                                
602
                                if (isScrollableH) {
603
                                        horizontalTrack.bind(
604
                                                'mousedown.jsp',
605
                                                function(e)
606
                                                {
607
                                                        if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
608
                                                                var clickedTrack = $(this),
609
                                                                        offset = clickedTrack.offset(),
610
                                                                        direction = e.pageX - offset.left - horizontalDragPosition,
611
                                                                        scrollTimeout,
612
                                                                        isFirst = true,
613
                                                                        doScroll = function()
614
                                                                        {
615
                                                                                var offset = clickedTrack.offset(),
616
                                                                                        pos = e.pageX - offset.left - horizontalDragWidth / 2,
617
                                                                                        contentDragX = paneWidth * settings.scrollPagePercent,
618
                                                                                        dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
619
                                                                                if (direction < 0) {
620
                                                                                        if (horizontalDragPosition - dragX > pos) {
621
                                                                                                jsp.scrollByX(-contentDragX);
622
                                                                                        } else {
623
                                                                                                positionDragX(pos);
624
                                                                                        }
625
                                                                                } else if (direction > 0) {
626
                                                                                        if (horizontalDragPosition + dragX < pos) {
627
                                                                                                jsp.scrollByX(contentDragX);
628
                                                                                        } else {
629
                                                                                                positionDragX(pos);
630
                                                                                        }
631
                                                                                } else {
632
                                                                                        cancelClick();
633
                                                                                        return;
634
                                                                                }
635
                                                                                scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
636
                                                                                isFirst = false;
637
                                                                        },
638
                                                                        cancelClick = function()
639
                                                                        {
640
                                                                                scrollTimeout && clearTimeout(scrollTimeout);
641
                                                                                scrollTimeout = null;
642
                                                                                $(document).unbind('mouseup.jsp', cancelClick);
643
                                                                        };
644
                                                                doScroll();
645
                                                                $(document).bind('mouseup.jsp', cancelClick);
646
                                                                return false;
647
                                                        }
648
                                                }
649
                                        );
650
                                }
651
                        }
652

    
653
                        function removeClickOnTrack()
654
                        {
655
                                if (horizontalTrack) {
656
                                        horizontalTrack.unbind('mousedown.jsp');
657
                                }
658
                                if (verticalTrack) {
659
                                        verticalTrack.unbind('mousedown.jsp');
660
                                }
661
                        }
662

    
663
                        function cancelDrag()
664
                        {
665
                                $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');
666

    
667
                                if (verticalDrag) {
668
                                        verticalDrag.removeClass('jspActive');
669
                                }
670
                                if (horizontalDrag) {
671
                                        horizontalDrag.removeClass('jspActive');
672
                                }
673
                        }
674

    
675
                        function positionDragY(destY, animate)
676
                        {
677
                                if (!isScrollableV) {
678
                                        return;
679
                                }
680
                                if (destY < 0) {
681
                                        destY = 0;
682
                                } else if (destY > dragMaxY) {
683
                                        destY = dragMaxY;
684
                                }
685

    
686
                                // can't just check if(animate) because false is a valid value that could be passed in...
687
                                if (animate === undefined) {
688
                                        animate = settings.animateScroll;
689
                                }
690
                                if (animate) {
691
                                        jsp.animate(verticalDrag, 'top', destY,        _positionDragY);
692
                                } else {
693
                                        verticalDrag.css('top', destY);
694
                                        _positionDragY(destY);
695
                                }
696

    
697
                        }
698

    
699
                        function _positionDragY(destY)
700
                        {
701
                                if (destY === undefined) {
702
                                        destY = verticalDrag.position().top;
703
                                }
704

    
705
                                container.scrollTop(0);
706
                                verticalDragPosition = destY;
707

    
708
                                var isAtTop = verticalDragPosition === 0,
709
                                        isAtBottom = verticalDragPosition == dragMaxY,
710
                                        percentScrolled = destY/ dragMaxY,
711
                                        destTop = -percentScrolled * (contentHeight - paneHeight);
712

    
713
                                if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
714
                                        wasAtTop = isAtTop;
715
                                        wasAtBottom = isAtBottom;
716
                                        elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
717
                                }
718
                                
719
                                updateVerticalArrows(isAtTop, isAtBottom);
720
                                pane.css('top', destTop);
721
                                elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
722
                        }
723

    
724
                        function positionDragX(destX, animate)
725
                        {
726
                                if (!isScrollableH) {
727
                                        return;
728
                                }
729
                                if (destX < 0) {
730
                                        destX = 0;
731
                                } else if (destX > dragMaxX) {
732
                                        destX = dragMaxX;
733
                                }
734

    
735
                                if (animate === undefined) {
736
                                        animate = settings.animateScroll;
737
                                }
738
                                if (animate) {
739
                                        jsp.animate(horizontalDrag, 'left', destX,        _positionDragX);
740
                                } else {
741
                                        horizontalDrag.css('left', destX);
742
                                        _positionDragX(destX);
743
                                }
744
                        }
745

    
746
                        function _positionDragX(destX)
747
                        {
748
                                if (destX === undefined) {
749
                                        destX = horizontalDrag.position().left;
750
                                }
751

    
752
                                container.scrollTop(0);
753
                                horizontalDragPosition = destX;
754

    
755
                                var isAtLeft = horizontalDragPosition === 0,
756
                                        isAtRight = horizontalDragPosition == dragMaxX,
757
                                        percentScrolled = destX / dragMaxX,
758
                                        destLeft = -percentScrolled * (contentWidth - paneWidth);
759

    
760
                                if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
761
                                        wasAtLeft = isAtLeft;
762
                                        wasAtRight = isAtRight;
763
                                        elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
764
                                }
765
                                
766
                                updateHorizontalArrows(isAtLeft, isAtRight);
767
                                pane.css('left', destLeft);
768
                                elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
769
                        }
770

    
771
                        function updateVerticalArrows(isAtTop, isAtBottom)
772
                        {
773
                                if (settings.showArrows) {
774
                                        arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
775
                                        arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
776
                                }
777
                        }
778

    
779
                        function updateHorizontalArrows(isAtLeft, isAtRight)
780
                        {
781
                                if (settings.showArrows) {
782
                                        arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
783
                                        arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
784
                                }
785
                        }
786

    
787
                        function scrollToY(destY, animate)
788
                        {
789
                                var percentScrolled = destY / (contentHeight - paneHeight);
790
                                positionDragY(percentScrolled * dragMaxY, animate);
791
                        }
792

    
793
                        function scrollToX(destX, animate)
794
                        {
795
                                var percentScrolled = destX / (contentWidth - paneWidth);
796
                                positionDragX(percentScrolled * dragMaxX, animate);
797
                        }
798

    
799
                        function scrollToElement(ele, stickToTop, animate)
800
                        {
801
                                var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;
802

    
803
                                // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
804
                                // errors from the lookup...
805
                                try {
806
                                        e = $(ele);
807
                                } catch (err) {
808
                                        return;
809
                                }
810
                                eleHeight = e.outerHeight();
811
                                eleWidth= e.outerWidth();
812

    
813
                                container.scrollTop(0);
814
                                container.scrollLeft(0);
815
                                
816
                                // loop through parents adding the offset top of any elements that are relatively positioned between
817
                                // the focused element and the jspPane so we can get the true distance from the top
818
                                // of the focused element to the top of the scrollpane...
819
                                while (!e.is('.jspPane')) {
820
                                        eleTop += e.position().top;
821
                                        eleLeft += e.position().left;
822
                                        e = e.offsetParent();
823
                                        if (/^body|html$/i.test(e[0].nodeName)) {
824
                                                // we ended up too high in the document structure. Quit!
825
                                                return;
826
                                        }
827
                                }
828

    
829
                                viewportTop = contentPositionY();
830
                                maxVisibleEleTop = viewportTop + paneHeight;
831
                                if (eleTop < viewportTop || stickToTop) { // element is above viewport
832
                                        destY = eleTop - settings.verticalGutter;
833
                                } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
834
                                        destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
835
                                }
836
                                if (!isNaN(destY)) {
837
                                        scrollToY(destY, animate);
838
                                }
839
                                
840
                                viewportLeft = contentPositionX();
841
                    maxVisibleEleLeft = viewportLeft + paneWidth;
842
                    if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
843
                        destX = eleLeft - settings.horizontalGutter;
844
                    } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
845
                        destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
846
                    }
847
                    if (!isNaN(destX)) {
848
                        scrollToX(destX, animate);
849
                    }
850

    
851
                        }
852

    
853
                        function contentPositionX()
854
                        {
855
                                return -pane.position().left;
856
                        }
857

    
858
                        function contentPositionY()
859
                        {
860
                                return -pane.position().top;
861
                        }
862

    
863
                        function isCloseToBottom()
864
                        {
865
                                var scrollableHeight = contentHeight - paneHeight;
866
                                return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10);
867
                        }
868

    
869
                        function isCloseToRight()
870
                        {
871
                                var scrollableWidth = contentWidth - paneWidth;
872
                                return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10);
873
                        }
874

    
875
                        function initMousewheel()
876
                        {
877
                                container.unbind(mwEvent).bind(
878
                                        mwEvent,
879
                                        function (event, delta, deltaX, deltaY) {
880
                                                var dX = horizontalDragPosition, dY = verticalDragPosition;
881
                                                jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -deltaY * settings.mouseWheelSpeed, false);
882
                                                // return true if there was no movement so rest of screen can scroll
883
                                                return dX == horizontalDragPosition && dY == verticalDragPosition;
884
                                        }
885
                                );
886
                        }
887

    
888
                        function removeMousewheel()
889
                        {
890
                                container.unbind(mwEvent);
891
                        }
892

    
893
                        function nil()
894
                        {
895
                                return false;
896
                        }
897

    
898
                        function initFocusHandler()
899
                        {
900
                                pane.find(':input,a').unbind('focus.jsp').bind(
901
                                        'focus.jsp',
902
                                        function(e)
903
                                        {
904
                                                scrollToElement(e.target, false);
905
                                        }
906
                                );
907
                        }
908

    
909
                        function removeFocusHandler()
910
                        {
911
                                pane.find(':input,a').unbind('focus.jsp');
912
                        }
913
                        
914
                        function initKeyboardNav()
915
                        {
916
                                var keyDown, elementHasScrolled, validParents = [];
917
                                isScrollableH && validParents.push(horizontalBar[0]);
918
                                isScrollableV && validParents.push(verticalBar[0]);
919
                                
920
                                // IE also focuses elements that don't have tabindex set.
921
                                pane.focus(
922
                                        function()
923
                                        {
924
                                                elem.focus();
925
                                        }
926
                                );
927
                                
928
                                elem.attr('tabindex', 0)
929
                                        .unbind('keydown.jsp keypress.jsp')
930
                                        .bind(
931
                                                'keydown.jsp',
932
                                                function(e)
933
                                                {
934
                                                        if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){
935
                                                                return;
936
                                                        }
937
                                                        var dX = horizontalDragPosition, dY = verticalDragPosition;
938
                                                        switch(e.keyCode) {
939
                                                                case 40: // down
940
                                                                case 38: // up
941
                                                                case 34: // page down
942
                                                                case 32: // space
943
                                                                case 33: // page up
944
                                                                case 39: // right
945
                                                                case 37: // left
946
                                                                        keyDown = e.keyCode;
947
                                                                        keyDownHandler();
948
                                                                        break;
949
                                                                case 35: // end
950
                                                                        scrollToY(contentHeight - paneHeight);
951
                                                                        keyDown = null;
952
                                                                        break;
953
                                                                case 36: // home
954
                                                                        scrollToY(0);
955
                                                                        keyDown = null;
956
                                                                        break;
957
                                                        }
958

    
959
                                                        elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition;
960
                                                        return !elementHasScrolled;
961
                                                }
962
                                        ).bind(
963
                                                'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
964
                                                function(e)
965
                                                {
966
                                                        if (e.keyCode == keyDown) {
967
                                                                keyDownHandler();
968
                                                        }
969
                                                        return !elementHasScrolled;
970
                                                }
971
                                        );
972
                                
973
                                if (settings.hideFocus) {
974
                                        elem.css('outline', 'none');
975
                                        if ('hideFocus' in container[0]){
976
                                                elem.attr('hideFocus', true);
977
                                        }
978
                                } else {
979
                                        elem.css('outline', '');
980
                                        if ('hideFocus' in container[0]){
981
                                                elem.attr('hideFocus', false);
982
                                        }
983
                                }
984
                                
985
                                function keyDownHandler()
986
                                {
987
                                        var dX = horizontalDragPosition, dY = verticalDragPosition;
988
                                        switch(keyDown) {
989
                                                case 40: // down
990
                                                        jsp.scrollByY(settings.keyboardSpeed, false);
991
                                                        break;
992
                                                case 38: // up
993
                                                        jsp.scrollByY(-settings.keyboardSpeed, false);
994
                                                        break;
995
                                                case 34: // page down
996
                                                case 32: // space
997
                                                        jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
998
                                                        break;
999
                                                case 33: // page up
1000
                                                        jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
1001
                                                        break;
1002
                                                case 39: // right
1003
                                                        jsp.scrollByX(settings.keyboardSpeed, false);
1004
                                                        break;
1005
                                                case 37: // left
1006
                                                        jsp.scrollByX(-settings.keyboardSpeed, false);
1007
                                                        break;
1008
                                        }
1009

    
1010
                                        elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition;
1011
                                        return elementHasScrolled;
1012
                                }
1013
                        }
1014
                        
1015
                        function removeKeyboardNav()
1016
                        {
1017
                                elem.attr('tabindex', '-1')
1018
                                        .removeAttr('tabindex')
1019
                                        .unbind('keydown.jsp keypress.jsp');
1020
                        }
1021

    
1022
                        function observeHash()
1023
                        {
1024
                                if (location.hash && location.hash.length > 1) {
1025
                                        var e,
1026
                                                retryInt,
1027
                                                hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS
1028
                                                ;
1029
                                        try {
1030
                                                e = $('#' + hash + ', a[name="' + hash + '"]');
1031
                                        } catch (err) {
1032
                                                return;
1033
                                        }
1034

    
1035
                                        if (e.length && pane.find(hash)) {
1036
                                                // nasty workaround but it appears to take a little while before the hash has done its thing
1037
                                                // to the rendered page so we just wait until the container's scrollTop has been messed up.
1038
                                                if (container.scrollTop() === 0) {
1039
                                                        retryInt = setInterval(
1040
                                                                function()
1041
                                                                {
1042
                                                                        if (container.scrollTop() > 0) {
1043
                                                                                scrollToElement(e, true);
1044
                                                                                $(document).scrollTop(container.position().top);
1045
                                                                                clearInterval(retryInt);
1046
                                                                        }
1047
                                                                },
1048
                                                                50
1049
                                                        );
1050
                                                } else {
1051
                                                        scrollToElement(e, true);
1052
                                                        $(document).scrollTop(container.position().top);
1053
                                                }
1054
                                        }
1055
                                }
1056
                        }
1057

    
1058
                        function hijackInternalLinks()
1059
                        {
1060
                                // only register the link handler once
1061
                                if ($(document.body).data('jspHijack')) {
1062
                                        return;
1063
                                }
1064

    
1065
                                // remember that the handler was bound
1066
                                $(document.body).data('jspHijack', true);
1067

    
1068
                                // use live handler to also capture newly created links
1069
                                $(document.body).delegate('a[href*=#]', 'click', function(event) {
1070
                                        // does the link point to the same page?
1071
                                        // this also takes care of cases with a <base>-Tag or Links not starting with the hash #
1072
                                        // e.g. <a href="index.html#test"> when the current url already is index.html
1073
                                        var href = this.href.substr(0, this.href.indexOf('#')),
1074
                                                locationHref = location.href,
1075
                                                hash,
1076
                                                element,
1077
                                                container,
1078
                                                jsp,
1079
                                                scrollTop,
1080
                                                elementTop;
1081
                                        if (location.href.indexOf('#') !== -1) {
1082
                                                locationHref = location.href.substr(0, location.href.indexOf('#'));
1083
                                        }
1084
                                        if (href !== locationHref) {
1085
                                                // the link points to another page
1086
                                                return;
1087
                                        }
1088

    
1089
                                        // check if jScrollPane should handle this click event
1090
                                        hash = escape(this.href.substr(this.href.indexOf('#') + 1));
1091

    
1092
                                        // find the element on the page
1093
                                        element;
1094
                                        try {
1095
                                                element = $('#' + hash + ', a[name="' + hash + '"]');
1096
                                        } catch (e) {
1097
                                                // hash is not a valid jQuery identifier
1098
                                                return;
1099
                                        }
1100

    
1101
                                        if (!element.length) {
1102
                                                // this link does not point to an element on this page
1103
                                                return;
1104
                                        }
1105

    
1106
                                        container = element.closest('.jspScrollable');
1107
                                        jsp = container.data('jsp');
1108

    
1109
                                        // jsp might be another jsp instance than the one, that bound this event
1110
                                        // remember: this event is only bound once for all instances.
1111
                                        jsp.scrollToElement(element, true);
1112

    
1113
                                        if (container[0].scrollIntoView) {
1114
                                                // also scroll to the top of the container (if it is not visible)
1115
                                                scrollTop = $(window).scrollTop();
1116
                                                elementTop = element.offset().top;
1117
                                                if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) {
1118
                                                        container[0].scrollIntoView();
1119
                                                }
1120
                                        }
1121

    
1122
                                        // jsp handled this event, prevent the browser default (scrolling :P)
1123
                                        event.preventDefault();
1124
                                });
1125
                        }
1126
                        
1127
                        // Init touch on iPad, iPhone, iPod, Android
1128
                        function initTouch()
1129
                        {
1130
                                var startX,
1131
                                        startY,
1132
                                        touchStartX,
1133
                                        touchStartY,
1134
                                        moved,
1135
                                        moving = false;
1136
  
1137
                                container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind(
1138
                                        'touchstart.jsp',
1139
                                        function(e)
1140
                                        {
1141
                                                var touch = e.originalEvent.touches[0];
1142
                                                startX = contentPositionX();
1143
                                                startY = contentPositionY();
1144
                                                touchStartX = touch.pageX;
1145
                                                touchStartY = touch.pageY;
1146
                                                moved = false;
1147
                                                moving = true;
1148
                                        }
1149
                                ).bind(
1150
                                        'touchmove.jsp',
1151
                                        function(ev)
1152
                                        {
1153
                                                if(!moving) {
1154
                                                        return;
1155
                                                }
1156
                                                
1157
                                                var touchPos = ev.originalEvent.touches[0],
1158
                                                        dX = horizontalDragPosition, dY = verticalDragPosition;
1159
                                                
1160
                                                jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);
1161
                                                
1162
                                                moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;
1163
                                                
1164
                                                // return true if there was no movement so rest of screen can scroll
1165
                                                return dX == horizontalDragPosition && dY == verticalDragPosition;
1166
                                        }
1167
                                ).bind(
1168
                                        'touchend.jsp',
1169
                                        function(e)
1170
                                        {
1171
                                                moving = false;
1172
                                                /*if(moved) {
1173
                                                        return false;
1174
                                                }*/
1175
                                        }
1176
                                ).bind(
1177
                                        'click.jsp-touchclick',
1178
                                        function(e)
1179
                                        {
1180
                                                if(moved) {
1181
                                                        moved = false;
1182
                                                        return false;
1183
                                                }
1184
                                        }
1185
                                );
1186
                        }
1187
                        
1188
                        function destroy(){
1189
                                var currentY = contentPositionY(),
1190
                                        currentX = contentPositionX();
1191
                                elem.removeClass('jspScrollable').unbind('.jsp');
1192
                                elem.replaceWith(originalElement.append(pane.children()));
1193
                                originalElement.scrollTop(currentY);
1194
                                originalElement.scrollLeft(currentX);
1195

    
1196
                                // clear reinitialize timer if active
1197
                                if (reinitialiseInterval) {
1198
                                        clearInterval(reinitialiseInterval);
1199
                                }
1200
                        }
1201

    
1202
                        // Public API
1203
                        $.extend(
1204
                                jsp,
1205
                                {
1206
                                        // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
1207
                                        // was initialised). The settings object which is passed in will override any settings from the
1208
                                        // previous time it was initialised - if you don't pass any settings then the ones from the previous
1209
                                        // initialisation will be used.
1210
                                        reinitialise: function(s)
1211
                                        {
1212
                                                s = $.extend({}, settings, s);
1213
                                                initialise(s);
1214
                                        },
1215
                                        // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
1216
                                        // that it can be seen within the viewport. If stickToTop is true then the element will appear at
1217
                                        // the top of the viewport, if it is false then the viewport will scroll as little as possible to
1218
                                        // show the element. You can also specify if you want animation to occur. If you don't provide this
1219
                                        // argument then the animateScroll value from the settings object is used instead.
1220
                                        scrollToElement: function(ele, stickToTop, animate)
1221
                                        {
1222
                                                scrollToElement(ele, stickToTop, animate);
1223
                                        },
1224
                                        // Scrolls the pane so that the specified co-ordinates within the content are at the top left
1225
                                        // of the viewport. animate is optional and if not passed then the value of animateScroll from
1226
                                        // the settings object this jScrollPane was initialised with is used.
1227
                                        scrollTo: function(destX, destY, animate)
1228
                                        {
1229
                                                scrollToX(destX, animate);
1230
                                                scrollToY(destY, animate);
1231
                                        },
1232
                                        // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
1233
                                        // viewport. animate is optional and if not passed then the value of animateScroll from the settings
1234
                                        // object this jScrollPane was initialised with is used.
1235
                                        scrollToX: function(destX, animate)
1236
                                        {
1237
                                                scrollToX(destX, animate);
1238
                                        },
1239
                                        // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
1240
                                        // viewport. animate is optional and if not passed then the value of animateScroll from the settings
1241
                                        // object this jScrollPane was initialised with is used.
1242
                                        scrollToY: function(destY, animate)
1243
                                        {
1244
                                                scrollToY(destY, animate);
1245
                                        },
1246
                                        // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
1247
                                        // is optional and if not passed then the value of animateScroll from the settings object this
1248
                                        // jScrollPane was initialised with is used.
1249
                                        scrollToPercentX: function(destPercentX, animate)
1250
                                        {
1251
                                                scrollToX(destPercentX * (contentWidth - paneWidth), animate);
1252
                                        },
1253
                                        // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
1254
                                        // is optional and if not passed then the value of animateScroll from the settings object this
1255
                                        // jScrollPane was initialised with is used.
1256
                                        scrollToPercentY: function(destPercentY, animate)
1257
                                        {
1258
                                                scrollToY(destPercentY * (contentHeight - paneHeight), animate);
1259
                                        },
1260
                                        // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1261
                                        // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1262
                                        scrollBy: function(deltaX, deltaY, animate)
1263
                                        {
1264
                                                jsp.scrollByX(deltaX, animate);
1265
                                                jsp.scrollByY(deltaY, animate);
1266
                                        },
1267
                                        // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1268
                                        // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1269
                                        scrollByX: function(deltaX, animate)
1270
                                        {
1271
                                                var destX = contentPositionX() + Math[deltaX<0 ? 'floor' : 'ceil'](deltaX),
1272
                                                        percentScrolled = destX / (contentWidth - paneWidth);
1273
                                                positionDragX(percentScrolled * dragMaxX, animate);
1274
                                        },
1275
                                        // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
1276
                                        // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
1277
                                        scrollByY: function(deltaY, animate)
1278
                                        {
1279
                                                var destY = contentPositionY() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY),
1280
                                                        percentScrolled = destY / (contentHeight - paneHeight);
1281
                                                positionDragY(percentScrolled * dragMaxY, animate);
1282
                                        },
1283
                                        // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
1284
                                        // this). animate is optional and if not passed then the value of animateScroll from the settings
1285
                                        // object this jScrollPane was initialised with is used.
1286
                                        positionDragX: function(x, animate)
1287
                                        {
1288
                                                positionDragX(x, animate);
1289
                                        },
1290
                                        // Positions the vertical drag at the specified y position (and updates the viewport to reflect
1291
                                        // this). animate is optional and if not passed then the value of animateScroll from the settings
1292
                                        // object this jScrollPane was initialised with is used.
1293
                                        positionDragY: function(y, animate)
1294
                                        {
1295
                                                positionDragY(y, animate);
1296
                                        },
1297
                                        // This method is called when jScrollPane is trying to animate to a new position. You can override
1298
                                        // it if you want to provide advanced animation functionality. It is passed the following arguments:
1299
                                        //  * ele          - the element whose position is being animated
1300
                                        //  * prop         - the property that is being animated
1301
                                        //  * value        - the value it's being animated to
1302
                                        //  * stepCallback - a function that you must execute each time you update the value of the property
1303
                                        // You can use the default implementation (below) as a starting point for your own implementation.
1304
                                        animate: function(ele, prop, value, stepCallback)
1305
                                        {
1306
                                                var params = {};
1307
                                                params[prop] = value;
1308
                                                ele.animate(
1309
                                                        params,
1310
                                                        {
1311
                                                                'duration'        : settings.animateDuration,
1312
                                                                'easing'        : settings.animateEase,
1313
                                                                'queue'                : false,
1314
                                                                'step'                : stepCallback
1315
                                                        }
1316
                                                );
1317
                                        },
1318
                                        // Returns the current x position of the viewport with regards to the content pane.
1319
                                        getContentPositionX: function()
1320
                                        {
1321
                                                return contentPositionX();
1322
                                        },
1323
                                        // Returns the current y position of the viewport with regards to the content pane.
1324
                                        getContentPositionY: function()
1325
                                        {
1326
                                                return contentPositionY();
1327
                                        },
1328
                                        // Returns the width of the content within the scroll pane.
1329
                                        getContentWidth: function()
1330
                                        {
1331
                                                return contentWidth;
1332
                                        },
1333
                                        // Returns the height of the content within the scroll pane.
1334
                                        getContentHeight: function()
1335
                                        {
1336
                                                return contentHeight;
1337
                                        },
1338
                                        // Returns the horizontal position of the viewport within the pane content.
1339
                                        getPercentScrolledX: function()
1340
                                        {
1341
                                                return contentPositionX() / (contentWidth - paneWidth);
1342
                                        },
1343
                                        // Returns the vertical position of the viewport within the pane content.
1344
                                        getPercentScrolledY: function()
1345
                                        {
1346
                                                return contentPositionY() / (contentHeight - paneHeight);
1347
                                        },
1348
                                        // Returns whether or not this scrollpane has a horizontal scrollbar.
1349
                                        getIsScrollableH: function()
1350
                                        {
1351
                                                return isScrollableH;
1352
                                        },
1353
                                        // Returns whether or not this scrollpane has a vertical scrollbar.
1354
                                        getIsScrollableV: function()
1355
                                        {
1356
                                                return isScrollableV;
1357
                                        },
1358
                                        // Gets a reference to the content pane. It is important that you use this method if you want to
1359
                                        // edit the content of your jScrollPane as if you access the element directly then you may have some
1360
                                        // problems (as your original element has had additional elements for the scrollbars etc added into
1361
                                        // it).
1362
                                        getContentPane: function()
1363
                                        {
1364
                                                return pane;
1365
                                        },
1366
                                        // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
1367
                                        // animateScroll value from settings is used instead.
1368
                                        scrollToBottom: function(animate)
1369
                                        {
1370
                                                positionDragY(dragMaxY, animate);
1371
                                        },
1372
                                        // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
1373
                                        // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
1374
                                        // contents of your scroll pane will work then call this function.
1375
                                        hijackInternalLinks: $.noop,
1376
                                        // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
1377
                                        // initialised.
1378
                                        destroy: function()
1379
                                        {
1380
                                                        destroy();
1381
                                        }
1382
                                }
1383
                        );
1384
                        
1385
                        initialise(s);
1386
                }
1387

    
1388
                // Pluginifying code...
1389
                settings = $.extend({}, $.fn.jScrollPane.defaults, settings);
1390
                
1391
                // Apply default speed
1392
                $.each(['arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() {
1393
                        settings[this] = settings[this] || settings.speed;
1394
                });
1395

    
1396
                return this.each(
1397
                        function()
1398
                        {
1399
                                var elem = $(this), jspApi = elem.data('jsp');
1400
                                if (jspApi) {
1401
                                        jspApi.reinitialise(settings);
1402
                                } else {
1403
                                        $("script",elem).filter('[type="text/javascript"],:not([type])').remove();
1404
                                        jspApi = new JScrollPane(elem, settings);
1405
                                        elem.data('jsp', jspApi);
1406
                                }
1407
                        }
1408
                );
1409
        };
1410

    
1411
        $.fn.jScrollPane.defaults = {
1412
                showArrows                                        : false,
1413
                maintainPosition                        : true,
1414
                stickToBottom                                : false,
1415
                stickToRight                                : false,
1416
                clickOnTrack                                : true,
1417
                autoReinitialise                        : false,
1418
                autoReinitialiseDelay                : 500,
1419
                verticalDragMinHeight                : 0,
1420
                verticalDragMaxHeight                : 99999,
1421
                horizontalDragMinWidth                : 0,
1422
                horizontalDragMaxWidth                : 99999,
1423
                contentWidth                                : undefined,
1424
                animateScroll                                : false,
1425
                animateDuration                                : 300,
1426
                animateEase                                        : 'linear',
1427
                hijackInternalLinks                        : false,
1428
                verticalGutter                                : 4,
1429
                horizontalGutter                        : 4,
1430
                mouseWheelSpeed                                : 3,
1431
                arrowButtonSpeed                        : 0,
1432
                arrowRepeatFreq                                : 50,
1433
                arrowScrollOnHover                        : false,
1434
                trackClickSpeed                                : 0,
1435
                trackClickRepeatFreq                : 70,
1436
                verticalArrowPositions                : 'split',
1437
                horizontalArrowPositions        : 'split',
1438
                enableKeyboardNavigation        : true,
1439
                hideFocus                                        : false,
1440
                keyboardSpeed                                : 0,
1441
                initialDelay                : 300,        // Delay before starting repeating
1442
                speed                                                : 30,                // Default speed when others falsey
1443
                scrollPagePercent                        : .8                // Percent of visible area scrolled when pageUp/Down or track area pressed
1444
        };
1445

    
1446
})(jQuery,this);