dynamictemplate
Version:
Δt - async & dynamic templating engine
551 lines (492 loc) • 15.8 kB
JavaScript
(function() {
var Binding, List, ListBinding, adiff, boundpartial, createBinding, deep_get, deep_set, functionify, isArray, listadd, listpartial, listpartialize, listrm, listswitch, listsync, multiplex, slice, test,
__slice = [].slice,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
slice = Array.prototype.slice;
isArray = Array.isArray;
deep_get = function(data, keys) {
var key, next, _i, _len, _ref;
if (data == null) {
return;
}
_ref = keys.split('.');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
key = _ref[_i];
next = data[key];
if (typeof next === 'function') {
next = next.call(data);
}
data = next;
if (data == null) {
break;
}
}
return data;
};
deep_set = function(data, keys, value) {
var key;
if (data == null) {
return;
}
keys = keys.split('.');
key = keys.pop();
data = deep_get(data, keys.join('.'));
return data != null ? data[key] = value : void 0;
};
functionify = function(callback, args) {
var method, methods;
if (typeof callback !== 'function') {
if (isArray(callback)) {
methods = callback;
callback = function(value) {
var method, _i, _len, _ref, _ref1;
for (_i = 0, _len = methods.length; _i < _len; _i++) {
method = methods[_i];
_ref = isArray(method) ? method : [method], method = _ref[0], args = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
if ((_ref1 = this[method]) != null) {
_ref1.apply(this, args.concat([value]));
}
}
};
callback.method = methods;
} else {
method = callback;
callback = function(value) {
var _ref;
return (_ref = this[method]) != null ? _ref.apply(this, args.concat([value])) : void 0;
};
callback.method = method;
}
} else {
return function(value) {
return callback.apply(this, args.concat([value]));
};
}
return callback;
};
multiplex = function(key, callback, args, action) {
var callbacks;
if (typeof key === 'object') {
callbacks = key;
return function() {
var _results;
_results = [];
for (key in callbacks) {
callback = callbacks[key];
callback = functionify(callback, args);
_results.push(action.call(this, key, callback));
}
return _results;
};
} else {
callback = functionify(callback, args);
return function() {
return action.call(this, key, callback);
};
}
};
Binding = (function() {
function Binding(data) {
this.data = data != null ? data : {};
this._binds = {};
}
Binding.prototype.bind = function() {
var args, callback, key, that;
key = arguments[0], callback = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
if (callback == null) {
callback = 'text';
}
that = this;
return multiplex(key, callback, args, function(key, callback) {
var _base, _ref;
((_ref = (_base = that._binds)[key]) != null ? _ref : _base[key] = []).push(callback.bind(this));
return callback.call(this, that.get(key));
});
};
Binding.prototype.unbind = function(key, callback) {
var callbacks, fun, i, _i, _len, _ref;
if (callback != null) {
callbacks = (_ref = this._binds[key]) != null ? _ref : [];
for (i = _i = 0, _len = callbacks.length; _i < _len; i = ++_i) {
fun = callbacks[i];
if (callback === fun || fun.method === callback) {
callbacks.splice(i, 1);
}
}
} else {
delete this._binds[key];
}
return this;
};
Binding.prototype.trigger = function(key, value) {
var callback, _i, _len, _ref, _ref1;
_ref1 = (_ref = this._binds[key]) != null ? _ref : [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
callback = _ref1[_i];
callback(value);
}
return this;
};
Binding.prototype.set = function(key, value) {
deep_set(this.data, key, value);
this.trigger(key, value);
return value;
};
Binding.prototype.get = function(key) {
return deep_get(this.data, key);
};
Binding.prototype.change = function(data) {
var key, value;
if (data == null) {
data = {};
}
for (key in data) {
value = data[key];
this.set(key, value);
}
return this;
};
return Binding;
})();
Binding.multiplex = multiplex;
Binding.Binding = Binding;
module.exports = Binding;
if (1) {
adiff = require('adiff');
List = require('dt-list').List;
slice = Array.prototype.slice;
isArray = Array.isArray;
adiff = adiff({
equal: function(a, b) {
if (a && !b) {
return false;
}
if (isArray(a) && a.length !== b.length) {
return false;
}
return a === b;
}
}, adiff);
createBinding = function(value) {
if (!(value && typeof value === 'object')) {
return value;
}
return new ListBinding(value);
};
boundpartial = function() {
var args, binding, create, partial, value;
create = arguments[0], value = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
binding = createBinding(value);
partial = create.apply(null, [binding].concat(__slice.call(args)));
if (typeof binding === 'object') {
partial._bind = binding;
}
return partial;
};
listadd = function(items, create, old, value) {
var added, i, partial, val, _i, _len;
added = [];
for (i = _i = 0, _len = value.length; _i < _len; i = ++_i) {
val = value[i];
partial = boundpartial(create, val, i);
added.push(partial);
items.push(partial);
}
old.value = slice.call(value);
return [added, [], []];
};
listrm = function(items, old) {
var item, removed, _ref;
removed = [];
while (items.length) {
item = (_ref = items.pop()) != null ? _ref.remove({
soft: false
}) : void 0;
if (item != null) {
removed.push(item);
}
}
old.value = [];
return [[], [], removed];
};
listsync = function(items, create, old, value) {
var added, changed, dead, i, item, n, patch, removed, _i, _j, _k, _len, _ref, _ref1, _ref2, _ref3, _ref4;
_ref = [[], [], {}], added = _ref[0], changed = _ref[1], dead = _ref[2];
_ref1 = adiff.diff(old.value, value);
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
patch = _ref1[_i];
for (i = _j = _ref2 = patch[0], _ref3 = patch[0] + patch[1]; _ref2 <= _ref3 ? _j < _ref3 : _j > _ref3; i = _ref2 <= _ref3 ? ++_j : --_j) {
dead[i] = items[i];
}
for (n = _k = 2, _ref4 = patch.length; 2 <= _ref4 ? _k < _ref4 : _k > _ref4; n = 2 <= _ref4 ? ++_k : --_k) {
i = old.value.indexOf(patch[n]);
if (i === -1) {
patch[n] = boundpartial(create, patch[n], patch[0] + n - 2);
added.push(patch[n]);
} else {
delete dead[i];
patch[n] = items[i];
changed.push(patch[n]);
items[i].remove({
soft: true
});
}
}
items.splice.apply(items, patch);
}
removed = (function() {
var _results;
_results = [];
for (i in dead) {
item = dead[i];
_results.push(item.remove({
soft: false
}));
}
return _results;
})();
old.value = slice.call(value);
return [added, changed, removed];
};
listswitch = function(items, create, old, value) {
var len, old_len, _ref;
_ref = [old.value.length, value.length], old_len = _ref[0], len = _ref[1];
if (!old_len && !len) {
return [[], [], []];
} else if (old_len && !len) {
return listrm(items, old);
} else if (!old_len && len) {
return listadd(items, create, old, value);
} else {
return listsync(items, create, old, value);
}
};
listpartialize = function(items, create, old, value) {
var added, changed, item, itempartial, removed, _i, _j, _len, _len1, _ref;
if (value == null) {
value = [];
}
_ref = listswitch(items, create.bind(this), old, value), added = _ref[0], changed = _ref[1], removed = _ref[2];
for (_i = 0, _len = changed.length; _i < _len; _i++) {
item = changed[_i];
this.add(item);
}
for (_j = 0, _len1 = added.length; _j < _len1; _j++) {
itempartial = added[_j];
if (itempartial.run != null) {
this.add(itempartial);
itempartial.run();
}
}
return this;
};
listpartial = function(items, create, old, value) {
var partial;
partial = boundpartial(create.bind(this), value);
old.value.push(value);
items.push(partial);
if (partial.run != null) {
this.add(partial);
partial.run();
}
return partial;
};
}
ListBinding = (function(_super) {
__extends(ListBinding, _super);
function ListBinding() {
this.items = {};
this.values = {};
this.partials = {};
ListBinding.__super__.constructor.apply(this, arguments);
}
ListBinding.prototype.repeat = function() {
var args, callback, items, key, old, that;
key = arguments[0], callback = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
if (callback == null) {
callback = 'text';
}
that = this;
old = {
value: []
};
items = new List;
return multiplex(key, callback, args, function(key, callback) {
var _base, _ref;
that.items[key] = items;
that.values[key] = old;
that.partials[key] = listpartial.bind(this, items, callback, old);
((_ref = (_base = that._binds)[key]) != null ? _ref : _base[key] = []).push(listpartialize.bind(this, items, callback, old));
return listpartialize.call(this, items, callback, old, that.get(key));
});
};
ListBinding.prototype.unbind = function(key) {
if (this.items[key] != null) {
delete this.items[key];
}
if (this.values[key] != null) {
delete this.values[key];
}
if (this.partials[key] != null) {
delete this.partials[key];
}
return ListBinding.__super__.unbind.apply(this, arguments);
};
ListBinding.prototype.set = function(key, value) {
var curkey, data, i, k, keys, last_key, next, restkeys, result, _i, _len, _ref, _ref1, _ref2;
data = this.data;
keys = key.split('.');
last_key = keys.pop();
curkey = '';
for (i = _i = 0, _len = keys.length; _i < _len; i = ++_i) {
k = keys[i];
curkey += (curkey && '.' || '') + k;
next = data[k];
if (typeof next === 'function') {
next = next.call(data);
}
data = next;
if (isArray(data)) {
restkeys = keys.slice(i + 1);
restkeys.push(last_key);
result = (_ref = this.items[curkey][k]) != null ? (_ref1 = _ref._bind) != null ? _ref1.set(restkey.join('.'), value) : void 0 : void 0;
if (((_ref2 = this.items[curkey][k]) != null ? _ref2._bind : void 0) != null) {
this.trigger(key, result);
}
return result;
}
if (data == null) {
break;
}
}
if (data != null) {
data[last_key] = value;
}
if (data != null) {
this.trigger(key, value);
}
return value;
};
ListBinding.prototype.addTo = function(key, value) {
var _base;
return typeof (_base = this.partials)[key] === "function" ? _base[key](value) : void 0;
};
ListBinding.prototype.removeFrom = function(key, i) {
if (this.values[key] == null) {
return;
}
this.values[key].value.splice(i, 1);
delete this.items[i]._bind;
return this.items.remove(i);
};
return ListBinding;
})(Binding);
if (0) {
ListBinding.listpartial = listpartial;
ListBinding.listsync = listsync;
ListBinding.ListBinding = ListBinding;
ListBinding.Binding = ListBinding;
module.exports = ListBinding;
}
test = function() {
var Template, data, i, numbers, render, template, tpl;
Template = require('./template');
render = require('./render');
template = function(data) {
return new Template({
schema: 5,
pretty: true
}, function() {
return this.$html(function() {
this.$head(function() {
return this.$title("test");
});
return this.$body(function() {
return this.$main(function() {
this.$div({
"class": 'users'
}, function() {
return this.$span('foobar');
});
this.$ul({
"class": 'users'
}, data.repeat('users', function(user) {
return this.$li({
"class": 'user'
}, function() {
user.bind('title', 'attr', 'title').call(this);
this.$div({
"class": 'name'
}, user.bind({
'name': 'text',
'age': ['attr', 'data-age'],
'repo': ['attr', 'data-repo']
}));
this.$div({
"class": 'repo'
}, user.bind('repo'));
this.$div({
"class": 'age'
}, user.bind('age'));
return this.$div({
"class": 'box'
}, user.bind('box.color', 'attr', 'data-color'));
});
}));
this.$h3("next lotto numbers are …");
return this.$ul({
"class": 'numbers'
}, data.repeat('lotto', '$li'));
});
});
});
});
};
numbers = (function() {
var _i, _results;
_results = [];
for (i = _i = 1; _i <= 10; i = ++_i) {
_results.push(Math.round(Math.random() * 100));
}
return _results;
})();
data = new ListBinding({
lotto: numbers,
users: [
{
name: "foobar",
age: 3,
repo: "git",
title: "red box",
box: {
color: "red"
}
}, {
name: "trololo",
age: 6,
repo: "hg",
title: "pink box",
box: {
color: "pink"
}
}
]
});
tpl = template(data);
tpl.ready(function() {
setTimeout(function() {
return data.set('users.0.name', "trololo");
}, 500);
setTimeout(function() {
return data.set('users.0.age', 6);
}, 1500);
return setTimeout(function() {
data.set('users.1.title', "green box");
return data.set('users.1.box.color', "green");
}, 1500);
});
return render(tpl).pipe(process.stdout);
};
test();
}).call(this);