hsx-jmacro-7.3.8: hsp+jmacro support

Safe HaskellNone
LanguageHaskell98

HSP.JMacro

Contents

Description

This module provides support for:

  1. embedding Javascript generated by JMacro into HSX.
  2. turning XML generated by HSX into a DOM node in Javascript

It provides the following instances:

instance (XMLGenerator m, IntegerSupply m) => EmbedAsChild m JStat
instance (IntegerSupply m, IsName n, EmbedAsAttr m (Attr Name String)) => EmbedAsAttr m (Attr n JStat)
instance ToJExpr XML
instance ToJExpr DOMNode
instance ToJExpr XMLToInnerHTML
instance ToJExpr XMLToDOM

In order to ensure that each embedded JStat block has unique variable names, the monad must supply a source of unique names. This is done by adding an instance of IntegerSupply for the monad being used with XMLGenerator.

For example, we can use StateT to provide an IntegerSupply instance for ServerPartT:

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

Alternatively, we can exploit the IO monad to provide an IntegerSupply instance for ServerPartT:

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

The ToJExpr XML instance allows you to splice in XML lifted out of an arbitrary monad to generate DOM nodes with JMacro antiquotation:

js = do html <- unXMLGenT <p>I'm in a Monad!</p>
        return [jmacro| document.getElementById("messages").appendChild(`(html)`); |]

The ToJExpr DOMNode instance allows you to run HSP in the Identity monad to render JMacro in pure code:

html :: DOMNode
html = <p>I'm using <em>JavaScript</em>!</p>
js = [jmacro| var language = `(html)`.getElementsByTagName("em")[0].textContent; |]

You can see here that you get an actual DOM tree in JavaScript. This is also compatible with libraries such as jQuery and YUI which are able to wrap DOM nodes in their own type, for example with jQuery:

js = [jmacro| var languages = $(`(html)`).find("em").text(); |]

Or with YUI:

js = [jmacro| var languages = Y.one(`(html)`).one("em").get("text"); |]

There are two ways to turn HTML into a a DOM node in the browser. One way is to render the HTML to a string, and pass the string to element.innerHTML. The other way is to us the use the DOM functions like createElement, setAttribute, to programatically create the DOM on the client.

In webkit-based browsers like Chrome and Safari, the DOM method appears to be slightly faster. In other browsers, the innerHTML method appears to be faster. The innerHTML method will almost always required fewer bytes to be transmitted. Additionally, if your XML/HTML contains pre-escaped content, you are required to use innerHTML anyway.

So, by default the ToJExpr XML instance uses the innerHTML method. Though, that could change in the future. If you care about using one method over the other you can use the newtype wrappers XMLToInnerHTML or XMLToDOM to select which method to use.

Synopsis

Documentation

class IntegerSupply m where Source #

This class provides a monotonically increasing supply of non-duplicate Integer values

Minimal complete definition

nextInteger

nextInteger' :: MonadState Integer m => m Integer Source #

This help function allows you to easily create an IntegerSupply instance for monads that have a MonadState Integer instance.

For example:

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

type DOMNode = HSPT XML Identity XML Source #

Provided for convenience since Ident is exported by both HSP.Identity and JMacro. Using this you can avoid the need for an extra and qualified import.

newtype XMLToInnerHTML Source #

newtype which can be used with toJExpr to specify that the XML should be converted to a DOM in javascript by using innerHTML

Constructors

XMLToInnerHTML XML 

newtype XMLToDOM Source #

newtype which can be used with toJExpr to specify that the XML should be converted to a DOM in javascript by using createElement, appendChild, and other DOM functions.

WARNING: CDATA FALSE values are assumed to be pre-escaped HTML and will be converted to a DOM node by using innerHTML. Additionally, if the call to innerHTML returns more than one node, only the first node is used.

Constructors

XMLToDOM XML 

Orphan instances