Created
November 10, 2015 15:59
-
-
Save tadatuta/bbf67d79e94693ebdcda to your computer and use it in GitHub Desktop.
bem-xjst@4 basic templates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// ------------------------------------- | |
/// --------- BEM-XJST Runtime Start ---- | |
/// ------------------------------------- | |
var BEMHTML = function(module, exports) { | |
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bemhtml = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
module.exports = require('../../bemxjst/runtime'); | |
},{"../../bemxjst/runtime":5}],2:[function(require,module,exports){ | |
function ClassBuilder(options) { | |
this.modDelim = options.mod || '_'; | |
this.elemDelim = options.elem || '__'; | |
} | |
exports.ClassBuilder = ClassBuilder; | |
ClassBuilder.prototype.build = function build(block, elem) { | |
if (elem === undefined) | |
return block; | |
else | |
return block + this.elemDelim + elem; | |
}; | |
ClassBuilder.prototype.buildModPostfix = function buildModPostfix(modName, | |
modVal) { | |
var res = this.modDelim + modName; | |
if (modVal !== true) res += this.modDelim + modVal; | |
return res; | |
}; | |
ClassBuilder.prototype.buildBlockClass = function buildBlockClass(name, | |
modName, | |
modVal) { | |
var res = name; | |
if (modVal) res += this.buildModPostfix(modName, modVal); | |
return res; | |
}; | |
ClassBuilder.prototype.buildElemClass = function buildElemClass(block, | |
name, | |
modName, | |
modVal) { | |
var res = this.buildBlockClass(block) + this.elemDelim + name; | |
if (modVal) res += this.buildModPostfix(modName, modVal); | |
return res; | |
}; | |
ClassBuilder.prototype.split = function split(key) { | |
return key.split(this.elemDelim, 2); | |
}; | |
},{}],3:[function(require,module,exports){ | |
var utils = require('./utils'); | |
function Context(bemxjst) { | |
this._bemxjst = bemxjst; | |
this.ctx = null; | |
this.block = ''; | |
// Save current block until the next BEM entity | |
this._currBlock = ''; | |
this.elem = null; | |
this.mods = {}; | |
this.elemMods = {}; | |
this.position = 0; | |
this._listLength = 0; | |
this._notNewList = false; | |
this._uniq = null; | |
// Used in `OnceMatch` check to detect context change | |
this._onceRef = {}; | |
} | |
exports.Context = Context; | |
Context.prototype._flush = null; | |
Context.prototype.isArray = utils.isArray; | |
Context.prototype.isSimple = utils.isSimple; | |
Context.prototype.isShortTag = utils.isShortTag; | |
Context.prototype.extend = utils.extend; | |
Context.prototype.identify = utils.identify; | |
Context.prototype.xmlEscape = utils.xmlEscape; | |
Context.prototype.attrEscape = utils.attrEscape; | |
Context.prototype.jsAttrEscape = utils.jsAttrEscape; | |
Context.prototype.BEM = {}; | |
Context.prototype.isFirst = function isFirst() { | |
return this.position === 1; | |
}; | |
Context.prototype.isLast = function isLast() { | |
return this.position === this._listLength; | |
}; | |
Context.prototype.generateId = function generateId() { | |
if (this._uniq === null) | |
this._uniq = utils.getUniq(); | |
return this._uniq; | |
}; | |
Context.prototype.reapply = function reapply(ctx) { | |
return this._bemxjst.run(ctx); | |
}; | |
},{"./utils":8}],4:[function(require,module,exports){ | |
var utils = require('./utils'); | |
var Template = require('./tree').Template; | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var CompilerOptions = require('./tree').CompilerOptions; | |
var Match = require('./match').Match; | |
function Entity(bemxjst, block, elem, templates) { | |
this.bemxjst = bemxjst; | |
this.block = null; | |
this.elem = null; | |
this.jsClass = null; | |
// `true` if entity has just a default renderer for `def()` mode | |
this.canFlush = true; | |
// Compiler options via `xjstOptions()` | |
this.options = {}; | |
// "Fast modes" | |
this.def = new Match(this); | |
this.tag = new Match(this); | |
this.attrs = new Match(this); | |
this.mod = new Match(this); | |
this.js = new Match(this); | |
this.mix = new Match(this); | |
this.bem = new Match(this); | |
this.cls = new Match(this); | |
this.content = new Match(this); | |
// "Slow modes" | |
this.rest = {}; | |
// Initialize | |
this.init(block, elem); | |
this.initModes(templates); | |
} | |
exports.Entity = Entity; | |
Entity.prototype.init = function init(block, elem) { | |
this.block = block; | |
this.elem = elem; | |
// Class for jsParams | |
this.jsClass = this.bemxjst.classBuilder.build(this.block, this.elem); | |
}; | |
function contentMode() { | |
return this.ctx.content; | |
} | |
Entity.prototype.initModes = function initModes(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._initRest = function _initRest(key) { | |
if (key === 'tag' || | |
key === 'attrs' || | |
key === 'js' || | |
key === 'mix' || | |
key === 'bem' || | |
key === 'cls' || | |
key === 'content' || | |
key === 'default') { | |
if (key === 'default') | |
this.rest[key] = this.def; | |
else | |
this.rest[key] = this[key]; | |
} else { | |
if (!this.rest.hasOwnProperty(key)) | |
this.rest[key] = new Match(this); | |
} | |
}; | |
Entity.prototype.setDefaults = function setDefaults() { | |
// Default .content() template for applyNext() | |
if (this.content.count !== 0) | |
this.content.push(new Template([], contentMode)); | |
// .def() default | |
if (this.def.count !== 0) { | |
// `.xjstOptions({ flush: true })` will override this | |
this.canFlush = this.options.flush || false; | |
var self = this; | |
this.def.push(new Template([], function defaultBodyProxy() { | |
return self.defaultBody(this); | |
})); | |
} | |
}; | |
Entity.prototype.prepend = function prepend(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 run(context) { | |
if (this.def.count !== 0) | |
return this.def.exec(context); | |
return this.defaultBody(context); | |
}; | |
Entity.prototype.defaultBody = function defaultBody(context) { | |
var tag = context.ctx.tag; | |
if (tag === undefined) | |
tag = this.tag.exec(context); | |
var js; | |
if (context.ctx.js !== false) | |
js = this.js.exec(context); | |
var bem = this.bem.exec(context); | |
var cls = this.cls.exec(context); | |
var mix = this.mix.exec(context); | |
var attrs = this.attrs.exec(context); | |
var content = this.content.exec(context); | |
// Default content | |
if (this.content.count === 0 && content === undefined) | |
content = context.ctx.content; | |
return this.bemxjst.render(context, | |
this, | |
tag, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content); | |
}; | |
},{"./match":6,"./tree":7,"./utils":8}],5:[function(require,module,exports){ | |
var inherits = require('inherits'); | |
var Tree = require('./tree').Tree; | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var Entity = require('./entity').Entity; | |
var Context = require('./context').Context; | |
var ClassBuilder = require('./class-builder').ClassBuilder; | |
var utils = require('./utils'); | |
function BEMXJST(options) { | |
this.options = options || {}; | |
this.entities = null; | |
this.defaultEnt = null; | |
// Current tree | |
this.tree = null; | |
// Current match | |
this.match = null; | |
// Create new Context constructor for overriding prototype | |
this.contextConstructor = function ContextChild(bemxjst) { | |
Context.call(this, bemxjst); | |
}; | |
inherits(this.contextConstructor, Context); | |
this.context = null; | |
this.classBuilder = new ClassBuilder(this.options.naming || {}); | |
// Execution depth, used to invalidate `applyNext` bitfields | |
this.depth = 0; | |
// Do not call `_flush` on overridden `def()` mode | |
this.canFlush = false; | |
// oninit templates | |
this.oninit = null; | |
// Initialize default entity (no block/elem match) | |
this.defaultEnt = new Entity(this, '', '', []); | |
this.defaultElemEnt = new Entity(this, '', '', []); | |
} | |
module.exports = BEMXJST; | |
BEMXJST.locals = Tree.methods.concat('local', 'applyCtx', 'applyNext', 'apply'); | |
BEMXJST.prototype.compile = function compile(code) { | |
var self = this; | |
function applyCtx() { | |
return self._run(self.context.ctx); | |
} | |
function applyCtxWrap(ctx, changes) { | |
// Fast case | |
if (!changes) | |
return self.local({ ctx: ctx }, applyCtx); | |
return self.local(changes, function() { | |
return self.local({ ctx: ctx }, applyCtx); | |
}); | |
} | |
function apply(mode, changes) { | |
return self.applyMode(mode, changes); | |
} | |
function localWrap(changes) { | |
return function localBody(body) { | |
return self.local(changes, body); | |
}; | |
} | |
var tree = new Tree({ | |
refs: { | |
applyCtx: applyCtxWrap, | |
local: localWrap | |
} | |
}); | |
// Yeah, let people pass functions to us! | |
var templates = this.recompileInput(code); | |
var out = tree.build(templates, [ | |
localWrap, | |
applyCtxWrap, | |
function applyNextWrap(changes) { | |
if (changes) | |
return self.local(changes, applyNextWrap); | |
return self.applyNext(); | |
}, | |
apply | |
]); | |
// Concatenate templates with existing ones | |
// TODO(indutny): it should be possible to incrementally add templates | |
if (this.tree) { | |
out = { | |
templates: out.templates.concat(this.tree.templates), | |
oninit: this.tree.oninit.concat(out.oninit) | |
}; | |
} | |
this.tree = out; | |
// Group block+elem entities into a hashmap | |
var ent = this.groupEntities(out.templates); | |
// Transform entities from arrays to Entity instances | |
ent = this.transformEntities(ent); | |
this.entities = ent; | |
this.oninit = out.oninit; | |
}; | |
BEMXJST.prototype.recompileInput = function recompileInput(code) { | |
var out = code.toString(); | |
var args = BEMXJST.locals; | |
if (typeof code === 'function') { | |
var start = out.match(/^function\s*\(([^{]+)\)\s*{/); | |
// Reuse function if it already has right arguments | |
if (start !== null && start[1].split(/,\s*/).length === args.length) | |
return code; | |
} | |
// Strip the function | |
out = out.replace(/^function[^{]+{|}$/g, ''); | |
// And recompile it with right arguments | |
out = new Function(args.join(', '), out); | |
return out; | |
}; | |
BEMXJST.prototype.groupEntities = function groupEntities(tree) { | |
var res = {}; | |
for (var i = 0; i < tree.length; i++) { | |
// Make sure to change only the copy, the original is cached in `this.tree` | |
var template = tree[i].clone(); | |
var block = null; | |
var elem; | |
elem = undefined; | |
for (var j = 0; j < template.predicates.length; j++) { | |
var pred = template.predicates[j]; | |
if (!(pred instanceof PropertyMatch)) | |
continue; | |
if (pred.key === 'block') | |
block = pred.value; | |
else if (pred.key === 'elem') | |
elem = pred.value; | |
else | |
continue; | |
// Remove predicate, we won't much against it | |
template.predicates.splice(j, 1); | |
j--; | |
} | |
// TODO(indutny): print out the template itself | |
if (block === null) | |
throw new Error('block("...") not found in one of the templates'); | |
var key = this.classBuilder.build(block, elem); | |
if (!res[key]) | |
res[key] = []; | |
res[key].push(template); | |
} | |
return res; | |
}; | |
BEMXJST.prototype.transformEntities = function transformEntities(entities) { | |
var wildcardElems = []; | |
var keys = Object.keys(entities); | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
// TODO(indutny): pass this values over | |
var parts = this.classBuilder.split(key); | |
var block = parts[0]; | |
var elem = parts[1]; | |
if (elem === '*') | |
wildcardElems.push(block); | |
entities[key] = new Entity(this, block, elem, entities[key]); | |
} | |
// Merge wildcard block templates | |
if (entities.hasOwnProperty('*')) { | |
var wildcard = entities['*']; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
if (key === '*') | |
continue; | |
entities[key].prepend(wildcard); | |
} | |
this.defaultEnt.prepend(wildcard); | |
this.defaultElemEnt.prepend(wildcard); | |
} | |
// Merge wildcard elem templates | |
for (var i = 0; i < wildcardElems.length; i++) { | |
var block = wildcardElems[i]; | |
var wildcardKey = this.classBuilder.build(block, '*'); | |
var wildcard = entities[wildcardKey]; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
if (key === wildcardKey) | |
continue; | |
var entity = entities[key]; | |
if (entity.block !== block) | |
continue; | |
if (entity.elem === undefined) | |
continue; | |
entities[key].prepend(wildcard); | |
} | |
this.defaultElemEnt.prepend(wildcard); | |
} | |
// Set default templates after merging with wildcard | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
entities[key].setDefaults(); | |
this.defaultEnt.setDefaults(); | |
this.defaultElemEnt.setDefaults(); | |
} | |
return entities; | |
}; | |
BEMXJST.prototype._run = function _run(context) { | |
var res; | |
if (context === undefined || context === '' || context === null) | |
res = this.runEmpty(); | |
else if (utils.isArray(context)) | |
res = this.runMany(context); | |
else if (utils.isSimple(context)) | |
res = this.runSimple(context); | |
else | |
res = this.runOne(context); | |
return res; | |
}; | |
BEMXJST.prototype.run = function run(json) { | |
var match = this.match; | |
var context = this.context; | |
this.match = null; | |
this.context = new this.contextConstructor(this); | |
this.canFlush = this.context._flush !== null; | |
this.depth = 0; | |
var res = this._run(json); | |
if (this.canFlush) | |
res = this.context._flush(res); | |
this.match = match; | |
this.context = context; | |
return res; | |
}; | |
BEMXJST.prototype.runEmpty = function runEmpty() { | |
this.context._listLength--; | |
return ''; | |
}; | |
BEMXJST.prototype.runMany = function runMany(arr) { | |
var out = ''; | |
var context = this.context; | |
var prevPos = context.position; | |
var prevNotNewList = context._notNewList; | |
if (prevNotNewList) { | |
context._listLength += arr.length - 1; | |
} else { | |
context.position = 0; | |
context._listLength = arr.length; | |
} | |
context._notNewList = true; | |
if (this.canFlush) { | |
for (var i = 0; i < arr.length; i++) | |
out += context._flush(this._run(arr[i])); | |
} else { | |
for (var i = 0; i < arr.length; i++) | |
out += this._run(arr[i]); | |
} | |
if (!prevNotNewList) | |
context.position = prevPos; | |
return out; | |
}; | |
BEMXJST.prototype.runSimple = function runSimple(context) { | |
this.context._listLength--; | |
var res = ''; | |
if (context && context !== true || context === 0) | |
res += context; | |
return res; | |
}; | |
BEMXJST.prototype.runOne = function runOne(json) { | |
var context = this.context; | |
var oldCtx = context.ctx; | |
var oldBlock = context.block; | |
var oldCurrBlock = context._currBlock; | |
var oldElem = context.elem; | |
var oldMods = context.mods; | |
var oldElemMods = context.elemMods; | |
if (json.block || json.elem) | |
context._currBlock = ''; | |
else | |
context._currBlock = context.block; | |
context.ctx = json; | |
if (json.block) { | |
context.block = json.block; | |
if (json.mods) | |
context.mods = json.mods; | |
else | |
context.mods = {}; | |
} else { | |
if (!json.elem) | |
context.block = ''; | |
else if (oldCurrBlock) | |
context.block = oldCurrBlock; | |
} | |
context.elem = json.elem; | |
if (json.elemMods) | |
context.elemMods = json.elemMods; | |
else | |
context.elemMods = {}; | |
var block = context.block || ''; | |
var elem = context.elem; | |
// Control list position | |
if (block || elem) | |
context.position++; | |
else | |
context._listLength--; | |
// To invalidate `applyNext` flags | |
this.depth++; | |
var key = this.classBuilder.build(block, elem); | |
var restoreFlush = false; | |
var ent = this.entities[key]; | |
if (ent) { | |
if (this.canFlush && !ent.canFlush) { | |
// Entity does not support flushing, do not flush anything nested | |
restoreFlush = true; | |
this.canFlush = false; | |
} | |
} else { | |
// No entity - use default one | |
ent = this.defaultEnt; | |
if (elem !== undefined) | |
ent = this.defaultElemEnt; | |
ent.init(block, elem); | |
} | |
var res = ent.run(context); | |
context.ctx = oldCtx; | |
context.block = oldBlock; | |
context.elem = oldElem; | |
context.mods = oldMods; | |
context.elemMods = oldElemMods; | |
context._currBlock = oldCurrBlock; | |
this.depth--; | |
if (restoreFlush) | |
this.canFlush = true; | |
return res; | |
}; | |
BEMXJST.prototype.render = function render(context, | |
entity, | |
tag, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content) { | |
var ctx = context.ctx; | |
if (tag === undefined) | |
tag = 'div'; | |
if (!tag) | |
return this.renderNoTag(context, js, bem, cls, mix, attrs, content); | |
var out = '<' + tag; | |
var ctxJS = ctx.js; | |
if (ctxJS !== false) { | |
if (js === true) | |
js = {}; | |
if (js) { | |
if (ctxJS !== true) | |
js = utils.extend(ctxJS, js); | |
} else if (ctxJS === true) { | |
js = {}; | |
} else { | |
js = ctxJS; | |
} | |
} | |
var jsParams; | |
if (js) { | |
jsParams = {}; | |
jsParams[entity.jsClass] = js; | |
} | |
var isBEM = bem; | |
if (isBEM === undefined) { | |
if (ctx.bem === undefined) | |
isBEM = entity.block || entity.elem; | |
else | |
isBEM = ctx.bem; | |
} | |
isBEM = !!isBEM; | |
if (cls === undefined) | |
cls = ctx.cls; | |
var addJSInitClass = entity.block && jsParams && !entity.elem; | |
if (!isBEM && !cls) { | |
return this.renderClose(out, context, tag, attrs, isBEM, ctx, content); | |
} | |
out += ' class="'; | |
if (isBEM) { | |
var mods = ctx.elemMods || ctx.mods; | |
if (!mods && ctx.block) | |
mods = context.mods; | |
out += entity.jsClass; | |
out += this.buildModsClasses(entity.block, entity.elem, mods); | |
var totalMix = mix; | |
if (ctx.mix) { | |
if (totalMix) | |
totalMix = [].concat(totalMix, ctx.mix); | |
else | |
totalMix = ctx.mix; | |
} | |
if (totalMix) { | |
var m = this.renderMix(entity, totalMix, jsParams, addJSInitClass); | |
out += m.out; | |
jsParams = m.jsParams; | |
addJSInitClass = m.addJSInitClass; | |
} | |
if (cls) | |
out += ' ' + cls; | |
} else { | |
if (cls) | |
out += cls; | |
} | |
if (addJSInitClass) | |
out += ' i-bem"'; | |
else | |
out += '"'; | |
if (isBEM && jsParams) | |
out += ' data-bem=\'' + utils.jsAttrEscape(JSON.stringify(jsParams)) + '\''; | |
return this.renderClose(out, context, tag, attrs, isBEM, ctx, content); | |
}; | |
BEMXJST.prototype.renderClose = function renderClose(prefix, | |
context, | |
tag, | |
attrs, | |
isBEM, | |
ctx, | |
content) { | |
var out = prefix; | |
// NOTE: maybe we need to make an array for quicker serialization | |
attrs = utils.extend(attrs, ctx.attrs); | |
if (attrs) { | |
var name; // TODO: do something with OmetaJS and YUI Compressor | |
/* jshint forin : false */ | |
for (name in attrs) { | |
var attr = attrs[name]; | |
if (attr === undefined) | |
continue; | |
// TODO(indutny): support `this.reapply()` | |
out += ' ' + name + '="' + | |
utils.attrEscape(utils.isSimple(attr) ? | |
attr : | |
this.reapply(attr)) + | |
'"'; | |
} | |
} | |
if (utils.isShortTag(tag)) { | |
out += '/>'; | |
if (this.canFlush) | |
out = context._flush(out); | |
} else { | |
out += '>'; | |
if (this.canFlush) | |
out = context._flush(out); | |
// TODO(indutny): skip apply next flags | |
if (content || content === 0) | |
out += this.renderContent(content, isBEM); | |
out += '</' + tag + '>'; | |
} | |
if (this.canFlush) | |
out = context._flush(out); | |
return out; | |
}; | |
BEMXJST.prototype.renderMix = function renderMix(entity, | |
mix, | |
jsParams, | |
addJSInitClass) { | |
var visited = {}; | |
var context = this.context; | |
var js = jsParams; | |
var addInit = addJSInitClass; | |
visited[entity.jsClass] = true; | |
// Transform mix to the single-item array if it's not array | |
if (!utils.isArray(mix)) | |
mix = [ mix ]; | |
var classBuilder = this.classBuilder; | |
var out = ''; | |
for (var i = 0; i < mix.length; i++) { | |
var item = mix[i]; | |
if (item === undefined) | |
continue; | |
if (typeof item === 'string') | |
item = { block: item, elem: undefined }; | |
var hasItem = item.block || item.elem; | |
var block = item.block || item._block || context.block; | |
var elem = item.elem || item._elem || context.elem; | |
var key = classBuilder.build(block, elem); | |
var classElem = item.elem || | |
item._elem || | |
(item.block ? undefined : context.elem); | |
if (hasItem) | |
out += ' ' + classBuilder.build(block, classElem); | |
out += this.buildModsClasses(block, classElem, item.elemMods || item.mods); | |
if (item.js) { | |
if (!js) | |
js = {}; | |
js[classBuilder.build(block, item.elem)] = | |
item.js === true ? {} : item.js; | |
if (!addInit) | |
addInit = block && !item.elem; | |
} | |
// Process nested mixes | |
if (!hasItem || visited[key]) | |
continue; | |
visited[key] = true; | |
var nestedEntity = this.entities[key]; | |
if (!nestedEntity) | |
continue; | |
var oldBlock = context.block; | |
var oldElem = context.elem; | |
var nestedMix = nestedEntity.mix.exec(context); | |
context.elem = oldElem; | |
context.block = oldBlock; | |
if (!nestedMix) | |
continue; | |
for (var j = 0; j < nestedMix.length; j++) { | |
var nestedItem = nestedMix[j]; | |
if (!nestedItem.block && | |
!nestedItem.elem || | |
!visited[classBuilder.build(nestedItem.block, nestedItem.elem)]) { | |
nestedItem._block = block; | |
nestedItem._elem = elem; | |
mix = mix.slice(0, i + 1).concat( | |
nestedItem, | |
mix.slice(i + 1) | |
); | |
} | |
} | |
} | |
return { | |
out: out, | |
jsParams: js, | |
addJSInitClass: addInit | |
}; | |
}; | |
BEMXJST.prototype.buildModsClasses = function buildModsClasses(block, | |
elem, | |
mods) { | |
if (!mods) | |
return ''; | |
var res = ''; | |
var modName; | |
for (modName in mods) { | |
if (!mods.hasOwnProperty(modName)) | |
continue; | |
var modVal = mods[modName]; | |
if (!modVal && modVal !== 0) continue; | |
if (typeof modVal !== 'boolean') | |
modVal += ''; | |
var builder = this.classBuilder; | |
res += ' ' + (elem ? | |
builder.buildElemClass(block, elem, modName, modVal) : | |
builder.buildBlockClass(block, modName, modVal)); | |
} | |
return res; | |
}; | |
BEMXJST.prototype.renderContent = function renderContent(content, isBEM) { | |
var context = this.context; | |
var oldPos = context.position; | |
var oldListLength = context._listLength; | |
var oldNotNewList = context._notNewList; | |
context._notNewList = false; | |
if (isBEM) { | |
context.position = 1; | |
context._listLength = 1; | |
} | |
var res = this._run(content); | |
context.position = oldPos; | |
context._listLength = oldListLength; | |
context._notNewList = oldNotNewList; | |
return res; | |
}; | |
BEMXJST.prototype.renderNoTag = function renderNoTag(context, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content) { | |
// TODO(indutny): skip apply next flags | |
if (content || content === 0) | |
return this._run(content); | |
return ''; | |
}; | |
BEMXJST.prototype.local = function local(changes, body) { | |
var keys = Object.keys(changes); | |
var restore = []; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
var parts = key.split('.'); | |
var value = this.context; | |
for (var j = 0; j < parts.length - 1; j++) | |
value = value[parts[j]]; | |
restore.push({ | |
parts: parts, | |
value: value[parts[j]] | |
}); | |
value[parts[j]] = changes[key]; | |
} | |
var res = body.call(this.context); | |
for (var i = 0; i < restore.length; i++) { | |
var parts = restore[i].parts; | |
var value = this.context; | |
for (var j = 0; j < parts.length - 1; j++) | |
value = value[parts[j]]; | |
value[parts[j]] = restore[i].value; | |
} | |
return res; | |
}; | |
BEMXJST.prototype.applyNext = function applyNext() { | |
return this.match.exec(this.context); | |
}; | |
BEMXJST.prototype.applyMode = function applyMode(mode, changes) { | |
var match = this.match.entity.rest[mode]; | |
if (!match) | |
return; | |
if (!changes) | |
return match.exec(this.context); | |
var self = this; | |
// Allocate function this way, to prevent allocation at the top of the | |
// `applyMode` | |
var fn = function localBody() { | |
return match.exec(self.context); | |
}; | |
return this.local(changes, fn); | |
}; | |
BEMXJST.prototype.exportApply = function exportApply(exports) { | |
var self = this; | |
exports.apply = function apply(context) { | |
return self.run(context); | |
}; | |
// Add templates at run time | |
exports.compile = function compile(templates) { | |
return self.compile(templates); | |
}; | |
var sharedContext = {}; | |
exports.BEMContext = this.contextConstructor; | |
sharedContext.BEMContext = exports.BEMContext; | |
for (var i = 0; i < this.oninit.length; i++) { | |
var oninit = this.oninit[i]; | |
oninit(exports, sharedContext); | |
} | |
}; | |
},{"./class-builder":2,"./context":3,"./entity":4,"./tree":7,"./utils":8,"inherits":9}],6:[function(require,module,exports){ | |
var utils = require('./utils'); | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var OnceMatch = require('./tree').OnceMatch; | |
var WrapMatch = require('./tree').WrapMatch; | |
var PropertyAbsent = require('./tree').PropertyAbsent; | |
var CustomMatch = require('./tree').CustomMatch; | |
function MatchProperty(template, pred) { | |
this.template = template; | |
this.key = pred.key; | |
this.value = pred.value; | |
} | |
MatchProperty.prototype.exec = function exec(context) { | |
return context[this.key] === this.value; | |
}; | |
function MatchNested(template, pred) { | |
this.template = template; | |
this.keys = pred.key; | |
this.value = pred.value; | |
} | |
MatchNested.prototype.exec = function exec(context) { | |
var val = context; | |
for (var i = 0; i < this.keys.length - 1; i++) { | |
val = val[this.keys[i]]; | |
if (!val) | |
return false; | |
} | |
return val[this.keys[i]] === this.value; | |
}; | |
function MatchAbsent(template, pred) { | |
this.template = template; | |
this.key = pred.key; | |
} | |
MatchAbsent.prototype.exec = function exec(context) { | |
return !context[this.key]; | |
}; | |
function MatchCustom(template, pred) { | |
this.template = template; | |
this.body = pred.body; | |
} | |
MatchCustom.prototype.exec = function exec(context) { | |
return this.body.call(context); | |
}; | |
function MatchOnce(template) { | |
this.template = template; | |
this.once = null; | |
} | |
MatchOnce.prototype.exec = function exec(context) { | |
var res = this.once !== context._onceRef; | |
this.once = context._onceRef; | |
return res; | |
}; | |
function MatchWrap(template) { | |
this.template = template; | |
this.wrap = null; | |
} | |
MatchWrap.prototype.exec = function exec(context) { | |
var res = this.wrap !== context.ctx; | |
this.wrap = context.ctx; | |
return res; | |
}; | |
function MatchTemplate(mode, template) { | |
this.mode = mode; | |
this.predicates = new Array(template.predicates.length); | |
this.body = template.body; | |
var postpone = []; | |
for (var i = 0, j = 0; i < this.predicates.length; i++, j++) { | |
var pred = template.predicates[i]; | |
if (pred instanceof PropertyMatch) { | |
if (utils.isArray(pred.key)) | |
this.predicates[j] = new MatchNested(this, pred); | |
else | |
this.predicates[j] = new MatchProperty(this, pred); | |
} else if (pred instanceof PropertyAbsent) { | |
this.predicates[j] = new MatchAbsent(this, pred); | |
} else if (pred instanceof CustomMatch) { | |
this.predicates[j] = new MatchCustom(this, pred); | |
// Push OnceMatch and MatchWrap later, they should not be executed first. | |
// Otherwise they will set flag too early, and body might not be executed | |
} else if (pred instanceof OnceMatch) { | |
j--; | |
postpone.push(new MatchOnce(this)); | |
} else if (pred instanceof WrapMatch) { | |
j--; | |
postpone.push(new MatchWrap(this)); | |
} else { | |
// Skip | |
j--; | |
} | |
} | |
// Insert late predicates | |
for (var i = postpone.length - 1; i >= 0; i--) | |
this.predicates[i + j] = this.predicates[i]; | |
for (var i = 0; i < postpone.length; i++) | |
this.predicates[i] = postpone[i]; | |
j += postpone.length; | |
if (this.predicates.length !== j) | |
this.predicates.length = j; | |
} | |
exports.MatchTemplate = MatchTemplate; | |
function Match(entity) { | |
this.entity = entity; | |
this.bemxjst = this.entity.bemxjst; | |
this.templates = []; | |
// applyNext mask | |
this.mask = [ 0 ]; | |
// We are going to create copies of mask for nested `applyNext()` | |
this.maskSize = 0; | |
this.maskOffset = 0; | |
this.count = 0; | |
this.depth = -1; | |
} | |
exports.Match = Match; | |
Match.prototype.clone = function clone(entity) { | |
var res = new Match(entity); | |
res.templates = this.templates.slice(); | |
res.mask = this.mask.slice(); | |
res.maskSize = this.maskSize; | |
res.count = this.count; | |
return res; | |
}; | |
Match.prototype.prepend = function prepend(other) { | |
this.templates = other.templates.concat(this.templates); | |
this.count += other.count; | |
while (Math.ceil(this.count / 31) > this.mask.length) | |
this.mask.push(0); | |
this.maskSize = this.mask.length; | |
}; | |
Match.prototype.push = function push(template) { | |
this.templates.push(new MatchTemplate(this, template)); | |
this.count++; | |
if (Math.ceil(this.count / 31) > this.mask.length) | |
this.mask.push(0); | |
this.maskSize = this.mask.length; | |
}; | |
Match.prototype.exec = function exec(context) { | |
var save = this.checkDepth(); | |
var template; | |
var bitIndex = this.maskOffset; | |
var mask = this.mask[bitIndex]; | |
var bit = 1; | |
for (var i = 0; i < this.count; i++) { | |
if ((mask & bit) === 0) { | |
template = this.templates[i]; | |
for (var j = template.predicates.length - 1; j >= 0; j--) { | |
var pred = template.predicates[j]; | |
/* jshint maxdepth : false */ | |
if (!pred.exec(context)) | |
break; | |
} | |
// All predicates matched! | |
if (j === -1) | |
break; | |
} | |
if (bit === 0x40000000) { | |
bitIndex++; | |
mask = this.mask[bitIndex]; | |
bit = 1; | |
} else { | |
bit <<= 1; | |
} | |
} | |
if (i === this.count) | |
return undefined; | |
var oldMask = mask; | |
var oldMatch = this.bemxjst.match; | |
this.mask[bitIndex] |= bit; | |
this.bemxjst.match = this; | |
var out; | |
if (typeof template.body === 'function') | |
out = template.body.call(context); | |
else | |
out = template.body; | |
this.mask[bitIndex] = oldMask; | |
this.bemxjst.match = oldMatch; | |
this.restoreDepth(save); | |
return out; | |
}; | |
Match.prototype.checkDepth = function checkDepth() { | |
if (this.depth === -1) { | |
this.depth = this.bemxjst.depth; | |
return -1; | |
} | |
if (this.bemxjst.depth === this.depth) | |
return this.depth; | |
var depth = this.depth; | |
this.depth = this.bemxjst.depth; | |
this.maskOffset += this.maskSize; | |
while (this.mask.length < this.maskOffset + this.maskSize) | |
this.mask.push(0); | |
return depth; | |
}; | |
Match.prototype.restoreDepth = function restoreDepth(depth) { | |
if (depth !== -1 && depth !== this.depth) | |
this.maskOffset -= this.maskSize; | |
this.depth = depth; | |
}; | |
},{"./tree":7,"./utils":8}],7:[function(require,module,exports){ | |
var assert = require('minimalistic-assert'); | |
var inherits = require('inherits'); | |
function Template(predicates, body) { | |
this.predicates = predicates; | |
this.body = body; | |
} | |
exports.Template = Template; | |
Template.prototype.wrap = function wrap() { | |
var body = this.body; | |
for (var i = 0; i < this.predicates.length; i++) { | |
var pred = this.predicates[i]; | |
body = pred.wrapBody(body); | |
} | |
this.body = body; | |
}; | |
Template.prototype.clone = function clone() { | |
return new Template(this.predicates.slice(), this.body); | |
}; | |
function MatchBase() { | |
} | |
exports.MatchBase = MatchBase; | |
MatchBase.prototype.wrapBody = function wrapBody(body) { | |
return body; | |
}; | |
function Item(tree, children) { | |
this.conditions = []; | |
this.children = []; | |
for (var i = children.length - 1; i >= 0; i--) { | |
var arg = children[i]; | |
if (arg instanceof MatchBase) | |
this.conditions.push(arg); | |
else if (arg === tree.boundBody) | |
this.children[i] = tree.queue.pop(); | |
else | |
this.children[i] = arg; | |
} | |
} | |
function OnceMatch() { | |
MatchBase.call(this); | |
} | |
inherits(OnceMatch, MatchBase); | |
exports.OnceMatch = OnceMatch; | |
function WrapMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(WrapMatch, MatchBase); | |
exports.WrapMatch = WrapMatch; | |
WrapMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
return applyCtx(body); | |
}; | |
} | |
return function wrapAdaptor() { | |
return applyCtx(body.call(this)); | |
}; | |
}; | |
function ReplaceMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(ReplaceMatch, MatchBase); | |
exports.ReplaceMatch = ReplaceMatch; | |
ReplaceMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
return applyCtx(body); | |
}; | |
} | |
return function replaceAdaptor() { | |
return applyCtx(body.call(this)); | |
}; | |
}; | |
function ExtendMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(ExtendMatch, MatchBase); | |
exports.ExtendMatch = ExtendMatch; | |
ExtendMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
var local = this.refs.local; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
var changes = {}; | |
var keys = Object.keys(body); | |
for (var i = 0; i < keys.length; i++) | |
changes['ctx.' + keys[i]] = body[keys[i]]; | |
return local(changes)(function preApplyCtx() { | |
return applyCtx(this.ctx); | |
}); | |
}; | |
} | |
return function localAdaptor() { | |
var changes = {}; | |
var obj = body.call(this); | |
var keys = Object.keys(obj); | |
for (var i = 0; i < keys.length; i++) | |
changes['ctx.' + keys[i]] = obj[keys[i]]; | |
return local(changes)(function preApplyCtx() { | |
return applyCtx(this.ctx); | |
}); | |
}; | |
}; | |
function CompilerOptions(options) { | |
MatchBase.call(this); | |
this.options = options; | |
} | |
inherits(CompilerOptions, MatchBase); | |
exports.CompilerOptions = CompilerOptions; | |
function PropertyMatch(key, value) { | |
MatchBase.call(this); | |
this.key = key; | |
this.value = value; | |
} | |
inherits(PropertyMatch, MatchBase); | |
exports.PropertyMatch = PropertyMatch; | |
function PropertyAbsent(key) { | |
MatchBase.call(this); | |
this.key = key; | |
} | |
inherits(PropertyAbsent, MatchBase); | |
exports.PropertyAbsent = PropertyAbsent; | |
function CustomMatch(body) { | |
MatchBase.call(this); | |
this.body = body; | |
} | |
inherits(CustomMatch, MatchBase); | |
exports.CustomMatch = CustomMatch; | |
function Tree(options) { | |
this.options = options; | |
this.refs = this.options.refs; | |
this.boundBody = this.body.bind(this); | |
var methods = this.methods('body'); | |
for (var i = 0; i < methods.length; i++) { | |
var method = methods[i]; | |
// NOTE: method.name is empty because of .bind() | |
this.boundBody[Tree.methods[i]] = method; | |
} | |
this.queue = []; | |
this.templates = []; | |
this.initializers = []; | |
} | |
exports.Tree = Tree; | |
Tree.methods = [ | |
'match', 'once', 'wrap', 'elemMatch', 'block', 'elem', 'mode', 'mod', | |
'elemMod', 'def', 'tag', 'attrs', 'cls', 'js', 'jsAttr', | |
'bem', 'mix', 'content', 'replace', 'extend', 'oninit', | |
'xjstOptions' | |
]; | |
Tree.prototype.build = function build(templates, apply) { | |
var methods = this.methods('global').concat(apply); | |
methods[0] = this.match.bind(this); | |
templates.apply({}, methods); | |
return { | |
templates: this.templates.slice().reverse(), | |
oninit: this.initializers | |
}; | |
}; | |
function methodFactory(self, kind, name) { | |
var method = self[name]; | |
var boundBody = self.boundBody; | |
if (kind !== 'body') { | |
if (name === 'replace' || name === 'extend' || name === 'wrap') { | |
return function wrapExtended() { | |
return method.apply(self, arguments); | |
}; | |
} | |
return function wrapNotBody() { | |
method.apply(self, arguments); | |
return boundBody; | |
}; | |
} | |
return function wrapBody() { | |
var res = method.apply(self, arguments); | |
// Insert body into last item | |
var child = self.queue.pop(); | |
var last = self.queue[self.queue.length - 1]; | |
last.conditions = last.conditions.concat(child.conditions); | |
last.children = last.children.concat(child.children); | |
if (name === 'replace' || name === 'extend' || name === 'wrap') | |
return res; | |
return boundBody; | |
}; | |
} | |
Tree.prototype.methods = function methods(kind) { | |
var out = new Array(Tree.methods.length); | |
for (var i = 0; i < out.length; i++) { | |
var name = Tree.methods[i]; | |
out[i] = methodFactory(this, kind, name); | |
} | |
return out; | |
}; | |
// Called after all matches | |
Tree.prototype.flush = function flush(conditions, item) { | |
var subcond; | |
if (item.conditions) | |
subcond = conditions.concat(item.conditions); | |
else | |
subcond = item.conditions; | |
for (var i = 0; i < item.children.length; i++) { | |
var arg = item.children[i]; | |
// Go deeper | |
if (arg instanceof Item) { | |
this.flush(subcond, item.children[i]); | |
// Body | |
} else { | |
var template = new Template(conditions, arg); | |
template.wrap(); | |
this.templates.push(template); | |
} | |
} | |
}; | |
Tree.prototype.body = function body() { | |
var children = new Array(arguments.length); | |
for (var i = 0; i < arguments.length; i++) | |
children[i] = arguments[i]; | |
var child = new Item(this, children); | |
this.queue[this.queue.length - 1].children.push(child); | |
if (this.queue.length === 1) | |
this.flush([], this.queue.shift()); | |
return this.boundBody; | |
}; | |
Tree.prototype.match = function match() { | |
var children = new Array(arguments.length); | |
for (var i = 0; i < arguments.length; i++) { | |
var arg = arguments[i]; | |
if (typeof arg === 'function') | |
arg = new CustomMatch(arg); | |
assert(arg instanceof MatchBase, 'Wrong .match() argument'); | |
children[i] = arg; | |
} | |
this.queue.push(new Item(this, children)); | |
return this.boundBody; | |
}; | |
Tree.prototype.once = function once() { | |
return this.match(new OnceMatch()); | |
}; | |
Tree.prototype.wrap = function wrap() { | |
return this.def().match(new WrapMatch(this.refs)); | |
}; | |
Tree.prototype.xjstOptions = function xjstOptions(options) { | |
this.queue.push(new Item(this, [ | |
new CompilerOptions(options) | |
])); | |
return this.boundBody; | |
}; | |
Tree.prototype.block = function block(name) { | |
return this.match(new PropertyMatch('block', name)); | |
}; | |
Tree.prototype.elemMatch = function elemMatch() { | |
return this.match.apply(this, arguments); | |
}; | |
Tree.prototype.elem = function elem(name) { | |
return this.match(new PropertyMatch('elem', name)); | |
}; | |
Tree.prototype.mode = function mode(name) { | |
return this.match(new PropertyMatch('_mode', name)); | |
}; | |
Tree.prototype.mod = function mod(name, value) { | |
return this.match(new PropertyMatch([ 'mods', name ], value)); | |
}; | |
Tree.prototype.elemMod = function elemMod(name, value) { | |
return this.match(new PropertyMatch([ 'elemMods', name ], value)); | |
}; | |
Tree.prototype.def = function def() { return this.mode('default'); }; | |
Tree.prototype.tag = function tag() { return this.mode('tag'); }; | |
Tree.prototype.attrs = function attrs() { return this.mode('attrs'); }; | |
Tree.prototype.cls = function cls() { return this.mode('cls'); }; | |
Tree.prototype.js = function js() { return this.mode('js'); }; | |
Tree.prototype.jsAttr = function jsAttr() { return this.mode('jsAttr'); }; | |
Tree.prototype.bem = function bem() { return this.mode('bem'); }; | |
Tree.prototype.mix = function mix() { return this.mode('mix'); }; | |
Tree.prototype.content = function content() { return this.mode('content'); }; | |
Tree.prototype.replace = function replace() { | |
return this.def().match(new ReplaceMatch(this.refs)); | |
}; | |
Tree.prototype.extend = function extend() { | |
return this.def().match(new ExtendMatch(this.refs)); | |
}; | |
Tree.prototype.oninit = function oninit(fn) { | |
this.initializers.push(fn); | |
}; | |
},{"inherits":9,"minimalistic-assert":10}],8:[function(require,module,exports){ | |
/** | |
* Pattern for acceptable names of elements and modifiers | |
* @const | |
* @type String | |
*/ | |
/* jshint unused : false */ | |
var NAME_PATTERN = '[a-zA-Z0-9-]+'; | |
var toString = Object.prototype.toString; | |
exports.isArray = Array.isArray; | |
if (!exports.isArray) { | |
exports.isArray = function isArrayPolyfill(obj) { | |
return toString.call(obj) === '[object Array]'; | |
}; | |
} | |
exports.xmlEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/</g, '<') | |
.replace(/>/g, '>'); | |
}; | |
exports.attrEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/"/g, '"'); | |
}; | |
exports.jsAttrEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/'/g, '''); | |
}; | |
exports.extend = function extend(o1, o2) { | |
if (!o1 || !o2) | |
return o1 || o2; | |
var res = {}; | |
var n; | |
for (n in o1) | |
if (o1.hasOwnProperty(n)) | |
res[n] = o1[n]; | |
for (n in o2) | |
if (o2.hasOwnProperty(n)) | |
res[n] = o2[n]; | |
return res; | |
}; | |
var SHORT_TAGS = { // хэш для быстрого определения, является ли тэг коротким | |
area: 1, base: 1, br: 1, col: 1, command: 1, embed: 1, hr: 1, img: 1, | |
input: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, wbr: 1 | |
}; | |
exports.isShortTag = function isShortTag(t) { | |
return SHORT_TAGS.hasOwnProperty(t); | |
}; | |
exports.isSimple = function isSimple(obj) { | |
if (!obj || obj === true) return true; | |
return typeof obj === 'string' || typeof obj === 'number'; | |
}; | |
var uniqCount = 0; | |
var uniqId = +new Date(); | |
var uniqExpando = '__' + uniqId; | |
var uniqPrefix = 'uniq' + uniqId; | |
function getUniq() { | |
return uniqPrefix + (++uniqCount); | |
} | |
exports.getUniq = getUniq; | |
exports.identify = function identify(obj, onlyGet) { | |
if (!obj) | |
return getUniq(); | |
if (onlyGet || obj[uniqExpando]) | |
return obj[uniqExpando]; | |
var u = getUniq(); | |
obj[uniqExpando] = u; | |
return u; | |
}; | |
},{}],9:[function(require,module,exports){ | |
if (typeof Object.create === 'function') { | |
// implementation from standard node.js 'util' module | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
ctor.prototype = Object.create(superCtor.prototype, { | |
constructor: { | |
value: ctor, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
}; | |
} else { | |
// old school shim for old browsers | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
var TempCtor = function () {} | |
TempCtor.prototype = superCtor.prototype | |
ctor.prototype = new TempCtor() | |
ctor.prototype.constructor = ctor | |
} | |
} | |
},{}],10:[function(require,module,exports){ | |
module.exports = assert; | |
function assert(val, msg) { | |
if (!val) | |
throw new Error(msg || 'Assertion failed'); | |
} | |
assert.equal = function assertEqual(l, r, msg) { | |
if (l != r) | |
throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); | |
}; | |
},{}]},{},[1])(1) | |
});; | |
return module.exports || | |
exports.BEMHTML; | |
}({}, {}); | |
/// ------------------------------------- | |
/// --------- BEM-XJST Runtime End ------ | |
/// ------------------------------------- | |
var api = new BEMHTML({}); | |
/// ------------------------------------- | |
/// ------ BEM-XJST User-code Start ----- | |
/// ------------------------------------- | |
api.compile(function(match, once, wrap, elemMatch, block, elem, mode, mod, elemMod, def, tag, attrs, cls, js, jsAttr, bem, mix, content, replace, extend, oninit, xjstOptions, local, applyCtx, applyNext, apply) { | |
; | |
}); | |
api.exportApply(exports); | |
/// ------------------------------------- | |
/// ------ BEM-XJST User-code End ------- | |
/// ------------------------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// ------------------------------------- | |
/// --------- BEM-XJST Runtime Start ---- | |
/// ------------------------------------- | |
var BEMHTML = function(module, exports) { | |
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bemtree = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
var BEMXJST = require('../../bemxjst/runtime/index'); | |
function BEMTREE() { | |
BEMXJST.apply(this, arguments); | |
} | |
BEMTREE.prototype = Object.create(BEMXJST.prototype); | |
BEMTREE.prototype.runMany = function runMany(arr) { | |
var out = []; | |
var context = this.context; | |
var prevPos = context.position; | |
var prevNotNewList = context._notNewList; | |
if (prevNotNewList) { | |
context._listLength += arr.length - 1; | |
} else { | |
context.position = 0; | |
context._listLength = arr.length; | |
} | |
context._notNewList = true; | |
if (this.canFlush) { | |
for (var i = 0; i < arr.length; i++) | |
out += context._flush(this._run(arr[i])); // TODO: fixme! | |
} else { | |
for (var i = 0; i < arr.length; i++) | |
out.push(this._run(arr[i])); | |
} | |
if (!prevNotNewList) | |
context.position = prevPos; | |
return out; | |
}; | |
BEMTREE.prototype.render = function render(context, | |
entity, | |
tag, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content) { | |
var ctx = context.ctx; | |
var isBEM = !!(ctx.block || ctx.elem || ctx.bem); // TODO: check | |
if (typeof content === 'undefined') return ctx; | |
ctx.content = this.renderContent(content, isBEM); | |
return ctx; | |
}; | |
BEMTREE.prototype._run = function _run(context) { | |
if (!context) return context; | |
return BEMXJST.prototype._run.call(this, context); | |
}; | |
var Tree = require('../../bemxjst/runtime/tree').Tree; | |
// TODO: fixme copy/paste | |
BEMTREE.locals = Tree.methods.concat('local', 'applyCtx', 'applyNext', 'apply'); | |
module.exports = BEMTREE; | |
},{"../../bemxjst/runtime/index":5,"../../bemxjst/runtime/tree":7}],2:[function(require,module,exports){ | |
function ClassBuilder(options) { | |
this.modDelim = options.mod || '_'; | |
this.elemDelim = options.elem || '__'; | |
} | |
exports.ClassBuilder = ClassBuilder; | |
ClassBuilder.prototype.build = function build(block, elem) { | |
if (elem === undefined) | |
return block; | |
else | |
return block + this.elemDelim + elem; | |
}; | |
ClassBuilder.prototype.buildModPostfix = function buildModPostfix(modName, | |
modVal) { | |
var res = this.modDelim + modName; | |
if (modVal !== true) res += this.modDelim + modVal; | |
return res; | |
}; | |
ClassBuilder.prototype.buildBlockClass = function buildBlockClass(name, | |
modName, | |
modVal) { | |
var res = name; | |
if (modVal) res += this.buildModPostfix(modName, modVal); | |
return res; | |
}; | |
ClassBuilder.prototype.buildElemClass = function buildElemClass(block, | |
name, | |
modName, | |
modVal) { | |
var res = this.buildBlockClass(block) + this.elemDelim + name; | |
if (modVal) res += this.buildModPostfix(modName, modVal); | |
return res; | |
}; | |
ClassBuilder.prototype.split = function split(key) { | |
return key.split(this.elemDelim, 2); | |
}; | |
},{}],3:[function(require,module,exports){ | |
var utils = require('./utils'); | |
function Context(bemxjst) { | |
this._bemxjst = bemxjst; | |
this.ctx = null; | |
this.block = ''; | |
// Save current block until the next BEM entity | |
this._currBlock = ''; | |
this.elem = null; | |
this.mods = {}; | |
this.elemMods = {}; | |
this.position = 0; | |
this._listLength = 0; | |
this._notNewList = false; | |
this._uniq = null; | |
// Used in `OnceMatch` check to detect context change | |
this._onceRef = {}; | |
} | |
exports.Context = Context; | |
Context.prototype._flush = null; | |
Context.prototype.isArray = utils.isArray; | |
Context.prototype.isSimple = utils.isSimple; | |
Context.prototype.isShortTag = utils.isShortTag; | |
Context.prototype.extend = utils.extend; | |
Context.prototype.identify = utils.identify; | |
Context.prototype.xmlEscape = utils.xmlEscape; | |
Context.prototype.attrEscape = utils.attrEscape; | |
Context.prototype.jsAttrEscape = utils.jsAttrEscape; | |
Context.prototype.BEM = {}; | |
Context.prototype.isFirst = function isFirst() { | |
return this.position === 1; | |
}; | |
Context.prototype.isLast = function isLast() { | |
return this.position === this._listLength; | |
}; | |
Context.prototype.generateId = function generateId() { | |
if (this._uniq === null) | |
this._uniq = utils.getUniq(); | |
return this._uniq; | |
}; | |
Context.prototype.reapply = function reapply(ctx) { | |
return this._bemxjst.run(ctx); | |
}; | |
},{"./utils":8}],4:[function(require,module,exports){ | |
var utils = require('./utils'); | |
var Template = require('./tree').Template; | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var CompilerOptions = require('./tree').CompilerOptions; | |
var Match = require('./match').Match; | |
function Entity(bemxjst, block, elem, templates) { | |
this.bemxjst = bemxjst; | |
this.block = null; | |
this.elem = null; | |
this.jsClass = null; | |
// `true` if entity has just a default renderer for `def()` mode | |
this.canFlush = true; | |
// Compiler options via `xjstOptions()` | |
this.options = {}; | |
// "Fast modes" | |
this.def = new Match(this); | |
this.tag = new Match(this); | |
this.attrs = new Match(this); | |
this.mod = new Match(this); | |
this.js = new Match(this); | |
this.mix = new Match(this); | |
this.bem = new Match(this); | |
this.cls = new Match(this); | |
this.content = new Match(this); | |
// "Slow modes" | |
this.rest = {}; | |
// Initialize | |
this.init(block, elem); | |
this.initModes(templates); | |
} | |
exports.Entity = Entity; | |
Entity.prototype.init = function init(block, elem) { | |
this.block = block; | |
this.elem = elem; | |
// Class for jsParams | |
this.jsClass = this.bemxjst.classBuilder.build(this.block, this.elem); | |
}; | |
function contentMode() { | |
return this.ctx.content; | |
} | |
Entity.prototype.initModes = function initModes(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._initRest = function _initRest(key) { | |
if (key === 'tag' || | |
key === 'attrs' || | |
key === 'js' || | |
key === 'mix' || | |
key === 'bem' || | |
key === 'cls' || | |
key === 'content' || | |
key === 'default') { | |
if (key === 'default') | |
this.rest[key] = this.def; | |
else | |
this.rest[key] = this[key]; | |
} else { | |
if (!this.rest.hasOwnProperty(key)) | |
this.rest[key] = new Match(this); | |
} | |
}; | |
Entity.prototype.setDefaults = function setDefaults() { | |
// Default .content() template for applyNext() | |
if (this.content.count !== 0) | |
this.content.push(new Template([], contentMode)); | |
// .def() default | |
if (this.def.count !== 0) { | |
// `.xjstOptions({ flush: true })` will override this | |
this.canFlush = this.options.flush || false; | |
var self = this; | |
this.def.push(new Template([], function defaultBodyProxy() { | |
return self.defaultBody(this); | |
})); | |
} | |
}; | |
Entity.prototype.prepend = function prepend(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 run(context) { | |
if (this.def.count !== 0) | |
return this.def.exec(context); | |
return this.defaultBody(context); | |
}; | |
Entity.prototype.defaultBody = function defaultBody(context) { | |
var tag = context.ctx.tag; | |
if (tag === undefined) | |
tag = this.tag.exec(context); | |
var js; | |
if (context.ctx.js !== false) | |
js = this.js.exec(context); | |
var bem = this.bem.exec(context); | |
var cls = this.cls.exec(context); | |
var mix = this.mix.exec(context); | |
var attrs = this.attrs.exec(context); | |
var content = this.content.exec(context); | |
// Default content | |
if (this.content.count === 0 && content === undefined) | |
content = context.ctx.content; | |
return this.bemxjst.render(context, | |
this, | |
tag, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content); | |
}; | |
},{"./match":6,"./tree":7,"./utils":8}],5:[function(require,module,exports){ | |
var inherits = require('inherits'); | |
var Tree = require('./tree').Tree; | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var Entity = require('./entity').Entity; | |
var Context = require('./context').Context; | |
var ClassBuilder = require('./class-builder').ClassBuilder; | |
var utils = require('./utils'); | |
function BEMXJST(options) { | |
this.options = options || {}; | |
this.entities = null; | |
this.defaultEnt = null; | |
// Current tree | |
this.tree = null; | |
// Current match | |
this.match = null; | |
// Create new Context constructor for overriding prototype | |
this.contextConstructor = function ContextChild(bemxjst) { | |
Context.call(this, bemxjst); | |
}; | |
inherits(this.contextConstructor, Context); | |
this.context = null; | |
this.classBuilder = new ClassBuilder(this.options.naming || {}); | |
// Execution depth, used to invalidate `applyNext` bitfields | |
this.depth = 0; | |
// Do not call `_flush` on overridden `def()` mode | |
this.canFlush = false; | |
// oninit templates | |
this.oninit = null; | |
// Initialize default entity (no block/elem match) | |
this.defaultEnt = new Entity(this, '', '', []); | |
this.defaultElemEnt = new Entity(this, '', '', []); | |
} | |
module.exports = BEMXJST; | |
BEMXJST.locals = Tree.methods.concat('local', 'applyCtx', 'applyNext', 'apply'); | |
BEMXJST.prototype.compile = function compile(code) { | |
var self = this; | |
function applyCtx() { | |
return self._run(self.context.ctx); | |
} | |
function applyCtxWrap(ctx, changes) { | |
// Fast case | |
if (!changes) | |
return self.local({ ctx: ctx }, applyCtx); | |
return self.local(changes, function() { | |
return self.local({ ctx: ctx }, applyCtx); | |
}); | |
} | |
function apply(mode, changes) { | |
return self.applyMode(mode, changes); | |
} | |
function localWrap(changes) { | |
return function localBody(body) { | |
return self.local(changes, body); | |
}; | |
} | |
var tree = new Tree({ | |
refs: { | |
applyCtx: applyCtxWrap, | |
local: localWrap | |
} | |
}); | |
// Yeah, let people pass functions to us! | |
var templates = this.recompileInput(code); | |
var out = tree.build(templates, [ | |
localWrap, | |
applyCtxWrap, | |
function applyNextWrap(changes) { | |
if (changes) | |
return self.local(changes, applyNextWrap); | |
return self.applyNext(); | |
}, | |
apply | |
]); | |
// Concatenate templates with existing ones | |
// TODO(indutny): it should be possible to incrementally add templates | |
if (this.tree) { | |
out = { | |
templates: out.templates.concat(this.tree.templates), | |
oninit: this.tree.oninit.concat(out.oninit) | |
}; | |
} | |
this.tree = out; | |
// Group block+elem entities into a hashmap | |
var ent = this.groupEntities(out.templates); | |
// Transform entities from arrays to Entity instances | |
ent = this.transformEntities(ent); | |
this.entities = ent; | |
this.oninit = out.oninit; | |
}; | |
BEMXJST.prototype.recompileInput = function recompileInput(code) { | |
var out = code.toString(); | |
var args = BEMXJST.locals; | |
if (typeof code === 'function') { | |
var start = out.match(/^function\s*\(([^{]+)\)\s*{/); | |
// Reuse function if it already has right arguments | |
if (start !== null && start[1].split(/,\s*/).length === args.length) | |
return code; | |
} | |
// Strip the function | |
out = out.replace(/^function[^{]+{|}$/g, ''); | |
// And recompile it with right arguments | |
out = new Function(args.join(', '), out); | |
return out; | |
}; | |
BEMXJST.prototype.groupEntities = function groupEntities(tree) { | |
var res = {}; | |
for (var i = 0; i < tree.length; i++) { | |
// Make sure to change only the copy, the original is cached in `this.tree` | |
var template = tree[i].clone(); | |
var block = null; | |
var elem; | |
elem = undefined; | |
for (var j = 0; j < template.predicates.length; j++) { | |
var pred = template.predicates[j]; | |
if (!(pred instanceof PropertyMatch)) | |
continue; | |
if (pred.key === 'block') | |
block = pred.value; | |
else if (pred.key === 'elem') | |
elem = pred.value; | |
else | |
continue; | |
// Remove predicate, we won't much against it | |
template.predicates.splice(j, 1); | |
j--; | |
} | |
// TODO(indutny): print out the template itself | |
if (block === null) | |
throw new Error('block("...") not found in one of the templates'); | |
var key = this.classBuilder.build(block, elem); | |
if (!res[key]) | |
res[key] = []; | |
res[key].push(template); | |
} | |
return res; | |
}; | |
BEMXJST.prototype.transformEntities = function transformEntities(entities) { | |
var wildcardElems = []; | |
var keys = Object.keys(entities); | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
// TODO(indutny): pass this values over | |
var parts = this.classBuilder.split(key); | |
var block = parts[0]; | |
var elem = parts[1]; | |
if (elem === '*') | |
wildcardElems.push(block); | |
entities[key] = new Entity(this, block, elem, entities[key]); | |
} | |
// Merge wildcard block templates | |
if (entities.hasOwnProperty('*')) { | |
var wildcard = entities['*']; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
if (key === '*') | |
continue; | |
entities[key].prepend(wildcard); | |
} | |
this.defaultEnt.prepend(wildcard); | |
this.defaultElemEnt.prepend(wildcard); | |
} | |
// Merge wildcard elem templates | |
for (var i = 0; i < wildcardElems.length; i++) { | |
var block = wildcardElems[i]; | |
var wildcardKey = this.classBuilder.build(block, '*'); | |
var wildcard = entities[wildcardKey]; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
if (key === wildcardKey) | |
continue; | |
var entity = entities[key]; | |
if (entity.block !== block) | |
continue; | |
if (entity.elem === undefined) | |
continue; | |
entities[key].prepend(wildcard); | |
} | |
this.defaultElemEnt.prepend(wildcard); | |
} | |
// Set default templates after merging with wildcard | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
entities[key].setDefaults(); | |
this.defaultEnt.setDefaults(); | |
this.defaultElemEnt.setDefaults(); | |
} | |
return entities; | |
}; | |
BEMXJST.prototype._run = function _run(context) { | |
var res; | |
if (context === undefined || context === '' || context === null) | |
res = this.runEmpty(); | |
else if (utils.isArray(context)) | |
res = this.runMany(context); | |
else if (utils.isSimple(context)) | |
res = this.runSimple(context); | |
else | |
res = this.runOne(context); | |
return res; | |
}; | |
BEMXJST.prototype.run = function run(json) { | |
var match = this.match; | |
var context = this.context; | |
this.match = null; | |
this.context = new this.contextConstructor(this); | |
this.canFlush = this.context._flush !== null; | |
this.depth = 0; | |
var res = this._run(json); | |
if (this.canFlush) | |
res = this.context._flush(res); | |
this.match = match; | |
this.context = context; | |
return res; | |
}; | |
BEMXJST.prototype.runEmpty = function runEmpty() { | |
this.context._listLength--; | |
return ''; | |
}; | |
BEMXJST.prototype.runMany = function runMany(arr) { | |
var out = ''; | |
var context = this.context; | |
var prevPos = context.position; | |
var prevNotNewList = context._notNewList; | |
if (prevNotNewList) { | |
context._listLength += arr.length - 1; | |
} else { | |
context.position = 0; | |
context._listLength = arr.length; | |
} | |
context._notNewList = true; | |
if (this.canFlush) { | |
for (var i = 0; i < arr.length; i++) | |
out += context._flush(this._run(arr[i])); | |
} else { | |
for (var i = 0; i < arr.length; i++) | |
out += this._run(arr[i]); | |
} | |
if (!prevNotNewList) | |
context.position = prevPos; | |
return out; | |
}; | |
BEMXJST.prototype.runSimple = function runSimple(context) { | |
this.context._listLength--; | |
var res = ''; | |
if (context && context !== true || context === 0) | |
res += context; | |
return res; | |
}; | |
BEMXJST.prototype.runOne = function runOne(json) { | |
var context = this.context; | |
var oldCtx = context.ctx; | |
var oldBlock = context.block; | |
var oldCurrBlock = context._currBlock; | |
var oldElem = context.elem; | |
var oldMods = context.mods; | |
var oldElemMods = context.elemMods; | |
if (json.block || json.elem) | |
context._currBlock = ''; | |
else | |
context._currBlock = context.block; | |
context.ctx = json; | |
if (json.block) { | |
context.block = json.block; | |
if (json.mods) | |
context.mods = json.mods; | |
else | |
context.mods = {}; | |
} else { | |
if (!json.elem) | |
context.block = ''; | |
else if (oldCurrBlock) | |
context.block = oldCurrBlock; | |
} | |
context.elem = json.elem; | |
if (json.elemMods) | |
context.elemMods = json.elemMods; | |
else | |
context.elemMods = {}; | |
var block = context.block || ''; | |
var elem = context.elem; | |
// Control list position | |
if (block || elem) | |
context.position++; | |
else | |
context._listLength--; | |
// To invalidate `applyNext` flags | |
this.depth++; | |
var key = this.classBuilder.build(block, elem); | |
var restoreFlush = false; | |
var ent = this.entities[key]; | |
if (ent) { | |
if (this.canFlush && !ent.canFlush) { | |
// Entity does not support flushing, do not flush anything nested | |
restoreFlush = true; | |
this.canFlush = false; | |
} | |
} else { | |
// No entity - use default one | |
ent = this.defaultEnt; | |
if (elem !== undefined) | |
ent = this.defaultElemEnt; | |
ent.init(block, elem); | |
} | |
var res = ent.run(context); | |
context.ctx = oldCtx; | |
context.block = oldBlock; | |
context.elem = oldElem; | |
context.mods = oldMods; | |
context.elemMods = oldElemMods; | |
context._currBlock = oldCurrBlock; | |
this.depth--; | |
if (restoreFlush) | |
this.canFlush = true; | |
return res; | |
}; | |
BEMXJST.prototype.render = function render(context, | |
entity, | |
tag, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content) { | |
var ctx = context.ctx; | |
if (tag === undefined) | |
tag = 'div'; | |
if (!tag) | |
return this.renderNoTag(context, js, bem, cls, mix, attrs, content); | |
var out = '<' + tag; | |
var ctxJS = ctx.js; | |
if (ctxJS !== false) { | |
if (js === true) | |
js = {}; | |
if (js) { | |
if (ctxJS !== true) | |
js = utils.extend(ctxJS, js); | |
} else if (ctxJS === true) { | |
js = {}; | |
} else { | |
js = ctxJS; | |
} | |
} | |
var jsParams; | |
if (js) { | |
jsParams = {}; | |
jsParams[entity.jsClass] = js; | |
} | |
var isBEM = bem; | |
if (isBEM === undefined) { | |
if (ctx.bem === undefined) | |
isBEM = entity.block || entity.elem; | |
else | |
isBEM = ctx.bem; | |
} | |
isBEM = !!isBEM; | |
if (cls === undefined) | |
cls = ctx.cls; | |
var addJSInitClass = entity.block && jsParams && !entity.elem; | |
if (!isBEM && !cls) { | |
return this.renderClose(out, context, tag, attrs, isBEM, ctx, content); | |
} | |
out += ' class="'; | |
if (isBEM) { | |
var mods = ctx.elemMods || ctx.mods; | |
if (!mods && ctx.block) | |
mods = context.mods; | |
out += entity.jsClass; | |
out += this.buildModsClasses(entity.block, entity.elem, mods); | |
var totalMix = mix; | |
if (ctx.mix) { | |
if (totalMix) | |
totalMix = [].concat(totalMix, ctx.mix); | |
else | |
totalMix = ctx.mix; | |
} | |
if (totalMix) { | |
var m = this.renderMix(entity, totalMix, jsParams, addJSInitClass); | |
out += m.out; | |
jsParams = m.jsParams; | |
addJSInitClass = m.addJSInitClass; | |
} | |
if (cls) | |
out += ' ' + cls; | |
} else { | |
if (cls) | |
out += cls; | |
} | |
if (addJSInitClass) | |
out += ' i-bem"'; | |
else | |
out += '"'; | |
if (isBEM && jsParams) | |
out += ' data-bem=\'' + utils.jsAttrEscape(JSON.stringify(jsParams)) + '\''; | |
return this.renderClose(out, context, tag, attrs, isBEM, ctx, content); | |
}; | |
BEMXJST.prototype.renderClose = function renderClose(prefix, | |
context, | |
tag, | |
attrs, | |
isBEM, | |
ctx, | |
content) { | |
var out = prefix; | |
// NOTE: maybe we need to make an array for quicker serialization | |
attrs = utils.extend(attrs, ctx.attrs); | |
if (attrs) { | |
var name; // TODO: do something with OmetaJS and YUI Compressor | |
/* jshint forin : false */ | |
for (name in attrs) { | |
var attr = attrs[name]; | |
if (attr === undefined) | |
continue; | |
// TODO(indutny): support `this.reapply()` | |
out += ' ' + name + '="' + | |
utils.attrEscape(utils.isSimple(attr) ? | |
attr : | |
this.reapply(attr)) + | |
'"'; | |
} | |
} | |
if (utils.isShortTag(tag)) { | |
out += '/>'; | |
if (this.canFlush) | |
out = context._flush(out); | |
} else { | |
out += '>'; | |
if (this.canFlush) | |
out = context._flush(out); | |
// TODO(indutny): skip apply next flags | |
if (content || content === 0) | |
out += this.renderContent(content, isBEM); | |
out += '</' + tag + '>'; | |
} | |
if (this.canFlush) | |
out = context._flush(out); | |
return out; | |
}; | |
BEMXJST.prototype.renderMix = function renderMix(entity, | |
mix, | |
jsParams, | |
addJSInitClass) { | |
var visited = {}; | |
var context = this.context; | |
var js = jsParams; | |
var addInit = addJSInitClass; | |
visited[entity.jsClass] = true; | |
// Transform mix to the single-item array if it's not array | |
if (!utils.isArray(mix)) | |
mix = [ mix ]; | |
var classBuilder = this.classBuilder; | |
var out = ''; | |
for (var i = 0; i < mix.length; i++) { | |
var item = mix[i]; | |
if (item === undefined) | |
continue; | |
if (typeof item === 'string') | |
item = { block: item, elem: undefined }; | |
var hasItem = item.block || item.elem; | |
var block = item.block || item._block || context.block; | |
var elem = item.elem || item._elem || context.elem; | |
var key = classBuilder.build(block, elem); | |
var classElem = item.elem || | |
item._elem || | |
(item.block ? undefined : context.elem); | |
if (hasItem) | |
out += ' ' + classBuilder.build(block, classElem); | |
out += this.buildModsClasses(block, classElem, item.elemMods || item.mods); | |
if (item.js) { | |
if (!js) | |
js = {}; | |
js[classBuilder.build(block, item.elem)] = | |
item.js === true ? {} : item.js; | |
if (!addInit) | |
addInit = block && !item.elem; | |
} | |
// Process nested mixes | |
if (!hasItem || visited[key]) | |
continue; | |
visited[key] = true; | |
var nestedEntity = this.entities[key]; | |
if (!nestedEntity) | |
continue; | |
var oldBlock = context.block; | |
var oldElem = context.elem; | |
var nestedMix = nestedEntity.mix.exec(context); | |
context.elem = oldElem; | |
context.block = oldBlock; | |
if (!nestedMix) | |
continue; | |
for (var j = 0; j < nestedMix.length; j++) { | |
var nestedItem = nestedMix[j]; | |
if (!nestedItem.block && | |
!nestedItem.elem || | |
!visited[classBuilder.build(nestedItem.block, nestedItem.elem)]) { | |
nestedItem._block = block; | |
nestedItem._elem = elem; | |
mix = mix.slice(0, i + 1).concat( | |
nestedItem, | |
mix.slice(i + 1) | |
); | |
} | |
} | |
} | |
return { | |
out: out, | |
jsParams: js, | |
addJSInitClass: addInit | |
}; | |
}; | |
BEMXJST.prototype.buildModsClasses = function buildModsClasses(block, | |
elem, | |
mods) { | |
if (!mods) | |
return ''; | |
var res = ''; | |
var modName; | |
for (modName in mods) { | |
if (!mods.hasOwnProperty(modName)) | |
continue; | |
var modVal = mods[modName]; | |
if (!modVal && modVal !== 0) continue; | |
if (typeof modVal !== 'boolean') | |
modVal += ''; | |
var builder = this.classBuilder; | |
res += ' ' + (elem ? | |
builder.buildElemClass(block, elem, modName, modVal) : | |
builder.buildBlockClass(block, modName, modVal)); | |
} | |
return res; | |
}; | |
BEMXJST.prototype.renderContent = function renderContent(content, isBEM) { | |
var context = this.context; | |
var oldPos = context.position; | |
var oldListLength = context._listLength; | |
var oldNotNewList = context._notNewList; | |
context._notNewList = false; | |
if (isBEM) { | |
context.position = 1; | |
context._listLength = 1; | |
} | |
var res = this._run(content); | |
context.position = oldPos; | |
context._listLength = oldListLength; | |
context._notNewList = oldNotNewList; | |
return res; | |
}; | |
BEMXJST.prototype.renderNoTag = function renderNoTag(context, | |
js, | |
bem, | |
cls, | |
mix, | |
attrs, | |
content) { | |
// TODO(indutny): skip apply next flags | |
if (content || content === 0) | |
return this._run(content); | |
return ''; | |
}; | |
BEMXJST.prototype.local = function local(changes, body) { | |
var keys = Object.keys(changes); | |
var restore = []; | |
for (var i = 0; i < keys.length; i++) { | |
var key = keys[i]; | |
var parts = key.split('.'); | |
var value = this.context; | |
for (var j = 0; j < parts.length - 1; j++) | |
value = value[parts[j]]; | |
restore.push({ | |
parts: parts, | |
value: value[parts[j]] | |
}); | |
value[parts[j]] = changes[key]; | |
} | |
var res = body.call(this.context); | |
for (var i = 0; i < restore.length; i++) { | |
var parts = restore[i].parts; | |
var value = this.context; | |
for (var j = 0; j < parts.length - 1; j++) | |
value = value[parts[j]]; | |
value[parts[j]] = restore[i].value; | |
} | |
return res; | |
}; | |
BEMXJST.prototype.applyNext = function applyNext() { | |
return this.match.exec(this.context); | |
}; | |
BEMXJST.prototype.applyMode = function applyMode(mode, changes) { | |
var match = this.match.entity.rest[mode]; | |
if (!match) | |
return; | |
if (!changes) | |
return match.exec(this.context); | |
var self = this; | |
// Allocate function this way, to prevent allocation at the top of the | |
// `applyMode` | |
var fn = function localBody() { | |
return match.exec(self.context); | |
}; | |
return this.local(changes, fn); | |
}; | |
BEMXJST.prototype.exportApply = function exportApply(exports) { | |
var self = this; | |
exports.apply = function apply(context) { | |
return self.run(context); | |
}; | |
// Add templates at run time | |
exports.compile = function compile(templates) { | |
return self.compile(templates); | |
}; | |
var sharedContext = {}; | |
exports.BEMContext = this.contextConstructor; | |
sharedContext.BEMContext = exports.BEMContext; | |
for (var i = 0; i < this.oninit.length; i++) { | |
var oninit = this.oninit[i]; | |
oninit(exports, sharedContext); | |
} | |
}; | |
},{"./class-builder":2,"./context":3,"./entity":4,"./tree":7,"./utils":8,"inherits":9}],6:[function(require,module,exports){ | |
var utils = require('./utils'); | |
var PropertyMatch = require('./tree').PropertyMatch; | |
var OnceMatch = require('./tree').OnceMatch; | |
var WrapMatch = require('./tree').WrapMatch; | |
var PropertyAbsent = require('./tree').PropertyAbsent; | |
var CustomMatch = require('./tree').CustomMatch; | |
function MatchProperty(template, pred) { | |
this.template = template; | |
this.key = pred.key; | |
this.value = pred.value; | |
} | |
MatchProperty.prototype.exec = function exec(context) { | |
return context[this.key] === this.value; | |
}; | |
function MatchNested(template, pred) { | |
this.template = template; | |
this.keys = pred.key; | |
this.value = pred.value; | |
} | |
MatchNested.prototype.exec = function exec(context) { | |
var val = context; | |
for (var i = 0; i < this.keys.length - 1; i++) { | |
val = val[this.keys[i]]; | |
if (!val) | |
return false; | |
} | |
return val[this.keys[i]] === this.value; | |
}; | |
function MatchAbsent(template, pred) { | |
this.template = template; | |
this.key = pred.key; | |
} | |
MatchAbsent.prototype.exec = function exec(context) { | |
return !context[this.key]; | |
}; | |
function MatchCustom(template, pred) { | |
this.template = template; | |
this.body = pred.body; | |
} | |
MatchCustom.prototype.exec = function exec(context) { | |
return this.body.call(context); | |
}; | |
function MatchOnce(template) { | |
this.template = template; | |
this.once = null; | |
} | |
MatchOnce.prototype.exec = function exec(context) { | |
var res = this.once !== context._onceRef; | |
this.once = context._onceRef; | |
return res; | |
}; | |
function MatchWrap(template) { | |
this.template = template; | |
this.wrap = null; | |
} | |
MatchWrap.prototype.exec = function exec(context) { | |
var res = this.wrap !== context.ctx; | |
this.wrap = context.ctx; | |
return res; | |
}; | |
function MatchTemplate(mode, template) { | |
this.mode = mode; | |
this.predicates = new Array(template.predicates.length); | |
this.body = template.body; | |
var postpone = []; | |
for (var i = 0, j = 0; i < this.predicates.length; i++, j++) { | |
var pred = template.predicates[i]; | |
if (pred instanceof PropertyMatch) { | |
if (utils.isArray(pred.key)) | |
this.predicates[j] = new MatchNested(this, pred); | |
else | |
this.predicates[j] = new MatchProperty(this, pred); | |
} else if (pred instanceof PropertyAbsent) { | |
this.predicates[j] = new MatchAbsent(this, pred); | |
} else if (pred instanceof CustomMatch) { | |
this.predicates[j] = new MatchCustom(this, pred); | |
// Push OnceMatch and MatchWrap later, they should not be executed first. | |
// Otherwise they will set flag too early, and body might not be executed | |
} else if (pred instanceof OnceMatch) { | |
j--; | |
postpone.push(new MatchOnce(this)); | |
} else if (pred instanceof WrapMatch) { | |
j--; | |
postpone.push(new MatchWrap(this)); | |
} else { | |
// Skip | |
j--; | |
} | |
} | |
// Insert late predicates | |
for (var i = postpone.length - 1; i >= 0; i--) | |
this.predicates[i + j] = this.predicates[i]; | |
for (var i = 0; i < postpone.length; i++) | |
this.predicates[i] = postpone[i]; | |
j += postpone.length; | |
if (this.predicates.length !== j) | |
this.predicates.length = j; | |
} | |
exports.MatchTemplate = MatchTemplate; | |
function Match(entity) { | |
this.entity = entity; | |
this.bemxjst = this.entity.bemxjst; | |
this.templates = []; | |
// applyNext mask | |
this.mask = [ 0 ]; | |
// We are going to create copies of mask for nested `applyNext()` | |
this.maskSize = 0; | |
this.maskOffset = 0; | |
this.count = 0; | |
this.depth = -1; | |
} | |
exports.Match = Match; | |
Match.prototype.clone = function clone(entity) { | |
var res = new Match(entity); | |
res.templates = this.templates.slice(); | |
res.mask = this.mask.slice(); | |
res.maskSize = this.maskSize; | |
res.count = this.count; | |
return res; | |
}; | |
Match.prototype.prepend = function prepend(other) { | |
this.templates = other.templates.concat(this.templates); | |
this.count += other.count; | |
while (Math.ceil(this.count / 31) > this.mask.length) | |
this.mask.push(0); | |
this.maskSize = this.mask.length; | |
}; | |
Match.prototype.push = function push(template) { | |
this.templates.push(new MatchTemplate(this, template)); | |
this.count++; | |
if (Math.ceil(this.count / 31) > this.mask.length) | |
this.mask.push(0); | |
this.maskSize = this.mask.length; | |
}; | |
Match.prototype.exec = function exec(context) { | |
var save = this.checkDepth(); | |
var template; | |
var bitIndex = this.maskOffset; | |
var mask = this.mask[bitIndex]; | |
var bit = 1; | |
for (var i = 0; i < this.count; i++) { | |
if ((mask & bit) === 0) { | |
template = this.templates[i]; | |
for (var j = template.predicates.length - 1; j >= 0; j--) { | |
var pred = template.predicates[j]; | |
/* jshint maxdepth : false */ | |
if (!pred.exec(context)) | |
break; | |
} | |
// All predicates matched! | |
if (j === -1) | |
break; | |
} | |
if (bit === 0x40000000) { | |
bitIndex++; | |
mask = this.mask[bitIndex]; | |
bit = 1; | |
} else { | |
bit <<= 1; | |
} | |
} | |
if (i === this.count) | |
return undefined; | |
var oldMask = mask; | |
var oldMatch = this.bemxjst.match; | |
this.mask[bitIndex] |= bit; | |
this.bemxjst.match = this; | |
var out; | |
if (typeof template.body === 'function') | |
out = template.body.call(context); | |
else | |
out = template.body; | |
this.mask[bitIndex] = oldMask; | |
this.bemxjst.match = oldMatch; | |
this.restoreDepth(save); | |
return out; | |
}; | |
Match.prototype.checkDepth = function checkDepth() { | |
if (this.depth === -1) { | |
this.depth = this.bemxjst.depth; | |
return -1; | |
} | |
if (this.bemxjst.depth === this.depth) | |
return this.depth; | |
var depth = this.depth; | |
this.depth = this.bemxjst.depth; | |
this.maskOffset += this.maskSize; | |
while (this.mask.length < this.maskOffset + this.maskSize) | |
this.mask.push(0); | |
return depth; | |
}; | |
Match.prototype.restoreDepth = function restoreDepth(depth) { | |
if (depth !== -1 && depth !== this.depth) | |
this.maskOffset -= this.maskSize; | |
this.depth = depth; | |
}; | |
},{"./tree":7,"./utils":8}],7:[function(require,module,exports){ | |
var assert = require('minimalistic-assert'); | |
var inherits = require('inherits'); | |
function Template(predicates, body) { | |
this.predicates = predicates; | |
this.body = body; | |
} | |
exports.Template = Template; | |
Template.prototype.wrap = function wrap() { | |
var body = this.body; | |
for (var i = 0; i < this.predicates.length; i++) { | |
var pred = this.predicates[i]; | |
body = pred.wrapBody(body); | |
} | |
this.body = body; | |
}; | |
Template.prototype.clone = function clone() { | |
return new Template(this.predicates.slice(), this.body); | |
}; | |
function MatchBase() { | |
} | |
exports.MatchBase = MatchBase; | |
MatchBase.prototype.wrapBody = function wrapBody(body) { | |
return body; | |
}; | |
function Item(tree, children) { | |
this.conditions = []; | |
this.children = []; | |
for (var i = children.length - 1; i >= 0; i--) { | |
var arg = children[i]; | |
if (arg instanceof MatchBase) | |
this.conditions.push(arg); | |
else if (arg === tree.boundBody) | |
this.children[i] = tree.queue.pop(); | |
else | |
this.children[i] = arg; | |
} | |
} | |
function OnceMatch() { | |
MatchBase.call(this); | |
} | |
inherits(OnceMatch, MatchBase); | |
exports.OnceMatch = OnceMatch; | |
function WrapMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(WrapMatch, MatchBase); | |
exports.WrapMatch = WrapMatch; | |
WrapMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
return applyCtx(body); | |
}; | |
} | |
return function wrapAdaptor() { | |
return applyCtx(body.call(this)); | |
}; | |
}; | |
function ReplaceMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(ReplaceMatch, MatchBase); | |
exports.ReplaceMatch = ReplaceMatch; | |
ReplaceMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
return applyCtx(body); | |
}; | |
} | |
return function replaceAdaptor() { | |
return applyCtx(body.call(this)); | |
}; | |
}; | |
function ExtendMatch(refs) { | |
MatchBase.call(this); | |
this.refs = refs; | |
} | |
inherits(ExtendMatch, MatchBase); | |
exports.ExtendMatch = ExtendMatch; | |
ExtendMatch.prototype.wrapBody = function wrapBody(body) { | |
var applyCtx = this.refs.applyCtx; | |
var local = this.refs.local; | |
if (typeof body !== 'function') { | |
return function inlineAdaptor() { | |
var changes = {}; | |
var keys = Object.keys(body); | |
for (var i = 0; i < keys.length; i++) | |
changes['ctx.' + keys[i]] = body[keys[i]]; | |
return local(changes)(function preApplyCtx() { | |
return applyCtx(this.ctx); | |
}); | |
}; | |
} | |
return function localAdaptor() { | |
var changes = {}; | |
var obj = body.call(this); | |
var keys = Object.keys(obj); | |
for (var i = 0; i < keys.length; i++) | |
changes['ctx.' + keys[i]] = obj[keys[i]]; | |
return local(changes)(function preApplyCtx() { | |
return applyCtx(this.ctx); | |
}); | |
}; | |
}; | |
function CompilerOptions(options) { | |
MatchBase.call(this); | |
this.options = options; | |
} | |
inherits(CompilerOptions, MatchBase); | |
exports.CompilerOptions = CompilerOptions; | |
function PropertyMatch(key, value) { | |
MatchBase.call(this); | |
this.key = key; | |
this.value = value; | |
} | |
inherits(PropertyMatch, MatchBase); | |
exports.PropertyMatch = PropertyMatch; | |
function PropertyAbsent(key) { | |
MatchBase.call(this); | |
this.key = key; | |
} | |
inherits(PropertyAbsent, MatchBase); | |
exports.PropertyAbsent = PropertyAbsent; | |
function CustomMatch(body) { | |
MatchBase.call(this); | |
this.body = body; | |
} | |
inherits(CustomMatch, MatchBase); | |
exports.CustomMatch = CustomMatch; | |
function Tree(options) { | |
this.options = options; | |
this.refs = this.options.refs; | |
this.boundBody = this.body.bind(this); | |
var methods = this.methods('body'); | |
for (var i = 0; i < methods.length; i++) { | |
var method = methods[i]; | |
// NOTE: method.name is empty because of .bind() | |
this.boundBody[Tree.methods[i]] = method; | |
} | |
this.queue = []; | |
this.templates = []; | |
this.initializers = []; | |
} | |
exports.Tree = Tree; | |
Tree.methods = [ | |
'match', 'once', 'wrap', 'elemMatch', 'block', 'elem', 'mode', 'mod', | |
'elemMod', 'def', 'tag', 'attrs', 'cls', 'js', 'jsAttr', | |
'bem', 'mix', 'content', 'replace', 'extend', 'oninit', | |
'xjstOptions' | |
]; | |
Tree.prototype.build = function build(templates, apply) { | |
var methods = this.methods('global').concat(apply); | |
methods[0] = this.match.bind(this); | |
templates.apply({}, methods); | |
return { | |
templates: this.templates.slice().reverse(), | |
oninit: this.initializers | |
}; | |
}; | |
function methodFactory(self, kind, name) { | |
var method = self[name]; | |
var boundBody = self.boundBody; | |
if (kind !== 'body') { | |
if (name === 'replace' || name === 'extend' || name === 'wrap') { | |
return function wrapExtended() { | |
return method.apply(self, arguments); | |
}; | |
} | |
return function wrapNotBody() { | |
method.apply(self, arguments); | |
return boundBody; | |
}; | |
} | |
return function wrapBody() { | |
var res = method.apply(self, arguments); | |
// Insert body into last item | |
var child = self.queue.pop(); | |
var last = self.queue[self.queue.length - 1]; | |
last.conditions = last.conditions.concat(child.conditions); | |
last.children = last.children.concat(child.children); | |
if (name === 'replace' || name === 'extend' || name === 'wrap') | |
return res; | |
return boundBody; | |
}; | |
} | |
Tree.prototype.methods = function methods(kind) { | |
var out = new Array(Tree.methods.length); | |
for (var i = 0; i < out.length; i++) { | |
var name = Tree.methods[i]; | |
out[i] = methodFactory(this, kind, name); | |
} | |
return out; | |
}; | |
// Called after all matches | |
Tree.prototype.flush = function flush(conditions, item) { | |
var subcond; | |
if (item.conditions) | |
subcond = conditions.concat(item.conditions); | |
else | |
subcond = item.conditions; | |
for (var i = 0; i < item.children.length; i++) { | |
var arg = item.children[i]; | |
// Go deeper | |
if (arg instanceof Item) { | |
this.flush(subcond, item.children[i]); | |
// Body | |
} else { | |
var template = new Template(conditions, arg); | |
template.wrap(); | |
this.templates.push(template); | |
} | |
} | |
}; | |
Tree.prototype.body = function body() { | |
var children = new Array(arguments.length); | |
for (var i = 0; i < arguments.length; i++) | |
children[i] = arguments[i]; | |
var child = new Item(this, children); | |
this.queue[this.queue.length - 1].children.push(child); | |
if (this.queue.length === 1) | |
this.flush([], this.queue.shift()); | |
return this.boundBody; | |
}; | |
Tree.prototype.match = function match() { | |
var children = new Array(arguments.length); | |
for (var i = 0; i < arguments.length; i++) { | |
var arg = arguments[i]; | |
if (typeof arg === 'function') | |
arg = new CustomMatch(arg); | |
assert(arg instanceof MatchBase, 'Wrong .match() argument'); | |
children[i] = arg; | |
} | |
this.queue.push(new Item(this, children)); | |
return this.boundBody; | |
}; | |
Tree.prototype.once = function once() { | |
return this.match(new OnceMatch()); | |
}; | |
Tree.prototype.wrap = function wrap() { | |
return this.def().match(new WrapMatch(this.refs)); | |
}; | |
Tree.prototype.xjstOptions = function xjstOptions(options) { | |
this.queue.push(new Item(this, [ | |
new CompilerOptions(options) | |
])); | |
return this.boundBody; | |
}; | |
Tree.prototype.block = function block(name) { | |
return this.match(new PropertyMatch('block', name)); | |
}; | |
Tree.prototype.elemMatch = function elemMatch() { | |
return this.match.apply(this, arguments); | |
}; | |
Tree.prototype.elem = function elem(name) { | |
return this.match(new PropertyMatch('elem', name)); | |
}; | |
Tree.prototype.mode = function mode(name) { | |
return this.match(new PropertyMatch('_mode', name)); | |
}; | |
Tree.prototype.mod = function mod(name, value) { | |
return this.match(new PropertyMatch([ 'mods', name ], value)); | |
}; | |
Tree.prototype.elemMod = function elemMod(name, value) { | |
return this.match(new PropertyMatch([ 'elemMods', name ], value)); | |
}; | |
Tree.prototype.def = function def() { return this.mode('default'); }; | |
Tree.prototype.tag = function tag() { return this.mode('tag'); }; | |
Tree.prototype.attrs = function attrs() { return this.mode('attrs'); }; | |
Tree.prototype.cls = function cls() { return this.mode('cls'); }; | |
Tree.prototype.js = function js() { return this.mode('js'); }; | |
Tree.prototype.jsAttr = function jsAttr() { return this.mode('jsAttr'); }; | |
Tree.prototype.bem = function bem() { return this.mode('bem'); }; | |
Tree.prototype.mix = function mix() { return this.mode('mix'); }; | |
Tree.prototype.content = function content() { return this.mode('content'); }; | |
Tree.prototype.replace = function replace() { | |
return this.def().match(new ReplaceMatch(this.refs)); | |
}; | |
Tree.prototype.extend = function extend() { | |
return this.def().match(new ExtendMatch(this.refs)); | |
}; | |
Tree.prototype.oninit = function oninit(fn) { | |
this.initializers.push(fn); | |
}; | |
},{"inherits":9,"minimalistic-assert":10}],8:[function(require,module,exports){ | |
/** | |
* Pattern for acceptable names of elements and modifiers | |
* @const | |
* @type String | |
*/ | |
/* jshint unused : false */ | |
var NAME_PATTERN = '[a-zA-Z0-9-]+'; | |
var toString = Object.prototype.toString; | |
exports.isArray = Array.isArray; | |
if (!exports.isArray) { | |
exports.isArray = function isArrayPolyfill(obj) { | |
return toString.call(obj) === '[object Array]'; | |
}; | |
} | |
exports.xmlEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/</g, '<') | |
.replace(/>/g, '>'); | |
}; | |
exports.attrEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/"/g, '"'); | |
}; | |
exports.jsAttrEscape = function(str) { | |
return (str + '') | |
.replace(/&/g, '&') | |
.replace(/'/g, '''); | |
}; | |
exports.extend = function extend(o1, o2) { | |
if (!o1 || !o2) | |
return o1 || o2; | |
var res = {}; | |
var n; | |
for (n in o1) | |
if (o1.hasOwnProperty(n)) | |
res[n] = o1[n]; | |
for (n in o2) | |
if (o2.hasOwnProperty(n)) | |
res[n] = o2[n]; | |
return res; | |
}; | |
var SHORT_TAGS = { // хэш для быстрого определения, является ли тэг коротким | |
area: 1, base: 1, br: 1, col: 1, command: 1, embed: 1, hr: 1, img: 1, | |
input: 1, keygen: 1, link: 1, meta: 1, param: 1, source: 1, wbr: 1 | |
}; | |
exports.isShortTag = function isShortTag(t) { | |
return SHORT_TAGS.hasOwnProperty(t); | |
}; | |
exports.isSimple = function isSimple(obj) { | |
if (!obj || obj === true) return true; | |
return typeof obj === 'string' || typeof obj === 'number'; | |
}; | |
var uniqCount = 0; | |
var uniqId = +new Date(); | |
var uniqExpando = '__' + uniqId; | |
var uniqPrefix = 'uniq' + uniqId; | |
function getUniq() { | |
return uniqPrefix + (++uniqCount); | |
} | |
exports.getUniq = getUniq; | |
exports.identify = function identify(obj, onlyGet) { | |
if (!obj) | |
return getUniq(); | |
if (onlyGet || obj[uniqExpando]) | |
return obj[uniqExpando]; | |
var u = getUniq(); | |
obj[uniqExpando] = u; | |
return u; | |
}; | |
},{}],9:[function(require,module,exports){ | |
if (typeof Object.create === 'function') { | |
// implementation from standard node.js 'util' module | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
ctor.prototype = Object.create(superCtor.prototype, { | |
constructor: { | |
value: ctor, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
}; | |
} else { | |
// old school shim for old browsers | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
var TempCtor = function () {} | |
TempCtor.prototype = superCtor.prototype | |
ctor.prototype = new TempCtor() | |
ctor.prototype.constructor = ctor | |
} | |
} | |
},{}],10:[function(require,module,exports){ | |
module.exports = assert; | |
function assert(val, msg) { | |
if (!val) | |
throw new Error(msg || 'Assertion failed'); | |
} | |
assert.equal = function assertEqual(l, r, msg) { | |
if (l != r) | |
throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); | |
}; | |
},{}]},{},[1])(1) | |
});; | |
return module.exports || | |
exports.BEMHTML; | |
}({}, {}); | |
/// ------------------------------------- | |
/// --------- BEM-XJST Runtime End ------ | |
/// ------------------------------------- | |
var api = new BEMHTML({}); | |
/// ------------------------------------- | |
/// ------ BEM-XJST User-code Start ----- | |
/// ------------------------------------- | |
api.compile(function(match, once, wrap, elemMatch, block, elem, mode, mod, elemMod, def, tag, attrs, cls, js, jsAttr, bem, mix, content, replace, extend, oninit, xjstOptions, local, applyCtx, applyNext, apply) { | |
; | |
}); | |
api.exportApply(exports); | |
/// ------------------------------------- | |
/// ------ BEM-XJST User-code End ------- | |
/// ------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment