mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-05-14 09:33:09 +00:00
The value attached to the event passed into handlers was based soley on screensize which is problematic given that some implementations (eg Android 2.3) don't change the screensize until after the event is fired. The orientation property appears to report a better value where it is provided so the solution is to prefer what it reports and then fallback to the screensize caculation where necessary.
319 lines
8.3 KiB
JavaScript
319 lines
8.3 KiB
JavaScript
/*
|
|
* jQuery Mobile Framework : events
|
|
* Copyright (c) jQuery Project
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
* http://jquery.org/license
|
|
*/
|
|
(function( $, window, undefined ) {
|
|
|
|
// add new event shortcuts
|
|
$.each( ( "touchstart touchmove touchend orientationchange throttledresize " +
|
|
"tap taphold swipe swipeleft swiperight scrollstart scrollstop" ).split( " " ), function( i, name ) {
|
|
|
|
$.fn[ name ] = function( fn ) {
|
|
return fn ? this.bind( name, fn ) : this.trigger( name );
|
|
};
|
|
|
|
$.attrFn[ name ] = true;
|
|
});
|
|
|
|
var supportTouch = $.support.touch,
|
|
scrollEvent = "touchmove scroll",
|
|
touchStartEvent = supportTouch ? "touchstart" : "mousedown",
|
|
touchStopEvent = supportTouch ? "touchend" : "mouseup",
|
|
touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
|
|
|
|
function triggerCustomEvent( obj, eventType, event ) {
|
|
var originalType = event.type;
|
|
event.type = eventType;
|
|
$.event.handle.call( obj, event );
|
|
event.type = originalType;
|
|
}
|
|
|
|
// also handles scrollstop
|
|
$.event.special.scrollstart = {
|
|
|
|
enabled: true,
|
|
|
|
setup: function() {
|
|
|
|
var thisObject = this,
|
|
$this = $( thisObject ),
|
|
scrolling,
|
|
timer;
|
|
|
|
function trigger( event, state ) {
|
|
scrolling = state;
|
|
triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
|
|
}
|
|
|
|
// iPhone triggers scroll after a small delay; use touchmove instead
|
|
$this.bind( scrollEvent, function( event ) {
|
|
|
|
if ( !$.event.special.scrollstart.enabled ) {
|
|
return;
|
|
}
|
|
|
|
if ( !scrolling ) {
|
|
trigger( event, true );
|
|
}
|
|
|
|
clearTimeout( timer );
|
|
timer = setTimeout(function() {
|
|
trigger( event, false );
|
|
}, 50 );
|
|
});
|
|
}
|
|
};
|
|
|
|
// also handles taphold
|
|
$.event.special.tap = {
|
|
setup: function() {
|
|
var thisObject = this,
|
|
$this = $( thisObject );
|
|
|
|
$this.bind( "vmousedown", function( event ) {
|
|
|
|
if ( event.which && event.which !== 1 ) {
|
|
return false;
|
|
}
|
|
|
|
var origTarget = event.target,
|
|
origEvent = event.originalEvent,
|
|
timer;
|
|
|
|
function clearTapTimer() {
|
|
clearTimeout( timer );
|
|
}
|
|
|
|
function clearTapHandlers() {
|
|
clearTapTimer();
|
|
|
|
$this.unbind( "vclick", clickHandler )
|
|
.unbind( "vmouseup", clearTapTimer )
|
|
.unbind( "vmousecancel", clearTapHandlers );
|
|
}
|
|
|
|
function clickHandler(event) {
|
|
clearTapHandlers();
|
|
|
|
// ONLY trigger a 'tap' event if the start target is
|
|
// the same as the stop target.
|
|
if ( origTarget == event.target ) {
|
|
triggerCustomEvent( thisObject, "tap", event );
|
|
}
|
|
}
|
|
|
|
$this.bind( "vmousecancel", clearTapHandlers )
|
|
.bind( "vmouseup", clearTapTimer )
|
|
.bind( "vclick", clickHandler );
|
|
|
|
timer = setTimeout(function() {
|
|
triggerCustomEvent( thisObject, "taphold", $.Event( "taphold" ) );
|
|
}, 750 );
|
|
});
|
|
}
|
|
};
|
|
|
|
// also handles swipeleft, swiperight
|
|
$.event.special.swipe = {
|
|
scrollSupressionThreshold: 10, // More than this horizontal displacement, and we will suppress scrolling.
|
|
|
|
durationThreshold: 1000, // More time than this, and it isn't a swipe.
|
|
|
|
horizontalDistanceThreshold: 30, // Swipe horizontal displacement must be more than this.
|
|
|
|
verticalDistanceThreshold: 75, // Swipe vertical displacement must be less than this.
|
|
|
|
setup: function() {
|
|
var thisObject = this,
|
|
$this = $( thisObject );
|
|
|
|
$this.bind( touchStartEvent, function( event ) {
|
|
var data = event.originalEvent.touches ?
|
|
event.originalEvent.touches[ 0 ] : event,
|
|
start = {
|
|
time: ( new Date() ).getTime(),
|
|
coords: [ data.pageX, data.pageY ],
|
|
origin: $( event.target )
|
|
},
|
|
stop;
|
|
|
|
function moveHandler( event ) {
|
|
|
|
if ( !start ) {
|
|
return;
|
|
}
|
|
|
|
var data = event.originalEvent.touches ?
|
|
event.originalEvent.touches[ 0 ] : event;
|
|
|
|
stop = {
|
|
time: ( new Date() ).getTime(),
|
|
coords: [ data.pageX, data.pageY ]
|
|
};
|
|
|
|
// prevent scrolling
|
|
if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
|
|
$this.bind( touchMoveEvent, moveHandler )
|
|
.one( touchStopEvent, function( event ) {
|
|
$this.unbind( touchMoveEvent, moveHandler );
|
|
|
|
if ( start && stop ) {
|
|
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 ) {
|
|
|
|
start.origin.trigger( "swipe" )
|
|
.trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
|
|
}
|
|
}
|
|
start = stop = undefined;
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
(function( $, window ) {
|
|
// "Cowboy" Ben Alman
|
|
|
|
var win = $( window ),
|
|
special_event,
|
|
get_orientation,
|
|
last_orientation;
|
|
|
|
$.event.special.orientationchange = special_event = {
|
|
setup: function() {
|
|
// If the event is supported natively, return false so that jQuery
|
|
// will bind to the event using DOM methods.
|
|
if ( $.support.orientation ) {
|
|
return false;
|
|
}
|
|
|
|
// Get the current orientation to avoid initial double-triggering.
|
|
last_orientation = get_orientation();
|
|
|
|
// Because the orientationchange event doesn't exist, simulate the
|
|
// event by testing window dimensions on resize.
|
|
win.bind( "throttledresize", handler );
|
|
},
|
|
teardown: function(){
|
|
// If the event is not supported natively, return false so that
|
|
// jQuery will unbind the event using DOM methods.
|
|
if ( $.support.orientation ) {
|
|
return false;
|
|
}
|
|
|
|
// Because the orientationchange event doesn't exist, unbind the
|
|
// resize event handler.
|
|
win.unbind( "throttledresize", handler );
|
|
},
|
|
add: function( handleObj ) {
|
|
// Save a reference to the bound event handler.
|
|
var old_handler = handleObj.handler;
|
|
|
|
handleObj.handler = function( event ) {
|
|
// Modify event object, adding the .orientation property.
|
|
event.orientation = get_orientation();
|
|
|
|
// Call the originally-bound event handler and return its result.
|
|
return old_handler.apply( this, arguments );
|
|
};
|
|
}
|
|
};
|
|
|
|
// If the event is not supported natively, this handler will be bound to
|
|
// the window resize event to simulate the orientationchange event.
|
|
function handler() {
|
|
// Get the current orientation.
|
|
var orientation = get_orientation();
|
|
|
|
if ( orientation !== last_orientation ) {
|
|
// The orientation has changed, so trigger the orientationchange event.
|
|
last_orientation = orientation;
|
|
win.trigger( "orientationchange" );
|
|
}
|
|
};
|
|
|
|
// Get the current page orientation. This method is exposed publicly, should it
|
|
// be needed, as jQuery.event.special.orientationchange.orientation()
|
|
$.event.special.orientationchange.orientation = get_orientation = function() {
|
|
var isPortrait = true, elem = document.documentElement;
|
|
|
|
// prefer window orientation to the calculation based on screensize as
|
|
// the actual screen resize takes place before or after the orientation change event
|
|
// has been fired depending on implementation (eg android 2.3 is before, iphone after).
|
|
// More testing is required to determine if a more reliable method of determining the new screensize
|
|
// is possible when orientationchange is fired. (eg, use media queries + element + opacity)
|
|
if ( $.support.orientation ) {
|
|
// if the window orientation registers as 0 or 180 degrees report
|
|
// portrait, otherwise landscape
|
|
isPortrait = window.orientation % 180 == 0;
|
|
} else {
|
|
isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
|
|
}
|
|
|
|
return isPortrait ? "portrait" : "landscape";
|
|
};
|
|
|
|
})( jQuery, window );
|
|
|
|
|
|
// throttled resize event
|
|
(function() {
|
|
|
|
$.event.special.throttledresize = {
|
|
setup: function() {
|
|
$( this ).bind( "resize", handler );
|
|
},
|
|
teardown: function(){
|
|
$( this ).unbind( "resize", handler );
|
|
}
|
|
};
|
|
|
|
var throttle = 250,
|
|
handler = function() {
|
|
curr = ( new Date() ).getTime();
|
|
diff = curr - lastCall;
|
|
|
|
if ( diff >= throttle ) {
|
|
|
|
lastCall = curr;
|
|
$( this ).trigger( "throttledresize" );
|
|
|
|
} else {
|
|
|
|
if ( heldCall ) {
|
|
clearTimeout( heldCall );
|
|
}
|
|
|
|
// Promise a held call will still execute
|
|
heldCall = setTimeout( handler, throttle - diff );
|
|
}
|
|
},
|
|
lastCall = 0,
|
|
heldCall,
|
|
curr,
|
|
diff;
|
|
})();
|
|
|
|
|
|
$.each({
|
|
scrollstop: "scrollstart",
|
|
taphold: "tap",
|
|
swipeleft: "swipe",
|
|
swiperight: "swipe"
|
|
}, function( event, sourceEvent ) {
|
|
|
|
$.event.special[ event ] = {
|
|
setup: function() {
|
|
$( this ).bind( sourceEvent, $.noop );
|
|
}
|
|
};
|
|
});
|
|
|
|
})( jQuery, this );
|