packages feed

snaplet-lss-0.1.0.0: src/Snap/Snaplet/Lss.hs

{-# LANGUAGE OverloadedStrings #-}
module Snap.Snaplet.Lss (Lss(..), initLss, lssSplices) where

import           Control.Monad      (when)
import           Data.List          (isSuffixOf)
import           Data.Monoid
import           Data.Text          (Text)
import qualified Data.Text          as T
import qualified Data.Text.IO       as T
import           Data.Unique
import           Heist              (Splices, getParamNode,
                                     hcInterpretedSplices, ( ## ))
import           Heist.Interpreted  (Splice)
import           Prelude            hiding ((++))
import           Snap
import           Snap.Snaplet.Heist (Heist, addConfig)
import           System.Directory
import           System.FilePath
import qualified Text.XmlHtml       as X

import           Language.Lss

(++) :: Monoid d => d -> d -> d
(++) = mappend

data Lss = Lss

initLss :: Snaplet (Heist b) -> SnapletInit b Lss
initLss heist = makeSnaplet "lss" "" Nothing $ do
  dir <- getSnapletFilePath
  dirExists <- liftIO $ doesDirectoryExist dir
  when (not dirExists) $ liftIO $ createDirectory dir
  files <- map (dir </>) <$> liftIO (getDirectoryContents dir)
  st <- foldM (\s f -> do isF <- liftIO $ doesFileExist f
                          if not isF || not (".lss" `isSuffixOf` f)
                             then return s
                             else do
                              c <- liftIO $ T.readFile f
                              case parseDefs c of
                                Left err -> error $ "Lss: Error parsing file " ++ f ++ ": " ++ err
                                Right stat -> return $ mappend s stat)
              mempty
              files
  addConfig heist mempty { hcInterpretedSplices = lssSplices st }
  return Lss


lssSplices :: (MonadIO m, Functor m) => LssState -> Splices (Splice m)
lssSplices st = "lss" ## lssSplice
  where lssSplice =
          do n <- getParamNode
             case X.getAttribute "apply" n of
               Nothing -> error "Lss: Can't apply <lss> tag without `apply` attribute."
               Just a ->
                 case parseApp a of
                   Left err -> error $ "Lss: error parsing `apply` attribute: " ++ err
                   Right (LssApp ident args) ->
                     do case apply st ident args  of
                          Left err -> error $ "Lss: error applying " ++ (T.unpack $ unIdent ident)
                                           ++ ": " ++ T.unpack err
                          Right rules -> do
                            let childs = case X.getAttribute "class" n of
                                           Nothing -> X.elementChildren n
                                           Just cls -> map (addClass cls) (X.elementChildren n)
                            sym <- (("lss" ++) . show . hashUnique) <$> liftIO newUnique
                            return $ attach sym rules childs
          where addClass newCls n@(X.Element _ attrs _) =
                  let classAttr = case lookup "class" attrs  of
                                    Nothing -> ("class", newCls)
                                    Just cls -> ("class", newCls ++ " " ++ cls)
                  in n { X.elementAttrs = classAttr : filter ((/= "class").fst) attrs}
                addClass _ n = n