1964 lines
59 KiB
JavaScript
1964 lines
59 KiB
JavaScript
/*:
|
|
----------------------------------------------------
|
|
event.js : 1.1.5 : 2014/02/12 : MIT License
|
|
----------------------------------------------------
|
|
https://github.com/mudcube/Event.js
|
|
----------------------------------------------------
|
|
1 : click, dblclick, dbltap
|
|
1+ : tap, longpress, drag, swipe
|
|
2+ : pinch, rotate
|
|
: mousewheel, devicemotion, shake
|
|
----------------------------------------------------
|
|
Ideas for the future
|
|
----------------------------------------------------
|
|
* GamePad, and other input abstractions.
|
|
* Event batching - i.e. for every x fingers down a new gesture is created.
|
|
----------------------------------------------------
|
|
http://www.w3.org/TR/2011/WD-touch-events-20110505/
|
|
----------------------------------------------------
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
|
|
(function(root) { "use strict";
|
|
|
|
// Add custom *EventListener commands to HTMLElements (set false to prevent funkiness).
|
|
root.modifyEventListener = false;
|
|
|
|
// Add bulk *EventListener commands on NodeLists from querySelectorAll and others (set false to prevent funkiness).
|
|
root.modifySelectors = false;
|
|
|
|
root.configure = function(conf) {
|
|
if (isFinite(conf.modifyEventListener)) root.modifyEventListener = conf.modifyEventListener;
|
|
if (isFinite(conf.modifySelectors)) root.modifySelectors = conf.modifySelectors;
|
|
/// Augment event listeners
|
|
if (eventListenersAgumented === false && root.modifyEventListener) {
|
|
augmentEventListeners();
|
|
}
|
|
if (selectorsAugmented === false && root.modifySelectors) {
|
|
augmentSelectors();
|
|
}
|
|
};
|
|
|
|
// Event maintenance.
|
|
root.add = function(target, type, listener, configure) {
|
|
return eventManager(target, type, listener, configure, "add");
|
|
};
|
|
|
|
root.remove = function(target, type, listener, configure) {
|
|
return eventManager(target, type, listener, configure, "remove");
|
|
};
|
|
|
|
root.returnFalse = function(event) {
|
|
return false;
|
|
};
|
|
|
|
root.stop = function(event) {
|
|
if (!event) return;
|
|
if (event.stopPropagation) event.stopPropagation();
|
|
event.cancelBubble = true; // <= IE8
|
|
event.cancelBubbleCount = 0;
|
|
};
|
|
|
|
root.prevent = function(event) {
|
|
if (!event) return;
|
|
if (event.preventDefault) {
|
|
event.preventDefault();
|
|
} else if (event.preventManipulation) {
|
|
event.preventManipulation(); // MS
|
|
} else {
|
|
event.returnValue = false; // <= IE8
|
|
}
|
|
};
|
|
|
|
root.cancel = function(event) {
|
|
root.stop(event);
|
|
root.prevent(event);
|
|
};
|
|
|
|
root.blur = function() { // Blurs the focused element. Useful when using eventjs.cancel as canceling will prevent focused elements from being blurred.
|
|
var node = document.activeElement;
|
|
if (!node) return;
|
|
var nodeName = document.activeElement.nodeName;
|
|
if (nodeName === "INPUT" || nodeName === "TEXTAREA" || node.contentEditable === "true") {
|
|
if (node.blur) node.blur();
|
|
}
|
|
};
|
|
|
|
// Check whether event is natively supported (via @kangax)
|
|
root.getEventSupport = function (target, type) {
|
|
if (typeof(target) === "string") {
|
|
type = target;
|
|
target = window;
|
|
}
|
|
type = "on" + type;
|
|
if (type in target) return true;
|
|
if (!target.setAttribute) target = document.createElement("div");
|
|
if (target.setAttribute && target.removeAttribute) {
|
|
target.setAttribute(type, "");
|
|
var isSupported = typeof target[type] === "function";
|
|
if (typeof target[type] !== "undefined") target[type] = null;
|
|
target.removeAttribute(type);
|
|
return isSupported;
|
|
}
|
|
};
|
|
|
|
var clone = function (obj) {
|
|
if (!obj || typeof (obj) !== 'object') return obj;
|
|
var temp = new obj.constructor();
|
|
for (var key in obj) {
|
|
if (!obj[key] || typeof (obj[key]) !== 'object') {
|
|
temp[key] = obj[key];
|
|
} else { // clone sub-object
|
|
temp[key] = clone(obj[key]);
|
|
}
|
|
}
|
|
return temp;
|
|
};
|
|
|
|
/// Handle custom *EventListener commands.
|
|
var eventManager = function(target, type, listener, configure, trigger, fromOverwrite) {
|
|
configure = configure || {};
|
|
// Check whether target is a configuration variable;
|
|
if (String(target) === "[object Object]") {
|
|
var data = target;
|
|
target = data.target; delete data.target;
|
|
///
|
|
if (data.type && data.listener) {
|
|
type = data.type; delete data.type;
|
|
listener = data.listener; delete data.listener;
|
|
for (var key in data) {
|
|
configure[key] = data[key];
|
|
}
|
|
} else { // specialness
|
|
for (var param in data) {
|
|
var value = data[param];
|
|
if (typeof(value) === "function") continue;
|
|
configure[param] = value;
|
|
}
|
|
///
|
|
var ret = {};
|
|
for (var key in data) {
|
|
var param = key.split(",");
|
|
var o = data[key];
|
|
var conf = {};
|
|
for (var k in configure) { // clone base configuration
|
|
conf[k] = configure[k];
|
|
}
|
|
///
|
|
if (typeof(o) === "function") { // without configuration
|
|
var listener = o;
|
|
} else if (typeof(o.listener) === "function") { // with configuration
|
|
var listener = o.listener;
|
|
for (var k in o) { // merge configure into base configuration
|
|
if (typeof(o[k]) === "function") continue;
|
|
conf[k] = o[k];
|
|
}
|
|
} else { // not a listener
|
|
continue;
|
|
}
|
|
///
|
|
for (var n = 0; n < param.length; n ++) {
|
|
ret[key] = eventjs.add(target, param[n], listener, conf, trigger);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
///
|
|
if (!target || !type || !listener) return;
|
|
// Check for element to load on interval (before onload).
|
|
if (typeof(target) === "string" && type === "ready") {
|
|
if (window.eventjs_stallOnReady) { /// force stall for scripts to load
|
|
type = "load";
|
|
target = window;
|
|
} else { //
|
|
var time = (new Date()).getTime();
|
|
var timeout = configure.timeout;
|
|
var ms = configure.interval || 1000 / 60;
|
|
var interval = window.setInterval(function() {
|
|
if ((new Date()).getTime() - time > timeout) {
|
|
window.clearInterval(interval);
|
|
}
|
|
if (document.querySelector(target)) {
|
|
window.clearInterval(interval);
|
|
setTimeout(listener, 1);
|
|
}
|
|
}, ms);
|
|
return;
|
|
}
|
|
}
|
|
// Get DOM element from Query Selector.
|
|
if (typeof(target) === "string") {
|
|
target = document.querySelectorAll(target);
|
|
if (target.length === 0) return createError("Missing target on listener!", arguments); // No results.
|
|
if (target.length === 1) { // Single target.
|
|
target = target[0];
|
|
}
|
|
}
|
|
|
|
/// Handle multiple targets.
|
|
var event;
|
|
var events = {};
|
|
if (target.length > 0 && target !== window) {
|
|
for (var n0 = 0, length0 = target.length; n0 < length0; n0 ++) {
|
|
event = eventManager(target[n0], type, listener, clone(configure), trigger);
|
|
if (event) events[n0] = event;
|
|
}
|
|
return createBatchCommands(events);
|
|
}
|
|
|
|
/// Check for multiple events in one string.
|
|
if (typeof(type) === "string") {
|
|
type = type.toLowerCase();
|
|
if (type.indexOf(" ") !== -1) {
|
|
type = type.split(" ");
|
|
} else if (type.indexOf(",") !== -1) {
|
|
type = type.split(",");
|
|
}
|
|
}
|
|
|
|
/// Attach or remove multiple events associated with a target.
|
|
if (typeof(type) !== "string") { // Has multiple events.
|
|
if (typeof(type.length) === "number") { // Handle multiple listeners glued together.
|
|
for (var n1 = 0, length1 = type.length; n1 < length1; n1 ++) { // Array [type]
|
|
event = eventManager(target, type[n1], listener, clone(configure), trigger);
|
|
if (event) events[type[n1]] = event;
|
|
}
|
|
} else { // Handle multiple listeners.
|
|
for (var key in type) { // Object {type}
|
|
if (typeof(type[key]) === "function") { // without configuration.
|
|
event = eventManager(target, key, type[key], clone(configure), trigger);
|
|
} else { // with configuration.
|
|
event = eventManager(target, key, type[key].listener, clone(type[key]), trigger);
|
|
}
|
|
if (event) events[key] = event;
|
|
}
|
|
}
|
|
return createBatchCommands(events);
|
|
} else if (type.indexOf("on") === 0) { // to support things like "onclick" instead of "click"
|
|
type = type.slice(2);
|
|
}
|
|
|
|
// Ensure listener is a function.
|
|
if (typeof(target) !== "object") return createError("Target is not defined!", arguments);
|
|
if (typeof(listener) !== "function") return createError("Listener is not a function!", arguments);
|
|
|
|
// Generate a unique wrapper identifier.
|
|
var useCapture = configure.useCapture || false;
|
|
var id = getID(target) + "." + getID(listener) + "." + (useCapture ? 1 : 0);
|
|
// Handle the event.
|
|
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // Fire custom event.
|
|
id = type + id;
|
|
if (trigger === "remove") { // Remove event listener.
|
|
if (!wrappers[id]) return; // Already removed.
|
|
wrappers[id].remove();
|
|
delete wrappers[id];
|
|
} else if (trigger === "add") { // Attach event listener.
|
|
if (wrappers[id]) {
|
|
wrappers[id].add();
|
|
return wrappers[id]; // Already attached.
|
|
}
|
|
// Retains "this" orientation.
|
|
if (configure.useCall && !root.modifyEventListener) {
|
|
var tmp = listener;
|
|
listener = function(event, self) {
|
|
for (var key in self) event[key] = self[key];
|
|
return tmp.call(target, event);
|
|
};
|
|
}
|
|
// Create listener proxy.
|
|
configure.gesture = type;
|
|
configure.target = target;
|
|
configure.listener = listener;
|
|
configure.fromOverwrite = fromOverwrite;
|
|
// Record wrapper.
|
|
wrappers[id] = root.proxy[type](configure);
|
|
}
|
|
return wrappers[id];
|
|
} else { // Fire native event.
|
|
var eventList = getEventList(type);
|
|
for (var n = 0, eventId; n < eventList.length; n ++) {
|
|
type = eventList[n];
|
|
eventId = type + "." + id;
|
|
if (trigger === "remove") { // Remove event listener.
|
|
if (!wrappers[eventId]) continue; // Already removed.
|
|
target[remove](type, listener, useCapture);
|
|
delete wrappers[eventId];
|
|
} else if (trigger === "add") { // Attach event listener.
|
|
if (wrappers[eventId]) return wrappers[eventId]; // Already attached.
|
|
target[add](type, listener, useCapture);
|
|
// Record wrapper.
|
|
wrappers[eventId] = {
|
|
id: eventId,
|
|
type: type,
|
|
target: target,
|
|
listener: listener,
|
|
remove: function() {
|
|
for (var n = 0; n < eventList.length; n ++) {
|
|
root.remove(target, eventList[n], listener, configure);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
return wrappers[eventId];
|
|
}
|
|
};
|
|
|
|
/// Perform batch actions on multiple events.
|
|
var createBatchCommands = function(events) {
|
|
return {
|
|
remove: function() { // Remove multiple events.
|
|
for (var key in events) {
|
|
events[key].remove();
|
|
}
|
|
},
|
|
add: function() { // Add multiple events.
|
|
for (var key in events) {
|
|
events[key].add();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
/// Display error message in console.
|
|
var createError = function(message, data) {
|
|
if (typeof(console) === "undefined") return;
|
|
if (typeof(console.error) === "undefined") return;
|
|
console.error(message, data);
|
|
};
|
|
|
|
/// Handle naming discrepancies between platforms.
|
|
var pointerDefs = {
|
|
"msPointer": [ "MSPointerDown", "MSPointerMove", "MSPointerUp" ],
|
|
"touch": [ "touchstart", "touchmove", "touchend" ],
|
|
"mouse": [ "mousedown", "mousemove", "mouseup" ]
|
|
};
|
|
|
|
var pointerDetect = {
|
|
// MSPointer
|
|
"MSPointerDown": 0,
|
|
"MSPointerMove": 1,
|
|
"MSPointerUp": 2,
|
|
// Touch
|
|
"touchstart": 0,
|
|
"touchmove": 1,
|
|
"touchend": 2,
|
|
// Mouse
|
|
"mousedown": 0,
|
|
"mousemove": 1,
|
|
"mouseup": 2
|
|
};
|
|
|
|
var getEventSupport = (function() {
|
|
root.supports = {};
|
|
if (window.navigator.msPointerEnabled) {
|
|
root.supports.msPointer = true;
|
|
}
|
|
if (root.getEventSupport("touchstart")) {
|
|
root.supports.touch = true;
|
|
}
|
|
if (root.getEventSupport("mousedown")) {
|
|
root.supports.mouse = true;
|
|
}
|
|
})();
|
|
|
|
var getEventList = (function() {
|
|
return function(type) {
|
|
var prefix = document.addEventListener ? "" : "on"; // IE
|
|
var idx = pointerDetect[type];
|
|
if (isFinite(idx)) {
|
|
var types = [];
|
|
for (var key in root.supports) {
|
|
types.push(prefix + pointerDefs[key][idx]);
|
|
}
|
|
return types;
|
|
} else {
|
|
return [ prefix + type ];
|
|
}
|
|
};
|
|
})();
|
|
|
|
/// Event wrappers to keep track of all events placed in the window.
|
|
var wrappers = {};
|
|
var counter = 0;
|
|
var getID = function(object) {
|
|
if (object === window) return "#window";
|
|
if (object === document) return "#document";
|
|
if (!object.uniqueID) object.uniqueID = "e" + counter ++;
|
|
return object.uniqueID;
|
|
};
|
|
|
|
/// Detect platforms native *EventListener command.
|
|
var add = document.addEventListener ? "addEventListener" : "attachEvent";
|
|
var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
|
|
|
|
/*
|
|
Pointer.js
|
|
----------------------------------------
|
|
Modified from; https://github.com/borismus/pointer.js
|
|
*/
|
|
|
|
root.createPointerEvent = function (event, self, preventRecord) {
|
|
var eventName = self.gesture;
|
|
var target = self.target;
|
|
var pts = event.changedTouches || root.proxy.getCoords(event);
|
|
if (pts.length) {
|
|
var pt = pts[0];
|
|
self.pointers = preventRecord ? [] : pts;
|
|
self.pageX = pt.pageX;
|
|
self.pageY = pt.pageY;
|
|
self.x = self.pageX;
|
|
self.y = self.pageY;
|
|
}
|
|
///
|
|
var newEvent = document.createEvent("Event");
|
|
newEvent.initEvent(eventName, true, true);
|
|
newEvent.originalEvent = event;
|
|
for (var k in self) {
|
|
if (k === "target") continue;
|
|
newEvent[k] = self[k];
|
|
}
|
|
///
|
|
var type = newEvent.type;
|
|
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.
|
|
// target.dispatchEvent(newEvent);
|
|
self.oldListener.call(target, newEvent, self, false);
|
|
}
|
|
};
|
|
|
|
var eventListenersAgumented = false;
|
|
var augmentEventListeners = function() {
|
|
/// Allows *EventListener to use custom event proxies.
|
|
if (!window.HTMLElement) return;
|
|
var augmentEventListener = function(proto) {
|
|
var recall = function(trigger) { // overwrite native *EventListener's
|
|
var handle = trigger + "EventListener";
|
|
var handler = proto[handle];
|
|
proto[handle] = function (type, listener, useCapture) {
|
|
if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.
|
|
var configure = useCapture;
|
|
if (typeof(useCapture) === "object") {
|
|
configure.useCall = true;
|
|
} else { // convert to configuration object.
|
|
configure = {
|
|
useCall: true,
|
|
useCapture: useCapture
|
|
};
|
|
}
|
|
eventManager(this, type, listener, configure, trigger, true);
|
|
// handler.call(this, type, listener, useCapture);
|
|
} else { // use native function.
|
|
var types = getEventList(type);
|
|
for (var n = 0; n < types.length; n ++) {
|
|
handler.call(this, types[n], listener, useCapture);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
recall("add");
|
|
recall("remove");
|
|
};
|
|
// NOTE: overwriting HTMLElement doesn't do anything in Firefox.
|
|
if (navigator.userAgent.match(/Firefox/)) {
|
|
// TODO: fix Firefox for the general case.
|
|
augmentEventListener(HTMLDivElement.prototype);
|
|
augmentEventListener(HTMLCanvasElement.prototype);
|
|
} else {
|
|
augmentEventListener(HTMLElement.prototype);
|
|
}
|
|
augmentEventListener(document);
|
|
augmentEventListener(window);
|
|
};
|
|
|
|
var selectorsAugmented = false;
|
|
var augmentSelectors = function() {
|
|
/// Allows querySelectorAll and other NodeLists to perform *EventListener commands in bulk.
|
|
var proto = NodeList.prototype;
|
|
proto.removeEventListener = function(type, listener, useCapture) {
|
|
for (var n = 0, length = this.length; n < length; n ++) {
|
|
this[n].removeEventListener(type, listener, useCapture);
|
|
}
|
|
};
|
|
proto.addEventListener = function(type, listener, useCapture) {
|
|
for (var n = 0, length = this.length; n < length; n ++) {
|
|
this[n].addEventListener(type, listener, useCapture);
|
|
}
|
|
};
|
|
};
|
|
|
|
return root;
|
|
|
|
})(eventjs);
|
|
|
|
/*:
|
|
----------------------------------------------------
|
|
eventjs.proxy : 0.4.2 : 2013/07/17 : MIT License
|
|
----------------------------------------------------
|
|
https://github.com/mudcube/eventjs.js
|
|
----------------------------------------------------
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
/*
|
|
Create a new pointer gesture instance.
|
|
*/
|
|
|
|
root.pointerSetup = function(conf, self) {
|
|
/// Configure.
|
|
conf.target = conf.target || window;
|
|
conf.doc = conf.target.ownerDocument || conf.target; // Associated document.
|
|
conf.minFingers = conf.minFingers || conf.fingers || 1; // Minimum required fingers.
|
|
conf.maxFingers = conf.maxFingers || conf.fingers || Infinity; // Maximum allowed fingers.
|
|
conf.position = conf.position || "relative"; // Determines what coordinate system points are returned.
|
|
delete conf.fingers; //-
|
|
/// Convenience data.
|
|
self = self || {};
|
|
self.enabled = true;
|
|
self.gesture = conf.gesture;
|
|
self.target = conf.target;
|
|
self.env = conf.env;
|
|
///
|
|
if (eventjs.modifyEventListener && conf.fromOverwrite) {
|
|
conf.oldListener = conf.listener;
|
|
conf.listener = eventjs.createPointerEvent;
|
|
}
|
|
/// Convenience commands.
|
|
var fingers = 0;
|
|
var type = self.gesture.indexOf("pointer") === 0 && eventjs.modifyEventListener ? "pointer" : "mouse";
|
|
if (conf.oldListener) self.oldListener = conf.oldListener;
|
|
///
|
|
self.listener = conf.listener;
|
|
self.proxy = function(listener) {
|
|
self.defaultListener = conf.listener;
|
|
conf.listener = listener;
|
|
listener(conf.event, self);
|
|
};
|
|
self.add = function() {
|
|
if (self.enabled === true) return;
|
|
if (conf.onPointerDown) eventjs.add(conf.target, type + "down", conf.onPointerDown);
|
|
if (conf.onPointerMove) eventjs.add(conf.doc, type + "move", conf.onPointerMove);
|
|
if (conf.onPointerUp) eventjs.add(conf.doc, type + "up", conf.onPointerUp);
|
|
self.enabled = true;
|
|
};
|
|
self.remove = function() {
|
|
if (self.enabled === false) return;
|
|
if (conf.onPointerDown) eventjs.remove(conf.target, type + "down", conf.onPointerDown);
|
|
if (conf.onPointerMove) eventjs.remove(conf.doc, type + "move", conf.onPointerMove);
|
|
if (conf.onPointerUp) eventjs.remove(conf.doc, type + "up", conf.onPointerUp);
|
|
self.reset();
|
|
self.enabled = false;
|
|
};
|
|
self.pause = function(opt) {
|
|
if (conf.onPointerMove && (!opt || opt.move)) eventjs.remove(conf.doc, type + "move", conf.onPointerMove);
|
|
if (conf.onPointerUp && (!opt || opt.up)) eventjs.remove(conf.doc, type + "up", conf.onPointerUp);
|
|
fingers = conf.fingers;
|
|
conf.fingers = 0;
|
|
};
|
|
self.resume = function(opt) {
|
|
if (conf.onPointerMove && (!opt || opt.move)) eventjs.add(conf.doc, type + "move", conf.onPointerMove);
|
|
if (conf.onPointerUp && (!opt || opt.up)) eventjs.add(conf.doc, type + "up", conf.onPointerUp);
|
|
conf.fingers = fingers;
|
|
};
|
|
self.reset = function() {
|
|
conf.tracker = {};
|
|
conf.fingers = 0;
|
|
};
|
|
///
|
|
return self;
|
|
};
|
|
|
|
/*
|
|
Begin proxied pointer command.
|
|
*/
|
|
|
|
var sp = eventjs.supports; // Default pointerType
|
|
///
|
|
eventjs.isMouse = !!sp.mouse;
|
|
eventjs.isMSPointer = !!sp.touch;
|
|
eventjs.isTouch = !!sp.msPointer;
|
|
///
|
|
root.pointerStart = function(event, self, conf) {
|
|
/// tracks multiple inputs
|
|
var type = (event.type || "mousedown").toUpperCase();
|
|
if (type.indexOf("MOUSE") === 0) {
|
|
eventjs.isMouse = true;
|
|
eventjs.isTouch = false;
|
|
eventjs.isMSPointer = false;
|
|
} else if (type.indexOf("TOUCH") === 0) {
|
|
eventjs.isMouse = false;
|
|
eventjs.isTouch = true;
|
|
eventjs.isMSPointer = false;
|
|
} else if (type.indexOf("MSPOINTER") === 0) {
|
|
eventjs.isMouse = false;
|
|
eventjs.isTouch = false;
|
|
eventjs.isMSPointer = true;
|
|
}
|
|
///
|
|
var addTouchStart = function(touch, sid) {
|
|
var bbox = conf.bbox;
|
|
var pt = track[sid] = {};
|
|
///
|
|
switch(conf.position) {
|
|
case "absolute": // Absolute from within window.
|
|
pt.offsetX = 0;
|
|
pt.offsetY = 0;
|
|
break;
|
|
case "differenceFromLast": // Since last coordinate recorded.
|
|
pt.offsetX = touch.pageX;
|
|
pt.offsetY = touch.pageY;
|
|
break;
|
|
case "difference": // Relative from origin.
|
|
pt.offsetX = touch.pageX;
|
|
pt.offsetY = touch.pageY;
|
|
break;
|
|
case "move": // Move target element.
|
|
pt.offsetX = touch.pageX - bbox.x1;
|
|
pt.offsetY = touch.pageY - bbox.y1;
|
|
break;
|
|
default: // Relative from within target.
|
|
pt.offsetX = bbox.x1 - bbox.scrollLeft;
|
|
pt.offsetY = bbox.y1 - bbox.scrollTop;
|
|
break;
|
|
}
|
|
///
|
|
var x = touch.pageX - pt.offsetX;
|
|
var y = touch.pageY - pt.offsetY;
|
|
///
|
|
pt.rotation = 0;
|
|
pt.scale = 1;
|
|
pt.startTime = pt.moveTime = (new Date()).getTime();
|
|
pt.move = { x: x, y: y };
|
|
pt.start = { x: x, y: y };
|
|
///
|
|
conf.fingers ++;
|
|
};
|
|
///
|
|
conf.event = event;
|
|
if (self.defaultListener) {
|
|
conf.listener = self.defaultListener;
|
|
delete self.defaultListener;
|
|
}
|
|
///
|
|
var isTouchStart = !conf.fingers;
|
|
var track = conf.tracker;
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
// Adding touch events to tracking.
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var sid = touch.identifier || Infinity; // Touch ID.
|
|
// Track the current state of the touches.
|
|
if (conf.fingers) {
|
|
if (conf.fingers >= conf.maxFingers) {
|
|
var ids = [];
|
|
for (var sid in conf.tracker) ids.push(sid);
|
|
self.identifier = ids.join(",");
|
|
return isTouchStart;
|
|
}
|
|
var fingers = 0; // Finger ID.
|
|
for (var rid in track) {
|
|
// Replace removed finger.
|
|
if (track[rid].up) {
|
|
delete track[rid];
|
|
addTouchStart(touch, sid);
|
|
conf.cancel = true;
|
|
break;
|
|
}
|
|
fingers ++;
|
|
}
|
|
// Add additional finger.
|
|
if (track[sid]) continue;
|
|
addTouchStart(touch, sid);
|
|
} else { // Start tracking fingers.
|
|
track = conf.tracker = {};
|
|
self.bbox = conf.bbox = root.getBoundingBox(conf.target);
|
|
conf.fingers = 0;
|
|
conf.cancel = false;
|
|
addTouchStart(touch, sid);
|
|
}
|
|
}
|
|
///
|
|
var ids = [];
|
|
for (var sid in conf.tracker) ids.push(sid);
|
|
self.identifier = ids.join(",");
|
|
///
|
|
return isTouchStart;
|
|
};
|
|
|
|
/*
|
|
End proxied pointer command.
|
|
*/
|
|
|
|
root.pointerEnd = function(event, self, conf, onPointerUp) {
|
|
// Record changed touches have ended (iOS changedTouches is not reliable).
|
|
var touches = event.touches || [];
|
|
var length = touches.length;
|
|
var exists = {};
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var sid = touch.identifier;
|
|
exists[sid || Infinity] = true;
|
|
}
|
|
for (var sid in conf.tracker) {
|
|
var track = conf.tracker[sid];
|
|
if (exists[sid] || track.up) continue;
|
|
if (onPointerUp) { // add changedTouches to mouse.
|
|
onPointerUp({
|
|
pageX: track.pageX,
|
|
pageY: track.pageY,
|
|
changedTouches: [{
|
|
pageX: track.pageX,
|
|
pageY: track.pageY,
|
|
identifier: sid === "Infinity" ? Infinity : sid
|
|
}]
|
|
}, "up");
|
|
}
|
|
track.up = true;
|
|
conf.fingers --;
|
|
}
|
|
/* // This should work but fails in Safari on iOS4 so not using it.
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
// Record changed touches have ended (this should work).
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var sid = touch.identifier || Infinity;
|
|
var track = conf.tracker[sid];
|
|
if (track && !track.up) {
|
|
if (onPointerUp) { // add changedTouches to mouse.
|
|
onPointerUp({
|
|
changedTouches: [{
|
|
pageX: track.pageX,
|
|
pageY: track.pageY,
|
|
identifier: sid === "Infinity" ? Infinity : sid
|
|
}]
|
|
}, "up");
|
|
}
|
|
track.up = true;
|
|
conf.fingers --;
|
|
}
|
|
} */
|
|
// Wait for all fingers to be released.
|
|
if (conf.fingers !== 0) return false;
|
|
// Record total number of fingers gesture used.
|
|
var ids = [];
|
|
conf.gestureFingers = 0;
|
|
for (var sid in conf.tracker) {
|
|
conf.gestureFingers ++;
|
|
ids.push(sid);
|
|
}
|
|
self.identifier = ids.join(",");
|
|
// Our pointer gesture has ended.
|
|
return true;
|
|
};
|
|
|
|
/*
|
|
Returns mouse coords in an array to match event.*Touches
|
|
------------------------------------------------------------
|
|
var touch = event.changedTouches || root.getCoords(event);
|
|
*/
|
|
|
|
root.getCoords = function(event) {
|
|
if (typeof(event.pageX) !== "undefined") { // Desktop browsers.
|
|
root.getCoords = function(event) {
|
|
return Array({
|
|
type: "mouse",
|
|
x: event.pageX,
|
|
y: event.pageY,
|
|
pageX: event.pageX,
|
|
pageY: event.pageY,
|
|
identifier: event.pointerId || Infinity // pointerId is MS
|
|
});
|
|
};
|
|
} else { // Internet Explorer <= 8.0
|
|
root.getCoords = function(event) {
|
|
var doc = document.documentElement;
|
|
event = event || window.event;
|
|
return Array({
|
|
type: "mouse",
|
|
x: event.clientX + doc.scrollLeft,
|
|
y: event.clientY + doc.scrollTop,
|
|
pageX: event.clientX + doc.scrollLeft,
|
|
pageY: event.clientY + doc.scrollTop,
|
|
identifier: Infinity
|
|
});
|
|
};
|
|
}
|
|
return root.getCoords(event);
|
|
};
|
|
|
|
/*
|
|
Returns single coords in an object.
|
|
------------------------------------------------------------
|
|
var mouse = root.getCoord(event);
|
|
*/
|
|
|
|
root.getCoord = function(event) {
|
|
if ("ontouchstart" in window) { // Mobile browsers.
|
|
var pX = 0;
|
|
var pY = 0;
|
|
root.getCoord = function(event) {
|
|
var touches = event.changedTouches;
|
|
if (touches && touches.length) { // ontouchstart + ontouchmove
|
|
return {
|
|
x: pX = touches[0].pageX,
|
|
y: pY = touches[0].pageY
|
|
};
|
|
} else { // ontouchend
|
|
return {
|
|
x: pX,
|
|
y: pY
|
|
};
|
|
}
|
|
};
|
|
} else if(typeof(event.pageX) !== "undefined" && typeof(event.pageY) !== "undefined") { // Desktop browsers.
|
|
root.getCoord = function(event) {
|
|
return {
|
|
x: event.pageX,
|
|
y: event.pageY
|
|
};
|
|
};
|
|
} else { // Internet Explorer <=8.0
|
|
root.getCoord = function(event) {
|
|
var doc = document.documentElement;
|
|
event = event || window.event;
|
|
return {
|
|
x: event.clientX + doc.scrollLeft,
|
|
y: event.clientY + doc.scrollTop
|
|
};
|
|
};
|
|
}
|
|
return root.getCoord(event);
|
|
};
|
|
|
|
/*
|
|
Get target scale and position in space.
|
|
*/
|
|
|
|
var getPropertyAsFloat = function(o, type) {
|
|
var n = parseFloat(o.getPropertyValue(type), 10);
|
|
return isFinite(n) ? n : 0;
|
|
};
|
|
|
|
root.getBoundingBox = function(o) {
|
|
if (o === window || o === document) o = document.body;
|
|
///
|
|
var bbox = {};
|
|
var bcr = o.getBoundingClientRect();
|
|
bbox.width = bcr.width;
|
|
bbox.height = bcr.height;
|
|
bbox.x1 = bcr.left;
|
|
bbox.y1 = bcr.top;
|
|
bbox.scaleX = bcr.width / o.offsetWidth || 1;
|
|
bbox.scaleY = bcr.height / o.offsetHeight || 1;
|
|
bbox.scrollLeft = 0;
|
|
bbox.scrollTop = 0;
|
|
///
|
|
var style = window.getComputedStyle(o);
|
|
var borderBox = style.getPropertyValue("box-sizing") === "border-box";
|
|
///
|
|
if (borderBox === false) {
|
|
var left = getPropertyAsFloat(style, "border-left-width");
|
|
var right = getPropertyAsFloat(style, "border-right-width");
|
|
var bottom = getPropertyAsFloat(style, "border-bottom-width");
|
|
var top = getPropertyAsFloat(style, "border-top-width");
|
|
bbox.border = [ left, right, top, bottom ];
|
|
bbox.x1 += left;
|
|
bbox.y1 += top;
|
|
bbox.width -= right + left;
|
|
bbox.height -= bottom + top;
|
|
}
|
|
|
|
/* var left = getPropertyAsFloat(style, "padding-left");
|
|
var right = getPropertyAsFloat(style, "padding-right");
|
|
var bottom = getPropertyAsFloat(style, "padding-bottom");
|
|
var top = getPropertyAsFloat(style, "padding-top");
|
|
bbox.padding = [ left, right, top, bottom ];*/
|
|
///
|
|
bbox.x2 = bbox.x1 + bbox.width;
|
|
bbox.y2 = bbox.y1 + bbox.height;
|
|
|
|
/// Get the scroll of container element.
|
|
var position = style.getPropertyValue("position");
|
|
var tmp = position === "fixed" ? o : o.parentNode;
|
|
while (tmp !== null) {
|
|
if (tmp === document.body) break;
|
|
if (tmp.scrollTop === undefined) break;
|
|
var style = window.getComputedStyle(tmp);
|
|
var position = style.getPropertyValue("position");
|
|
if (position === "absolute") {
|
|
|
|
} else if (position === "fixed") {
|
|
// bbox.scrollTop += document.body.scrollTop;
|
|
// bbox.scrollLeft += document.body.scrollLeft;
|
|
bbox.scrollTop -= tmp.parentNode.scrollTop;
|
|
bbox.scrollLeft -= tmp.parentNode.scrollLeft;
|
|
break;
|
|
} else {
|
|
bbox.scrollLeft += tmp.scrollLeft;
|
|
bbox.scrollTop += tmp.scrollTop;
|
|
}
|
|
///
|
|
tmp = tmp.parentNode;
|
|
};
|
|
///
|
|
bbox.scrollBodyLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
|
|
bbox.scrollBodyTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
|
|
///
|
|
bbox.scrollLeft -= bbox.scrollBodyLeft;
|
|
bbox.scrollTop -= bbox.scrollBodyTop;
|
|
///
|
|
return bbox;
|
|
};
|
|
|
|
/*
|
|
Keep track of metaKey, the proper ctrlKey for users platform.
|
|
----------------------------------------------------
|
|
http://www.quirksmode.org/js/keys.html
|
|
-----------------------------------
|
|
http://unixpapa.com/js/key.html
|
|
*/
|
|
|
|
(function() {
|
|
var agent = navigator.userAgent.toLowerCase();
|
|
var mac = agent.indexOf("macintosh") !== -1;
|
|
var metaKeys;
|
|
if (mac && agent.indexOf("khtml") !== -1) { // chrome, safari.
|
|
metaKeys = { 91: true, 93: true };
|
|
} else if (mac && agent.indexOf("firefox") !== -1) { // mac firefox.
|
|
metaKeys = { 224: true };
|
|
} else { // windows, linux, or mac opera.
|
|
metaKeys = { 17: true };
|
|
}
|
|
(root.metaTrackerReset = function() {
|
|
eventjs.fnKey = root.fnKey = false;
|
|
eventjs.metaKey = root.metaKey = false;
|
|
eventjs.escKey = root.escKey = false;
|
|
eventjs.ctrlKey = root.ctrlKey = false;
|
|
eventjs.shiftKey = root.shiftKey = false;
|
|
eventjs.altKey = root.altKey = false;
|
|
})();
|
|
root.metaTracker = function(event) {
|
|
var isKeyDown = event.type === "keydown";
|
|
if (event.keyCode === 27) eventjs.escKey = root.escKey = isKeyDown;
|
|
if (metaKeys[event.keyCode]) eventjs.metaKey = root.metaKey = isKeyDown;
|
|
eventjs.ctrlKey = root.ctrlKey = event.ctrlKey;
|
|
eventjs.shiftKey = root.shiftKey = event.shiftKey;
|
|
eventjs.altKey = root.altKey = event.altKey;
|
|
};
|
|
})();
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
----------------------------------------------------
|
|
"MutationObserver" event proxy.
|
|
----------------------------------------------------
|
|
author: Selvakumar Arumugam - MIT LICENSE
|
|
src: http://stackoverflow.com/questions/10868104/can-you-have-a-javascript-hook-trigger-after-a-dom-elements-style-object-change
|
|
----------------------------------------------------
|
|
*/
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
|
|
eventjs.MutationObserver = (function() {
|
|
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
|
|
var DOMAttrModifiedSupported = !MutationObserver && (function() {
|
|
var p = document.createElement("p");
|
|
var flag = false;
|
|
var fn = function() { flag = true };
|
|
if (p.addEventListener) {
|
|
p.addEventListener("DOMAttrModified", fn, false);
|
|
} else if (p.attachEvent) {
|
|
p.attachEvent("onDOMAttrModified", fn);
|
|
} else {
|
|
return false;
|
|
}
|
|
///
|
|
p.setAttribute("id", "target");
|
|
///
|
|
return flag;
|
|
})();
|
|
///
|
|
return function(container, callback) {
|
|
if (MutationObserver) {
|
|
var options = {
|
|
subtree: false,
|
|
attributes: true
|
|
};
|
|
var observer = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(e) {
|
|
callback.call(e.target, e.attributeName);
|
|
});
|
|
});
|
|
observer.observe(container, options)
|
|
} else if (DOMAttrModifiedSupported) {
|
|
eventjs.add(container, "DOMAttrModified", function(e) {
|
|
callback.call(container, e.attrName);
|
|
});
|
|
} else if ("onpropertychange" in document.body) {
|
|
eventjs.add(container, "propertychange", function(e) {
|
|
callback.call(container, window.event.propertyName);
|
|
});
|
|
}
|
|
}
|
|
})();
|
|
/*:
|
|
"Click" event proxy.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "click", function(event, self) {});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.click = function(conf) {
|
|
conf.gesture = conf.gesture || "click";
|
|
conf.maxFingers = conf.maxFingers || conf.fingers || 1;
|
|
/// Tracking the events.
|
|
conf.onPointerDown = function (event) {
|
|
if (root.pointerStart(event, self, conf)) {
|
|
eventjs.add(conf.target, "mouseup", conf.onPointerUp);
|
|
}
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
if (root.pointerEnd(event, self, conf)) {
|
|
eventjs.remove(conf.target, "mouseup", conf.onPointerUp);
|
|
var pointers = event.changedTouches || root.getCoords(event);
|
|
var pointer = pointers[0];
|
|
var bbox = conf.bbox;
|
|
var newbbox = root.getBoundingBox(conf.target);
|
|
var y = pointer.pageY - newbbox.scrollBodyTop;
|
|
var x = pointer.pageX - newbbox.scrollBodyLeft;
|
|
////
|
|
if (x > bbox.x1 && y > bbox.y1 &&
|
|
x < bbox.x2 && y < bbox.y2 &&
|
|
bbox.scrollTop === newbbox.scrollTop) { // has not been scrolled
|
|
///
|
|
for (var key in conf.tracker) break; //- should be modularized? in dblclick too
|
|
var point = conf.tracker[key];
|
|
self.x = point.start.x;
|
|
self.y = point.start.y;
|
|
///
|
|
conf.listener(event, self);
|
|
}
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
self.state = "click";
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.click = root.click;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Double-Click" aka "Double-Tap" event proxy.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "dblclick", function(event, self) {});
|
|
----------------------------------------------------
|
|
Touch an target twice for <= 700ms, with less than 25 pixel drift.
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.dbltap =
|
|
root.dblclick = function(conf) {
|
|
conf.gesture = conf.gesture || "dbltap";
|
|
conf.maxFingers = conf.maxFingers || conf.fingers || 1;
|
|
// Setting up local variables.
|
|
var delay = 700; // in milliseconds
|
|
var time0, time1, timeout;
|
|
var pointer0, pointer1;
|
|
// Tracking the events.
|
|
conf.onPointerDown = function (event) {
|
|
var pointers = event.changedTouches || root.getCoords(event);
|
|
if (time0 && !time1) { // Click #2
|
|
pointer1 = pointers[0];
|
|
time1 = (new Date()).getTime() - time0;
|
|
} else { // Click #1
|
|
pointer0 = pointers[0];
|
|
time0 = (new Date()).getTime();
|
|
time1 = 0;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(function() {
|
|
time0 = 0;
|
|
}, delay);
|
|
}
|
|
if (root.pointerStart(event, self, conf)) {
|
|
eventjs.add(conf.target, "mousemove", conf.onPointerMove).listener(event);
|
|
eventjs.add(conf.target, "mouseup", conf.onPointerUp);
|
|
}
|
|
};
|
|
conf.onPointerMove = function (event) {
|
|
if (time0 && !time1) {
|
|
var pointers = event.changedTouches || root.getCoords(event);
|
|
pointer1 = pointers[0];
|
|
}
|
|
var bbox = conf.bbox;
|
|
var ax = (pointer1.pageX - bbox.x1);
|
|
var ay = (pointer1.pageY - bbox.y1);
|
|
if (!(ax > 0 && ax < bbox.width && // Within target coordinates..
|
|
ay > 0 && ay < bbox.height &&
|
|
Math.abs(pointer1.pageX - pointer0.pageX) <= 25 && // Within drift deviance.
|
|
Math.abs(pointer1.pageY - pointer0.pageY) <= 25)) {
|
|
// Cancel out this listener.
|
|
eventjs.remove(conf.target, "mousemove", conf.onPointerMove);
|
|
clearTimeout(timeout);
|
|
time0 = time1 = 0;
|
|
}
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
if (root.pointerEnd(event, self, conf)) {
|
|
eventjs.remove(conf.target, "mousemove", conf.onPointerMove);
|
|
eventjs.remove(conf.target, "mouseup", conf.onPointerUp);
|
|
}
|
|
if (time0 && time1) {
|
|
if (time1 <= delay) { // && !(event.cancelBubble && ++event.cancelBubbleCount > 1)) {
|
|
self.state = conf.gesture;
|
|
for (var key in conf.tracker) break;
|
|
var point = conf.tracker[key];
|
|
self.x = point.start.x;
|
|
self.y = point.start.y;
|
|
conf.listener(event, self);
|
|
}
|
|
clearTimeout(timeout);
|
|
time0 = time1 = 0;
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
self.state = "dblclick";
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.dbltap = root.dbltap;
|
|
eventjs.Gesture._gestureHandlers.dblclick = root.dblclick;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Drag" event proxy (1+ fingers).
|
|
----------------------------------------------------
|
|
CONFIGURE: maxFingers, position.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "drag", function(event, self) {
|
|
console.log(self.gesture, self.state, self.start, self.x, self.y, self.bbox);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.dragElement = function(that, event) {
|
|
root.drag({
|
|
event: event,
|
|
target: that,
|
|
position: "move",
|
|
listener: function(event, self) {
|
|
that.style.left = self.x + "px";
|
|
that.style.top = self.y + "px";
|
|
eventjs.prevent(event);
|
|
}
|
|
});
|
|
};
|
|
|
|
root.drag = function(conf) {
|
|
conf.gesture = "drag";
|
|
conf.onPointerDown = function (event) {
|
|
if (root.pointerStart(event, self, conf)) {
|
|
if (!conf.monitor) {
|
|
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
}
|
|
// Process event listener.
|
|
conf.onPointerMove(event, "down");
|
|
};
|
|
conf.onPointerMove = function (event, state) {
|
|
if (!conf.tracker) return conf.onPointerDown(event);
|
|
var bbox = conf.bbox;
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var identifier = touch.identifier || Infinity;
|
|
var pt = conf.tracker[identifier];
|
|
// Identifier defined outside of listener.
|
|
if (!pt) continue;
|
|
pt.pageX = touch.pageX;
|
|
pt.pageY = touch.pageY;
|
|
// Record data.
|
|
self.state = state || "move";
|
|
self.identifier = identifier;
|
|
self.start = pt.start;
|
|
self.fingers = conf.fingers;
|
|
if (conf.position === "differenceFromLast") {
|
|
self.x = (pt.pageX - pt.offsetX);
|
|
self.y = (pt.pageY - pt.offsetY);
|
|
pt.offsetX = pt.pageX;
|
|
pt.offsetY = pt.pageY;
|
|
} else {
|
|
self.x = (pt.pageX - pt.offsetX);
|
|
self.y = (pt.pageY - pt.offsetY);
|
|
}
|
|
///
|
|
conf.listener(event, self);
|
|
}
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
// Remove tracking for touch.
|
|
if (root.pointerEnd(event, self, conf, conf.onPointerMove)) {
|
|
if (!conf.monitor) {
|
|
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
// Attach events.
|
|
if (conf.event) {
|
|
conf.onPointerDown(conf.event);
|
|
} else { //
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
if (conf.monitor) {
|
|
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
}
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.drag = root.drag;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Gesture" event proxy (2+ fingers).
|
|
----------------------------------------------------
|
|
CONFIGURE: minFingers, maxFingers.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "gesture", function(event, self) {
|
|
console.log(
|
|
self.x, // centroid
|
|
self.y,
|
|
self.rotation,
|
|
self.scale,
|
|
self.fingers,
|
|
self.state
|
|
);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
var RAD_DEG = Math.PI / 180;
|
|
var getCentroid = function(self, points) {
|
|
var centroidx = 0;
|
|
var centroidy = 0;
|
|
var length = 0;
|
|
for (var sid in points) {
|
|
var touch = points[sid];
|
|
if (touch.up) continue;
|
|
centroidx += touch.move.x;
|
|
centroidy += touch.move.y;
|
|
length ++;
|
|
}
|
|
self.x = centroidx /= length;
|
|
self.y = centroidy /= length;
|
|
return self;
|
|
};
|
|
|
|
root.gesture = function(conf) {
|
|
conf.gesture = conf.gesture || "gesture";
|
|
conf.minFingers = conf.minFingers || conf.fingers || 2;
|
|
// Tracking the events.
|
|
conf.onPointerDown = function (event) {
|
|
var fingers = conf.fingers;
|
|
if (root.pointerStart(event, self, conf)) {
|
|
eventjs.add(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
// Record gesture start.
|
|
if (conf.fingers === conf.minFingers && fingers !== conf.fingers) {
|
|
self.fingers = conf.minFingers;
|
|
self.scale = 1;
|
|
self.rotation = 0;
|
|
self.state = "start";
|
|
var sids = ""; //- FIXME(mud): can generate duplicate IDs.
|
|
for (var key in conf.tracker) sids += key;
|
|
self.identifier = parseInt(sids);
|
|
getCentroid(self, conf.tracker);
|
|
conf.listener(event, self);
|
|
}
|
|
};
|
|
///
|
|
conf.onPointerMove = function (event, state) {
|
|
var bbox = conf.bbox;
|
|
var points = conf.tracker;
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
// Update tracker coordinates.
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var sid = touch.identifier || Infinity;
|
|
var pt = points[sid];
|
|
// Check whether "pt" is used by another gesture.
|
|
if (!pt) continue;
|
|
// Find the actual coordinates.
|
|
pt.move.x = (touch.pageX - bbox.x1);
|
|
pt.move.y = (touch.pageY - bbox.y1);
|
|
}
|
|
///
|
|
if (conf.fingers < conf.minFingers) return;
|
|
///
|
|
var touches = [];
|
|
var scale = 0;
|
|
var rotation = 0;
|
|
|
|
/// Calculate centroid of gesture.
|
|
getCentroid(self, points);
|
|
///
|
|
for (var sid in points) {
|
|
var touch = points[sid];
|
|
if (touch.up) continue;
|
|
var start = touch.start;
|
|
if (!start.distance) {
|
|
var dx = start.x - self.x;
|
|
var dy = start.y - self.y;
|
|
start.distance = Math.sqrt(dx * dx + dy * dy);
|
|
start.angle = Math.atan2(dx, dy) / RAD_DEG;
|
|
}
|
|
// Calculate scale.
|
|
var dx = touch.move.x - self.x;
|
|
var dy = touch.move.y - self.y;
|
|
var distance = Math.sqrt(dx * dx + dy * dy);
|
|
// If touch start.distance from centroid is 0, scale should not be updated.
|
|
// This prevents dividing by 0 in cases where start.distance is oddly 0.
|
|
if (start.distance !== 0) {
|
|
scale += distance / start.distance;
|
|
}
|
|
// Calculate rotation.
|
|
var angle = Math.atan2(dx, dy) / RAD_DEG;
|
|
var rotate = (start.angle - angle + 360) % 360 - 180;
|
|
touch.DEG2 = touch.DEG1; // Previous degree.
|
|
touch.DEG1 = rotate > 0 ? rotate : -rotate; // Current degree.
|
|
if (typeof(touch.DEG2) !== "undefined") {
|
|
if (rotate > 0) {
|
|
touch.rotation += touch.DEG1 - touch.DEG2;
|
|
} else {
|
|
touch.rotation -= touch.DEG1 - touch.DEG2;
|
|
}
|
|
rotation += touch.rotation;
|
|
}
|
|
// Attach current points to self.
|
|
touches.push(touch.move);
|
|
}
|
|
///
|
|
self.touches = touches;
|
|
self.fingers = conf.fingers;
|
|
self.scale = scale / conf.fingers;
|
|
self.rotation = rotation / conf.fingers;
|
|
self.state = "change";
|
|
conf.listener(event, self);
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
// Remove tracking for touch.
|
|
var fingers = conf.fingers;
|
|
if (root.pointerEnd(event, self, conf)) {
|
|
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
// Check whether fingers has dropped below minFingers.
|
|
if (fingers === conf.minFingers && conf.fingers < conf.minFingers) {
|
|
self.fingers = conf.fingers;
|
|
self.state = "end";
|
|
conf.listener(event, self);
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.gesture = root.gesture;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Pointer" event proxy (1+ fingers).
|
|
----------------------------------------------------
|
|
CONFIGURE: minFingers, maxFingers.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "gesture", function(event, self) {
|
|
console.log(self.rotation, self.scale, self.fingers, self.state);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.pointerdown =
|
|
root.pointermove =
|
|
root.pointerup = function(conf) {
|
|
conf.gesture = conf.gesture || "pointer";
|
|
if (conf.target.isPointerEmitter) return;
|
|
// Tracking the events.
|
|
var isDown = true;
|
|
conf.onPointerDown = function (event) {
|
|
isDown = false;
|
|
self.gesture = "pointerdown";
|
|
conf.listener(event, self);
|
|
};
|
|
conf.onPointerMove = function (event) {
|
|
self.gesture = "pointermove";
|
|
conf.listener(event, self, isDown);
|
|
};
|
|
conf.onPointerUp = function (event) {
|
|
isDown = true;
|
|
self.gesture = "pointerup";
|
|
conf.listener(event, self, true);
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
eventjs.add(conf.target, "mousemove", conf.onPointerMove);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
// Return this object.
|
|
conf.target.isPointerEmitter = true;
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.pointerdown = root.pointerdown;
|
|
eventjs.Gesture._gestureHandlers.pointermove = root.pointermove;
|
|
eventjs.Gesture._gestureHandlers.pointerup = root.pointerup;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Device Motion" and "Shake" event proxy.
|
|
----------------------------------------------------
|
|
http://developer.android.com/reference/android/hardware/Sensoreventjs.html#values
|
|
----------------------------------------------------
|
|
eventjs.add(window, "shake", function(event, self) {});
|
|
eventjs.add(window, "devicemotion", function(event, self) {
|
|
console.log(self.acceleration, self.accelerationIncludingGravity);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.shake = function(conf) {
|
|
// Externally accessible data.
|
|
var self = {
|
|
gesture: "devicemotion",
|
|
acceleration: {},
|
|
accelerationIncludingGravity: {},
|
|
target: conf.target,
|
|
listener: conf.listener,
|
|
remove: function() {
|
|
window.removeEventListener('devicemotion', onDeviceMotion, false);
|
|
}
|
|
};
|
|
// Setting up local variables.
|
|
var threshold = 4; // Gravitational threshold.
|
|
var timeout = 1000; // Timeout between shake events.
|
|
var timeframe = 200; // Time between shakes.
|
|
var shakes = 3; // Minimum shakes to trigger event.
|
|
var lastShake = (new Date()).getTime();
|
|
var gravity = { x: 0, y: 0, z: 0 };
|
|
var delta = {
|
|
x: { count: 0, value: 0 },
|
|
y: { count: 0, value: 0 },
|
|
z: { count: 0, value: 0 }
|
|
};
|
|
// Tracking the events.
|
|
var onDeviceMotion = function(e) {
|
|
var alpha = 0.8; // Low pass filter.
|
|
var o = e.accelerationIncludingGravity;
|
|
gravity.x = alpha * gravity.x + (1 - alpha) * o.x;
|
|
gravity.y = alpha * gravity.y + (1 - alpha) * o.y;
|
|
gravity.z = alpha * gravity.z + (1 - alpha) * o.z;
|
|
self.accelerationIncludingGravity = gravity;
|
|
self.acceleration.x = o.x - gravity.x;
|
|
self.acceleration.y = o.y - gravity.y;
|
|
self.acceleration.z = o.z - gravity.z;
|
|
///
|
|
if (conf.gesture === "devicemotion") {
|
|
conf.listener(e, self);
|
|
return;
|
|
}
|
|
var data = "xyz";
|
|
var now = (new Date()).getTime();
|
|
for (var n = 0, length = data.length; n < length; n ++) {
|
|
var letter = data[n];
|
|
var ACCELERATION = self.acceleration[letter];
|
|
var DELTA = delta[letter];
|
|
var abs = Math.abs(ACCELERATION);
|
|
/// Check whether another shake event was recently registered.
|
|
if (now - lastShake < timeout) continue;
|
|
/// Check whether delta surpasses threshold.
|
|
if (abs > threshold) {
|
|
var idx = now * ACCELERATION / abs;
|
|
var span = Math.abs(idx + DELTA.value);
|
|
// Check whether last delta was registered within timeframe.
|
|
if (DELTA.value && span < timeframe) {
|
|
DELTA.value = idx;
|
|
DELTA.count ++;
|
|
// Check whether delta count has enough shakes.
|
|
if (DELTA.count === shakes) {
|
|
conf.listener(e, self);
|
|
// Reset tracking.
|
|
lastShake = now;
|
|
DELTA.value = 0;
|
|
DELTA.count = 0;
|
|
}
|
|
} else {
|
|
// Track first shake.
|
|
DELTA.value = idx;
|
|
DELTA.count = 1;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
// Attach events.
|
|
if (!window.addEventListener) return;
|
|
window.addEventListener('devicemotion', onDeviceMotion, false);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.shake = root.shake;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Swipe" event proxy (1+ fingers).
|
|
----------------------------------------------------
|
|
CONFIGURE: snap, threshold, maxFingers.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "swipe", function(event, self) {
|
|
console.log(self.velocity, self.angle);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
var RAD_DEG = Math.PI / 180;
|
|
|
|
root.swipe = function(conf) {
|
|
conf.snap = conf.snap || 90; // angle snap.
|
|
conf.threshold = conf.threshold || 1; // velocity threshold.
|
|
conf.gesture = conf.gesture || "swipe";
|
|
// Tracking the events.
|
|
conf.onPointerDown = function (event) {
|
|
if (root.pointerStart(event, self, conf)) {
|
|
eventjs.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
}
|
|
};
|
|
conf.onPointerMove = function (event) {
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var sid = touch.identifier || Infinity;
|
|
var o = conf.tracker[sid];
|
|
// Identifier defined outside of listener.
|
|
if (!o) continue;
|
|
o.move.x = touch.pageX;
|
|
o.move.y = touch.pageY;
|
|
o.moveTime = (new Date()).getTime();
|
|
}
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
if (root.pointerEnd(event, self, conf)) {
|
|
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
|
|
///
|
|
var velocity1;
|
|
var velocity2
|
|
var degree1;
|
|
var degree2;
|
|
/// Calculate centroid of gesture.
|
|
var start = { x: 0, y: 0 };
|
|
var endx = 0;
|
|
var endy = 0;
|
|
var length = 0;
|
|
///
|
|
for (var sid in conf.tracker) {
|
|
var touch = conf.tracker[sid];
|
|
var xdist = touch.move.x - touch.start.x;
|
|
var ydist = touch.move.y - touch.start.y;
|
|
///
|
|
endx += touch.move.x;
|
|
endy += touch.move.y;
|
|
start.x += touch.start.x;
|
|
start.y += touch.start.y;
|
|
length ++;
|
|
///
|
|
var distance = Math.sqrt(xdist * xdist + ydist * ydist);
|
|
var ms = touch.moveTime - touch.startTime;
|
|
var degree2 = Math.atan2(xdist, ydist) / RAD_DEG + 180;
|
|
var velocity2 = ms ? distance / ms : 0;
|
|
if (typeof(degree1) === "undefined") {
|
|
degree1 = degree2;
|
|
velocity1 = velocity2;
|
|
} else if (Math.abs(degree2 - degree1) <= 20) {
|
|
degree1 = (degree1 + degree2) / 2;
|
|
velocity1 = (velocity1 + velocity2) / 2;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
///
|
|
var fingers = conf.gestureFingers;
|
|
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
|
|
if (velocity1 > conf.threshold) {
|
|
start.x /= length;
|
|
start.y /= length;
|
|
self.start = start;
|
|
self.x = endx / length;
|
|
self.y = endy / length;
|
|
self.angle = -((((degree1 / conf.snap + 0.5) >> 0) * conf.snap || 360) - 360);
|
|
self.velocity = velocity1;
|
|
self.fingers = fingers;
|
|
self.state = "swipe";
|
|
conf.listener(event, self);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.swipe = root.swipe;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Tap" and "Longpress" event proxy.
|
|
----------------------------------------------------
|
|
CONFIGURE: delay (longpress), timeout (tap).
|
|
----------------------------------------------------
|
|
eventjs.add(window, "tap", function(event, self) {
|
|
console.log(self.fingers);
|
|
});
|
|
----------------------------------------------------
|
|
multi-finger tap // touch an target for <= 250ms.
|
|
multi-finger longpress // touch an target for >= 500ms
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.longpress = function(conf) {
|
|
conf.gesture = "longpress";
|
|
return root.tap(conf);
|
|
};
|
|
|
|
root.tap = function(conf) {
|
|
conf.delay = conf.delay || 500;
|
|
conf.timeout = conf.timeout || 250;
|
|
conf.driftDeviance = conf.driftDeviance || 10;
|
|
conf.gesture = conf.gesture || "tap";
|
|
// Setting up local variables.
|
|
var timestamp, timeout;
|
|
// Tracking the events.
|
|
conf.onPointerDown = function (event) {
|
|
if (root.pointerStart(event, self, conf)) {
|
|
timestamp = (new Date()).getTime();
|
|
// Initialize event listeners.
|
|
eventjs.add(conf.doc, "mousemove", conf.onPointerMove).listener(event);
|
|
eventjs.add(conf.doc, "mouseup", conf.onPointerUp);
|
|
// Make sure this is a "longpress" event.
|
|
if (conf.gesture !== "longpress") return;
|
|
timeout = setTimeout(function() {
|
|
if (event.cancelBubble && ++event.cancelBubbleCount > 1) return;
|
|
// Make sure no fingers have been changed.
|
|
var fingers = 0;
|
|
for (var key in conf.tracker) {
|
|
var point = conf.tracker[key];
|
|
if (point.end === true) return;
|
|
if (conf.cancel) return;
|
|
fingers ++;
|
|
}
|
|
// Send callback.
|
|
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
|
|
self.state = "start";
|
|
self.fingers = fingers;
|
|
self.x = point.start.x;
|
|
self.y = point.start.y;
|
|
conf.listener(event, self);
|
|
}
|
|
}, conf.delay);
|
|
}
|
|
};
|
|
conf.onPointerMove = function (event) {
|
|
var bbox = conf.bbox;
|
|
var touches = event.changedTouches || root.getCoords(event);
|
|
var length = touches.length;
|
|
for (var i = 0; i < length; i ++) {
|
|
var touch = touches[i];
|
|
var identifier = touch.identifier || Infinity;
|
|
var pt = conf.tracker[identifier];
|
|
if (!pt) continue;
|
|
var x = (touch.pageX - bbox.x1 - parseInt(window.scrollX));
|
|
var y = (touch.pageY - bbox.y1 - parseInt(window.scrollY));
|
|
///
|
|
var dx = x - pt.start.x;
|
|
var dy = y - pt.start.y;
|
|
var distance = Math.sqrt(dx * dx + dy * dy);
|
|
if (!(x > 0 && x < bbox.width && // Within target coordinates..
|
|
y > 0 && y < bbox.height &&
|
|
distance <= conf.driftDeviance)) { // Within drift deviance.
|
|
// Cancel out this listener.
|
|
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
|
|
conf.cancel = true;
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
conf.onPointerUp = function(event) {
|
|
if (root.pointerEnd(event, self, conf)) {
|
|
clearTimeout(timeout);
|
|
eventjs.remove(conf.doc, "mousemove", conf.onPointerMove);
|
|
eventjs.remove(conf.doc, "mouseup", conf.onPointerUp);
|
|
if (event.cancelBubble && ++event.cancelBubbleCount > 1) return;
|
|
// Callback release on longpress.
|
|
if (conf.gesture === "longpress") {
|
|
if (self.state === "start") {
|
|
self.state = "end";
|
|
conf.listener(event, self);
|
|
}
|
|
return;
|
|
}
|
|
// Cancel event due to movement.
|
|
if (conf.cancel) return;
|
|
// Ensure delay is within margins.
|
|
if ((new Date()).getTime() - timestamp > conf.timeout) return;
|
|
// Send callback.
|
|
var fingers = conf.gestureFingers;
|
|
if (conf.minFingers <= fingers && conf.maxFingers >= fingers) {
|
|
self.state = "tap";
|
|
self.fingers = conf.gestureFingers;
|
|
conf.listener(event, self);
|
|
}
|
|
}
|
|
};
|
|
// Generate maintenance commands, and other configurations.
|
|
var self = root.pointerSetup(conf);
|
|
// Attach events.
|
|
eventjs.add(conf.target, "mousedown", conf.onPointerDown);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.tap = root.tap;
|
|
eventjs.Gesture._gestureHandlers.longpress = root.longpress;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*:
|
|
"Mouse Wheel" event proxy.
|
|
----------------------------------------------------
|
|
eventjs.add(window, "wheel", function(event, self) {
|
|
console.log(self.state, self.wheelDelta);
|
|
});
|
|
*/
|
|
|
|
if (typeof(eventjs) === "undefined") var eventjs = {};
|
|
if (typeof(eventjs.proxy) === "undefined") eventjs.proxy = {};
|
|
|
|
eventjs.proxy = (function(root) { "use strict";
|
|
|
|
root.wheelPreventElasticBounce = function(el) {
|
|
if (!el) return;
|
|
if (typeof(el) === "string") el = document.querySelector(el);
|
|
eventjs.add(el, "wheel", function(event, self) {
|
|
self.preventElasticBounce();
|
|
eventjs.stop(event);
|
|
});
|
|
};
|
|
|
|
root.wheel = function(conf) {
|
|
// Configure event listener.
|
|
var interval;
|
|
var timeout = conf.timeout || 150;
|
|
var count = 0;
|
|
// Externally accessible data.
|
|
var self = {
|
|
gesture: "wheel",
|
|
state: "start",
|
|
wheelDelta: 0,
|
|
target: conf.target,
|
|
listener: conf.listener,
|
|
preventElasticBounce: function(event) {
|
|
var target = this.target;
|
|
var scrollTop = target.scrollTop;
|
|
var top = scrollTop + target.offsetHeight;
|
|
var height = target.scrollHeight;
|
|
if (top === height && this.wheelDelta <= 0) eventjs.cancel(event);
|
|
else if (scrollTop === 0 && this.wheelDelta >= 0) eventjs.cancel(event);
|
|
eventjs.stop(event);
|
|
},
|
|
add: function() {
|
|
conf.target[add](type, onMouseWheel, false);
|
|
},
|
|
remove: function() {
|
|
conf.target[remove](type, onMouseWheel, false);
|
|
}
|
|
};
|
|
// Tracking the events.
|
|
var onMouseWheel = function(event) {
|
|
event = event || window.event;
|
|
self.state = count++ ? "change" : "start";
|
|
self.wheelDelta = event.detail ? event.detail * -20 : event.wheelDelta;
|
|
conf.listener(event, self);
|
|
clearTimeout(interval);
|
|
interval = setTimeout(function() {
|
|
count = 0;
|
|
self.state = "end";
|
|
self.wheelDelta = 0;
|
|
conf.listener(event, self);
|
|
}, timeout);
|
|
};
|
|
// Attach events.
|
|
var add = document.addEventListener ? "addEventListener" : "attachEvent";
|
|
var remove = document.removeEventListener ? "removeEventListener" : "detachEvent";
|
|
var type = eventjs.getEventSupport("mousewheel") ? "mousewheel" : "DOMMouseScroll";
|
|
conf.target[add](type, onMouseWheel, false);
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
eventjs.Gesture = eventjs.Gesture || {};
|
|
eventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};
|
|
eventjs.Gesture._gestureHandlers.wheel = root.wheel;
|
|
|
|
return root;
|
|
|
|
})(eventjs.proxy);
|
|
/*
|
|
"Orientation Change"
|
|
----------------------------------------------------
|
|
https://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html#//apple_ref/doc/uid/TP40010526
|
|
----------------------------------------------------
|
|
Event.add(window, "deviceorientation", function(event, self) {});
|
|
*/
|
|
|
|
if (typeof(Event) === "undefined") var Event = {};
|
|
if (typeof(Event.proxy) === "undefined") Event.proxy = {};
|
|
|
|
Event.proxy = (function(root) { "use strict";
|
|
|
|
root.orientation = function(conf) {
|
|
// Externally accessible data.
|
|
var self = {
|
|
gesture: "orientationchange",
|
|
previous: null, /* Report the previous orientation */
|
|
current: window.orientation,
|
|
target: conf.target,
|
|
listener: conf.listener,
|
|
remove: function() {
|
|
window.removeEventListener('orientationchange', onOrientationChange, false);
|
|
}
|
|
};
|
|
|
|
// Tracking the events.
|
|
var onOrientationChange = function(e) {
|
|
|
|
self.previous = self.current;
|
|
self.current = window.orientation;
|
|
if(self.previous !== null && self.previous != self.current) {
|
|
conf.listener(e, self);
|
|
return;
|
|
}
|
|
|
|
|
|
};
|
|
// Attach events.
|
|
if (window.DeviceOrientationEvent) {
|
|
window.addEventListener("orientationchange", onOrientationChange, false);
|
|
}
|
|
// Return this object.
|
|
return self;
|
|
};
|
|
|
|
Event.Gesture = Event.Gesture || {};
|
|
Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};
|
|
Event.Gesture._gestureHandlers.orientation = root.orientation;
|
|
|
|
return root;
|
|
|
|
})(Event.proxy);
|