I decided that I've had it up the wazoo with typing (and looking at) "ognl:" all the time. Probably my least favorite things about Tapestry is the eye-bending verbosity of its template files -- the previewability is fantastic, but it comes at a *high* price in keystrokes and readability, IMO.

I have a new approach I'm somewhat happier with, and thought I'd share it so that everyone else can either try it out or decry my foolishness, as they see fit.

I added this to my hivemodule.xml:

        <contribution configuration-id="tapestry.bindings.BindingFactories">
<binding prefix="" service- id="tapestry.bindings.OGNLBindingFactory"/> <binding prefix="M" service- id="tapestry.bindings.MessageBindingFactory"/> <binding prefix="-" service- id="tapestry.bindings.LiteralBindingFactory"/> <binding prefix="A" service- id="tapestry.bindings.AssetBindingFactory"/> <binding prefix="B" service- id="tapestry.bindings.BeanBindingFactory"/> <binding prefix="L" service- id="tapestry.bindings.ListenerBindingFactory"/> <binding prefix="C" service- id="tapestry.bindings.ComponentBindingFactory"/> <binding prefix="S" service- id="tapestry.bindings.StateBindingFactory"/> <binding prefix="H" service- id="tapestry.bindings.HiveMindBindingFactory"/>
        </contribution>

This makes allows me to write ":value" instead of "ognl:value" ... which seems like a very small thing until you see how it cleans up template files! It also creates one-letter prefixes for all the other bindings. (Specific choices here are a matter of taste -- I like the caps so that I don't have to twiddle the shift key back and forth to type quote - prefix - colon, but one could easily change this.)

Unfortunately, Tapestry is one step ahead of me, and actually seems to intentionally to prevent what I'm doing. (Sorry, HLS, if you are gritting your teeth as you read this!) In BindingSourceImpl:

public IBinding createBinding(IComponent component, String bindingDescription,
            String reference, String defaultPrefix, Location location)
    {
    ...
        int colonx = reference.indexOf(':');

        if (colonx > 1)
        {
            String pathPrefix = reference.substring(0, colonx);
    ...

In other words binding prefixes are customizable, but they must be at least two characters.

Soooooo, I just overrode the default binding factory:

        <implementation service-id="tapestry.bindings.BindingSource">
          <invoke-factory>
            <construct class="InnigBindingSourceImpl">
<set-configuration property="contributions" configuration- id="tapestry.bindings.BindingFactories"/>
            </construct>
          </invoke-factory>
        </implementation>

public class InnigBindingSourceImpl
    implements BindingSource
    {
    private List<BindingPrefixContribution> contributions;
private Map<String,BindingFactory> factoriesByPrefix = new HashMap<String,BindingFactory>();

    public void initializeService()
        {
        for(BindingPrefixContribution c : contributions)
            factoriesByPrefix.put(c.getPrefix(), c.getFactory());
        }

public IBinding createBinding(IComponent component, String bindingDescription, String reference, String defaultPrefix, Location location)
        {
        String prefix = defaultPrefix;
        String path = reference;

        int colonx = reference.indexOf(':');
        if(colonx != -1)
            {
            String pathPrefix = reference.substring(0, colonx);

            if(factoriesByPrefix.containsKey(pathPrefix))
                {
                prefix = pathPrefix;
                path = reference.substring(colonx + 1);
                }
            else
                throw new ApplicationRuntimeException(
"Unknown binding prefix \"" + pathPrefix + "\" in expression \"" + reference + '"');
            }

return factoriesByPrefix.get(prefix).createBinding (component, bindingDescription, path, location);
        }

public void setContributions(List<BindingPrefixContribution> contributions)
        { this.contributions = contributions; }
    }

(Note that this code explicitly requires the use of "literal:" or "-:" if a binding contains a colon. This prevents me from having a literal accidentally turn into some other kind of binding in a future upgrade.)

Combined with this, I've abandoned the use of <span> as a generic "Tapestry-only" tag, and am now using <if> for @If, <for> for @For, and <x> for @Insert.

Before:
    <span jwcid="@For" source="ognl:articles" value="ognl:article">
        <li>
<a href="#" jwcid="@ExternalLink" page="ArticleView" parameters="ognl:article"> <span jwcid="@Insert" value="ognl:article.title">Article Title</span>
            </a>
        </li>
    </span>

After:
    <for jwcid="@For" source=":articles" value=":article">
        <li>
<a href="#" jwcid="@ExternalLink" page="ArticleView" parameters=":article"> <x jwcid="@Insert" value=":article.title">Article Title</x>
            </a>
        </li>
    </for>

It's still not as concise as Velocity or Rails's ERB, but it *is* still code-free (unlike ERB) and browser-previewable (unlike both). I'm definitely happier with it. I still don't like the redundancy of <for jwcid="@For">, and don't like the verbosity of the @Insert....

Cheers,

Paul

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to