-- © 2001-2003 Peter Thiemann
module WASH.HTML.HTMLBase
{-
(ATTR_(), attr_, attr_name, attr_value
,ELEMENT_(), element_, empty_, cdata_, comment_, doctype_
,CDATA_OPTIONS(..)
,add_, add_attr_
,get_attrs_
,BT(..)
,element_S, empty_S, cdata_S, comment_S, doctype_S
,element_T, empty_T, cdata_T, comment_T, doctype_T
,attr_SS, attr_SD, attr_TS, attr_TD
,showTemplatified)
-}
where
import Char
data BT = STATIC | DYNAMIC | TOPLEVEL
-- untyped layer
-- attributes
data ATTR_ =
ATTR_ { attr_BT :: BT
, attr_value_BT :: BT
, attr_name :: String
, attr_value :: String
}
attr_ = ATTR_ DYNAMIC DYNAMIC
attr_SS = ATTR_ STATIC STATIC
attr_SD = ATTR_ STATIC DYNAMIC
attr_TS = ATTR_ TOPLEVEL STATIC
attr_TD = ATTR_ TOPLEVEL DYNAMIC
-- elements
data ELEMENT_ =
ELEMENT_ { elem_BT :: BT
, tag :: String
, attrs :: [ATTR_]
, elems :: [ELEMENT_]
}
| EMPTY_ { elem_BT :: BT
, tag :: String
, attrs :: [ATTR_]
}
| CDATA_ { elem_BT :: BT
, elem_cdata :: String
}
| COMMENT_ { elem_BT :: BT
, elem_comment :: String
}
| DOCTYPE_ { elem_BT :: BT
, doctype :: [String]
, elems :: [ELEMENT_]
}
data CDATA_OPTIONS = CDATA_ENCODED | CDATA_FORMATTED
deriving (Eq)
element_ = ELEMENT_ DYNAMIC
element_S = ELEMENT_ STATIC
element_T = ELEMENT_ TOPLEVEL
empty_ = EMPTY_ DYNAMIC
empty_S = EMPTY_ STATIC
empty_T = EMPTY_ TOPLEVEL
makeEncoder opt = format . encode
where format | CDATA_FORMATTED `elem` opt = id
| otherwise = htmlFormat
encode | CDATA_ENCODED `elem` opt = id
| otherwise = htmlEncode
cdata_ opt = CDATA_ DYNAMIC . makeEncoder opt
cdata_S opt = CDATA_ STATIC . makeEncoder opt
cdata_T opt = CDATA_ TOPLEVEL . makeEncoder opt
comment_ = COMMENT_ DYNAMIC
comment_S = COMMENT_ STATIC
comment_T = COMMENT_ TOPLEVEL
doctype_ = DOCTYPE_ DYNAMIC
doctype_S = DOCTYPE_ STATIC
doctype_T = DOCTYPE_ TOPLEVEL
add_ e_ e'_ = e_ { elems = e'_ : elems e_}
-- | Takes element and attribute. Attaches attribute to the element. Replaces
-- prior attribute with same name.
add_attr_ e_ att =
let nameOfAtt = attr_name att
all_attrs = attrs e_
f [] = Nothing
f (att' : attrs) = if attr_name att' == nameOfAtt
then return (att : attrs)
else f attrs >>= \ attrs' -> return (att' : attrs')
new_attrs = case f all_attrs of
Nothing -> att : all_attrs
Just attrs -> attrs
in e_ { attrs = new_attrs }
get_attrs_ = attrs
-- show functions
instance Show ATTR_ where
showsPrec i = shows_attribute
showList = shows_attributes
shows_attributes :: [ATTR_] -> ShowS
shows_attributes atts = foldr (.) id (map shows_attribute atts)
shows_attribute :: ATTR_ -> ShowS
shows_attribute a =
showChar ' ' . showString (attr_name a) .
case attr_value a of
"()" ->
id
str@('\"':_) ->
showString "=\"" . htmlAttr (read str) . showString "\""
str ->
showString "=\"" . htmlAttr str . showString "\""
instance Show ELEMENT_ where
showsPrec i = shows_element
showList = shows_elements
shows_elements :: [ELEMENT_] -> ShowS
shows_elements elts = foldr (.) id (reverse (map shows_element elts))
shows_element :: ELEMENT_ -> ShowS
shows_element (EMPTY_ bt tag atts) =
showChar '<' . showString tag . shows atts . showString "\n/>"
shows_element (ELEMENT_ bt tag atts elts) =
showChar '<' . showString tag . shows atts . showChar '>'
. shows_elements elts
. showString "" . showString tag . showString "\n>"
shows_element (DOCTYPE_ bt strs elems) =
showString " showChar ' ' . showString str . f) id strs . showString "\n>" .
showString "" .
shows_elements elems .
showChar '\n'
shows_element (CDATA_ bt str) =
showString str
shows_element (COMMENT_ bt str) =
showString ""
-- |removes illegal characters and sequences of -- from comment
commentEncode :: String -> ShowS
commentEncode "" ys = ys
commentEncode ('-':xs@('-':_)) ys = '-':' ': commentEncode xs ys
commentEncode (x:xs) ys =
if x == chr 0x9 ||
x == chr 0xa ||
x == chr 0xd ||
x >= chr 0x20 && x <= chr 0xd7ff ||
x >= chr 0xe000 && x <= chr 0xfffd ||
x >= chr 0x10000 && x <= chr 0x10ffff
then x: commentEncode xs ys
else '?': commentEncode xs ys
htmlForbiddenChars = "<&\""
htmlEncode :: String -> String
htmlEncode s = htmlAttr s ""
htmlFormat s = s
htmlAttr :: String -> ShowS
htmlAttr "" = id
htmlAttr (x:xs) =
(if x `elem` htmlForbiddenChars
then showString "" . shows (ord x) . showChar ';'
else showChar x) . htmlAttr xs
{--htmlFormat "" = ""
htmlFormat (x:xs) =
if isSpace x then
"\n " ++ htmlFormat (dropWhile isSpace xs)
else
x : htmlFormat xs
--}