Back to Table of Contents

Templating for HTML and Javascript

Happstack supports a number of third party templating and HTML libraries. It is easy to add support for additional libraries, if your favorite does not already have support.

Each templating system has it's own set of advantages and drawbacks.

BlazeHtml

The BlazeHtml library provides combinators for generating HTML 4 and HTML 5 in Haskell.

pros:

cons:

HSP

HSP allows you to embed literal XML syntax inside your Haskell code. A pre-processor rewrites the literal XML into normal haskell function calls, and then the code is compiled.

pros:

cons:

Hamlet
HStringTemplate
Heist
XSLT
more to come..

Using BlazeHtml

It is trivial to use BlazeHtml with Happstack. Essentially you just use toResponse to convert a blaze Html value into a Response. For more detailed information on using BlazeHtml, see the BlazeHtml website. The following example should get you started:

> {-# LANGUAGE OverloadedStrings #-}
> module Main where
>
> import Happstack.Server
> import           Text.Blaze ((!))
> import qualified Text.Blaze.Html4.Strict as H
> import qualified Text.Blaze.Html4.Strict.Attributes as A
>
> appTemplate :: String -> [H.Html] -> H.Html -> H.Html
> appTemplate title headers body =
>     H.html $ do
>       H.head $ do
>         H.title (H.toHtml title)
>         H.meta ! A.httpEquiv "Content-Type" ! A.content "text/html;charset=utf-8"
>         sequence_ headers
>       H.body $ do
>         body
>
> helloBlaze :: ServerPart Response
> helloBlaze = 
>    ok $ toResponse $ 
>     appTemplate "Hello, Blaze!" 
>                 [H.meta ! A.name "keywords" ! A.content "happstack, blaze, html"] 
>                 (H.p "hello, blaze!")
>
> main :: IO ()
> main = simpleHTTP nullConf $ helloBlaze

[Source code for the app is here.]

Now if we visit http://localhost:8000/, we will get an html page which says:

hello, blaze!

This example is pretty simple, but there are a few things to note:

Using HSP

To enable HSP support, you must install the happstack-hsp package.

HSP is an XML-based templating system that allows you to embed XML in your Haskell source files. If you have ever had to use PHP, you may want to run screaming from this idea. However, the HSP solution is far saner than the PHP solution, so you may want to give it a chance.

The first thing we will see is a funny OPTIONS_GHC pragma at the top of our file:

> {-# LANGUAGE FlexibleContexts, OverlappingInstances #-}
> {-# OPTIONS_GHC -F -pgmF trhsx #-}
> module Main where
>

HSP works by running the code through an external pre-processor named trhsx. This pragma at the top is how we tell GHC that this file needs to be run through the trhsx pre-processor in order to work. So, that options line looks a bit like line noise. You can try to remember it like this:

  1. -F says we want to filter the source code (or maybe transForm the source code)
  2. -pgmF specifies the program we want to do the transformation
  3. trhsx is short for transform using hsx

Next we have some imports:

> import Control.Applicative ((<$>))
> import Control.Monad.Identity (Identity(runIdentity))
> import qualified HSX.XMLGenerator as HSX
> import Happstack.Server.HSP.HTML
> import Happstack.Server (Request(rqMethod), ServerPartT, askRq, nullConf, simpleHTTP)
> import HSP.Identity () -- instance (XMLGen Identity)
>

Now we can define a function which generates an HTML page:

> hello :: ServerPartT IO XML
> hello = unXMLGenT
>   <html>
>    <head>
>     <title>Hello, HSP!</title>
>    </head>
>    <body>
>     <h1>Hello HSP!</h1>
>     <p>We can insert Haskell expression such as this: <% sum [1 .. (10 :: Int)] %></p>
>     <p>We can use the ServerPartT monad too. Your request method was: <% getMethod %></p>
>     <hr/>
>     <p>We don't have to escape & or >. Isn't that nice?</p>
>     <p>If we want <% "<" %> then we have to do something funny.</p>
>     <p>But we don't have to worry about escaping <% "<p>a string like this</p>" %></p>
>     <p>We can also nest <% <span>like <% "this." %> </span> %></p>
>    </body>
>   </html>
>       where
>       getMethod :: XMLGenT (ServerPartT IO) String
>       getMethod = show . rqMethod <$> askRq
>
> main :: IO ()
> main = simpleHTTP nullConf $ hello
>

The first thing we notice is that syntax looks pretty much like normal HTML syntax. There are a few key differences though:

  1. like XML, all tags must be closed
  2. like XML, we can use shortags (e.g. < hr />)
  3. We do not have to escape & and >
  4. To embed < we have to do something extra funny

The syntax:

<% haskell expression %>

allows us to embed a Haskell expression inside of literal XML.

As shown in this line:

>     <p>We can also nest <% <span>like <% "this." %> </span> %></p>

we can freely nest Haskell and XML expressions.

What does trhsx do?

In order to use HSP it is very useful to understand what is actually going on behind the magic. If we have the line:

> foo :: XMLGenT (ServerPartT IO) XML
> foo = <span class="bar">foo</span>

and we run trhsx, it gets turned into a line like this:

> foo :: XMLGenT (ServerPartT IO) XML
> foo = genElement (Nothing, "span") [ asAttr ("class" := "bar") ] [asChild ("foo")]
>

We see that the XML syntax has simply been translated into normal haskell function calls.

Important HSX types and classes

There are a few types and classes that you will need to be familiar with.

the XMLGenT type

The first type is the XMLGenT monad transformer:

> newtype XMLGenT m a = XMLGenT (m a)
> -- | un-lift.
> unXMLGenT :: XMLGenT m a -> m a
> unXMLGenT (XMLGenT ma) =  ma

This seemingly useless type exists solely to make the type-checker happy. Without it we would need an instance like:

> instance (EmbedAsChild (IdentityT m) a, Functor m, Monad m, m ~ n) => 
>          EmbedAsChild (IdentityT m) (n a) where
>   asChild = ...

Unfortunately, because (n a) is so vague, that results in overlapping instances that cannot be resolved without IncohorentInstances. And, in my experience, enabling IncohorentInstances is never the right solution.

So, when generating XML you will generally need to apply unXMLGenT to the result to remove the XMLGenT wrapper as we did in the hello function. Anyone who can figure out to do away with the XMLGenT class will be my personal hero.

the XMLGen class

Next we have the XMLGen class:

> class Monad m => XMLGen m where
>  type XML       m
>  data Child     m
>  data Attribute m
>  genElement    :: Name -> [XMLGenT m [Attribute m]] -> [XMLGenT m [Child m]] -> XMLGenT m (XML m)
>  genEElement   :: Name -> [XMLGenT m [Attribute m]]                          -> XMLGenT m (XML m)
>  genEElement n ats = genElement n ats []
>  xmlToChild    :: XML m -> Child m
>  pcdataToChild :: String -> Child m

Most of these functions and types are used internally and not used directly by the developer.

You will notice that we have a type-class instead of just simple functions and types. One feature of HSX is that it is not tied to any particular XML representation. Instead, the XML representation is based on the monad we are currently inside. For example, inside of a javascript monad, we might generate javascript code that renders the XML, inside of another monad, we might generate the Node type used by the heist template library. We will see some examples of this in a later section.

The data and type declarations appearing inside the class declaration are allowed because of the TypeFamilies extension. For a detailed coverage of type families see this wiki entry.

the XML m type synonym

The XMLGen type-class defines an associated type synonym XML m:

> type XML m

XML m is a synonym for whatever the xml type is for the monad m. We can write an XML fragment that is parameterized over an arbitrary monad and xml type like this:

> bar :: (XMLGenerator m) => XMLGenT m (HSX.XML m)
> bar = <span>bar</span>
>

Note that we had this qualified import:

> import qualified HSX.XMLGenerator as HSX

That is because we need to differentiate the XML associated type synonym from the plain-old XML data type that is declared elsewhere. Having two types with the same name is a bit silly, but that is the way it is for now.

the EmbedAsChild class

The EmbedAsChild is used to turn a value into a list of children of an element:

> type GenChildList m     = XMLGenT m [Child m]
>
> -- | Embed values as child nodes of an XML element. The parent type will be clear
> -- from the context so it is not mentioned.
> class XMLGen m => EmbedAsChild m c where
>  asChild :: c -> GenChildList m

There are generally many instances of EmbedAsChild allowing you to embed String, Text, Int, and other values. You might find it useful to create additional instances for types in your program. We will some some examples later in this tutorial.

To use the EmbedAsChild class we us the <% %> syntax shown earlier. For example, when we write:

> a :: (XMLGenerator m) => GenChildList m
> a = <% 'a' %>
>

It gets turned into:

> a :: (XMLGenerator m) => GenChildList m
> a = (asChild ('a'))
>

the EmbedAsAttr class

The EmbedAsAttr class is similar to the EmbedAsChild class. It is used to turn arbitrary values into element attributes.

> type GenAttributeList m = XMLGenT m [Attribute m]
>
> -- | Similarly embed values as attributes of an XML element.
> class XMLGen m => EmbedAsAttr m a where
>  asAttr :: a -> GenAttributeList m

If we have some attributes like this:

> foo = <span class="foo" size=(80 :: Int) bogus=False>foo</span>

It will get translated to:

> foo
>  = (genElement (Nothing, "span")
>       [asAttr ("class" := "foo"), asAttr ("size" := (80 :: Int)),
>        asAttr ("bogus" := False)]
>       [asChild ("foo")])

which might be rendered as:

<span class="foo" size="80" bogus="false" >foo</span >

the XMLGenerator class

You may have noticed that some of the examples had a class constraint (XMLGenerator m):

> bar :: (XMLGenerator m) => XMLGenT m (HSX.XML m)
> bar = <span>bar</span>
>

XMLGenerator is just a class alias. It is defined as such:

> class ( XMLGen m
>       , SetAttr      m (HSX.XML m)
>       , AppendChild  m (HSX.XML m)
>       , EmbedAsChild m (HSX.XML m)
>       , EmbedAsChild m [HSX.XML m]
>       , EmbedAsChild m String
>       , EmbedAsChild m Char
>       , EmbedAsAttr  m (Attr String String)
>       , EmbedAsAttr  m (Attr String Int)
>       , EmbedAsAttr  m (Attr String Bool)
>       ) => XMLGenerator m

It contains a list of common instances that all xml generation monads are expected to provide. It just saves you from having to list all thoses instances by hand when you use them.

HSX by Example

First we have a simple function to render the pages and print them to stdout:

> printXML :: Identity XML -> IO ()
> printXML = putStrLn . renderAsHTML . runIdentity

HSX and do syntax

It is possible to use hsx markup inside a do-block. You just need to be aware of one little catch. In this example:

> doBlock :: (XMLGenerator m) => XMLGenT m (HSX.XML m)
> doBlock =
>     do <div>
>         <p>A child element</p>
>         </div>

Notice that we indent the closing </div> tag. That indentation rule is consistent with the specification for how do-notation works. It is intend for the same reason that if .. then .. else ..' blocks have to be idented in a special way insidedo`-blocks.

defaultTemplate

There is a bit of boiler plate that appears in ever html document such as the <html>, <head>, <title>, and <body> tags. The defaultTemplate function provides a minimal skeleton template with those tags:

> defaultTemplate :: ( XMLGenerator m
>                    , EmbedAsChild m body
>                    , EmbedAsChild m headers
>                    ) =>
>                    String   -- string to put in <title>
>                 -> headers  -- additional elements to put in <head>
>                 -> body     -- elements to put in <body>
>                 -> m (HSX.XML m)

How to embed empty/nothing/zero

defaultTemplate requires that we pass in headers and a body. But what if we don't have any headers that we want to add?

Most XMLGenerator monads provide an EmbedAsChild m () instance, such as this one:

> instance EmbedAsChild Identity () where
>  asChild () = return []

So, we can just pass in () like so:

> empty = printXML $ defaultTemplate "empty" () ()

Which will render as such:

<html
><head
  ><title
    >empty</title
    ></head
  ><body
  ></body
  ></html
>

Creating a list of children

Sometimes we want to create a number of child elements without knowing what their parent element will be. We can do that using the:

<%> ... </%>

syntax. For example, here we return two paragraphs:

> twoParagraphs :: (XMLGenerator m) => XMLGenT m [HSX.Child m]
> twoParagraphs =
>     <%>
>      <p>Paragraph one</p>
>      <p>Paragraph two</p>
>    </%>

We can embed those in parent element like this:

> twoParagraphsWithParent :: (XMLGenerator m) => XMLGenT m (HSX.XML m)
> twoParagraphsWithParent =
>     <div>
>      <% twoParagraphs %>
>     </div>

if .. then .. else ..

Using an if .. then .. else .. is straight-foward. But what happens when you don't really want an else case? This is another place we can use ():

> ifThen bool = 
>     printXML $ defaultTemplate "ifThen" () $
>      <div>
>       <% if bool 
>          then <%
>                <p>Showing this thing.</p> 
>               %>
>          else <% () %>
>        %>
>      </div>
>

Lists of attributes & optional attributes

Normally attributes are added to an element using the normal html attribute syntax. HSX, has a special extension where the last attribute can be a Haskell expression which returns a list of attributes to add to the element. For example:

> attrList = 
>     printXML $ defaultTemplate "attrList" () $
>      <div id="somediv" ["class" := "classy", "title" := "untitled"] >
>      </div>
>

The type of the elements of the list can be anything with an EmbedAsAttr m a instance. In this case we create a list of Attr values:

> data Attr n a = n := a

We can use this feature to conditionally add attributes using a simple if .. then .. else .. statment:

> optAttrList bool = 
>     printXML $ defaultTemplate "attrList" () $
>      <div id="somediv" (if bool then ["class" := "classy", "title" := "untitled"] else []) >
>      </div>
>

Using Heist

Heist is an XML templating engine. The static HTML portions of your web pages reside in XML files which can be edited and reloaded with out having to recompile your server. The dynamic portions are generated in Haskell and spliced into the templates.

To enable Heist support, you must install the happstack-heist package. It is not installed by default.

The following template is almost an XHTML document, except that it contains the special tag <fact>6</fact>:

<html>
  <head>
    <title>Factorial Page</title>
  </head>
  <body>
    <h1>Factorial Page</h1>
    <p>The factorial of 6 is <fact>6</fact></p>
  </body>
</html>

The <fact/> tag is an application specific tag which performs a factorial and splices in the result.

The following example shows how to initialize the Heist template system and how to create your own custom tags.

First a bunch of boring imports:

> module Main where
> import Control.Monad          (msum)
> import Control.Monad.Trans    (MonadIO)
> import qualified Data.Text    as T
> import Happstack.Server       (dir, nullConf, nullDir, simpleHTTP, seeOther, toResponse)
> import Happstack.Server.Heist (templateServe, templateReloader)
> import Text.Templating.Heist  (HeistT, Template, HeistState
>                               , bindSplice, defaultHeistState, getParamNode)
> import Text.Templating.Heist.TemplateDirectory (newTemplateDirectory')
> import qualified Text.XmlHtml as X

Next we have the factorial splice:

> factSplice :: (Monad m) => HeistT m Template
> factSplice = do
>   input <- getParamNode
>   let text = T.unpack $ X.nodeText input
>       n    = read text :: Int
>   return [X.TextNode $ T.pack $ show $ product [1..n]]
>

The splice runs in the HeistT monad transformer. The getParamNode function:

> getParamNode :: (Monad m) => HeistT m Node

returns the XHTML node that triggered this splice function to be called. In this case it would be, <fact>6</fact>

We then use textContent:

> X.textContent :: Node -> ByteString

to extract the string "6" from the node, which we convert to an Int.

Finally, we calculate the factorial, and convert the result back into the XML that we want to splice into the template.

The mapping from tag names to template functions is stored in the HeistState m. New tags can be added by using bindSplice:

> bindSplice :: Monad m => 
>               ByteString               -- ^ name to use for splice tag
>            -> HeistT m Template -- ^ template function to handle the splice
>            -> HeistState m          -- ^ template state to update
>            -> HeistState m

So here we bind <fact/> to factSplice

> templateState :: (MonadIO m) => 
>                  FilePath -- ^ path to template directory
>               -> HeistState m
> templateState templateDir = bindSplice (T.pack "fact") factSplice defaultHeistState
>

In our main function, we must first initialize the Heist template system by using newTemplateDirectory':

> newTemplateDirectory' :: (MonadIO m, MonadIO n) => 
>                          FilePath        -- ^ path to template directory on disk
>                       -> HeistState m -- ^ the template state
>                       -> n (TemplateDirectory m) -- ^ a handle to the template directory

In this example, we would put the templates in same directory the app is running from:

> main :: IO ()
> main = do
>     let templateDir = "."
>     td <- newTemplateDirectory' templateDir (templateState templateDir)

to serve templates we simply use the templateServe function:

> templateServe ::  (ServerMonad m, MonadPlus m, MonadIO m) =>
>                   TemplateDirectory m -- ^ the handle returned by newTemplateDirectory'
>               -> m Response

templateServe will look at the path in the URL, add .tpl to the end, and try to find a matching template file on disk to return.

Because the templates are loaded into memory, updating the files on disk will not have any immediate effect. You can use templateReloader to force the templates to be reloaded:

> templateReloader :: (MonadIO m, MonadIO n) =>
>                     TemplateDirectory m -- ^ handle returned by newTemplateDirectory'
>                  -> n Response

so putting those together we get our handlers:

>     simpleHTTP nullConf $ msum 
>        [ templateServe td
>        , dir "reload" $ nullDir >> templateReloader td
>        , nullDir >> seeOther "/factorial" (toResponse ())
>        ]

[Source code for the app is here. You will also need to download the source for factorial.tpl and save it in the same directory as TemplateHeist.hs.]

If you point your browser at http://localhost:8000/factorial you should see the factorial page. You can point your browser at http://localhost:8000/reload to reload the template.

Other Heist Features

Heist offers a variety of other features not shown here. We have only covered the Happstack integration aspects. For more general information on Heist look at the Official Heist Template Tutorial and the Heist Haddock Documenation.

JavaScript via JMacro

To use JMacro with happstack and hsx, you should install the hsx-jmacro and happstack-jmacro packages. You will also need to be sure that your version of happstack-hsp is >= 6.1.0.

JMacro is a library that makes it easy to include javascript in your templates.

The syntax used by JMacro is almost identical to JavaScript. So, you do not have to learn some special DSL to use it. In fact, JMacro can work with most JavaScript you find in the wild. Using JMacro has a number of advantages over just using plain-old javascript.

The hsx-jmacro and happstack-jmacro libraries makes it easy to use JMacro with Happstack and HSP.

The following examples demonstrate the basics of JMacro and how it interfaces with HSX and Happstack. The examples are intended to demonstrate what is possible with JMacro. The examples are not intended to demonstrate good javascript practices. For example, many developers frown on the use of the onclick attribute in html, or having <script> tags in the <body>.

The JMacro library does not require any external pre-processors. Instead it uses the magic of QuasiQuotation.

QuasiQuotes can be enabled via the LANGUAGE extension:

> {-# LANGUAGE CPP, FlexibleInstances, GeneralizedNewtypeDeriving, 
>     TypeSynonymInstances, QuasiQuotes #-}

In this example we are also using HSX, which does require a pre-processor. (A crash course section on HSX itself will be coming soon). The following line will automatically run the pre-processor for us (and also suppress warnings about orphan instances):

> {-# OPTIONS_GHC -F -pgmFtrhsx -fno-warn-orphans #-}

Next we have a boatload of imports. Not all of these are required to use JMacro. Many are just used for the demos.

> import Control.Applicative ((<$>), optional)
> import Control.Monad       (msum)
> import Control.Monad.State (StateT, evalStateT)
> import Control.Monad.Trans (liftIO)
> import qualified Data.Map  as Map
> import Data.Maybe          (fromMaybe)
> import Happstack.Server    (Response, ServerPartT, dir, mapServerPartT, look, nullConf,
>                             ok, simpleHTTP, toResponse)
> import Happstack.Server.HSP.HTML    (defaultTemplate) -- ^ also imports 'ToMessage XML'
> import Happstack.Server.JMacro      ()                -- ToMessage instance for JStat
> import HSP                          ( Attr(..), EmbedAsAttr(..), EmbedAsChild(..), genElement
>                                     , genEElement)
> import HSP.ServerPartT              ()                -- ^ instance 'XMLGenerator ServerPartT'
> import HSX.JMacro (IntegerSupply(..), nextInteger')   -- ^ EmbedAsChild and EmbedAsAttr for JStat
> import Language.Javascript.JMacro   ( ToJExpr(..), Ident(..), JStat(..), JExpr(..), JVal(..)
>                                     , jmacro, jsv, jLam, jVarTy)
> import System.Random                (Random(..))
>

In order to ensure that each <script> tag generates unique variables names, we need a source of unique prefixes. An easy way to do that is to wrap the ServerPartT monad around a StateT monad that supplies integers:

> type JMacroPart = ServerPartT (StateT Integer IO)
>
> instance IntegerSupply JMacroPart where
>     nextInteger = nextInteger'
>

The nextInteger' helper function has the type:

>  nextInteger' :: (MonadState Integer m) => m Integer

To use JMacroPart with simpleHTTP, we just evaluate the StateT monad:

> main :: IO ()
> main = simpleHTTP nullConf $ flatten handlers
>     where
>       flatten :: JMacroPart a -> ServerPartT IO a 
>       flatten = mapServerPartT (flip evalStateT 0)
>

JMacro in a <script> tag

Now that we have the scene set, we can actually look at some JMacro usage.

In this example we embed a single JavaScript block inside the page:

> helloJMacro :: JMacroPart Response
> helloJMacro =
>     toResponse <$> defaultTemplate "Hello JMacro" ()
>       <div>
>        <% [$jmacro| 
>            var helloNode = document.createElement('h1');
>            helloNode.appendChild(document.createTextNode("Hello, JMacro!"));
>            document.body.appendChild(helloNode);
>            |] %>
>       </div>
>

We do not need to specify the <script> tag explicitly, it will automatically be created for us.

The syntax [$jmacro| ... |] is the magic incantation for running the jmacro quasiquoter. In GHC 7.x, the $ is no longer required, so in theory you could write, [jmacro| ... |]. However, HSX has not been updated to support the $ free syntax. So, for now you will need to stick with the $ syntax, despite the compiler warnings saying, Warning: Deprecated syntax: quasiquotes no longer need a dollar sign: $jmacro.

JMacro in an HTML attribute (onclick, etc)

We can also use JMacro inside html attributes, such as onclick.

> helloAttr :: JMacroPart Response
> helloAttr =
>     toResponse <$> defaultTemplate "Hello Attr" ()
>     <h1 style="cursor:pointer" onclick=[$jmacro| alert("that </tickles>!") |]>Click me!</h1>
>

Note that we do not have to worry about escaping the ", < or > in the onclick handler. It is taken care of for us automatically! The code is automatically escaped as:

onclick="alert(&quot;that &lt;/tickles&gt;!&quot;);"

Automatice escaping of </

According to the HTML spec it is invalid for </ to appear anywhere inside the <script> tag.

The JMacro embedding also takes care of handling </ appearing in string literals. So we can just write this:

> helloEndTag :: JMacroPart Response
> helloEndTag =
>     toResponse <$> defaultTemplate "Hello End Tag" ()
>     <%>
>      <h1>Tricky End Tag</h1>
>      <% [$jmacro| alert("this </script> won't mess things up!") |] %>
>     </%>
>

And it will generate:

<script type="text/javascript">alert("this <\/script> won't mess things up!");</script>

Hygienic Variable Names

So far, using HSP with JMacro looks almost exactly like using HSP with plain-old JavaScript. That's actually pretty exciting. It means that the mental tax for using JMacro over straight JavaScript is very low.

Now let's look at an example of hygienic naming. Let's say we write the following block of JavaScript code:

> clickMe :: JStat
> clickMe =
>     [$jmacro|
>
>     var clickNode = document.createElement('p');
>     clickNode.appendChild(document.createTextNode("Click me!"));
>     document.body.appendChild(clickNode);
>     var clickCnt = 0;
>     clickNode.setAttribute('style', 'cursor: pointer');
>     clickNode.onclick = function () { clickCnt++;
>                                       alert ('Been clicked ' + clickCnt + ' time(s).'); 
>                                     };
>     |]
>

That block of code tracks how many times you have clicked on the Click me! text. It uses a global variable to keep track of the number of clicks. Normally that would spell trouble. If we tried to use that code twice on the same page, both copies would end up writing to the same global variable clickCnt.

But, JMacro automatically renames the variables for us so that the names are unique. In the following code each Click me! tracks its counts separately:

> clickPart :: JMacroPart Response
> clickPart = 
>     toResponse <$> defaultTemplate "Hygienic Naming" ()
>                    <div>
>                     <h1>A Demo of Happstack+HSP+JMacro</h1>
>                     <% clickMe %>
>                     <% clickMe %>
>                    </div>
>

Non-Hygienic Variable Names

Of course, sometimes we want the code blocks to share a global variable. We can easily do that by changing the line:

>   var clickCnt = 0;

to

>   var !clickCnt = 0;

The use of ! when declaring a variable disables hygienic naming. Now all the copies of clickMe2 will share the same counter:

> clickMe2Init :: JStat
> clickMe2Init = 
>     [$jmacro| var !clickCnt = 0; |];
>     
> clickMe2 :: JStat
> clickMe2 =
>     [$jmacro|
>
>     var clickNode = document.createElement('p');
>     clickNode.appendChild(document.createTextNode("Click me!"));
>     document.body.appendChild(clickNode);
>     clickNode.setAttribute("style", "cursor: pointer");
>     clickNode.onclick = function () { clickCnt++;
>                                       alert ('Been clicked ' + clickCnt + ' time(s).'); 
>                                     };
>     |]
>
> clickPart2 :: JMacroPart Response
> clickPart2 = 
>     toResponse <$> defaultTemplate "Hygienic Naming"
>                    <% clickMe2Init %>
>                    <div>
>                     <h1>A Demo of Happstack+HSP+JMacro</h1>
>                     <% clickMe2 %>
>                     <% clickMe2 %>
>                    </div>
>

Declaring Functions

Hygienic naming affects function declarations as well. If we want to define a function in <head>, but call the function from the <body>, then we need to disable hygienic naming. We can do that using the ! trick again:

> function !hello(noun) { alert('hello ' + noun); }

JMacro also has some syntax extensions for declaring functions. We can create an anonymous function using Haskell-like syntax assign it to a variable:

> var !helloAgain = \noun ->alert('hello again, ' + noun);

Another option is to use the ML-like fun keyword to declare a function. When using fun we do not need the !.

> fun goodbye noun { alert('goodbye ' + noun); }

Or we can do both:

> fun goodbyeAgain noun -> alert('goodbye again, ' + noun);

Here they all are in an example:

> functionNames :: JMacroPart Response
> functionNames =
>     toResponse <$> defaultTemplate "Function Names"
>                     <% [$jmacro| 
>                          function !hello(noun) { alert('hello, ' + noun); }
>                          var !helloAgain = \noun ->alert('hello again, ' + noun);
>                          fun goodbye noun { alert('goodbye ' + noun); }
>                          fun goodbyeAgain noun -> alert('goodbye again, ' + noun);
>                        |]
>                      %>
>                     <%>
>                       <button onclick=[$jmacro| hello('world'); |]>hello</button>
>                       <button onclick=[$jmacro| helloAgain('world'); |]>helloAgain</button>
>                       <button onclick=[$jmacro| goodbye('world'); |]>goodbye</button>
>                       <button onclick=[$jmacro| goodbyeAgain('world'); |]>goodbyeAgain</button>
>                     </%>
>

Splicing Haskell Values into JavaScript (Antiquotation)

We can also splice Haskell values into the JavaScript code by using `( )`. In the following example, the onclick action for the <button> calls revealFortune(). The argument to revealForture is the String returned by evaluating the Haskell expression fortunes !! n.

> fortunePart :: JMacroPart Response
> fortunePart =
>     do let fortunes = ["You will be cursed to write Java for the rest of your days."
>                       , "Fortune smiles upon you, your future will be filled with lambdas"
>                       ]
>        n <- liftIO $ randomRIO (0, (length fortunes) - 1)
>             
>        toResponse <$> defaultTemplate "Fortune"
>                     <% [$jmacro|
>                         fun revealFortune fortune
>                         {
>                          var b = document.getElementById("button");
>                          b.setAttribute('disabled', 'disabled');
>                          var p = document.getElementById("fortune");
>                          p.appendChild(document.createTextNode(fortune));
>                         }
>                        |]
>                         %>
>                    <div>
>                     <h1>Your Fortune</h1>
>                     <p id="fortune"></p>
>                     <button id="button" onclick=[$jmacro| revealFortune(`(fortunes !! n)`); |]>
>                       Click to reveal your fortune
>                     </button>
>                    </div>
>

Using ToJExpr to convert Haskell values to JavaScript

JMacro can embed common types such as Int, Bool, Char, String, etc, by default. But we can also embed other types by creating a ToJExpr instance for them. For example, let's say we create some types for reporting the weather:

> data Skies = Cloudy | Clear
>            deriving (Bounded, Enum, Eq, Ord, Read, Show)
>
> newtype Fahrenheit = Fahrenheit Double
>            deriving (Num, Enum, Eq, Ord, Read, Show, ToJExpr, Random)
>
> data Weather = Weather
>     { skies :: Skies
>     , temp  :: Fahrenheit
>     }
>     deriving (Eq, Ord, Read, Show)
>
> instance Random Skies where
>     randomR (lo, hi) g =
>        case randomR (fromEnum lo, fromEnum hi) g of
>          (c, g') -> (toEnum c, g')
>     random g = randomR (minBound, maxBound) g
>
> instance Random Weather where
>     randomR (Weather skiesLo tempLo, Weather skiesHi tempHi) g =
>         let (skies, g') = randomR (skiesLo, skiesHi) g
>             (temp, g'') = randomR (tempLo, tempHi) g'
>         in ((Weather skies temp), g'')
>     random g =
>         let (skies, g') = random g
>             (temp, g'') = random g'
>         in ((Weather skies temp), g'')
>

To pass these values into the generated JavaScript, we simply create a ToJExpr instance:

> class ToJExpr a where
>   toJExpr :: a -> JExpr

For Fahrenheit, we were actually able to derive the ToJExpr instance automatically (aka, deriving (ToJExpr)), because it is a newtype wrapper around Double which already has a ToExpr instance.

For Skies, we can just convert the constructors into JavaScript strings:

> instance ToJExpr Skies where
>     toJExpr = toJExpr . show
>

For the Weather type, we create a JavaScript object/hash/associative array/record/whatever you want to call it:

> instance ToJExpr Weather where
>    toJExpr (Weather skies temp) = 
>        toJExpr (Map.fromList [ ("skies", toJExpr skies)
>                              , ("temp",  toJExpr temp)
>                              ])
>

Now we can splice a random weather report into our JavaScript:

> weatherPart :: JMacroPart Response
> weatherPart =
>     do weather <- liftIO $ randomRIO ((Weather minBound (-40)), (Weather maxBound 100))
>        toResponse <$> defaultTemplate "Weather Report" () 
>         <div>
>          <% [$jmacro|
>              var w = `(weather)`;
>              var p = document.createElement('p');
>              p.appendChild(document.createTextNode("The skies will be " + w.skies + 
>                                                    " and the temperature will be " + 
>                                                    w.temp.toFixed(1) + "°F"));
>              document.body.appendChild(p);
>              |] %>
>         </div>
>

ToJExpr has an instance for JSValue from the json library. So, if your type already has a JSON istance, you can trivially create a ToJExpr instance for it:

> instance ToJExpr Foo where
>   toJExpr = toJExpr . showJSON

Using JMacro in external .js scripts

So far we have used JMacro to generate JavaScript that is embedded in HTML. We can also use it to create standalone JavaScript.

First we have a script template that is parametrized by a greeting.

> externalJs :: String -> JStat
> externalJs greeting =
>     [$jmacro|
>      fun greet noun
>      {
>        alert(`(greeting)` + ' ' + noun);
>      }
>      |]
>

Then we have a server part with two sub-parts:

> externalPart :: JMacroPart Response
> externalPart = dir "external" $ msum [ 

If external/script.js is requested, then we check for a query string parameter greeting and generate the script. toResponse will automatically convert the script to a Response and serve it with the content-type, text/javascript; charset=UTF-8:

>             dir "script.js" $
>                do greeting <- optional $ look "greeting"
>                   ok $ toResponse $ externalJs (fromMaybe "hello" greeting)

Next we have an html page that includes the external script, and calls the greet function:

>          , toResponse <$> defaultTemplate "external" 
>              <script type="text/javascript" src="/external/script.js?greeting=Ahoy" />
>              <div>
>               <h1>Greetings</h1>
>               <button onclick=[$jmacro| greet('JMacro'); |]>Click for a greeting.</button>
>              </div>
>          ]
>

Links to demos

Here is a little page that links to all the JMacro demos:

> demosPart :: JMacroPart Response
> demosPart =
>     toResponse <$> defaultTemplate "demos" ()
>                    <ul>
>                     <li><a href="/hello"    >Hello, JMacro</a></li>
>                     <li><a href="/attr"     >Hello, Attr</a></li>
>                     <li><a href="/endTag"   >Hello, End Tag</a></li>
>                     <li><a href="/clickMe"  >ClickMe</a></li>
>                     <li><a href="/clickMe2" >ClickMe2</a></li>
>                     <li><a href="/functions">Function Names</a></li>
>                     <li><a href="/fortune"  >Fortune</a></li>
>                     <li><a href="/weather"  >Weather</a></li>
>                     <li><a href="/external" >External</a></li>
>                    </ul>
>

and our routes:

> handlers :: JMacroPart Response
> handlers = 
>    msum [ dir "hello"     $ helloJMacro
>         , dir "attr"      $ helloAttr
>         , dir "endTag"    $ helloEndTag
>         , dir "clickMe"   $ clickPart
>         , dir "clickMe2"  $ clickPart2
>         , dir "functions" $ functionNames
>         , dir "fortune"   $ fortunePart
>         , dir "weather"   $ weatherPart
>         , externalPart
>         , demosPart
>         ]
>

[Source code for these demos is here.]

Alternative IntegerSupply instance

If you do not like having to use the StateT monad transformer to generate names, there are other options. For example, we could use Data.Unique to generate unique names:

> instance IntegerSupply (ServerPartT IO) where
>     nextInteger = fmap (fromIntegral . (`mod` 1024) . hashUnique) (liftIO newUnique)

This should be safe as long as you have less than 1024 different JMacro blocks on a single page.

More Information

For more information on using JMacro I recommend reading this wiki page and the tutorial at the top of Language.Javascript.JMacro. The documentation is this tutorial has covered the basics of JMacro, but not everything!

Next: Request parameters and data