simplesvg
Version:
A very simple svg wrapper, inspired by original vivagraph
93 lines (74 loc) • 2.63 kB
JavaScript
module.exports = template;
var BINDING_EXPR = /{{(.+?)}}/;
function template(domNode) {
var allBindings = Object.create(null);
extractAllBindings(domNode, allBindings);
return {
link: function(model) {
Object.keys(allBindings).forEach(function(key) {
var setter = allBindings[key];
setter.forEach(changeModel);
});
function changeModel(setter) {
setter(model);
}
}
};
}
function extractAllBindings(domNode, allBindings) {
var nodeType = domNode.nodeType;
var typeSupported = (nodeType === 1) || (nodeType === 3);
if (!typeSupported) return;
var i;
if (domNode.hasChildNodes()) {
var domChildren = domNode.childNodes;
for (i = 0; i < domChildren.length; ++i) {
extractAllBindings(domChildren[i], allBindings);
}
}
if (nodeType === 3) { // text:
bindTextContent(domNode, allBindings);
}
if (!domNode.attributes) return; // this might be a text. Need to figure out what to do in that case
var attrs = domNode.attributes;
for (i = 0; i < attrs.length; ++i) {
bindDomAttribute(attrs[i], domNode, allBindings);
}
}
function bindDomAttribute(domAttribute, element, allBindings) {
var value = domAttribute.value;
if (!value) return; // unary attribute?
var modelNameMatch = value.match(BINDING_EXPR);
if (!modelNameMatch) return; // does not look like a binding
var attrName = domAttribute.localName;
var modelPropertyName = modelNameMatch[1];
var isSimpleValue = modelPropertyName.indexOf('.') < 0;
if (!isSimpleValue) throw new Error('simplesvg currently does not support nested bindings');
var propertyBindings = allBindings[modelPropertyName];
if (!propertyBindings) {
propertyBindings = allBindings[modelPropertyName] = [attributeSetter];
} else {
propertyBindings.push(attributeSetter);
}
function attributeSetter(model) {
element.setAttributeNS(null, attrName, model[modelPropertyName]);
}
}
function bindTextContent(element, allBindings) {
// todo reduce duplication
var value = element.nodeValue;
if (!value) return; // unary attribute?
var modelNameMatch = value.match(BINDING_EXPR);
if (!modelNameMatch) return; // does not look like a binding
var modelPropertyName = modelNameMatch[1];
var isSimpleValue = modelPropertyName.indexOf('.') < 0;
var propertyBindings = allBindings[modelPropertyName];
if (!propertyBindings) {
propertyBindings = allBindings[modelPropertyName] = [textSetter];
} else {
propertyBindings.push(textSetter);
}
function textSetter(model) {
element.nodeValue = model[modelPropertyName];
}
}