In order to avoid some confusion as to how you can extend the template system in Scala, even though you will be using the templates from JavaScript, I'll quickly explain how Soy templates work when you're using JavaScript. Essentially, you precompile your .soy file into a .js file using a template compiler (which is written in Java). It's the compiler that you're extending and it's output is what you use in your web app. So you don't directly use the template from JavaScript.
What I wanted to do was something like this:
{switch typeof($msgparm)}
{case 'number'}
<i4>{$msgparm}</i4>
{case 'string'}
<string>{$msgparm}</string>
{/switch}
Unfortunatly, there is no typeof function "out of the box" so I needed to write my own in a plugin. As I was only interested in using this function in templates that I'm going to use in JavaScript, I needed to write a class that implements a single interface - SoyJsSrcFunction. If I wanted to use this function from Java, I'd need to implement SoyToFuFunction instead. There are only 3 methods to implement, 2 of which are one-liners in Scala. In this instance, all three are one liners, but computeForJsSrc could be more complicated, depending on what you're doing.
@Singleton
class TypeOfFunction @Inject() extends SoyJsSrcFunction {
def getName = "typeof"
def getValidArgsSizes: java.util.Set[Integer] = ImmutableSet.of[Integer](1);
def computeForJsSrc(args: java.util.List[JsExpr]): JsExpr = new JsExpr("typeof(" + args.get(0).getText() + ")", Integer.MAX_VALUE)
}
Scala Source Code
As you can probably tell, all this does is use JavaScript's typeof operator to implement the functionality I was looking for.
You might notice the @Singleton and @Inject annotations - Soy uses Google Guice for dependency injection. This means that we're not done yet - we also need to write a subclass of Guice's AbstractModule so that our extension can be injected into Soy. Fortunately it's trivial and XML-free:
class ExtendedFunctionsModule extends AbstractModule {
def configure() = {
val soyFunctionsSetBinder = Multibinder.newSetBinder(binder(), classOf[SoyFunction])
soyFunctionsSetBinder.addBinding().to(classOf[TypeOfFunction])
}
}
Scala Source Code
To use the extension all I need to do is add my Module class to the template compiler's pluginModules option:
java -cp typeof.jar:scala-library.jar:SoyToJsSrcCompiler.jar com.google.template.soy.SoyToJsSrcCompiler --pluginModules com.maethorechannen.widgets.ExtendedFunctionsModule --outputPathFormat rpc.js rpc.soy
1 comments:
So thats way i will implement this, I hope it will never let down.
Post a Comment