jquery-ui/ui/jquery.ui.interaction.js
2012-12-21 11:33:13 -05:00

306 lines
6.7 KiB
JavaScript

/*
* jQuery UI Interaction @VERSION
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Interaction
*
* Depends:
* jquery.ui.widget.js
*/
(function( $, undefined ) {
var interaction, touchHook, pointerHook;
$.widget( "ui.interaction", {
version: "@VERSION",
_create: function() {
// force the context so we can pass these methods to the hooks
this._interactionMove = $.proxy( this, "_interactionMove" );
this._interactionStop = $.proxy( this, "_interactionStop" );
// initialize all hooks for this widget
for ( var hook in interaction.hooks ) {
interaction.hooks[ hook ].setup( this, this._startProxy( hook ) );
}
},
/** abstract methods **/
// _start: function( event, pointerPosition )
// _move: function( event, pointerPosition )
// _stop: function( event, pointerPosition )
/** protected **/
_isValidTarget: function() {
return true;
},
/** internal **/
// a pass through to _interactionStart() which tracks the hook that was used
_startProxy: function( hook ) {
var that = this;
return function( event, target, pointerPosition ) {
return that._interactionStart( event, target, pointerPosition, hook );
};
},
_interactionStart: function( event, target, pointerPosition, hook ) {
var started;
// only one interaction can happen at a time
if ( interaction.started ) {
return false;
}
// check if the event occurred on a valid target
if ( false === this._isValidTarget( $( target ) ) ) {
return false;
}
// check if the widget wants the event to start an interaction
started = ( this._start( event, pointerPosition ) !== false );
if ( started ) {
interaction.started = true;
interaction.hooks[ hook ].handle( this,
this._interactionMove, this._interactionStop );
}
// let the hook know if the interaction was started
return started;
},
_interactionMove: function( event, pointerPosition ) {
this._move( event, pointerPosition );
},
_interactionStop: function( event, pointerPosition ) {
this._stop( event, pointerPosition );
interaction.started = false;
}
});
interaction = $.ui.interaction;
$.extend( interaction, {
started: false,
hooks: {}
});
interaction.hooks.mouse = {
setup: function( widget, start ) {
widget._on( widget.widget(), {
"mousedown": function( event ) {
// only react to the primary button
if ( event.which === 1 ) {
var started = start( event, event.target, {
x: event.pageX,
y: event.pageY
});
if ( started ) {
// prevent selection
event.preventDefault();
}
}
}
});
},
handle: function( widget, move, stop ) {
function mousemove( event ) {
event.preventDefault();
move( event, {
x: event.pageX,
y: event.pageY
});
}
function mouseup( event ) {
stop( event, {
x: event.pageX,
y: event.pageY
});
widget.document
.unbind( "mousemove", mousemove )
.unbind( "mouseup", mouseup );
}
widget._on( widget.document, {
"mousemove": mousemove,
"mouseup": mouseup
});
}
};
// WebKit doesn't support TouchList.identifiedTouch()
function getTouch( event ) {
var touches = event.originalEvent.changedTouches,
i = 0, length = touches.length;
for ( ; i < length; i++ ) {
if ( touches[ i ].identifier === touchHook.id ) {
return touches[ i ];
}
}
}
touchHook = interaction.hooks.touch = {
setup: function( widget, start ) {
widget._on( widget.widget(), {
"touchstart": function( event ) {
var touch, started;
if ( touchHook.id ) {
return;
}
touch = event.originalEvent.changedTouches.item( 0 );
started = start( event, touch.target, {
x: touch.pageX,
y: touch.pageY
});
if ( started ) {
// track which finger is performing the interaction
touchHook.id = touch.identifier;
// prevent panning/zooming
event.preventDefault();
}
}
});
},
handle: function( widget, move, stop ) {
function moveHandler( event ) {
// TODO: test non-Apple WebKits to see if they allow
// zooming/scrolling if we don't preventDefault()
var touch = getTouch( event );
if ( !touch ) {
return;
}
event.preventDefault();
move( event, {
x: touch.pageX,
y: touch.pageY
});
}
function stopHandler( event ) {
var touch = getTouch( event );
if ( !touch ) {
return;
}
stop( event, {
x: touch.pageX,
y: touch.pageY
});
touchHook.id = null;
widget.document
.unbind( "touchmove", moveHandler )
.unbind( "touchend", stopHandler );
}
widget._on( widget.document, {
"touchmove": moveHandler,
"touchend": stopHandler
});
}
};
pointerHook = interaction.hooks.msPointer = {
setup: function( widget, start ) {
widget._on( widget.widget(), {
"MSPointerDown": function( _event ) {
var started,
event = _event.originalEvent;
if ( pointerHook.id ) {
return;
}
// TODO: how can we detect a "right click" with a pen?
// TODO: get full details about which and button from MS
// touch and pen = 1
// primary mouse button = 2
if ( event.which > 2 ) {
return;
}
started = start( event, event.target, {
x: event.pageX,
y: event.pageY
});
if ( started ) {
// track which pointer is performing the interaction
pointerHook.id = event.pointerId;
// prevent panning/zooming
event.preventManipulation();
// prevent promoting pointer events to mouse events
event.preventMouseEvent();
}
}
});
},
handle: function( widget, move, stop ) {
function moveHandler( _event ) {
var event = _event.originalEvent,
pageX = event.pageX,
pageY = event.pageY;
// always prevent manipulation to avoid panning/zooming
event.preventManipulation();
if ( event.pointerId !== pointerHook.id ) {
return;
}
// MS streams events constantly, even if there is no movement
// so we optimize by ignoring repeat events
if ( pointerHook.x === pageX && pointerHook.y === pageY ) {
return;
}
pointerHook.x = pageX;
pointerHook.y = pageY;
move( event, {
x: pageX,
y: pageY
});
}
function stopHandler( _event ) {
var event = _event.originalEvent;
if ( event.pointerId !== pointerHook.id ) {
return;
}
stop( event, {
x: event.pageX,
y: event.pageY
});
pointerHook.id = pointerHook.x = pointerHook.y = undefined;
widget.document
.unbind( "MSPointerMove", moveHandler )
.unbind( "MSPointerUp", stopHandler )
.unbind( "MSPointerCancel", stopHandler );
}
widget._on( widget.document, {
"MSPointerMove": moveHandler,
"MSPointerUp": stopHandler,
"MSPointerCancel": stopHandler
});
}
};
})( jQuery );