fabric-rails 1.0.12 → 1.0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/README.md +1 -1
  3. data/lib/fabric/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/event.js +1909 -0
  5. data/vendor/assets/javascripts/fabric.js +64 -16464
  6. data/vendor/assets/javascripts/fabric/HEADER.js +31 -0
  7. data/vendor/assets/javascripts/fabric/canvas.class.js +1007 -0
  8. data/vendor/assets/javascripts/fabric/canvas_animation.mixin.js +113 -0
  9. data/vendor/assets/javascripts/fabric/canvas_events.mixin.js +482 -0
  10. data/vendor/assets/javascripts/fabric/canvas_gestures.mixin.js +79 -0
  11. data/vendor/assets/javascripts/fabric/canvas_serialization.mixin.js +311 -0
  12. data/vendor/assets/javascripts/fabric/circle.class.js +182 -0
  13. data/vendor/assets/javascripts/fabric/color.class.js +284 -0
  14. data/vendor/assets/javascripts/fabric/ellipse.class.js +169 -0
  15. data/vendor/assets/javascripts/fabric/freedrawing.class.js +256 -0
  16. data/vendor/assets/javascripts/fabric/gradient.class.js +211 -0
  17. data/vendor/assets/javascripts/fabric/group.class.js +556 -0
  18. data/vendor/assets/javascripts/fabric/image.class.js +418 -0
  19. data/vendor/assets/javascripts/fabric/image_filters.js +809 -0
  20. data/vendor/assets/javascripts/fabric/intersection.class.js +178 -0
  21. data/vendor/assets/javascripts/fabric/line.class.js +188 -0
  22. data/vendor/assets/javascripts/fabric/log.js +26 -0
  23. data/vendor/assets/javascripts/fabric/node.js +149 -0
  24. data/vendor/assets/javascripts/fabric/object.class.js +1068 -0
  25. data/vendor/assets/javascripts/fabric/object_geometry.mixin.js +308 -0
  26. data/vendor/assets/javascripts/fabric/object_interactivity.mixin.js +496 -0
  27. data/vendor/assets/javascripts/fabric/object_origin.mixin.js +207 -0
  28. data/vendor/assets/javascripts/fabric/object_straightening.mixin.js +94 -0
  29. data/vendor/assets/javascripts/fabric/observable.mixin.js +91 -0
  30. data/vendor/assets/javascripts/fabric/parser.js +750 -0
  31. data/vendor/assets/javascripts/fabric/path.class.js +794 -0
  32. data/vendor/assets/javascripts/fabric/path_group.class.js +240 -0
  33. data/vendor/assets/javascripts/fabric/pattern.class.js +69 -0
  34. data/vendor/assets/javascripts/fabric/point.class.js +327 -0
  35. data/vendor/assets/javascripts/fabric/polygon.class.js +184 -0
  36. data/vendor/assets/javascripts/fabric/polyline.class.js +157 -0
  37. data/vendor/assets/javascripts/fabric/rect.class.js +298 -0
  38. data/vendor/assets/javascripts/fabric/scout.js +45 -0
  39. data/vendor/assets/javascripts/fabric/shadow.class.js +70 -0
  40. data/vendor/assets/javascripts/fabric/stateful.js +88 -0
  41. data/vendor/assets/javascripts/fabric/static_canvas.class.js +1298 -0
  42. data/vendor/assets/javascripts/fabric/text.class.js +934 -0
  43. data/vendor/assets/javascripts/fabric/triangle.class.js +108 -0
  44. data/vendor/assets/javascripts/fabric/util/anim_ease.js +360 -0
  45. data/vendor/assets/javascripts/fabric/util/dom_event.js +237 -0
  46. data/vendor/assets/javascripts/fabric/util/dom_misc.js +245 -0
  47. data/vendor/assets/javascripts/fabric/util/dom_request.js +72 -0
  48. data/vendor/assets/javascripts/fabric/util/dom_style.js +71 -0
  49. data/vendor/assets/javascripts/fabric/util/lang_array.js +250 -0
  50. data/vendor/assets/javascripts/fabric/util/lang_class.js +97 -0
  51. data/vendor/assets/javascripts/fabric/util/lang_function.js +35 -0
  52. data/vendor/assets/javascripts/fabric/util/lang_object.js +34 -0
  53. data/vendor/assets/javascripts/fabric/util/lang_string.js +60 -0
  54. data/vendor/assets/javascripts/fabric/util/misc.js +406 -0
  55. data/vendor/assets/javascripts/json2.js +491 -0
  56. metadata +53 -2
@@ -1,3 +1,11 @@
1
+ ## 1.0.12.1 (28 February 2013)
2
+
3
+ - now use fabric.js source files and compile as needed via sprockets
4
+
5
+ ## 1.0.12 (21 February 2013)
6
+
7
+ - fabric.js version 1.0.12
8
+
1
9
  ## 1.0.11 (19 February 2013)
2
10
 
3
11
  - fabric.js version 1.0.11
@@ -6,6 +14,14 @@
6
14
 
7
15
  - fabric.js version 1.0.10
8
16
 
17
+ ## 0.9.17 (19 February 2013)
18
+
19
+ - fabric.js version 0.9.17
20
+
21
+ ## 0.9.16 (19 February 2013)
22
+
23
+ - fabric.js version 0.9.16
24
+
9
25
  ## 0.0.8 (19 September 2012)
10
26
 
11
27
  - fabric.js version 0.9.8
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  This gem provides:
6
6
 
7
- * fabric.js 0.9.8
7
+ * fabric.js 1.0.12
8
8
 
9
9
  ## Installation
10
10
 
@@ -1,6 +1,6 @@
1
1
  module Fabric
2
2
  module Rails
3
- VERSION = "1.0.12"
4
- FABRIC_VERSION = "1.0.12"
3
+ VERSION = "1.0.12.1"
4
+ FABRIC_VERSION = "1.0.12.1"
5
5
  end
6
6
  end
