zumbrunn.com

I love E4X

As a reality check of my proposal for skins in Helma 2, I so far came up with the following prototype. The idea seems to work quite nicely already with current builds of Helma 2. I thought E4X could make implementing these kinds of mocha objects very easy, but I was surprised that it really turned out that way in practice.

function handle_get() {
    // first prototype for the next incarnation of mocha objects
    
    // the render function, providing the magic
    var render = function(view) {
        // loop
        var toLoop = view...(@loop.toSource() != '<></>');
        for (var item in toLoop) {
            var dataName = toLoop[item].@loop.toString();
            delete toLoop[item].@loop;
            var data = eval(dataName);
            var stamp = toLoop[item].toString();
            for (var i in data) {
                var stencil = stamp.replace(
                    eval("/%% "+dataName+"\$\.(.+) %%/g"),
                    '{ '+dataName+'['+i+'].$1 }'
                );
                stencil = stencil.replace(
                    eval('/"'+dataName+'\$/g'),
                    '"'+dataName+'['+i+']'
                );
                stencil = stencil.replace(
                    eval('/"%% (.
)\$'+dataName+'(.) %%"/g'),
                    '{ $1'+i+'$2 }'
                );
                toLoop.parent().insertChildBefore(
                    toLoop[item],
                    eval(stencil)
                );
            }
            delete toLoop[item].parent().
[toLoop[item].childIndex()];
        }
       
        // lookup
        var toLookup = view...(@lookup.toSource() != '<></>');
        for (var item in toLookup) {
            delete toLookup[item].@lookup;
            var lookedup = '('+toLookup[item].children()[0]+')';
            toLookup[item].setChildren(lookedup);
        }
   
        // check
        var toCheck = view..
.(@check.toSource() != '<></>');
        for (var item in toCheck) {
            if (eval(toCheck[item].@check.toString()))
                delete toCheck[item].@check;
            else
                toCheck[item] = '';
        }
        return view;
    }
   
    // an example skin
    var myview = <table border="1">
        <tr check="topics">
            <th lookup="true">Topic Name</th>
            <th lookup="true">Comment Count</th>
        </tr>
        <tr loop="topics" class="%% 'rowcolor'+ ($topics % 2) %%">
            <td>%% topics$.name %%</td>
            <td check="topics$.count == 0" lookup="true">
                No comments yet</td>
            <td check="topics$.count == 1" lookup="true">
                %% topics$.count %% comment</td>
            <td check="topics$.count > 1" lookup="true">
                %% topics$.count %% comments</td>
        </tr>
        <tr check="!topics">
            <td colspan="2" align="center" lookup="true">
                This list is empty</td>
        </tr>
    </table>;
   
    // the example data
    var topics = [
        {name : 'Peter', count : 0},
        {name : 'Wolf', count : 2},
        {name : 'John', count : 1},
        {name : 'Andy', count : 8}
    ];
   
    // rendering the list
    var listtable = render(myview.copy());

    // rendering the empty table
    topics = null;
    var emptytable = render(myview.copy());
   
    // assembling the page
    var page = <html><body>{ listtable }<hr/>{ emptytable }</body></html>;
   
    // writing the page source to the reponse buffer
    res.contentType = "text/html";
    res.write(page.toSource());
}

Resulting in the following output:

</p><table border="1">

  <tbody><tr>

    <th>(Topic Name)</th>

    <th>(Comment Count)</th>

  </tr>

  <tr class="rowcolor0">

    <td>Peter</td>

    <td>(No comments yet)</td>

  </tr>

  <tr class="rowcolor1">

    <td>Wolf</td>

    <td>(2 comments)</td>

  </tr>

  <tr class="rowcolor0">

    <td>John</td>

    <td>(1 comment)</td>

  </tr>

  <tr class="rowcolor1">

    <td>Andy</td>

    <td>(8 comments)</td>

  </tr>

</tbody></table>

<hr />

<table border="1">

  <tbody><tr>

    <td align="center" colspan="2">(This list is empty)</td>

  </tr>

</tbody></table>



 19.12.2005, 10:28