-/* original:\r
- * Hammer.JS - v1.0.5 - 2013-04-07\r
- * http://eightmedia.github.com/hammer.js\r
- * Jorik Tangelder <j.tangelder@gmail.com>, MIT license\r
- **/\r
-\r
- \r
- var ELEENT_LIST = [],\r
- HAMMER_LIST = [],\r
- POINTERS = [],\r
- ABS = new Function( 'v', 'return v<0?-v:v' );\r
- \r
- function Hammer( uinodeRoot, uinode, type ){\r
- this.uinode = uinode;\r
- this.enabled = true;\r
- \r
- Hammer.startup && Hammer.startup( uinodeRoot );\r
-\r
- this.options = Hammer.defaults;\r
-\r
- // start detection on touchstart\r
- Utils.addEvents( uinode, Hammer.EVENT_TYPES_START, this );\r
- \r
- this[ 'listen' ]( type );\r
- };\r
- \r
- Hammer.defaults = {};\r
- \r
- Hammer.prototype.handleEvent = function( e ){\r
- //var sourceEventType = e.type.toLowerCase();\r
-\r
- var type = IdToGestureID[ e.type ],\r
- gestures = Detection.gestures,\r
- numTouches = 0,// count the total touches on the screen\r
- pointerType, i, l, touches, ret, active, gesture, startEv,\r
- hammer, deltaTime, deltaX, deltaY, velocity, center;\r
- \r
- //console.log( 'Hammer@handleEvent ' + XUI_Event.IdToName[ e.type ] + ' ' + e.pointerType + ' ' + type );\r
- if( !type ) return;\r
- \r
- //console.log( e.type + ' dw:' + XUI_Event._POINTER_DOWN + ' up:' + XUI_Event._POINTER_UP + ' mv:' + XUI_Event._POINTER_MOVE );\r
- \r
- if( e.pointerType ){\r
- type |= POINTER;\r
- switch( e.pointerType ){\r
- case 'touch' :\r
- type |= TOUCH; break;\r
- case 'pen' :\r
- type |= PEN; break;\r
- case 'mouse' :\r
- type |= MOUSE; break;\r
- default :\r
- return;\r
- };\r
- };\r
- \r
- // onmouseup, but when touchend has been fired we do nothing.\r
- // this is for touchdevices which also fire a mouseup on touchend\r
- if( type & MOUSE && touch_triggered ){\r
- return X_Callback_STOP_NOW | X_Callback_PREVENT_DEFAULT;\r
- } else\r
- // mousebutton must be down or a touch event\r
- if( type & TOUCH || //sourceEventType.match(/touch/) || // touch events are always on screen\r
- ( type & POINTER && type & START ) || //sourceEventType.match(/pointerdown/) || // pointerevents touch\r
- ( type & MOUSE && e.button === 0 ) //(sourceEventType.match(/mouse/) && e.which === 1) // mouse is pressed\r
- ){\r
- enable_detect = true;\r
- };\r
-\r
- //console.log( 'Hammer@handleEvent ' + IdToGestureID[ e.type ] + ' ' + e.type + ' ' + XUI_Event._POINTER_DOWN + ' ' + enable_detect );\r
-\r
- // we are in a touch event, set the touch triggered bool to true,\r
- // this for the conflicts that may occur on ios and android\r
- //type & ( TOUCH | POINTER ) && ( touch_triggered = true );\r
- type & TOUCH && ( touch_triggered = true );\r
- //if (sourceEventType.match(/touch|pointer/)) { touch_triggered = true;}\r
-\r
- // when touch has been triggered in this detection session\r
- // and we are now handling a mouse event, we stop that to prevent conflicts\r
- if( enable_detect ){\r
- // update pointerevent\r
-\r
- POINTERS[ e.pointerId ] = type & END ? null : e;\r
- touches = [];\r
- numTouches = -1;\r
- // we can use forEach since pointerEvents only is in IE10\r
- for( i in POINTERS ){\r
- POINTERS[ i ] && ( touches[ ++numTouches ] = POINTERS[ i ] );\r
- };\r
- ++numTouches;\r
- ///console.log( 'numTouches ' + numTouches );\r
-\r
- // if we are in a end event, but when we remove one touch and\r
- // we still have enough, set eventType to move\r
- if( 0 < numTouches && type & END ){ // eventType === Hammer.EVENT_END ){\r
- type = type & POINTER_TYPE_MASK | MOVE;\r
- //eventType = Hammer.EVENT_MOVE;\r
- } else if( !numTouches ){\r
- // no touches, force the end event\r
- type = type & POINTER_TYPE_MASK | END;\r
- //eventType = Hammer.EVENT_END;\r
- };\r
-\r
- // because touchend has no touches, and we often want to use these in our gestures,\r
- // we send the last move event as our eventData in touchend\r
- ( !numTouches && last_move_event !== null ) ?\r
- ( e = last_move_event ):\r
- ( last_move_event = e ); // store the last move event\r
-\r
- e = {\r
- center : Utils.getCenter( touches ),\r
- timeStamp : e.timeStamp,\r
- target : e.target,\r
- touches : touches,\r
- eventType : type & EVENT_TYPE_MASK,\r
- pointerType : type & POINTER_TYPE_MASK\r
- };\r
-\r
- if( type & START ){\r
- if( !this.enabled ) return;\r
- // already busy with a Hammer.gesture detection on an element\r
- if( Detection.current ) return;\r
- Detection.current = {\r
- hammer : this, // reference to HammerInstance we're working for\r
- startEvent : Utils.extend( {}, e ), // start eventData for distances, timing etc\r
- lastEvent : false, // last eventData\r
- name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc\r
- };\r
- Detection.stopped = false;\r
- hammer = this;\r
- active = hammer.activeGesture;\r
- } else\r
- if( !Detection.current || Detection.stopped ){\r
- return;\r
- } else {\r
- hammer = Detection.current.hammer;\r
- active = hammer.activeGesture;\r
- };\r
- \r
- // ----------------------------------------------------------------------------------------------------------------\r
- // ret = Detection.detect( e );\r
-\r
- // ----------------------------------------------------------------------------------------------------------------\r
- // extend event data with calculations about scale, distance etc\r
- // e = Detection.extendEventData( e );\r
- startEv = Detection.current.startEvent;\r
- center = e.center;\r
-\r
- // if the touches change, set the new touches over the startEvent touches\r
- // this because touchevents don't have all the touches on touchstart, or the\r
- // user must place his fingers at the EXACT same time on the screen, which is not realistic\r
- // but, sometimes it happens that both fingers are touching at the EXACT same time\r
- if( startEv && ( numTouches !== startEv.touches.length || touches === startEv.touches ) ){\r
- // extend 1 level deep to get the touchlist with the touch objects\r
- startEv.touches.length = i = 0;\r
- for( ; i < numTouches; ++i ){\r
- startEv.touches[ startEv.touches.length ] = Utils.extend( {}, touches[ i ] );\r
- };\r
- };\r
-\r
- deltaTime = e.timeStamp - startEv.timeStamp;\r
- deltaX = center.pageX - startEv.center.pageX;\r
- deltaY = center.pageY - startEv.center.pageY;\r
- velocity = Utils.getVelocity( deltaTime, deltaX, deltaY );\r
-\r
- Utils.extend( e, {\r
- deltaTime : deltaTime,\r
-\r
- deltaX : deltaX,\r
- deltaY : deltaY,\r
-\r
- velocityX : velocity.x,\r
- velocityY : velocity.y,\r
-\r
- distance : Utils.getDistance( startEv.center, center ),\r
- angle : Utils.getAngle( startEv.center, center ),\r
- direction : Utils.getDirection( startEv.center, center ),\r
-\r
- scale : Utils.getScale( startEv.touches, touches ),\r
- rotation : Utils.getRotation( startEv.touches, touches ),\r
-\r
- startEvent : startEv\r
- });\r
-\r
- // store as previous event event\r
- Detection.current.lastEvent = e;\r
- \r
- // call Hammer.gesture handlers\r
- for( i = 0, l = gestures.length; i < l; ++i ){\r
- gesture = gestures[ i ];\r
- if( Detection.stopped ) break;\r
- //if( active[ gesture.name ] ) console.log( gesture.name );\r
- // only when the instance options have enabled this gesture\r
- active[ gesture.name ] &&\r
- // if a handler returns false, we stop with the detection\r
- ( ret |= ( gesture.handler( e, hammer ) || X_Callback_NONE ) );\r
- };\r
-\r
- // endevent, but not the last touch, so dont stop\r
- type & END && numTouches === 0 && Detection.stopDetect();\r
- \r
- // ----------------------------------------------------------------------------------------------------------------\r
- // trigger the handler\r
- //handler.call( context, HamEvent.collectEventData( element, eventType, e ) );\r
-\r
- // remove pointerevent from list\r
- if( Hammer.HAS_POINTEREVENTS && type & END ){ // eventType === Hammer.EVENT_END ){\r
- numTouches = 0;\r
- };\r
- };\r
-\r
- //debug(sourceEventType +" "+ eventType);\r
-\r
- // on the end we reset everything\r
- if( numTouches === 0 ){\r
- last_move_event = null;\r
- enable_detect = false;\r
- touch_triggered = false;\r
- POINTERS.length = 0;\r
- };\r
- \r
- return ret;\r
- };\r
- \r
- Hammer.startup = function( uinodeRoot ){\r
- // find what eventtypes we add listeners to\r
- /**\r
- * we have different events for each device/browser\r
- * determine what we need and set them in the Hammer.EVENT_TYPES constant\r
- */\r
- // determine the eventtype we want to set\r
- // for non pointer events browsers and mixed browsers,\r
- // like chrome on windows8 touch laptop \r
- var types, name;\r
-\r
- // Register all gestures inside Gestures\r
- for( name in Gestures ){\r
- //Gestures.hasOwnProperty( name ) && \r
- Detection.register( Gestures[ name ] );\r
- };\r
-\r
- Hammer.EVENT_TYPES_START = [ XUI_Event._POINTER_DOWN ];\r
- types = [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL ];\r
-\r
- // Add touch events on the document\r
- Utils.addEvents( uinodeRoot, types, Hammer.prototype.handleEvent );\r
-\r
- // Hammer is ready...!\r
- delete Hammer.startup;\r
- };\r
- \r
- Hammer.prototype.trigger = function( type, gesture ){\r
- if( !this.types[ type ] ) return;\r
- var e = Utils.extend( {}, gesture );\r
- e.type = type;\r
- return this.uinode[ 'dispatch' ]( e );\r
- };\r
- \r
- Hammer.prototype.listen = function( type ){\r
- var gestures = Detection.gestures,\r
- i = gestures.length, g;\r
- for( ; i; ){\r
- g = gestures[ --i ];\r
- if( g.startID <= type && type <= g.endID ){\r
- if( !this.activeGesture ) this.activeGesture = {};\r
- if( !this.types ) this.types = {};\r
- this.activeGesture[ g.name ] = this.types[ type ] = 1;\r
- return;\r
- };\r
- };\r
- };\r
- \r
- Hammer.prototype.unlisten = function( type ){\r
- var gestures = Detection.gestures,\r
- i = gestures.length, g;\r
- if( !this.activeGesture ) return;\r
- for( ; i; ){\r
- g = gestures[ --i ];\r
- if( g.startID <= type && type <= g.endID ){\r
- if( this.activeGesture[ g.name ] ){\r
- if( this.types[ type ] ) delete this.types[ type ];\r
- for( i = g.startID; i <= g.endID; ++i ){\r
- if( this.types[ i ] ) return;\r
- };\r
- delete this.activeGesture[ g.name ];\r
- };\r
- return;\r
- };\r
- };\r
- };\r
- \r
- /*\r
- * "Android version < 2.2" return ev.touches.length === 1 when touchend, others return ev.touches.length === 0\r
- */\r
- Hammer.DO_TOUCHES_FIX = Hammer.HAS_TOUCHEVENTS && ( X_UA[ 'Android' ] < 2.2 || X_UA[ 'Blink' ] || X_UA[ 'Opera' ] );\r
- \r
- // detect touchevents\r
- Hammer.HAS_POINTEREVENTS = true; // navigator.pointerEnabled || navigator.msPointerEnabled;\r
- Hammer.HAS_POINTEREVENTS && console.log( 'Hammer.HAS_POINTEREVENTS : true' );\r
-\r
-\r
- // eventtypes per touchevent (start, move, end)\r
- // are filled by HamEvent.determineEventTypes on setup\r
- Hammer.EVENT_TYPES_START = null;\r
-\r
- // direction defines\r
- Hammer.DIRECTION_DOWN = 'down';\r
- Hammer.DIRECTION_LEFT = 'left';\r
- Hammer.DIRECTION_UP = 'up';\r
- Hammer.DIRECTION_RIGHT = 'right';\r
-\r
- // plugins namespace\r
- Hammer.plugins = {};\r
-\r
- var POINTER = 1,\r
- TOUCH = 2,\r
- PEN = 8, //4,\r
- MOUSE = 8,\r
- START = 16,\r
- MOVE = 32,\r
- END = 64,\r
- CANCEL = 128,\r
- EVENT_TYPE_MASK = START | MOVE | END,\r
- POINTER_TYPE_MASK = POINTER | TOUCH | MOUSE | PEN,\r
- IdToGestureID = {};\r
- IdToGestureID[ XUI_Event._POINTER_DOWN ] = START;\r
- IdToGestureID[ XUI_Event._POINTER_MOVE ] = MOVE;\r
- IdToGestureID[ XUI_Event._POINTER_UP ] = END;\r
- IdToGestureID[ XUI_Event._POINTER_CANCEL ] = END;\r
- \r
- var Utils = {\r
- \r
- /**\r
- * touch events with mouse fallback\r
- * @param {HTMLElement} element\r
- * @param {String} eventType like Hammer.EVENT_MOVE\r
- * @param {Function} handler\r
- */\r
- addEvents : function( uinode, types, context ){\r
- for( var i = 0; i < types.length; ++i ){\r
- uinode[ 'listen' ]( types[ i ], context );\r
- };\r
- },\r
- \r
- /**\r
- * extend method,\r
- * also used for cloning when dest is an empty object\r
- * @param {Object} dest\r
- * @param {Object} src\r
- * @parm {Boolean} merge do a merge\r
- * @returns {Object} dest\r
- */\r
- extend : function extend( dest, src, merge ){\r
- for( var key in src ){\r
- if( dest[ key ] !== undefined && merge ) continue;\r
- dest[ key ] = src[ key ];\r
- };\r
- return dest;\r
- },\r
-\r
- /**\r
- * find if a node is in the given parent\r
- * used for event delegation tricks\r
- * @param {HTMLElement} node\r
- * @param {HTMLElement} parent\r
- * @returns {boolean} has_parent\r
- */\r
- hasParent : function( node, parent ){\r
- while( node && node.tagName ){ /* tagName for ie */\r
- if( node === parent ) return true;\r
- node = node.parentNode;\r
- };\r
- return false;\r
- },\r
-\r
+var XUI_GestureUtils = {\r
/**\r
* get the center of all the touches\r
* @param {Array} touches\r
* @returns {Object} center\r
*/\r
- getCenter : function getCenter(touches) {\r
+ getCenter : function( touches ){\r
var i = 0,\r
l = touches.length,\r
- valuesX, valuesY;\r
+ x, y, minX, minY, maxX, maxY;\r
+\r
switch( l ){\r
case 0 :\r
return {};\r
pageY : ( touches[ 0 ].pageY + touches[ 1 ].pageY ) / 2\r
};\r
};\r
- valuesX = [];\r
- valuesY = [];\r
+ minX = minY = 1 / 0;\r
+ maxX = maxY = - 1 / 0;\r
for( ; i < l; ++i ){\r
- valuesX[ valuesX.length ] = touches[ i ].pageX;\r
- valuesY[ valuesY.length ] = touches[ i ].pageY;\r
+ x = touches[ i ].pageX;\r
+ minX = x < minX ? x : minX;\r
+ maxX = maxX < x ? x : maxX;\r
+ y = touches[ i ].pageY;\r
+ minY = y < minY ? y : minY;\r
+ maxY = maxY < y ? y : maxY;\r
};\r
return {\r
- pageX : ( ( Math.min.apply( null, valuesX ) + Math.max.apply( null, valuesX ) ) / 2 ),\r
- pageY : ( ( Math.min.apply( null, valuesY ) + Math.max.apply( null, valuesY ) ) / 2 )\r
+ pageX : ( minX + maxX ) / 2 | 0,\r
+ pageY : ( minY + maxY ) / 2 | 0\r
};\r
},\r
\r
* @param {Number} deltaY\r
* @returns {Object} velocity\r
*/\r
- getVelocity : function getVelocity( deltaTime, deltaX, deltaY ) {\r
+ getVelocity : function( deltaTime, deltaX, deltaY ) {\r
return {\r
- x : ABS( deltaX / deltaTime ) || 0,\r
- y : ABS( deltaY / deltaTime ) || 0\r
+ x : Math.abs( deltaX / deltaTime ) || 0,\r
+ y : Math.abs( deltaY / deltaTime ) || 0\r
};\r
},\r
\r
* @param {Touch} touch2\r
* @returns {Number} angle\r
*/\r
- getAngle : function getAngle(touch1, touch2) {\r
+ getAngle : function( touch1, touch2 ){\r
var y = touch2.pageY - touch1.pageY,\r
x = touch2.pageX - touch1.pageX;\r
return Math.atan2( y, x ) * 180 / Math.PI;\r
* angle to direction define\r
* @param {Touch} touch1\r
* @param {Touch} touch2\r
- * @returns {String} direction constant, like Hammer.DIRECTION_LEFT\r
+ * @returns {String} direction constant, like 'left'\r
*/\r
- getDirection : function getDirection( touch1, touch2 ){\r
+ getDirection : function( touch1, touch2 ){\r
var x = touch1.pageX - touch2.pageX,\r
y = touch1.pageY - touch2.pageY;\r
- return ABS( y ) <= ABS( x ) ?\r
- ( x > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT ) :\r
- ( y > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN );\r
+ return Math.abs( y ) <= Math.abs( x ) ?\r
+ ( x > 0 ? 'left' : 'right' ) :\r
+ ( y > 0 ? 'up' : 'down' );\r
},\r
\r
/**\r
* @param {Touch} touch2\r
* @returns {Number} distance\r
*/\r
- getDistance : function getDistance( touch1, touch2 ){\r
+ getDistance : function( touch1, touch2 ){\r
var x = touch2.pageX - touch1.pageX,\r
y = touch2.pageY - touch1.pageY;\r
return Math.sqrt( ( x * x ) + ( y * y ) );\r
* @param {Array} end\r
* @returns {Number} scale\r
*/\r
- getScale : function getScale( start, end ){\r
+ getScale : function( start, end ){\r
// need two fingers...\r
return ( 2 <= start.length && 2 <= end.length ) ?\r
- Utils.getDistance( end[ 0 ], end[ 1 ] ) / Utils.getDistance( start[ 0 ], start[ 1 ] ) :\r
+ XUI_GestureUtils.getDistance( end[ 0 ], end[ 1 ] ) / XUI_GestureUtils.getDistance( start[ 0 ], start[ 1 ] ) :\r
1;\r
},\r
\r
getRotation : function getRotation( start, end ){\r
// need two fingers\r
return ( 2 <= start.length && 2 <= end.length ) ?\r
- Utils.getAngle( end[ 1 ], end[ 0 ] ) - Utils.getAngle( start[ 1 ], start[ 0 ] ) :\r
+ XUI_GestureUtils.getAngle( end[ 1 ], end[ 0 ] ) - XUI_GestureUtils.getAngle( start[ 1 ], start[ 0 ] ) :\r
0;\r
},\r
\r
* @returns {Boolean} is_vertical\r
*/\r
isVertical : function isVertical( direction ){\r
- return direction === Hammer.DIRECTION_UP || direction === Hammer.DIRECTION_DOWN;\r
+ return direction === 'up' || direction === 'down';\r
}\r
};\r
- \r
- /*\r
- * this holds the last move event,\r
- * used to fix empty touchend issue\r
- * see the onTouch event for an explanation\r
- * @type {Object}\r
- */\r
- var last_move_event = null;\r
\r
- /*\r
- * when the mouse is hold down, this is true\r
- * @type {Boolean}\r
- */\r
- var enable_detect = false;\r
+var XUI_Gesture_POINTERS = {},\r
+ XUI_Gesture_CAPTURED = {},\r
+ XUI_Gesture_DEFAULTS = {};\r
\r
- /*\r
- * when touch events have been fired, this is true\r
- * @type {Boolean}\r
- */\r
- var touch_triggered = false;\r
+\r
+function XUI_Gesture_trigger( uinode, type, hammerEvent ){\r
+ if( !uinode.gestureTypes[ type ] ) return X_CALLBACK_NONE;\r
+ hammerEvent = X_Object_copy( hammerEvent );\r
+ hammerEvent.type = type;\r
+ return uinode[ 'dispatch' ]( hammerEvent ) || X_CALLBACK_NONE;\r
+};\r
+\r
+function XUI_$UINodeBase_listen( type, arg1, arg2, arg3 ){\r
+ var events, gestures, i, g;\r
\r
- var Detection = {\r
- // contains all registred Gestures in the correct order\r
- gestures : [],\r
+ if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){\r
+ if( this.phase < 3 ){\r
+ if( !( events = this.reserveEvents ) ) this.reserveEvents = events = [];\r
+ events[ events.length ] = [ type, arg1, arg2, arg3 ];\r
+ return this;\r
+ };\r
+ \r
+ if( this[ 'listening' ]( type, arg1, arg2, arg3 ) ){\r
+ return this;\r
+ };\r
+ \r
+ if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){\r
+ gestures = XUI_Gesture_LIST;\r
+ for( i = gestures.length; i; ){\r
+ g = gestures[ --i ];\r
+ if( g.startID <= type && type <= g.endID ){\r
+ if( !this.gestureActivated ){\r
+ this.gestureOptions = XUI_Gesture_DEFAULTS; //X_Object_override( X_Object_copy( XUI_Gesture_DEFAULTS ), opt_options );\r
+ this.gestureActivated = {};\r
+ this.gestureTypes = {};\r
+ this.gestureTriggered = {};\r
+ this.gestureCanceled = {};\r
+ };\r
+ if( X_Object_isEmpty( this.gestureActivated ) ){\r
+ this[ 'listen' ]( XUI_Event._POINTER_DOWN, this, XUI_Gesture_handleEvent );\r
+ };\r
+ this.gestureActivated[ g.name ] = this.gestureTypes[ type ] = true;\r
+ break;\r
+ };\r
+ };\r
+ } else\r
+ if( XUI_EVENT_COUNTER[ type ] ){\r
+ ++XUI_EVENT_COUNTER[ type ];\r
+ } else {\r
+ XUI_EVENT_COUNTER[ type ] = 1; \r
+ XUI_xnodeIneraction[ 'listen' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay );\r
+ };\r
+ };\r
+ \r
+ return X_EventDispatcher_listen.apply( this, arguments );\r
+};\r
\r
- // data of the current Hammer.gesture detection session\r
- current : null,\r
+function XUI_$UINodeBase_unlisten( type, arg1, arg2, arg3 ){\r
+ var events, i, ev, gestures, active, g, f;\r
+ \r
+ if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){\r
+ if( this.phase < 3 ){\r
+ if( !( events = this.reserveEvents ) ) return this;\r
+ for( i = events.length; i; ){\r
+ ev = events[ --i ];\r
+ if( ev[ 0 ] === type && ev[ 1 ] === arg1 && ev[ 2 ] === arg2 && ev[ 3 ] === arg3 ){\r
+ events.split( i, 1 );\r
+ return this;\r
+ };\r
+ }; \r
+ return this;\r
+ };\r
\r
- // the previous Hammer.gesture session data\r
- // is a full clone of the previous gesture.current object\r
- previous : null,\r
+ if( !this[ 'listening' ]( type, arg1, arg2, arg3 ) ){\r
+ return this;\r
+ };\r
+ \r
+ if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){\r
+ if( active = this.gestureActivated ){\r
+ gestures = XUI_Gesture_LIST;\r
+ for( i = gestures.length ; i; ){\r
+ g = gestures[ --i ];\r
+ if( g.startID <= type && type <= g.endID ){\r
+ if( active[ g.name ] ){\r
+ if( this.gestureTypes[ type ] ) delete this.gestureTypes[ type ];\r
+ for( i = g.startID; i <= g.endID; ++i ){\r
+ if( this.gestureTypes[ i ] ){\r
+ f = true;\r
+ break;\r
+ };\r
+ };\r
+ if( !f ){\r
+ delete active[ g.name ];\r
+ \r
+ if( X_Object_isEmpty( active ) ){\r
+ this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, this, XUI_Gesture_handleEvent );\r
+ //delete this.gestureTriggered;\r
+ //delete this.gestureCanceled;\r
+ //delete this.gestureTypes;\r
+ //delete this.gestureActivated;\r
+ };\r
+ };\r
+ };\r
+ break;\r
+ };\r
+ }; \r
+ };\r
+ } else {\r
+ if( XUI_EVENT_COUNTER[ type ] === 1 ){\r
+ XUI_xnodeIneraction[ 'unlisten' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay );\r
+ XUI_EVENT_COUNTER[ type ] = 0;\r
+ } else\r
+ if( XUI_EVENT_COUNTER[ type ] ){\r
+ --XUI_EVENT_COUNTER[ type ];\r
+ };\r
+ };\r
+ };\r
\r
- // when this becomes true, no gestures are fired\r
- stopped : false,\r
+ return X_EventDispatcher_unlisten.apply( this, arguments );\r
+};\r
+\r
+function XUI_Gesture_handleEvent( e ){\r
+ var gestures = XUI_Gesture_LIST,\r
+ type = e.type,\r
+ uid = e[ 'pointerId' ],\r
+ isStart = type === XUI_Event._POINTER_DOWN,\r
+ isEnd = type === XUI_Event._POINTER_UP || type === XUI_Event._POINTER_CANCEL || type === XUI_Event.POINTER_OUT,\r
+ hammer = this,\r
+ isMouse = e.pointerType === 'mouse',\r
+ touches = [], \r
+ numTouches = 0,// count the total touches on the screen\r
+ i, p, l, j, captured, hammerEvent, ret, activated, gesture, startEv,\r
+ deltaTime, deltaX, deltaY, velocity, center, startCenter;\r
\r
- /**\r
- * clear the Hammer.gesture vars\r
- * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected\r
- * to stop other Gestures from being fired\r
- */\r
- stopDetect : function stopDetect() {\r
- // clone current data to the store as the previous gesture\r
- // used for the double tap gesture, since this is an other gesture detect session\r
- Detection.previous = Utils.extend( {}, Detection.current );\r
+ if( !isStart && !hammer.gestureStartEvent ) return;\r
\r
- // reset the current\r
- Detection.current = null;\r
+ if( isEnd ){\r
+ if( XUI_Gesture_POINTERS[ uid ] ){\r
+ delete XUI_Gesture_POINTERS[ uid ];\r
+ if( XUI_Gesture_CAPTURED[ uid ] ) delete XUI_Gesture_CAPTURED[ uid ];\r
+ };\r
+ } else {\r
+ XUI_Gesture_POINTERS[ uid ] = e;\r
+ };\r
\r
- // stopped!\r
- Detection.stopped = true;\r
- },\r
+ // mousebutton must be down or a touch event\r
+ if( ( isEnd || !isMouse || e.button === 0 ) ){\r
+ numTouches = -1;\r
\r
- /**\r
- * register new gesture\r
- * @param {Object} gesture object, see gestures.js for documentation\r
- * @returns {Array} gestures\r
- */\r
- register : function( gesture ){\r
- // add an enable gesture options if there is no given\r
- var options = gesture.defaults || {},\r
- list = Detection.gestures,\r
- _index, i = 0, l = list.length, index;\r
- if( options[ gesture.name ] === undefined ) options[ gesture.name ] = true;\r
-\r
- // extend Hammer default options with the Hammer.gesture options\r
- Utils.extend( Hammer.defaults, options, true );\r
-\r
- // set its index\r
- gesture.index = gesture.index || 1000;\r
-\r
- // add Hammer.gesture to the list\r
- //Detection.gestures.push( gesture );\r
-\r
- // sort the list by index\r
- //Detection.gestures.sort( function( a, b ){\r
- // return\r
- // a.index < b.index ? -1 :\r
- // a.index > b.index ? 1 : 0;\r
- //});\r
- if( l === 0 ){\r
- list[ 0 ] = gesture;\r
- return;\r
+ for( i in XUI_Gesture_POINTERS ){\r
+ if( p = XUI_Gesture_POINTERS[ i ] ){\r
+ // いずれかの hammer によって束縛されている場合、その束縛している hammer なら\r
+ captured = XUI_Gesture_CAPTURED[ p[ 'pointerId' ] ];\r
+ if( captured && captured !== hammer ){\r
+ continue;\r
+ };\r
+ touches[ ++numTouches ] = p;\r
+ };\r
};\r
- _index = gesture.index;\r
- for( i = 0; i < l; ++i ){\r
- index = list[ i ].index;\r
- if( i === 0 && _index < index ){\r
- list.unshift( gesture );\r
- return;\r
- } else\r
- if( i === l - 1 ){\r
- list[ l ] = gesture;\r
- return;\r
- } else\r
- if( index <= _index && _index < list[ i + 1 ].index ){\r
- list.splice( i, 0, gesture );\r
- return;\r
+ ++numTouches;\r
+\r
+ // if we are in a end event, but when we remove one touch and\r
+ // we still have enough, set eventType to move\r
+ if( !numTouches ){ // no touches, force the end event\r
+ isEnd = true;\r
+ };\r
+\r
+ // because touchend has no touches, and we often want to use these in our gestures,\r
+ // we send the last move event as our eventData in touchend\r
+ ( isEnd && hammer.gestureLastMoveEvent ) ? ( e = hammer.gestureLastMoveEvent ) : ( hammer.gestureLastMoveEvent = e ); // store the last move event\r
+\r
+ hammerEvent = X_Object_copy( e );\r
+ hammerEvent.touches = touches;\r
+\r
+ if( isStart && !hammer.gestureStartEvent ){\r
+ //console.log( '=- add -=' );\r
+ // already busy with a Hammer.gesture detection on an element\r
+ hammer.gestureStartEvent = hammerEvent;\r
+ XUI_rootData[ 'listen' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent ); \r
+ };\r
+ \r
+ startEv = hammer.gestureStartEvent;\r
+ \r
+\r
+ // if the touches change, set the new touches over the startEvent touches\r
+ // this because touchevents don't have all the touches on touchstart, or the\r
+ // user must place his fingers at the EXACT same time on the screen, which is not realistic\r
+ // but, sometimes it happens that both fingers are touching at the EXACT same time\r
+ if( startEv && ( numTouches !== startEv.touches.length || touches !== startEv.touches ) ){\r
+ // extend 1 level deep to get the touchlist with the touch objects\r
+ startEv.touches.length = i = 0;\r
+ j = -1;\r
+ for( ; i < numTouches; ++i ){\r
+ startEv.touches[ ++j ] = touches[ i ];\r
};\r
};\r
- }\r
- };\r
\r
- var Gestures = Gestures || {};\r
-\r
- /**\r
- * Custom gestures\r
- * ==============================\r
- *\r
- * Gesture object\r
- * --------------------\r
- * The object structure of a gesture:\r
- *\r
- * { name: 'mygesture',\r
- * index: 1337,\r
- * defaults: {\r
- * mygesture_option: true\r
- * }\r
- * handler: function(type, e, inst) {\r
- * // trigger gesture event\r
- * inst.trigger(this.name, e );\r
- * }\r
- * }\r
-\r
- * @param {String} name\r
- * this should be the name of the gesture, lowercase\r
- * it is also being used to disable/enable the gesture per instance config.\r
- *\r
- * @param {Number} [index=1000]\r
- * the index of the gesture, where it is going to be in the stack of gestures detection\r
- * like when you build an gesture that depends on the drag gesture, it is a good\r
- * idea to place it after the index of the drag gesture.\r
- *\r
- * @param {Object} [defaults={}]\r
- * the default settings of the gesture. these are added to the instance settings,\r
- * and can be overruled per instance. you can also add the name of the gesture,\r
- * but this is also added by default (and set to true).\r
- *\r
- * @param {Function} handler\r
- * this handles the gesture detection of your custom gesture and receives the\r
- * following arguments:\r
- *\r
- * @param {Object} eventData\r
- * event data containing the following properties:\r
- * timeStamp {Number} time the event occurred\r
- * target {HTMLElement} target element\r
- * touches {Array} touches (fingers, pointers, mouse) on the screen\r
- * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH\r
- * center {Object} center position of the touches. contains pageX and pageY\r
- * deltaTime {Number} the total time of the touches in the screen\r
- * deltaX {Number} the delta on x axis we haved moved\r
- * deltaY {Number} the delta on y axis we haved moved\r
- * velocityX {Number} the velocity on the x\r
- * velocityY {Number} the velocity on y\r
- * angle {Number} the angle we are moving\r
- * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT\r
- * distance {Number} the distance we haved moved\r
- * scale {Number} scaling of the touches, needs 2 touches\r
- * rotation {Number} rotation of the touches, needs 2 touches *\r
- * eventType {String} matches Hammer.EVENT_START|MOVE|END\r
- * srcEvent {Object} the source event, like TouchStart or MouseDown *\r
- * startEvent {Object} contains the same properties as above,\r
- * but from the first touch. this is used to calculate\r
- * distances, deltaTime, scaling etc\r
- *\r
- * @param {Hammer.Instance} inst\r
- * the instance we are doing the detection for. you can get the options from\r
- * the inst.options object and trigger the gesture event by calling inst.trigger\r
- *\r
- *\r
- * Handle gestures\r
- * --------------------\r
- * inside the handler you can get/set Detection.current. This is the current\r
- * detection session. It has the following properties\r
- * @param {String} name\r
- * contains the name of the gesture we have detected. it has not a real function,\r
- * only to check in other gestures if something is detected.\r
- * like in the drag gesture we set it to 'drag' and in the swipe gesture we can\r
- * check if the current gesture is 'drag' by accessing Detection.current.name\r
- *\r
- * @readonly\r
- * @param {Hammer.Instance} inst\r
- * the instance we do the detection for\r
- *\r
- * @readonly\r
- * @param {Object} startEvent\r
- * contains the properties of the first gesture detection in this session.\r
- * Used for calculations about timing, distance, etc.\r
- *\r
- * @readonly\r
- * @param {Object} lastEvent\r
- * contains all the properties of the last gesture detect in this session.\r
- *\r
- * after the gesture detection session has been completed (user has released the screen)\r
- * the Detection.current object is copied into Detection.previous,\r
- * this is usefull for gestures like doubletap, where you need to know if the\r
- * previous gesture was a tap\r
- *\r
- * options that have been set by the instance can be received by calling inst.options\r
- *\r
- * You can trigger a gesture event by calling inst.trigger("mygesture", event).\r
- * The first param is the name of your gesture, the second the event argument\r
- *\r
- *\r
- * Register gestures\r
- * --------------------\r
- * When an gesture is added to the Gestures object, it is auto registered\r
- * at the setup of the first Hammer instance. You can also call Detection.register\r
- * manually and pass your gesture object as a param\r
- *\r
- */\r
+ deltaTime = hammerEvent.timestamp - startEv.timestamp;\r
+ center = XUI_GestureUtils.getCenter( touches );\r
+ startCenter = startEv.center;\r
+ deltaX = startCenter ? ( center.pageX - startCenter.pageX ) : 0;\r
+ deltaY = startCenter ? ( center.pageY - startCenter.pageY ) : 0;\r
+ velocity = XUI_GestureUtils.getVelocity( deltaTime, deltaX, deltaY );\r
\r
- /**\r
- * Hold\r
- * Touch stays at the same place for x time\r
- * @events hold holdend\r
- */\r
- Gestures.Hold = {\r
- name : 'hold',\r
- index : 10,\r
- startID : XUI_Event.HOLD,\r
- endID : XUI_Event.HOLD_END,\r
- defaults : {\r
- hold_timeout : 500,\r
- hold_threshold : 1\r
- },\r
- timerID : null,\r
- holding : false,\r
- handler : function holdGesture( e, hammer ){\r
- switch( e.eventType ){\r
- case START :\r
- // clear any running timers\r
- this.timerID && X_Timer_remove( this.timerID );\r
-\r
- // set the gesture so we can check in the timeout if it still is\r
- Detection.current.name = this.name;\r
- Gestures.Hold.holding = false;\r
- \r
- // set timer and if after the timeout it still is hold,\r
- // we trigger the hold event\r
- this.timerID = X_Timer_add( hammer.options.hold_timeout, 1, Gestures.Hold._onTimer, [ e, hammer ] );\r
- return;\r
-\r
- // when you move or end we clear the timer\r
- case MOVE :\r
- if( e.distance <= hammer.options.hold_threshold ) return;\r
- case END :\r
- this.timerID && X_Timer_remove( this.timerID );\r
- if( Gestures.Hold.holding === true ){\r
- Gestures.Hold.holding = false;\r
- return hammer.trigger( XUI_Event.HOLD_END, e );\r
+ X_Object_override( hammerEvent, {\r
+ type : isEnd ? XUI_Event._POINTER_UP : type,\r
+ \r
+ deltaTime : deltaTime,\r
+\r
+ deltaX : deltaX,\r
+ deltaY : deltaY,\r
+\r
+ velocityX : velocity.x,\r
+ velocityY : velocity.y,\r
+\r
+ center : center,\r
+ distance : startCenter ? XUI_GestureUtils.getDistance( startCenter, center ) : 0,\r
+ angle : startCenter ? XUI_GestureUtils.getAngle( startCenter, center ) : 0,\r
+ direction : startCenter ? XUI_GestureUtils.getDirection( startCenter, center ) : 0,\r
+\r
+ scale : XUI_GestureUtils.getScale( startEv.touches, touches ),\r
+ rotation : XUI_GestureUtils.getRotation( startEv.touches, touches ),\r
+\r
+ gestureStartEvent : startEv\r
+ });\r
+\r
+ // store as previous event event\r
+ hammer.gestureLastEvent = hammerEvent;\r
+ activated = hammer.gestureActivated;\r
+ //console.log( '... ' );\r
+ // call Hammer.gesture handlers\r
+ for( i = 0, l = gestures.length; i < l; ++i ){\r
+ gesture = gestures[ i ];\r
+\r
+ if( activated[ gesture.name ] && !hammer.gestureCanceled[ gesture.name ] ){\r
+ //( console.log( '... ' + i + ' ' + gesture.name ) );\r
+ // if a handler returns false, we stop with the detection\r
+ ( ret |= ( gesture.handler( hammerEvent, hammer ) || X_CALLBACK_NONE ) );\r
+ };\r
+\r
+ if( ret & X_CALLBACK_CAPTURE_POINTER ){\r
+ for( i = touches.length; i; ){\r
+ uid = touches[ --i ][ 'pointerId' ];\r
+ XUI_Gesture_CAPTURED[ uid ] = hammer;\r
+ //console.log( 'captured. ' + uid );\r
};\r
break;\r
+ } else\r
+ if( ret & X_CALLBACK_STOP_NOW ){\r
+ break;\r
+ };\r
};\r
- },\r
- _onTimer : function( e, hammer ){\r
- if( Detection.current.name === 'hold' ){\r
- hammer.trigger( XUI_Event.HOLD, e );\r
- Gestures.Hold.holding = true;\r
+ //console.log( '----' );\r
+ } else {\r
+ \r
+ };\r
+ \r
+ if( isEnd || ( ret & X_CALLBACK_RELEASE_POINTER ) ){\r
+ for( i = touches.length; i; ){\r
+ uid = touches[ --i ][ 'pointerId' ];\r
+ if( XUI_Gesture_CAPTURED[ uid ] === hammer ){\r
+ //console.log( 'released. ' + uid );\r
+ delete XUI_Gesture_CAPTURED[ uid ];\r
+ };\r
};\r
- }\r
- };\r
+ };\r
\r
- /**\r
- * Tap/DoubleTap\r
- * Quick touch at a place or double at the same place\r
- * @events tap, doubletap\r
+ if( isEnd ){\r
+ //console.log( '=- clear -=' );\r
+ XUI_rootData[ 'unlisten' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent );\r
+ \r
+ hammer.previous = {\r
+ gestureCurrentName : hammer.gestureCurrentName,\r
+ gestureStartEvent : hammer.gestureStartEvent,\r
+ gestureLastEvent : hammer.gestureLastEvent,\r
+ gestureLastMoveEvent : hammer.gestureLastMoveEvent\r
+ };\r
+ \r
+ X_Object_clear( hammer.gestureTriggered );\r
+ X_Object_clear( hammer.gestureCanceled );\r
+ \r
+ delete hammer.gestureCurrentName;\r
+ delete hammer.gestureStartEvent;\r
+ delete hammer.gestureLastEvent;\r
+ delete hammer.gestureLastMoveEvent;\r
+ \r
+ ret |= X_CALLBACK_RELEASE_POINTER;\r
+ };\r
+ \r
+ return ret;\r
+};\r
+\r
+\r
+\r
+var XUI_Gesture_LIST = [\r
+ /*\r
+ * Touch\r
+ * Called as first, tells the user has touched the screen\r
+ * @events touch\r
*/\r
- Gestures.Tap = {\r
- name : 'tap',\r
- index : 100,\r
- startID : XUI_Event.TAP,\r
- endID : XUI_Event.DOUBLE_TAP,\r
+ {\r
+ name : 'touch',\r
+ index : -Infinity,\r
defaults : {\r
- tap_max_touchtime : 250,\r
- tap_max_distance : 10,\r
- tap_always : true,\r
- doubletap_distance : 20,\r
- doubletap_interval : 300\r
- },\r
- handler : function tapGesture( e, hammer ){\r
- // previous gesture, for the double tap since these are two different gesture detections\r
- var prev = Detection.previous;\r
- if( e.eventType === END ){\r
- // when the touchtime is higher then the max touch time\r
- // or when the moving distance is too much\r
- if( hammer.options.tap_max_touchtime < e.deltaTime || hammer.options.tap_max_distance < e.distance ) return;\r
+ // call preventDefault at touchstart, and makes the element blocking by\r
+ // disabling the scrolling of the page, but it improves gestures like\r
+ // transforming and dragging.\r
+ // be careful with using this, it can be very annoying for users to be stuck\r
+ // on the page\r
+ prevent_default : false,\r
\r
- // check if double tap\r
- if( prev && prev.name === 'tap' && ( e.timeStamp - prev.lastEvent.timeStamp ) < hammer.options.doubletap_interval && e.distance < hammer.options.doubletap_distance ){\r
- return hammer.trigger( XUI_Event.DOUBLE_TAP, e );\r
- } else\r
- // do a single tap\r
- if( hammer.options.tap_always && Detection.current.name !== 'tap' ){ // EventFire中にalert すると mouseleave で再び呼ばれるのを防ぐ\r
- Detection.current.name = 'tap';\r
- return hammer.trigger( XUI_Event.TAP, e );\r
- };\r
+ // disable mouse events, so only touch (or pen!) input triggers events\r
+ prevent_mouseevents : false\r
+ },\r
+ handler : function( e, hammer ){\r
+ if( hammer.gestureOptions.prevent_mouseevents && e[ 'pointerType' ] === 'mouse' ){\r
+ return X_CALLBACK_STOP_NOW;\r
};\r
- }\r
- };\r
\r
- /**\r
- * Swipe\r
- * triggers swipe events when the end velocity is above the threshold\r
- * @events swipe, swipeleft, swiperight, swipeup, swipedown\r
+ //hammer.gestureOptions.prevent_default && e.preventDefault();\r
+\r
+ return e.type === XUI_Event._POINTER_DOWN && XUI_Gesture_trigger( hammer, XUI_Event.TOUCH, e );\r
+ }\r
+ },\r
+ \r
+ /*\r
+ * Transform\r
+ * User want to scale or rotate with 2 fingers\r
+ * @events transform, transformstart, transformend, pinch, pinchin, pinchout, rotate\r
*/\r
- Gestures.Swipe = {\r
- name : 'swipe',\r
- index : 40,\r
- startID : XUI_Event.SWIP,\r
- endID : XUI_Event.SWIP_DOWN,\r
+ {\r
+ name : 'transform',\r
+ index : 45,\r
+ startID : XUI_Event.TRANSFORM,\r
+ endID : XUI_Event.ROTATE,\r
defaults : {\r
- // set 0 for unlimited, but this can conflict with transform\r
- swipe_max_touches : 1,\r
- swipe_velocity : 0.7\r
+ // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1\r
+ transform_min_scale : 0.01,\r
+ // rotation in degrees\r
+ transform_min_rotation : 1,\r
+ // prevent default browser behavior when two touches are on the screen\r
+ // but it makes the element a blocking element\r
+ // when you are using the transform gesture, it is a good practice to set this true\r
+ transform_always_block : false\r
},\r
- handler : function swipeGesture(e, hammer) {\r
- if( e.eventType === END ){\r
- // max touches\r
- if( 0 < hammer.options.swipe_max_touches && hammer.options.swipe_max_touches < e.touches.length ) return;\r
-\r
- // when the distance we moved is too small we skip this gesture\r
- // or we can be already in dragging\r
- if( hammer.options.swipe_velocity < e.velocityX || hammer.options.swipe_velocity < e.velocityY ){\r
- // trigger swipe events\r
- hammer.trigger( XUI_Event.SWIP, e );\r
- hammer.trigger(\r
- e.direction === Hammer.DIRECTION_UP ?\r
- XUI_Event.SWIP_UP :\r
- e.direction === Hammer.DIRECTION_DOWN ?\r
- XUI_Event.SWIP_DOWN :\r
- e.direction === Hammer.DIRECTION_LEFT ?\r
- XUI_Event.SWIP_LEFT :\r
- XUI_Event.SWIP_RIGHT,\r
- e\r
- );\r
- };\r
+\r
+ handler : function( e, hammer ){\r
+ var transform = this, ret = X_CALLBACK_NONE, scale_threshold, rotation_threshold;\r
+ \r
+ // current gesture isnt drag, but dragged is true\r
+ // this means an other gesture is busy. now call dragend\r
+ if( hammer.gestureCurrentName !== transform.name && hammer.gestureTriggered[ transform.name ] ){\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
+ delete hammer.gestureTriggered[ transform.name ];\r
+ return ret;\r
};\r
- }\r
- };\r
\r
- /**\r
+ // atleast multitouch\r
+ if( e.touches.length < 2 ) return;\r
+\r
+ // prevent default when two fingers are on the screen\r
+ //hammer.gestureOptions.transform_always_block && e.preventDefault();\r
+\r
+ switch( e.type ){\r
+ case XUI_Event._POINTER_DOWN :\r
+ //hammer.gestureTriggered[ transform.name ] = false;\r
+ break;\r
+\r
+ case XUI_Event._POINTER_MOVE:\r
+ scale_threshold = Math.abs( 1 - e.scale );\r
+ rotation_threshold = Math.abs( e.rotation );\r
+\r
+ // when the distance we moved is too small we skip this gesture\r
+ // or we can be already in dragging\r
+ if( scale_threshold < hammer.gestureOptions.transform_min_scale && rotation_threshold < hammer.gestureOptions.transform_min_rotation ) return;\r
+\r
+ // we are transforming!\r
+ hammer.gestureCurrentName = transform.name;\r
+\r
+ // first time, trigger dragstart event\r
+ if( !hammer.gestureTriggered[ transform.name ] ){\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_START, e );\r
+ if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
+ hammer.gestureCanceled[ transform.name ] = true;\r
+ break;\r
+ };\r
+ hammer.gestureTriggered[ transform.name ] = true;\r
+ break;\r
+ };\r
+\r
+ ret |= XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM, e );\r
+ // basic transform event\r
+\r
+ // trigger rotate event\r
+ if( hammer.gestureOptions.transform_min_rotation < rotation_threshold ){\r
+ ret |= XUI_Gesture_trigger( hammer, XUI_Event.ROTATE, e );\r
+ };\r
+ \r
+ // trigger pinch event\r
+ if( scale_threshold > hammer.gestureOptions.transform_min_scale ){\r
+ ret |= XUI_Gesture_trigger( hammer, XUI_Event.PINCH, e );\r
+ ret |= XUI_Gesture_trigger( hammer, e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e );\r
+ };\r
+ break;\r
+\r
+ case XUI_Event.POINTER_OUT :\r
+ case XUI_Event._POINTER_CANCEL :\r
+ case XUI_Event._POINTER_UP :\r
+ // trigger dragend\r
+ ret = hammer.gestureTriggered[ transform.name ] && XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
+ hammer.gestureTriggered[ transform.name ] = false;\r
+ break;\r
+ };\r
+ return ret;\r
+ }\r
+ },\r
+ \r
+ /*\r
* Drag\r
* Move with x fingers (default 1) around on the page. Blocking the scrolling when\r
* moving left and right is a good practice. When all the drag events are blocking\r
* you disable scrolling on that area.\r
* @events drag, dragstart, dragend, drapleft, dragright, dragup, dragdown\r
*/\r
- Gestures.Drag = {\r
+ {\r
name : 'drag',\r
index : 50,\r
startID : XUI_Event.DRAG,\r
endID : XUI_Event.DRAG_DOWN,\r
+ \r
defaults : {\r
drag_min_distance : 10,\r
// set 0 for unlimited, but this can conflict with transform\r
// This way, locking occurs only when the distance has become large enough to reliably determine the direction\r
drag_lock_min_distance : 25\r
},\r
- triggered : false,\r
- handler : function dragGesture( e, hammer ){\r
- var last_direction;\r
+\r
+ handler : function( e, hammer ){\r
+ var drag = this, last_direction, ret;\r
+\r
// current gesture isnt drag, but dragged is true\r
// this means an other gesture is busy. now call dragend\r
- if( Detection.current.name !== this.name && this.triggered ){\r
- hammer.trigger( XUI_Event.DRAG_END, e );\r
- this.triggered = false;\r
- return;\r
+ if( hammer.gestureCurrentName !== drag.name && hammer.gestureTriggered[ drag.name ] ){\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e );\r
+ hammer.gestureTriggered[ drag.name ] = false;\r
+ return ret;\r
};\r
\r
// max touches\r
- if( 0 < hammer.options.drag_max_touches && hammer.options.drag_max_touches < e.touches.length ) return;\r
-\r
- switch( e.eventType ){\r
- case START:\r
- this.triggered = false;\r
+ if( 0 < hammer.gestureOptions.drag_max_touches && hammer.gestureOptions.drag_max_touches < e.touches.length ) return;\r
+ \r
+ switch( e.type ){\r
+ case XUI_Event._POINTER_DOWN :\r
+ hammer.gestureTriggered[ drag.name ] = false;\r
break;\r
\r
- case MOVE :\r
+ case XUI_Event._POINTER_MOVE :\r
// when the distance we moved is too small we skip this gesture\r
// or we can be already in dragging\r
- if( e.distance < hammer.options.drag_min_distance && Detection.current.name !== this.name ) return;\r
+ if( e.distance < hammer.gestureOptions.drag_min_distance && hammer.gestureCurrentName !== drag.name ) return;\r
\r
// we are dragging!\r
- Detection.current.name = this.name;\r
+ hammer.gestureCurrentName = drag.name;\r
\r
// lock drag to axis?\r
- if( Detection.current.lastEvent.drag_locked_to_axis || ( hammer.options.drag_lock_to_axis && hammer.options.drag_lock_min_distance <= e.distance ) ){\r
+ if( hammer.gestureLastEvent.drag_locked_to_axis || ( hammer.gestureOptions.drag_lock_to_axis && hammer.gestureOptions.drag_lock_min_distance <= e.distance ) ){\r
e.drag_locked_to_axis = true;\r
};\r
- last_direction = Detection.current.lastEvent.direction;\r
+ last_direction = hammer.gestureLastEvent.direction;\r
if( e.drag_locked_to_axis && last_direction !== e.direction ){\r
// keep direction on the axis that the drag gesture started on\r
- e.direction = Utils.isVertical( last_direction ) ?\r
- ( e.deltaY < 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN ) :\r
- ( e.deltaX < 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT );\r
+ e.direction = XUI_GestureUtils.isVertical( last_direction ) ?\r
+ ( e.deltaY < 0 ? 'up' : 'down' ) :\r
+ ( e.deltaX < 0 ? 'left' : 'right' );\r
};\r
\r
+ ret = X_CALLBACK_NONE;\r
+\r
// first time, trigger dragstart event\r
- if( !this.triggered ){\r
- hammer.trigger( XUI_Event.DRAG_START, e );\r
- this.triggered = true;\r
+ if( !hammer.gestureTriggered[ drag.name ] ){\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_START, e );\r
+ //if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
+ // hammer.gestureCanceled[ drag.name ] = true;\r
+ // break;\r
+ //};\r
+ ret |= X_CALLBACK_CAPTURE_POINTER;\r
+ //console.log( '----- drag start ....' + e.type );\r
+ hammer.gestureTriggered[ drag.name ] = true;\r
+ break;\r
};\r
\r
+ //console.log( '----- drag ....' + e.type );\r
// trigger normal event\r
- hammer.trigger( XUI_Event.DRAG, e );\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG, e ) | X_CALLBACK_CAPTURE_POINTER;\r
\r
// direction event, like dragdown\r
- hammer.trigger(\r
- e.direction === Hammer.DIRECTION_UP ?\r
+ ret |= XUI_Gesture_trigger( hammer,\r
+ e.direction === 'up' ?\r
XUI_Event.DRAG_UP :\r
- e.direction === Hammer.DIRECTION_DOWN ?\r
+ e.direction === 'down' ?\r
XUI_Event.DRAG_DOWN :\r
- e.direction === Hammer.DIRECTION_LEFT ?\r
+ e.direction === 'left' ?\r
XUI_Event.DRAG_LEFT :\r
XUI_Event.DRAG_RIGHT,\r
e\r
);\r
\r
// block the browser events\r
- (\r
- ( hammer.options.drag_block_vertical && Utils.isVertical( e.direction ) ) ||\r
- ( hammer.options.drag_block_horizontal && !Utils.isVertical( e.direction ) )\r
- ) && e.preventDefault();\r
+ /* (\r
+ ( hammer.gestureOptions.drag_block_vertical && XUI_GestureUtils.isVertical( e.direction ) ) ||\r
+ ( hammer.gestureOptions.drag_block_horizontal && !XUI_GestureUtils.isVertical( e.direction ) )\r
+ ) && e.preventDefault(); */\r
break;\r
\r
- case END:\r
+ case XUI_Event.POINTER_OUT :\r
+ //console.log( 'cancel!!' );\r
+ case XUI_Event._POINTER_CANCEL :\r
+ case XUI_Event._POINTER_UP:\r
// trigger dragend\r
- this.triggered && hammer.trigger( XUI_Event.DRAG_END, e );\r
- this.triggered = false;\r
+ if( hammer.gestureTriggered[ drag.name ] ){\r
+ ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e ) | X_CALLBACK_CAPTURE_POINTER;\r
+ //console.log( '----- drag end ....' + e.type );\r
+ hammer.gestureTriggered[ drag.name ] = false;\r
+ };\r
break;\r
- }\r
+ };\r
+ return ret;\r
}\r
- };\r
+ },\r
\r
- /**\r
- * Transform\r
- * User want to scale or rotate with 2 fingers\r
- * @events transform, transformstart, transformend, pinch, pinchin, pinchout, rotate\r
+ /*\r
+ * Tap/DoubleTap\r
+ * Quick touch at a place or double at the same place\r
+ * @events tap, doubletap\r
*/\r
- Gestures.Transform = {\r
- name : 'transform',\r
- index : 45,\r
- startID : XUI_Event.TRANSFORM,\r
- endID : XUI_Event.ROTATE,\r
+ {\r
+ name : 'tap',\r
+ index : 100,\r
+ startID : XUI_Event.TAP,\r
+ endID : XUI_Event.DOUBLE_TAP,\r
defaults : {\r
- // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1\r
- transform_min_scale : 0.01,\r
- // rotation in degrees\r
- transform_min_rotation : 1,\r
- // prevent default browser behavior when two touches are on the screen\r
- // but it makes the element a blocking element\r
- // when you are using the transform gesture, it is a good practice to set this true\r
- transform_always_block : false\r
+ tap_max_touchtime : 250,\r
+ tap_max_distance : 3,\r
+ tap_always : true,\r
+ doubletap_distance : 20,\r
+ doubletap_interval : 300\r
},\r
- triggered : false,\r
- handler : function transformGesture( e, hammer ){\r
- // current gesture isnt drag, but dragged is true\r
- // this means an other gesture is busy. now call dragend\r
- if( Detection.current.name !== this.name && this.triggered ){\r
- hammer.trigger( XUI_Event.TRANSFORM_END, e );\r
- this.triggered = false;\r
- return;\r
+ handler : function( e, hammer ){\r
+ // previous gesture, for the double tap since these are two different gesture detections\r
+ var prev = hammer.previous;\r
+ \r
+ if( e.type === XUI_Event._POINTER_MOVE && hammer.gestureOptions.tap_max_distance < e.distance ){\r
+ hammer.gestureCanceled[ 'tap' ] = true;\r
};\r
+ if( e.type === XUI_Event._POINTER_UP ){\r
+ // when the touchtime is higher then the max touch time\r
+ // or when the moving distance is too much\r
+ if( hammer.gestureOptions.tap_max_touchtime < e.deltaTime || hammer.gestureOptions.tap_max_distance < e.distance ) return;\r
\r
- // atleast multitouch\r
- if( e.touches.length < 2 ) return;\r
-\r
- // prevent default when two fingers are on the screen\r
- hammer.options.transform_always_block && e.preventDefault();\r
-\r
- switch(e.eventType) {\r
- case START:\r
- this.triggered = false;\r
- break;\r
-\r
- case MOVE:\r
- var scale_threshold = ABS( 1 - e.scale ),\r
- rotation_threshold = ABS( e.rotation );\r
-\r
- // when the distance we moved is too small we skip this gesture\r
- // or we can be already in dragging\r
- if( scale_threshold < hammer.options.transform_min_scale && rotation_threshold < hammer.options.transform_min_rotation ) return;\r
-\r
- // we are transforming!\r
- Detection.current.name = this.name;\r
-\r
- // first time, trigger dragstart event\r
- if( !this.triggered ){\r
- hammer.trigger( XUI_Event.TRANSFORM_START, e );\r
- this.triggered = true;\r
- };\r
-\r
- hammer.trigger( XUI_Event.TRANSFORM, e );\r
- // basic transform event\r
-\r
- // trigger rotate event\r
- hammer.options.transform_min_rotation < rotation_threshold && hammer.trigger( XUI_Event.ROTATE, e );\r
-\r
- // trigger pinch event\r
- if( scale_threshold > hammer.options.transform_min_scale ){\r
- hammer.trigger( XUI_Event.PINCH, e );\r
- hammer.trigger( e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e );\r
- };\r
- break;\r
-\r
- case END:\r
- // trigger dragend\r
- this.triggered && hammer.trigger( XUI_Event.TRANSFORM_END, e );\r
- this.triggered = false;\r
- break;\r
+ // check if double tap\r
+ if( prev && prev.gestureCurrentName === 'tap' && ( e.timestamp - prev.gestureLastEvent.timestamp ) < hammer.gestureOptions.doubletap_interval && e.distance < hammer.gestureOptions.doubletap_distance ){\r
+ return XUI_Gesture_trigger( hammer, XUI_Event.DOUBLE_TAP, e );\r
+ } else\r
+ // do a single tap\r
+ if( hammer.gestureOptions.tap_always ){\r
+ hammer.gestureCurrentName = 'tap';\r
+ //console.log( 'tap! ' + e.deltaTime + 'ms ' + e.type );\r
+ return XUI_Gesture_trigger( hammer, XUI_Event.TAP, e );\r
+ };\r
};\r
}\r
- };\r
+ }\r
\r
- /**\r
- * Touch\r
- * Called as first, tells the user has touched the screen\r
- * @events touch\r
- */\r
- Gestures.Touch = {\r
- name : 'touch',\r
- index : -Infinity,\r
- defaults : {\r
- // call preventDefault at touchstart, and makes the element blocking by\r
- // disabling the scrolling of the page, but it improves gestures like\r
- // transforming and dragging.\r
- // be careful with using this, it can be very annoying for users to be stuck\r
- // on the page\r
- prevent_default : false,\r
+];\r
\r
- // disable mouse events, so only touch (or pen!) input triggers events\r
- prevent_mouseevents : false\r
- },\r
- handler : function touchGesture( e, hammer ){\r
- if( hammer.options.prevent_mouseevents && e.pointerType === MOUSE ){\r
- Detection.stopDetect();\r
- return;\r
- };\r
-\r
- hammer.options.prevent_default && e.preventDefault();\r
-\r
- e.eventType === START && hammer.trigger( this.name, e );\r
- }\r
+(function( i, g ){\r
+ for( ; i; ){\r
+ g = XUI_Gesture_LIST[ --i ];\r
+ X_Object_override( XUI_Gesture_DEFAULTS, g.defaults );\r
+ delete g.defaults;\r
};\r
+})( XUI_Gesture_LIST.length );\r
\r
- /**\r
- * Release\r
- * Called as last, tells the user has released the screen\r
- * @events release\r
- */\r
- Gestures.Release = {\r
- name : 'release',\r
- index : Infinity,\r
- handler : function releaseGesture( e, hammer ){\r
- e.eventType === END && hammer.trigger( this.name, e );\r
- }\r
- };\r