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