Matt recently wrote in ASP.NET MVC HtmlHelper for Uploadify, Take One about a fairly common problem in the shades of gray where html and code concerns overlap. It’s a game of trying to get the least of both evils mixed in with the other.

Matt makes a particularly insightful remark in a comment, “what I dislike is how the balance of language in the helpers tends to shift from C# to JavaScript or HTML.”

I’d agree with that. On the one hand you’re trying to avoid excessive code in your template, but in doing so you’re dragging markup into your code. It’s actually a great example of a primary use-case for a macro in the Spark language, which lets you declare a helper method in the template language.

Here is the HtmlHelper extension exactly as it appeared on Matt’s post:

/// <summary>
/// Renders JavaScript to turn the specified file input control into an
/// Uploadify upload control.
/// </summary>
/// <param name="helper"></param>
/// <param name="name"></param>
/// <param name="options"></param>
/// <returns></returns>
public static string Uploadify(this HtmlHelper helper, string name, UploadifyOptions options)
{
    string scriptPath = helper.ResolveUrl("~/Content/jqueryPlugins/uploadify/");

    StringBuilder sb = new StringBuilder();
    //Include the JS file.
    sb.Append(helper.ScriptInclude("~/Content/jqueryPlugins/uploadify/jquery.uploadify.js"));
    sb.Append(helper.ScriptInclude("~/Content/jqueryPlugins/uploadify/jquery.uploadify.init.js"));

    //Dump the script to initialze Uploadify
    sb.AppendLine("<script type=\"text/javascript\">");
    sb.AppendLine("$(document).ready(function() {");
    sb.AppendFormat("initUploadify($('#{0}'),'{1}','{2}','{3}','{4}','{5}',{6},{7});",
                    name, options.UploadUrl,
                    scriptPath, options.FileExtensions,
                    options.FileDescription, options.AuthenticationToken,
                    options.ErrorFunction ?? "null",
                    options.CompleteFunction ?? "null");
    sb.AppendLine();
    sb.AppendLine("});");
    sb.AppendLine("</script");

    return sb.ToString();
}

And here’s the same helper implemented as a macro:

<macro name="Uploadify" name="string" options="UploadifyOptions">

  <var scriptPath="Html.ResolveUrl('~/Content/jqueryPlugins/uploadify/')"/>

  !{Html.ScriptInclude("~/Content/jqueryPlugins/uploadify/jquery.uploadify.js")}
  !{Html.ScriptInclude("~/Content/jqueryPlugins/uploadify/jquery.uploadify.init.js")}

  <script type="text/javascript">
    $(document).ready(function() {
      initUploadify($('#!{name}'), '!{options.UploadUrl}',
        '!{scriptPath}', '!{options.FileExtensions}',
        '!{options.FileDescription}', '!{options.AuthenticationToken}',
        !{options.ErrorFunction ?? "null"},
        !{options.CompleteFunction ?? "null"});
    });
  </script>

</macro>

The usage of the helper remains nearly identical. It’s a method on the view now instead of an Html extension method… So:

<%= Html.Uploadify("fileInput", new UploadifyOptions { ... }) %>

becomes:

<%= Uploadify("fileInput", new UploadifyOptions { ... }) %>

or rather:

!{Uploadify("fileInput", new UploadifyOptions { ... })}