toolkit 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/lib/toolkit.rb +6 -0
  2. data/stylesheets/_toolkit.scss +24 -0
  3. data/stylesheets/toolkit/_border-box.scss +7 -0
  4. data/stylesheets/toolkit/_fluid-media.scss +36 -0
  5. data/stylesheets/toolkit/_progressive-enhancement.scss +57 -0
  6. data/templates/project/embeds.respond.js +37 -0
  7. data/templates/project/hammer.js +731 -0
  8. data/templates/project/ie.scss +28 -0
  9. data/templates/project/loader.js +4 -0
  10. data/templates/project/manifest.rb +68 -0
  11. data/templates/project/modernizr-2.5.3.js +726 -0
  12. data/templates/project/partials/design/_design.scss +9 -0
  13. data/templates/project/partials/design/_ie-design.scss +9 -0
  14. data/templates/project/partials/design/_print-design.scss +9 -0
  15. data/templates/project/partials/global/_base.scss +25 -0
  16. data/templates/project/partials/global/_extendables.scss +6 -0
  17. data/templates/project/partials/global/_functions.scss +5 -0
  18. data/templates/project/partials/global/_mixins.scss +5 -0
  19. data/templates/project/partials/global/_variables.scss +5 -0
  20. data/templates/project/partials/layout/_ie-layout.scss +9 -0
  21. data/templates/project/partials/layout/_layout.scss +9 -0
  22. data/templates/project/partials/layout/_print-layout.scss +9 -0
  23. data/templates/project/partials/styleguide/_style-guide.scss +10 -0
  24. data/templates/project/print.scss +28 -0
  25. data/templates/project/style.scss +27 -0
  26. data/templates/respond-to/embeds.respond.js +37 -0
  27. data/templates/respond-to/hammer.js +731 -0
  28. data/templates/respond-to/ie.scss +28 -0
  29. data/templates/respond-to/loader.js +4 -0
  30. data/templates/respond-to/manifest.rb +69 -0
  31. data/templates/respond-to/modernizr-2.5.3.js +726 -0
  32. data/templates/respond-to/partials/design/_design.scss +9 -0
  33. data/templates/respond-to/partials/design/_ie-design.scss +9 -0
  34. data/templates/respond-to/partials/design/_print-design.scss +9 -0
  35. data/templates/respond-to/partials/global/_base.scss +25 -0
  36. data/templates/respond-to/partials/global/_extendables.scss +6 -0
  37. data/templates/respond-to/partials/global/_functions.scss +5 -0
  38. data/templates/respond-to/partials/global/_mixins.scss +5 -0
  39. data/templates/respond-to/partials/global/_variables.scss +5 -0
  40. data/templates/respond-to/partials/layout/_ie-layout.scss +9 -0
  41. data/templates/respond-to/partials/layout/_layout.scss +9 -0
  42. data/templates/respond-to/partials/layout/_print-layout.scss +9 -0
  43. data/templates/respond-to/partials/styleguide/_style-guide.scss +10 -0
  44. data/templates/respond-to/print.scss +28 -0
  45. data/templates/respond-to/style.scss +27 -0
  46. metadata +151 -0
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // Design Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file.
7
+ //
8
+ // All styling, non box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // IE Design Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file. This is for Internet Explorer's Use.
7
+ //
8
+ // All styling, non box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // Print Design Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file. This is for Printed files.
7
+ //
8
+ // All styling, non box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,25 @@
1
+ ////////////////////////
2
+ // Base Partials
3
+ //
4
+ // These files will be shared across all three of your output
5
+ // CSS files. Generally included here are only Compass Extension
6
+ // imports and imports for variables, functions, mixins, and extendables.
7
+ ////////////////////////
8
+
9
+ ////////////////////////
10
+ // Compass Imports
11
+ ////////////////////////
12
+
13
+ ////////////////////////
14
+ // Compass Extensions
15
+ ////////////////////////
16
+ @import 'toolkit';
17
+ @import 'breakpoint';
18
+
19
+ ////////////////////////
20
+ // Private Imports
21
+ ////////////////////////
22
+ @import 'variables';
23
+ @import 'functions';
24
+ @import 'mixins';
25
+ @import 'extendables';
@@ -0,0 +1,6 @@
1
+ ////////////////////////
2
+ // Extendables Partials
3
+ //
4
+ // All of your extendable classes, ids, and silent extendables
5
+ // should go in this file.
6
+ ////////////////////////
@@ -0,0 +1,5 @@
1
+ ////////////////////////
2
+ // Functions Partials
3
+ //
4
+ // All of your functions should go in this file.
5
+ ////////////////////////
@@ -0,0 +1,5 @@
1
+ ////////////////////////
2
+ // Mixins Partials
3
+ //
4
+ // All of your mixins should go in this file.
5
+ ////////////////////////
@@ -0,0 +1,5 @@
1
+ ////////////////////////
2
+ // Variables Partials
3
+ //
4
+ // All of your variables should go in this file.
5
+ ////////////////////////
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // IE Layout Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file. This is for Internet Explorer's Use
7
+ //
8
+ // All box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // Layout Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file.
7
+ //
8
+ // All box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,9 @@
1
+ ////////////////////////
2
+ // Print Layout Partials
3
+ //
4
+ // Seperate your layout from design, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file. This is for Print files.
7
+ //
8
+ // All box model properties go here
9
+ ////////////////////////
@@ -0,0 +1,10 @@
1
+ ////////////////////////
2
+ // Style Guide Partials
3
+ //
4
+ // Write a Style Guide for your website, building sub folders and partials
5
+ // in this folder, with everything being imported, in casading order,
6
+ // into this file.
7
+ //
8
+ // All Style Guide selectors should go in here, regardless of layout or design
9
+ // (but separating the two in here is a good idea).
10
+ ////////////////////////
@@ -0,0 +1,28 @@
1
+ ////////////////////////
2
+ // Print File
3
+ //
4
+ // This file gets turned into style.css. This file should really
5
+ // hold nothing except for imports of your base, layout, and design
6
+ // partials, plus the mixins required to kickstart Aura and Style Guide.
7
+ // This file is styles specific to Printed files.
8
+ ////////////////////////
9
+
10
+ ////////////////////////
11
+ // Base Import
12
+ ////////////////////////
13
+ @import 'partials/global/base';
14
+
15
+ ////////////////////////
16
+ // Import Style Guide
17
+ ////////////////////////
18
+ @import 'partials/styleguide/style-guide';
19
+
20
+ ////////////////////////
21
+ // Import Layout
22
+ ////////////////////////
23
+ @import 'partials/layout/print-layout';
24
+
25
+ ////////////////////////
26
+ // Import Design
27
+ ////////////////////////
28
+ @import 'partials/design/print-design';
@@ -0,0 +1,27 @@
1
+ ////////////////////////
2
+ // Style File
3
+ //
4
+ // This file gets turned into style.css. This file should really
5
+ // hold nothing except for imports of your base, layout, and design
6
+ // partials, plus the mixins required to kickstart Aura and Style Guide.
7
+ ////////////////////////
8
+
9
+ ////////////////////////
10
+ // Base Import
11
+ ////////////////////////
12
+ @import 'partials/global/base';
13
+
14
+ ////////////////////////
15
+ // Import Style Guide
16
+ ////////////////////////
17
+ @import 'partials/styleguide/style-guide';
18
+
19
+ ////////////////////////
20
+ // Import Layout
21
+ ////////////////////////
22
+ @import 'partials/layout/layout';
23
+
24
+ ////////////////////////
25
+ // Import Design
26
+ ////////////////////////
27
+ @import 'partials/design/design';
@@ -0,0 +1,37 @@
1
+ jQuery(document).ready(function($) {
2
+ // Find all YouTube videos
3
+ var $allVideos = $("iframe[src^='http://player.vimeo.com'], iframe[src^='http://www.youtube.com']");
4
+
5
+ // The element that is fluid width
6
+ $fluidEl = $("#content");
7
+
8
+ // Figure out and save aspect ratio for each video
9
+ $allVideos.each(function() {
10
+
11
+ $(this)
12
+ .data('aspectRatio', this.height / this.width)
13
+
14
+ // and remove the hard coded width/height
15
+ .removeAttr('height')
16
+ .removeAttr('width');
17
+
18
+ });
19
+
20
+ // When the window is resized
21
+ $(window).resize(function() {
22
+
23
+ var newWidth = $fluidEl.width();
24
+
25
+ // Resize all videos according to their own aspect ratio
26
+ $allVideos.each(function() {
27
+
28
+ var $el = $(this);
29
+ $el
30
+ .width(newWidth)
31
+ .height(newWidth * $el.data('aspectRatio'));
32
+
33
+ });
34
+
35
+ // Kick off one resize to fix all videos on page load
36
+ }).resize();
37
+ });
@@ -0,0 +1,731 @@
1
+ /*
2
+ * Hammer.JS
3
+ * version 0.6.1
4
+ * author: Eight Media
5
+ * https://github.com/EightMedia/hammer.js
6
+ */
7
+ function Hammer(element, options, undefined)
8
+ {
9
+ var self = this;
10
+
11
+ var defaults = {
12
+ // prevent the default event or not... might be buggy when false
13
+ prevent_default : false,
14
+ css_hacks : true,
15
+
16
+ swipe : true,
17
+ swipe_time : 200, // ms
18
+ swipe_min_distance : 20, // pixels
19
+
20
+ drag : true,
21
+ drag_vertical : true,
22
+ drag_horizontal : true,
23
+ // minimum distance before the drag event starts
24
+ drag_min_distance : 20, // pixels
25
+
26
+ // pinch zoom and rotation
27
+ transform : true,
28
+ scale_treshold : 0.1,
29
+ rotation_treshold : 15, // degrees
30
+
31
+ tap : true,
32
+ tap_double : true,
33
+ tap_max_interval : 300,
34
+ tap_max_distance : 10,
35
+ tap_double_distance: 20,
36
+
37
+ hold : true,
38
+ hold_timeout : 500
39
+ };
40
+ options = mergeObject(defaults, options);
41
+
42
+ // some css hacks
43
+ (function() {
44
+ if(!options.css_hacks) {
45
+ return false;
46
+ }
47
+
48
+ var vendors = ['webkit','moz','ms','o',''];
49
+ var css_props = {
50
+ "userSelect": "none",
51
+ "touchCallout": "none",
52
+ "userDrag": "none",
53
+ "tapHighlightColor": "rgba(0,0,0,0)"
54
+ };
55
+
56
+ var prop = '';
57
+ for(var i = 0; i < vendors.length; i++) {
58
+ for(var p in css_props) {
59
+ prop = p;
60
+ if(vendors[i]) {
61
+ prop = vendors[i] + prop.substring(0, 1).toUpperCase() + prop.substring(1);
62
+ }
63
+ element.style[ prop ] = css_props[p];
64
+ }
65
+ }
66
+ })();
67
+
68
+ // holds the distance that has been moved
69
+ var _distance = 0;
70
+
71
+ // holds the exact angle that has been moved
72
+ var _angle = 0;
73
+
74
+ // holds the diraction that has been moved
75
+ var _direction = 0;
76
+
77
+ // holds position movement for sliding
78
+ var _pos = { };
79
+
80
+ // how many fingers are on the screen
81
+ var _fingers = 0;
82
+
83
+ var _first = false;
84
+
85
+ var _gesture = null;
86
+ var _prev_gesture = null;
87
+
88
+ var _touch_start_time = null;
89
+ var _prev_tap_pos = {x: 0, y: 0};
90
+ var _prev_tap_end_time = null;
91
+
92
+ var _hold_timer = null;
93
+
94
+ var _offset = {};
95
+
96
+ // keep track of the mouse status
97
+ var _mousedown = false;
98
+
99
+ var _event_start;
100
+ var _event_move;
101
+ var _event_end;
102
+
103
+ var _has_touch = ('ontouchstart' in window);
104
+
105
+
106
+ /**
107
+ * option setter/getter
108
+ * @param string key
109
+ * @param mixed value
110
+ * @return mixed value
111
+ */
112
+ this.option = function(key, val) {
113
+ if(val != undefined) {
114
+ options[key] = val;
115
+ }
116
+
117
+ return options[key];
118
+ };
119
+
120
+
121
+ /**
122
+ * angle to direction define
123
+ * @param float angle
124
+ * @return string direction
125
+ */
126
+ this.getDirectionFromAngle = function( angle )
127
+ {
128
+ var directions = {
129
+ down: angle >= 45 && angle < 135, //90
130
+ left: angle >= 135 || angle <= -135, //180
131
+ up: angle < -45 && angle > -135, //270
132
+ right: angle >= -45 && angle <= 45 //0
133
+ };
134
+
135
+ var direction, key;
136
+ for(key in directions){
137
+ if(directions[key]){
138
+ direction = key;
139
+ break;
140
+ }
141
+ }
142
+ return direction;
143
+ };
144
+
145
+
146
+ /**
147
+ * count the number of fingers in the event
148
+ * when no fingers are detected, one finger is returned (mouse pointer)
149
+ * @param event
150
+ * @return int fingers
151
+ */
152
+ function countFingers( event )
153
+ {
154
+ // there is a bug on android (until v4?) that touches is always 1,
155
+ // so no multitouch is supported, e.g. no, zoom and rotation...
156
+ return event.touches ? event.touches.length : 1;
157
+ }
158
+
159
+
160
+ /**
161
+ * get the x and y positions from the event object
162
+ * @param event
163
+ * @return array [{ x: int, y: int }]
164
+ */
165
+ function getXYfromEvent( event )
166
+ {
167
+ event = event || window.event;
168
+
169
+ // no touches, use the event pageX and pageY
170
+ if(!_has_touch) {
171
+ var doc = document,
172
+ body = doc.body;
173
+
174
+ return [{
175
+ x: event.pageX || event.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && doc.clientLeft || 0 ),
176
+ y: event.pageY || event.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && doc.clientTop || 0 )
177
+ }];
178
+ }
179
+ // multitouch, return array with positions
180
+ else {
181
+ var pos = [], src, touches = event.touches.length > 0 ? event.touches : event.changedTouches;
182
+ for(var t=0, len=touches.length; t<len; t++) {
183
+ src = touches[t];
184
+ pos.push({ x: src.pageX, y: src.pageY });
185
+ }
186
+ return pos;
187
+ }
188
+ }
189
+
190
+
191
+ /**
192
+ * calculate the angle between two points
193
+ * @param object pos1 { x: int, y: int }
194
+ * @param object pos2 { x: int, y: int }
195
+ */
196
+ function getAngle( pos1, pos2 )
197
+ {
198
+ return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x) * 180 / Math.PI;
199
+ }
200
+
201
+
202
+ /**
203
+ * calculate the scale size between two fingers
204
+ * @param object pos_start
205
+ * @param object pos_move
206
+ * @return float scale
207
+ */
208
+ function calculateScale(pos_start, pos_move)
209
+ {
210
+ if(pos_start.length == 2 && pos_move.length == 2) {
211
+ var x, y;
212
+
213
+ x = pos_start[0].x - pos_start[1].x;
214
+ y = pos_start[0].y - pos_start[1].y;
215
+ var start_distance = Math.sqrt((x*x) + (y*y));
216
+
217
+ x = pos_move[0].x - pos_move[1].x;
218
+ y = pos_move[0].y - pos_move[1].y;
219
+ var end_distance = Math.sqrt((x*x) + (y*y));
220
+
221
+ return end_distance / start_distance;
222
+ }
223
+
224
+ return 0;
225
+ }
226
+
227
+
228
+ /**
229
+ * calculate the rotation degrees between two fingers
230
+ * @param object pos_start
231
+ * @param object pos_move
232
+ * @return float rotation
233
+ */
234
+ function calculateRotation(pos_start, pos_move)
235
+ {
236
+ if(pos_start.length == 2 && pos_move.length == 2) {
237
+ var x, y;
238
+
239
+ x = pos_start[0].x - pos_start[1].x;
240
+ y = pos_start[0].y - pos_start[1].y;
241
+ var start_rotation = Math.atan2(y, x) * 180 / Math.PI;
242
+
243
+ x = pos_move[0].x - pos_move[1].x;
244
+ y = pos_move[0].y - pos_move[1].y;
245
+ var end_rotation = Math.atan2(y, x) * 180 / Math.PI;
246
+
247
+ return end_rotation - start_rotation;
248
+ }
249
+
250
+ return 0;
251
+ }
252
+
253
+
254
+ /**
255
+ * trigger an event/callback by name with params
256
+ * @param string name
257
+ * @param array params
258
+ */
259
+ function triggerEvent( eventName, params )
260
+ {
261
+ // return touches object
262
+ params.touches = getXYfromEvent(params.originalEvent);
263
+ params.type = eventName;
264
+
265
+ // trigger callback
266
+ if(isFunction(self["on"+ eventName])) {
267
+ self["on"+ eventName].call(self, params);
268
+ }
269
+ }
270
+
271
+
272
+ /**
273
+ * cancel event
274
+ * @param object event
275
+ * @return void
276
+ */
277
+
278
+ function cancelEvent(event)
279
+ {
280
+ event = event || window.event;
281
+ if(event.preventDefault){
282
+ event.preventDefault();
283
+ event.stopPropagation();
284
+ }else{
285
+ event.returnValue = false;
286
+ event.cancelBubble = true;
287
+ }
288
+ }
289
+
290
+
291
+ /**
292
+ * reset the internal vars to the start values
293
+ */
294
+ function reset()
295
+ {
296
+ _pos = {};
297
+ _first = false;
298
+ _fingers = 0;
299
+ _distance = 0;
300
+ _angle = 0;
301
+ _gesture = null;
302
+ }
303
+
304
+
305
+ var gestures = {
306
+ // hold gesture
307
+ // fired on touchstart
308
+ hold : function(event)
309
+ {
310
+ // only when one finger is on the screen
311
+ if(options.hold) {
312
+ _gesture = 'hold';
313
+ clearTimeout(_hold_timer);
314
+
315
+ _hold_timer = setTimeout(function() {
316
+ if(_gesture == 'hold') {
317
+ triggerEvent("hold", {
318
+ originalEvent : event,
319
+ position : _pos.start
320
+ });
321
+ }
322
+ }, options.hold_timeout);
323
+ }
324
+ },
325
+
326
+ // swipe gesture
327
+ // fired on touchend
328
+ swipe : function(event)
329
+ {
330
+ if(!_pos.move) {
331
+ return;
332
+ }
333
+
334
+ // get the distance we moved
335
+ var _distance_x = _pos.move[0].x - _pos.start[0].x;
336
+ var _distance_y = _pos.move[0].y - _pos.start[0].y;
337
+ _distance = Math.sqrt(_distance_x*_distance_x + _distance_y*_distance_y);
338
+
339
+ // compare the kind of gesture by time
340
+ var now = new Date().getTime();
341
+ var touch_time = now - _touch_start_time;
342
+
343
+ if(options.swipe && (options.swipe_time > touch_time) && (_distance > options.swipe_min_distance)) {
344
+ // calculate the angle
345
+ _angle = getAngle(_pos.start[0], _pos.move[0]);
346
+ _direction = self.getDirectionFromAngle(_angle);
347
+
348
+ _gesture = 'swipe';
349
+
350
+ var position = { x: _pos.move[0].x - _offset.left,
351
+ y: _pos.move[0].y - _offset.top };
352
+
353
+ var event_obj = {
354
+ originalEvent : event,
355
+ position : position,
356
+ direction : _direction,
357
+ distance : _distance,
358
+ distanceX : _distance_x,
359
+ distanceY : _distance_y,
360
+ angle : _angle
361
+ };
362
+
363
+ // normal slide event
364
+ triggerEvent("swipe", event_obj);
365
+ }
366
+ },
367
+
368
+
369
+ // drag gesture
370
+ // fired on mousemove
371
+ drag : function(event)
372
+ {
373
+ // get the distance we moved
374
+ var _distance_x = _pos.move[0].x - _pos.start[0].x;
375
+ var _distance_y = _pos.move[0].y - _pos.start[0].y;
376
+ _distance = Math.sqrt(_distance_x * _distance_x + _distance_y * _distance_y);
377
+
378
+ // drag
379
+ // minimal movement required
380
+ if(options.drag && (_distance > options.drag_min_distance) || _gesture == 'drag') {
381
+ // calculate the angle
382
+ _angle = getAngle(_pos.start[0], _pos.move[0]);
383
+ _direction = self.getDirectionFromAngle(_angle);
384
+
385
+ // check the movement and stop if we go in the wrong direction
386
+ var is_vertical = (_direction == 'up' || _direction == 'down');
387
+ if(((is_vertical && !options.drag_vertical) || (!is_vertical && !options.drag_horizontal))
388
+ && (_distance > options.drag_min_distance)) {
389
+ return;
390
+ }
391
+
392
+ _gesture = 'drag';
393
+
394
+ var position = { x: _pos.move[0].x - _offset.left,
395
+ y: _pos.move[0].y - _offset.top };
396
+
397
+ var event_obj = {
398
+ originalEvent : event,
399
+ position : position,
400
+ direction : _direction,
401
+ distance : _distance,
402
+ distanceX : _distance_x,
403
+ distanceY : _distance_y,
404
+ angle : _angle
405
+ };
406
+
407
+ // on the first time trigger the start event
408
+ if(_first) {
409
+ triggerEvent("dragstart", event_obj);
410
+
411
+ _first = false;
412
+ }
413
+
414
+ // normal slide event
415
+ triggerEvent("drag", event_obj);
416
+
417
+ cancelEvent(event);
418
+ }
419
+ },
420
+
421
+
422
+ // transform gesture
423
+ // fired on touchmove
424
+ transform : function(event)
425
+ {
426
+ if(options.transform) {
427
+ if(countFingers(event) != 2) {
428
+ return false;
429
+ }
430
+
431
+ var rotation = calculateRotation(_pos.start, _pos.move);
432
+ var scale = calculateScale(_pos.start, _pos.move);
433
+
434
+ if(_gesture != 'drag' &&
435
+ (_gesture == 'transform' || Math.abs(1-scale) > options.scale_treshold || Math.abs(rotation) > options.rotation_treshold)) {
436
+ _gesture = 'transform';
437
+
438
+ _pos.center = { x: ((_pos.move[0].x + _pos.move[1].x) / 2) - _offset.left,
439
+ y: ((_pos.move[0].y + _pos.move[1].y) / 2) - _offset.top };
440
+
441
+ var event_obj = {
442
+ originalEvent : event,
443
+ position : _pos.center,
444
+ scale : scale,
445
+ rotation : rotation
446
+ };
447
+
448
+ // on the first time trigger the start event
449
+ if(_first) {
450
+ triggerEvent("transformstart", event_obj);
451
+ _first = false;
452
+ }
453
+
454
+ triggerEvent("transform", event_obj);
455
+
456
+ cancelEvent(event);
457
+
458
+ return true;
459
+ }
460
+ }
461
+
462
+ return false;
463
+ },
464
+
465
+
466
+ // tap and double tap gesture
467
+ // fired on touchend
468
+ tap : function(event)
469
+ {
470
+ // compare the kind of gesture by time
471
+ var now = new Date().getTime();
472
+ var touch_time = now - _touch_start_time;
473
+
474
+ // dont fire when hold is fired
475
+ if(options.hold && !(options.hold && options.hold_timeout > touch_time)) {
476
+ return;
477
+ }
478
+
479
+ // when previous event was tap and the tap was max_interval ms ago
480
+ var is_double_tap = (function(){
481
+ if (_prev_tap_pos &&
482
+ options.tap_double &&
483
+ _prev_gesture == 'tap' &&
484
+ (_touch_start_time - _prev_tap_end_time) < options.tap_max_interval)
485
+ {
486
+ var x_distance = Math.abs(_prev_tap_pos[0].x - _pos.start[0].x);
487
+ var y_distance = Math.abs(_prev_tap_pos[0].y - _pos.start[0].y);
488
+ return (_prev_tap_pos && _pos.start && Math.max(x_distance, y_distance) < options.tap_double_distance);
489
+ }
490
+ return false;
491
+ })();
492
+
493
+ if(is_double_tap) {
494
+ _gesture = 'double_tap';
495
+ _prev_tap_end_time = null;
496
+
497
+ triggerEvent("doubletap", {
498
+ originalEvent : event,
499
+ position : _pos.start
500
+ });
501
+ cancelEvent(event);
502
+ }
503
+
504
+ // single tap is single touch
505
+ else {
506
+ var x_distance = (_pos.move) ? Math.abs(_pos.move[0].x - _pos.start[0].x) : 0;
507
+ var y_distance = (_pos.move) ? Math.abs(_pos.move[0].y - _pos.start[0].y) : 0;
508
+ _distance = Math.max(x_distance, y_distance);
509
+
510
+ if(_distance < options.tap_max_distance) {
511
+ _gesture = 'tap';
512
+ _prev_tap_end_time = now;
513
+ _prev_tap_pos = _pos.start;
514
+
515
+ if(options.tap) {
516
+ triggerEvent("tap", {
517
+ originalEvent : event,
518
+ position : _pos.start
519
+ });
520
+ cancelEvent(event);
521
+ }
522
+ }
523
+ }
524
+
525
+ }
526
+
527
+ };
528
+
529
+
530
+ function handleEvents(event)
531
+ {
532
+ switch(event.type)
533
+ {
534
+ case 'mousedown':
535
+ case 'touchstart':
536
+ _pos.start = getXYfromEvent(event);
537
+ _touch_start_time = new Date().getTime();
538
+ _fingers = countFingers(event);
539
+ _first = true;
540
+ _event_start = event;
541
+
542
+ // borrowed from jquery offset https://github.com/jquery/jquery/blob/master/src/offset.js
543
+ var box = element.getBoundingClientRect();
544
+ var clientTop = element.clientTop || document.body.clientTop || 0;
545
+ var clientLeft = element.clientLeft || document.body.clientLeft || 0;
546
+ var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop;
547
+ var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft;
548
+
549
+ _offset = {
550
+ top: box.top + scrollTop - clientTop,
551
+ left: box.left + scrollLeft - clientLeft
552
+ };
553
+
554
+ _mousedown = true;
555
+
556
+ // hold gesture
557
+ gestures.hold(event);
558
+
559
+ if(options.prevent_default) {
560
+ cancelEvent(event);
561
+ }
562
+ break;
563
+
564
+ case 'mousemove':
565
+ case 'touchmove':
566
+ if(!_mousedown) {
567
+ return false;
568
+ }
569
+ _event_move = event;
570
+ _pos.move = getXYfromEvent(event);
571
+
572
+ if(!gestures.transform(event)) {
573
+ gestures.drag(event);
574
+ }
575
+ break;
576
+
577
+ case 'mouseup':
578
+ case 'mouseout':
579
+ case 'touchcancel':
580
+ case 'touchend':
581
+ if(!_mousedown || (_gesture != 'transform' && event.touches && event.touches.length > 0)) {
582
+ return false;
583
+ }
584
+
585
+ _mousedown = false;
586
+ _event_end = event;
587
+
588
+ var dragging = _gesture == 'drag';
589
+
590
+ // swipe gesture
591
+ gestures.swipe(event);
592
+
593
+
594
+ // drag gesture
595
+ // dragstart is triggered, so dragend is possible
596
+ if(dragging) {
597
+ triggerEvent("dragend", {
598
+ originalEvent : event,
599
+ direction : _direction,
600
+ distance : _distance,
601
+ angle : _angle
602
+ });
603
+ }
604
+
605
+ // transform
606
+ // transformstart is triggered, so transformed is possible
607
+ else if(_gesture == 'transform') {
608
+ triggerEvent("transformend", {
609
+ originalEvent : event,
610
+ position : _pos.center,
611
+ scale : calculateScale(_pos.start, _pos.move),
612
+ rotation : calculateRotation(_pos.start, _pos.move)
613
+ });
614
+ }
615
+ else {
616
+ gestures.tap(_event_start);
617
+ }
618
+
619
+ _prev_gesture = _gesture;
620
+
621
+ // trigger release event
622
+ triggerEvent("release", {
623
+ originalEvent : event,
624
+ gesture : _gesture
625
+ });
626
+
627
+ // reset vars
628
+ reset();
629
+ break;
630
+ }
631
+ }
632
+
633
+
634
+ // bind events for touch devices
635
+ // except for windows phone 7.5, it doesnt support touch events..!
636
+ if(_has_touch) {
637
+ addEvent(element, "touchstart touchmove touchend touchcancel", handleEvents);
638
+ }
639
+ // for non-touch
640
+ else {
641
+ addEvent(element, "mouseup mousedown mousemove", handleEvents);
642
+ addEvent(element, "mouseout", function(event) {
643
+ if(!isInsideHammer(element, event.relatedTarget)) {
644
+ handleEvents(event);
645
+ }
646
+ });
647
+ }
648
+
649
+
650
+ /**
651
+ * find if element is (inside) given parent element
652
+ * @param object element
653
+ * @param object parent
654
+ * @return bool inside
655
+ */
656
+ function isInsideHammer(parent, child) {
657
+ // get related target for IE
658
+ if(!child && window.event && window.event.toElement){
659
+ child = window.event.toElement;
660
+ }
661
+
662
+ if(parent === child){
663
+ return true;
664
+ }
665
+
666
+ // loop over parentNodes of child until we find hammer element
667
+ if(child){
668
+ var node = child.parentNode;
669
+ while(node !== null){
670
+ if(node === parent){
671
+ return true;
672
+ };
673
+ node = node.parentNode;
674
+ }
675
+ }
676
+ return false;
677
+ }
678
+
679
+
680
+ /**
681
+ * merge 2 objects into a new object
682
+ * @param object obj1
683
+ * @param object obj2
684
+ * @return object merged object
685
+ */
686
+ function mergeObject(obj1, obj2) {
687
+ var output = {};
688
+
689
+ if(!obj2) {
690
+ return obj1;
691
+ }
692
+
693
+ for (var prop in obj1) {
694
+ if (prop in obj2) {
695
+ output[prop] = obj2[prop];
696
+ } else {
697
+ output[prop] = obj1[prop];
698
+ }
699
+ }
700
+ return output;
701
+ }
702
+
703
+
704
+ /**
705
+ * check if object is a function
706
+ * @param object obj
707
+ * @return bool is function
708
+ */
709
+ function isFunction( obj ){
710
+ return Object.prototype.toString.call( obj ) == "[object Function]";
711
+ }
712
+
713
+
714
+ /**
715
+ * attach event
716
+ * @param node element
717
+ * @param string types
718
+ * @param object callback
719
+ */
720
+ function addEvent(element, types, callback) {
721
+ types = types.split(" ");
722
+ for(var t= 0,len=types.length; t<len; t++) {
723
+ if(element.addEventListener){
724
+ element.addEventListener(types[t], callback, false);
725
+ }
726
+ else if(document.attachEvent){
727
+ element.attachEvent("on"+ types[t], callback);
728
+ }
729
+ }
730
+ }
731
+ }