1 /*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
2 * Licensed under the MIT License (LICENSE.txt).
6 * Requires: jQuery 1.2.2+
10 if ( typeof define
=== 'function' && define
.amd
) {
11 // AMD. Register as an anonymous module.
12 define(['jquery'], factory
);
13 } else if (typeof exports
=== 'object') {
14 // Node/CommonJS style for Browserify
15 module
.exports
= factory
;
22 var toFix
= ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
23 toBind
= ( 'onwheel' in document
|| document
.documentMode
>= 9 ) ?
24 ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
25 slice
= Array
.prototype.slice
,
26 nullLowestDeltaTimeout
, lowestDelta
;
28 if ( $.event
.fixHooks
) {
29 for ( var i
= toFix
.length
; i
; ) {
30 $.event
.fixHooks
[ toFix
[--i
] ] = $.event
.mouseHooks
;
34 var special
= $.event
.special
.mousewheel
= {
38 if ( this.addEventListener
) {
39 for ( var i
= toBind
.length
; i
; ) {
40 this.addEventListener( toBind
[--i
], handler
, false );
43 this.onmousewheel
= handler
;
45 // Store the line height and page height for this particular element
46 $.data(this, 'mousewheel-line-height', special
.getLineHeight(this));
47 $.data(this, 'mousewheel-page-height', special
.getPageHeight(this));
50 teardown: function() {
51 if ( this.removeEventListener
) {
52 for ( var i
= toBind
.length
; i
; ) {
53 this.removeEventListener( toBind
[--i
], handler
, false );
56 this.onmousewheel
= null;
60 getLineHeight: function(elem
) {
61 var $parent
= $(elem
)['offsetParent' in $.fn
? 'offsetParent' : 'parent']();
62 if (!$parent
.length
) {
65 return parseInt($parent
.css('fontSize'), 10);
68 getPageHeight: function(elem
) {
69 return $(elem
).height();
78 mousewheel: function(fn
) {
79 return fn
? this.bind('mousewheel', fn
) : this.trigger('mousewheel');
82 unmousewheel: function(fn
) {
83 return this.unbind('mousewheel', fn
);
88 function handler(event
) {
89 var orgEvent
= event
|| window
.event
,
90 args
= slice
.call(arguments
, 1),
95 event
= $.event
.fix(orgEvent
);
96 event
.type
= 'mousewheel';
98 // Old school scrollwheel delta
99 if ( 'detail' in orgEvent
) { deltaY
= orgEvent
.detail
* -1; }
100 if ( 'wheelDelta' in orgEvent
) { deltaY
= orgEvent
.wheelDelta
; }
101 if ( 'wheelDeltaY' in orgEvent
) { deltaY
= orgEvent
.wheelDeltaY
; }
102 if ( 'wheelDeltaX' in orgEvent
) { deltaX
= orgEvent
.wheelDeltaX
* -1; }
104 // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
105 if ( 'axis' in orgEvent
&& orgEvent
.axis
=== orgEvent
.HORIZONTAL_AXIS
) {
106 deltaX
= deltaY
* -1;
110 // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
111 delta
= deltaY
=== 0 ? deltaX
: deltaY
;
113 // New school wheel delta (wheel event)
114 if ( 'deltaY' in orgEvent
) {
115 deltaY
= orgEvent
.deltaY
* -1;
118 if ( 'deltaX' in orgEvent
) {
119 deltaX
= orgEvent
.deltaX
;
120 if ( deltaY
=== 0 ) { delta
= deltaX
* -1; }
123 // No change actually happened, no reason to go any further
124 if ( deltaY
=== 0 && deltaX
=== 0 ) { return; }
126 // Need to convert lines and pages to pixels if we aren't already in pixels
127 // There are three delta modes:
128 // * deltaMode 0 is by pixels, nothing to do
129 // * deltaMode 1 is by lines
130 // * deltaMode 2 is by pages
131 if ( orgEvent
.deltaMode
=== 1 ) {
132 var lineHeight
= $.data(this, 'mousewheel-line-height');
134 deltaY
*= lineHeight
;
135 deltaX
*= lineHeight
;
136 } else if ( orgEvent
.deltaMode
=== 2 ) {
137 var pageHeight
= $.data(this, 'mousewheel-page-height');
139 deltaY
*= pageHeight
;
140 deltaX
*= pageHeight
;
143 // Store lowest absolute delta to normalize the delta values
144 absDelta
= Math
.max( Math
.abs(deltaY
), Math
.abs(deltaX
) );
146 if ( !lowestDelta
|| absDelta
< lowestDelta
) {
147 lowestDelta
= absDelta
;
149 // Adjust older deltas if necessary
150 if ( shouldAdjustOldDeltas(orgEvent
, absDelta
) ) {
155 // Adjust older deltas if necessary
156 if ( shouldAdjustOldDeltas(orgEvent
, absDelta
) ) {
157 // Divide all the things by 40!
163 // Get a whole, normalized value for the deltas
164 delta
= Math
[ delta
>= 1 ? 'floor' : 'ceil' ](delta
/ lowestDelta
);
165 deltaX
= Math
[ deltaX
>= 1 ? 'floor' : 'ceil' ](deltaX
/ lowestDelta
);
166 deltaY
= Math
[ deltaY
>= 1 ? 'floor' : 'ceil' ](deltaY
/ lowestDelta
);
168 // Add information to the event object
169 event
.deltaX
= deltaX
;
170 event
.deltaY
= deltaY
;
171 event
.deltaFactor
= lowestDelta
;
172 // Go ahead and set deltaMode to 0 since we converted to pixels
173 // Although this is a little odd since we overwrite the deltaX/Y
174 // properties with normalized deltas.
177 // Add event and delta to the front of the arguments
178 args
.unshift(event
, delta
, deltaX
, deltaY
);
180 // Clearout lowestDelta after sometime to better
181 // handle multiple device types that give different
182 // a different lowestDelta
183 // Ex: trackpad = 3 and mouse wheel = 120
184 if (nullLowestDeltaTimeout
) { clearTimeout(nullLowestDeltaTimeout
); }
185 nullLowestDeltaTimeout
= setTimeout(nullLowestDelta
, 200);
187 return ($.event
.dispatch
|| $.event
.handle
).apply(this, args
);
190 function nullLowestDelta() {
194 function shouldAdjustOldDeltas(orgEvent
, absDelta
) {
195 // If this is an older event and the delta is divisable by 120,
196 // then we are assuming that the browser is treating this as an
197 // older mouse wheel event and that we should divide the deltas
198 // by 40 to try and get a more usable deltaFactor.
199 // Side note, this actually impacts the reported scroll distance
200 // in older browsers and can cause scrolling to be slower than native.
201 // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
202 return special
.settings
.adjustOldDeltas
&& orgEvent
.type
=== 'mousewheel' && absDelta
% 120 === 0;