Have I just not found it? It seems a pretty basic, fundamental, and
important feature. And I have not yet found any built-in support in
HTML::Mason for constructing a link (as in <a href=...)
from one Mason component to another where that link includes arguments.
That is, other than a quite awkward construction like:
<a href="/path/to/component?who=<% $who |u %>;why=<% $why |u %>">
Title goes here</a>
Having to remember to include "|u" for each parameter makes that nearly
unacceptable in my book (after seeing way too many bugs from lack of URL
escaping that pass unnoticed for a long time and then turn into a crisis,
even a security problem). It also gets quite tedious (and error-prone
and hard to read) when producing a table full of similar links.
But to see how awkward that really can be, imagine what I find to be a common
case: Having a hash of arguments that you want to include in the link. Am I
really supposed to roll my own URL constructor for such an obvious case?
<& .link, 'Edit Settings', '/widget/settings', %Context &>
...
<%def .link>
% my( $title, $page, %args ) = @_;
<a href="<% $page %>?
% for my $key ( sort keys %args ) {
<% $key |u %>=<% $args{$key} |u %>;
% }
"><% $title |h %></a>
</%def>
Although that first line is a reasonable interface, the implementation, of
course, doesn't actually work, producing:
<a href="/widget/settings?
acct=some_acct%23id;
widget=widget%2Bid;
">Edit Settings</a>
Is there a better (and actually correct) way to write such in Mason?
Too bad defining a "removing newlines and adjacent whitespace" Mason filter
(call it "|w") doesn't allow me to address this problem as simply as:
<& .link, 'Edit Settings', '/widget/settings', %Context |w &>
(You can use "|w" inside of <% ... %> but not inside of
<& ... &>.)
So, (at least for now) I resign myself to looking outside of Mason for a
solution.
So, I roll these pieces together and get:
And try to use that in my Mason:
Note the gyrations to prevent .link from including newlines.
Okay, that is quite a bit uglier than I had hoped for. But it actually works.
But it quickly demonstrated how it wasn't very flexible when I tried to use
it in a page that uses JavaScript to generate a list of links client-side
(also changing it to not take a hash of parameters but instead just a
comma-separated list of key names used to look up the parameter names and
values that are ever used from this page):
<& .link, "Edit $widget_name Settings", 'settings', 'acct,widg' &>
...
<script type="text/javascript">
...
+ '<& .link, "Edit {{feature_name}}", 'edit', 'acct,widg,feat'
+ &>'
Where the new .link replaces the ',feat' with
feature_id => '{{feature_id}}' and the JavaScript replaces
'{{feature_name}}' and '{{feature_id}}' with values
that vary between rows (one row generated per feature).
There is a risk that the second call to .link above would include something
(a ', a \, or a newline) that wouldn't be legal inside of a JavaScript string.
That sounds like a job for a Mason filter. I could define "|l" to strip
newlines (a common desire when using Mason, it seems) and "|sq" to escape
those problem characters.
Oh, except, as we already mentioned, you can't use something like "|sq"
with <& ... &>.
I could define .sq that escapes the string passed to it. Ooh, I just found
this syntax:
+ '<&| .sq &><& .link, ... &></&>'
That actually addresses (if in a manner still uglier than I had hoped)
some of the questions I had when I started writing this.
What other features am I missing? How can I do this better?
|