jscrollpane-rails 2.0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Yzk5MGVlMGQ4ZDQ3ODAwY2NlZjQwYTRhODFmYmVhZTkxNTcwYTcwNQ==
5
+ data.tar.gz: !binary |-
6
+ ZDQzMzMyMTI3M2JjMDU4NDRhZDBiNjg1NDFkMTVkNmViNDQwMmVlOA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ODViZjQ0MTUzZDNhMDQ4M2MzMmUxODJlMzdmYTJlOGVlODFkYmMwZjMxMTAz
10
+ NGU3MzRmMDk2Y2NhYzYzZTU2ZmQ2ZDVkOWVkMjg0NzE4ZTc2N2Q2YTNlMTg3
11
+ NDZjYWE2NTZkZjZjZThlZDliZjI1M2JhYzBkYThkZDZhOTlmNzE=
12
+ data.tar.gz: !binary |-
13
+ OGYyMjYxODc2MzE4NzJkNTFmYjNkNmEzMGIwZjc2MDYyNmI3MWIxODBhYmVk
14
+ ZjI4OTFlN2NlNjU1MDVkMTA3MmZmOTc4YTdkMGZjYjkzMTE0YjU1NWM0MTg0
15
+ NTIxMjJjYjdiM2QxZDZlMDEwZGM2M2Y0ZmFlNGJkYThlZmU0NmE=
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ilya Bodrov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # JScrollPane::Rails
2
+
3
+ A ruby gem that uses the Rails asset pipeline to include the jScrollPane plugin by Kelvin Luck
4
+ (www.kelvinluck.com):
5
+
6
+ * Homepage: http://jscrollpane.kelvinluck.com/
7
+ * Source Code: https://github.com/vitch/jScrollPane
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'jscrollpane-rails'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install jscrollpane-rails
22
+
23
+ NOTE: this is a jQuery plugin so you will also need the `jquery-rails` gem:
24
+
25
+ * https://github.com/rails/jquery-rails
26
+
27
+ ## Usage
28
+
29
+ In your `application.js` you will need to add this line:
30
+
31
+ //= require jscrollpane
32
+
33
+ And in your `application.css` you will need to add this line:
34
+
35
+ *= require jscrollpane
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "jscrollpane-rails/version"
2
+
3
+ module JScrollPane
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module JScrollPane
2
+ module Rails
3
+ VERSION = "2.0.17.1"
4
+ end
5
+ end
@@ -0,0 +1,1447 @@
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);
1447
+