@danielkalen/simplybind
Version:
Magically simple, framework-less one-way/two-way data binding for frontend/backend in ~5kb.
133 lines (109 loc) • 3.06 kB
JavaScript
var h = require('./rendering').html;
var VText = require("virtual-dom/vnode/vtext.js")
var domComponent = require('./domComponent');
function ComponentWidget(state, vdom) {
if (!vdom) {
throw new Error('plastiq.html.component([options], vdom) expects a vdom argument');
}
this.state = state;
this.key = state.key;
if (typeof vdom === 'function') {
this.render = function () {
if (h.currentRender) {
h.currentRender.eventHandlerWrapper = state.on;
}
return vdom.apply(this.state, arguments);
};
this.canRefresh = true;
} else {
vdom = vdom || new VText('');
this.render = function () {
return vdom;
}
}
this.cacheKey = state.cacheKey;
this.component = domComponent();
var renderFinished = h.currentRender && h.currentRender.finished;
if (renderFinished) {
this.afterRender = function (fn) {
renderFinished.then(fn);
};
} else {
this.afterRender = function () {};
}
}
ComponentWidget.prototype.type = 'Widget';
ComponentWidget.prototype.init = function () {
var self = this;
if (self.state.onbeforeadd) {
self.state.onbeforeadd();
}
var vdom = this.render(this);
if (vdom instanceof Array) {
throw new Error('vdom returned from component cannot be an array');
}
var element = this.component.create(vdom);
if (self.state.onadd) {
this.afterRender(function () {
self.state.onadd(element);
});
}
if (self.state.detached) {
return document.createTextNode('');
} else {
return element;
}
};
ComponentWidget.prototype.update = function (previous) {
var self = this;
var refresh = !this.cacheKey || this.cacheKey !== previous.cacheKey;
if (refresh) {
if (self.state.onupdate) {
this.afterRender(function () {
self.state.onupdate(self.component.element);
});
}
}
this.component = previous.component;
if (previous.state && this.state) {
var keys = Object.keys(this.state);
for(var n = 0; n < keys.length; n++) {
var key = keys[n];
previous.state[key] = self.state[key];
}
this.state = previous.state;
}
if (refresh) {
var element = this.component.update(this.render(this));
if (self.state.detached) {
return document.createTextNode('');
} else {
return element;
}
}
};
ComponentWidget.prototype.refresh = function () {
this.component.update(this.render(this));
if (this.state.onupdate) {
this.state.onupdate(this.component.element);
}
};
ComponentWidget.prototype.destroy = function (element) {
var self = this;
if (self.state.onremove) {
this.afterRender(function () {
self.state.onremove(element);
});
}
this.component.destroy();
};
module.exports = function (state, vdom) {
if (typeof state === 'function') {
return new ComponentWidget({}, state);
} else if (state.constructor === Object) {
return new ComponentWidget(state, vdom);
} else {
return new ComponentWidget({}, state);
}
};
module.exports.ComponentWidget = ComponentWidget;