UNPKG

toloframework

Version:

Javascript/HTML/CSS compiler for Firefox OS or nodewebkit apps using modules in the nodejs style.

196 lines (175 loc) 6.07 kB
/**************************************** Component x-template ``` <x-template mod="test.contact"> <fieldset> <legend $tpl="title">Contact</legend> <dl> <dt>Name:</dt> <dd> <input type="text" $tpl="name"> </dd> </dl> <dl> <dt>E-Mail:</dt> <dd> <input type="text" $tpl="email"> </dd> </dl> </fieldset> </x-template> ``` ****************************************/ exports.tags = ["x-template"]; /** * Compile a node of the HTML tree. */ exports.compile = function(root, libs) { // Name of the module created by this template. var name = root.attribs.name; if( typeof name === 'undefined' ) { libs.fatal("[x-template] Missing mandatory attribute `name`!"); } var componentName = getComponentName( name ); var output = "/****************************************\n" + libs.Tree.toString( root, ' ' ) + "\n****************************************/\n" + "require('x-template').register(" + JSON.stringify( name ) + ", function( root ) {\n" + " var $ = require( 'dom' );\n"; // Counter is used to name the children elements. var counter = {value: 1}; // Each time we find `$tpl="toto"`, we will add the element as a // value of the key `toto` of `ids`. var ids = {}; // Javascript code for template creation using the DOM. var code = parseChildren( libs, 'root', counter, root.children, ids ); output += code + getReturnCode( ids ) + "});\n"; //console.log( output ); libs.addInitJS( output ); libs.require( "x-template" ); root.type = libs.Tree.VOID; root.children = []; }; function getReturnCode( ids ) { var code = " return { "; var key, val, first = true; for( key in ids ) { val = ids[key]; if( first ) first = false; else code += ", "; code += JSON.stringify( key ) + ": " + val; } return code += " };\n"; } /** * @param parent {string} - name of the varible representing the parent to which append new elements. */ function parseChildren( libs, parent, counter, children, ids ) { var Tree = libs.Tree; var indent = ' '; var code = ''; children.forEach(function ( child ) { var name = counter.value == 0 ? 'root' : 'elem' + counter.value; // Use `prefix` instead of directly `code` bevause we want to // cancel var assignment in case of empty text nodes. var prefix = indent + "var " + name + " = "; switch( child.type ) { case Tree.TEXT: if( child.text.trim().length > 0 ) { prefix += "$.txt( " + JSON.stringify( child.text ) +" );\n"; } else { // Ignoring this child because it is an empty text node. return; } break; case Tree.TAG: if( child.name == 'div' ) { prefix += "$.div("; if( typeof child.attribs['class'] === 'string' ) { prefix += " " + JSON.stringify( child.attribs.class ) + " "; delete child.attribs.class; } prefix += ");\n"; } else if( child.name == 'x-widget' ) { libs.require( "x-widget" ); prefix += "require('x-widget').template(" + JSON.stringify( child.attribs ) + ");\n"; } else { prefix += "$.tag( " + JSON.stringify(child.name); if( typeof child.attribs['class'] === 'string' ) { prefix += ", " + JSON.stringify( child.attribs.class ); delete child.attribs.class; } prefix += " );\n"; } break; default: return; } code += prefix; counter.value++; // Attribute `$` is used to prepare code for object properties. child.$ = []; child.$name = name; // Deal with attributes. var hasAttribs = false; var attribs = {}; // Real HTML5 attributes. var key, val, keyNS; for( key in child.attribs || {} ) { val = child.attribs[key]; keyNS = parseNS( key ); if( keyNS.ns ) { // Spécial template attribute. child.$.push({ type: keyNS.ns, name: keyNS.id, prop: val }); } else { if( keyNS.id == '$tpl' ) { ids[val] = name; } else { hasAttribs = true; attribs[keyNS.id] = val; } } } if( hasAttribs && child.name != 'x-widget' ) { code += indent + "$.att( " + name + ", " + JSON.stringify( attribs ) + " );\n"; } if( parent ) { // Attach to the parent. code += indent + parent + ".appendChild( " + name + " );\n"; } // Look recursively for children. if( Array.isArray( child.children ) ) { code += parseChildren( libs, name, counter, child.children, ids ); } }); return code; } /** * Extract the namespace of a `name`. * @return * `parseNS( "toto" ) === { id: "toto" }` * `parseNS( "tpl-att:value" ) === { ns: "tpl-add", id: "value" }` * `parseNS( "zip:toto:bob" ) === { ns: "zip", id: "toto:bob" }` */ function parseNS( name ) { var i = name.indexOf( ":" ); if( i < 0 ) return { id: name }; return { ns: name.substr( 0, i ), id: name.substr( i + 1 ) }; } /** * Transform `toto-bob` into `TotoBob` and `wdg.input` into `Input`. */ function getComponentName( name ) { // If there are dots, take the string after the last dot. name = name.split( '.' ).pop(); return name.split( '-' ).map( function( item ) { return item.charAt( 0 ).toUpperCase() + item.substr( 1 ).toLowerCase(); }).join( '' ); }