mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-03-17 06:20:26 +00:00
the frequency of the triggered event in certain android releases ( 2.1, 2.2) appears to be dependent on a host of things other than an actual orientation change, eg alerts, zoom, and scrolling. This provides a way for the user to disable it in favor for using throttled resize while still making use of the window.orientation where its available for reliability
320 lines
8.4 KiB
JavaScript
320 lines
8.4 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 && $.mobile.orientationChangeEnabled ) {
|
|
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 && $.mobile.orientationChangeEnabled ) {
|
|
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 );
|