Skip to content

Instantly share code, notes, and snippets.

@potch
Created December 5, 2013 23:10
Show Gist options
  • Save potch/7815727 to your computer and use it in GitHub Desktop.
Save potch/7815727 to your computer and use it in GitHub Desktop.
var dombind = (function() {
function makeSmart(obj) {
obj.__bound__ = {};
}
function isSmart(obj) {
return '__bound__' in obj;
}
function makeSmartProperty(obj, property) {
var oldVal = obj[property];
obj.__bound__[property] = [];
var bound = obj.__bound__;
// Apply magic
Object.defineProperty(obj, property, {
set: function(v) {
// set the stored value
bound[property].__value__ = v;
var els = bound[property];
// fire our handlers
for (var i = 0; i < els.length; i++) {
// for each [el, fn] pair, call fn(el)
els[i][1](els[i][0],v);
}
},
get: function() {
return bound[property].__value__;
}
});
// apply an old value if it existed
if (typeof oldVal !== 'undefined') {
obj[property] = oldVal;
}
}
function isSmartProperty(obj, property) {
return obj.__bound__ && (property in obj.__bound__);
}
var tag = 0;
function getTag(obj) {
if (!('__tag__' in obj)) {
obj.__tag__ = (++tag).toString(36);
}
return obj.__tag__;
}
// wire data to DOM.
function link(obj, property, el, fn) {
// resolve selector to element
el = getEl(el);
var elTag = getTag(el);
// set up smartness
if (!isSmart(obj)) {
makeSmart(obj);
}
// get an appropriate default handler
fn = fn || getOutputFunction(el);
if (!isSmartProperty(obj, property)) {
makeSmartProperty(obj, property);
}
// call our handler once to initialize things
fn(el, obj[property]);
obj.__bound__[property].push([el, fn, elTag]);
}
function unlink(el) {
}
function map(obj, el, map) {
if (!(el instanceof HTMLElement)) {
map = el;
el = document.body
}
if ('set' in map) {
var mapping = map.set;
for (property in mapping) {
var propMap = mapping[property];
if (propMap instanceof Array) {
propMap.forEach(singleMappingSet);
} else {
singleMappingSet(propMap)
}
}
}
if ('watch' in map) {
var mapping = map.watch;
for (property in mapping) {
var propMap = mapping[property];
if (propMap instanceof Array) {
propMap.forEach(singleMappingWatch);
} else {
singleMappingWatch(propMap);
}
}
}
function singleMappingSet(propMap) {
var mapEl;
if (typeof propMap === 'object') {
mapEl = el.querySelector(propMap.el);
if (mapEl) {
link(obj, property, mapEl, propMap.method);
}
} else if (typeof propMap === 'string') {
mapEl = el.querySelector(propMap);
link(obj, property, mapEl, getOutputFunction(mapEl));
}
}
function singleMappingWatch(propMap) {
var mapEl = el.querySelector(propMap.el);
var on = propMap.on;
if (mapEl && on) {
on = on.split(/\s+/);
on.forEach(function (evt) {
watch(mapEl, evt, obj, property, propMap.method);
});
}
}
}
function getOutputFunction(el) {
if (el instanceof HTMLInputElement) {
return set.value;
} else {
return set.text;
}
}
function getInputFunction(el) {
if (el instanceof HTMLInputElement) {
return get.value;
} else {
return get.noop;
}
}
function watch(watchEl, evt, o, prop, fn) {
watchEl = getEl(watchEl);
fn = fn || getInputFunction(watchEl);
watchEl.addEventListener(evt, function(e) {
o[prop] = fn(e, watchEl);
});
}
function getEl(sel, searchEl) {
searchEl = searchEl || document;
if (sel instanceof HTMLElement) {
return sel;
} else if (typeof sel === 'string') {
return searchEl.querySelector(sel);
}
}
function bind(o, el, map) {
for (var sel in map) {
var links = map[sel];
if (sel === '_') {
var els = [el];
} else {
var els = el.querySelectorAll(sel);
}
if (!links || !els) continue;
for (var prop in links) {
for (var i = 0; i < els.length; i++) {
link(o, prop, els[i], links[prop]);
}
}
}
el.__data__ = o;
}
var get = {
value: function value(e, el) {
return el.value;
},
noop: function noop() {}
};
var cssCache = {};
var set = {
'value': function value(el, v) {
el.value = v;
},
'css': function css(prop) {
if (!(prop in cssCache)) {
cssCache[prop] = function(el, v) {
el.style.setProperty(prop, v);
}
}
return cssCache[prop];
},
'text': function text(el, v) {
el.innerHTML = '';
el.appendChild(document.createTextNode(v));
}
};
return {
'link' : link,
'bind' : bind,
'watch': watch,
'map' : map,
'set' : set,
'get' : get
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment