@ -1,12 +1,12 @@
// Custom hacks:
// * Replaced .bind() calls with .on() for compatibility with jQuery 3
// * Replaced .unbind() calls with .off() for compatibility with jQuery 3
// Local hacks:
// * Replaced all .bind() calls with .on() to avoid jQuery Migrate warnings
// * Replaced all .unbind() calls with .off() to avoid jQuery Migrate warnings
/ *
* jQuery Mobile v1 . 4.5
* jQuery Mobile v1 . 5.0- alpha . 1
* http : //jquerymobile.com
*
* Copyright 2010 , 2014 jQuery Foundation , Inc . and other contributors
* Copyright jQuery Foundation , Inc . and other contributors
* Released under the MIT license .
* http : //jquery.org/license
*
@ -23,7 +23,21 @@
// Browser globals
factory ( root . jQuery , root , doc ) ;
}
} ( this , document , function ( jQuery , window , document , undefined ) { // This plugin is an experiment for abstracting away the touch and mouse
} ( this , document , function ( jQuery , window , document , undefined ) { / * !
* jQuery Mobile Virtual Mouse @ VERSION
* http : //jquerymobile.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license .
* http : //jquery.org/license
* /
//>>label: Virtual Mouse (vmouse) Bindings
//>>group: Core
//>>description: Normalizes touch/mouse events.
//>>docs: http://api.jquerymobile.com/?s=vmouse
// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
@ -38,14 +52,26 @@
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
( function ( $ , window , document , undefined ) {
( function ( factory ) {
if ( typeof define === "function" && define . amd ) {
// AMD. Register as an anonymous module.
define ( 'vmouse' , [ "jquery" ] , factory ) ;
} else {
// Browser globals
factory ( jQuery ) ;
}
} ) ( function ( $ ) {
var dataPropertyName = "virtualMouseBindings" ,
touchTargetPropertyName = "virtualTouchID" ,
virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" . split ( " " ) ,
touchEventProps = "clientX clientY pageX pageY screenX screenY" . split ( " " ) ,
virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" . split ( " " ) ,
generalProps = ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " +
"metaKey relatedTarget shiftKey target timeStamp view which" ) . split ( " " ) ,
mouseHookProps = $ . event . mouseHooks ? $ . event . mouseHooks . props : [ ] ,
mouseEventProps = $ . event . props . concat ( mouseHookProps ) ,
mouseEventProps = generalP rops. concat ( mouseHookProps ) ,
activeDocHandlers = { } ,
resetTimerID = 0 ,
startX = 0 ,
@ -63,7 +89,8 @@ var dataPropertyName = "virtualMouseBindings",
$ . vmouse = {
moveDistanceThreshold : 10 ,
clickDistanceThreshold : 10 ,
resetTimerDuration : 1500
resetTimerDuration : 1500 ,
maximumTimeBetweenTouches : 100
} ;
function getNativeEvent ( event ) {
@ -83,7 +110,7 @@ function createVirtualEvent( event, eventType ) {
event . type = eventType ;
oe = event . originalEvent ;
props = $. event . p rops;
props = generalP rops;
// addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
// https://github.com/jquery/jquery-mobile/issues/3280
@ -95,7 +122,7 @@ function createVirtualEvent( event, eventType ) {
// this would happen if we could call $.event.fix instead of $.Event
// but we don't have a way to force an event to be fixed multiple times
if ( oe ) {
for ( i = props . length , prop ; i ; ) {
for ( i = props . length ; i ; ) {
prop = props [ -- i ] ;
event [ prop ] = oe [ prop ] ;
}
@ -103,18 +130,18 @@ function createVirtualEvent( event, eventType ) {
// make sure that if the mouse and click virtual events are generated
// without a .which one is defined
if ( t . search ( /mouse(down|up)|click/ ) > - 1 && ! event . which ) {
if ( t . search ( /mouse(down|up)|click/ ) > - 1 && ! event . which ) {
event . which = 1 ;
}
if ( t . search ( /^touch/ ) !== - 1 ) {
if ( t . search ( /^touch/ ) !== - 1 ) {
ne = getNativeEvent ( oe ) ;
t = ne . touches ;
ct = ne . changedTouches ;
touch = ( t && t . length ) ? t [ 0 ] : ( ( ct && ct . length ) ? ct [ 0 ] : undefined ) ;
touch = ( t && t . length ) ? t [ 0 ] : ( ( ct && ct . length ) ? ct [ 0 ] : undefined ) ;
if ( touch ) {
for ( j = 0 , len = touchEventProps . length ; j < len ; j ++ ) {
for ( j = 0 , len = touchEventProps . length ; j < len ; j ++ ) {
prop = touchEventProps [ j ] ;
event [ prop ] = touch [ prop ] ;
}
@ -133,7 +160,7 @@ function getVirtualBindingFlags( element ) {
b = $ . data ( element , dataPropertyName ) ;
for ( k in b ) {
for ( k in b ) {
if ( b [ k ] ) {
flags [ k ] = flags . hasVirtualBinding = true ;
}
@ -181,6 +208,13 @@ function disableMouseBindings() {
enableTouchBindings ( ) ;
}
function clearResetTimer ( ) {
if ( resetTimerID ) {
clearTimeout ( resetTimerID ) ;
resetTimerID = 0 ;
}
}
function startResetTimer ( ) {
clearResetTimer ( ) ;
resetTimerID = setTimeout ( function ( ) {
@ -189,22 +223,15 @@ function startResetTimer() {
} , $ . vmouse . resetTimerDuration ) ;
}
function clearResetTimer ( ) {
if ( resetTimerID ) {
clearTimeout ( resetTimerID ) ;
resetTimerID = 0 ;
}
}
function triggerVirtualEvent ( eventType , event , flags ) {
var ve ;
if ( ( flags && flags [ eventType ] ) ||
( ! flags && getClosestElementWithVirtualBinding ( event . target , eventType ) ) ) {
( ! flags && getClosestElementWithVirtualBinding ( event . target , eventType ) ) ) {
ve = createVirtualEvent ( event , eventType ) ;
$ ( event . target ) . trigger ( ve ) ;
$ ( event . target ) . trigger ( ve ) ;
}
return ve ;
@ -214,6 +241,22 @@ function mouseEventCallback( event ) {
var touchID = $ . data ( event . target , touchTargetPropertyName ) ,
ve ;
// It is unexpected if a click event is received before a touchend
// or touchmove event, however this is a known behavior in Mobile
// Safari when Mobile VoiceOver (as of iOS 8) is enabled and the user
// double taps to activate a link element. In these cases if a touch
// event is not received within the maximum time between touches,
// re-enable mouse bindings and call the mouse event handler again.
if ( event . type === "click" && $ . data ( event . target , "lastTouchType" ) === "touchstart" ) {
setTimeout ( function ( ) {
if ( $ . data ( event . target , "lastTouchType" ) === "touchstart" ) {
enableMouseBindings ( ) ;
delete $ . data ( event . target ) . lastTouchType ;
mouseEventCallback ( event ) ;
}
} , $ . vmouse . maximumTimeBetweenTouches ) ;
}
if ( ! blockMouseTriggers && ( ! lastTouchID || lastTouchID !== touchID ) ) {
ve = triggerVirtualEvent ( "v" + event . type , event ) ;
if ( ve ) {
@ -240,6 +283,8 @@ function handleTouchStart( event ) {
target = event . target ;
flags = getVirtualBindingFlags ( target ) ;
$ . data ( event . target , "lastTouchType" , event . type ) ;
if ( flags . hasVirtualBinding ) {
lastTouchID = nextTouchID ++ ;
@ -269,6 +314,8 @@ function handleScroll( event ) {
triggerVirtualEvent ( "vmousecancel" , event , getVirtualBindingFlags ( event . target ) ) ;
}
$ . data ( event . target , "lastTouchType" , event . type ) ;
didScroll = true ;
startResetTimer ( ) ;
}
@ -283,9 +330,11 @@ function handleTouchMove( event ) {
moveThreshold = $ . vmouse . moveDistanceThreshold ,
flags = getVirtualBindingFlags ( event . target ) ;
didScroll = didScroll ||
( Math . abs ( t . pageX - startX ) > moveThreshold ||
Math . abs ( t . pageY - startY ) > moveThreshold ) ;
$ . data ( event . target , "lastTouchType" , event . type ) ;
didScroll = didScroll ||
( Math . abs ( t . pageX - startX ) > moveThreshold ||
Math . abs ( t . pageY - startY ) > moveThreshold ) ;
if ( didScroll && ! didCancel ) {
triggerVirtualEvent ( "vmousecancel" , event , flags ) ;
@ -296,11 +345,12 @@ function handleTouchMove( event ) {
}
function handleTouchEnd ( event ) {
if ( blockTouchTriggers ) {
if ( blockTouchTriggers || $ . data ( event . target , "lastTouchType" ) === undefined ) {
return ;
}
disableTouchBindings ( ) ;
delete $ . data ( event . target ) . lastTouchType ;
var flags = getVirtualBindingFlags ( event . target ) ,
ve , t ;
@ -314,18 +364,18 @@ function handleTouchEnd( event ) {
// touch. This means we need to rely on coordinates for blocking
// any click that is generated.
t = getNativeEvent ( event ) . changedTouches [ 0 ] ;
clickBlockList . push ( {
clickBlockList . push ( {
touchID : lastTouchID ,
x : t . clientX ,
y : t . clientY
} ) ;
} ) ;
// Prevent any mouse events that follow from triggering
// virtual event notifications.
blockMouseTriggers = true ;
}
}
triggerVirtualEvent ( "vmouseout" , event , flags ) ;
triggerVirtualEvent ( "vmouseout" , event , flags ) ;
didScroll = false ;
startResetTimer ( ) ;
@ -345,13 +395,14 @@ function hasVirtualBindings( ele ) {
return false ;
}
function dummyMouseHandler ( ) { }
function dummyMouseHandler ( ) {
}
function getSpecialEventObject ( eventType ) {
var realType = eventType . substr ( 1 ) ;
return {
setup : function ( /* data, namespace */ ) {
setup : function ( /* data, namespace */ ) {
// If this is the first virtual mouse binding for this element,
// add a bindings object to its data.
@ -384,7 +435,7 @@ function getSpecialEventObject( eventType ) {
// If this is the first virtual mouse binding for the document,
// register our touchstart handler on the document.
activeDocHandlers [ "touchstart" ] = ( activeDocHandlers [ "touchstart" ] || 0 ) + 1 ;
activeDocHandlers [ "touchstart" ] = ( activeDocHandlers [ "touchstart" ] || 0 ) + 1 ;
if ( activeDocHandlers [ "touchstart" ] === 1 ) {
$document . on ( "touchstart" , handleTouchStart )
@ -406,11 +457,11 @@ function getSpecialEventObject( eventType ) {
}
} ,
teardown : function ( /* data, namespace */ ) {
teardown : function ( /* data, namespace */ ) {
// If this is the last virtual binding for this eventType,
// remove its global handler from the document.
-- activeDocHandlers [ eventType ] ;
-- activeDocHandlers [ eventType ] ;
if ( ! activeDocHandlers [ eventType ] ) {
$document . off ( realType , mouseEventCallback ) ;
@ -420,7 +471,7 @@ function getSpecialEventObject( eventType ) {
// If this is the last virtual mouse binding in existence,
// remove our document touchstart listener.
-- activeDocHandlers [ "touchstart" ] ;
-- activeDocHandlers [ "touchstart" ] ;
if ( ! activeDocHandlers [ "touchstart" ] ) {
$document . off ( "touchstart" , handleTouchStart )
@ -511,7 +562,7 @@ if ( eventCaptureSupported ) {
touchID = 0 ;
if ( ( ele === target && Math . abs ( o . x - x ) < threshold && Math . abs ( o . y - y ) < threshold ) ||
$ . data ( ele , touchTargetPropertyName ) === o . touchID ) {
$ . data ( ele , touchTargetPropertyName ) === o . touchID ) {
// XXX: We may want to consider removing matches from the block list
// instead of waiting for the reset timer to fire.
e . preventDefault ( ) ;
@ -522,347 +573,391 @@ if ( eventCaptureSupported ) {
ele = ele . parentNode ;
}
}
} , true ) ;
} , true ) ;
}
} ) ( jQuery , window , document ) ;
} ) ;
/ * !
* jQuery Mobile Namespace @ VERSION
* http : //jquerymobile.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license .
* http : //jquery.org/license
* /
//>>label: Namespace
//>>group: Core
//>>description: The mobile namespace on the jQuery object
( function ( factory ) {
if ( typeof define === "function" && define . amd ) {
( function ( $ ) {
$ . mobile = { } ;
} ( jQuery ) ) ;
// AMD. Register as an anonymous module.
define ( 'ns' , [ "jquery" ] , factory ) ;
} else {
( function ( $ , undefined ) {
var support = {
touch : "ontouchend" in document
} ;
// Browser globals
factory ( jQuery ) ;
}
} ) ( function ( $ ) {
$ . mobile . support = $ . mobile . support || { } ;
$ . extend ( $ . support , support ) ;
$ . extend ( $ . mobile . support , support ) ;
} ( jQuery ) ) ;
$ . mobile = { version : "@VERSION" } ;
return $ . mobile ;
} ) ;
( function ( $ , window , undefined ) {
var $document = $ ( document ) ,
supportTouch = $ . mobile . support . touch ,
scrollEvent = "touchmove scroll" ,
touchStartEvent = supportTouch ? "touchstart" : "mousedown" ,
touchStopEvent = supportTouch ? "touchend" : "mouseup" ,
touchMoveEvent = supportTouch ? "touchmove" : "mousemove" ;
/ * !
* jQuery Mobile Touch Support Test @ VERSION
* http : //jquerymobile.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license .
* http : //jquery.org/license
* /
// setup new event shortcuts
$ . each ( ( "touchstart touchmove touchend " +
"tap taphold " +
"swipe swipeleft swiperight " +
"scrollstart scrollstop" ) . split ( " " ) , function ( i , name ) {
//>>label: Touch support test
//>>group: Core
//>>description: Touch feature test
$ . fn [ name ] = function ( fn ) {
return fn ? this . on ( name , fn ) : this . trigger ( name ) ;
} ;
( function ( factory ) {
if ( typeof define === "function" && define . amd ) {
// jQuery < 1.8
if ( $ . attrFn ) {
$ . attrFn [ name ] = true ;
}
} ) ;
function triggerCustomEvent ( obj , eventType , event , bubble ) {
var originalType = event . type ;
event . type = eventType ;
if ( bubble ) {
$ . event . trigger ( event , undefined , obj ) ;
} else {
$ . event . dispatch . call ( obj , event ) ;
}
event . type = originalType ;
// AMD. Register as an anonymous module.
define ( 'support/touch' , [
"jquery" ,
"../ns" ] , factory ) ;
} else {
// Browser globals
factory ( jQuery ) ;
}
} ) ( function ( $ ) {
// also handles scrollstop
$ . event . special . scrollstart = {
var support = {
touch : "ontouchend" in document
} ;
enabled : true ,
setup : function ( ) {
$ . mobile . support = $ . mobile . support || { } ;
$ . extend ( $ . support , support ) ;
$ . extend ( $ . mobile . support , support ) ;
var thisObject = this ,
$this = $ ( thisObject ) ,
scrolling ,
timer ;
return $ . support ;
} ) ;
function trigger ( event , state ) {
scrolling = state ;
triggerCustomEvent ( thisObject , scrolling ? "scrollstart" : "scrollstop" , event ) ;
}
/ * !
* jQuery Mobile Touch Events @ VERSION
* http : //jquerymobile.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license .
* http : //jquery.org/license
* /
// iPhone triggers scroll after a small delay; use touchmove instead
$this . on ( scrollEvent , function ( event ) {
//>>label: Touch
//>>group: Events
//>>description: Touch events including: touchstart, touchmove, touchend, tap, taphold, swipe, swipeleft, swiperight
if ( ! $ . event . special . scrollstart . enabled ) {
return ;
}
( function ( factory ) {
if ( typeof define === "function" && define . amd ) {
if ( ! scrolling ) {
trigger ( event , true ) ;
}
// AMD. Register as an anonymous module.
define ( 'events/touch' , [
"jquery" ,
"../vmouse" ,
"../support/touch" ] , factory ) ;
} else {
clearTimeout ( timer ) ;
timer = setTimeout ( function ( ) {
trigger ( event , false ) ;
} , 50 ) ;
} ) ;
} ,
teardown : function ( ) {
$ ( this ) . off ( scrollEvent ) ;
}
// Browser globals
factory ( jQuery ) ;
}
} ) ( function ( $ ) {
var $document = $ ( document ) ,
supportTouch = $ . mobile . support . touch ,
touchStartEvent = supportTouch ? "touchstart" : "mousedown" ,
touchStopEvent = supportTouch ? "touchend" : "mouseup" ,
touchMoveEvent = supportTouch ? "touchmove" : "mousemove" ;
// setup new event shortcuts
$ . each ( ( "touchstart touchmove touchend " +
"tap taphold " +
"swipe swipeleft swiperight" ) . split ( " " ) , function ( i , name ) {
$ . fn [ name ] = function ( fn ) {
return fn ? this . on ( name , fn ) : this . trigger ( name ) ;
} ;
// also handles taphold
$ . event . special . tap = {
tapholdThreshold : 750 ,
emitTapOnTaphold : true ,
setup : function ( ) {
var thisObject = this ,
$this = $ ( thisObject ) ,
isTaphold = false ;
$this . on ( "vmousedown" , function ( event ) {
isTaphold = false ;
if ( event . which && event . which !== 1 ) {
return false ;
}
// jQuery < 1.8
if ( $ . attrFn ) {
$ . attrFn [ name ] = true ;
}
} ) ;
function triggerCustomEvent ( obj , eventType , event , bubble ) {
var originalType = event . type ;
event . type = eventType ;
if ( bubble ) {
$ . event . trigger ( event , undefined , obj ) ;
} else {
$ . event . dispatch . call ( obj , event ) ;
}
event . type = originalType ;
}
var origTarget = event . target ,
timer ;
// also handles taphold
$ . event . special . tap = {
tapholdThreshold : 750 ,
emitTapOnTaphold : true ,
setup : function ( ) {
var thisObject = this ,
$this = $ ( thisObject ) ,
isTaphold = false ;
$this . on ( "vmousedown" , function ( event ) {
isTaphold = false ;
if ( event . which && event . which !== 1 ) {
return true ;
}
function clearTapTimer ( ) {
var origTarget = event . target ,
timer , clickHandler ;
function clearTapTimer ( ) {
if ( timer ) {
$this . on ( "vclick" , clickHandler ) ;
clearTimeout ( timer ) ;
}
}
function clearTapHandlers ( ) {
clearTapTimer ( ) ;
function clearTapHandlers ( ) {
clearTapTimer ( ) ;
$this . off ( "vclick" , clickHandler )
. off ( "vmouseup" , clearTapTimer ) ;
$document . off ( "vmousecancel" , clearTapHandlers ) ;
}
$this . off ( "vclick" , clickHandler )
. off ( "vmouseup" , clearTapTimer ) ;
$document . off ( "vmousecancel" , clearTapHandlers ) ;
}
function clickHandler ( event ) {
clearTapHandlers ( ) ;
clickHandler = function ( event ) {
clearTapHandlers ( ) ;
// ONLY trigger a 'tap' event if the start target is
// the same as the stop target.
if ( ! isTaphold && origTarget === event . target ) {
triggerCustomEvent ( thisObject , "tap" , event ) ;
} else if ( isTaphold ) {
event . preventDefault ( ) ;
}
// ONLY trigger a 'tap' event if the start target is
// the same as the stop target.
if ( ! isTaphold && origTarget === event . target ) {
triggerCustomEvent ( thisObject , "tap" , event ) ;
} else if ( isTaphold ) {
event . preventDefault ( ) ;
}
} ;
$this . on ( "vmouseup" , clearTapTimer )
. on ( "vclick" , clickHandler ) ;
$document . on ( "vmousecancel" , clearTapHandlers ) ;
$this . on ( "vmouseup" , clearTapTimer ) ;
timer = setTimeout ( function ( ) {
if ( ! $ . event . special . tap . emitTapOnTaphold ) {
isTaphold = true ;
}
triggerCustomEvent ( thisObject , "taphold" , $ . Event ( "taphold" , { target : origTarget } ) ) ;
} , $ . event . special . tap . tapholdThreshold ) ;
} ) ;
} ,
teardown : function ( ) {
$ ( this ) . off ( "vmousedown" ) . off ( "vclick" ) . off ( "vmouseup" ) ;
$document . off ( "vmousecancel" ) ;
}
} ;
$document . on ( "vmousecancel" , clearTapHandlers ) ;
// Also handles swipeleft, swiperight
$ . event . special . swipe = {
// More than this horizontal displacement, and we will suppress scrolling.
scrollSupressionThreshold : 30 ,
timer = setTimeout ( function ( ) {
if ( ! $ . event . special . tap . emitTapOnTaphold ) {
isTaphold = true ;
}
timer = 0 ;
triggerCustomEvent ( thisObject , "taphold" , $ . Event ( "taphold" , { target : origTarget } ) ) ;
} , $ . event . special . tap . tapholdThreshold ) ;
} ) ;
} ,
teardown : function ( ) {
$ ( this ) . off ( "vmousedown" ) . off ( "vclick" ) . off ( "vmouseup" ) ;
$document . off ( "vmousecancel" ) ;
}
} ;
// More time than this, and it isn't a swipe.
durationThreshold : 1000 ,
// Also handles swipeleft, swiperight
$ . event . special . swipe = {
// Swipe horizontal displacement must be more than this.
horizontalDistanceThreshold : 30 ,
// More than this horizontal displacement, and we will suppress scrolling .
scrollSupression Threshold: 30 ,
// Swipe vertical displacement must be less than this.
verticalDistanceThreshold : 30 ,
// More time than this, and it isn't a swipe .
durationThreshold : 100 0,
getLocation : function ( event ) {
var winPageX = window . pageXOffset ,
winPageY = window . pageYOffset ,
x = event . clientX ,
y = event . clientY ;
// Swipe horizontal displacement must be more than this.
horizontalDistanceThreshold : window . devicePixelRatio >= 2 ? 15 : 30 ,
if ( event . pageY === 0 && Math . floor ( y ) > Math . floor ( event . pageY ) ||
event . pageX === 0 && Math . floor ( x ) > Math . floor ( event . pageX ) ) {
// Swipe vertical displacement must be less than this.
verticalDistanceThreshold : window . devicePixelRatio >= 2 ? 15 : 30 ,
// iOS4 clientX/clientY have the value that should have been
// in pageX/pageY. While pageX/page/ have the value 0
x = x - winPageX ;
y = y - winPageY ;
} else if ( y < ( event . pageY - winPageY ) || x < ( event . pageX - winPageX ) ) {
// Some Android browsers have totally bogus values for clientX/Y
// when scrolling/zooming a page. Detectable since clientX/clientY
// should never be smaller than pageX/pageY minus page scroll
x = event . pageX - winPageX ;
y = event . pageY - winPageY ;
}
getLocation : function ( event ) {
var winPageX = window . pageXOffset ,
winPageY = window . pageYOffset ,
x = event . clientX ,
y = event . clientY ;
return {
x : x ,
y : y
} ;
} ,
if ( event . pageY === 0 && Math . floor ( y ) > Math . floor ( event . pageY ) ||
event . pageX === 0 && Math . floor ( x ) > Math . floor ( event . pageX ) ) {
start : function ( event ) {
var data = event . originalEvent . touches ?
event . originalEvent . touches [ 0 ] : event ,
location = $ . event . special . swipe . getLocation ( data ) ;
return {
time : ( new Date ( ) ) . getTime ( ) ,
coords : [ location . x , location . y ] ,
origin : $ ( event . target )
} ;
} ,
// iOS4 clientX/clientY have the value that should have been
// in pageX/pageY. While pageX/page/ have the value 0
x = x - winPageX ;
y = y - winPageY ;
} else if ( y < ( event . pageY - winPageY ) || x < ( event . pageX - winPageX ) ) {
// Some Android browsers have totally bogus values for clientX/Y
// when scrolling/zooming a page. Detectable since clientX/clientY
// should never be smaller than pageX/pageY minus page scroll
x = event . pageX - winPageX ;
y = event . pageY - winPageY ;
}
stop : function ( event ) {
var data = event . originalEvent . touches ?
event . originalEvent . touches [ 0 ] : event ,
location = $ . event . special . swipe . getLocation ( data ) ;
return {
time : ( new Date ( ) ) . getTime ( ) ,
coords : [ location . x , location . y ]
} ;
} ,
return {
x : x ,
y : y
} ;
} ,
start : function ( event ) {
var data = event . originalEvent . touches ?
event . originalEvent . touches [ 0 ] : event ,
location = $ . event . special . swipe . getLocation ( data ) ;
return {
time : ( new Date ( ) ) . getTime ( ) ,
coords : [ location . x , location . y ] ,
origin : $ ( event . target )
} ;
} ,
stop : function ( event ) {
var data = event . originalEvent . touches ?
event . originalEvent . touches [ 0 ] : event ,
location = $ . event . special . swipe . getLocation ( data ) ;
return {
time : ( new Date ( ) ) . getTime ( ) ,
coords : [ location . x , location . y ]
} ;
} ,
handleSwipe : function ( start , stop , thisObject , origTarget ) {
if ( stop . time - start . time < $ . event . special . swipe . durationThreshold &&
handleSwipe : function ( start , stop , thisObject , origTarget ) {
if ( stop . time - start . time < $ . event . special . swipe . durationThreshold &&
Math . abs ( start . coords [ 0 ] - stop . coords [ 0 ] ) > $ . event . special . swipe . horizontalDistanceThreshold &&
Math . abs ( start . coords [ 1 ] - stop . coords [ 1 ] ) < $ . event . special . swipe . verticalDistanceThreshold ) {
var direction = start . coords [ 0 ] > stop . coords [ 0 ] ? "swipeleft" : "swiperight" ;
var direction = start . coords [ 0 ] > stop . coords [ 0 ] ? "swipeleft" : "swiperight" ;
triggerCustomEvent ( thisObject , "swipe" , $ . Event ( "swipe" , { target : origTarget , swipestart : start , swipestop : stop } ) , true ) ;
triggerCustomEvent ( thisObject , direction , $ . Event ( direction , { target : origTarget , swipestart : start , swipestop : stop } ) , true ) ;
return true ;
}
return false ;
} ,
triggerCustomEvent ( thisObject , "swipe" , $ . Event ( "swipe" , { target : origTarget , swipestart : start , swipestop : stop } ) , true ) ;
triggerCustomEvent ( thisObject , direction , $ . Event ( direction , { target : origTarget , swipestart : start , swipestop : stop } ) , true ) ;
return true ;
}
return false ;
// This serves as a flag to ensure that at most one swipe event event is
// in work at any given time
eventInProgress : false ,
} ,
setup : function ( ) {
var events ,
thisObject = this ,
$this = $ ( thisObject ) ,
context = { } ;
// Retrieve the events data for this element and add the swipe context
events = $ . data ( this , "mobile-events" ) ;
if ( ! events ) {
events = { length : 0 } ;
$ . data ( this , "mobile-events" , events ) ;
}
events . length ++ ;
events . swipe = context ;
// This serves as a flag to ensure that at most one swipe event event is
// in work at any given time
eventInProgress : false ,
context . start = function ( event ) {
setup : function ( ) {
var events ,
thisObject = this ,
$this = $ ( thisObject ) ,
context = { } ;
// Bail if we're already working on a swipe event
if ( $ . event . special . swipe . eventInProgress ) {
return ;
}
$ . event . special . swipe . eventInProgress = true ;
// Retrieve the events data for this element and add the swipe context
events = $ . data ( this , "mobile-events" ) ;
if ( ! events ) {
events = { length : 0 } ;
$ . data ( this , "mobile-events" , events ) ;
}
events . length ++ ;
events . swipe = context ;
var stop ,
start = $ . event . special . swipe . start ( event ) ,
origTarget = event . target ,
emitted = false ;
context . start = function ( event ) {
context . move = function ( event ) {
if ( ! start || event . isDefaultPrevented ( ) ) {
return ;
}
// Bail if we're already working on a swipe event
if ( $ . event . special . swipe . eventInProgress ) {
return ;
}
$ . event . special . swipe . eventInProgress = true ;
stop = $ . event . special . swipe . stop ( event ) ;
if ( ! emitted ) {
emitted = $ . event . special . swipe . handleSwipe ( start , stop , thisObject , origTarget ) ;
if ( emitted ) {
var stop ,
start = $ . event . special . swipe . start ( event ) ,
origTarget = event . target ,
emitted = false ;
// Reset the context to make way for the next swipe event
$ . event . special . swipe . eventInProgress = false ;
}
}
// prevent scrolling
if ( Math . abs ( start . coords [ 0 ] - stop . coords [ 0 ] ) > $ . event . special . swipe . scrollSupressionThreshold ) {
event . preventDefault ( ) ;
}
} ;
context . move = function ( event ) {
if ( ! start || event . isDefaultPrevented ( ) ) {
return ;
}
context . stop = function ( ) {
emitted = true ;
stop = $ . event . special . swipe . stop ( event ) ;
if ( ! emitted ) {
emitted = $ . event . special . swipe . handleSwipe ( start , stop , thisObject , origTarget ) ;
if ( emitted ) {
// Reset the context to make way for the next swipe event
$ . event . special . swipe . eventInProgress = false ;
$document . off ( touchMoveEvent , context . move ) ;
context . move = null ;
} ;
}
}
// prevent scrolling
if ( Math . abs ( start . coords [ 0 ] - stop . coords [ 0 ] ) > $ . event . special . swipe . scrollSupressionThreshold ) {
event . preventDefault ( ) ;
}
} ;
$document . on ( touchMoveEvent , context . move )
. one ( touchStopEvent , context . stop ) ;
context . stop = function ( ) {
emitted = true ;
// Reset the context to make way for the next swipe event
$ . event . special . swipe . eventInProgress = false ;
$document . off ( touchMoveEvent , context . move ) ;
context . move = null ;
} ;
$this . on ( touchStartEvent , context . start ) ;
} ,
teardown : function ( ) {
var events , context ;
events = $ . data ( this , "mobile-events" ) ;
if ( events ) {
context = events . swipe ;
delete events . swipe ;
events . length -- ;
if ( events . length === 0 ) {
$ . removeData ( this , "mobile-events" ) ;
}
$document . on ( touchMoveEvent , context . move )
. one ( touchStopEvent , context . stop ) ;
} ;
$this . on ( touchStartEvent , context . start ) ;
} ,
teardown : function ( ) {
var events , context ;
events = $ . data ( this , "mobile-events" ) ;
if ( events ) {
context = events . swipe ;
delete events . swipe ;
events . length -- ;
if ( events . length === 0 ) {
$ . removeData ( this , "mobile-events" ) ;
}
}
if ( context ) {
if ( context . start ) {
$ ( this ) . off ( touchStartEvent , context . start ) ;
}
if ( context . move ) {
$document . off ( touchMoveEvent , context . move ) ;
}
if ( context . stop ) {
$document . off ( touchStopEvent , context . stop ) ;
}
if ( context ) {
if ( context . start ) {
$ ( this ) . off ( touchStartEvent , context . start ) ;
}
if ( context . move ) {
$document . off ( touchMoveEvent , context . move ) ;
}
if ( context . stop ) {
$document . off ( touchStopEvent , context . stop ) ;
}
}
}
} ;
$ . each ( {
taphold : "tap" ,
swipeleft : "swipe.left" ,
swiperight : "swipe.right"
} , function ( event , sourceEvent ) {
$ . event . special [ event ] = {
setup : function ( ) {
$ ( this ) . on ( sourceEvent , $ . noop ) ;
} ,
teardown : function ( ) {
$ ( this ) . off ( sourceEvent ) ;
}
} ;
$ . each ( {
scrollstop : "scrollstart" ,
taphold : "tap" ,
swipeleft : "swipe.left" ,
swiperight : "swipe.right"
} , function ( event , sourceEvent ) {
$ . event . special [ event ] = {
setup : function ( ) {
$ ( this ) . on ( sourceEvent , $ . noop ) ;
} ,
teardown : function ( ) {
$ ( this ) . off ( sourceEvent ) ;
}
} ;
} ) ;
} ) ;
return $ . event . special ;
} ) ;
} ) ( jQuery , this ) ;
} ) ) ;