Comparing version 0.6.1 to 0.6.2
{ | ||
"name": "bemer", | ||
"description": "Template engine. BEMJSON to HTML processor.", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"license": "MIT", | ||
@@ -6,0 +6,0 @@ "ignore": [ |
definer.export('bemer', /** @exports bemer */ function( | ||
Tag, Tree, Template, Pool, functions, Selector, Node, object, Helpers, modules | ||
Tag, Tree, Template, Pool, Selector, Node, Helpers, functions, object, is, modules | ||
) { | ||
@@ -86,2 +86,6 @@ | ||
}, | ||
escape: { | ||
content: Tag.escapeContent, | ||
attr: Tag.escapeAttr | ||
}, | ||
tag: Tag.defaultName, | ||
@@ -108,2 +112,6 @@ bemClass: Node.bemClass, | ||
* | ||
* @param {boolean|object} [config.escape=true] Флаг экранирования спецсимволов | ||
* @param {boolean} [config.escape.content=true] Флаг экранирования содержимого | ||
* @param {boolean} [config.escape.attr=true] Флаг экранирования значений атрибутов | ||
* | ||
* @param {string} [config.tag=div] Стандартное имя тега | ||
@@ -125,10 +133,10 @@ * @param {string} [config.bemClass=i-bem] Имя класса для js-инициализации | ||
if(config.xhtml !== undefined) { | ||
if(typeof config.xhtml === 'boolean') { | ||
if(is.boolean(config.xhtml)) { | ||
Tag.repeatBooleanAttr = config.xhtml; | ||
Tag.closeSingleTag = config.xhtml; | ||
} else { | ||
if(typeof config.xhtml.repeatBooleanAttr === 'boolean') { | ||
if(is.boolean(config.xhtml.repeatBooleanAttr)) { | ||
Tag.repeatBooleanAttr = config.xhtml.repeatBooleanAttr; | ||
} | ||
if(typeof config.xhtml.closeSingleTag === 'boolean') { | ||
if(is.boolean(config.xhtml.closeSingleTag)) { | ||
Tag.closeSingleTag = config.xhtml.closeSingleTag; | ||
@@ -139,2 +147,6 @@ } | ||
var escape = Node.resolveOptionEscape(config.escape); | ||
Tag.escapeContent = escape.content; | ||
Tag.escapeAttr = escape.attrs; | ||
if(config.tag) { | ||
@@ -141,0 +153,0 @@ Tag.defaultName = config.tag; |
@@ -171,3 +171,3 @@ definer('Helpers', /** @exports Helpers */ function(string, number, object, is) { | ||
this._getHelpersFromModule(string, [ | ||
'escape', 'htmlEscape', 'unHtmlEscape', | ||
'escape', 'unEscape', 'htmlEscape', 'unHtmlEscape', | ||
'collapse', 'stripTags', | ||
@@ -174,0 +174,0 @@ 'upper', 'lower', 'repeat' |
@@ -54,2 +54,10 @@ definer('Node', /** @exports Node */ function(Tag, Selector, object) { | ||
this._params = this.getParams(); | ||
/** | ||
* Опции преобразования узла. | ||
* | ||
* @private | ||
* @type {object} | ||
*/ | ||
this._options = node.options || {}; | ||
} | ||
@@ -214,3 +222,8 @@ | ||
return this._tag.toString(); | ||
var escape = Node.resolveOptionEscape(this._options.escape); | ||
return this._tag.toString({ | ||
escapeContent: escape.content, | ||
escapeAttr: escape.attrs | ||
}); | ||
}, | ||
@@ -254,4 +267,36 @@ | ||
/** | ||
* Разернуть опции экранирования. | ||
* | ||
* @param {boolean|object} escape Флаг экранирования спецсимволов | ||
* @param {boolean} [escape.content] Флаг экранирования содержимого | ||
* @param {boolean} [escape.attrs] Флаг экранирования значений атрибутов | ||
* @returns {object} | ||
*/ | ||
Node.resolveOptionEscape = function(escape) { | ||
var content = Tag.escapeContent, | ||
attrs = Tag.escapeAttr; | ||
if(escape !== undefined) { | ||
if(is.boolean(escape)) { | ||
content = escape; | ||
attrs = escape; | ||
} else { | ||
if(is.boolean(escape.content)) { | ||
content = escape.content; | ||
} | ||
if(is.boolean(escape.attrs)) { | ||
attrs = escape.attrs; | ||
} | ||
} | ||
} | ||
return { | ||
content: content, | ||
attrs: attrs | ||
}; | ||
}; | ||
return Node; | ||
}); |
@@ -1,2 +0,2 @@ | ||
definer('Tag', /** @exports Tag */ function(string, is) { | ||
definer('Tag', /** @exports Tag */ function(string, object, is) { | ||
@@ -17,3 +17,3 @@ /** | ||
*/ | ||
this._name = typeof name === 'string' || name === false ? name : Tag.defaultName; | ||
this._name = is.string(name) || name === false ? name : true; | ||
@@ -75,2 +75,16 @@ /** | ||
/** | ||
* Флаг экранирования содержимого тега. | ||
* | ||
* @type {boolean} | ||
*/ | ||
Tag.escapeContent = true; | ||
/** | ||
* Флаг экранирования значений атрибутов. | ||
* | ||
* @type {boolean} | ||
*/ | ||
Tag.escapeAttr = true; | ||
/** | ||
* Список одиночных HTML-тегов. | ||
@@ -96,5 +110,5 @@ * | ||
name: function(name) { | ||
if(name === undefined) return this._name; | ||
if(name === undefined) return this._name === true ? Tag.defaultName : this._name; | ||
this._name = typeof name === 'string' || name === false ? name : Tag.defaultName; | ||
this._name = is.string(name) || name === false ? name : true; | ||
return this; | ||
@@ -155,10 +169,10 @@ }, | ||
* | ||
* @param {boolean} [state] Флаг одиночного тега | ||
* @param {boolean|string} [state] Флаг одиночного тега или имя тега для проверки | ||
* @returns {boolean|Tag} | ||
*/ | ||
single: function(state) { | ||
if(state === undefined) { | ||
if(state === undefined || is.string(state)) { | ||
return this._single !== undefined | ||
? this._single | ||
: !!~Tag.singleTags.indexOf(this._name); | ||
: !!~Tag.singleTags.indexOf(state || this._name); | ||
} | ||
@@ -189,4 +203,4 @@ | ||
if(is.map(name)) { | ||
Object.keys(name).forEach(function(attr) { | ||
this.attr(attr, name[attr]); | ||
object.each(name, function(key, val) { | ||
this.attr(key, val); | ||
}, this); | ||
@@ -198,6 +212,2 @@ return this; | ||
if(is.array(val) || is.map(val)) { | ||
val = string.htmlEscape(JSON.stringify(val)); | ||
} | ||
if(val === false) { | ||
@@ -251,8 +261,23 @@ this.delAttr(name); | ||
* | ||
* @param {object} [options] Опции | ||
* @param {string} [options.defaultName=div] Имя тега по умолчанию | ||
* @param {string} [options.repeatBooleanAttr=false] Флаг автоповтора булева атрибута | ||
* @param {string} [options.closeSingleTag=false] Флаг закрытия одиночного тега | ||
* @param {string} [options.escapeContent=true] Флаг экранирования содержимого тега | ||
* @param {string} [options.escapeAttr=true] Флаг экранирования значений атрибутов | ||
* @returns {string} | ||
*/ | ||
toString: function() { | ||
toString: function(options) { | ||
if(this.name() === false) return this.content().join(''); | ||
var tag = ['<' + this.name()], | ||
options = object.extend({ | ||
defaultName: Tag.defaultName, | ||
repeatBooleanAttr: Tag.repeatBooleanAttr, | ||
closeSingleTag: Tag.closeSingleTag, | ||
escapeContent: Tag.escapeContent, | ||
escapeAttr: Tag.escapeAttr | ||
}, options || {}); | ||
var name = this._name === true ? options.defaultName : this._name, | ||
tag = ['<' + name], | ||
classes = this.getClass(), | ||
@@ -265,14 +290,27 @@ attrs = this.attr(); | ||
Object.keys(attrs).forEach(function(attr) { | ||
attrs[attr] === true | ||
? tag.push(' ' + attr + (Tag.repeatBooleanAttr ? '="' + attr + '"' : '')) | ||
: tag.push(' ' + attr + '="' + attrs[attr] + '"'); | ||
}, this); | ||
object.each(attrs, function(key, val) { | ||
if(val === true) { | ||
tag.push(' ' + key + (options.repeatBooleanAttr ? '="' + key + '"' : '')) | ||
} else { | ||
if(this.single()) { | ||
tag.push(Tag.closeSingleTag ? '/>' : '>'); | ||
if(is.array(val) || is.map(val)) { | ||
val = string.htmlEscape(JSON.stringify(val)); | ||
} else if(options.escapeAttr && is.string(val)) { | ||
val = string.htmlEscape(val); | ||
} | ||
tag.push(' ' + key + '="' + val + '"'); | ||
} | ||
}); | ||
if(this.single(name)) { | ||
tag.push(options.closeSingleTag ? '/>' : '>'); | ||
} else { | ||
tag.push('>'); | ||
tag = tag.concat(this.content()); | ||
tag.push('</' + this.name() + '>'); | ||
tag = tag.concat(options.escapeContent | ||
? this.content().map(function(chunk) { | ||
return is.string(chunk) ? string.htmlEscape(chunk) : chunk; | ||
}) | ||
: this.content()); | ||
tag.push('</' + name + '>'); | ||
} | ||
@@ -279,0 +317,0 @@ |
@@ -57,3 +57,3 @@ definer('Template', /** @exports Template */ function(Match, classify, Node, Selector, Helpers, object, string, is) { | ||
/** | ||
* Получить БЭМ-узел на основе BEMJSON по базому шаблону. | ||
* Получить БЭМ-узел на основе BEMJSON по базовому шаблону. | ||
* | ||
@@ -65,5 +65,3 @@ * @param {object} bemjson Входящий BEMJSON | ||
Template.base = function(bemjson, data) { | ||
return new Template( | ||
new Node(bemjson).isBlock() ? '*' : '*' + Selector.delimiters.elem + '*', {} | ||
).transform(bemjson, data); | ||
return Template.baseTemplate.transform(bemjson, data); | ||
}; | ||
@@ -101,5 +99,6 @@ | ||
Object.keys(this._getDefaultModes()).forEach(function(mode) { | ||
for(var i = 0, len = Template._defaultModesNames.length; i < len; i++) { | ||
var mode = Template._defaultModesNames[i]; | ||
bemjson[mode] = this._getMode(modes, bemjson, mode); | ||
}, this); | ||
} | ||
@@ -162,4 +161,4 @@ return new Node(bemjson); | ||
} else { | ||
Object.keys(nameOrList).forEach(function(name) { | ||
this._helpers.add(name, nameOrList[name]); | ||
object.each(nameOrList, function(name, callback) { | ||
this._helpers.add(name, callback); | ||
}, this); | ||
@@ -195,5 +194,2 @@ } | ||
* | ||
* Если среди селекторов шаблона присутствует хотя бы | ||
* один блок, то будут отданы стандартные моды для блоков. | ||
* | ||
* @private | ||
@@ -213,3 +209,4 @@ * @returns {object} | ||
cls: '', | ||
content: '' | ||
content: '', | ||
options: {} | ||
}; | ||
@@ -244,6 +241,2 @@ }, | ||
if(name === 'content') { | ||
return this._escapeContent(priorityVal); | ||
} | ||
return priorityVal; | ||
@@ -253,24 +246,2 @@ }, | ||
/** | ||
* Заэкранировать содержимое узла. | ||
* | ||
* @private | ||
* @param {*} content Содержимое | ||
* @returns {*} | ||
*/ | ||
_escapeContent: function(content) { | ||
if(is.string(content)) { | ||
return string.htmlEscape(content); | ||
} | ||
if(is.array(content)) { | ||
return content.map(function(item) { | ||
return this._escapeContent(item); | ||
}, this); | ||
} | ||
return content; | ||
}, | ||
/** | ||
* Получить приоритетное значение моды. | ||
@@ -294,4 +265,19 @@ * | ||
/** | ||
* Базовый шаблон. | ||
* | ||
* @type {Template} | ||
*/ | ||
Template.baseTemplate = new Template('', {}); | ||
/** | ||
* Список имён стандартных мод. | ||
* | ||
* @private | ||
* @type {array} | ||
*/ | ||
Template._defaultModesNames = Object.keys(Template.baseTemplate._getDefaultModes()); | ||
return Template; | ||
}); |
@@ -59,8 +59,7 @@ definer('Tree', /** @exports Tree */ function(Template, is, object) { | ||
/** | ||
* Получить узел или примитив | ||
* или список узлов и примитивов | ||
* на основе контента. | ||
* Получить список узлов и примитивов | ||
* на основе массива контента. | ||
* | ||
* @private | ||
* @param {*} bemjson BEMJSON, массив или примитив | ||
* @param {array} bemjson Массив | ||
* @param {object} data Данные по сущности в дереве | ||
@@ -70,9 +69,9 @@ * @param {object} [data.context] Информация о родительском контексте (если родитель — блок) | ||
* @param {object} [data.context.mods] Модификаторы родительского блока | ||
* @returns {*} | ||
* @returns {array} | ||
*/ | ||
_getContent: function(bemjson, data) { | ||
if(is.array(bemjson)) { | ||
return bemjson.reduce(function(list, elem, index) { | ||
var elemData = { | ||
_getContentList: function(bemjson, data) { | ||
var list = []; | ||
for(var index = 0, len = bemjson.length; index < len; index++) { | ||
var elem = bemjson[index], | ||
elemData = { | ||
index: index, | ||
@@ -82,21 +81,13 @@ length: bemjson.length | ||
if(elem && elem.elem) { | ||
elemData.context = data.context; | ||
} | ||
if(elem && elem.elem) { | ||
elemData.context = data.context; | ||
} | ||
var node = is.array(elem) | ||
? this._getContent(elem, data) | ||
: this._getNode(elem, elemData); | ||
var node = is.array(elem) | ||
? this._getContentList(elem, data) | ||
: this._getNode(elem, elemData); | ||
if(is.array(node)) { | ||
list = list.concat(node); | ||
} else { | ||
list.push(node); | ||
} | ||
return list; | ||
}.bind(this), []); | ||
list = list.concat(node); | ||
} | ||
return this._getNode(bemjson, data); | ||
return list; | ||
}, | ||
@@ -119,27 +110,25 @@ | ||
_getNode: function(bemjson, data) { | ||
if(!is.map(bemjson)) return bemjson; | ||
if(is.map(bemjson)) { | ||
data = data || {}; | ||
if(bemjson.elem && !bemjson.block && data.context.block) { | ||
bemjson.block = data.context.block; | ||
if(data.context.mods) { | ||
bemjson.mods = object.extend(bemjson.mods || {}, data.context.mods); | ||
} | ||
if(bemjson.elem && !bemjson.block && data.context.block) { | ||
bemjson.block = data.context.block; | ||
if(data.context.mods) { | ||
bemjson.mods = object.extend(data.context.mods, bemjson.mods || {}); | ||
} | ||
} | ||
var node = this._pool.find(bemjson, data) || Template.base(bemjson, data), | ||
data = {}; | ||
var node = this._pool.find(bemjson, data) || Template.base(bemjson, data); | ||
if(bemjson.block) { | ||
data.context = { block: bemjson.block }; | ||
if(bemjson.mods) { | ||
data.context.mods = bemjson.mods; | ||
} | ||
if(bemjson.block) { | ||
data.context = { block: bemjson.block }; | ||
if(bemjson.mods) { | ||
data.context.mods = object.clone(bemjson.mods); | ||
} | ||
node.content(this._getContent(bemjson.content, data)); | ||
return node; | ||
} | ||
return bemjson; | ||
return node.content(this[ | ||
is.array(bemjson.content) ? '_getContentList' : '_getNode' | ||
](bemjson.content, data)); | ||
} | ||
@@ -146,0 +135,0 @@ |
{ | ||
"name": "bemer", | ||
"description": "Template engine. BEMJSON to HTML processor.", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"repository": { | ||
@@ -33,4 +33,6 @@ "type": "git", | ||
"grunt-mkdir": "~0.1.1", | ||
"grunt-contrib-uglify": "~0.4.0" | ||
"grunt-contrib-uglify": "~0.4.0", | ||
"benchmark": "~1.0.0", | ||
"beautify-benchmark": "~0.2.4" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
538664
57
5313
1
1273
16