bem-xjst
Version:
Declarative Template Engine for the browser and server
145 lines (116 loc) • 3.45 kB
JavaScript
var utils = require('./utils');
var Match = require('./match').Match;
var tree = require('./tree');
var Template = tree.Template;
var PropertyMatch = tree.PropertyMatch;
var CompilerOptions = tree.CompilerOptions;
function Entity(bemxjst, block, elem, templates) {
this.bemxjst = bemxjst;
this.block = null;
this.elem = null;
// Compiler options via `xjstOptions()`
this.options = {};
// `true` if entity has just a default renderer for `def()` mode
this.canFlush = true;
// "Fast modes"
this.def = new Match(this);
this.mix = new Match(this, 'mix');
this.js = new Match(this, 'js');
this.mods = new Match(this, 'mods');
this.elemMods = new Match(this, 'elemMods');
this.content = new Match(this, 'content');
// "Slow modes"
this.rest = {};
// Initialize
this.init(block, elem);
this.initModes(templates);
}
exports.Entity = Entity;
Entity.prototype.init = function(block, elem) {
this.block = block;
this.elem = elem;
};
Entity.prototype._keys = {
content: 1,
mix: 1,
js: 1,
mods: 1,
elemMods: 1
};
Entity.prototype._initRest = function(key) {
if (key === 'default') {
this.rest[key] = this.def;
} else if (this._keys[key]) {
this.rest[key] = this[key];
} else {
this.rest[key] = this.rest[key] || new Match(this, key);
}
};
Entity.prototype.initModes = function(templates) {
/* jshint maxdepth : false */
for (var i = 0; i < templates.length; i++) {
var template = templates[i];
for (var j = template.predicates.length - 1; j >= 0; j--) {
var pred = template.predicates[j];
if (!(pred instanceof PropertyMatch))
continue;
if (pred.key !== '_mode')
continue;
template.predicates.splice(j, 1);
this._initRest(pred.value);
// All templates should go there anyway
this.rest[pred.value].push(template);
break;
}
if (j === -1)
this.def.push(template);
// Merge compiler options
for (var j = template.predicates.length - 1; j >= 0; j--) {
var pred = template.predicates[j];
if (!(pred instanceof CompilerOptions))
continue;
this.options = utils.extend(this.options, pred.options);
}
}
};
Entity.prototype.prepend = function(other) {
// Prepend to the slow modes, fast modes are in this hashmap too anyway
var keys = Object.keys(this.rest);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!other.rest[key])
continue;
this.rest[key].prepend(other.rest[key]);
}
// Add new slow modes
keys = Object.keys(other.rest);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (this.rest[key])
continue;
this._initRest(key);
this.rest[key].prepend(other.rest[key]);
}
};
// NOTE: This could be potentially compiled into inlined invokations
Entity.prototype.run = function(context) {
if (this.def.count !== 0)
return this.def.exec(context);
return this.defaultBody(context);
};
function contentMode() {
return this.ctx.content;
}
Entity.prototype.setDefaults = function() {
// Default .content() template for applyNext()
if (this.content.count !== 0)
this.content.push(new Template([], contentMode));
// .def() default
if (this.def.count !== 0) {
this.canFlush = this.options.flush || false;
var self = this;
this.def.push(new Template([], function defaultBodyProxy() {
return self.defaultBody(this);
}));
}
};