npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

idom-template

v1.1.3

Published

Library for converting templates into Incremental DOM rendering functions

Downloads

63

Readme

idom-template

Now you can speed up and optimize your application, which once used standard templates by incremental DOM. You may read more about it here.

Library for converting your HTML or templates (ejs/underscore templates or like) into incremental-DOM by Google rendering functions.

You can use this library with any framework with you want.

New functionality is available. The documentation going to be updated, but now, see Tests.

###Example The simplest example of use looks like this, html:

<div id="container"></div>
<script type="x-template" id="underscore-template">
    <div> <%- data.listTitle %></div>
    <ul>
        <%  var showFootnote = false;
            data.listItems.forEach(function(listItem, i) {
        %>
        <li class="row <%=(i % 2 == 1 ? ' even' : '')%>">
            <%- listItem.name %>
            <% if (listItem.hasOlympicGold){
            showFootnote = true; %>
            <em>*</em>
            <% } %>
        </li>
        <%  }); %>
    </ul>

    <% if (showFootnote){ %>
    <p style="font-size: 12px ;">
        <em>* Olympic gold medalist</em>
    </p>
    <% } %>
</script>

javascript:

var templateData = {
    listTitle: "Olympic Volleyball Players",
    listItems: [
        {
            name: "Misty May-Treanor",
            hasOlympicGold: true
        },
        {
            name: "Kerri Walsh Jennings",
            hasOlympicGold: true
        },
        {
            name: "Jennifer Kessy",
            hasOlympicGold: false
        },
        {
            name: "April Ross",
            hasOlympicGold: false
        }
    ]
};

var templateStr = document.getElementById('underscore-template').innerHTML;
var renderFn = itemplate.compile(templateStr, IncrementalDOM);

IncrementalDOM.patch(document.querySelector('#container'), renderFn, templateData);

In this case your template will be compiled by idom-template into the following JS function:

function (data) {
    var o = lib.elementOpen, c = lib.elementClose, t = lib.text, v = lib.elementVoid;
    o('div');
    t(data.listTitle);
    c('div');
    o('ul');
    var showFootnote = false;
    data.listItems.forEach(function (listItem, i) {
        o('li', null, null, 'class', 'row ' + (i % 2 == 1 ? ' even' : ''));
        t(listItem.name);
        if (listItem.hasOlympicGold) {
            showFootnote = true;
            o('em');
            t('*');
            c('em');
        }
        c('li');
    });
    c('ul');
    if (showFootnote) {
        o('p', null, null, 'style', 'font-size: 12px ;');
        o('em');
        t('* Olympic gold medalist');
        c('em');
        c('p');
    }
}

Take note that the dependencies: lib(incremental-dom library) и helpers are ejected with closure. The same closure contains the creation of static arrays, when you use them for the array of static attributes.

As opposed to underscore.js, compilation of comments does not take place!

This one and more complicated examples can be viewed in the directory examples.

You may also compare the performance of BackboneJS, BackboneJS + incremental-dom, ReactJS 0.13.3: DEMO

npm

More over then include library directly, You also can use npm for installation:

npm install idom-template --save

Include

    <script src="../lib/incremental-dom.js"></script>
    <script src="../lib/itemplate.js"></script>

Use

var templateStr = document.getElementById('underscore-template').innerHTML;
var renderFn = itemplate.compile(templateStr, IncrementalDOM);

patch(containerElement, renderFn, templateData);

You should consider the following issues:

  • You should be careful with the ' symbol in templates; if it's mentioned in the text, it should be screened as \'. This will be fixed in further versions.
  • The data is transferred to the template as one object; so if you don't want to transfer data via closure in templates, you should work with one object that will be transferred as a parameter to path.

####unwrap Be careful, if the second parameter is absent during the compilation of the template, which means you won't transmit the link to the library:

var renderFn = itemplate.compile(templateStr[, IncrementalDOM]);

In this case it's not a rendering function that will be compiled, it will be just a function without closure and wrapping:

function (data, lib, helpers){
        // throw error or something if not lib and helpers
        var o=lib.elementOpen,c=lib.elementClose,t=lib.text,v=lib.elementVoid;
        o('div', null, null, 'class', 'box');
            t( data.content );
        c('div');
        helpers['my-console']({data:7+8});
}

In this case you should call it and transmit compilation parameters as follows:

patch(document.getElementById('container'), function () {
    template(data, IncrementalDOM, customHelpers);
});

It allows to work with templates with more flexibility; for example, call several templates in one rendering function, or introduce additional logic, such as filtration etc.

###Options You may set compiling option as object to the library:

itemplate.options({
	//...
});

Where:

  • parameterName - name of the data object, which is transferred to the render function.
  • template (interpolate, escape, evaluate) - regular expression of your templates; you may change them, so that the compiler will process your template syntax.

