compass-aurora 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ require 'compass'
2
+ require 'toolkit'
3
+ require 'sassy-buttons'
4
+
5
+ extension_path = File.expand_path(File.join(File.dirname(__FILE__), ".."))
6
+ Compass::Frameworks.register('aurora', :path => extension_path)
7
+
8
+ module Aurora
9
+ VERSION = "0.1"
10
+ DATE = "2012-08-1"
11
+ end
@@ -0,0 +1,4 @@
1
+ @import 'toolkit';
2
+ @import 'singularitygs';
3
+ @import 'respond-to';
4
+ @import "sassy-buttons"
@@ -0,0 +1,4 @@
1
+ @import 'toolkit';
2
+ @import 'susy';
3
+ @import 'respond-to';
4
+ @import "sassy-buttons"
@@ -0,0 +1,28 @@
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
+ // Aurora includes @import 'compass' so you don't need to.
13
+ ////////////////////////
14
+
15
+ ////////////////////////
16
+ // Compass Extensions
17
+ //
18
+ // Aurora includes Toolkit, Breakpoint, Respond-to, Sassy Buttons, and Susy
19
+ ////////////////////////
20
+ @import 'aurora-susy';
21
+
22
+ ////////////////////////
23
+ // Private Imports
24
+ ////////////////////////
25
+ @import 'variables';
26
+ @import 'functions';
27
+ @import 'mixins';
28
+ @import 'extendables';
@@ -0,0 +1,75 @@
1
+ description "Responsive Web Design Kickstart"
2
+
3
+ # ERB ALL the Drupal files!
4
+ file '../shared/aurora.info.erb', :to => "#{options[:project_name] || File.basename(Compass.configuration.project_path)}.info", :erb => true
5
+
6
+ file '../shared/template.php.erb', :to => "template.php", :erb => true
7
+
8
+ # Stylesheets
9
+ file '../shared/style.scss', :like => :stylesheet, :media => 'screen, projection', :to => 'style.scss'
10
+
11
+ file '_base.scss', :like => :stylesheet, :to => 'partials/global/_base.scss'
12
+ file '../shared/_variables.scss', :like => :stylesheet, :to => 'partials/global/_variables.scss'
13
+ file '../shared/_functions.scss', :like => :stylesheet, :to => 'partials/global/_functions.scss'
14
+ file '../shared/_mixins.scss', :like => :stylesheet, :to => 'partials/global/_mixins.scss'
15
+ file '../shared/_extendables.scss', :like => :stylesheet, :to => 'partials/global/_extendables.scss'
16
+
17
+ file '../shared/_style-guide.scss', :like => :stylesheet, :to => 'partials/styleguide/_style-guide.scss'
18
+
19
+ file '../shared/_layout.scss', :like => :stylesheet, :to => 'partials/layout/_layout.scss'
20
+ file '../shared/_ie-layout.scss', :like => :stylesheet, :to => 'partials/layout/_ie-layout.scss'
21
+ file '../shared/_print-layout.scss', :like => :stylesheet, :to => 'partials/layout/_print-layout.scss'
22
+
23
+ file '../shared/_design.scss', :like => :stylesheet, :to => 'partials/design/_design.scss'
24
+ file '../shared/_ie-design.scss', :like => :stylesheet, :to => 'partials/design/_ie-design.scss'
25
+ file '../shared/_print-design.scss', :like => :stylesheet, :to => 'partials/design/_print-design.scss'
26
+
27
+ file '../shared/print.scss', :like => :stylesheet, :media => 'print', :to => 'print.scss'
28
+ file '../shared/ie.scss', :like => :stylesheet, :media => 'screen, projection', :condition => "lt IE 8", :to => 'ie.scss'
29
+
30
+ # JavaScript
31
+ file '../shared/hammer.js', :like => :javascript, :to => 'hammer.js'
32
+ file '../shared/loader.js', :like => :javascript, :to => 'loader.js'
33
+ file '../shared/modernizr-2.5.3.js', :like => :javascript, :to => 'modernizr-2.5.3.js'
34
+
35
+ help %Q{
36
+ Please contact Sam Richard with questions:
37
+
38
+ sam@snug.ug
39
+ }
40
+
41
+ welcome_message %Q{
42
+
43
+ Responsive Web Design Kickstart
44
+
45
+ Welcome to the Responsive Web Design Kickstart gem! Provided are the basic tools needed to kickstart a custom Responsive Web Design solution tailor made to your needs! Remember, tools and best practices are always changing, so keep up to date!
46
+
47
+ The following is included in this build:
48
+ Compass Extensions:
49
+ * Singularity
50
+ * Toolkit
51
+ * Respond-to
52
+
53
+ JavaScript:
54
+ * Modernizr Custom Build with all Standard features of 2.3.5 except html5shiv w/printshiv or Media Queries. Build your own from http://modernizr.com/download/ when you are ready for production
55
+ * Loader.js custom JavaScript file for holding conditional asset loading scripts thanks to Modernizr's yepnope (http://yepnopejs.com/). Comes with yepnope code for loading in Hammer.js, just make sure the path is correct from root.. Ready for production, but remember to minify and gzip!
56
+ * Hammer.js (http://eightmedia.github.com/hammer.js/) for awesome touch events. Ready for production, but remember to minify and gzip!
57
+
58
+ Include the following in your <head> tag:
59
+
60
+ <meta content='width=device-width, initial-scale=1.0' name='viewport' />
61
+ <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible' />
62
+ <!--[if lt IE 9 ]> <script src="//ajax.googleapis.com/ajax/libs/chrome-frame/1.0.2/CFInstall.min.js"></script><script>window.attachEvent("onload",function(){CFInstall.check({mode:"overlay"})})</script> <![endif]-->
63
+ <!-- CSS -->
64
+ <link href='path/to/css/style.css?v=1' rel='stylesheet' />
65
+ <!-- All JavaScript at the bottom, except for Modernizr and Respond/Selectivizr for IE 8 and Below. -->
66
+ <script src='path/to/js/modernizr-2.5.3.js'></script>
67
+
68
+ Include the following, and all other JavaScript, including any JavaScript frameworks you may be using like jQuery, right before your closing </body> tag:
69
+
70
+ <!-- Javascript at the bottom for fast page loading -->
71
+ <script src='path/to/js/loader.js'></script>
72
+
73
+
74
+ }
75
+
@@ -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,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,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
+ // 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,5 @@
1
+ ////////////////////////
2
+ // Mixins Partials
3
+ //
4
+ // All of your mixins should go in this file.
5
+ ////////////////////////
@@ -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,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,5 @@
1
+ ////////////////////////
2
+ // Variables Partials
3
+ //
4
+ // All of your variables should go in this file.
5
+ ////////////////////////
@@ -0,0 +1,20 @@
1
+ <% project_name = File.basename(Compass.configuration.project_path) %><% project_js = Compass.configuration.javascripts_dir %><% project_css = Compass.configuration.css_dir %>name = <%= project_name %>
2
+ description = <%= project_name %> theme based on the Aurora base theme.
3
+ core = 7.x
4
+ base theme = aurora
5
+
6
+ stylesheets[all][] = <%= project_css %>/style.css
7
+ stylesheets[print][] = <%= project_css %>/print.css
8
+ stylesheets-conditional[lt IE 9][all][] = <%= project_css %>/ie.css
9
+
10
+ regions[sidebar_first] = Primary Sidebar
11
+ regions[sidebar_second] = Secondary Sidebar
12
+ regions[content] = Content
13
+ regions[footer] = Footer
14
+ regions[header] = Header
15
+ regions[help] = Help
16
+ regions[highlighted] = Highlighted
17
+
18
+ settings[aurora_enable_chrome_frame] = 1
19
+ settings[aurora_min_ie_support] = 10
20
+ settings[aurora_footer_js] = 1
@@ -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
+ }