[VID-6] Initial rebase push
[vid.git] / epsdk-app-onap / src / main / webapp / app / fusion / external / ebz / angular_js / gestures.js
1 /*! Hammer.JS - v1.0.5 - 2013-04-07\r
2  * http://eightmedia.github.com/hammer.js\r
3  *\r
4  * Copyright (c) 2013 Jorik Tangelder <j.tangelder@gmail.com>;\r
5  * Licensed under the MIT license */\r
6 \r
7 (function(window, undefined) {\r
8     'use strict';\r
9 \r
10 /**\r
11  * Hammer\r
12  * use this to create instances\r
13  * @param   {HTMLElement}   element\r
14  * @param   {Object}        options\r
15  * @returns {Hammer.Instance}\r
16  * @constructor\r
17  */\r
18 var Hammer = function(element, options) {\r
19     return new Hammer.Instance(element, options || {});\r
20 };\r
21 \r
22 // default settings\r
23 Hammer.defaults = {\r
24     // add styles and attributes to the element to prevent the browser from doing\r
25     // its native behavior. this doesnt prevent the scrolling, but cancels\r
26     // the contextmenu, tap highlighting etc\r
27     // set to false to disable this\r
28     stop_browser_behavior: {\r
29                 // this also triggers onselectstart=false for IE\r
30         userSelect: 'none',\r
31                 // this makes the element blocking in IE10 >, you could experiment with the value\r
32                 // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241\r
33         touchAction: 'none',\r
34                 touchCallout: 'none',\r
35         contentZooming: 'none',\r
36         userDrag: 'none',\r
37         tapHighlightColor: 'rgba(0,0,0,0)'\r
38     }\r
39 \r
40     // more settings are defined per gesture at gestures.js\r
41 };\r
42 \r
43 // detect touchevents\r
44 Hammer.HAS_POINTEREVENTS = navigator.pointerEnabled || navigator.msPointerEnabled;\r
45 Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window);\r
46 \r
47 // dont use mouseevents on mobile devices\r
48 Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\r
49 Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && navigator.userAgent.match(Hammer.MOBILE_REGEX);\r
50 \r
51 // eventtypes per touchevent (start, move, end)\r
52 // are filled by Hammer.event.determineEventTypes on setup\r
53 Hammer.EVENT_TYPES = {};\r
54 \r
55 // direction defines\r
56 Hammer.DIRECTION_DOWN = 'down';\r
57 Hammer.DIRECTION_LEFT = 'left';\r
58 Hammer.DIRECTION_UP = 'up';\r
59 Hammer.DIRECTION_RIGHT = 'right';\r
60 \r
61 // pointer type\r
62 Hammer.POINTER_MOUSE = 'mouse';\r
63 Hammer.POINTER_TOUCH = 'touch';\r
64 Hammer.POINTER_PEN = 'pen';\r
65 \r
66 // touch event defines\r
67 Hammer.EVENT_START = 'start';\r
68 Hammer.EVENT_MOVE = 'move';\r
69 Hammer.EVENT_END = 'end';\r
70 \r
71 // hammer document where the base events are added at\r
72 Hammer.DOCUMENT = document;\r
73 \r
74 // plugins namespace\r
75 Hammer.plugins = {};\r
76 \r
77 // if the window events are set...\r
78 Hammer.READY = false;\r
79 \r
80 /**\r
81  * setup events to detect gestures on the document\r
82  */\r
83 function setup() {\r
84     if(Hammer.READY) {\r
85         return;\r
86     }\r
87 \r
88     // find what eventtypes we add listeners to\r
89     Hammer.event.determineEventTypes();\r
90 \r
91     // Register all gestures inside Hammer.gestures\r
92     for(var name in Hammer.gestures) {\r
93         if(Hammer.gestures.hasOwnProperty(name)) {\r
94             Hammer.detection.register(Hammer.gestures[name]);\r
95         }\r
96     }\r
97 \r
98     // Add touch events on the document\r
99     Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect);\r
100     Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect);\r
101 \r
102     // Hammer is ready...!\r
103     Hammer.READY = true;\r
104 }\r
105 \r
106 /**\r
107  * create new hammer instance\r
108  * all methods should return the instance itself, so it is chainable.\r
109  * @param   {HTMLElement}       element\r
110  * @param   {Object}            [options={}]\r
111  * @returns {Hammer.Instance}\r
112  * @constructor\r
113  */\r
114 Hammer.Instance = function(element, options) {\r
115     var self = this;\r
116 \r
117     // setup HammerJS window events and register all gestures\r
118     // this also sets up the default options\r
119     setup();\r
120 \r
121     this.element = element;\r
122 \r
123     // start/stop detection option\r
124     this.enabled = true;\r
125 \r
126     // merge options\r
127     this.options = Hammer.utils.extend(\r
128         Hammer.utils.extend({}, Hammer.defaults),\r
129         options || {});\r
130 \r
131     // add some css to the element to prevent the browser from doing its native behavoir\r
132     if(this.options.stop_browser_behavior) {\r
133         Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior);\r
134     }\r
135 \r
136     // start detection on touchstart\r
137     Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) {\r
138         if(self.enabled) {\r
139             Hammer.detection.startDetect(self, ev);\r
140         }\r
141     });\r
142 \r
143     // return instance\r
144     return this;\r
145 };\r
146 \r
147 \r
148 Hammer.Instance.prototype = {\r
149     /**\r
150      * bind events to the instance\r
151      * @param   {String}      gesture\r
152      * @param   {Function}    handler\r
153      * @returns {Hammer.Instance}\r
154      */\r
155     on: function onEvent(gesture, handler){\r
156         var gestures = gesture.split(' ');\r
157         for(var t=0; t<gestures.length; t++) {\r
158             this.element.addEventListener(gestures[t], handler, false);\r
159         }\r
160         return this;\r
161     },\r
162 \r
163 \r
164     /**\r
165      * unbind events to the instance\r
166      * @param   {String}      gesture\r
167      * @param   {Function}    handler\r
168      * @returns {Hammer.Instance}\r
169      */\r
170     off: function offEvent(gesture, handler){\r
171         var gestures = gesture.split(' ');\r
172         for(var t=0; t<gestures.length; t++) {\r
173             this.element.removeEventListener(gestures[t], handler, false);\r
174         }\r
175         return this;\r
176     },\r
177 \r
178 \r
179     /**\r
180      * trigger gesture event\r
181      * @param   {String}      gesture\r
182      * @param   {Object}      eventData\r
183      * @returns {Hammer.Instance}\r
184      */\r
185     trigger: function triggerEvent(gesture, eventData){\r
186         // create DOM event\r
187         var event = Hammer.DOCUMENT.createEvent('Event');\r
188                 event.initEvent(gesture, true, true);\r
189                 event.gesture = eventData;\r
190 \r
191         // trigger on the target if it is in the instance element,\r
192         // this is for event delegation tricks\r
193         var element = this.element;\r
194         if(Hammer.utils.hasParent(eventData.target, element)) {\r
195             element = eventData.target;\r
196         }\r
197 \r
198         element.dispatchEvent(event);\r
199         return this;\r
200     },\r
201 \r
202 \r
203     /**\r
204      * enable of disable hammer.js detection\r
205      * @param   {Boolean}   state\r
206      * @returns {Hammer.Instance}\r
207      */\r
208     enable: function enable(state) {\r
209         this.enabled = state;\r
210         return this;\r
211     }\r
212 };\r
213 \r
214 /**\r
215  * this holds the last move event,\r
216  * used to fix empty touchend issue\r
217  * see the onTouch event for an explanation\r
218  * @type {Object}\r
219  */\r
220 var last_move_event = null;\r
221 \r
222 \r
223 /**\r
224  * when the mouse is hold down, this is true\r
225  * @type {Boolean}\r
226  */\r
227 var enable_detect = false;\r
228 \r
229 \r
230 /**\r
231  * when touch events have been fired, this is true\r
232  * @type {Boolean}\r
233  */\r
234 var touch_triggered = false;\r
235 \r
236 \r
237 Hammer.event = {\r
238     /**\r
239      * simple addEventListener\r
240      * @param   {HTMLElement}   element\r
241      * @param   {String}        type\r
242      * @param   {Function}      handler\r
243      */\r
244     bindDom: function(element, type, handler) {\r
245         var types = type.split(' ');\r
246         for(var t=0; t<types.length; t++) {\r
247             element.addEventListener(types[t], handler, false);\r
248         }\r
249     },\r
250 \r
251 \r
252     /**\r
253      * touch events with mouse fallback\r
254      * @param   {HTMLElement}   element\r
255      * @param   {String}        eventType        like Hammer.EVENT_MOVE\r
256      * @param   {Function}      handler\r
257      */\r
258     onTouch: function onTouch(element, eventType, handler) {\r
259                 var self = this;\r
260 \r
261         this.bindDom(element, Hammer.EVENT_TYPES[eventType], function bindDomOnTouch(ev) {\r
262             var sourceEventType = ev.type.toLowerCase();\r
263 \r
264             // onmouseup, but when touchend has been fired we do nothing.\r
265             // this is for touchdevices which also fire a mouseup on touchend\r
266             if(sourceEventType.match(/mouse/) && touch_triggered) {\r
267                 return;\r
268             }\r
269 \r
270             // mousebutton must be down or a touch event\r
271             else if( sourceEventType.match(/touch/) ||   // touch events are always on screen\r
272                 sourceEventType.match(/pointerdown/) || // pointerevents touch\r
273                 (sourceEventType.match(/mouse/) && ev.which === 1)   // mouse is pressed\r
274             ){\r
275                 enable_detect = true;\r
276             }\r
277 \r
278             // we are in a touch event, set the touch triggered bool to true,\r
279             // this for the conflicts that may occur on ios and android\r
280             if(sourceEventType.match(/touch|pointer/)) {\r
281                 touch_triggered = true;\r
282             }\r
283 \r
284             // count the total touches on the screen\r
285             var count_touches = 0;\r
286 \r
287             // when touch has been triggered in this detection session\r
288             // and we are now handling a mouse event, we stop that to prevent conflicts\r
289             if(enable_detect) {\r
290                 // update pointerevent\r
291                 if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) {\r
292                     count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);\r
293                 }\r
294                 // touch\r
295                 else if(sourceEventType.match(/touch/)) {\r
296                     count_touches = ev.touches.length;\r
297                 }\r
298                 // mouse\r
299                 else if(!touch_triggered) {\r
300                     count_touches = sourceEventType.match(/up/) ? 0 : 1;\r
301                 }\r
302 \r
303                 // if we are in a end event, but when we remove one touch and\r
304                 // we still have enough, set eventType to move\r
305                 if(count_touches > 0 && eventType == Hammer.EVENT_END) {\r
306                     eventType = Hammer.EVENT_MOVE;\r
307                 }\r
308                 // no touches, force the end event\r
309                 else if(!count_touches) {\r
310                     eventType = Hammer.EVENT_END;\r
311                 }\r
312 \r
313                 // because touchend has no touches, and we often want to use these in our gestures,\r
314                 // we send the last move event as our eventData in touchend\r
315                 if(!count_touches && last_move_event !== null) {\r
316                     ev = last_move_event;\r
317                 }\r
318                 // store the last move event\r
319                 else {\r
320                     last_move_event = ev;\r
321                 }\r
322 \r
323                 // trigger the handler\r
324                 handler.call(Hammer.detection, self.collectEventData(element, eventType, ev));\r
325 \r
326                 // remove pointerevent from list\r
327                 if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) {\r
328                     count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);\r
329                 }\r
330             }\r
331 \r
332             //debug(sourceEventType +" "+ eventType);\r
333 \r
334             // on the end we reset everything\r
335             if(!count_touches) {\r
336                 last_move_event = null;\r
337                 enable_detect = false;\r
338                 touch_triggered = false;\r
339                 Hammer.PointerEvent.reset();\r
340             }\r
341         });\r
342     },\r
343 \r
344 \r
345     /**\r
346      * we have different events for each device/browser\r
347      * determine what we need and set them in the Hammer.EVENT_TYPES constant\r
348      */\r
349     determineEventTypes: function determineEventTypes() {\r
350         // determine the eventtype we want to set\r
351         var types;\r
352 \r
353         // pointerEvents magic\r
354         if(Hammer.HAS_POINTEREVENTS) {\r
355             types = Hammer.PointerEvent.getEvents();\r
356         }\r
357         // on Android, iOS, blackberry, windows mobile we dont want any mouseevents\r
358         else if(Hammer.NO_MOUSEEVENTS) {\r
359             types = [\r
360                 'touchstart',\r
361                 'touchmove',\r
362                 'touchend touchcancel'];\r
363         }\r
364         // for non pointer events browsers and mixed browsers,\r
365         // like chrome on windows8 touch laptop\r
366         else {\r
367             types = [\r
368                 'touchstart mousedown',\r
369                 'touchmove mousemove',\r
370                 'touchend touchcancel mouseup'];\r
371         }\r
372 \r
373         Hammer.EVENT_TYPES[Hammer.EVENT_START]  = types[0];\r
374         Hammer.EVENT_TYPES[Hammer.EVENT_MOVE]   = types[1];\r
375         Hammer.EVENT_TYPES[Hammer.EVENT_END]    = types[2];\r
376     },\r
377 \r
378 \r
379     /**\r
380      * create touchlist depending on the event\r
381      * @param   {Object}    ev\r
382      * @param   {String}    eventType   used by the fakemultitouch plugin\r
383      */\r
384     getTouchList: function getTouchList(ev/*, eventType*/) {\r
385         // get the fake pointerEvent touchlist\r
386         if(Hammer.HAS_POINTEREVENTS) {\r
387             return Hammer.PointerEvent.getTouchList();\r
388         }\r
389         // get the touchlist\r
390         else if(ev.touches) {\r
391             return ev.touches;\r
392         }\r
393         // make fake touchlist from mouse position\r
394         else {\r
395             return [{\r
396                 identifier: 1,\r
397                 pageX: ev.pageX,\r
398                 pageY: ev.pageY,\r
399                 target: ev.target\r
400             }];\r
401         }\r
402     },\r
403 \r
404 \r
405     /**\r
406      * collect event data for Hammer js\r
407      * @param   {HTMLElement}   element\r
408      * @param   {String}        eventType        like Hammer.EVENT_MOVE\r
409      * @param   {Object}        eventData\r
410      */\r
411     collectEventData: function collectEventData(element, eventType, ev) {\r
412         var touches = this.getTouchList(ev, eventType);\r
413 \r
414         // find out pointerType\r
415         var pointerType = Hammer.POINTER_TOUCH;\r
416         if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) {\r
417             pointerType = Hammer.POINTER_MOUSE;\r
418         }\r
419 \r
420         return {\r
421             center      : Hammer.utils.getCenter(touches),\r
422             timeStamp   : new Date().getTime(),\r
423             target      : ev.target,\r
424             touches     : touches,\r
425             eventType   : eventType,\r
426             pointerType : pointerType,\r
427             srcEvent    : ev,\r
428 \r
429             /**\r
430              * prevent the browser default actions\r
431              * mostly used to disable scrolling of the browser\r
432              */\r
433             preventDefault: function() {\r
434                 if(this.srcEvent.preventManipulation) {\r
435                     this.srcEvent.preventManipulation();\r
436                 }\r
437 \r
438                 if(this.srcEvent.preventDefault) {\r
439                     this.srcEvent.preventDefault();\r
440                 }\r
441             },\r
442 \r
443             /**\r
444              * stop bubbling the event up to its parents\r
445              */\r
446             stopPropagation: function() {\r
447                 this.srcEvent.stopPropagation();\r
448             },\r
449 \r
450             /**\r
451              * immediately stop gesture detection\r
452              * might be useful after a swipe was detected\r
453              * @return {*}\r
454              */\r
455             stopDetect: function() {\r
456                 return Hammer.detection.stopDetect();\r
457             }\r
458         };\r
459     }\r
460 };\r
461 \r
462 Hammer.PointerEvent = {\r
463     /**\r
464      * holds all pointers\r
465      * @type {Object}\r
466      */\r
467     pointers: {},\r
468 \r
469     /**\r
470      * get a list of pointers\r
471      * @returns {Array}     touchlist\r
472      */\r
473     getTouchList: function() {\r
474         var self = this;\r
475         var touchlist = [];\r
476 \r
477         // we can use forEach since pointerEvents only is in IE10\r
478         Object.keys(self.pointers).sort().forEach(function(id) {\r
479             touchlist.push(self.pointers[id]);\r
480         });\r
481         return touchlist;\r
482     },\r
483 \r
484     /**\r
485      * update the position of a pointer\r
486      * @param   {String}   type             Hammer.EVENT_END\r
487      * @param   {Object}   pointerEvent\r
488      */\r
489     updatePointer: function(type, pointerEvent) {\r
490         if(type == Hammer.EVENT_END) {\r
491             this.pointers = {};\r
492         }\r
493         else {\r
494             pointerEvent.identifier = pointerEvent.pointerId;\r
495             this.pointers[pointerEvent.pointerId] = pointerEvent;\r
496         }\r
497 \r
498         return Object.keys(this.pointers).length;\r
499     },\r
500 \r
501     /**\r
502      * check if ev matches pointertype\r
503      * @param   {String}        pointerType     Hammer.POINTER_MOUSE\r
504      * @param   {PointerEvent}  ev\r
505      */\r
506     matchType: function(pointerType, ev) {\r
507         if(!ev.pointerType) {\r
508             return false;\r
509         }\r
510 \r
511         var types = {};\r
512         types[Hammer.POINTER_MOUSE] = (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || ev.pointerType == Hammer.POINTER_MOUSE);\r
513         types[Hammer.POINTER_TOUCH] = (ev.pointerType == ev.MSPOINTER_TYPE_TOUCH || ev.pointerType == Hammer.POINTER_TOUCH);\r
514         types[Hammer.POINTER_PEN] = (ev.pointerType == ev.MSPOINTER_TYPE_PEN || ev.pointerType == Hammer.POINTER_PEN);\r
515         return types[pointerType];\r
516     },\r
517 \r
518 \r
519     /**\r
520      * get events\r
521      */\r
522     getEvents: function() {\r
523         return [\r
524             'pointerdown MSPointerDown',\r
525             'pointermove MSPointerMove',\r
526             'pointerup pointercancel MSPointerUp MSPointerCancel'\r
527         ];\r
528     },\r
529 \r
530     /**\r
531      * reset the list\r
532      */\r
533     reset: function() {\r
534         this.pointers = {};\r
535     }\r
536 };\r
537 \r
538 \r
539 Hammer.utils = {\r
540     /**\r
541      * extend method,\r
542      * also used for cloning when dest is an empty object\r
543      * @param   {Object}    dest\r
544      * @param   {Object}    src\r
545          * @parm        {Boolean}       merge           do a merge\r
546      * @returns {Object}    dest\r
547      */\r
548     extend: function extend(dest, src, merge) {\r
549         for (var key in src) {\r
550                         if(dest[key] !== undefined && merge) {\r
551                                 continue;\r
552                         }\r
553             dest[key] = src[key];\r
554         }\r
555         return dest;\r
556     },\r
557 \r
558 \r
559     /**\r
560      * find if a node is in the given parent\r
561      * used for event delegation tricks\r
562      * @param   {HTMLElement}   node\r
563      * @param   {HTMLElement}   parent\r
564      * @returns {boolean}       has_parent\r
565      */\r
566     hasParent: function(node, parent) {\r
567         while(node){\r
568             if(node == parent) {\r
569                 return true;\r
570             }\r
571             node = node.parentNode;\r
572         }\r
573         return false;\r
574     },\r
575 \r
576 \r
577     /**\r
578      * get the center of all the touches\r
579      * @param   {Array}     touches\r
580      * @returns {Object}    center\r
581      */\r
582     getCenter: function getCenter(touches) {\r
583         var valuesX = [], valuesY = [];\r
584 \r
585         for(var t= 0,len=touches.length; t<len; t++) {\r
586             valuesX.push(touches[t].pageX);\r
587             valuesY.push(touches[t].pageY);\r
588         }\r
589 \r
590         return {\r
591             pageX: ((Math.min.apply(Math, valuesX) + Math.max.apply(Math, valuesX)) / 2),\r
592             pageY: ((Math.min.apply(Math, valuesY) + Math.max.apply(Math, valuesY)) / 2)\r
593         };\r
594     },\r
595 \r
596 \r
597     /**\r
598      * calculate the velocity between two points\r
599      * @param   {Number}    delta_time\r
600      * @param   {Number}    delta_x\r
601      * @param   {Number}    delta_y\r
602      * @returns {Object}    velocity\r
603      */\r
604     getVelocity: function getVelocity(delta_time, delta_x, delta_y) {\r
605         return {\r
606             x: Math.abs(delta_x / delta_time) || 0,\r
607             y: Math.abs(delta_y / delta_time) || 0\r
608         };\r
609     },\r
610 \r
611 \r
612     /**\r
613      * calculate the angle between two coordinates\r
614      * @param   {Touch}     touch1\r
615      * @param   {Touch}     touch2\r
616      * @returns {Number}    angle\r
617      */\r
618     getAngle: function getAngle(touch1, touch2) {\r
619         var y = touch2.pageY - touch1.pageY,\r
620             x = touch2.pageX - touch1.pageX;\r
621         return Math.atan2(y, x) * 180 / Math.PI;\r
622     },\r
623 \r
624 \r
625     /**\r
626      * angle to direction define\r
627      * @param   {Touch}     touch1\r
628      * @param   {Touch}     touch2\r
629      * @returns {String}    direction constant, like Hammer.DIRECTION_LEFT\r
630      */\r
631     getDirection: function getDirection(touch1, touch2) {\r
632         var x = Math.abs(touch1.pageX - touch2.pageX),\r
633             y = Math.abs(touch1.pageY - touch2.pageY);\r
634 \r
635         if(x >= y) {\r
636             return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;\r
637         }\r
638         else {\r
639             return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;\r
640         }\r
641     },\r
642 \r
643 \r
644     /**\r
645      * calculate the distance between two touches\r
646      * @param   {Touch}     touch1\r
647      * @param   {Touch}     touch2\r
648      * @returns {Number}    distance\r
649      */\r
650     getDistance: function getDistance(touch1, touch2) {\r
651         var x = touch2.pageX - touch1.pageX,\r
652             y = touch2.pageY - touch1.pageY;\r
653         return Math.sqrt((x*x) + (y*y));\r
654     },\r
655 \r
656 \r
657     /**\r
658      * calculate the scale factor between two touchLists (fingers)\r
659      * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out\r
660      * @param   {Array}     start\r
661      * @param   {Array}     end\r
662      * @returns {Number}    scale\r
663      */\r
664     getScale: function getScale(start, end) {\r
665         // need two fingers...\r
666         if(start.length >= 2 && end.length >= 2) {\r
667             return this.getDistance(end[0], end[1]) /\r
668                 this.getDistance(start[0], start[1]);\r
669         }\r
670         return 1;\r
671     },\r
672 \r
673 \r
674     /**\r
675      * calculate the rotation degrees between two touchLists (fingers)\r
676      * @param   {Array}     start\r
677      * @param   {Array}     end\r
678      * @returns {Number}    rotation\r
679      */\r
680     getRotation: function getRotation(start, end) {\r
681         // need two fingers\r
682         if(start.length >= 2 && end.length >= 2) {\r
683             return this.getAngle(end[1], end[0]) -\r
684                 this.getAngle(start[1], start[0]);\r
685         }\r
686         return 0;\r
687     },\r
688 \r
689 \r
690     /**\r
691      * boolean if the direction is vertical\r
692      * @param    {String}    direction\r
693      * @returns  {Boolean}   is_vertical\r
694      */\r
695     isVertical: function isVertical(direction) {\r
696         return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN);\r
697     },\r
698 \r
699 \r
700     /**\r
701      * stop browser default behavior with css props\r
702      * @param   {HtmlElement}   element\r
703      * @param   {Object}        css_props\r
704      */\r
705     stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) {\r
706         var prop,\r
707             vendors = ['webkit','khtml','moz','ms','o',''];\r
708 \r
709         if(!css_props || !element.style) {\r
710             return;\r
711         }\r
712 \r
713         // with css properties for modern browsers\r
714         for(var i = 0; i < vendors.length; i++) {\r
715             for(var p in css_props) {\r
716                 if(css_props.hasOwnProperty(p)) {\r
717                     prop = p;\r
718 \r
719                     // vender prefix at the property\r
720                     if(vendors[i]) {\r
721                         prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1);\r
722                     }\r
723 \r
724                     // set the style\r
725                     element.style[prop] = css_props[p];\r
726                 }\r
727             }\r
728         }\r
729 \r
730         // also the disable onselectstart\r
731         if(css_props.userSelect == 'none') {\r
732             element.onselectstart = function() {\r
733                 return false;\r
734             };\r
735         }\r
736     }\r
737 };\r
738 \r
739 Hammer.detection = {\r
740     // contains all registred Hammer.gestures in the correct order\r
741     gestures: [],\r
742 \r
743     // data of the current Hammer.gesture detection session\r
744     current: null,\r
745 \r
746     // the previous Hammer.gesture session data\r
747     // is a full clone of the previous gesture.current object\r
748     previous: null,\r
749 \r
750     // when this becomes true, no gestures are fired\r
751     stopped: false,\r
752 \r
753 \r
754     /**\r
755      * start Hammer.gesture detection\r
756      * @param   {Hammer.Instance}   inst\r
757      * @param   {Object}            eventData\r
758      */\r
759     startDetect: function startDetect(inst, eventData) {\r
760         // already busy with a Hammer.gesture detection on an element\r
761         if(this.current) {\r
762             return;\r
763         }\r
764 \r
765         this.stopped = false;\r
766 \r
767         this.current = {\r
768             inst        : inst, // reference to HammerInstance we're working for\r
769             startEvent  : Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc\r
770             lastEvent   : false, // last eventData\r
771             name        : '' // current gesture we're in/detected, can be 'tap', 'hold' etc\r
772         };\r
773 \r
774         this.detect(eventData);\r
775     },\r
776 \r
777 \r
778     /**\r
779      * Hammer.gesture detection\r
780      * @param   {Object}    eventData\r
781      * @param   {Object}    eventData\r
782      */\r
783     detect: function detect(eventData) {\r
784         if(!this.current || this.stopped) {\r
785             return;\r
786         }\r
787 \r
788         // extend event data with calculations about scale, distance etc\r
789         eventData = this.extendEventData(eventData);\r
790 \r
791         // instance options\r
792         var inst_options = this.current.inst.options;\r
793 \r
794         // call Hammer.gesture handlers\r
795         for(var g=0,len=this.gestures.length; g<len; g++) {\r
796             var gesture = this.gestures[g];\r
797 \r
798             // only when the instance options have enabled this gesture\r
799             if(!this.stopped && inst_options[gesture.name] !== false) {\r
800                 // if a handler returns false, we stop with the detection\r
801                 if(gesture.handler.call(gesture, eventData, this.current.inst) === false) {\r
802                     this.stopDetect();\r
803                     break;\r
804                 }\r
805             }\r
806         }\r
807 \r
808         // store as previous event event\r
809         if(this.current) {\r
810             this.current.lastEvent = eventData;\r
811         }\r
812 \r
813         // endevent, but not the last touch, so dont stop\r
814         if(eventData.eventType == Hammer.EVENT_END && !eventData.touches.length-1) {\r
815             this.stopDetect();\r
816         }\r
817 \r
818         return eventData;\r
819     },\r
820 \r
821 \r
822     /**\r
823      * clear the Hammer.gesture vars\r
824      * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected\r
825      * to stop other Hammer.gestures from being fired\r
826      */\r
827     stopDetect: function stopDetect() {\r
828         // clone current data to the store as the previous gesture\r
829         // used for the double tap gesture, since this is an other gesture detect session\r
830         this.previous = Hammer.utils.extend({}, this.current);\r
831 \r
832         // reset the current\r
833         this.current = null;\r
834 \r
835         // stopped!\r
836         this.stopped = true;\r
837     },\r
838 \r
839 \r
840     /**\r
841      * extend eventData for Hammer.gestures\r
842      * @param   {Object}   ev\r
843      * @returns {Object}   ev\r
844      */\r
845     extendEventData: function extendEventData(ev) {\r
846         var startEv = this.current.startEvent;\r
847 \r
848         // if the touches change, set the new touches over the startEvent touches\r
849         // this because touchevents don't have all the touches on touchstart, or the\r
850         // user must place his fingers at the EXACT same time on the screen, which is not realistic\r
851         // but, sometimes it happens that both fingers are touching at the EXACT same time\r
852         if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) {\r
853             // extend 1 level deep to get the touchlist with the touch objects\r
854             startEv.touches = [];\r
855             for(var i=0,len=ev.touches.length; i<len; i++) {\r
856                 startEv.touches.push(Hammer.utils.extend({}, ev.touches[i]));\r
857             }\r
858         }\r
859 \r
860         var delta_time = ev.timeStamp - startEv.timeStamp,\r
861             delta_x = ev.center.pageX - startEv.center.pageX,\r
862             delta_y = ev.center.pageY - startEv.center.pageY,\r
863             velocity = Hammer.utils.getVelocity(delta_time, delta_x, delta_y);\r
864 \r
865         Hammer.utils.extend(ev, {\r
866             deltaTime   : delta_time,\r
867 \r
868             deltaX      : delta_x,\r
869             deltaY      : delta_y,\r
870 \r
871             velocityX   : velocity.x,\r
872             velocityY   : velocity.y,\r
873 \r
874             distance    : Hammer.utils.getDistance(startEv.center, ev.center),\r
875             angle       : Hammer.utils.getAngle(startEv.center, ev.center),\r
876             direction   : Hammer.utils.getDirection(startEv.center, ev.center),\r
877 \r
878             scale       : Hammer.utils.getScale(startEv.touches, ev.touches),\r
879             rotation    : Hammer.utils.getRotation(startEv.touches, ev.touches),\r
880 \r
881             startEvent  : startEv\r
882         });\r
883 \r
884         return ev;\r
885     },\r
886 \r
887 \r
888     /**\r
889      * register new gesture\r
890      * @param   {Object}    gesture object, see gestures.js for documentation\r
891      * @returns {Array}     gestures\r
892      */\r
893     register: function register(gesture) {\r
894         // add an enable gesture options if there is no given\r
895         var options = gesture.defaults || {};\r
896         if(options[gesture.name] === undefined) {\r
897             options[gesture.name] = true;\r
898         }\r
899 \r
900         // extend Hammer default options with the Hammer.gesture options\r
901         Hammer.utils.extend(Hammer.defaults, options, true);\r
902 \r
903         // set its index\r
904         gesture.index = gesture.index || 1000;\r
905 \r
906         // add Hammer.gesture to the list\r
907         this.gestures.push(gesture);\r
908 \r
909         // sort the list by index\r
910         this.gestures.sort(function(a, b) {\r
911             if (a.index < b.index) {\r
912                 return -1;\r
913             }\r
914             if (a.index > b.index) {\r
915                 return 1;\r
916             }\r
917             return 0;\r
918         });\r
919 \r
920         return this.gestures;\r
921     }\r
922 };\r
923 \r
924 \r
925 Hammer.gestures = Hammer.gestures || {};\r
926 \r
927 /**\r
928  * Custom gestures\r
929  * ==============================\r
930  *\r
931  * Gesture object\r
932  * --------------------\r
933  * The object structure of a gesture:\r
934  *\r
935  * { name: 'mygesture',\r
936  *   index: 1337,\r
937  *   defaults: {\r
938  *     mygesture_option: true\r
939  *   }\r
940  *   handler: function(type, ev, inst) {\r
941  *     // trigger gesture event\r
942  *     inst.trigger(this.name, ev);\r
943  *   }\r
944  * }\r
945 \r
946  * @param   {String}    name\r
947  * this should be the name of the gesture, lowercase\r
948  * it is also being used to disable/enable the gesture per instance config.\r
949  *\r
950  * @param   {Number}    [index=1000]\r
951  * the index of the gesture, where it is going to be in the stack of gestures detection\r
952  * like when you build an gesture that depends on the drag gesture, it is a good\r
953  * idea to place it after the index of the drag gesture.\r
954  *\r
955  * @param   {Object}    [defaults={}]\r
956  * the default settings of the gesture. these are added to the instance settings,\r
957  * and can be overruled per instance. you can also add the name of the gesture,\r
958  * but this is also added by default (and set to true).\r
959  *\r
960  * @param   {Function}  handler\r
961  * this handles the gesture detection of your custom gesture and receives the\r
962  * following arguments:\r
963  *\r
964  *      @param  {Object}    eventData\r
965  *      event data containing the following properties:\r
966  *          timeStamp   {Number}        time the event occurred\r
967  *          target      {HTMLElement}   target element\r
968  *          touches     {Array}         touches (fingers, pointers, mouse) on the screen\r
969  *          pointerType {String}        kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH\r
970  *          center      {Object}        center position of the touches. contains pageX and pageY\r
971  *          deltaTime   {Number}        the total time of the touches in the screen\r
972  *          deltaX      {Number}        the delta on x axis we haved moved\r
973  *          deltaY      {Number}        the delta on y axis we haved moved\r
974  *          velocityX   {Number}        the velocity on the x\r
975  *          velocityY   {Number}        the velocity on y\r
976  *          angle       {Number}        the angle we are moving\r
977  *          direction   {String}        the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT\r
978  *          distance    {Number}        the distance we haved moved\r
979  *          scale       {Number}        scaling of the touches, needs 2 touches\r
980  *          rotation    {Number}        rotation of the touches, needs 2 touches *\r
981  *          eventType   {String}        matches Hammer.EVENT_START|MOVE|END\r
982  *          srcEvent    {Object}        the source event, like TouchStart or MouseDown *\r
983  *          startEvent  {Object}        contains the same properties as above,\r
984  *                                      but from the first touch. this is used to calculate\r
985  *                                      distances, deltaTime, scaling etc\r
986  *\r
987  *      @param  {Hammer.Instance}    inst\r
988  *      the instance we are doing the detection for. you can get the options from\r
989  *      the inst.options object and trigger the gesture event by calling inst.trigger\r
990  *\r
991  *\r
992  * Handle gestures\r
993  * --------------------\r
994  * inside the handler you can get/set Hammer.detection.current. This is the current\r
995  * detection session. It has the following properties\r
996  *      @param  {String}    name\r
997  *      contains the name of the gesture we have detected. it has not a real function,\r
998  *      only to check in other gestures if something is detected.\r
999  *      like in the drag gesture we set it to 'drag' and in the swipe gesture we can\r
1000  *      check if the current gesture is 'drag' by accessing Hammer.detection.current.name\r
1001  *\r
1002  *      @readonly\r
1003  *      @param  {Hammer.Instance}    inst\r
1004  *      the instance we do the detection for\r
1005  *\r
1006  *      @readonly\r
1007  *      @param  {Object}    startEvent\r
1008  *      contains the properties of the first gesture detection in this session.\r
1009  *      Used for calculations about timing, distance, etc.\r
1010  *\r
1011  *      @readonly\r
1012  *      @param  {Object}    lastEvent\r
1013  *      contains all the properties of the last gesture detect in this session.\r
1014  *\r
1015  * after the gesture detection session has been completed (user has released the screen)\r
1016  * the Hammer.detection.current object is copied into Hammer.detection.previous,\r
1017  * this is usefull for gestures like doubletap, where you need to know if the\r
1018  * previous gesture was a tap\r
1019  *\r
1020  * options that have been set by the instance can be received by calling inst.options\r
1021  *\r
1022  * You can trigger a gesture event by calling inst.trigger("mygesture", event).\r
1023  * The first param is the name of your gesture, the second the event argument\r
1024  *\r
1025  *\r
1026  * Register gestures\r
1027  * --------------------\r
1028  * When an gesture is added to the Hammer.gestures object, it is auto registered\r
1029  * at the setup of the first Hammer instance. You can also call Hammer.detection.register\r
1030  * manually and pass your gesture object as a param\r
1031  *\r
1032  */\r
1033 \r
1034 /**\r
1035  * Hold\r
1036  * Touch stays at the same place for x time\r
1037  * @events  hold\r
1038  */\r
1039 Hammer.gestures.Hold = {\r
1040     name: 'hold',\r
1041     index: 10,\r
1042     defaults: {\r
1043         hold_timeout    : 500,\r
1044         hold_threshold  : 1\r
1045     },\r
1046     timer: null,\r
1047     handler: function holdGesture(ev, inst) {\r
1048         switch(ev.eventType) {\r
1049             case Hammer.EVENT_START:\r
1050                 // clear any running timers\r
1051                 clearTimeout(this.timer);\r
1052 \r
1053                 // set the gesture so we can check in the timeout if it still is\r
1054                 Hammer.detection.current.name = this.name;\r
1055 \r
1056                 // set timer and if after the timeout it still is hold,\r
1057                 // we trigger the hold event\r
1058                 this.timer = setTimeout(function() {\r
1059                     if(Hammer.detection.current.name == 'hold') {\r
1060                         inst.trigger('hold', ev);\r
1061                     }\r
1062                 }, inst.options.hold_timeout);\r
1063                 break;\r
1064 \r
1065             // when you move or end we clear the timer\r
1066             case Hammer.EVENT_MOVE:\r
1067                 if(ev.distance > inst.options.hold_threshold) {\r
1068                     clearTimeout(this.timer);\r
1069                 }\r
1070                 break;\r
1071 \r
1072             case Hammer.EVENT_END:\r
1073                 clearTimeout(this.timer);\r
1074                 break;\r
1075         }\r
1076     }\r
1077 };\r
1078 \r
1079 \r
1080 /**\r
1081  * Tap/DoubleTap\r
1082  * Quick touch at a place or double at the same place\r
1083  * @events  tap, doubletap\r
1084  */\r
1085 Hammer.gestures.Tap = {\r
1086     name: 'tap',\r
1087     index: 100,\r
1088     defaults: {\r
1089         tap_max_touchtime       : 250,\r
1090         tap_max_distance        : 10,\r
1091                 tap_always                      : true,\r
1092         doubletap_distance      : 20,\r
1093         doubletap_interval      : 300\r
1094     },\r
1095     handler: function tapGesture(ev, inst) {\r
1096         if(ev.eventType == Hammer.EVENT_END) {\r
1097             // previous gesture, for the double tap since these are two different gesture detections\r
1098             var prev = Hammer.detection.previous,\r
1099                                 did_doubletap = false;\r
1100 \r
1101             // when the touchtime is higher then the max touch time\r
1102             // or when the moving distance is too much\r
1103             if(ev.deltaTime > inst.options.tap_max_touchtime ||\r
1104                 ev.distance > inst.options.tap_max_distance) {\r
1105                 return;\r
1106             }\r
1107 \r
1108             // check if double tap\r
1109             if(prev && prev.name == 'tap' &&\r
1110                 (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval &&\r
1111                 ev.distance < inst.options.doubletap_distance) {\r
1112                                 inst.trigger('doubletap', ev);\r
1113                                 did_doubletap = true;\r
1114             }\r
1115 \r
1116                         // do a single tap\r
1117                         if(!did_doubletap || inst.options.tap_always) {\r
1118                                 Hammer.detection.current.name = 'tap';\r
1119                                 inst.trigger(Hammer.detection.current.name, ev);\r
1120                         }\r
1121         }\r
1122     }\r
1123 };\r
1124 \r
1125 \r
1126 /**\r
1127  * Swipe\r
1128  * triggers swipe events when the end velocity is above the threshold\r
1129  * @events  swipe, swipeleft, swiperight, swipeup, swipedown\r
1130  */\r
1131 Hammer.gestures.Swipe = {\r
1132     name: 'swipe',\r
1133     index: 40,\r
1134     defaults: {\r
1135         // set 0 for unlimited, but this can conflict with transform\r
1136         swipe_max_touches  : 1,\r
1137         swipe_velocity     : 0.7\r
1138     },\r
1139     handler: function swipeGesture(ev, inst) {\r
1140         if(ev.eventType == Hammer.EVENT_END) {\r
1141             // max touches\r
1142             if(inst.options.swipe_max_touches > 0 &&\r
1143                 ev.touches.length > inst.options.swipe_max_touches) {\r
1144                 return;\r
1145             }\r
1146 \r
1147             // when the distance we moved is too small we skip this gesture\r
1148             // or we can be already in dragging\r
1149             if(ev.velocityX > inst.options.swipe_velocity ||\r
1150                 ev.velocityY > inst.options.swipe_velocity) {\r
1151                 // trigger swipe events\r
1152                 inst.trigger(this.name, ev);\r
1153                 inst.trigger(this.name + ev.direction, ev);\r
1154             }\r
1155         }\r
1156     }\r
1157 };\r
1158 \r
1159 \r
1160 /**\r
1161  * Drag\r
1162  * Move with x fingers (default 1) around on the page. Blocking the scrolling when\r
1163  * moving left and right is a good practice. When all the drag events are blocking\r
1164  * you disable scrolling on that area.\r
1165  * @events  drag, drapleft, dragright, dragup, dragdown\r
1166  */\r
1167 Hammer.gestures.Drag = {\r
1168     name: 'drag',\r
1169     index: 50,\r
1170     defaults: {\r
1171         drag_min_distance : 10,\r
1172         // set 0 for unlimited, but this can conflict with transform\r
1173         drag_max_touches  : 1,\r
1174         // prevent default browser behavior when dragging occurs\r
1175         // be careful with it, it makes the element a blocking element\r
1176         // when you are using the drag gesture, it is a good practice to set this true\r
1177         drag_block_horizontal   : false,\r
1178         drag_block_vertical     : false,\r
1179         // drag_lock_to_axis keeps the drag gesture on the axis that it started on,\r
1180         // It disallows vertical directions if the initial direction was horizontal, and vice versa.\r
1181         drag_lock_to_axis       : false,\r
1182         // drag lock only kicks in when distance > drag_lock_min_distance\r
1183         // This way, locking occurs only when the distance has become large enough to reliably determine the direction\r
1184         drag_lock_min_distance : 25\r
1185     },\r
1186     triggered: false,\r
1187     handler: function dragGesture(ev, inst) {\r
1188         // current gesture isnt drag, but dragged is true\r
1189         // this means an other gesture is busy. now call dragend\r
1190         if(Hammer.detection.current.name != this.name && this.triggered) {\r
1191             inst.trigger(this.name +'end', ev);\r
1192             this.triggered = false;\r
1193             return;\r
1194         }\r
1195 \r
1196         // max touches\r
1197         if(inst.options.drag_max_touches > 0 &&\r
1198             ev.touches.length > inst.options.drag_max_touches) {\r
1199             return;\r
1200         }\r
1201 \r
1202         switch(ev.eventType) {\r
1203             case Hammer.EVENT_START:\r
1204                 this.triggered = false;\r
1205                 break;\r
1206 \r
1207             case Hammer.EVENT_MOVE:\r
1208                 // when the distance we moved is too small we skip this gesture\r
1209                 // or we can be already in dragging\r
1210                 if(ev.distance < inst.options.drag_min_distance &&\r
1211                     Hammer.detection.current.name != this.name) {\r
1212                     return;\r
1213                 }\r
1214 \r
1215                 // we are dragging!\r
1216                 Hammer.detection.current.name = this.name;\r
1217 \r
1218                 // lock drag to axis?\r
1219                 if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance<=ev.distance)) {\r
1220                     ev.drag_locked_to_axis = true;\r
1221                 }\r
1222                 var last_direction = Hammer.detection.current.lastEvent.direction;\r
1223                 if(ev.drag_locked_to_axis && last_direction !== ev.direction) {\r
1224                     // keep direction on the axis that the drag gesture started on\r
1225                     if(Hammer.utils.isVertical(last_direction)) {\r
1226                         ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN;\r
1227                     }\r
1228                     else {\r
1229                         ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT;\r
1230                     }\r
1231                 }\r
1232 \r
1233                 // first time, trigger dragstart event\r
1234                 if(!this.triggered) {\r
1235                     inst.trigger(this.name +'start', ev);\r
1236                     this.triggered = true;\r
1237                 }\r
1238 \r
1239                 // trigger normal event\r
1240                 inst.trigger(this.name, ev);\r
1241 \r
1242                 // direction event, like dragdown\r
1243                 inst.trigger(this.name + ev.direction, ev);\r
1244 \r
1245                 // block the browser events\r
1246                 if( (inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) ||\r
1247                     (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) {\r
1248                     ev.preventDefault();\r
1249                 }\r
1250                 break;\r
1251 \r
1252             case Hammer.EVENT_END:\r
1253                 // trigger dragend\r
1254                 if(this.triggered) {\r
1255                     inst.trigger(this.name +'end', ev);\r
1256                 }\r
1257 \r
1258                 this.triggered = false;\r
1259                 break;\r
1260         }\r
1261     }\r
1262 };\r
1263 \r
1264 \r
1265 /**\r
1266  * Transform\r
1267  * User want to scale or rotate with 2 fingers\r
1268  * @events  transform, pinch, pinchin, pinchout, rotate\r
1269  */\r
1270 Hammer.gestures.Transform = {\r
1271     name: 'transform',\r
1272     index: 45,\r
1273     defaults: {\r
1274         // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1\r
1275         transform_min_scale     : 0.01,\r
1276         // rotation in degrees\r
1277         transform_min_rotation  : 1,\r
1278         // prevent default browser behavior when two touches are on the screen\r
1279         // but it makes the element a blocking element\r
1280         // when you are using the transform gesture, it is a good practice to set this true\r
1281         transform_always_block  : false\r
1282     },\r
1283     triggered: false,\r
1284     handler: function transformGesture(ev, inst) {\r
1285         // current gesture isnt drag, but dragged is true\r
1286         // this means an other gesture is busy. now call dragend\r
1287         if(Hammer.detection.current.name != this.name && this.triggered) {\r
1288             inst.trigger(this.name +'end', ev);\r
1289             this.triggered = false;\r
1290             return;\r
1291         }\r
1292 \r
1293         // atleast multitouch\r
1294         if(ev.touches.length < 2) {\r
1295             return;\r
1296         }\r
1297 \r
1298         // prevent default when two fingers are on the screen\r
1299         if(inst.options.transform_always_block) {\r
1300             ev.preventDefault();\r
1301         }\r
1302 \r
1303         switch(ev.eventType) {\r
1304             case Hammer.EVENT_START:\r
1305                 this.triggered = false;\r
1306                 break;\r
1307 \r
1308             case Hammer.EVENT_MOVE:\r
1309                 var scale_threshold = Math.abs(1-ev.scale);\r
1310                 var rotation_threshold = Math.abs(ev.rotation);\r
1311 \r
1312                 // when the distance we moved is too small we skip this gesture\r
1313                 // or we can be already in dragging\r
1314                 if(scale_threshold < inst.options.transform_min_scale &&\r
1315                     rotation_threshold < inst.options.transform_min_rotation) {\r
1316                     return;\r
1317                 }\r
1318 \r
1319                 // we are transforming!\r
1320                 Hammer.detection.current.name = this.name;\r
1321 \r
1322                 // first time, trigger dragstart event\r
1323                 if(!this.triggered) {\r
1324                     inst.trigger(this.name +'start', ev);\r
1325                     this.triggered = true;\r
1326                 }\r
1327 \r
1328                 inst.trigger(this.name, ev); // basic transform event\r
1329 \r
1330                 // trigger rotate event\r
1331                 if(rotation_threshold > inst.options.transform_min_rotation) {\r
1332                     inst.trigger('rotate', ev);\r
1333                 }\r
1334 \r
1335                 // trigger pinch event\r
1336                 if(scale_threshold > inst.options.transform_min_scale) {\r
1337                     inst.trigger('pinch', ev);\r
1338                     inst.trigger('pinch'+ ((ev.scale < 1) ? 'in' : 'out'), ev);\r
1339                 }\r
1340                 break;\r
1341 \r
1342             case Hammer.EVENT_END:\r
1343                 // trigger dragend\r
1344                 if(this.triggered) {\r
1345                     inst.trigger(this.name +'end', ev);\r
1346                 }\r
1347 \r
1348                 this.triggered = false;\r
1349                 break;\r
1350         }\r
1351     }\r
1352 };\r
1353 \r
1354 \r
1355 /**\r
1356  * Touch\r
1357  * Called as first, tells the user has touched the screen\r
1358  * @events  touch\r
1359  */\r
1360 Hammer.gestures.Touch = {\r
1361     name: 'touch',\r
1362     index: -Infinity,\r
1363     defaults: {\r
1364         // call preventDefault at touchstart, and makes the element blocking by\r
1365         // disabling the scrolling of the page, but it improves gestures like\r
1366         // transforming and dragging.\r
1367         // be careful with using this, it can be very annoying for users to be stuck\r
1368         // on the page\r
1369         prevent_default: false,\r
1370 \r
1371         // disable mouse events, so only touch (or pen!) input triggers events\r
1372         prevent_mouseevents: false\r
1373     },\r
1374     handler: function touchGesture(ev, inst) {\r
1375         if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) {\r
1376             ev.stopDetect();\r
1377             return;\r
1378         }\r
1379 \r
1380         if(inst.options.prevent_default) {\r
1381             ev.preventDefault();\r
1382         }\r
1383 \r
1384         if(ev.eventType ==  Hammer.EVENT_START) {\r
1385             inst.trigger(this.name, ev);\r
1386         }\r
1387     }\r
1388 };\r
1389 \r
1390 \r
1391 /**\r
1392  * Release\r
1393  * Called as last, tells the user has released the screen\r
1394  * @events  release\r
1395  */\r
1396 Hammer.gestures.Release = {\r
1397     name: 'release',\r
1398     index: Infinity,\r
1399     handler: function releaseGesture(ev, inst) {\r
1400         if(ev.eventType ==  Hammer.EVENT_END) {\r
1401             inst.trigger(this.name, ev);\r
1402         }\r
1403     }\r
1404 };\r
1405 \r
1406 // node export\r
1407 if(typeof module === 'object' && typeof module.exports === 'object'){\r
1408     module.exports = Hammer;\r
1409 }\r
1410 // just window export\r
1411 else {\r
1412     window.Hammer = Hammer;\r
1413 \r
1414     // requireJS module definition\r
1415     if(typeof window.define === 'function' && window.define.amd) {\r
1416         window.define('hammer', [], function() {\r
1417             return Hammer;\r
1418         });\r
1419     }\r
1420 }\r
1421 })(this);\r
1422 'use strict';\r
1423 \r
1424 angular.module('angular-gestures', []);\r
1425 \r
1426 /**\r
1427  * Inspired by AngularJS' implementation of "click dblclick mousedown..."\r
1428  *\r
1429  * This ties in the Hammer 1.0.0 events to attributes like:\r
1430  *\r
1431  * hm-tap="add_something()" hm-swipe="remove_something()"\r
1432  *\r
1433  * and also has support for Hammer options with:\r
1434  *\r
1435  * hm-tap-opts="{hold: false}"\r
1436  *\r
1437  * or any other of the "hm-event" listed underneath.\r
1438  */\r
1439 var HGESTURES = {\r
1440     hmDoubleTap : 'doubletap',\r
1441     hmDragstart : 'dragstart',\r
1442     hmDrag : 'drag',\r
1443     hmDragUp : 'dragup',\r
1444     hmDragDown : 'dragdown',\r
1445     hmDragLeft : 'dragleft',\r
1446     hmDragRight : 'dragright',\r
1447     hmDragend : 'dragend',\r
1448     hmHold : 'hold',\r
1449     hmPinch : 'pinch',\r
1450     hmPinchIn : 'pinchin',\r
1451     hmPinchOut : 'pinchout',\r
1452     hmRelease : 'release',\r
1453     hmRotate : 'rotate',\r
1454     hmSwipe : 'swipe',\r
1455     hmSwipeUp : 'swipeup',\r
1456     hmSwipeDown : 'swipedown',\r
1457     hmSwipeLeft : 'swipeleft',\r
1458     hmSwipeRight : 'swiperight',\r
1459     hmTap : 'tap',\r
1460     hmTouch : 'touch',\r
1461     hmTransformstart : 'transformstart',\r
1462     hmTransform : 'transform',\r
1463     hmTransformend : 'transformend'\r
1464 };\r
1465 \r
1466 var VERBOSE = false;\r
1467 \r
1468 angular.forEach(HGESTURES, function(eventName, directiveName) {\r
1469     angular.module('angular-gestures').directive(\r
1470             directiveName,\r
1471             ['$parse', '$log', '$timeout', function($parse, $log, $timeout) {\r
1472                 return function(scope, element, attr) {\r
1473                     var hammertime, handler;\r
1474                     attr.$observe(directiveName, function(value) {\r
1475                         var fn = $parse(value);\r
1476                         var opts = $parse(attr[directiveName + 'Opts'])\r
1477                         (scope, {});\r
1478                         hammertime = new Hammer(element[0], opts);\r
1479                         handler = function(event) {\r
1480                             if (VERBOSE) {\r
1481                                 $log.debug('angular-gestures: %s',\r
1482                                         eventName);\r
1483                             }\r
1484                             $timeout(function() {\r
1485                                 fn(scope, { $event : event });\r
1486                             }, 0);\r
1487                         };\r
1488                         hammertime.on(eventName, handler);\r
1489                     });\r
1490                     scope.$on('$destroy', function() {\r
1491                         hammertime.off(eventName, handler);\r
1492                     });\r
1493                 };\r
1494             }]);\r
1495 });\r