Very cool use of macro and _global.spark
opensource, programming, spark, tech October 2nd, 2008Here’s an example Artem Tikhomirov posted on the discussion group of using macros and a few service globals to create a nice little ability to easily register items in the html <head> without duplication. I thought it was remarkable how it demonstrates several different features of the language, and is also a very practical application that boils down to the ability to add stylesheets with a statement as small as ${css("jQuery/clockpick.1.2.4", "jQuery/datepicker/ui.datepicker")}.
From: “Артём Тихомиров”
Subject: Re: [Spark View Engine] #74: Add an attribute to declare a “just once” flagI’ve ended up with following solution.
In Shared/_global.spark:
<!-- Service globals - do not use directly -->
<global __CssReferences="new OrderedSet[[string]]()" type="ISet[[string]]"/>
<global __JsReferences="new OrderedSet[[string]]()" type="ISet[[string]]"/>
<global __OnReadyStatements="new List[[string]]()" type="IList[[string]]"/>
<!-- End of service globals declaration -->
<macro name="WriteJsReferencesDown">
<for each="var fileName in __JsReferences">
<script type="text/javascript" src="~/Content/${fileName}.js"></script>
</for>
</macro>
<macro name="WriteCssReferencesDown">
<for each="var file in __CssReferences">
<link rel="stylesheet" type="text/css"
href="~/Content/${file}.css"/>
</for>
</macro>
<macro name="WriteOnReadyStatements">
<script type="text/javascript" if="__OnReadyStatements.Count > 0">
jQuery(document).ready(
function() {
<for each="var statement in __OnReadyStatements">
${statement}
</for>
}
);
</script>
</macro>
<macro name="css" files="params string[]">
<for each="var file in files">
# __CssReferences.Add(file);
</for>
</macro>
<macro name="jQuery" additionalFiles="params string[]">
# __JsReferences.Add("jQuery/jquery-1.2.6.min");
<for each="var file in additionalFiles">
# __JsReferences.Add("jQuery/" + file);
</for>
</macro>
<macro name="js" additionalFiles="params string[]">
<for each="var file in additionalFiles">
# __JsReferences.Add(file);
</for>
</macro>
<macro name="onReady" jsText="string">
# if(!System.String.IsNullOrEmpty(jsText.Trim()))
# __OnReadyStatements.Add(jsText);
</macro>
In Shared/Application.spark:
<html>
<head>
<title></title>
<use content="pageHead" />
${WriteCssReferencesDown()}
${WriteJsReferencesDown()}
${WriteOnReadyStatements()}
</head>
<body>
</body>
</html>
In any *.spark file using default master-layout:
${css("jQuery/clockpick.1.2.4", "jQuery/datepicker/ui.datepicker")}
${jQuery("jquery-ui-1.6b.min", "i18n/ui.datepicker-ru", "jquery.clockpick.1.2.4.min")}
April 29th, 2009 at 9:58 pm
[...] working on a project right now, and I used a slightly modified version of the clever trick Lou posted from Artem Tikhomirov about using _global.spark and some macros to create a simple system for [...]
April 29th, 2009 at 10:02 pm
So I’ve implemented this on a personal project, and it works great. I modified it a bit, because I didn’t need all of the functionality, and added some of my own. However, I ran into a problem!
I have some partial views that I want to render on the client-side using the RenderView method that comes from a JavascriptViewResult. However, when I try and run that JavaScript, it comes with JavaScript-ified versions of the macros and variables in this chunk of code from _global.spark, which breaks the JavaScript, since it can’t understand generics and such.
Is there a way to force _global.spark to be not included in this output? For now, I’ve moved this to a separate file that I am including in application.spark, but I’d like a better solution.
I wrote about this at my blog, and I’ll update it if I find a good solution:
http://bcherry.net/archives/60