1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    2 
    3 {-|
    4 
    5   This module contains the core definitions for the Heist template system.
    6 
    7   The Heist template system is based on HTML and XML.  It allows you to build
    8   custom HTML and XML based markup languages.  With Heist you can define your
    9   own domain-specific HTML and XML tags implemented with Haskell and use them
   10   in your templates.
   11 
   12   The most important concept in Heist is the 'Splice'.  Splices can be thought
   13   of as functions that transform a node into a list of nodes.  Heist then
   14   substitutes the resulting list of nodes into your template in place of the
   15   input node.  'Splice' is implemented as a type synonym @type Splice m =
   16   HeistT m [Node]@, and 'HeistT' has a function 'getParamNode'
   17   that lets you get the input node.
   18 
   19   Suppose you have a place on your page where you want to display a link with
   20   the text \"Logout username\" if the user is currently logged in or a link to
   21   the login page if no user is logged in.  Assume you have a function
   22   @getUser :: MyAppMonad (Maybe Text)@ that gets the current user.
   23   You can implement this functionality with a 'Splice' as follows:
   24 
   25   > import             Blaze.ByteString.Builder
   26   > import             Data.ByteString.Char8 (ByteString)
   27   > import qualified   Data.ByteString.Char8 as B
   28   > import             Data.Text (Text)
   29   > import qualified   Data.Text as T
   30   > import qualified   Text.XmlHtml as X
   31   >
   32   > import             Text.Templating.Heist
   33   >
   34   > link :: Text -> Text -> X.Node
   35   > link target text = X.Element "a" [("href", target)] [X.TextNode text]
   36   >
   37   > loginLink :: X.Node
   38   > loginLink = link "/login" "Login"
   39   >
   40   > logoutLink :: Text -> X.Node
   41   > logoutLink user = link "/logout" (T.append "Logout " user)
   42   >
   43   > loginLogoutSplice :: Splice MyAppMonad
   44   > loginLogoutSplice = do
   45   >     user <- lift getUser
   46   >     return [maybe loginLink logoutLink user]
   47   >
   48 
   49   Next, you need to bind that splice to a tag.  Heist stores information
   50   about splices and templates in the 'TemplateState' data structure.  The
   51   following code demonstrates how this splice would be used.
   52 
   53   > mySplices = [ ("loginLogout", loginLogoutSplice) ]
   54   >
   55   > main = do
   56   >     ets <- loadTemplates "templates" $
   57   >            bindSplices mySplices (emptyTemplateState "templates")
   58   >     let ts = either error id ets
   59   >     t <- runMyAppMonad $ renderTemplate ts "index"
   60   >     print $ maybe "Page not found" (toByteString . fst) t
   61 
   62   Here we build up our 'TemplateState' by starting with emptyTemplateState and
   63   applying bindSplice for all the splices we want to add.  Then we pass this
   64   to loadTemplates our final 'TemplateState' wrapped in an Either to handle
   65   errors.  Then we use this 'TemplateState' to render our templates.
   66 
   67 -}
   68 
   69 module Text.Templating.Heist
   70   (
   71     -- * Types
   72     Template
   73   , MIMEType
   74   , Splice
   75   , TemplateMonad
   76   , HeistT
   77   , TemplateState
   78 
   79     -- * Functions and declarations on TemplateState values
   80   , addTemplate
   81   , addXMLTemplate
   82   , emptyTemplateState
   83   , bindSplice
   84   , bindSplices
   85   , lookupSplice
   86   , setTemplates
   87   , loadTemplates
   88   , hasTemplate
   89   , addTemplatePathPrefix
   90 
   91     -- * Hook functions
   92     -- $hookDoc
   93   , addOnLoadHook
   94   , addPreRunHook
   95   , addPostRunHook
   96 
   97     -- * HeistT functions
   98   , stopRecursion
   99   , getParamNode
  100   , runNodeList
  101   , getContext
  102   , getTemplateFilePath
  103 
  104   , localParamNode
  105   , getsTS
  106   , getTS
  107   , putTS
  108   , modifyTS
  109   , restoreTS
  110   , localTS
  111 
  112     -- * Functions for running splices and templates
  113   , evalTemplate
  114   , callTemplate
  115   , renderTemplate
  116   , renderWithArgs
  117   , bindStrings
  118   , bindString
  119 
  120     -- * Functions for creating splices
  121   , textSplice
  122   , runChildren
  123   , runChildrenWith
  124   , runChildrenWithTrans
  125   , runChildrenWithTemplates
  126   , runChildrenWithText
  127   , mapSplices
  128 
  129     -- * Misc functions
  130   , getDoc
  131   , getXMLDoc
  132   , bindStaticTag
  133 
  134   ) where
  135 
  136 import           Control.Monad.Trans
  137 import qualified Data.Map as Map
  138 import           Text.Templating.Heist.Internal
  139 import           Text.Templating.Heist.Splices
  140 import           Text.Templating.Heist.Types
  141 
  142 
  143 ------------------------------------------------------------------------------
  144 -- | The default set of built-in splices.
  145 defaultSpliceMap :: MonadIO m => SpliceMap m
  146 defaultSpliceMap = Map.fromList
  147     [(applyTag, applyImpl)
  148     ,(bindTag, bindImpl)
  149     ,(ignoreTag, ignoreImpl)
  150     ,(markdownTag, markdownSplice)
  151     ]
  152 
  153 
  154 ------------------------------------------------------------------------------
  155 -- | An empty template state, with Heist's default splices (@\<apply\>@,
  156 -- @\<bind\>@, @\<ignore\>@, and @\<markdown\>@) mapped.  The static tag is
  157 -- not mapped here because it must be mapped manually in your application.
  158 emptyTemplateState :: MonadIO m => TemplateState m
  159 emptyTemplateState =
  160     TemplateState (defaultSpliceMap) Map.empty True [] 0
  161                   return return return [] Nothing
  162 
  163 
  164 -- $hookDoc
  165 -- Heist hooks allow you to modify templates when they are loaded and before
  166 -- and after they are run.  Every time you call one of the addAbcHook
  167 -- functions the hook is added to onto the processing pipeline.  The hooks
  168 -- processes the template in the order that they were added to the
  169 -- TemplateState.
  170 --
  171 -- The pre-run and post-run hooks are run before and after every template is
  172 -- run/rendered.  You should be careful what code you put in these hooks
  173 -- because it can significantly affect the performance of your site.
  174