jscrollpane-rails 2.0.23 → 2.1.1

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