Take note that compilation is carried out in the following order: interpolate, escape, evaluate. In further versions we plan to provide an opportunity of changing the sequence of template processing.

  • escape, MAP - regular expression and MAP for processing the html escaping expression.

  • accessory (open, close) - service lines for processing interpolate, escape templates; it's better not to modify them.

  • staticKey - attribute name for static attributes array generation in current tag. See static attributes.

By default the options have the following values:

 {
    BREAK_LINE: /(\r\n|\n|\r)\s{0,}/gm,
    // prepare options
    template: {
        evaluate: /<%([\s\S]+?)%>/g,
        interpolate: /<%=([\s\S]+?)%>/g,
        escape: /<%-([\s\S]+?)%>/g
    },
    order: ['interpolate', 'escape', 'evaluate'],
    evaluate: {
        name: 'script',
        open: '<script>',
        close: '</script>'
    },
    accessory: {
        open: '{%',
        close: '%}'
    },
    escape: /(&amp;|&lt;|&gt;|&quot;)/g,
    MAP: {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"'
    },
    // build options
    emptyString: true,
    staticKey: 'key',
    staticArray: 'static-array',
    nonStaticAttributes: ['id', 'name'],
    parameterName: 'data',
    parentParameterName: 'parent',
    renderContentFnName: 'content',
    // tags parse rules
    textSaveTags: ['pre', 'code'],
    voidRequireTags: ['input', 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'keygen', 'link', 'meta',
        'param', 'source', 'track', 'wbr'],
    debug: false
}

You may modify any option.

###Static attributes Arrays of static attributes are used to save memory.

For generation of a static array, you should select the static-array attribute from element attriibutes and add it to the template tag.

The value of this attribute will become the name of the static array:

  • in case the value is not specified, the array will be generated, and its name will be a unique generated line.
  • in case different tags contain the same name of the static array, the same array will be used for all of these elements. This generated array will be based on all static attributes of the last tag with this key in the template.
  • the name of the attribute can be changed in options.

Example

If you compile the function of the following template:

    <div class="box" key="box_class" data-key="my-custom-key"
         style="top: <%= data.top %>px; left: <%= data.left %>px; background: rgb(0,0,<%= data.color %>);">
        <%= data.content %>
    </div>

You will get the result:

(function (lib, helpers) {
    var box_class = ['class', 'box', 'data-key', 'my-custom-key'];
    return function (data) {
        var o = lib.elementOpen, c = lib.elementClose, t = lib.text, v = lib.elementVoid;
        o('div', 'ZYjoAthjdzUz', box_class, 'style', 'top: ' + data.top + 'px; left: ' + data.left + 'px; background: rgb(0,0,' + data.color + ');');
        t(data.content);
        c('div');
    }
})(IncrementalDOM, {
    // ... helpers object
});

It's important to understand that arrays of static attributes are unqiue for every template. If you use the same key name in different templates, there will be different arrays with different values.

Take note that:

  • if you use an array of static attributes, a key for this element will be generated automatically.

###Helpers There is an option of injecting JS functions as a part of the compiled template.

For that purpose we use self-closing tag (with /). All attributes of this tag will be moved to the JS function as a data object with keys, which are attributes of the tag.

That is, upon registering the following helper:

itemplate.registerHelper('my-console', function (attrs) {
    console.log(attrs);
});

...where the first parameter is the helper name, and the second one is the JS function.

In this case, in order to call the helper it will suffice to indicate the tag is your template:

<!-- ... -->
<my-console id="console_1" data="<%=7+8%>"/>
<!-- ... -->

Every time the template is rendered, the registered function will be executed in the place where the given tag is inserted. This is what will be in the console:

{id: 'console_1', data: 15}

This option can be used in the following ways:

Insertion of templates:

You may register any rendering function of incremental DOM as a helper. In this case external templates will be inserted into the rendering function.

For example, having registered the following template as a helper:

 var footnoteRenderFn = itemplate.compile(footnoteTemplate, IncrementalDOM);
 itemplate.registerHelper('my-footnote', footnoteRenderFn);

You will be able to simply insert it in another template in the following way .ejs:

<my-footnote listItems="<%=data.listItems%>"/>

Auxiliary logic of templates:

It's similarly possible to describe synchronous auxiliary logic using helpers.

var itemRenderFn = itemplate.compile(itemTemplate, IncrementalDOM);
itemplate.registerHelper('my-list', function (attrs) {
    elementOpen('ul');
    _.each(attrs.listItems, function (listItem, i) {
        // render single list item
        itemRenderFn({
            i: i,
            name: listItem.name,
            hasOlympicGold: listItem.hasOlympicGold
        });
    });
    elementClose('ul');
});

The following line in your template will be responsible for full rendering of the .ejs list:

<my-list listItems="<%=data.listItems%>"/>

Examples of use of helpers can be viewed in the directory examples

Please consider:

  • data in helpers can be transmitted only via tag attributes. For example, the internal template will have access only to the data received via attributes.
  • helpers are not web-components, so they work only if you have registered helper beforehand, and then compiled the template that uses it.