commentit


Create Natural Web-Page Layouts Effortlessly, With No More Redundant Markup Or Spooky Work-Arounds And Without Maintenance Nigtmares

Introduction

Revolutionize your web pages – easy, natural and
self-documenting. No more mind-numbing work-arounds. No more
redundant style-sheets and/or scripts in your page source code. No more
XML namespaces just to have your HTML markup validate. No more JSP Tags
(thank gawd!). Use HTML markup like it was intended to be used.
Really, it’s absolutely transparent.

And what else makes this solution absolutely indispensable?

  1. It works seamlessly with ANY existing expression-language
    framework, for instance MVEL, OGNL, JEXL, String-Template etc. You pick what you want and run with it.
  2. You can visually test your pages in your favorite browser, without a
    web-server. You can put all your style-sheets and scripts on the
    static page, then when you are satisfied with the result, you
    simply “commentit”, and the page will be ready for production.
  3. It captures the essence of fast page-loading by providing the
    leanest page possible and a place-holder for “body” scripts,
    which should execute after the page is loaded and rendered.
  4. The page output lends itself easily to compression and
    g-zipping. The solution does not attempt in any way to
    manipulate the response however. It assumes you should be able
    to manipulate the appropriate response headers yourself.
  5. You can optionally apply the BundleFilter which ships with the library to bundle up (put in one file) all your stylesheets and javascript, and in addition compress (g-zip) your output if the filter detects that the client browser supports g-zip.
  6. Perfect replacement for Sitemesh and Tiles if you are NOT working with JSPs

Ok, so how do you do this? The solution is to make use
of markup comments to describe the structure of your page.
That’s it!!

Breaking It Down

At the end of the day, whatever solution you use to structure or lay-out your
page, the browser sees your page as one input-stream and it
renders this stream progressively from top to bottom. This is the
same concept used by the “commentit” solution – build your page
output progressively from top to bottom.

”CommentIt” introduces some five very simple concepts (definitions) that
capture the general structure of a web-page.

  1. A Page – a page is the file which is targeted for decoration using a specified
    “layout” file. The page may within itself contain
    “widgets” and/or “snippets”.
  2. A Widget – A widget is a self-contained markup file. It has it's own js and css. It can be reused across different pages and also on different projects. For this last reason, widgets definitions are ideal candidates for storing in a database table and having the parser resolve which one to use during runtime
  3. A Snippet – A snipppet is basically the same as a widget. However, it may or may not have it's own js and css. For this reason, snippets are ideal candidates for reuse in different pages within a single project. Using a snippet on a different project would more likely than not, require changes to its css and/or js
  4. A Layout – this is the markup which decorates a page, and
    determines to a large extent the look and feel of the website. The layout contains place-holders for different
    parts of the page which are resolved and inserted dynamically.
  5. Static Removable – this is markup on your definitions which is used
    ONLY while statically testing your page in your browser. This
    markup is STRIPPED OFF when the page template is being created.

Complete Example

samples/layout.html

``` Hello Footer ```

samples/widget.html

``` First Widget Widget (1) content ```

samples/snippet.html

``` Testing Snippet Snippet (1) content ```

samples/page.html

``` Sample Page

Page (1) content

Everything inside this definition will be stripped of in the final generated page Some markup that is outside the definition for the page - won't be included in the final generated page ```

assembled page output

``` Final Page Title Widget (1) content

Page (1) content

Widget (1) content Snippet (1) content Hello Footer ```

The first thing that strikes you is how each definition is a full-blown
(natural) HTML page – you can test it statically in your browser without a web-server.

The second thing is how each definition is self-documenting. You
can literally tell how the final generated page will look like
just by reading through the comments.

A third striking thing is how the assembled page is WITHOUT ANY redundancy. There is NOT a single character in that page that was not intended to be in it. It's clean and lean!

Let’s eye-ball each of the definitions a bit more closely now:

Layout.html

To define a file as a layout, there is nothing special to it. It is referenced through the page definition. It can contain the following five exclusive tags in it,
which are populated dynamically:

  1. <!-- c:put(title) -->
    : place-holder for a
    title value which is provided in Page.html
  2. <!-- c:put(styles) -->
    : place-holder for
    style-sheets. These are declared in a page, the snippets and the
    widgets.
  3. <!-- c:put(scripts) -->
    : place-holder for
    “head” scripts. These are declared in a page, the snippets and
    the widgets.
  4. <!-- c:put(page) -->
    : place-holder for
    the generated page
  5. <!-- c:put(bscripts) -->
    : place-holder
    for “body” scripts. These are declared in a page, the snippets
    and the widgets.

The layout page may also contain placeholder for inserting widgets or snippets

Widget.html

To define a file as a widget, you need to wrap the content inside
the tags below:


<!-- c:def(type=”widget”) -->
YOUR_WIDGET_MARKUP
<!-- c:end -->

