My Web application is currently using Tapestry 5.2.6. I want to write a new feature with the following requirements:
- Users can click on items in a gallery to see a lightbox showing a detailed view, including description, comments, seller controls if they have the right credentials, and the ability to buy without leaving the page.
- The url should be updated to reflect whether they’re in gallery view or details view.
- URL changes should be dynamic in browsers that support HTML5 pushState. Full page refreshes are acceptable in older browsers.
- Both the gallery page and the details page must be crawlable – users without Javascript should see a fully marked up page.
- Speed – needs to be much faster than I know I can expect from Tapestry.
My plan is to choose and implement a template language that can evaluate equally well on the server or on the client. For the initial page load, I can render the template on the server. For subsequent updates, I can pass the item’s viewmodel object as JSON to the client and evaluate the template there.
So far so good. The problem is that none of the template languages I’ve looked at are powerful enough to feel good about moving toward for the future. As a case study, consider that out of the following:
- Mustache
- dust
- Hogan
- Handlebars
None seem to have the power to do a “wrapping” transformation like this:
# base template
{>widget}
<span class="content">Hello world</span>
{/widget}
# widget template
<div class="widget">
{>widget_body/}
</div>
# rendered output
<div class="widget">
<span class="content">Hello world</span>
</div>
Notice that the wrapped content is taken from the base template, and the output of the widget template surrounds it on both sides. The only way I know to achieve this in the above languages would be a template something like:
{>open_widget/}
{>widget_body/}
{>close_widget/}
Which means two templates for every component, an opener and a closer, both containing unclosed tags. (In fairness, dust can do this somewhat elegantly using blocks and inline partials, but because inline partials are global to the template, you’re limited to one use of the widget per template.)
My questions about templates are these:
- I know that industry leaders like LinkedIn and Twitter are using these technologies and doing great. Am I asking too much? If you’ve used one of them, how did you deal with the “wrapping problem”?
- A few solutions I’ve investigated do appear to support it: jquery-tmpl, which is no longer officially maintained; underscore and ejs, which make me nervous as a long term solution with their embedded code; and Closure templates. Currently Closure looks the best to me, to my surprise! If you’ve used any of these, what were your findings?
I’m not sure whether anything out there does what you’re talking about. I needed something similar and figured writing a simple text replacement script would be quicker than comparing existing solutions and learning to use one.
This script is not production ready (should be tested more, and the API is weird), but it should give you an idea of one way it can be done.
Here’s how it’s set up:
Storing templates in the document
The template text is stored in script tags with a
typeattribute other than “text/javascript”. Each template has a unique id attribute.Browsers should not render these. Any characters are allowed (except
</script>), and nothing needs to be escaped.Placeholders
Placeholders look like this:
{@some_identifier}.Each placeholder will be replaced with either:
Including one template in another
The
@@“pseudotag” includes the contents of another template in the current template.photo_templateincludesimage_template. All inclusion replacement happens before any placeholder replacement, sophoto_templatehas{@img_url}and{@caption}placeholders.Inclusion with placeholder replacement
This is where the “wrapping” comes from. Ideally, placeholders will almost always be replaced by content from other templates, rather than values passed in when getting a copy of the template.
missing_photo_templateincludesphoto_template, providing it with a replacement for{@img_url}, somissing_photo_templatehas only the{@caption}placeholder.JavaScript
The API sucks right now, but essentially the main namespace
athas two functions,txtandnode. The first one gets a copy of a template as text, the second one gets a copy as an Element (which means it should have one root node, unlike some of my examples above).Here it is:
Again, I’m not recommending you use this in production as it hasn’t been tested much (although it seems to work fine), but hopefully this will give you some ideas about how what you want can be accomplished.