MIDI.js/js/Event.js
2012-04-13 21:56:56 -07:00

253 lines
7.5 KiB
JavaScript

/*
Event.js : v1.2 : 2012.02.22
-----------------------------
/// calling "Event" with "new" provides additional support;
Event(syntax.area, "click", function(event, self) {
self.stop().prevent().remove();
});
/// calling "Event" without "new" also works, but requires more work (and is faster);
var click = Event.add(syntax.area, "click", function(event) {
Event.stop(event);
Event.prevent(event);
Event.remove(syntax.area, "click", click);
});
/// multiple event-types bound to one function
var binding = Event(window, "click,mousemove,mousemove,mouseup", function(event, self) {
self.stop().prevent(); // stopPropagation and preventDefault
binding.remove(); // removes all the listeners
});
/// multiple events bound to one element
var binding = Event(window, {
"mousedown": function(event, self) {
self.remove(); // remove all the listeners
},
"mouseup": function(event, self) {
binding.remove(); // just remove this listener
}
});
/// on-element-is-ready (loads before onload)
Event("document.body", "ready", function(event, state, wheelData, self) {
self.stop.prevent.remove();
});
/// easier mousewheel events
Event.mousewheel(window, function(event, state, wheelData, self) {
self.stop.prevent.remove();
});
*/
var Event = (function(root) { "use strict";
var add = document.addEventListener ? 'addEventListener' : 'attachEvent';
var remove = document.removeEventListener ? 'removeEventListener' : 'detachEvent';
var isEvent = (function () {
var events = {};
var types = [
'abort', 'beforeunload', 'blur', 'broadcast', 'change', 'click', 'close',
'command', 'commandupdate', 'contextmenu', 'dblclick', 'dragdrop',
'dragenter', 'dragexit', 'draggesture', 'dragover', 'error', 'focus',
'input', 'keydown', 'keypress', 'keyup', 'load', 'mousedown',
'mousewheel', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',
'mouseup', 'move', 'overflow', 'overflowchanged', 'popuphidden',
'popuphiding', 'popupshowing', 'popupshown', 'select', 'scroll',
'syncfrompreference', 'synctopreference', 'readystatechange',
'reset', 'resize', 'select', 'submit', 'underflow', 'unload'
];
for (var n = 0, length = types.length; n < length; n ++) {
events[types[n]] = true;
}
return events;
})();
// event wrappers, and associated variables
var wrappers = {};
var counter = 0;
var testElement = document.createElement("div");
var getEventID = function(object) {
if (object === window) return "#window";
if (object === document) return "#document";
if (!object) object = {}; // FIXME: Happens in iOS
if (!object.uniqueID) {
object.uniqueID = "id" + counter ++;
}
return object.uniqueID;
};
// function to create new Events
root = {}; // double type the root function as object + function
root = function(target, type, listener, scope) {
// find the where function was called from (window is undefined)
var that = typeof(this) !== "undefined" ? this : {};
// check for multiple events in one string
if (type.indexOf && type.indexOf(",") !== -1) {
type = type.split(",");
}
// check for element to load on interval (before onload)
if (typeof(target) === "string" && type === "ready") {
var interval = window.setInterval(function() {
if (eval(target)) {
window.clearInterval(interval);
listener();
}
}, 10);
return that;
}
// check type for multipel events
if (typeof(type) !== "string") { // has multiple events
that.events = {};
if (typeof(type.length) === "undefined") { // has multiple listeners (object)
for (var key in type) {
if (isEvent[key] && typeof(type[key]) === "function") {
that.events[key] = Event(target, key, type[key], scope);
}
}
} else { // has multiple listeners glued together (array)
if (typeof(listener) !== "function") return "missing listener";
for (var n = 0, length = type.length; n < length; n ++) {
that.events[type[n]] = Event(target, type[n], listener, scope);
}
}
that.remove = function() { // remove multiple events
for (var key in that.events) {
that.events[key].remove();
}
return that;
};
that.add = function() { // add multiple events
for (var key in that.events) {
that.events[key].add();
}
return that;
};
return that;
} else { // is single call
if (!(target && type && listener)) return "missing listener.";
type = standardize(type);
}
// the wrapped unique id
var wrapperID = type + getEventID(target) + "." + getEventID(listener);
if (!wrappers[wrapperID]) { // create new wrapper
wrappers[wrapperID] = function(event) {
return listener.call(scope, that.event = event, that);
};
}
// the wrapped listener
var wrapper = wrappers[wrapperID];
target[add](type, wrapper, false);
//
that.stop = function(event) {
event = event || that.event;
if (event.stopPropagation) {
event.stopPropagation();
} else { // <= IE8
event.cancelBubble = true;
}
return that;
};
that.prevent = function(event) {
event = event || that.event;
if (event.preventDefault) {
event.preventDefault();
} else { // <= IE8
event.returnValue = false;
}
return that;
};
that.add = function() { // so you can add it back
target[add](type, wrapper, false);
return that;
};
that.remove = function() {
target[remove](type, wrapper, false);
return that;
};
return that;
};
//////////////// LEGACY SUPPORT //////////////////
root.add = function(target, type, listener, scope) {
if (typeof(type) !== "string") {
var config = type;
for (var type in config) {
if (isEvent[type] && typeof(config[type]) === "function") {
root.add(target, type, config[type]);
}
}
return config;
}
target[add](standardize(type), wrap(type, target, listener, scope || target), false);
return listener;
};
root.remove = function(target, type, listener, scope) {
type = standardize(type);
target[remove](type, wrap(type, target, listener, scope || target), false);
return listener;
};
root.stop =
root.stopPropagation = function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else { // <= IE8
event.cancelBubble = true;
}
return root;
};
root.prevent =
root.preventDefault = function(event) {
if (event.preventDefault) {
event.preventDefault();
} else { // <= IE8
event.returnValue = false;
}
return root;
};
/////////////
var standardize = function(type) { // fix any browser discrepancies
if (!document.addEventListener) {
return "on" + type;
} else if (type === "mousewheel" && !("onmousewheel" in testElement)) {
return "DOMMouseScroll";
} else { //
return type;
}
};
var wrap = function(type, target, listener, scope) { // un-tracked wrapper
var wrapperID = type + getEventID(target) + "." + getEventID(listener);
if (!wrappers[wrapperID]) {
wrappers[wrapperID] = function(event) {
return listener.call(scope, event);
};
}
return wrappers[wrapperID];
};
//////////////// MouseWheel ////////////////
root.mousewheel = function(target, listener, timeout) {
var interval = 0;
var self = Event(target, "mousewheel", function(event) {
event = event || window.event;
var wheelData = event.detail ? event.detail * -1 : event.wheelDelta / 40;
listener(event, "wheel", wheelData);
window.clearInterval(interval);
interval = window.setInterval(function() {
window.clearInterval(interval);
listener(event, "wheelup", wheelData, self);
}, timeout || 150);
});
return self;
};
//
return root;
//
})({});