(Nth) Alternative syntax proposal for FreeMarker
Denis <[email protected]>
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
This has been raised several times already, especially from people
coming from Velocity-land... The FreeMarker syntax is quite heavy.
Now we can use square brackets which help when working with XML/HTML
templates but there is still room for improvement.
My suggestion is quite simple, but it may require a new parser.
Comparison:
Directive without a body
--------------------------------
=FreeMarker classic=
Opening: <#directive
Closing: />
=FreeMarker 'light'=
Opening: ##directive
Closing: end of line
Directive with a body
----------------------------
=FreeMarker classic=
Opening: <#directive parameters>
Closing: <#/directive> (short form: <#/>)
=FreeMarker 'light'=
Opening: ##directive parameters
Closing: ##/directive (short form: ##/)
Macro call without a body
----------------------------------
=FreeMarker classic=
Opening: <@macroname
Closing: />
=FreeMarker 'light'=
Opening: @@macroname
Closing: end of line
Macro call with a body
------------------------------
=FreeMarker classic=
Opening: <@macroname parameters>
Closing: </@macroname> (short form: <@/>)
=FreeMarker 'light'=
Opening: ##@macroname parameters
Closing: ##/@macroname (short form: ##/)
Single-line comment
----------------------------
=FreeMarker classic=
Opening: <#-- comment
Closing: -->
=FreeMarker 'light'=
Opening: ##-- comment
Closing: end of line
Multi-line comment
--------------------------
=FreeMarker classic=
Opening: <#--
Closing: -->
=FreeMarker 'light'=
Opening: ##--
Closing: ##/-- (short form: ##/)
I chose double characters to minimize clashes with the rendered
document. Escaping is done by trippling the double character, ie. ###
renders as ## and @@@ renders as @@. Using single characters would
require a different escaping rule.
To put more than one directive in a line, enclose in brackets eg. ##
(if n > 5)##(-- display in long form)@@(showLongList items)##(else)@@
(showList items)##/
I tried it on a few templates and I think the result is quite pleasing.
Now a real-world example (borrowed from http://www.devdaily.com/java/
jwarehouse/spring-framework-2.5.3/dist/resources/spring.ftl.shtml)
Original
-----------
<#--
* formCheckboxes
*
* Show checkboxes.
*
* @param path the name of the field to bind to
* @param options a map (value=label) of all the available options
* @param separator the html tag or other character list that should
be used to
* separate each option. Typically ' ' or '<br>'
* @param attributes any additional attributes for the element (such
as class
* or CSS styles or size
-->
<#macro formCheckboxes path options separator attributes="">
<@bind path/>
<#list options?keys as value>
<#assign id="${status.expression}${value_index}">
<#assign isSelected = contains(status.value?default([""]),
value)>
<input type="checkbox" id="${id}" name="${status.expression}"
value="${value?html}"<#if isSelected> checked="checked"<#/if> $
{attributes}<@closeTag/>
<label for="${id}">${options[value]?html}${separator}
</#list>
<input type="hidden" name="_${status.expression}" value="on"/>
</#macro>
<#--
* showErrors
*
* Show validation errors for the currently bound field, with
* optional style attributes.
*
* @param separator the html tag or other character list that should
be used to
* separate each option. Typically '<br>'.
* @param classOrStyle either the name of a CSS class element (which
is defined in
* the template or an external CSS file) or an inline style. If
the value passed in here
* contains a colon (:) then a 'style=' attribute will be used,
else a 'class=' attribute
* will be used.
-->
<#macro showErrors separator classOrStyle="">
<#list status.errorMessages as error>
<#if classOrStyle == "">
<b>${error}
<#else>
<#if classOrStyle?index_of(":") == -1><#assign
attr="class"><#else><#assign attr="style"></#if>
<span ${attr}="${classOrStyle}">${error}
</#if>
<#if error_has_next>${separator}
</#list>
</#macro>
<#--
* checkSelected
*
* Check a value in a list to see if it is the currently selected
value.
* If so, add the 'selected="selected"' text to the output.
* Handles values of numeric and string types.
* This function is used internally but can be accessed by user code
if required.
*
* @param value the current value in a list iteration
-->
<#macro checkSelected value>
<#if stringStatusValue?is_number && stringStatusValue == value?
number>selected="selected"</#if>
<#if stringStatusValue?is_string && stringStatusValue ==
value>selected="selected"</#if>
</#macro>
<#--
* closeTag
*
* Simple macro to close an HTML tag that has no body with '>' or '/>',
* depending on the value of a 'xhtmlCompliant' variable in the
namespace
* of this library.
-->
<#macro closeTag>
<#if xhtmlCompliant?exists && xhtmlCompliant>/><#else>></#if>
</#macro>
'Light' version
------------------
##--
* formCheckboxes
*
* Show checkboxes.
*
* @param path the name of the field to bind to
* @param options a map (value=label) of all the available options
* @param separator the html tag or other character list that should
be used to
* separate each option. Typically ' ' or '<br>'
* @param attributes any additional attributes for the element (such
as class
* or CSS styles or size
##/
##macro formCheckboxes path options separator attributes=""
@@bind path
##list options?keys as value
##assign id="${status.expression}${value_index}"
##assign isSelected = contains(status.value?default([""]),
value)
<input type="checkbox" id="${id}" name="$
{status.expression}" value="${value?html}"##(if isSelected)
checked="checked"##(/if) ${attributes}@@closeTag
<label for="${id}">${options[value]?html}${separator}
##/list
<input type="hidden" name="_${status.expression}" value="on"/>
##/macro
##--
* showErrors
*
* Show validation errors for the currently bound field, with
* optional style attributes.
*
* @param separator the html tag or other character list that should
be used to
* separate each option. Typically '<br>'.
* @param classOrStyle either the name of a CSS class element (which
is defined in
* the template or an external CSS file) or an inline style. If
the value passed in here
* contains a colon (:) then a 'style=' attribute will be used,
else a 'class=' attribute
* will be used.
##/
##macro showErrors separator classOrStyle=""
##list status.errorMessages as error
##if classOrStyle == ""
<b>${error}
##else
##(if classOrStyle?index_of(":") == -1)##(assign
attr="class")##(else)##(assign attr="style")##/
<span ${attr}="${classOrStyle}">${error}
##/if
##(if error_has_next)${separator}##/
##/list
##/macro
##--
* checkSelected
*
* Check a value in a list to see if it is the currently selected
value.
* If so, add the 'selected="selected"' text to the output.
* Handles values of numeric and string types.
* This function is used internally but can be accessed by user code
if required.
*
* @param value the current value in a list iteration
##/
##macro checkSelected value
##(if stringStatusValue?is_number && stringStatusValue == value?
number)selected="selected"##/
##(if stringStatusValue?is_string && stringStatusValue == value)
selected="selected"##/
##/macro
##--
* closeTag
*
* Simple macro to close an HTML tag that has no body with '>' or '/>',
* depending on the value of a 'xhtmlCompliant' variable in the
namespace
* of this library.
##/
##macro closeTag
##(if xhtmlCompliant?exists && xhtmlCompliant)/>##(else)>##/
##/macro
For reference, the first macro in case FreeMarker 'light' uses single
characters would look like:
#macro formCheckboxes path options separator attributes=""
@bind path
#list options?keys as value
#assign id="${status.expression}${value_index}"
#assign isSelected = contains(status.value?default([""]),
value)
<input type="checkbox" id="${id}" name="$
{status.expression}" value="${value?html}"#(if isSelected)
checked="checked"#(/if) ${attributes}@closeTag
<label for="${id}">${options[value]?html}${separator}
#/list
<input type="hidden" name="_${status.expression}" value="on"/>
#/macro
What do you think?
-- Denis.
-------------------------------------------------------------------------
Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW!
Studies have shown that voting for your favorite open source project,
along with a healthy diet, reduces your potential for chronic lameness
and boredom. Vote Now at http://www.sourceforge.net/community/cca08