-/* 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