{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.Blaze.Front.Renderer where
import qualified Data.ByteString.Char8 as SBC
import Data.List (isInfixOf)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.ByteString as S
import Data.Text.Lazy.Builder (Builder)
import qualified Data.Text.Lazy.Builder as TLB
import qualified Data.Text.Lazy as TL
import Prelude hiding (span)
import Text.Blaze.Front
import Text.Blaze.Front.Internal
import qualified Text.Blaze.Html as B
import Bridge
escapeMarkupEntities :: Text
-> Builder
escapeMarkupEntities = T.foldr escape mempty
where
escape :: Char -> Builder -> Builder
escape '<' b = TLB.fromText "<" `mappend` b
escape '>' b = TLB.fromText ">" `mappend` b
escape '&' b = TLB.fromText "&" `mappend` b
escape '"' b = TLB.fromText """ `mappend` b
escape '\'' b = TLB.fromText "'" `mappend` b
escape x b = TLB.singleton x `mappend` b
fromChoiceString :: ChoiceString
-> Builder
-> Builder
fromChoiceString (Static s) = (((TLB.fromText . getText) s) `mappend`)
fromChoiceString (String s) = (((escapeMarkupEntities . T.pack) s) `mappend`)
fromChoiceString (Text s) = ((escapeMarkupEntities s) `mappend`)
fromChoiceString (ByteString s) = (((TLB.fromText . T.pack . SBC.unpack) s) `mappend`)
fromChoiceString (PreEscaped x) =
case x of
String s -> (((TLB.fromText . T.pack) s) `mappend`)
Text s -> ((TLB.fromText s) `mappend`)
s -> fromChoiceString s
fromChoiceString (External x) = case x of
String s -> if "</" `isInfixOf` s then id else (((TLB.fromText . T.pack) s) `mappend`)
Text s -> if "</" `T.isInfixOf` s then id else ((TLB.fromText s) `mappend`)
ByteString s -> if "</" `S.isInfixOf` s then id else (((TLB.fromText . T.pack . SBC.unpack) s) `mappend`)
s -> fromChoiceString s
fromChoiceString (AppendChoiceString x y) =
fromChoiceString x . fromChoiceString y
fromChoiceString EmptyChoiceString = id
render
:: Show act
=> Markup act
-> Builder
-> Builder
render = go 0 id
where
go :: forall act' b. Int
-> (Builder -> Builder)
-> MarkupM act' b
-> Builder -> Builder
go i attrs (Parent _ open close content) =
ind i
. (((TLB.fromText . getText) open) `mappend`)
. attrs . ((TLB.fromText ">\n") `mappend`)
. go (inc i) id content . ind i
. (((TLB.fromText . getText) close) `mappend`)
. ((TLB.singleton '\n') `mappend`)
go i attrs (CustomParent tag content) =
ind i
. ((TLB.singleton '<') `mappend`)
. fromChoiceString tag . (attrs)
. ((TLB.fromText ">\n") `mappend`)
. go (inc i) id content . ind i
. ((TLB.fromText "</") `mappend`)
. fromChoiceString tag
. ((TLB.fromText ">\n") `mappend`)
go i attrs (Leaf _ begin end) =
ind i
. (((TLB.fromText . getText) begin) `mappend`)
. (attrs)
. (((TLB.fromText . getText) end) `mappend`)
. ((TLB.singleton '\n') `mappend`)
go i attrs (CustomLeaf tag close) =
ind i
. ((TLB.singleton '<') `mappend`)
. fromChoiceString tag . attrs
. ((TLB.fromText (if close then " />\n" else ">\n")) `mappend`)
go i attrs (AddAttribute _ key value h) = flip (go i) h $
(((TLB.fromText . getText) key) `mappend`)
. fromChoiceString value
. ((TLB.singleton '"') `mappend`) . attrs
go i attrs (AddCustomAttribute key value h) = flip (go i) h $
((TLB.singleton ' ') `mappend`)
. fromChoiceString key
. ((TLB.fromText "=\"") `mappend`)
. fromChoiceString value
. ((TLB.singleton '"') `mappend`) . attrs
go i _ (Content content) = ind i . fromChoiceString content
. ((TLB.singleton '\n') `mappend`)
go i attrs (Append h1 h2) = go i attrs h1 . go i attrs h2
go _ _ (Empty) = id
go _ _ (MapActions _ _) = id
go i attrs (OnEvent _ h) = go i attrs h
{-# NOINLINE go #-}
inc = (+) 4
ind i = ((TLB.fromString (replicate i ' ')) `mappend`)
{-# INLINE render #-}
renderHtml
:: Show act
=> Markup act
-> String
renderHtml html = TL.unpack . TLB.toLazyText $ render html TLB.flush
{-# INLINE renderHtml #-}
data EventType
= OnCopyE | OnCutE | OnPasteE
| OnKeyDownE | OnKeyPressE | OnKeyUpE
| OnFocusE | OnBlurE
| OnChangeE | OnInputE | OnSubmitE
| OnClickE | OnDoubleClickE | OnDragE | OnDragEndE | OnDragEnterE
| OnDragExitE | OnDragLeaveE | OnDragOverE | OnDragStartE | OnDropE
| OnMouseDownE | OnMouseEnterE | OnMouseLeaveE | OnMouseMoveE
| OnMouseOutE | OnMouseOverE | OnMouseUpE
| OnTouchCancelE | OnTouchEndE | OnTouchMoveE | OnTouchStartE
| OnScrollE
| OnWheelE
eventName :: EventType -> String
eventName _ = ""
data Handler
= IgnoreEvent
| HandleEvent (IO (Bool -> IO ()))
registerEvents
:: Markup a -> [CallbackAction a] -> [CallbackAction a]
registerEvents x = go x
where
go :: MarkupM a b -> [CallbackAction a] -> [CallbackAction a]
go (MapActions _ _) = id
go (Parent _ _ _ content) = go content
go (CustomParent _ content) = go content
go (Leaf _ _ _) = id
go (CustomLeaf _ _) = id
go (Content _) = id
go (Append a b) = (go a) . (go b)
go (AddAttribute _ _ _ a) = go a
go (AddCustomAttribute _ _ a) = go a
go Empty = id
go (OnEvent eh a) = ((reg eh) :) . (go a)
reg x' = CallbackAction x'
renderNewMarkup :: Show act => Markup act -> B.Html
renderNewMarkup = B.preEscapedToHtml . T.pack . renderHtml