[MaskJS](http://atmajs.com/mask' target='_blank'>mask.js) — is a markup | template | HMVC engine for
modern and fast web(Browser), server(NodeJS) or mobile(PhoneGap) applications. Component-based architecture
simplifies defining, implementing and composing loosely coupled independent elements into a single application.
Resources:
Syntax
- Component and element-based markup
- Statements, Expressions, Interpolations
- Performance. No precompilation is required
- Small size. ~30% smaller than HTML Additionaly, there is a minification tool - mask-minify.
- DOM Builder
[Template → Mask DOM → Shadow DOM → Live DOM]
- HTML Builder (nodejs)
[Template → Mask DOM → HTML]
.container {
h4 > 'Title'
section.content data-id='myID' {
span > 'Hello ~[name]!'
if (admins.indexOf(name) > -1) {
em > 'Admin'
}
}
:customComponent {
button x-signal='click: changeName' >
'~[bind: name]'
for (tag of tags) {
h4 > '~[tag.title]'
}
}
}
MaskJS has extremely extendable API based on interfaces and contracts. It supports Custom Tag Handlers, Custom Attribute Handlers, Model Utils.
MaskJS default build contains sub projects: CompoJS
, Bindings
, jMask
.
Components Library
Documentation
Core of the HMVC engine. Simple compo sample:
mask.registerHandler(':customComponent', mask.Compo({
slots: {
refreshDate: function(){
this.model.date = new Date();
},
domInsert: function(){
alert(this.$.innerWidth());
}
},
events: {
'click: button': function(){
alert(this.model.date);
}
},
onRenderStart: function(model, ctx){
this.model = { date: new Date(); }
},
onRenderEnd: function(elements, model, ctx){
this.$
},
dispose: function(){
}
})
Bindings Library
Documentation (IE9+)
MaskJS itself supports simple interpolations. It means the models are only accessed while render, but with this library you can define single or dual bindings. As MaskJS is a DOM based engine, the bindings are instant.
Simple bindings sample:
h4 > '~[bind: age/percent]'
input type=number >
:dualbind
value='age'
// e.g. send a signal when the value changes in the DOM
x-signal='dom: ageChanged'
;
input type=number >
:dualbind value='percent';
// `:dualbind` component also supports some other properties
jMask Library
Documentation
jMask offers jQuery-alike syntax for the dynamic MaskDOM Manipulations.
jQuery
MaskJS is loosely coupled with the DOM Library, like jQuery-Zepto-Kimbo. It means, that it does not depend on any DOM library, but it is highly recommended to use one. Additionally there are some extensions, like
$.fn.appendMask
$.fn.prependMask
$.fn.beforeMask
$.fn.afterMask
$.fn.emptyAndDispose
$.fn.removeAndDispose
$('.foo').appendMask('h4 > "~[title]"', { title: 'Hello' });
So you would never need to use the HTML.
Performance
We thoroughly pay attention to the performance, especially on the mobile CPU. The DOM based and the Shadow DOM approach is the fastest way to create hierarchical component structure.
Some benchmarks:
Node.JS
MaskJS on the server - mask.node. (server)
- HMVC benefits
- Models serialization/de-serialization
- Components render mode - Server, Client, Both
- HTML rendered output with the Bootstrapping on the client, so that the components are initialized, all events and bindings are attached
- Application start performance: browser receives ready html for rendering.
- SEO
Browser Support
Plugins
There are already many plugins, components and useful utilities. Some of them worth checking out:
Quick Start
Quick start and examples
Most simple MaskJS sample to show where you could start from:
<!DOCTYPE html>
<html>
<body>
<header>
<script type='text/mask' data-run='true'>
ul {
for(page of pages) {
log('>> Log current:', page);
li > a
href='/~[page].html'
x-signal='click: fooAction' > '~[page]'
}
:bazCompo > :quxCompo;
debugger;
}
</script>
</header>
<script src='http://cdn.jsdelivr.net/g/maskjs'></script>
<script type='text/javascript'>
var App = mask.Compo({
model: {
pages: [ 'blog', 'about', 'contact' ]
},
slots: {
fooAction: function(event){
event.preventDefault();
console.log(this instanceof App);
}
}
});
mask.registerHandler(':bazCompo', mask.Compo({}));
mask.registerHandler(':quxCompo', mask.Compo({}));
mask.run(App);
</script>
</body>
</html>
###Changelog
-
0.9.6
- Merge feature for better encapsulation, e.g:
define :dialog {
.wrapper > .modal {
.modal-header {
@title;
.close;
}
.modal-content > @body;
}
}
// ..
:dialog {
@title > 'Hello'
@body > 'World!'
}
-
0.9.1
-
0.9.0
- Syntax: (statements)
if (expression) { ... } else if (expr) {} else {}
for (el of array) { ... }
for ((el,index) of array) { ... }
for (key in object) { ... }
for ((key, value) in object) { ... }
each (array) { ... }
with (obj.property.value) { ... }
switch (value) { case (expression) { ... } /*...*/ }
- Controllers scoped model
- IncludeJS integration
include ("./UserTemplate.mask") {
for(user in users) {
import('UserTemplate');
}
}
-
0.8.1
-
0.8.0
- Async components. If a components needs to accomplish any async task, it can be done in
renderStart/onRenderStart
function using
Compo.pause(this, ctx) / Compo.resume(this, ctx)
mask.registerHandler(':asyncCompo', mask.Compo({
onRenderStart: function(model, ctx){
var resume = Compo.pause(this, ctx);
someAsyncJob(function(){
resume();
});
}
}));
-
0.7.5
- Binded Percent Handler -
if
, `each
-
0.7.0
-
0.6.95
-
Use ~[]
for string interpolation instead of #{}
, as mask templates are already overloaded with '#','{' and '}' usage
mask.setInterpolationQuotes('#{','}')
- for fallback (or any other start/end, caution - start should be of 2 chars and the end of 1
:copyright: MIT - 2014 Atma.js Project