event delegation foobar

by phloe

HTML

<div id="root">    <div>
    <div>
    
    
</div><div>
    
    <div>
    
        <div class="red"></div>
    
</div>
</div>
    
</div><div>
    <div>
    
        <div class="green"><div class="blue">
        <div></div></div></div>
    
</div><div>
    
    
</div>
    
        <div class="blue">
        <div></div></div>
</div>
    
</div>

CSS

div {
    background-color: #EEE;
    margin: 40px;
    min-width: 200px;
    min-height: 200px;
    float: left;
    
}
div:after {
    content: "";
    display: table;
    clear: both;
}
div > div {
    background-color: #DDD;
}
div > div > div {
    background-color: #CCC;
}

.red,
.blue,
.green {
    min-width: 100px;
    min-height: 100px;
}

.red {
    background-color: red;
}

.blue {
    background-color: blue;
}

.green {
    background-color: green;
}

.blue > div {
    min-width: 50px;
    min-height: 50px;
    background-color: white;
    
}

JavaScript

var html = document.documentElement;
var _matches = html.matches || html.matchesSelector ||
	html.mozMatchesSelector || html.webkitMatchesSelector ||
	html.msMatchesSelector || html.oMatchesSelector ||
	function (selector) {
		var elements = this.parentNode.querySelectorAll(selector);
		var length = elements.length;
		var i = 0;
		while (i < length) {
			if (elements[i++] === this) {
				return true;
			}
		}
		return false;
	};

function matches (element, selector) {
	return _matches.call(element, selector);
}

var elementEventProp = "__drc-util/dom/event/delegate";
var elementBindingProp = "__drc-util/dom/event/delegate_binding";

/*
element.__drc-util/dom/event/delegate: {
	[event-selector]: {
		wrappers: [],
		listeners: []
	},
	...
}
*/

function matchAncestor(selector, element, root) {
    root = root || document;
    while (element && element != root && !matches(element, selector)) {
        element = element.parentNode;
    }
    if (element != root) {
        return element;
    }
    return null;
}

function getDeep (object, keys, defaults) {
	var index = 0;
	var length = keys.length;
	var key;
	while (index < length) {
		key = keys[index];
		if (arguments.length === 3 && index in defaults && !(key in object)) {
			object[key] = defaults[index];
		}
		if (key in object) {
			object = object[key];
		}
		else {

			return null;
		}
		index++;
	}
	return object;
}

function wrap (element, selector, event) {
	var target = matchAncestor(selector, event.target, element);
	if (target) {
		// @jase's hack to avoid paving over `this`...
		target[elementBindingProp] = this;
		target[elementBindingProp](event, target);
		target[elementBindingProp] = null;
	}
}

function add (element, event, selector, listener) {

	if (typeof event === "object") {
		var events = event;
		for (event in events) {
			for (var selector in events[event]) {
				addSingle(element, event, selector, events[event][selector]);
			}
		}
	}
	else if (typeof listener === "function")...