Other permissible attributes of the widget definition are:

  1. base: indicates the base directory to load all
    style-sheets and scripts declared on the current page, relative
    to the page itself. For dynamic web apps, what I recommend is making the value of "servletContext.getContextPath()" available as a variable, say 'root' in your templating code, and then passing this through the 'base' attribute, which would look something close to 'base=@{root}/'
  2. styles: declares all the style-sheets this page
    would require to style itself. If more than one, the file paths
    are separated using a semi-colon “;”.These styles will be
    inserted in the
    <head>

    Unknown end tag for </head>

    section of the layout page,
    where there is a corresponding
    <!--c:put(styles) -->
    place-holder.
  3. scripts: declares all the java-script files this
    page would require to manipulate itself before the page renders.
    If more than one, the file paths are separated using a
    semi-colon “;”.These scripts will be inserted in the
    <head>

    Unknown end tag for </head>

    section of the layout page, where there is a
    corresponding
    <!--c:put(scripts) -->
    place-holder.
  4. bscripts: declares all the java-script files
    this page would require to manipulate itself after the page
    renders. If more than one, the file paths are separated using a
    semi-colon “;”.These scripts will be inserted in the
    <body>

    Unknown end tag for </body>

    section of the layout page, where
    there is a corresponding
    <!--c:put(bscripts) -->
    place-holder.

To insert a widget into a file by resolving from the specified url:

<!-- c:ins(widget(url=file_name)) --> 

To insert a widget into a file by resolving from the widgetsContext: (ver 1.1.1)

<!-- c:ins(widget(res=file_name)) --> 

Snippet.html

To define a file as a snippet, you need to wrap the content inside
the tags as shown below:


<!-- c:def(type=”snippet”) -->
YOUR_SNIPPET_MARKUP
<!-- c:end -->

Other admissible attributes of the snippet definition are exactly
the same as those of a widget.

To insert a snippet into a file, by resolving from the specified url:

<!-- c:ins(snippet(url=file_name)) --> 

There is no concept of a snippets context, unlike widgets

Page.html

To define a file as a page, you need to wrap the content inside the
tags as shown below:


<!-- c:def(type=”page”) -->
YOUR_PAGE_MARKUP
<!-- c:end -->

Other admissible attributes of the page definition are:

  1. title: this is the page title in the browser. It
    will be inserted in the
    <head>

    Unknown end tag for </head>

    section of the
    layout page where there is a corresponding
    <!--c:put(title)-->
    place-holder.
  2. layout: this indicates the layout page which
    should contain the current page. The entire content of this page
    will be inserted in the
    <body>

    Unknown end tag for </body>

    section of the
    layout page where there is a corresponding
    <!--c:put(page)-->
    place-holder.

The remaining admissible attributes of the page definition are
exactly the same as those of the WIDGET/SNIPPET.

Removable Section

This is not a file like the rest of the definitions. It’s instead a
section of the page which will show up in the browser when viewing
the page statically (without a web-server), but will be stripped off
in the final dynamic page (with a web-server).

A removable section can be declared inside of LAYOUT, WIDGET, PAGE
or SNIPPET. To define a removable section inside any definition
described aobve, you need to wrap the content inside the tags as
shown below:


<!-- c:rem -->
YOUR_REMOVABLE_MARKUP
<!-- c:end -->

And finally...

And that is really it! Whip out your favorite IDE and start
test-driving this solution. Look at the Wiki section for the Integration (http://code.google.com/p/commentit/wiki/Integration) article to start using commentit. Tell me if you don’t love it!

Note (only with version 1.1.1 and below)

  1. You should pay attention to ensure that each definition has
    the first 10 characters written out correctly:

Features Updates

Version 1.1 adds two cool features;

  1. The parser will automatically cache any page file it parses and uses the cached version on subsequent requests. This is the default mode. You can however set the development = true parameter in the servlet context to bypass this behavior

        <context-param>
    
    <param-name>development</param-name>
    <param-value>[TRUE|FALSE]</param-value>
    </context-param>
  2. The parser can now load up files outside of the web app folder. To do this you would have to add a parameter named "fs_templates_dir" in the servlet context and have that point to your desired location.

        <context-param>
    
    <param-name>fs_templates_dir</param-name>
    <param-value>[YOUR LOCATION]</param-value>
    </context-param>
  3. Version 1.1.1 add the ability to resolve widgets from a widgetsContext. The widgetsContext is simply a map of database records. It is able to map a specified key to url location, as stores in the database. This adds enormous potential to a widget, and it enalbes a widget to be reusable across different project

    public TemplateParser(ServletContext servletContext, Map<String, String> widgetsContext) {
    
    this(servletContext);
    this.widgetsContext = widgetsContext;
    }
  4. Version 1.1.2 is a complete re-write, based on improvements borrowed from a python POC for the same library. Look at the new features update here

Stay tuned for more feature updates...

Project Information

The project was created on Aug 25, 2012.

Labels:
Java Web HTML Layout Template Design Sitemesh Tiles Webapp Python