@@ -0,0 +1,1909 @@
1
+ if (typeof document == 'undefined' && typeof navigator == 'undefined') {
2
+ var document = fabric.document;
3
+ var navigator = fabric.window.navigator;
4
+ }
5
+
6
+ /*
7
+ ----------------------------------------------------
8
+ Event.js : 1.1.1 : 2012/11/19 : MIT License
9
+ ----------------------------------------------------
10
+ https://github.com/mudcube/Event.js
11
+ ----------------------------------------------------
12
+ 1 : click, dblclick, dbltap
13
+ 1+ : tap, longpress, drag, swipe
14
+ 2+ : pinch, rotate
15
+ : mousewheel, devicemotion, shake
16
+ ----------------------------------------------------
17
+ TODO
18
+ ----------------------------------------------------
19
+ * switch configuration to 4th argument on addEventListener
20
+ * bbox calculation for elements scaled with transform.
21
+ ----------------------------------------------------
22
+ NOTES
23
+ ----------------------------------------------------
24
+ * When using other libraries that may have built in "Event" namespace,
25
+ i.e. Typescript, you can use "eventjs" instead of "Event" for all example calls.
26
+ ----------------------------------------------------
27
+ REQUIREMENTS: querySelector, querySelectorAll
28
+ ----------------------------------------------------
29
+ * There are two ways to add/remove events with this library.
30
+ ----------------------------------------------------
31
+ // Retains "this" attribute as target, and overrides native addEventListener.
32
+ target.addEventListener(type, listener, useCapture);
33
+ target.removeEventListener(type, listener, useCapture);
34
+
35
+ // Attempts to perform as fast as possible.
36
+ Event.add(type, listener, configure);
37
+ Event.remove(type, listener, configure);
38
+
39
+ * You can turn prototyping on/off for individual features.
40
+ ----------------------------------------------------
41
+ Event.modifyEventListener = true; // add custom *EventListener commands to HTMLElements.
42
+ Event.modifySelectors = true; // add bulk *EventListener commands on NodeLists from querySelectorAll and others.
43
+
44
+ * Example of setting up a single listener with a custom configuration.
45
+ ----------------------------------------------------
46
+ // optional configuration.
47
+ var configure = {
48
+ fingers: 2, // listen for specifically two fingers.
49
+ snap: 90 // snap to 90 degree intervals.
50
+ };
51
+ // adding with addEventListener()
52
+ target.addEventListener("swipe", function(event) {
53
+ // additional variables can be found on the event object.
54
+ console.log(event.velocity, event.angle, event.fingers);
55
+ }, configure);
56
+
57
+ // adding with Event.add()
58
+ Event.add("swipe", function(event, self) {
59
+ // additional variables can be found on the self object.
60
+ console.log(self.velocity, self.angle, self.fingers);
61
+ }, configure);
62
+
63
+ * Multiple listeners glued together.
64
+ ----------------------------------------------------
65
+ // adding with addEventListener()
66
+ target.addEventListener("click swipe", function(event) { });
67
+
68
+ // adding with Event.add()
69
+ Event.add(target, "click swipe", function(event, self) { });
70
+
71
+ * Use query selectors to create an event (querySelectorAll)
72
+ ----------------------------------------------------
73
+ // adding events to NodeList from querySelectorAll()
74
+ document.querySelectorAll("#element a.link").addEventListener("click", callback);
75
+
76
+ // adding with Event.add()
77
+ Event.add("#element a.link", "click", callback);
78
+
79
+ * Listen for selector to become available (querySelector)
80
+ ----------------------------------------------------
81
+ Event.add("body", "ready", callback);
82
+ // or...
83
+ Event.add({
84
+ target: "body",
85
+ type: "ready",
86
+ timeout: 10000, // set a timeout to stop checking.
87
+ interval: 30, // set how often to check for element.
88
+ listener: callback
89
+ });
90
+
91
+ * Multiple listeners bound to one callback w/ single configuration.
92
+ ----------------------------------------------------
93
+ var bindings = Event.add({
94
+ target: target,
95
+ type: "click swipe",
96
+ snap: 90, // snap to 90 degree intervals.
97
+ minFingers: 2, // minimum required fingers to start event.
98
+ maxFingers: 4, // maximum fingers in one event.
99
+ listener: function(event, self) {
100
+ console.log(self.gesture); // will be click or swipe.
101
+ console.log(self.x);
102
+ console.log(self.y);
103
+ console.log(self.identifier);
104
+ console.log(self.start);
105
+ console.log(self.fingers); // somewhere between "2" and "4".
106
+ self.pause(); // disable event.
107
+ self.resume(); // enable event.
108
+ self.remove(); // remove event.
109
+ }
110
+ });
111
+
112
+ * Multiple listeners bound to multiple callbacks w/ single configuration.
113
+ ----------------------------------------------------
114
+ var bindings = Event.add({
115
+ target: target,
116
+ minFingers: 1,
117
+ maxFingers: 12,
118
+ listeners: {
119
+ click: function(event, self) {
120
+ self.remove(); // removes this click listener.
121
+ },
122
+ swipe: function(event, self) {
123
+ binding.remove(); // removes both the click + swipe listeners.
124
+ }
125
+ }
126
+ });
127
+
128
+ * Multiple listeners bound to multiple callbacks w/ multiple configurations.
129
+ ----------------------------------------------------
130
+ var binding = Event.add({
131
+ target: target,
132
+ listeners: {
133
+ longpress: {
134
+ fingers: 1,
135
+ wait: 500, // milliseconds
136
+ listener: function(event, self) {
137
+ console.log(self.fingers); // "1" finger.
138
+ }
139
+ },
140
+ drag: {
141
+ fingers: 3,
142
+ position: "relative", // "relative", "absolute", "difference", "move"
143
+ listener: function(event, self) {
144
+ console.log(self.fingers); // "3" fingers.
145
+ console.log(self.x); // coordinate is relative to edge of target.
146
+ }
147
+ }
148
+ }
149
+ });
150
+
151
+ * Capturing an event and manually forwarding it to a proxy (tiered events).
152
+ ----------------------------------------------------
153
+ Event.add(target, "down", function(event, self) {
154
+ var x = event.pageX; // local variables that wont change.
155
+ var y = event.pageY;
156
+ Event.proxy.drag({
157
+ event: event,
158
+ target: target,
159
+ listener: function(event, self) {
160
+ console.log(x - event.pageX); // measure movement.
161
+ console.log(y - event.pageY);
162
+ }
163
+ });
164
+ });
165
+ ----------------------------------------------------
166
+
167
+ * Event proxies.
168
+ * type, fingers, state, start, x, y, position, bbox
169
+ * rotation, scale, velocity, angle, delay, timeout
170
+ ----------------------------------------------------
171
+ // "Click" :: fingers, minFingers, maxFingers.
172
+ Event.add(window, "click", function(event, self) {
173
+ console.log(self.gesture, self.x, self.y);
174
+ });
175
+ // "Double-Click" :: fingers, minFingers, maxFingers.
176
+ Event.add(window, "dblclick", function(event, self) {
177
+ console.log(self.gesture, self.x, self.y);
178
+ });
179
+ // "Drag" :: fingers, maxFingers, position
180
+ Event.add(window, "drag", function(event, self) {
181
+ console.log(self.gesture, self.fingers, self.state, self.start, self.x, self.y, self.bbox);
182
+ });
183
+ // "Gesture" :: fingers, minFingers, maxFingers.
184
+ Event.add(window, "gesture", function(event, self) {
185
+ console.log(self.gesture, self.fingers, self.state, self.rotation, self.scale);
186
+ });
187
+ // "Swipe" :: fingers, minFingers, maxFingers, snap, threshold.
188
+ Event.add(window, "swipe", function(event, self) {
189
+ console.log(self.gesture, self.fingers, self.velocity, self.angle, self.start, self.x, self.y);
190
+ });
191
+ // "Tap" :: fingers, minFingers, maxFingers, timeout.
192
+ Event.add(window, "tap", function(event, self) {
193
+ console.log(self.gesture, self.fingers);
194
+ });
195
+ // "Longpress" :: fingers, minFingers, maxFingers, delay.
196
+ Event.add(window, "longpress", function(event, self) {
197
+ console.log(self.gesture, self.fingers);
198
+ });
199
+ //
200
+ Event.add(window, "shake", function(event, self) {
201
+ console.log(self.gesture, self.acceleration, self.accelerationIncludingGravity);
202
+ });
203
+ //
204
+ Event.add(window, "devicemotion", function(event, self) {
205
+ console.log(self.gesture, self.acceleration, self.accelerationIncludingGravity);
206
+ });
207
+ //
208
+ Event.add(window, "wheel", function(event, self) {
209
+ console.log(self.gesture, self.state, self.wheelDelta);
210
+ });
211
+
212
+ * Stop, prevent and cancel.
213
+ ----------------------------------------------------
214
+ Event.stop(event); // stop bubble.
215
+ Event.prevent(event); // prevent default.
216
+ Event.cancel(event); // stop and prevent.
217
+
218
+ * Track for proper command/control-key for Mac/PC.
219
+ ----------------------------------------------------
220
+ Event.add(window, "keyup keydown", Event.proxy.metaTracker);
221
+ console.log(Event.proxy.metaKey);
222
+
223
+ * Test for event features, in this example Drag & Drop file support.
224
+ ----------------------------------------------------
225
+ console.log(Event.supports('dragstart') && Event.supports('drop') && !!window.FileReader);
226
+
227
+ */
228
+
229
+ if (typeof(Event) === "undefined")
230
+ var Event = {};
231
+ if (typeof(eventjs) === "undefined")
232
+ var eventjs = Event;
233
+
234
+ Event = (function(root) {
235
+ "use strict";
236
+
237
+ // Add custom *EventListener commands to HTMLElements.
238
+ root.modifyEventListener = false;
239
+
240
+ // Add bulk *EventListener commands on NodeLists from querySelectorAll and others.
241
+ root.modifySelectors = false;
242
+
243
+ // Event maintenance.
244
+ root.add = function(target, type, listener, configure) {
245
+ return eventManager(target, type, listener, configure, "add");
246
+ };
247
+
248
+ root.remove = function(target, type, listener, configure) {
249
+ return eventManager(target, type, listener, configure, "remove");
250
+ };
251
+
252
+ root.stop = function(event) {
253
+ if (event.stopPropagation)
254
+ event.stopPropagation();
255
+ event.cancelBubble = true; // <= IE8
256
+ event.bubble = 0;
257
+ };
258
+
259
+ root.prevent = function(event) {
260
+ if (event.preventDefault)
261
+ event.preventDefault();
262
+ event.returnValue = false; // <= IE8
263
+ };
264
+
265
+ root.cancel = function(event) {
266
+ root.stop(event);
267
+ root.prevent(event);
268
+ };
269
+
270
+ // Check whether event is natively supported (via @kangax)
271
+ root.supports = function(target, type) {
272
+ if (typeof(target) === "string") {
273
+ type = target;
274
+ target = window;
275
+ }
276
+ type = "on" + type;
277
+ if (type in target)
278
+ return true;
279
+ if (!target.setAttribute)
280
+ target = document.createElement("div");
281
+ if (target.setAttribute && target.removeAttribute) {
282
+ target.setAttribute(type, "");
283
+ var isSupported = typeof target[type] === "function";
284
+ if (typeof target[type] !== "undefined")
285
+ target[type] = null;
286
+ target.removeAttribute(type);
287
+ return isSupported;
288
+ }
289
+ };
290
+
291
+ var clone = function(obj) {
292
+ if (!obj || typeof (obj) !== 'object')
293
+ return obj;
294
+ var temp = new obj.constructor();
295
+ for (var key in obj) {
296
+ if (!obj[key] || typeof (obj[key]) !== 'object') {
297
+ temp[key] = obj[key];
298
+ } else { // clone sub-object
299
+ temp[key] = clone(obj[key]);
300
+ }
301
+ }
302
+ return temp;
303
+ };
304
+
305
+ /// Handle custom *EventListener commands.
306
+ var eventManager = function(target, type, listener, configure, trigger, fromOverwrite) {
307
+ configure = configure || {};
308
+ // Check for element to load on interval (before onload).
309
+ if (typeof(target) === "string" && type === "ready") {
310
+ var time = (new Date()).getTime();
311
+ var timeout = configure.timeout;
312
+ var ms = configure.interval || 1000 / 60;
313
+ var interval = window.setInterval(function() {
314
+ if ((new Date()).getTime() - time > timeout) {
315
+ window.clearInterval(interval);
316
+ }
317
+ if (document.querySelector(target)) {
318
+ window.clearInterval(interval);
319
+ listener();
320
+ }
321
+ }, ms);
322
+ return;
323
+ }
324
+ // Get DOM element from Query Selector.
325
+ if (typeof(target) === "string") {
326
+ target = document.querySelectorAll(target);
327
+ if (target.length === 0)
328
+ return createError("Missing target on listener!"); // No results.
329
+ if (target.length === 1) { // Single target.
330
+ target = target[0];
331
+ }
332
+ }
333
+ /// Handle multiple targets.
334
+ var event;
335
+ var events = {};
336
+ if (target.length > 0) {
337
+ for (var n0 = 0, length0 = target.length; n0 < length0; n0++) {
338
+ event = eventManager(target[n0], type, listener, clone(configure), trigger);
339
+ if (event)
340
+ events[n0] = event;
341
+ }
342
+ return createBatchCommands(events);
343
+ }
344
+ // Check for multiple events in one string.
345
+ if (type.indexOf && type.indexOf(" ") !== -1)
346
+ type = type.split(" ");
347
+ if (type.indexOf && type.indexOf(",") !== -1)
348
+ type = type.split(",");
349
+ // Attach or remove multiple events associated with a target.
350
+ if (typeof(type) !== "string") { // Has multiple events.
351
+ if (typeof(type.length) === "number") { // Handle multiple listeners glued together.
352
+ for (var n1 = 0, length1 = type.length; n1 < length1; n1++) { // Array [type]
353
+ event = eventManager(target, type[n1], listener, clone(configure), trigger);
354
+ if (event)
355
+ events[type[n1]] = event;
356
+ }
357
+ } else { // Handle multiple listeners.
358
+ for (var key in type) { // Object {type}
359
+ if (typeof(type[key]) === "function") { // without configuration.
360
+ event = eventManager(target, key, type[key], clone(configure), trigger);
361
+ } else { // with configuration.
362
+ event = eventManager(target, key, type[key].listener, clone(type[key]), trigger);
363
+ }
364
+ if (event)
365
+ events[key] = event;
366
+ }
367
+ }
368
+ return createBatchCommands(events);
369
+ }
370
+ // Ensure listener is a function.
371
+ if (typeof(listener) !== "function")
372
+ return createError("Listener is not a function!");
373
+ // Generate a unique wrapper identifier.
374
+ var useCapture = configure.useCapture || false;
375
+ var id = normalize(type) + getID(target) + "." + getID(listener) + "." + (useCapture ? 1 : 0);
376
+ // Handle the event.
377
+ if (root.Gesture && root.Gesture._gestureHandlers[type]) { // Fire custom event.
378
+ if (trigger === "remove") { // Remove event listener.
379
+ if (!wrappers[id])
380
+ return; // Already removed.
381
+ wrappers[id].remove();
382
+ delete wrappers[id];
383
+ } else if (trigger === "add") { // Attach event listener.
384
+ if (wrappers[id])
385
+ return wrappers[id]; // Already attached.
386
+ // Retains "this" orientation.
387
+ if (configure.useCall && !root.modifyEventListener) {
388
+ var tmp = listener;
389
+ listener = function(event, self) {
390
+ for (var key in self)
391
+ event[key] = self[key];
392
+ return tmp.call(target, event);
393
+ };
394
+ }
395
+ // Create listener proxy.
396
+ configure.gesture = type;
397
+ configure.target = target;
398
+ configure.listener = listener;
399
+ configure.fromOverwrite = fromOverwrite;
400
+ // Record wrapper.
401
+ wrappers[id] = root.proxy[type](configure);
402
+ }
403
+ } else { // Fire native event.
404
+ type = normalize(type);
405
+ if (trigger === "remove") { // Remove event listener.
406
+ if (!wrappers[id])
407
+ return; // Already removed.
408
+ target[remove](type, listener, useCapture);
409
+ delete wrappers[id];
410
+ } else if (trigger === "add") { // Attach event listener.
411
+ if (wrappers[id])
412
+ return wrappers[id]; // Already attached.
413
+ target[add](type, listener, useCapture);
414
+ // Record wrapper.
415
+ wrappers[id] = {
416
+ type: type,
417
+ target: target,
418
+ listener: listener,
419
+ remove: function() {
420
+ root.remove(target, type, listener, configure);
421
+ }
422
+ };
423
+ }
424
+ }
425
+ return wrappers[id];
426
+ };
427
+
428
+ /// Perform batch actions on multiple events.
429
+ var createBatchCommands = function(events) {
430
+ return {
431
+ remove: function() { // Remove multiple events.
432
+ for (var key in events) {
433
+ events[key].remove();
434
+ }
435
+ },
436
+ add: function() { // Add multiple events.
437
+ for (var key in events) {
438
+ events[key].add();
439
+ }
440
+ }
441
+ };
442
+ };
443
+
444
+ /// Display error message in console.
445
+ var createError = function(message) {
446
+ if (typeof(console) === "undefined")
447
+ return;
448
+ if (typeof(console.error) === "undefined")
449
+ return;
450
+ console.error(message);
451
+ };
452
+
453
+ /// Handle naming discrepancies between platforms.
454
+ var normalize = (function() {
455
+ var translate = {};
456
+ return function(type) {
457
+ if (!root.pointerType) {
458
+ if (window.navigator.msPointerEnabled) {
459
+ root.pointerType = "mspointer";
460
+ translate = {
461
+ "mousedown": "MSPointerDown",
462
+ "mousemove": "MSPointerMove",
463
+ "mouseup": "MSPointerUp"
464
+ };
465
+ } else if (root.supports("touchstart")) {
466
+ root.pointerType = "touch";
467
+ translate = {
468
+ "mousedown": "touchstart",
469
+ "mouseup": "touchend",
470
+ "mousemove": "touchmove"
471
+ };
472
+ } else {
473
+ root.pointerType = "mouse";
474
+ }
475
+ }
476
+ if (translate[type])
477
+ type = translate[type];
478
+ if (!document.addEventListener) { // IE
479
+ return "on" + type;
480
+ } else {
481
+ return type;
482
+ }
483
+ };
484
+ })();
485
+
486
+ /// Event wrappers to keep track of all events placed in the window.
487
+ var wrappers = {};
488
+ var counter = 0;
489
+ var getID = function(object) {
490
+ if (object === window)
491
+ return "#window";
492
+ if (object === document)
493
+ return "#document";
494
+ if (!object)
495
+ return createError("Missing target on listener!");
496
+ if (!object.uniqueID)
497
+ object.uniqueID = "id" + counter++;
498
+ return object.uniqueID;
499
+ };
500
+
501
+ /// Detect platforms native *EventListener command.
502
+ var add = document.addEventListener ? "addEventListener" : "attachEvent";
503
+ var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
504
+
505
+ /*
506
+ Pointer.js
507
+ ------------------------
508
+ Modified from; https://github.com/borismus/pointer.js
509
+ */
510
+
511
+ root.createPointerEvent = function(event, self, preventRecord) {
512
+ var eventName = self.gesture;
513
+ var target = self.target;
514
+ var pts = event.changedTouches || root.proxy.getCoords(event);
515
+ if (pts.length) {
516
+ var pt = pts[0];
517
+ self.pointers = preventRecord ? [] : pts;
518
+ self.pageX = pt.pageX;
519
+ self.pageY = pt.pageY;
520
+ self.x = self.pageX;
521
+ self.y = self.pageY;
522
+ }
523
+ ///
524
+ var newEvent = document.createEvent("Event");
525
+ newEvent.initEvent(eventName, true, true);
526
+ newEvent.originalEvent = event;
527
+ for (var k in self) {
528
+ if (k === "target")
529
+ continue;
530
+ newEvent[k] = self[k];
531
+ }
532
+ target.dispatchEvent(newEvent);
533
+ };
534
+
535
+ /// Allows *EventListener to use custom event proxies.
536
+ if (root.modifyEventListener && window.HTMLElement)
537
+ (function() {
538
+ var augmentEventListener = function(proto) {
539
+ var recall = function(trigger) { // overwrite native *EventListener's
540
+ var handle = trigger + "EventListener";
541
+ var handler = proto[handle];
542
+ proto[handle] = function(type, listener, useCapture) {
543
+ if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.
544
+ var configure = useCapture;
545
+ if (typeof(useCapture) === "object") {
546
+ configure.useCall = true;
547
+ } else { // convert to configuration object.
548
+ configure = {
549
+ useCall: true,
550
+ useCapture: useCapture
551
+ };
552
+ }
553
+ eventManager(this, type, listener, configure, trigger, true);
554
+ handler.call(this, type, listener, useCapture);
555
+ } else { // use native function.
556
+ handler.call(this, normalize(type), listener, useCapture);
557
+ }
558
+ };
559
+ };
560
+ recall("add");
561
+ recall("remove");
562
+ };
563
+ // NOTE: overwriting HTMLElement doesn't do anything in Firefox.
564
+ if (navigator.userAgent.match(/Firefox/)) {
565
+ // TODO: fix Firefox for the general case.
566
+ augmentEventListener(HTMLDivElement.prototype);
567
+ augmentEventListener(HTMLCanvasElement.prototype);
568
+ } else {
569
+ augmentEventListener(HTMLElement.prototype);
570
+ }
571
+ augmentEventListener(document);
572
+ augmentEventListener(window);
573
+ })();
574
+
575
+ /// Allows querySelectorAll and other NodeLists to perform *EventListener commands in bulk.
576
+ if (root.modifySelectors)
577
+ (function() {
578
+ var proto = NodeList.prototype;
579
+ proto.removeEventListener = function(type, listener, useCapture) {
580
+ for (var n = 0, length = this.length; n < length; n++) {
581
+ this[n].removeEventListener(type, listener, useCapture);
582
+ }
583
+ };
584
+ proto.addEventListener = function(type, listener, useCapture) {
585
+ for (var n = 0, length = this.length; n < length; n++) {
586
+ this[n].addEventListener(type, listener, useCapture);
587
+ }
588
+ };
589
+ })();
590
+
591
+ return root;
592
+
593
+ })(Event);
594
+ /*
595
+ ----------------------------------------------------
596
+ Event.proxy : 0.4.2 : 2012/07/29 : MIT License
597
+ ----------------------------------------------------
598
+ https://github.com/mudcube/Event.js
599
+ ----------------------------------------------------
600
+ Pointer Gestures
601
+ ----------------------------------------------------
602
+ 1 : click, dblclick, dbltap
603
+ 1+ : tap, taphold, drag, swipe
604
+ 2+ : pinch, rotate
605
+ ----------------------------------------------------
606
+ Gyroscope Gestures
607
+ ----------------------------------------------------
608
+ * shake
609
+ ----------------------------------------------------
610
+ Fixes issues with
611
+ ----------------------------------------------------
612
+ * mousewheel-Firefox uses DOMMouseScroll and does not return wheelDelta.
613
+ * devicemotion-Fixes issue where event.acceleration is not returned.
614
+ ----------------------------------------------------
615
+ Ideas for the future
616
+ ----------------------------------------------------
617
+ * Keyboard, GamePad, and other input abstractions.
618
+ * Event batching - i.e. for every x fingers down a new gesture is created.
619
+ */
620
+
621
+ if (typeof(Event) === "undefined")
622
+ var Event = {};
623
+ if (typeof(Event.proxy) === "undefined")
624
+ Event.proxy = {};
625
+
626
+ Event.proxy = (function(root) {
627
+ "use strict";
628
+
629
+ /*
630
+ Create a new pointer gesture instance.
631
+ */
632
+
633
+ root.pointerSetup = function(conf, self) {
634
+ /// Configure.
635
+ conf.doc = conf.target.ownerDocument || conf.target; // Associated document.
636
+ conf.minFingers = conf.minFingers || conf.fingers || 1; // Minimum required fingers.
637
+ conf.maxFingers = conf.maxFingers || conf.fingers || Infinity; // Maximum allowed fingers.
638
+ conf.position = conf.position || "relative"; // Determines what coordinate system points are returned.
639
+ delete conf.fingers; //-
640
+ /// Convenience data.
641
+ self = self || {};
642
+ self.gesture = conf.gesture;
643
+ self.target = conf.target;
644
+ self.pointerType = Event.pointerType;
645
+ ///
646
+ if (Event.modifyEventListener && conf.fromOverwrite)
647
+ conf.listener = Event.createPointerEvent;
648
+ /// Convenience commands.
649
+ var fingers = 0;
650
+ var type = self.gesture.indexOf("pointer") === 0 && Event.modifyEventListener ? "pointer" : "mouse";
651
+ self.listener = conf.listener;
652
+ self.proxy = function(listener) {
653
+ self.defaultListener = conf.listener;
654
+ conf.listener = listener;
655
+ listener(conf.event, self);
656
+ };
657
+ self.remove = function() {
658
+ if (conf.onPointerDown)
659
+ Event.remove(conf.target, type + "down", conf.onPointerDown);
660
+ if (conf.onPointerMove)
661
+ Event.remove(conf.doc, type + "move", conf.onPointerMove);
662
+ if (conf.onPointerUp)
663
+ Event.remove(conf.doc, type + "up", conf.onPointerUp);
664
+ };
665
+ self.resume = function(opt) {
666
+ if (conf.onPointerMove && (!opt || opt.move))
667
+ Event.add(conf.doc, type + "move", conf.onPointerMove);
668
+ if (conf.onPointerUp && (!opt || opt.move))
669
+ Event.add(conf.doc, type + "up", conf.onPointerUp);
670
+ conf.fingers = fingers;
671
+ };
672
+ self.pause = function(opt) {
673
+ fingers = conf.fingers;
674
+ if (conf.onPointerMove && (!opt || opt.move))
675
+ Event.remove(conf.doc, type + "move", conf.onPointerMove);
676
+ if (conf.onPointerUp && (!opt || opt.up))
677
+ Event.remove(conf.doc, type + "up", conf.onPointerUp);
678
+ conf.fingers = 0;
679
+ };
680
+ ///
681
+ return self;
682
+ };
683
+
684
+ /*
685
+ Begin proxied pointer command.
686
+ */
687
+
688
+ root.pointerStart = function(event, self, conf) {
689
+ var addTouchStart = function(touch, sid) {
690
+ var bbox = conf.bbox;
691
+ var pt = track[sid] = {};
692
+ ///
693
+ switch (conf.position) {
694
+ case "absolute": // Absolute from within window.
695
+ pt.offsetX = 0;
696
+ pt.offsetY = 0;
697
+ break;
698
+ case "difference": // Relative from origin.
699
+ pt.offsetX = touch.pageX;
700
+ pt.offsetY = touch.pageY;
701
+ break;
702
+ case "move": // Move target element.
703
+ pt.offsetX = touch.pageX - bbox.x1;
704
+ pt.offsetY = touch.pageY - bbox.y1;
705
+ break;
706
+ default: // Relative from within target.
707
+ pt.offsetX = bbox.x1;
708
+ pt.offsetY = bbox.y1;
709
+ break;
710
+ }
711
+ ///
712
+ if (conf.position === "relative") {
713
+ var x = (touch.pageX + bbox.scrollLeft - pt.offsetX) * bbox.scaleX;
714
+ var y = (touch.pageY + bbox.scrollTop - pt.offsetY) * bbox.scaleY;
715
+ } else {
716
+ var x = (touch.pageX - pt.offsetX);
717
+ var y = (touch.pageY - pt.offsetY);
718
+ }
719
+ ///
720
+ pt.rotation = 0;
721
+ pt.scale = 1;
722
+ pt.startTime = pt.moveTime = (new Date).getTime();
723
+ pt.move = {x: x, y: y};
724
+ pt.start = {x: x, y: y};
725
+ ///
726
+ conf.fingers++;
727
+ };
728
+ ///
729
+ conf.event = event;
730
+ if (self.defaultListener) {
731
+ conf.listener = self.defaultListener;
732
+ delete self.defaultListener;
733
+ }
734
+ ///
735
+ var isTouchStart = !conf.fingers;
736
+ var track = conf.tracker;
737
+ var touches = event.changedTouches || root.getCoords(event);
738
+ var length = touches.length;
739
+ // Adding touch events to tracking.
740
+ for (var i = 0; i < length; i++) {
741
+ var touch = touches[i];
742
+ var sid = touch.identifier || Infinity; // Touch ID.
743
+ // Track the current state of the touches.
744
+ if (conf.fingers) {
745
+ if (conf.fingers >= conf.maxFingers) {
746
+ var ids = [];
747
+ for (var sid in conf.tracker)
748
+ ids.push(sid);
749
+ self.identifier = ids.join(",");
750
+ return isTouchStart;
751
+ }
752
+ var fingers = 0; // Finger ID.
753
+ for (var rid in track) {
754
+ // Replace removed finger.
755
+ if (track[rid].up) {
756
+ delete track[rid];
757
+ addTouchStart(touch, sid);
758
+ conf.cancel = true;
759
+ break;
760
+ }
761
+ fingers++;
762
+ }
763
+ // Add additional finger.
764
+ if (track[sid])
765
+ continue;
766
+ addTouchStart(touch, sid);
767
+ } else { // Start tracking fingers.
768
+ track = conf.tracker = {};
769
+ self.bbox = conf.bbox = root.getBoundingBox(conf.target);
770
+ conf.fingers = 0;
771
+ conf.cancel = false;
772
+ addTouchStart(touch, sid);
773
+ }
774
+ }
775
+ ///
776
+ var ids = [];
777
+ for (var sid in conf.tracker)
778
+ ids.push(sid);
779
+ self.identifier = ids.join(",");
780
+ ///
781
+ return isTouchStart;
782
+ };
783
+
784
+ /*
785
+ End proxied pointer command.
786
+ */
787
+
788
+ root.pointerEnd = function(event, self, conf, onPointerUp) {
789
+ // Record changed touches have ended (iOS changedTouches is not reliable).
790
+ var touches = event.touches || [];
791
+ var length = touches.length;
792
+ var exists = {};
793
+ for (var i = 0; i < length; i++) {
794
+ var touch = touches[i];
795
+ var sid = touch.identifier;
796
+ exists[sid || Infinity] = true;
797
+ }
798
+ for (var sid in conf.tracker) {
799
+ var track = conf.tracker[sid];
800
+ if (exists[sid] || track.up)
801
+ continue;
802
+ if (onPointerUp) { // add changedTouches to mouse.
803
+ onPointerUp({
804
+ pageX: track.pageX,
805
+ pageY: track.pageY,
806
+ changedTouches: [{
807
+ pageX: track.pageX,
808
+ pageY: track.pageY,
809
+ identifier: sid === "Infinity" ? Infinity : sid
810
+ }]
811
+ }, "up");
812
+ }
813
+ track.up = true;
814
+ conf.fingers--;
815
+ }
816
+ /* // This should work but fails in Safari on iOS4 so not using it.
817
+ var touches = event.changedTouches || root.getCoords(event);
818
+ var length = touches.length;
819
+ // Record changed touches have ended (this should work).
820
+ for (var i = 0; i < length; i ++) {
821
+ var touch = touches[i];
822
+ var sid = touch.identifier || Infinity;
823
+ var track = conf.tracker[sid];
824
+ if (track && !track.up) {
825
+ if (onPointerUp) { // add changedTouches to mouse.
826
+ onPointerUp({
827
+ changedTouches: [{
828
+ pageX: track.pageX,
829
+ pageY: track.pageY,
830
+ identifier: sid === "Infinity" ? Infinity : sid
831
+ }]
832
+ }, "up");
833
+ }
834
+ track.up = true;
835
+ conf.fingers --;
836
+ }
837
+ } */
838
+ // Wait for all fingers to be released.
839
+ if (conf.fingers !== 0)
840
+ return false;
841
+ // Record total number of fingers gesture used.
842
+ var ids = [];
843
+ conf.gestureFingers = 0;
844
+ for (var sid in conf.tracker) {
845
+ conf.gestureFingers++;
846
+ ids.push(sid);
847
+ }
848
+ self.identifier = ids.join(",");
849
+ // Our pointer gesture has ended.
850
+ return true;
851
+ };
852
+
853
+ /*
854
+ Returns mouse coords in an array to match event.*Touches
855
+ ------------------------------------------------------------
856
+ var touch = event.changedTouches || root.getCoords(event);
857
+ */
858
+
859
+ root.getCoords = function(event) {
860
+ if (typeof(event.pageX) !== "undefined") { // Desktop browsers.
861
+ root.getCoords = function(event) {
862
+ return Array({
863
+ type: "mouse",
864
+ x: event.pageX,
865
+ y: event.pageY,
866
+ pageX: event.pageX,
867
+ pageY: event.pageY,
868
+ identifier: Infinity
869
+ });
870
+ };
871
+ } else { // Internet Explorer <= 8.0
872
+ root.getCoords = function(event) {
873
+ event = event || window.event;
874
+ return Array({
875
+ type: "mouse",
876
+ x: event.clientX + document.documentElement.scrollLeft,
877
+ y: event.clientY + document.documentElement.scrollTop,
878
+ pageX: event.clientX + document.documentElement.scrollLeft,
879
+ pageY: event.clientY + document.documentElement.scrollTop,
880
+ identifier: Infinity
881
+ });
882
+ };
883
+ }
884
+ return root.getCoords(event);
885
+ };
886
+
887
+ /*
888
+ Returns single coords in an object.
889
+ ------------------------------------------------------------
890
+ var mouse = root.getCoord(event);
891
+ */
892
+
893
+ root.getCoord = function(event) {
894
+ if ("ontouchstart" in window) { // Mobile browsers.
895
+ var pX = 0;
896
+ var pY = 0;
897
+ root.getCoord = function(event) {
898
+ var touches = event.changedTouches;
899
+ if (touches.length) { // ontouchstart + ontouchmove
900
+ return {
901
+ x: pX = touches[0].pageX,
902
+ y: pY = touches[0].pageY
903
+ };
904
+ } else { // ontouchend
905
+ return {
906
+ x: pX,
907
+ y: pY
908
+ };
909
+ }
910
+ };
911
+ } else if (typeof(event.pageX) !== "undefined" && typeof(event.pageY) !== "undefined") { // Desktop browsers.
912
+ root.getCoord = function(event) {
913
+ return {
914
+ x: event.pageX,
915
+ y: event.pageY
916
+ };
917
+ };
918
+ } else { // Internet Explorer <=8.0
919
+ root.getCoord = function(event) {
920
+ event = event || window.event;
921
+ return {
922
+ x: event.clientX + document.documentElement.scrollLeft,
923
+ y: event.clientY + document.documentElement.scrollTop
924
+ };
925
+ };
926
+ }
927
+ return root.getCoord(event);
928
+ };
929
+
930
+ /*
931
+ Get target scale and position in space.
932
+ */
933
+
934
+ root.getBoundingBox = function(o) {
935
+ if (o === window || o === document)
936
+ o = document.body;
937
+ ///
938
+ var bbox = {
939
+ x1: 0,
940
+ y1: 0,
941
+ x2: 0,
942
+ y2: 0,
943
+ scrollLeft: 0,
944
+ scrollTop: 0
945
+ };
946
+ ///
947
+ if (o === document.body) {
948
+ bbox.height = window.innerHeight;
949
+ bbox.width = window.innerWidth;
950
+ } else {
951
+ bbox.height = o.offsetHeight;
952
+ bbox.width = o.offsetWidth;
953
+ }
954
+ /// Get the scale of the element.
955
+ bbox.scaleX = o.width / bbox.width || 1;
956
+ bbox.scaleY = o.height / bbox.height || 1;
957
+ /// Get the offset of element.
958
+ var tmp = o;
959
+ while (tmp !== null) {
960
+ bbox.x1 += tmp.offsetLeft;
961
+ bbox.y1 += tmp.offsetTop;
962
+ tmp = tmp.offsetParent;
963
+ }
964
+ ;
965
+ /// Get the scroll of container element.
966
+ var tmp = o.parentNode;
967
+ while (tmp !== null) {
968
+ if (tmp === document.body)
969
+ break;
970
+ if (tmp.scrollTop === undefined)
971
+ break;
972
+ bbox.scrollLeft += tmp.scrollLeft;
973
+ bbox.scrollTop += tmp.scrollTop;
974
+ tmp = tmp.parentNode;
975
+ }
976
+ ;
977
+ /// Record the extent of box.
978
+ bbox.x2 = bbox.x1 + bbox.width;
979
+ bbox.y2 = bbox.y1 + bbox.height;
980
+ ///
981
+ return bbox;
982
+ };
983
+
984
+ /*
985
+ Keep track of metaKey, the proper ctrlKey for users platform.
986
+ */
987
+
988
+ (function() {
989
+ var agent = navigator.userAgent.toLowerCase();
990
+ var mac = agent.indexOf("macintosh") !== -1;
991
+ if (mac && agent.indexOf("khtml") !== -1) { // chrome, safari.
992
+ var watch = {91: true, 93: true};
993
+ } else if (mac && agent.indexOf("firefox") !== -1) { // mac firefox.
994
+ var watch = {224: true};
995
+ } else { // windows, linux, or mac opera.
996
+ var watch = {17: true};
997
+ }
998
+ root.isMetaKey = function(event) {
999
+ return !!watch[event.keyCode];
1000
+ };
1001
+ root.metaTracker = function(event) {
1002
+ if (watch[event.keyCode]) {
1003
+ root.metaKey = event.type === "keydown";
1004
+ }
1005
+ };
1006
+ })();
1007
+
1008
+ return root;
1009
+
1010
+ })(Event.proxy);
1011
+ /*
1012
+ "Click" event proxy.
1013
+ ----------------------------------------------------
1014
+ Event.add(window, "click", function(event, self) {});
1015
+ */
1016
+
1017
+ if (typeof(Event) === "undefined")
1018
+ var Event = {};
1019
+ if (typeof(Event.proxy) === "undefined")
1020
+ Event.proxy = {};
1021
+
1022
+ Event.proxy = (function(root) {
1023
+ "use strict";
1024
+
1025
+ root.click = function(conf) {
1026
+ conf.maxFingers = conf.maxFingers || conf.fingers || 1;
1027
+ // Setting up local variables.
1028
+ var EVENT;
1029
+ // Tracking the events.
1030
+ conf.onPointerDown = function(event) {
1031
+ if (root.pointerStart(event, self, conf)) {
1032
+ Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
1033
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1034
+ }
1035
+ };
1036
+ conf.onPointerMove = function(event) {
1037
+ EVENT = event;
1038
+ };
1039
+ conf.onPointerUp = function(event) {
1040
+ if (root.pointerEnd(event, self, conf)) {
1041
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1042
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1043
+ if (EVENT.cancelBubble && ++EVENT.bubble > 1)
1044
+ return;
1045
+ var pointers = EVENT.changedTouches || root.getCoords(EVENT);
1046
+ var pointer = pointers[0];
1047
+ var bbox = conf.bbox;
1048
+ var newbbox = root.getBoundingBox(conf.target);
1049
+ if (conf.position === "relative") {
1050
+ var ax = (pointer.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX;
1051
+ var ay = (pointer.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY;
1052
+ } else {
1053
+ var ax = (pointer.pageX - bbox.x1);
1054
+ var ay = (pointer.pageY - bbox.y1);
1055
+ }
1056
+ if (ax > 0 && ax < bbox.width && // Within target coordinates.
1057
+ ay > 0 && ay < bbox.height &&
1058
+ bbox.scrollTop === newbbox.scrollTop) {
1059
+ conf.listener(EVENT, self);
1060
+ }
1061
+ }
1062
+ };
1063
+ // Generate maintenance commands, and other configurations.
1064
+ var self = root.pointerSetup(conf);
1065
+ self.state = "click";
1066
+ // Attach events.
1067
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1068
+ // Return this object.
1069
+ return self;
1070
+ };
1071
+
1072
+ Event.Gesture = Event.Gesture || {};
1073
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1074
+ Event.Gesture._gestureHandlers.click = root.click;
1075
+
1076
+ return root;
1077
+
1078
+ })(Event.proxy);
1079
+ /*
1080
+ "Double-Click" aka "Double-Tap" event proxy.
1081
+ ----------------------------------------------------
1082
+ Event.add(window, "dblclick", function(event, self) {});
1083
+ ----------------------------------------------------
1084
+ Touch an target twice for <= 700ms, with less than 25 pixel drift.
1085
+ */
1086
+
1087
+ if (typeof(Event) === "undefined")
1088
+ var Event = {};
1089
+ if (typeof(Event.proxy) === "undefined")
1090
+ Event.proxy = {};
1091
+
1092
+ Event.proxy = (function(root) {
1093
+ "use strict";
1094
+
1095
+ root.dbltap =
1096
+ root.dblclick = function(conf) {
1097
+ conf.maxFingers = conf.maxFingers || conf.fingers || 1;
1098
+ // Setting up local variables.
1099
+ var delay = 700; // in milliseconds
1100
+ var time0, time1, timeout;
1101
+ var pointer0, pointer1;
1102
+ // Tracking the events.
1103
+ conf.onPointerDown = function(event) {
1104
+ var pointers = event.changedTouches || root.getCoords(event);
1105
+ if (time0 && !time1) { // Click #2
1106
+ pointer1 = pointers[0];
1107
+ time1 = (new Date).getTime() - time0;
1108
+ } else { // Click #1
1109
+ pointer0 = pointers[0];
1110
+ time0 = (new Date).getTime();
1111
+ time1 = 0;
1112
+ clearTimeout(timeout);
1113
+ timeout = setTimeout(function() {
1114
+ time0 = 0;
1115
+ }, delay);
1116
+ }
1117
+ if (root.pointerStart(event, self, conf)) {
1118
+ Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
1119
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1120
+ }
1121
+ };
1122
+ conf.onPointerMove = function(event) {
1123
+ if (time0 && !time1) {
1124
+ var pointers = event.changedTouches || root.getCoords(event);
1125
+ pointer1 = pointers[0];
1126
+ }
1127
+ var bbox = conf.bbox;
1128
+ if (conf.position === "relative") {
1129
+ var ax = (pointer1.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX;
1130
+ var ay = (pointer1.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY;
1131
+ } else {
1132
+ var ax = (pointer1.pageX - bbox.x1);
1133
+ var ay = (pointer1.pageY - bbox.y1);
1134
+ }
1135
+ if (!(ax > 0 && ax < bbox.width && // Within target coordinates..
1136
+ ay > 0 && ay < bbox.height &&
1137
+ Math.abs(pointer1.pageX - pointer0.pageX) <= 25 && // Within drift deviance.
1138
+ Math.abs(pointer1.pageY - pointer0.pageY) <= 25)) {
1139
+ // Cancel out this listener.
1140
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1141
+ clearTimeout(timeout);
1142
+ time0 = time1 = 0;
1143
+ }
1144
+ };
1145
+ conf.onPointerUp = function(event) {
1146
+ if (root.pointerEnd(event, self, conf)) {
1147
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1148
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1149
+ }
1150
+ if (time0 && time1) {
1151
+ if (time1 <= delay && !(event.cancelBubble && ++event.bubble > 1)) {
1152
+ self.state = conf.gesture;
1153
+ conf.listener(event, self);
1154
+ }
1155
+ clearTimeout(timeout);
1156
+ time0 = time1 = 0;
1157
+ }
1158
+ };
1159
+ // Generate maintenance commands, and other configurations.
1160
+ var self = root.pointerSetup(conf);
1161
+ self.state = "dblclick";
1162
+ // Attach events.
1163
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1164
+ // Return this object.
1165
+ return self;
1166
+ };
1167
+
1168
+ Event.Gesture = Event.Gesture || {};
1169
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1170
+ Event.Gesture._gestureHandlers.dbltap = root.dbltap;
1171
+ Event.Gesture._gestureHandlers.dblclick = root.dblclick;
1172
+
1173
+ return root;
1174
+
1175
+ })(Event.proxy);
1176
+ /*
1177
+ "Drag" event proxy (1+ fingers).
1178
+ ----------------------------------------------------
1179
+ CONFIGURE: maxFingers, position.
1180
+ ----------------------------------------------------
1181
+ Event.add(window, "drag", function(event, self) {
1182
+ console.log(self.gesture, self.state, self.start, self.x, self.y, self.bbox);
1183
+ });
1184
+ */
1185
+
1186
+ if (typeof(Event) === "undefined")
1187
+ var Event = {};
1188
+ if (typeof(Event.proxy) === "undefined")
1189
+ Event.proxy = {};
1190
+
1191
+ Event.proxy = (function(root) {
1192
+ "use strict";
1193
+
1194
+ root.dragElement = function(that, event) {
1195
+ root.drag({
1196
+ event: event,
1197
+ target: that,
1198
+ position: "move",
1199
+ listener: function(event, self) {
1200
+ that.style.left = self.x + "px";
1201
+ that.style.top = self.y + "px";
1202
+ Event.prevent(event);
1203
+ }
1204
+ });
1205
+ };
1206
+
1207
+ root.drag = function(conf) {
1208
+ conf.gesture = "drag";
1209
+ conf.onPointerDown = function(event) {
1210
+ if (root.pointerStart(event, self, conf)) {
1211
+ if (!conf.monitor) {
1212
+ Event.add(conf.doc, "mousemove", conf.onPointerMove);
1213
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1214
+ }
1215
+ }
1216
+ // Process event listener.
1217
+ conf.onPointerMove(event, "down");
1218
+ };
1219
+ conf.onPointerMove = function(event, state) {
1220
+ if (!conf.tracker)
1221
+ return conf.onPointerDown(event);
1222
+ var bbox = conf.bbox;
1223
+ var touches = event.changedTouches || root.getCoords(event);
1224
+ var length = touches.length;
1225
+ for (var i = 0; i < length; i++) {
1226
+ var touch = touches[i];
1227
+ var identifier = touch.identifier || Infinity;
1228
+ var pt = conf.tracker[identifier];
1229
+ // Identifier defined outside of listener.
1230
+ if (!pt)
1231
+ continue;
1232
+ pt.pageX = touch.pageX;
1233
+ pt.pageY = touch.pageY;
1234
+ // Record data.
1235
+ self.state = state || "move";
1236
+ self.identifier = identifier;
1237
+ self.start = pt.start;
1238
+ self.fingers = conf.fingers;
1239
+ if (conf.position === "relative") {
1240
+ self.x = (pt.pageX + bbox.scrollLeft - pt.offsetX) * bbox.scaleX;
1241
+ self.y = (pt.pageY + bbox.scrollTop - pt.offsetY) * bbox.scaleY;
1242
+ } else {
1243
+ self.x = (pt.pageX - pt.offsetX);
1244
+ self.y = (pt.pageY - pt.offsetY);
1245
+ }
1246
+ ///
1247
+ conf.listener(event, self);
1248
+ }
1249
+ };
1250
+ conf.onPointerUp = function(event) {
1251
+ // Remove tracking for touch.
1252
+ if (root.pointerEnd(event, self, conf, conf.onPointerMove)) {
1253
+ if (!conf.monitor) {
1254
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1255
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1256
+ }
1257
+ }
1258
+ };
1259
+ // Generate maintenance commands, and other configurations.
1260
+ var self = root.pointerSetup(conf);
1261
+ // Attach events.
1262
+ if (conf.event) {
1263
+ conf.onPointerDown(conf.event);
1264
+ } else { //
1265
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1266
+ if (conf.monitor) {
1267
+ Event.add(conf.doc, "mousemove", conf.onPointerMove);
1268
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1269
+ }
1270
+ }
1271
+ // Return this object.
1272
+ return self;
1273
+ };
1274
+
1275
+ Event.Gesture = Event.Gesture || {};
1276
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1277
+ Event.Gesture._gestureHandlers.drag = root.drag;
1278
+
1279
+ return root;
1280
+
1281
+ })(Event.proxy);
1282
+ /*
1283
+ "Gesture" event proxy (2+ fingers).
1284
+ ----------------------------------------------------
1285
+ CONFIGURE: minFingers, maxFingers.
1286
+ ----------------------------------------------------
1287
+ Event.add(window, "gesture", function(event, self) {
1288
+ console.log(self.rotation, self.scale, self.fingers, self.state);
1289
+ });
1290
+ */
1291
+
1292
+ if (typeof(Event) === "undefined")
1293
+ var Event = {};
1294
+ if (typeof(Event.proxy) === "undefined")
1295
+ Event.proxy = {};
1296
+
1297
+ Event.proxy = (function(root) {
1298
+ "use strict";
1299
+
1300
+ var RAD_DEG = Math.PI / 180;
1301
+
1302
+ root.gesture = function(conf) {
1303
+ conf.minFingers = conf.minFingers || conf.fingers || 2;
1304
+ // Tracking the events.
1305
+ conf.onPointerDown = function(event) {
1306
+ var fingers = conf.fingers;
1307
+ if (root.pointerStart(event, self, conf)) {
1308
+ Event.add(conf.doc, "mousemove", conf.onPointerMove);
1309
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1310
+ }
1311
+ // Record gesture start.
1312
+ if (conf.fingers === conf.minFingers && fingers !== conf.fingers) {
1313
+ self.fingers = conf.minFingers;
1314
+ self.scale = 1;
1315
+ self.rotation = 0;
1316
+ self.state = "start";
1317
+ var sids = ""; //- FIXME(mud): can generate duplicate IDs.
1318
+ for (var key in conf.tracker)
1319
+ sids += key;
1320
+ self.identifier = parseInt(sids);
1321
+ conf.listener(event, self);
1322
+ }
1323
+ };
1324
+ ///
1325
+ conf.onPointerMove = function(event, state) {
1326
+ var bbox = conf.bbox;
1327
+ var points = conf.tracker;
1328
+ var touches = event.changedTouches || root.getCoords(event);
1329
+ var length = touches.length;
1330
+ // Update tracker coordinates.
1331
+ for (var i = 0; i < length; i++) {
1332
+ var touch = touches[i];
1333
+ var sid = touch.identifier || Infinity;
1334
+ var pt = points[sid];
1335
+ // Check whether "pt" is used by another gesture.
1336
+ if (!pt)
1337
+ continue;
1338
+ // Find the actual coordinates.
1339
+ if (conf.position === "relative") {
1340
+ pt.move.x = (touch.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX;
1341
+ pt.move.y = (touch.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY;
1342
+ } else {
1343
+ pt.move.x = (touch.pageX - bbox.x1);
1344
+ pt.move.y = (touch.pageY - bbox.y1);
1345
+ }
1346
+ }
1347
+ ///
1348
+ if (conf.fingers < conf.minFingers)
1349
+ return;
1350
+ ///
1351
+ var touches = [];
1352
+ var scale = 0;
1353
+ var rotation = 0;
1354
+ /// Calculate centroid of gesture.
1355
+ var centroidx = 0;
1356
+ var centroidy = 0;
1357
+ var length = 0;
1358
+ for (var sid in points) {
1359
+ var touch = points[sid];
1360
+ if (touch.up)
1361
+ continue;
1362
+ centroidx += touch.move.x;
1363
+ centroidy += touch.move.y;
1364
+ length++;
1365
+ }
1366
+ centroidx /= length;
1367
+ centroidy /= length;
1368
+ ///
1369
+ for (var sid in points) {
1370
+ var touch = points[sid];
1371
+ if (touch.up)
1372
+ continue;
1373
+ var start = touch.start;
1374
+ if (!start.distance) {
1375
+ var dx = start.x - centroidx;
1376
+ var dy = start.y - centroidy;
1377
+ start.distance = Math.sqrt(dx * dx + dy * dy);
1378
+ start.angle = Math.atan2(dx, dy) / RAD_DEG;
1379
+ }
1380
+ // Calculate scale.
1381
+ var dx = touch.move.x - centroidx;
1382
+ var dy = touch.move.y - centroidy;
1383
+ var distance = Math.sqrt(dx * dx + dy * dy);
1384
+ scale += distance / start.distance;
1385
+ // Calculate rotation.
1386
+ var angle = Math.atan2(dx, dy) / RAD_DEG;
1387
+ var rotate = (start.angle - angle + 360) % 360 - 180;
1388
+ touch.DEG2 = touch.DEG1; // Previous degree.
1389
+ touch.DEG1 = rotate > 0 ? rotate : -rotate; // Current degree.
1390
+ if (typeof(touch.DEG2) !== "undefined") {
1391
+ if (rotate > 0) {
1392
+ touch.rotation += touch.DEG1 - touch.DEG2;
1393
+ } else {
1394
+ touch.rotation -= touch.DEG1 - touch.DEG2;
1395
+ }
1396
+ rotation += touch.rotation;
1397
+ }
1398
+ // Attach current points to self.
1399
+ touches.push(touch.move);
1400
+ }
1401
+ ///
1402
+ self.touches = touches;
1403
+ self.fingers = conf.fingers;
1404
+ self.scale = scale / conf.fingers;
1405
+ self.rotation = rotation / conf.fingers;
1406
+ self.state = "change";
1407
+ conf.listener(event, self);
1408
+ };
1409
+ conf.onPointerUp = function(event) {
1410
+ // Remove tracking for touch.
1411
+ var fingers = conf.fingers;
1412
+ if (root.pointerEnd(event, self, conf)) {
1413
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1414
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1415
+ }
1416
+ // Check whether fingers has dropped below minFingers.
1417
+ if (fingers === conf.minFingers && conf.fingers < conf.minFingers) {
1418
+ self.fingers = conf.fingers;
1419
+ self.state = "end";
1420
+ conf.listener(event, self);
1421
+ }
1422
+ };
1423
+ // Generate maintenance commands, and other configurations.
1424
+ var self = root.pointerSetup(conf);
1425
+ // Attach events.
1426
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1427
+ // Return this object.
1428
+ return self;
1429
+ };
1430
+
1431
+ Event.Gesture = Event.Gesture || {};
1432
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1433
+ Event.Gesture._gestureHandlers.gesture = root.gesture;
1434
+
1435
+ return root;
1436
+
1437
+ })(Event.proxy);
1438
+ /*
1439
+ "Pointer" event proxy (1+ fingers).
1440
+ ----------------------------------------------------
1441
+ CONFIGURE: minFingers, maxFingers.
1442
+ ----------------------------------------------------
1443
+ Event.add(window, "gesture", function(event, self) {
1444
+ console.log(self.rotation, self.scale, self.fingers, self.state);
1445
+ });
1446
+ */
1447
+
1448
+ if (typeof(Event) === "undefined")
1449
+ var Event = {};
1450
+ if (typeof(Event.proxy) === "undefined")
1451
+ Event.proxy = {};
1452
+
1453
+ Event.proxy = (function(root) {
1454
+ "use strict";
1455
+
1456
+ root.pointerdown =
1457
+ root.pointermove =
1458
+ root.pointerup = function(conf) {
1459
+ if (conf.target.isPointerEmitter)
1460
+ return;
1461
+ // Tracking the events.
1462
+ var isDown = true;
1463
+ conf.onPointerDown = function(event) {
1464
+ isDown = false;
1465
+ self.gesture = "pointerdown";
1466
+ conf.listener(event, self);
1467
+ };
1468
+ conf.onPointerMove = function(event) {
1469
+ self.gesture = "pointermove";
1470
+ conf.listener(event, self, isDown);
1471
+ };
1472
+ conf.onPointerUp = function(event) {
1473
+ isDown = true;
1474
+ self.gesture = "pointerup";
1475
+ conf.listener(event, self, true);
1476
+ };
1477
+ // Generate maintenance commands, and other configurations.
1478
+ var self = root.pointerSetup(conf);
1479
+ // Attach events.
1480
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1481
+ Event.add(conf.target, "mousemove", conf.onPointerMove);
1482
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1483
+ // Return this object.
1484
+ conf.target.isPointerEmitter = true;
1485
+ return self;
1486
+ };
1487
+
1488
+ Event.Gesture = Event.Gesture || {};
1489
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1490
+ Event.Gesture._gestureHandlers.pointerdown = root.pointerdown;
1491
+ Event.Gesture._gestureHandlers.pointermove = root.pointermove;
1492
+ Event.Gesture._gestureHandlers.pointerup = root.pointerup;
1493
+
1494
+ return root;
1495
+
1496
+ })(Event.proxy);
1497
+ /*
1498
+ "Device Motion" and "Shake" event proxy.
1499
+ ----------------------------------------------------
1500
+ http://developer.android.com/reference/android/hardware/SensorEvent.html#values
1501
+ ----------------------------------------------------
1502
+ Event.add(window, "shake", function(event, self) {});
1503
+ Event.add(window, "devicemotion", function(event, self) {
1504
+ console.log(self.acceleration, self.accelerationIncludingGravity);
1505
+ });
1506
+ */
1507
+
1508
+ if (typeof(Event) === "undefined")
1509
+ var Event = {};
1510
+ if (typeof(Event.proxy) === "undefined")
1511
+ Event.proxy = {};
1512
+
1513
+ Event.proxy = (function(root) {
1514
+ "use strict";
1515
+
1516
+ root.shake = function(conf) {
1517
+ // Externally accessible data.
1518
+ var self = {
1519
+ gesture: "devicemotion",
1520
+ acceleration: {},
1521
+ accelerationIncludingGravity: {},
1522
+ target: conf.target,
1523
+ listener: conf.listener,
1524
+ remove: function() {
1525
+ window.removeEventListener('devicemotion', onDeviceMotion, false);
1526
+ }
1527
+ };
1528
+ // Setting up local variables.
1529
+ var threshold = 4; // Gravitational threshold.
1530
+ var timeout = 1000; // Timeout between shake events.
1531
+ var timeframe = 200; // Time between shakes.
1532
+ var shakes = 3; // Minimum shakes to trigger event.
1533
+ var lastShake = (new Date).getTime();
1534
+ var gravity = {x: 0, y: 0, z: 0};
1535
+ var delta = {
1536
+ x: {count: 0, value: 0},
1537
+ y: {count: 0, value: 0},
1538
+ z: {count: 0, value: 0}
1539
+ };
1540
+ // Tracking the events.
1541
+ var onDeviceMotion = function(e) {
1542
+ var alpha = 0.8; // Low pass filter.
1543
+ var o = e.accelerationIncludingGravity;
1544
+ gravity.x = alpha * gravity.x + (1 - alpha) * o.x;
1545
+ gravity.y = alpha * gravity.y + (1 - alpha) * o.y;
1546
+ gravity.z = alpha * gravity.z + (1 - alpha) * o.z;
1547
+ self.accelerationIncludingGravity = gravity;
1548
+ self.acceleration.x = o.x - gravity.x;
1549
+ self.acceleration.y = o.y - gravity.y;
1550
+ self.acceleration.z = o.z - gravity.z;
1551
+ ///
1552
+ if (conf.gesture === "devicemotion") {
1553
+ conf.listener(e, self);
1554
+ return;
1555
+ }
1556
+ var data = "xyz";
1557
+ var now = (new Date).getTime();
1558
+ for (var n = 0, length = data.length; n < length; n++) {
1559
+ var letter = data[n];
1560
+ var ACCELERATION = self.acceleration[letter];
1561
+ var DELTA = delta[letter];
1562
+ var abs = Math.abs(ACCELERATION);
1563
+ /// Check whether another shake event was recently registered.
1564
+ if (now - lastShake < timeout)
1565
+ continue;
1566
+ /// Check whether delta surpasses threshold.
1567
+ if (abs > threshold) {
1568
+ var idx = now * ACCELERATION / abs;
1569
+ var span = Math.abs(idx + DELTA.value);
1570
+ // Check whether last delta was registered within timeframe.
1571
+ if (DELTA.value && span < timeframe) {
1572
+ DELTA.value = idx;
1573
+ DELTA.count++;
1574
+ // Check whether delta count has enough shakes.
1575
+ if (DELTA.count === shakes) {
1576
+ conf.listener(e, self);
1577
+ // Reset tracking.
1578
+ lastShake = now;
1579
+ DELTA.value = 0;
1580
+ DELTA.count = 0;
1581
+ }
1582
+ } else {
1583
+ // Track first shake.
1584
+ DELTA.value = idx;
1585
+ DELTA.count = 1;
1586
+ }
1587
+ }
1588
+ }
1589
+ };
1590
+ // Attach events.
1591
+ if (!window.addEventListener)
1592
+ return;
1593
+ window.addEventListener('devicemotion', onDeviceMotion, false);
1594
+ // Return this object.
1595
+ return self;
1596
+ };
1597
+
1598
+ Event.Gesture = Event.Gesture || {};
1599
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1600
+ Event.Gesture._gestureHandlers.shake = root.shake;
1601
+
1602
+ return root;
1603
+
1604
+ })(Event.proxy);
1605
+ /*
1606
+ "Swipe" event proxy (1+ fingers).
1607
+ ----------------------------------------------------
1608
+ CONFIGURE: snap, threshold, maxFingers.
1609
+ ----------------------------------------------------
1610
+ Event.add(window, "swipe", function(event, self) {
1611
+ console.log(self.velocity, self.angle);
1612
+ });
1613
+ */
1614
+
1615
+ if (typeof(Event) === "undefined")
1616
+ var Event = {};
1617
+ if (typeof(Event.proxy) === "undefined")
1618
+ Event.proxy = {};
1619
+
1620
+ Event.proxy = (function(root) {
1621
+ "use strict";
1622
+
1623
+ var RAD_DEG = Math.PI / 180;
1624
+
1625
+ root.swipe = function(conf) {
1626
+ conf.snap = conf.snap || 90; // angle snap.
1627
+ conf.threshold = conf.threshold || 1; // velocity threshold.
1628
+ // Tracking the events.
1629
+ conf.onPointerDown = function(event) {
1630
+ if (root.pointerStart(event, self, conf)) {
1631
+ Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
1632
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1633
+ }
1634
+ };
1635
+ conf.onPointerMove = function(event) {
1636
+ var touches = event.changedTouches || root.getCoords(event);
1637
+ var length = touches.length;
1638
+ for (var i = 0; i < length; i++) {
1639
+ var touch = touches[i];
1640
+ var sid = touch.identifier || Infinity;
1641
+ var o = conf.tracker[sid];
1642
+ // Identifier defined outside of listener.
1643
+ if (!o)
1644
+ continue;
1645
+ o.move.x = touch.pageX;
1646
+ o.move.y = touch.pageY;
1647
+ o.moveTime = (new Date).getTime();
1648
+ }
1649
+ };
1650
+ conf.onPointerUp = function(event) {
1651
+ if (root.pointerEnd(event, self, conf)) {
1652
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1653
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1654
+ ///
1655
+ var velocity1;
1656
+ var velocity2
1657
+ var degree1;
1658
+ var degree2;
1659
+ /// Calculate centroid of gesture.
1660
+ var start = {x: 0, y: 0};
1661
+ var endx = 0;
1662
+ var endy = 0;
1663
+ var length = 0;
1664
+ ///
1665
+ for (var sid in conf.tracker) {
1666
+ var touch = conf.tracker[sid];
1667
+ var xdist = touch.move.x - touch.start.x;
1668
+ var ydist = touch.move.y - touch.start.y;
1669
+
1670
+ endx += touch.move.x;
1671
+ endy += touch.move.y;
1672
+ start.x += touch.start.x;
1673
+ start.y += touch.start.y;
1674
+ length++;
1675
+
1676
+
1677
+ var distance = Math.sqrt(xdist * xdist + ydist * ydist);
1678
+ var ms = touch.moveTime - touch.startTime;
1679
+ var degree2 = Math.atan2(xdist, ydist) / RAD_DEG + 180;
1680
+ var velocity2 = ms ? distance / ms : 0;
1681
+ if (typeof(degree1) === "undefined") {
1682
+ degree1 = degree2;
1683
+ velocity1 = velocity2;
1684
+ } else if (Math.abs(degree2 - degree1) <= 20) {
1685
+ degree1 = (degree1 + degree2) / 2;
1686
+ velocity1 = (velocity1 + velocity2) / 2;
1687
+ } else {
1688
+ return;
1689
+ }
1690
+ }
1691
+ ///
1692
+ if (velocity1 > conf.threshold) {
1693
+ start.x /= length;
1694
+ start.y /= length;
1695
+ self.start = start;
1696
+ self.x = endx / length;
1697
+ self.y = endy / length;
1698
+ self.angle = -((((degree1 / conf.snap + 0.5) >> 0) * conf.snap || 360) - 360);
1699
+ self.velocity = velocity1;
1700
+ self.fingers = conf.gestureFingers;
1701
+ self.state = "swipe";
1702
+ conf.listener(event, self);
1703
+ }
1704
+ }
1705
+ };
1706
+ // Generate maintenance commands, and other configurations.
1707
+ var self = root.pointerSetup(conf);
1708
+ // Attach events.
1709
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1710
+ // Return this object.
1711
+ return self;
1712
+ };
1713
+
1714
+ Event.Gesture = Event.Gesture || {};
1715
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1716
+ Event.Gesture._gestureHandlers.swipe = root.swipe;
1717
+
1718
+ return root;
1719
+
1720
+ })(Event.proxy);
1721
+ /*
1722
+ "Tap" and "Longpress" event proxy.
1723
+ ----------------------------------------------------
1724
+ CONFIGURE: delay (longpress), timeout (tap).
1725
+ ----------------------------------------------------
1726
+ Event.add(window, "tap", function(event, self) {
1727
+ console.log(self.fingers);
1728
+ });
1729
+ ----------------------------------------------------
1730
+ multi-finger tap // touch an target for <= 250ms.
1731
+ multi-finger longpress // touch an target for >= 500ms
1732
+ */
1733
+
1734
+ if (typeof(Event) === "undefined")
1735
+ var Event = {};
1736
+ if (typeof(Event.proxy) === "undefined")
1737
+ Event.proxy = {};
1738
+
1739
+ Event.proxy = (function(root) {
1740
+ "use strict";
1741
+
1742
+ root.tap =
1743
+ root.longpress = function(conf) {
1744
+ conf.delay = conf.delay || 500;
1745
+ conf.timeout = conf.timeout || 250;
1746
+ // Setting up local variables.
1747
+ var timestamp, timeout;
1748
+ // Tracking the events.
1749
+ conf.onPointerDown = function(event) {
1750
+ if (root.pointerStart(event, self, conf)) {
1751
+ timestamp = (new Date).getTime();
1752
+ // Initialize event listeners.
1753
+ Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
1754
+ Event.add(conf.doc, "mouseup", conf.onPointerUp);
1755
+ // Make sure this is a "longpress" event.
1756
+ if (conf.gesture !== "longpress")
1757
+ return;
1758
+ timeout = setTimeout(function() {
1759
+ if (event.cancelBubble && ++event.bubble > 1)
1760
+ return;
1761
+ // Make sure no fingers have been changed.
1762
+ var fingers = 0;
1763
+ for (var key in conf.tracker) {
1764
+ if (conf.tracker[key].end === true)
1765
+ return;
1766
+ if (conf.cancel)
1767
+ return;
1768
+ fingers++;
1769
+ }
1770
+ // Send callback.
1771
+ self.state = "start";
1772
+ self.fingers = fingers;
1773
+ conf.listener(event, self);
1774
+ }, conf.delay);
1775
+ }
1776
+ };
1777
+ conf.onPointerMove = function(event) {
1778
+ var bbox = conf.bbox;
1779
+ var touches = event.changedTouches || root.getCoords(event);
1780
+ var length = touches.length;
1781
+ for (var i = 0; i < length; i++) {
1782
+ var touch = touches[i];
1783
+ var identifier = touch.identifier || Infinity;
1784
+ var pt = conf.tracker[identifier];
1785
+ if (!pt)
1786
+ continue;
1787
+ if (conf.position === "relative") {
1788
+ var x = (touch.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX;
1789
+ var y = (touch.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY;
1790
+ } else {
1791
+ var x = (touch.pageX - bbox.x1);
1792
+ var y = (touch.pageY - bbox.y1);
1793
+ }
1794
+ if (!(x > 0 && x < bbox.width && // Within target coordinates..
1795
+ y > 0 && y < bbox.height &&
1796
+ Math.abs(x - pt.start.x) <= 25 && // Within drift deviance.
1797
+ Math.abs(y - pt.start.y) <= 25)) {
1798
+ // Cancel out this listener.
1799
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1800
+ conf.cancel = true;
1801
+ return;
1802
+ }
1803
+ }
1804
+ };
1805
+ conf.onPointerUp = function(event) {
1806
+ if (root.pointerEnd(event, self, conf)) {
1807
+ clearTimeout(timeout);
1808
+ Event.remove(conf.doc, "mousemove", conf.onPointerMove);
1809
+ Event.remove(conf.doc, "mouseup", conf.onPointerUp);
1810
+ if (event.cancelBubble && ++event.bubble > 1)
1811
+ return;
1812
+ // Callback release on longpress.
1813
+ if (conf.gesture === "longpress") {
1814
+ if (self.state === "start") {
1815
+ self.state = "end";
1816
+ conf.listener(event, self);
1817
+ }
1818
+ return;
1819
+ }
1820
+ // Cancel event due to movement.
1821
+ if (conf.cancel)
1822
+ return;
1823
+ // Ensure delay is within margins.
1824
+ if ((new Date).getTime() - timestamp > conf.timeout)
1825
+ return;
1826
+ // Send callback.
1827
+ self.state = "tap";
1828
+ self.fingers = conf.gestureFingers;
1829
+ conf.listener(event, self);
1830
+ }
1831
+ };
1832
+ // Generate maintenance commands, and other configurations.
1833
+ var self = root.pointerSetup(conf);
1834
+ // Attach events.
1835
+ Event.add(conf.target, "mousedown", conf.onPointerDown);
1836
+ // Return this object.
1837
+ return self;
1838
+ };
1839
+
1840
+ Event.Gesture = Event.Gesture || {};
1841
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1842
+ Event.Gesture._gestureHandlers.tap = root.tap;
1843
+ Event.Gesture._gestureHandlers.longpress = root.longpress;
1844
+
1845
+ return root;
1846
+
1847
+ })(Event.proxy);
1848
+ /*
1849
+ "Mouse Wheel" event proxy.
1850
+ ----------------------------------------------------
1851
+ Event.add(window, "wheel", function(event, self) {
1852
+ console.log(self.state, self.wheelDelta);
1853
+ });
1854
+ */
1855
+
1856
+ if (typeof(Event) === "undefined")
1857
+ var Event = {};
1858
+ if (typeof(Event.proxy) === "undefined")
1859
+ Event.proxy = {};
1860
+
1861
+ Event.proxy = (function(root) {
1862
+ "use strict";
1863
+
1864
+ root.wheel = function(conf) {
1865
+ // Configure event listener.
1866
+ var interval;
1867
+ var timeout = conf.timeout || 150;
1868
+ var count = 0;
1869
+ // Externally accessible data.
1870
+ var self = {
1871
+ gesture: "wheel",
1872
+ state: "start",
1873
+ wheelDelta: 0,
1874
+ target: conf.target,
1875
+ listener: conf.listener,
1876
+ remove: function() {
1877
+ conf.target[remove](type, onMouseWheel, false);
1878
+ }
1879
+ };
1880
+ // Tracking the events.
1881
+ var onMouseWheel = function(event) {
1882
+ event = event || window.event;
1883
+ self.state = count++ ? "change" : "start";
1884
+ self.wheelDelta = event.detail ? event.detail * -20 : event.wheelDelta;
1885
+ conf.listener(event, self);
1886
+ clearTimeout(interval);
1887
+ interval = setTimeout(function() {
1888
+ count = 0;
1889
+ self.state = "end";
1890
+ self.wheelDelta = 0;
1891
+ conf.listener(event, self);
1892
+ }, timeout);
1893
+ };
1894
+ // Attach events.
1895
+ var add = document.addEventListener ? "addEventListener" : "attachEvent";
1896
+ var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
1897
+ var type = Event.supports("mousewheel") ? "mousewheel" : "DOMMouseScroll";
1898
+ conf.target[add](type, onMouseWheel, false);
1899
+ // Return this object.
1900
+ return self;
1901
+ };
1902
+
1903
+ Event.Gesture = Event.Gesture || {};
1904
+ Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
1905
+ Event.Gesture._gestureHandlers.wheel = root.wheel;
1906
+
1907
+ return root;
1908
+
1909
+ })(Event.proxy);