Comparing version 2.0.0 to 3.0.0
191
lib/index.js
@@ -1,24 +0,177 @@ | ||
var htmlparser = require('htmlparser2'); | ||
var Compiler = require('./compiler'); | ||
'use strict'; | ||
function Monkberry(name, text, options, callback) { | ||
if (options.normalizeWhitespace) { | ||
text = text.replace(/>\s+</g, '><'); | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); | ||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
var _parsersMonk = require('../parsers/monk'); | ||
var _figure = require('./figure'); | ||
var _visitor = require('./visitor'); | ||
var _compilerSourceNode = require('./compiler/sourceNode'); | ||
var _compilerExpression = require('./compiler/expression'); | ||
var _compilerExpression2 = _interopRequireDefault(_compilerExpression); | ||
var _compilerDocument = require('./compiler/document'); | ||
var _compilerDocument2 = _interopRequireDefault(_compilerDocument); | ||
var _compilerElement = require('./compiler/element'); | ||
var _compilerElement2 = _interopRequireDefault(_compilerElement); | ||
var _compilerElementHtml = require('./compiler/element/html'); | ||
var _compilerElementHtml2 = _interopRequireDefault(_compilerElementHtml); | ||
var _compilerElementSvg = require('./compiler/element/svg'); | ||
var _compilerElementSvg2 = _interopRequireDefault(_compilerElementSvg); | ||
var _compilerElementCustom = require('./compiler/element/custom'); | ||
var _compilerElementCustom2 = _interopRequireDefault(_compilerElementCustom); | ||
var _compilerAttribute = require('./compiler/attribute'); | ||
var _compilerAttribute2 = _interopRequireDefault(_compilerAttribute); | ||
var _compilerText = require('./compiler/text'); | ||
var _compilerText2 = _interopRequireDefault(_compilerText); | ||
var _compilerIf = require('./compiler/if'); | ||
var _compilerIf2 = _interopRequireDefault(_compilerIf); | ||
var _compilerFor = require('./compiler/for'); | ||
var _compilerFor2 = _interopRequireDefault(_compilerFor); | ||
var _optimizeWhitespace = require('./optimize/whitespace'); | ||
var Compiler = (function () { | ||
function Compiler() { | ||
_classCallCheck(this, Compiler); | ||
this.sources = []; | ||
this.parsers = { monk: _parsersMonk.parser }; | ||
this.transforms = { whitespace: _optimizeWhitespace.whitespace }; | ||
} | ||
var handler = new htmlparser.DomHandler(function (error, dom) { | ||
if (error) { | ||
console.error(error); | ||
} else { | ||
var compiler = new Compiler(name, dom); | ||
callback(compiler); | ||
_createClass(Compiler, [{ | ||
key: 'addSource', | ||
value: function addSource(name, code) { | ||
var parser = arguments.length <= 2 || arguments[2] === undefined ? 'monk' : arguments[2]; | ||
var asLibrary = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3]; | ||
this.sources.push([name, code, parser, asLibrary]); | ||
} | ||
}, options); | ||
var parser = new htmlparser.Parser(handler, { | ||
recognizeSelfClosing: true | ||
}); | ||
parser.write(text); | ||
parser.done(); | ||
} | ||
}, { | ||
key: 'enhanceParsers', | ||
value: function enhanceParsers() { | ||
var _this = this; | ||
module.exports = Monkberry; | ||
Object.keys(this.parsers).forEach(function (type) { | ||
var parser = _this.parsers[type]; | ||
// Extend AST with compilers. | ||
(0, _compilerDocument2['default'])(parser.ast); | ||
(0, _compilerElement2['default'])(parser.ast); | ||
(0, _compilerElementHtml2['default'])(parser.ast); | ||
(0, _compilerElementSvg2['default'])(parser.ast); | ||
(0, _compilerElementCustom2['default'])(parser.ast); | ||
(0, _compilerAttribute2['default'])(parser.ast); | ||
(0, _compilerExpression2['default'])(parser.ast); | ||
(0, _compilerText2['default'])(parser.ast); | ||
(0, _compilerIf2['default'])(parser.ast); | ||
(0, _compilerFor2['default'])(parser.ast); | ||
(0, _visitor.visitor)(parser.ast); | ||
}); | ||
} | ||
}, { | ||
key: 'compile', | ||
value: function compile() { | ||
var _this2 = this; | ||
var asModule = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0]; | ||
this.enhanceParsers(); | ||
var figures = (0, _compilerSourceNode.sourceNode)(null, ''); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = this.sources[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _step$value = _slicedToArray(_step.value, 4); | ||
var _name = _step$value[0]; | ||
var code = _step$value[1]; | ||
var parserType = _step$value[2]; | ||
var asLibrary = _step$value[3]; | ||
if (parserType in this.parsers) { | ||
var parser = this.parsers[parserType]; | ||
var ast = parser.parse(code, _name); | ||
// Transforms | ||
Object.keys(this.transforms).forEach(function (key) { | ||
return _this2.transforms[key](ast, parser); | ||
}); | ||
var figure = new _figure.Figure(_name.replace(/\.\w+$/, '')); | ||
if (asLibrary) { | ||
figure.perceivedAsLibrary = true; | ||
} | ||
figures.add(ast.compile(figure)); | ||
} else { | ||
throw Error('Unknown parser ' + parser + '.'); | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator['return']) { | ||
_iterator['return'](); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
var output = (0, _compilerSourceNode.sourceNode)(null, ''); | ||
if (asModule) { | ||
output.add('module.exports = function (monkberry, document) {\n').add('var filters = monkberry.filters;\n').add('return {\n').add(figures.join(',\n')).add('};\n').add('};\n'); | ||
} else { | ||
output.add('(function (monkberry, filters, document, undefined) {\n').add('monkberry.mount({\n').add(figures.join(',\n')).add('\n});\n').add('})(monkberry, monkberry.filters, window.document, void 0);\n'); | ||
} | ||
return output; | ||
} | ||
}]); | ||
return Compiler; | ||
})(); | ||
exports.Compiler = Compiler; |
@@ -1,53 +0,221 @@ | ||
function Visitor(callback) { | ||
this.callback = callback; | ||
} | ||
"use strict"; | ||
var HTMLElements = ( | ||
'a abbr address area article aside audio b base bdi bdo big blockquote body br ' + | ||
'button canvas caption cite code col colgroup data datalist dd del details dfn ' + | ||
'dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 ' + | ||
'h6 head header hr html i iframe img input ins kbd keygen label legend li link ' + | ||
'main map mark menu menuitem meta meter nav noscript object ol optgroup option ' + | ||
'output p param picture pre progress q rp rt ruby s samp script section select ' + | ||
'small source span strong style sub summary sup table tbody td textarea tfoot th ' + | ||
'thead time title tr track u ul var video wbr' | ||
).split(' '); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.visitor = visitor; | ||
var SVGElements = ( | ||
'circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline ' + | ||
'radialGradient rect stop svg text tspan' | ||
).split(' '); | ||
function visitor(ast) { | ||
ast.DocumentNode.prototype.visit = function (callback) { | ||
callback(this); | ||
Visitor.prototype.visit = function (nodes) { | ||
var children = [], push = function (value) { | ||
if (value) { | ||
children.push(value); | ||
for (var i = 0; i < this.body.length; i++) { | ||
this.body[i].visit(callback); | ||
} | ||
}; | ||
for (var node of nodes) { | ||
if (node.type === 'tag') { | ||
if (HTMLElements.indexOf(node.name) != -1) { | ||
push(this.callback.tagNode(node)); | ||
} else if (SVGElements.indexOf(node.name) != -1) { | ||
push(this.callback.svgNode(node)); | ||
} else if (node.name === 'if') { | ||
push(this.callback.ifNode(node)); | ||
} else if (node.name === 'for') { | ||
push(this.callback.forNode(node)); | ||
ast.TextNode.prototype.visit = function (callback) { | ||
callback(this); | ||
}; | ||
ast.ElementNode.prototype.visit = function (callback) { | ||
callback(this); | ||
for (var i = 0; i < this.attributes.length; i++) { | ||
this.attributes[i].visit(callback); | ||
} | ||
for (var i = 0; i < this.body.length; i++) { | ||
this.body[i].visit(callback); | ||
} | ||
}; | ||
ast.AttributeNode.prototype.visit = function (callback) { | ||
callback(this); | ||
if (this.body) { | ||
for (var i = 0; i < this.body.length; i++) { | ||
this.body[i].visit(callback); | ||
} | ||
} | ||
}; | ||
ast.ExpressionStatementNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.expression.visit(callback); | ||
}; | ||
ast.IfStatementNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.test.visit(callback); | ||
for (var i = 0; i < this.then.length; i++) { | ||
this.then[i].visit(callback); | ||
} | ||
if (this._else) { | ||
for (var i = 0; i < this._else.length; i++) { | ||
this._else[i].visit(callback); | ||
} | ||
} | ||
}; | ||
ast.ForStatementNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.expr.visit(callback); | ||
for (var i = 0; i < this.body.length; i++) { | ||
this.body[i].visit(callback); | ||
} | ||
}; | ||
ast.FilterExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.callee.visit(callback); | ||
var args = this.arguments; | ||
for (var i = 0, len = args.length; i < len; i++) { | ||
args[i].visit(callback); | ||
} | ||
}; | ||
ast.ArrayExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
var elements = this.elements; | ||
for (var i = 0, len = elements.length; i < len; i++) { | ||
elements[i].visit(callback); | ||
} | ||
}; | ||
ast.ObjectExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
var i, | ||
j, | ||
properties = this.properties; | ||
for (i = 0, len = properties.length; i < len; i++) { | ||
var prop = properties[i]; | ||
var kind = prop.kind; | ||
var key = prop.key; | ||
var value = prop.value; | ||
if (kind === "init") { | ||
key.visit(callback); | ||
value.visit(callback); | ||
} else { | ||
push(this.callback.customNode(node)); | ||
var params = value.params; | ||
var body = value.body; | ||
key.visit(callback); | ||
for (j = 0, plen = params.length; j < plen; j++) { | ||
params[j].visit(callback); | ||
} | ||
for (j = 0, blen = body.length; j < blen; j++) { | ||
body[j].visit(callback); | ||
} | ||
} | ||
} | ||
}; | ||
} else if (node.type === 'text') { | ||
push(this.callback.textNode(node)); | ||
} else if (node.type === 'directive') { | ||
push(this.callback.directiveNode(node)); | ||
} else { | ||
throw new Error('Unknown node type: "' + node.type + '".'); | ||
ast.SequenceExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
var expressions = this.expressions; | ||
for (var i = 0, len = expressions.length; i < len; i++) { | ||
expressions[i].visit(callback); | ||
} | ||
} | ||
return children; | ||
}; | ||
}; | ||
module.exports = Visitor; | ||
ast.UnaryExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.argument.visit(callback); | ||
}; | ||
ast.BinaryExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.left.visit(callback); | ||
this.right.visit(callback); | ||
}; | ||
ast.AssignmentExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.left.visit(callback); | ||
this.right.visit(callback); | ||
}; | ||
ast.UpdateExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.argument.visit(callback); | ||
this.argument.visit(callback); | ||
}; | ||
ast.LogicalExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.left.visit(callback); | ||
this.right.visit(callback); | ||
}; | ||
ast.ConditionalExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.test.visit(callback); | ||
this.consequent.visit(callback); | ||
this.alternate.visit(callback); | ||
}; | ||
ast.NewExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.callee.visit(callback); | ||
var args = this.arguments; | ||
if (args !== null) { | ||
for (var i = 0, len = args.length; i < len; i++) { | ||
args[i].visit(callback); | ||
} | ||
} | ||
}; | ||
ast.CallExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.callee.visit(callback); | ||
var args = this.arguments; | ||
for (var i = 0, len = args.length; i < len; i++) { | ||
args[i].visit(callback); | ||
} | ||
}; | ||
ast.MemberExpressionNode.prototype.visit = function (callback) { | ||
callback(this); | ||
this.object.visit(callback); | ||
this.property.visit(callback); | ||
}; | ||
ast.IdentifierNode.prototype.visit = function (callback) { | ||
callback(this); | ||
}; | ||
ast.AccessorNode.prototype.visit = function (callback) { | ||
callback(this); | ||
}; | ||
ast.LiteralNode.prototype.visit = function (callback) { | ||
callback(this); | ||
}; | ||
} |
@@ -10,5 +10,14 @@ (function (document) { | ||
Monkberry.prototype.foreach = function (parent, node, map, template, data, array, options) { | ||
var i, j, len, childrenSize = map.length; | ||
var i, j, len, keys, transform, arrayLength, childrenSize = map.length; | ||
len = childrenSize - array.length; | ||
if (Array.isArray(array)) { | ||
transform = transformArray; | ||
arrayLength = array.length; | ||
} else { | ||
transform = transformObject; | ||
keys = Object.keys(array); | ||
arrayLength = keys.length; | ||
} | ||
len = childrenSize - arrayLength; | ||
for (i in map.items) { | ||
@@ -24,7 +33,7 @@ if (len-- > 0) { | ||
for (i in map.items) { | ||
map.items[i].update(forData(data, array[j], j, options)); | ||
map.items[i].update(transform(data, array, keys, j, options)); | ||
j++; | ||
} | ||
for (j = childrenSize, len = array.length; j < len; j++) { | ||
for (j = childrenSize, len = arrayLength; j < len; j++) { | ||
// Render new view. | ||
@@ -45,3 +54,3 @@ var view = this.render(template); | ||
// Set view data (note what it must be after adding nodes to DOM). | ||
view.update(forData(data, array[j], j, options)); | ||
view.update(transform(data, array, keys, j, options)); | ||
@@ -62,4 +71,3 @@ // Remember to remove from children map on view remove. | ||
child.ref.update(data); | ||
} | ||
else { | ||
} else { | ||
child.ref.remove(); | ||
@@ -91,2 +99,4 @@ } | ||
} | ||
return test; | ||
}; | ||
@@ -117,2 +127,6 @@ | ||
if (view.onRender) { | ||
view.onRender(); | ||
} | ||
view.wrapped = view.wrapped || {}; | ||
@@ -149,11 +163,2 @@ if (this.wrappers[name] && !view.wrapped[name]) { | ||
Monkberry.prototype.extend = function (obj, from) { | ||
for (var key in from) { | ||
if (from.hasOwnProperty(key)) { | ||
obj[key] = from[key]; | ||
} | ||
} | ||
return obj; | ||
}; | ||
Monkberry.prototype.view = function () { | ||
@@ -193,12 +198,9 @@ return new View; | ||
} | ||
if (_this.set) { | ||
if (_this.__update__) { | ||
keys.forEach(function (key) { | ||
if (_this.set.hasOwnProperty(key)) { | ||
_this.set[key](data, data[key]); | ||
if (_this.__update__.hasOwnProperty(key)) { | ||
_this.__update__[key](data, data[key]); | ||
} | ||
}); | ||
} | ||
if (_this._update) { | ||
_this._update(data); | ||
} | ||
}; | ||
@@ -301,2 +303,8 @@ | ||
Map.prototype.forEach = function (callback) { | ||
for (var i in this.items) { | ||
callback(this.items[i]); | ||
} | ||
}; | ||
/** | ||
@@ -306,17 +314,33 @@ * Helper function for working with foreach loops data. | ||
*/ | ||
function forData(data, item, key, options) { | ||
function transformArray(data, array, keys, i, options) { | ||
if (options) { | ||
var newData = data; | ||
newData[options.valueName] = item; | ||
var t = data; | ||
t[options.value] = array[i]; | ||
if (options.keyName) { | ||
newData[options.keyName] = key; | ||
if (options.key) { | ||
t[options.key] = i; | ||
} | ||
return newData; | ||
return t; | ||
} else { | ||
return item; | ||
return i; | ||
} | ||
} | ||
function transformObject(data, array, keys, i, options) { | ||
if (options) { | ||
var t = data; | ||
t[options.value] = array[keys[i]]; | ||
if (options.key) { | ||
t[options.key] = keys[i]; | ||
} | ||
return t; | ||
} else { | ||
return array[keys[i]]; | ||
} | ||
} | ||
if (typeof module !== "undefined") { | ||
@@ -323,0 +347,0 @@ module.exports = new Monkberry(); |
{ | ||
"name": "monkberry", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "JavaScript DOM Template Engine", | ||
@@ -8,3 +8,7 @@ "bin": "./bin/monkberry", | ||
"scripts": { | ||
"test": "node_modules/.bin/testem ci -l phantomjs" | ||
"test": "node_modules/.bin/testem ci -l phantomjs", | ||
"compile:parsers": "parsers/build.sh", | ||
"compile": "node_modules/.bin/babel -d lib/ src/", | ||
"build": "node_modules/.bin/babel -w -d lib/ src/", | ||
"prepublish": "npm run compile && npm run compile:parsers" | ||
}, | ||
@@ -29,3 +33,3 @@ "browser": "./monkberry.js", | ||
"commander": "^2.8.1", | ||
"htmlparser2": "^3.8.3", | ||
"source-map": "^0.5.1", | ||
"through": "^2.3.7" | ||
@@ -35,5 +39,8 @@ }, | ||
"asciitree": "^1.0.0", | ||
"babel": "^5.8.23", | ||
"jasmine": "^2.3.2", | ||
"jison": "^0.4.15", | ||
"preprocessor": "^1.4.0", | ||
"testem": "^0.9.4" | ||
} | ||
} |
346
README.md
@@ -1,6 +0,348 @@ | ||
# Monkberry | ||
# Monkberry - JavaScript template engine | ||
[![Build Status](https://travis-ci.org/monkberry/monkberry.svg?branch=master)](https://travis-ci.org/monkberry/monkberry) | ||
JavaScript DOM template engine. | ||
Monkberry compile template to JavaScript code for creating nodes with DOM API and helper methods for updating content of these nodes. | ||
``` | ||
npm install monkberry --save | ||
``` | ||
## Features | ||
* Small, dependency free | ||
* Simple and minimalistic | ||
* Fully tested | ||
* One-way data flow | ||
* Precompiled templates | ||
* SourceMaps | ||
* Custom tags | ||
* Extremely fast! | ||
## Example | ||
Monkberry will compile this template: | ||
```html | ||
<div> | ||
<h1>{{ title }}</h1> | ||
<p> | ||
{{ text }} | ||
</p> | ||
</div> | ||
``` | ||
To JavaScript code like this: | ||
```js | ||
var div = document.createElement('div'); | ||
var h1 = document.createElement('h1'); | ||
var p = document.createElement('p'); | ||
div.appendChild(h1); | ||
div.appendChild(p); | ||
... | ||
view.update = function (data) { | ||
h1.textContent = data.title; | ||
p.textContent = data.text; | ||
}; | ||
``` | ||
Which can be used like that: | ||
```js | ||
var view = monkberry.render('template'); | ||
document.body.appendChild(view.dom()); | ||
view.update({ | ||
title: 'Monkberry', | ||
text: 'JavaScript DOM template engine' | ||
}); | ||
``` | ||
## Documentation | ||
### Getting Started | ||
Monkberry has support for both browserify via [monkberrify](https://github.com/monkberry/monkberrify) and for webpack via [monkberry-loader](https://github.com/monkberry/monkberry-loader). | ||
Monkberry can be used like CLI tool. Install Monkberry globally: | ||
``` | ||
npm install monkberry -g | ||
``` | ||
To compile all templates into single JavaScript file with source map run next command: | ||
``` | ||
monkberry --source-map --output template.js templates/*.html | ||
``` | ||
Require generated `template.js` and `monkberry.js` files and mount template: | ||
```js | ||
var monkberry = require('monkberry'); | ||
var template = require('./template.js'); | ||
monkberry.mount(template); | ||
``` | ||
Render that view. | ||
```js | ||
var view = monkberry.render('template'); | ||
// or | ||
var view = monkberry.render('template', {...}); | ||
``` | ||
Attach generated DOM nodes to the page. | ||
```js | ||
document.getElementById('root').appendChild(view.dom()); | ||
``` | ||
Now, to update data of view on page: | ||
```js | ||
view.update({...}); | ||
// or update only what's needed | ||
view.update({key: value}); | ||
``` | ||
### Expressions | ||
Monkberry perceives everything inside `{{` and `}}` mustache as JavaScript expression. | ||
```html | ||
<div class="greetings {{ visible ? '' : 'hidden' }}"> | ||
Hello, {{ user.name + "!" }} | ||
</div> | ||
``` | ||
### If, Else | ||
Can be any valid JavaScrpt expressions. | ||
```twig | ||
{% if count < 0 || count > 10 %} | ||
... | ||
{% else %} | ||
... | ||
{% endif %} | ||
``` | ||
Any number on variables in `if`: | ||
```twig | ||
{% if array.indexOf(search) != -1 %} | ||
... | ||
{% endif %} | ||
``` | ||
> Note what Monkberry update only one of `if`/`else` block. | ||
> ```twig | ||
> {% if check %} | ||
> Then {{ value }}! | ||
> {% else %} | ||
> Else {{ value }}! | ||
> {% endif %} | ||
> ``` | ||
> Render that template: | ||
> ```js | ||
> var view = monkberry.render('example', { | ||
> check: true, | ||
> value: 'one' | ||
> }); | ||
> ``` | ||
> View will be `Then one!`. When if update view: | ||
> ```js | ||
> view.update({ | ||
> check: false, | ||
> value: 'two' | ||
> }); | ||
> ``` | ||
> View will be `Else two!`. But if update only `check`, variable of then part will be same as before. | ||
> ```js | ||
> view.update({check: true}); | ||
> ``` | ||
> View will be `Then one!`. | ||
> | ||
> This is happens becouse Monkberry does not stores variables passed to `update` function, it stores only DOM nodes. | ||
> Monkberry will update only one part of `if`/`else`. | ||
### For | ||
Monkberry can loop other arrays and objects as well. | ||
```twig | ||
{% for array %} | ||
{{ name }} | ||
{% endfor %} | ||
``` | ||
In this form, body of `for` has access only for variables iterating on. | ||
```js | ||
view.update({ | ||
array: [ | ||
{name: 'Anton'}, | ||
... | ||
] | ||
}); | ||
``` | ||
To access outer scope specify iterator name. | ||
```twig | ||
{% for user of array %} | ||
{{ user.name }} | ||
{% endfor %} | ||
``` | ||
Also key can be specified. | ||
```twig | ||
{% for key, user of array %} | ||
{{ key }}: {{ user.name }} | ||
{% endfor %} | ||
``` | ||
### Filters | ||
Any expression support filter statement. | ||
```twig | ||
Hello, {{ user.name | upper }} | ||
``` | ||
To define that filter: | ||
```js | ||
monkberry.filters.upper = function (text) { | ||
return text.toUpperCase(); | ||
}; | ||
``` | ||
Also Monkberry understand parameters for filters: | ||
```js | ||
monkberry.filters.replace = function (text, from, to) { | ||
return text.replace(from, to); | ||
}; | ||
``` | ||
```twig | ||
{{ text | replace(/.../, '$1') }} | ||
``` | ||
And allow to combine filters: | ||
```twig | ||
{{ text | lower | replace(/.../, '$1') | upper }} | ||
``` | ||
That expression will be compiled to next JavaScript: | ||
```js | ||
upper(replace(lower(text), /.../, '$1')); | ||
``` | ||
Filters can be used in expressions, `if` and `for` statements. | ||
### Custom tags | ||
Any template mounted to Monkberry can be called as custom tag. | ||
```js | ||
monkberry.mount(require('./views/block.html')); | ||
``` | ||
Inside another template possible to insert that `block` templace as custom tag: | ||
```html | ||
<div> | ||
<block/> | ||
</div> | ||
``` | ||
One file can contains several definitions of custom tags: | ||
```html | ||
<my-tag> | ||
... | ||
</my-tag> | ||
<my-second-tag> | ||
... | ||
</my-second-tag> | ||
``` | ||
Custom tags may contains variables: | ||
```twig | ||
<greet> | ||
{{ value }}, {{ name }}! | ||
</greet> | ||
``` | ||
To render that custom tag, specify variables as attributes: | ||
```twig | ||
<greet value="Hello" name="world"> | ||
<greet value="Hello" name="{{ user.name }}"> | ||
``` | ||
### Prerender | ||
To speedup render Monkberry can prerender DOM nodes to use them in future. | ||
```js | ||
monkberry.prerender('template', 10); // Preprender template 10 times. | ||
``` | ||
Then next `render` call will use one of these prerendered views: | ||
```js | ||
monkberry.render('template', {...}); // Will use already created DOM nodes. | ||
``` | ||
This is very usefull to do then browser waiting some xhr request. | ||
To get info about prerendered template in runtime, use `monkberry.pool.store`. | ||
### Wrappers | ||
Every template in Monkbeery when rendered can be "wrapped" by function. | ||
For example we have a template `logo.html`: | ||
```twig | ||
<div> | ||
<i class="svg-icon"></i> | ||
</div> | ||
``` | ||
And we want to insert SVG nodes inside `i` tag on render. This is can be done via wrappers: | ||
```js | ||
monkberry.wrappers.logo = function (view) { | ||
view.dom().querySelector('.svg-icon').appendChild(svgIconNodes); | ||
return view; | ||
}; | ||
``` | ||
Wrappers usefull to manipulate view's nodes, adding event listeners and a lot of other staff. | ||
### Transforms | ||
Transformers allow to modify [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) before compilation of templates. | ||
List of AST nodes can be founded here: [ast.js](https://github.com/monkberry/monkberry/blob/master/parsers/ast.js) | ||
Example of transform which trim whitespaces: [whitespace.js](https://github.com/monkberry/monkberry/blob/master/src/optimize/whitespace.js) | ||
Add transforms to Monkbeery before compilation: | ||
```js | ||
import { Compiler } from 'monkberry'; | ||
import { myTransform } from './myTransform'; | ||
var compiler = new Compiler(); | ||
compiler.transforms.custom = myTransform; | ||
``` | ||
### Parsers | ||
Now Monkberry support only one type of parser, mustage like (`monk` named). But it can be extender with custom parsers. Every parser must return valid [AST](https://github.com/monkberry/monkberry/blob/master/parsers/ast.js) tree. | ||
```js | ||
import { Compiler } from 'monkberry'; | ||
import { myParser } from './parser'; | ||
var compiler = new Compiler(); | ||
compiler.parsers.myParser = myTransform; | ||
compiler.addSource('template', code, 'myParser'); | ||
compiler.addSource('another', code, 'monk'); | ||
var output = compiler.compile(); | ||
``` | ||
## Tests | ||
@@ -7,0 +349,0 @@ |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
3445193
79
42290
354
6
+ Addedsource-map@^0.5.1
+ Addedsource-map@0.5.7(transitive)
- Removedhtmlparser2@^3.8.3
- Removeddom-serializer@0.2.2(transitive)
- Removeddomelementtype@1.3.12.3.0(transitive)
- Removeddomhandler@2.4.2(transitive)
- Removeddomutils@1.7.0(transitive)
- Removedentities@1.1.22.2.0(transitive)
- Removedhtmlparser2@3.10.1(transitive)
- Removedinherits@2.0.4(transitive)
- Removedreadable-stream@3.6.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedstring_decoder@1.3.0(transitive)
- Removedutil-deprecate@1.0.2(transitive)