parade 0.9.2 → 0.10.0

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