knockoff

0.1.3 • Public • Published

KnockOff

KnockoutJS to TAssembly compiler.

  • Compiles a basic subset of KnockoutJS functionality to TAssembly, a simple JSON-based intermediate template representation.
  • Builds a HTML5 DOM internally, ensures proper nesting.
  • TAssembly performs context-sensitive escaping of all user-provided data.
  • The overall solution is the fastest JS templating library in our micro-benchmarks, but yet provides the security benefits of much more expensive DOM templating libraries.

Usage

Simple example:

var ko = require('knockoff');
 
var template = ko.compile('<div data-bind="attr:{id:id}, text: body"></div>'),
    model = {
    id: "myId",
    body: "some text"
    };
 
console.log( template( model ) );

Compile to TAssembly for later execution:

var ko = require('knockoff');
 
var tassemblyTemplate = ko.compile(
    '<div data-bind="attr:{id:id}, text: body"></div>',
    { toTAssembly: true }
    );
// ["<div",["attr",{"id":"m.id"}],">",["text","m.body"],"</div>"]
console.log( JSON.stringify( tassemblyTemplate) );

Compile all the way to a function, and pass in TAssembly compilation options:

var ko = require('knockoff');
 
var options = {
    // Define globals accessible as $.* in any scope
    globals: {
        echo: function(x) {
            return x;
        }
    },
    // Define partial templates.
    // This one uses the global echo function defined above.
    partials: {
        userTpl: '<span data-bind="text: $.echo(name)"></span>'
    }
};
 
// Our simple template using KnockOut syntax, and referencing the partial
var templateString = '<div data-bind="template: { name: \'userTpl\', data: user }"></div>';
 
// Now compile the template & options into a function.
// Uses TAssembly internally, use toTAssembly option for TAssembly output.
var templateFn = ko.compile(templateString, options);
 
// A simple model object
var model = {
    user: { name: "Foo" }
};
 
// Now execute the template with the model.
// Prints: <div><span>Foo</span></div>
console.log( templateFn( model ) );

Partials are expected to be in KnockOff syntax, and will be compiled to TAssembly automatically.

KnockOff spec

KnockOff supports a subset of KnockOut functionality. The biggest differences are:

  • No reactivity. KnockOff aims for speed and one-shot operation.

  • Limited expression syntax. KnockOut supports arbitrary JS, while we restrict ourselves to literals (including objects), model access and function calls. The usual KnockOut model accessors are supported. In addition, a global $ object is defined, which can be populated with the globals compile time option.

text

Emit text content. HTML-sensitive chars are escaped. Options is a single expression:

<div data=bind="text: textContent"></div>

See also the KnockOut docs for text.

foreach

Iterate over an array. The view model '$data' in each iteration is each member of the array.

<ul data-bind="foreach: links">
    <li data-bind="text: $data"></li>
</ul>

If each array element is an object, its members will be directly accessible in the loop's view model:

<ul data-bind="foreach: people">
    <li><a data-bind="attr: { href: homepageURL }, text: name"></a></li>
</ul>

You can pass in the name of a partial instead of the inline template.

$index, $parent and other context properties work just like in KnockOut.

See also the KnockOut docs for foreach.

template

Calls a template (inline or name of a partial) with a given model.

<div data-bind="template: { name: 'person-template', data: buyer }"></div>

See also the KnockOut docs for template.

with

The with binding creates a new binding context, so that descendant elements are bound in the context of a specified object. It evaluates a nested block iff the model object is truish.

<div data-bind="with: person">
    <span data-bind="text: firstName"></span>
    <span data-bind="text: lastName"></span>
</div>

See also the KnockOut docs for with.

if

Evaluates a block or template if an expression is true.

<div data-bind="if: displayMessage">Here is a message. Astonishing.</div>

See also the KnockOut docs for if.

ifnot

Evaluates a block or template if an expression is false.

<div data-bind="ifnot: displayMessage">No message to display.</div>

See also the KnockOut docs for ifnot.

attr

Emit one or more HTML attributes. Automatic context-sensitive escaping is applied to href, src and style attributes.

<a data-bind="attr: { href: url, title: details }">
    Report
</a>

See also the KnockOut docs for attr.

visible

Hides a block using CSS if the condition is falsy.

<div data-bind="visible: shouldShowMessage">
    You will see this message only when "shouldShowMessage" holds a true value.
</div>

Currently this uses display: none !important; inline, but we could also add a class instead. Let us know which you prefer.

See also the KnockOut docs for visible.

Virtual elements / container-less syntax

You can use Knockout's comment syntax to apply control flow bindings (if, ifnot, foreach, with) to arbitrary content outside of elements:

<ul>
    <li>This item always appears</li>
    <!-- ko if: someExpressionGoesHere -->
        <li>I want to make this item present/absent dynamically</li>
    <!-- /ko -->
</ul>

See also the KnockOut docs for if and other control flow bindings.

Model access and expressions

KnockOff supports a restricted set of simple JS expressions. These are a subset of KnockOut's arbitrary JS. A KnockOff expression will normally also be a valid KnockOut expression.

  • Literals:
    • Number 2 or 3.4
    • Quoted string 'Some string literal'
    • Object {foo: 'bar', baz: someVar}
  • Variable access with dot notation: foo.bar
  • Array references: users[user]
  • Function calls: $.i18n('username', {foo: bar} ); nesting and multiple parameters supported

Expressions have access to a handful of variables defined in the current context:

  • $data - current view model
  • $root - root (topmost) view model
  • $parent - parent view model
  • $parents - array of parent view models
  • $parentContext - parent context object
  • $index - current iteration index in foreach
  • $ - globals defined at compile time; typically used for helper functions which should not be part of the model (i18n etc). This is an extension over KnockOut, which can be replicated there using expression rewriting.

Readme

Keywords

none

Package Sidebar

Install

npm i knockoff

Weekly Downloads

3

Version

0.1.3

License

none

Last publish

Collaborators

  • gwicke