Merge pull request #20 from sjmiles/e334f1293f394165dd1e53e7527bc624f99ec4f7

use MutationObserver to maintain custom event bindings, bug fixes
This commit is contained in:
Frankie Fu
2012-10-23 15:03:50 -07:00

View File

@@ -16,8 +16,8 @@ license that can be found in the LICENSE file.
PROPERTY_CHANGED_SUFFIX: "Changed",
CUSTOM_EVENT_PREFIX: "at"
};
// polyfill for DOMTokenList features: list of classes in add/remove;
// polyfill for DOMTokenList features: list of classes in add/remove;
// enable method.
(function() {
'use strict';
@@ -37,11 +37,11 @@ license that can be found in the LICENSE file.
value ? this.add(name) : this.remove(name);
};
})();
(function(){
// attribute bindings
var bindAttrs = function(inAttributes) {
var attrs = this.boundAttributes = [];
if (inAttributes) {
@@ -53,9 +53,9 @@ license that can be found in the LICENSE file.
}, this);
}
};
// event bindings
var bindEvents = function(inEvents) {
if (inEvents) {
var bindables = inEvents.value.split(",");
@@ -70,7 +70,7 @@ license that can be found in the LICENSE file.
}, this);
}
};
// property bindings
var propertyChanged = function(inName, inOld) {
@@ -88,7 +88,7 @@ license that can be found in the LICENSE file.
}
};
};
var squelchSideEffects = false;
var setPropertySilently = function(inName, inValue) {
@@ -105,6 +105,7 @@ license that can be found in the LICENSE file.
// set default value in a property already bound via attrs
setPropertySilently.call(this, inName, value);
} else {
console.log('binding', inName, this)
var value = inValue;
var sideEffect = sideEffectFactory(inName);
Object.defineProperty(this, inName, {
@@ -121,7 +122,7 @@ license that can be found in the LICENSE file.
});
}
};
var bindProperties = function(inProperties) {
if (inProperties) {
Object.keys(inProperties).forEach(function(n) {
@@ -129,7 +130,7 @@ license that can be found in the LICENSE file.
}, this);
}
};
var deref = function(inNode) {
return inNode && (inNode.baby || inNode);
};
@@ -137,14 +138,16 @@ license that can be found in the LICENSE file.
var establishNodeReferences = function(inRoot) {
this.$ = this.$ || {};
// search the LOCAL tree
var nodes = ShadowDOM.localQueryAll(inRoot, "[id]");
Array.prototype.forEach.call(nodes, function(n) {
this.$[n.id] = deref(n);
}, this);
if (inRoot) {
var nodes = ShadowDOM.localQueryAll(inRoot, "[id]");
Array.prototype.forEach.call(nodes, function(n) {
this.$[n.id] = deref(n);
}, this);
}
};
// attribute mutations
var deserializeValue = function(inValue) {
switch (inValue) {
case "":
@@ -180,7 +183,7 @@ license that can be found in the LICENSE file.
propertyChanged.call(this, c.name, c.old);
}, this);
};
var attributeChanged = function(inName) {
var value = this.getAttribute(inName);
this[inName] = deserializeValue(value);
@@ -189,7 +192,7 @@ license that can be found in the LICENSE file.
var handleMutations = function(inMxns) {
inMxns.forEach(function(inMxn) {
var name = inMxn.attributeName;
if (this.boundAttributes[name]) {
if (this.boundAttributes.indexOf(name) >= 0) {
attributeChanged.call(this, name);
}
}, this);
@@ -221,7 +224,7 @@ license that can be found in the LICENSE file.
};
// decorate HTMLElementElement with toolkit API
HTMLElementElement.prototype.component = function(inUber) {
var attributes = this.element.attributes;
this.lifecycle({
@@ -238,7 +241,7 @@ license that can be found in the LICENSE file.
this.attrObserver = new AttrObserver(this);
}
});
var p = inUber.prototype;
var p = inUber.prototype || {};
// attach some API
// TODO(sjmiles): this is probably not the best way to do this;
// probably better to insert another link in the prototype chain
@@ -247,11 +250,11 @@ license that can be found in the LICENSE file.
// install our prototype
this.generatedConstructor.prototype = p;
};
// utility methods
// job
var job = function(inJobName, inJob, inWait) {
var name = inJobName || ("__" + Math.random());
job.stop(name);
@@ -270,8 +273,8 @@ license that can be found in the LICENSE file.
job._jobs = {};
// target finding
findDistributedTarget = function(inTarget, inItems) {
var findDistributedTarget = function(inTarget, inItems) {
// find ancestor of target (including himself) that
// is in our item list, if any
var n = inTarget;
@@ -283,19 +286,19 @@ license that can be found in the LICENSE file.
n = n.parentNode;
}
};
// collect utils
// collect utils
var utils = {
job: job,
findDistributedTarget: findDistributedTarget
};
// code below provides a shim for declarative event handlers
// (aka 'x', as in onclick="x('click')")
// it's only really for evaluating syntax, and not
// it's only really for evaluating syntax, and not
// a real solution
var nodeIterator = function(inNodes, inFn) {
if (inNodes) {
for (var i=0, n; (n=inNodes[i]); i++) {
@@ -336,7 +339,7 @@ license that can be found in the LICENSE file.
// experimental event handler for mapping events to component instances
// publish handler globally, make name as small as possible since
// this is ideally an invisible helper API
x = function(inHandler) {
var owner = findOwner(event.currentTarget);
//console.log(inHandler, owner, event);
@@ -344,7 +347,7 @@ license that can be found in the LICENSE file.
owner[inHandler](event);
}
};
// newer experimental event handler
var findController = function(inNode) {
@@ -357,7 +360,7 @@ license that can be found in the LICENSE file.
n = n.parentNode || n.host;
}
};
_ = function(inHandlerName) {
var controller = findController(event.currentTarget);
//console.log(inHandler, owner, event);
@@ -365,14 +368,18 @@ license that can be found in the LICENSE file.
controller[inHandlerName](event);
}
};
// automagic event mapping
var bindCustomEvent = function(inNode, inEventName, inHandler) {
//console.log(inEventName, inHandler);
inNode.addEventListener(inEventName, function() {
_(inHandler);
});
var h = inNode.__athandlers = inNode.__athandlers || {};
if (!h[inEventName]) {
console.log("bindCustomEvent:", inEventName, inHandler, inNode);
h[inEventName] = function() {
_(inHandler);
};
inNode.addEventListener(inEventName, h[inEventName]);
}
};
var bindCustomEvents = function(inNode) {
@@ -385,9 +392,9 @@ license that can be found in the LICENSE file.
}
}
};
// TODO(sjmiles): improper tree walking (?)
var bindAllCustomEvents = function(inNode) {
var _bindAllCustomEvents = function(inNode) {
bindCustomEvents(inNode);
if (inNode.childNodes) {
for (var i=0, c; c=deref(inNode.childNodes[i]); i++) {
@@ -398,6 +405,25 @@ license that can be found in the LICENSE file.
}
};
var __bindAllCustomEvents = function(inNode) {
_bindAllCustomEvents(inNode);
};
var eventsObserver = function(inNode) {
new WebKitMutationObserver(__bindAllCustomEvents.bind(this, inNode))
.observe(inNode, {
childList: true,
subTree: true
});
};
var bindAllCustomEvents = function(inNode) {
if (inNode) {
_bindAllCustomEvents(inNode);
eventsObserver(inNode);
}
};
})();
</script>
</element>