{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | Defines operations on html data types.
module Zenacy.HTML.Internal.Oper
  ( htmlNodeIsElem
  , htmlNodeIsText
  , htmlNodeContent
  , htmlNodeContentSet
  , htmlNodeShow
  , htmlNodeFind
  , htmlNodeCount
  , htmlNodeCountM
  , htmlTextSpace
  , htmlTextAppend
  , htmlTextPrepend
  , htmlAttrHasName
  , htmlAttrRename
  , htmlElemAttr
  , htmlElemAttrCount
  , htmlElemAttrFind
  , htmlElemAttrFindName
  , htmlElemAttrApply
  , htmlElemAttrFilter
  , htmlElemAttrMap
  , htmlElemHasAttr
  , htmlElemHasAttrName
  , htmlElemHasAttrVal
  , htmlElemHasAttrValInfix
  , htmlElemAddAttr
  , htmlElemSetAttr
  , htmlElemGetAttr
  , htmlElemAttrRemove
  , htmlElemRemoveAllAttr
  , htmlElemAttrRename
  , htmlElemID
  , htmlElemIDSet
  , htmlElemHasID
  , htmlElemFindID
  , htmlElemClass
  , htmlElemClassSet
  , htmlElemClasses
  , htmlElemClassesSet
  , htmlElemClassesAdd
  , htmlElemClassesRemove
  , htmlElemClassesContains
  , htmlElemStyle
  , htmlElemStyles
  , htmlElemStyleParseURL
  , htmlElemContent
  , htmlElemContentSet
  , htmlElemHasContent
  , htmlElemNodeFirst
  , htmlElemNodeLast
  , htmlElemNodeCount
  , htmlElemName
  , htmlElemHasName
  , htmlElemRename
  , htmlElemFindElem
  , htmlElemFindElemNamed
  , htmlElemHasElem
  , htmlElemHasElemNamed
  , htmlElemContentApply
  , htmlElemContentMap
  , htmlElemContentFilter
  , htmlElemSearch
  , htmlElemText
  , htmlDocHtml
  , htmlDocBody
  , htmlDocHead
  , htmlDocTitle
  , htmlMapElem
  , htmlMapElemM
  , htmlElemCollapse
  , htmlElemCollapseM
  ) where

import Zenacy.HTML.Internal.Core
import Zenacy.HTML.Internal.HTML
import Control.Monad
  ( (>=>)
  )
import Control.Monad.Extra as X
  ( whenJust
  , whenJustM
  , concatMapM
  , ifM
  )
-- import Control.Monad.Identity
--   ( runIdentity
--   )
import Data.Char
  ( isSpace
  )
import Data.Functor.Identity
  ( runIdentity
  )
import Data.List
  ( find
  )
import Data.List.Extra
  ( firstJust
  )
import Data.Map
  ( Map
  )
import qualified Data.Map as Map
  ( empty
  , fromList
  , lookup
  )
import Data.Maybe
  ( listToMaybe
  , isJust
  )
import Data.Monoid
  ( (<>)
  )
import Data.Set
  ( Set
  )
import qualified Data.Set as Set
  ( delete
  , empty
  , fromList
  , insert
  , member
  , notMember
  , toList
  , union
  , unions
  )
import Data.Text
  ( Text
  )
import qualified Data.Text as T
  ( all
  , append
  , breakOn
  , concat
  , drop
  , dropAround
  , empty
  , isInfixOf
  , isPrefixOf
  , null
  , split
  , splitOn
  , strip
  , words
  , unwords
  )
import Data.Tuple.Extra
  ( first
  , second
  )

-- | Determines if a node is an element node.
htmlNodeIsElem :: HTMLNode -> Bool
htmlNodeIsElem :: HTMLNode -> Bool
htmlNodeIsElem HTMLElement {} = Bool
True
htmlNodeIsElem HTMLNode
_ = Bool
False

-- | Determines if a node is a text node.
htmlNodeIsText :: HTMLNode -> Bool
htmlNodeIsText :: HTMLNode -> Bool
htmlNodeIsText HTMLText {} = Bool
True
htmlNodeIsText HTMLNode
_ = Bool
False

-- | Gets the content of a node.
htmlNodeContent :: HTMLNode -> [HTMLNode]
htmlNodeContent :: HTMLNode -> [HTMLNode]
htmlNodeContent (HTMLDocument Text
_ [HTMLNode]
c) = [HTMLNode]
c
htmlNodeContent (HTMLFragment Text
_ [HTMLNode]
c) = [HTMLNode]
c
htmlNodeContent (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ [HTMLNode]
c) = [HTMLNode]
c
htmlNodeContent HTMLNode
_ = []

-- | Sets the content of a node.
htmlNodeContentSet :: [HTMLNode] -> HTMLNode -> HTMLNode
htmlNodeContentSet :: [HTMLNode] -> HTMLNode -> HTMLNode
htmlNodeContentSet [HTMLNode]
x (HTMLDocument Text
n [HTMLNode]
c) = Text -> [HTMLNode] -> HTMLNode
HTMLDocument Text
n [HTMLNode]
x
htmlNodeContentSet [HTMLNode]
x (HTMLFragment Text
n [HTMLNode]
c) = Text -> [HTMLNode] -> HTMLNode
HTMLFragment Text
n [HTMLNode]
x
htmlNodeContentSet [HTMLNode]
x (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
x
htmlNodeContentSet [HTMLNode]
x HTMLNode
y = HTMLNode
y

-- | Shows the node without its content.
htmlNodeShow :: HTMLNode -> String
htmlNodeShow :: HTMLNode -> String
htmlNodeShow = HTMLNode -> String
forall a. Show a => a -> String
show (HTMLNode -> String)
-> (HTMLNode -> HTMLNode) -> HTMLNode -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [HTMLNode] -> HTMLNode -> HTMLNode
htmlNodeContentSet []

-- | Finds a child node using a predicate.
htmlNodeFind :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlNodeFind :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlNodeFind HTMLNode -> Bool
p HTMLNode
x = (HTMLNode -> Bool) -> [HTMLNode] -> Maybe HTMLNode
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find HTMLNode -> Bool
p ([HTMLNode] -> Maybe HTMLNode) -> [HTMLNode] -> Maybe HTMLNode
forall a b. (a -> b) -> a -> b
$ HTMLNode -> [HTMLNode]
htmlNodeContent HTMLNode
x

-- | Counts the number of nodes matching a predicate.
htmlNodeCount :: (HTMLNode -> Bool) -> HTMLNode -> Int
htmlNodeCount :: (HTMLNode -> Bool) -> HTMLNode -> Int
htmlNodeCount HTMLNode -> Bool
f = Identity Int -> Int
forall a. Identity a -> a
runIdentity (Identity Int -> Int)
-> (HTMLNode -> Identity Int) -> HTMLNode -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HTMLNode -> Identity Bool) -> HTMLNode -> Identity Int
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m Bool) -> HTMLNode -> m Int
htmlNodeCountM (Bool -> Identity Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> Identity Bool)
-> (HTMLNode -> Bool) -> HTMLNode -> Identity Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> Bool
f)

-- | Counts the number of nodes matching a predicate.
htmlNodeCountM :: Monad m => (HTMLNode -> m Bool) -> HTMLNode -> m Int
htmlNodeCountM :: (HTMLNode -> m Bool) -> HTMLNode -> m Int
htmlNodeCountM HTMLNode -> m Bool
f HTMLNode
x = do
  Int
n <- [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> m [Int] -> m Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (HTMLNode -> m Int) -> [HTMLNode] -> m [Int]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((HTMLNode -> m Bool) -> HTMLNode -> m Int
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m Bool) -> HTMLNode -> m Int
htmlNodeCountM HTMLNode -> m Bool
f) (HTMLNode -> [HTMLNode]
htmlNodeContent HTMLNode
x)
  m Bool -> m Int -> m Int -> m Int
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (HTMLNode -> m Bool
f HTMLNode
x) (Int -> m Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> m Int) -> Int -> m Int
forall a b. (a -> b) -> a -> b
$ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n) (Int -> m Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
n)

-- | Determines if a node is a text node containing only whitespace.
htmlTextSpace :: HTMLNode -> Bool
htmlTextSpace :: HTMLNode -> Bool
htmlTextSpace (HTMLText Text
x) = (Char -> Bool) -> Text -> Bool
T.all Char -> Bool
isSpace Text
x
htmlTextSpace HTMLNode
_ = Bool
False

-- | Appends text to a text node.
htmlTextAppend :: Text -> HTMLNode -> HTMLNode
htmlTextAppend :: Text -> HTMLNode -> HTMLNode
htmlTextAppend Text
a (HTMLText Text
x) = Text -> HTMLNode
HTMLText (Text -> HTMLNode) -> Text -> HTMLNode
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Text
T.append Text
x Text
a
htmlTextAppend Text
a HTMLNode
x = HTMLNode
x

-- | Prepends text to a text node.
htmlTextPrepend :: Text -> HTMLNode -> HTMLNode
htmlTextPrepend :: Text -> HTMLNode -> HTMLNode
htmlTextPrepend Text
a (HTMLText Text
x) = Text -> HTMLNode
HTMLText (Text -> HTMLNode) -> Text -> HTMLNode
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Text
T.append Text
a Text
x
htmlTextPrepend Text
a HTMLNode
x = HTMLNode
x

-- | A predicate for checking attribute names.
htmlAttrHasName :: Text -> HTMLAttr -> Bool
htmlAttrHasName :: Text -> HTMLAttr -> Bool
htmlAttrHasName Text
x HTMLAttr
a = Text
x Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== HTMLAttr -> Text
htmlAttrName HTMLAttr
a

-- | Renames an attribute.
htmlAttrRename :: Text -> HTMLAttr -> HTMLAttr
htmlAttrRename :: Text -> HTMLAttr -> HTMLAttr
htmlAttrRename Text
x (HTMLAttr Text
n Text
v HTMLAttrNamespace
s) = Text -> Text -> HTMLAttrNamespace -> HTMLAttr
HTMLAttr Text
x Text
v HTMLAttrNamespace
s

-- | Gets the attributes for an element.
htmlElemAttr :: HTMLNode -> [HTMLAttr]
htmlElemAttr :: HTMLNode -> [HTMLAttr]
htmlElemAttr (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
a [HTMLNode]
_) = [HTMLAttr]
a
htmlElemAttr HTMLNode
_ = []

-- | Gets the number of attributes for an element.
htmlElemAttrCount :: HTMLNode -> Int
htmlElemAttrCount :: HTMLNode -> Int
htmlElemAttrCount = [HTMLAttr] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([HTMLAttr] -> Int) -> (HTMLNode -> [HTMLAttr]) -> HTMLNode -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> [HTMLAttr]
htmlElemAttr

-- | Finds an attribute for an element.
htmlElemAttrFind :: (HTMLAttr -> Bool) -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFind :: (HTMLAttr -> Bool) -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFind HTMLAttr -> Bool
f (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
a [HTMLNode]
_) = (HTMLAttr -> Bool) -> [HTMLAttr] -> Maybe HTMLAttr
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find HTMLAttr -> Bool
f [HTMLAttr]
a
htmlElemAttrFind HTMLAttr -> Bool
_ HTMLNode
_ = Maybe HTMLAttr
forall a. Maybe a
Nothing

-- | Finds an attribute by name for an element.
htmlElemAttrFindName :: Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName :: Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName Text
x = (HTMLAttr -> Bool) -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFind ((HTMLAttr -> Bool) -> HTMLNode -> Maybe HTMLAttr)
-> (HTMLAttr -> Bool) -> HTMLNode -> Maybe HTMLAttr
forall a b. (a -> b) -> a -> b
$ Text -> HTMLAttr -> Bool
htmlAttrHasName Text
x

-- | Applies a function to the attributes for an element.
htmlElemAttrApply :: ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
htmlElemAttrApply :: ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
htmlElemAttrApply [HTMLAttr] -> [HTMLAttr]
f (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s ([HTMLAttr] -> [HTMLAttr]
f [HTMLAttr]
a) [HTMLNode]
c
htmlElemAttrApply [HTMLAttr] -> [HTMLAttr]
_ HTMLNode
x = HTMLNode
x

-- | Filters the attributes for an element.
htmlElemAttrFilter :: (HTMLAttr -> Bool) -> HTMLNode -> HTMLNode
htmlElemAttrFilter :: (HTMLAttr -> Bool) -> HTMLNode -> HTMLNode
htmlElemAttrFilter HTMLAttr -> Bool
f = ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
htmlElemAttrApply (([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode)
-> ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
forall a b. (a -> b) -> a -> b
$ (HTMLAttr -> Bool) -> [HTMLAttr] -> [HTMLAttr]
forall a. (a -> Bool) -> [a] -> [a]
filter HTMLAttr -> Bool
f

-- | Maps an endofunctor over an element attributes.
htmlElemAttrMap :: (HTMLAttr -> HTMLAttr) -> HTMLNode -> HTMLNode
htmlElemAttrMap :: (HTMLAttr -> HTMLAttr) -> HTMLNode -> HTMLNode
htmlElemAttrMap HTMLAttr -> HTMLAttr
f = ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
htmlElemAttrApply (([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode)
-> ([HTMLAttr] -> [HTMLAttr]) -> HTMLNode -> HTMLNode
forall a b. (a -> b) -> a -> b
$ (HTMLAttr -> HTMLAttr) -> [HTMLAttr] -> [HTMLAttr]
forall a b. (a -> b) -> [a] -> [b]
map HTMLAttr -> HTMLAttr
f

-- | Determines if the element has attributes.
htmlElemHasAttr :: HTMLNode -> Bool
htmlElemHasAttr :: HTMLNode -> Bool
htmlElemHasAttr HTMLNode
x = HTMLNode -> Int
htmlElemAttrCount HTMLNode
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0

-- | Determines if an element has an attribute.
htmlElemHasAttrName :: Text -> HTMLNode -> Bool
htmlElemHasAttrName :: Text -> HTMLNode -> Bool
htmlElemHasAttrName Text
x = Maybe HTMLAttr -> Bool
forall a. Maybe a -> Bool
isJust (Maybe HTMLAttr -> Bool)
-> (HTMLNode -> Maybe HTMLAttr) -> HTMLNode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName Text
x

-- | Determines if an element has an attribute value.
htmlElemHasAttrVal :: Text -> Text -> HTMLNode -> Bool
htmlElemHasAttrVal :: Text -> Text -> HTMLNode -> Bool
htmlElemHasAttrVal Text
x Text
y HTMLNode
z =
  Bool -> (HTMLAttr -> Bool) -> Maybe HTMLAttr -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\HTMLAttr
a -> Text
y Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== HTMLAttr -> Text
htmlAttrVal HTMLAttr
a) (Maybe HTMLAttr -> Bool) -> Maybe HTMLAttr -> Bool
forall a b. (a -> b) -> a -> b
$ Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName Text
x HTMLNode
z

-- | Determines if an element has part of an attribute value.
htmlElemHasAttrValInfix :: Text -> Text -> HTMLNode -> Bool
htmlElemHasAttrValInfix :: Text -> Text -> HTMLNode -> Bool
htmlElemHasAttrValInfix Text
x Text
y HTMLNode
z =
  Bool -> (HTMLAttr -> Bool) -> Maybe HTMLAttr -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (\HTMLAttr
a -> Text
y Text -> Text -> Bool
`T.isInfixOf` HTMLAttr -> Text
htmlAttrVal HTMLAttr
a) (Maybe HTMLAttr -> Bool) -> Maybe HTMLAttr -> Bool
forall a b. (a -> b) -> a -> b
$ Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName Text
x HTMLNode
z

-- | Adds an attribute to an element.
htmlElemAddAttr :: HTMLAttr -> HTMLNode -> HTMLNode
htmlElemAddAttr :: HTMLAttr -> HTMLNode -> HTMLNode
htmlElemAddAttr HTMLAttr
x (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s ([HTMLAttr]
a [HTMLAttr] -> [HTMLAttr] -> [HTMLAttr]
forall a. Semigroup a => a -> a -> a
<> [HTMLAttr
x]) [HTMLNode]
c
htmlElemAddAttr HTMLAttr
x HTMLNode
y = HTMLNode
y

-- | Sets an attribute value.
htmlElemSetAttr :: Text -> Text -> HTMLNode -> HTMLNode
htmlElemSetAttr :: Text -> Text -> HTMLNode -> HTMLNode
htmlElemSetAttr Text
x Text
v HTMLNode
n =
  if Text -> HTMLNode -> Bool
htmlElemHasAttrName Text
x HTMLNode
n
     then (HTMLAttr -> HTMLAttr) -> HTMLNode -> HTMLNode
htmlElemAttrMap HTMLAttr -> HTMLAttr
f HTMLNode
n
     else HTMLAttr -> HTMLNode -> HTMLNode
htmlElemAddAttr (Text -> Text -> HTMLAttr
htmlAttr Text
x Text
v) HTMLNode
n
  where
    f :: HTMLAttr -> HTMLAttr
f a :: HTMLAttr
a@(HTMLAttr Text
an Text
av HTMLAttrNamespace
as) =
      if Text
an Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
x then (Text -> Text -> HTMLAttrNamespace -> HTMLAttr
HTMLAttr Text
an Text
v HTMLAttrNamespace
as) else HTMLAttr
a

-- | Gets an attribute value.
htmlElemGetAttr :: Text -> HTMLNode -> Maybe Text
htmlElemGetAttr :: Text -> HTMLNode -> Maybe Text
htmlElemGetAttr Text
x HTMLNode
n = HTMLAttr -> Text
htmlAttrVal (HTMLAttr -> Text) -> Maybe HTMLAttr -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> HTMLNode -> Maybe HTMLAttr
htmlElemAttrFindName Text
x HTMLNode
n

-- | Removes an attribute from an element.
htmlElemAttrRemove :: Text -> HTMLNode -> HTMLNode
htmlElemAttrRemove :: Text -> HTMLNode -> HTMLNode
htmlElemAttrRemove Text
x (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a' [HTMLNode]
c
  where a' :: [HTMLAttr]
a' = (HTMLAttr -> Bool) -> [HTMLAttr] -> [HTMLAttr]
forall a. (a -> Bool) -> [a] -> [a]
filter (\HTMLAttr
y -> HTMLAttr -> Text
htmlAttrName HTMLAttr
y Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
/= Text
x) [HTMLAttr]
a
htmlElemAttrRemove Text
x HTMLNode
y = HTMLNode
y

-- | Removes all attributes from an element.
htmlElemRemoveAllAttr :: HTMLNode -> HTMLNode
htmlElemRemoveAllAttr :: HTMLNode -> HTMLNode
htmlElemRemoveAllAttr (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [] [HTMLNode]
c
htmlElemRemoveAllAttr HTMLNode
x = HTMLNode
x

-- | Renames an attribute for an element.
htmlElemAttrRename :: Text -> Text -> HTMLNode -> HTMLNode
htmlElemAttrRename :: Text -> Text -> HTMLNode -> HTMLNode
htmlElemAttrRename Text
old Text
new = (HTMLAttr -> HTMLAttr) -> HTMLNode -> HTMLNode
htmlElemAttrMap HTMLAttr -> HTMLAttr
rename
  where
    rename :: HTMLAttr -> HTMLAttr
rename HTMLAttr
x =
      if Text -> HTMLAttr -> Bool
htmlAttrHasName Text
old HTMLAttr
x
         then Text -> HTMLAttr -> HTMLAttr
htmlAttrRename Text
new HTMLAttr
x
         else HTMLAttr
x

-- | Gets the id attribute for an element.
htmlElemID :: HTMLNode -> Maybe Text
htmlElemID :: HTMLNode -> Maybe Text
htmlElemID = Text -> HTMLNode -> Maybe Text
htmlElemGetAttr Text
"id"

-- | Sets the id attribute for an element.
htmlElemIDSet :: Text -> HTMLNode -> HTMLNode
htmlElemIDSet :: Text -> HTMLNode -> HTMLNode
htmlElemIDSet = Text -> Text -> HTMLNode -> HTMLNode
htmlElemSetAttr Text
"id"

-- | Determines if an element has an id.
htmlElemHasID :: Text -> HTMLNode -> Bool
htmlElemHasID :: Text -> HTMLNode -> Bool
htmlElemHasID Text
x HTMLNode
y = HTMLNode -> Maybe Text
htmlElemID HTMLNode
y Maybe Text -> Maybe Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Maybe Text
forall a. a -> Maybe a
Just Text
x

-- | Searches for an element with an id.
htmlElemFindID :: Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindID :: Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindID Text
x = (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemSearch ((HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
forall a b. (a -> b) -> a -> b
$ Text -> HTMLNode -> Bool
htmlElemHasID Text
x

-- | Gets the id attribute for an element.
htmlElemClass :: HTMLNode -> Maybe Text
htmlElemClass :: HTMLNode -> Maybe Text
htmlElemClass = Text -> HTMLNode -> Maybe Text
htmlElemGetAttr Text
"class"

-- | Sets the class attribute for an element.
htmlElemClassSet :: Text -> HTMLNode -> HTMLNode
htmlElemClassSet :: Text -> HTMLNode -> HTMLNode
htmlElemClassSet = Text -> Text -> HTMLNode -> HTMLNode
htmlElemSetAttr Text
"class"

-- | Gets the element classes.
htmlElemClasses :: HTMLNode -> Set Text
htmlElemClasses :: HTMLNode -> Set Text
htmlElemClasses = Set Text -> (Text -> Set Text) -> Maybe Text -> Set Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Set Text
forall a. Set a
Set.empty ([Text] -> Set Text
forall a. Ord a => [a] -> Set a
Set.fromList ([Text] -> Set Text) -> (Text -> [Text]) -> Text -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.words) (Maybe Text -> Set Text)
-> (HTMLNode -> Maybe Text) -> HTMLNode -> Set Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> Maybe Text
htmlElemClass

-- | Sets the element classes.
htmlElemClassesSet :: Set Text -> HTMLNode -> HTMLNode
htmlElemClassesSet :: Set Text -> HTMLNode -> HTMLNode
htmlElemClassesSet Set Text
s = Text -> HTMLNode -> HTMLNode
htmlElemClassSet ([Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ Set Text -> [Text]
forall a. Set a -> [a]
Set.toList Set Text
s)

-- | Adds the class to the element's classes.
htmlElemClassesAdd :: Text -> HTMLNode -> HTMLNode
htmlElemClassesAdd :: Text -> HTMLNode -> HTMLNode
htmlElemClassesAdd Text
c HTMLNode
x =
  Set Text -> HTMLNode -> HTMLNode
htmlElemClassesSet (Text -> Set Text -> Set Text
forall a. Ord a => a -> Set a -> Set a
Set.insert Text
c (Set Text -> Set Text) -> Set Text -> Set Text
forall a b. (a -> b) -> a -> b
$ HTMLNode -> Set Text
htmlElemClasses HTMLNode
x) HTMLNode
x

-- | Removes a class from the element's classes.
htmlElemClassesRemove :: Text -> HTMLNode -> HTMLNode
htmlElemClassesRemove :: Text -> HTMLNode -> HTMLNode
htmlElemClassesRemove Text
c HTMLNode
x =
  Set Text -> HTMLNode -> HTMLNode
htmlElemClassesSet (Text -> Set Text -> Set Text
forall a. Ord a => a -> Set a -> Set a
Set.delete Text
c (Set Text -> Set Text) -> Set Text -> Set Text
forall a b. (a -> b) -> a -> b
$ HTMLNode -> Set Text
htmlElemClasses HTMLNode
x) HTMLNode
x

-- | Determines if the element contains a class.
htmlElemClassesContains :: Text -> HTMLNode -> Bool
htmlElemClassesContains :: Text -> HTMLNode -> Bool
htmlElemClassesContains Text
c = Text -> Set Text -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member Text
c (Set Text -> Bool) -> (HTMLNode -> Set Text) -> HTMLNode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> Set Text
htmlElemClasses

-- | Gets the style attribute for an element.
htmlElemStyle :: HTMLNode -> Maybe Text
htmlElemStyle :: HTMLNode -> Maybe Text
htmlElemStyle = Text -> HTMLNode -> Maybe Text
htmlElemGetAttr Text
"style"

-- | Gets the styles for an element.
htmlElemStyles :: HTMLNode -> Map Text Text
htmlElemStyles :: HTMLNode -> Map Text Text
htmlElemStyles =
  Map Text Text
-> (Text -> Map Text Text) -> Maybe Text -> Map Text Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Map Text Text
forall k a. Map k a
Map.empty Text -> Map Text Text
parse (Maybe Text -> Map Text Text)
-> (HTMLNode -> Maybe Text) -> HTMLNode -> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> Maybe Text
htmlElemStyle
  where
    parse :: Text -> Map Text Text
parse =
      ( [(Text, Text)] -> Map Text Text
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
      ([(Text, Text)] -> Map Text Text)
-> (Text -> [(Text, Text)]) -> Text -> Map Text Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> (Text, Text)) -> [Text] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
map
        ( (Text -> Text) -> (Text, Text) -> (Text, Text)
forall a a' b. (a -> a') -> (a, b) -> (a', b)
first Text -> Text
T.strip
        ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> (Text, Text) -> (Text, Text)
forall b b' a. (b -> b') -> (a, b) -> (a, b')
second Text -> Text
T.strip
        ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> (Text, Text) -> (Text, Text)
forall b b' a. (b -> b') -> (a, b) -> (a, b')
second (Int -> Text -> Text
T.drop Int
1)
        ((Text, Text) -> (Text, Text))
-> (Text -> (Text, Text)) -> Text -> (Text, Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> (Text, Text)
T.breakOn Text
":"
        )
      ([Text] -> [(Text, Text)])
-> (Text -> [Text]) -> Text -> [(Text, Text)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Bool) -> [Text] -> [Text]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Text -> Bool) -> Text -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null)
      ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Text -> Text
T.strip
      ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> [Text]
T.splitOn Text
";"
      )

-- | Parses and returns a url style value.
htmlElemStyleParseURL :: Text -> Maybe Text
htmlElemStyleParseURL :: Text -> Maybe Text
htmlElemStyleParseURL Text
x
  | Text
"url" Text -> Text -> Bool
`T.isPrefixOf` Text
x =
      ( Text -> Text
T.strip
      (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
T.dropAround (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
'\'')
      -- Only a stylesheet can have a double quote, but we check for it anyway.
      (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> Text
T.dropAround (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
'\"')
      (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
T.strip
      ) (Text -> Text) -> Maybe Text -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Text -> Text -> Maybe Text
textExtract Text
"(" Text
")" Text
x
  | Bool
otherwise = Maybe Text
forall a. Maybe a
Nothing

-- | Gets the children for the element if the node is an element.
htmlElemContent :: HTMLNode -> [HTMLNode]
htmlElemContent :: HTMLNode -> [HTMLNode]
htmlElemContent (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ [HTMLNode]
c) = [HTMLNode]
c
htmlElemContent HTMLNode
_ = []

-- | Sets the content for an element.
htmlElemContentSet :: [HTMLNode] -> HTMLNode -> HTMLNode
htmlElemContentSet :: [HTMLNode] -> HTMLNode -> HTMLNode
htmlElemContentSet [HTMLNode]
x (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
x
htmlElemContentSet [HTMLNode]
x HTMLNode
y = HTMLNode
y

-- | Determines if the element has children.
htmlElemHasContent :: HTMLNode -> Bool
htmlElemHasContent :: HTMLNode -> Bool
htmlElemHasContent (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ []) = Bool
False
htmlElemHasContent (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ (HTMLNode
x:[HTMLNode]
xs)) = Bool
True
htmlElemHasContent HTMLNode
_ = Bool
False

-- | Gets the first child for an element.
htmlElemNodeFirst :: HTMLNode -> Maybe HTMLNode
htmlElemNodeFirst :: HTMLNode -> Maybe HTMLNode
htmlElemNodeFirst = [HTMLNode] -> Maybe HTMLNode
forall a. [a] -> Maybe a
listToMaybe ([HTMLNode] -> Maybe HTMLNode)
-> (HTMLNode -> [HTMLNode]) -> HTMLNode -> Maybe HTMLNode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> [HTMLNode]
htmlElemContent

-- | Gets the last child for an element.
htmlElemNodeLast :: HTMLNode -> Maybe HTMLNode
htmlElemNodeLast :: HTMLNode -> Maybe HTMLNode
htmlElemNodeLast =  [HTMLNode] -> Maybe HTMLNode
forall a. [a] -> Maybe a
listToMaybe ([HTMLNode] -> Maybe HTMLNode)
-> (HTMLNode -> [HTMLNode]) -> HTMLNode -> Maybe HTMLNode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [HTMLNode] -> [HTMLNode]
forall a. [a] -> [a]
reverse ([HTMLNode] -> [HTMLNode])
-> (HTMLNode -> [HTMLNode]) -> HTMLNode -> [HTMLNode]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> [HTMLNode]
htmlElemContent

-- | Gets the number of children for an element.
htmlElemNodeCount :: HTMLNode -> Int
htmlElemNodeCount :: HTMLNode -> Int
htmlElemNodeCount = [HTMLNode] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([HTMLNode] -> Int) -> (HTMLNode -> [HTMLNode]) -> HTMLNode -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> [HTMLNode]
htmlElemContent

-- | Gets the name of an element.
htmlElemName :: HTMLNode -> Text
htmlElemName :: HTMLNode -> Text
htmlElemName (HTMLElement Text
n HTMLNamespace
_ [HTMLAttr]
_ [HTMLNode]
_) = Text
n
htmlElemName HTMLNode
_ = Text
T.empty

-- | Checks if the name of an element matches a specified name.
htmlElemHasName :: Text -> HTMLNode -> Bool
htmlElemHasName :: Text -> HTMLNode -> Bool
htmlElemHasName Text
x HTMLNode
y = HTMLNode -> Text
htmlElemName HTMLNode
y Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
x

-- | Sets the name of an element.
htmlElemRename :: Text -> HTMLNode -> HTMLNode
htmlElemRename :: Text -> HTMLNode -> HTMLNode
htmlElemRename Text
n (HTMLElement Text
_ HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c
htmlElemRename Text
n HTMLNode
x = HTMLNode
x

-- | Finds a child element using a predicate.
htmlElemFindElem :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemFindElem :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemFindElem HTMLNode -> Bool
p (HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ [HTMLNode]
c) = (HTMLNode -> Bool) -> [HTMLNode] -> Maybe HTMLNode
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find HTMLNode -> Bool
p [HTMLNode]
c
htmlElemFindElem HTMLNode -> Bool
_ HTMLNode
_ = Maybe HTMLNode
forall a. Maybe a
Nothing

-- | Finds a child element with a specified name.
htmlElemFindElemNamed :: Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed :: Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed Text
x = (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemFindElem ((HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
forall a b. (a -> b) -> a -> b
$ Text -> HTMLNode -> Bool
htmlElemHasName Text
x

-- | Determines if an element has a child.
htmlElemHasElem :: (HTMLNode -> Bool) -> HTMLNode -> Bool
htmlElemHasElem :: (HTMLNode -> Bool) -> HTMLNode -> Bool
htmlElemHasElem HTMLNode -> Bool
p = Maybe HTMLNode -> Bool
forall a. Maybe a -> Bool
isJust (Maybe HTMLNode -> Bool)
-> (HTMLNode -> Maybe HTMLNode) -> HTMLNode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemFindElem HTMLNode -> Bool
p

-- | Determines if an element has a child.
htmlElemHasElemNamed :: Text -> HTMLNode -> Bool
htmlElemHasElemNamed :: Text -> HTMLNode -> Bool
htmlElemHasElemNamed Text
x = Maybe HTMLNode -> Bool
forall a. Maybe a -> Bool
isJust (Maybe HTMLNode -> Bool)
-> (HTMLNode -> Maybe HTMLNode) -> HTMLNode -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed Text
x

-- | Modifies an elements children by applying a function.
htmlElemContentApply :: ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
htmlElemContentApply :: ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
htmlElemContentApply [HTMLNode] -> [HTMLNode]
f (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a ([HTMLNode] -> HTMLNode) -> [HTMLNode] -> HTMLNode
forall a b. (a -> b) -> a -> b
$ [HTMLNode] -> [HTMLNode]
f [HTMLNode]
c
htmlElemContentApply [HTMLNode] -> [HTMLNode]
_ HTMLNode
x = HTMLNode
x

-- | Modifies an elements children by mapping a function over them.
htmlElemContentMap :: (HTMLNode -> HTMLNode) -> HTMLNode -> HTMLNode
htmlElemContentMap :: (HTMLNode -> HTMLNode) -> HTMLNode -> HTMLNode
htmlElemContentMap HTMLNode -> HTMLNode
f = ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
htmlElemContentApply (([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode)
-> ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
forall a b. (a -> b) -> a -> b
$ (HTMLNode -> HTMLNode) -> [HTMLNode] -> [HTMLNode]
forall a b. (a -> b) -> [a] -> [b]
map HTMLNode -> HTMLNode
f

-- | Modifies an elements children by filtering them.
htmlElemContentFilter :: (HTMLNode -> Bool) -> HTMLNode -> HTMLNode
htmlElemContentFilter :: (HTMLNode -> Bool) -> HTMLNode -> HTMLNode
htmlElemContentFilter HTMLNode -> Bool
f = ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
htmlElemContentApply (([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode)
-> ([HTMLNode] -> [HTMLNode]) -> HTMLNode -> HTMLNode
forall a b. (a -> b) -> a -> b
$ (HTMLNode -> Bool) -> [HTMLNode] -> [HTMLNode]
forall a. (a -> Bool) -> [a] -> [a]
filter HTMLNode -> Bool
f

-- | Finds an element using a depth-first search.
htmlElemSearch :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemSearch :: (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemSearch HTMLNode -> Bool
f HTMLNode
x = case HTMLNode
x of
  HTMLElement Text
_ HTMLNamespace
_ [HTMLAttr]
_ [HTMLNode]
c ->
    if HTMLNode -> Bool
f HTMLNode
x then HTMLNode -> Maybe HTMLNode
forall a. a -> Maybe a
Just HTMLNode
x else (HTMLNode -> Maybe HTMLNode) -> [HTMLNode] -> Maybe HTMLNode
forall a b. (a -> Maybe b) -> [a] -> Maybe b
firstJust ((HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlElemSearch HTMLNode -> Bool
f) [HTMLNode]
c
  HTMLNode
_otherwise -> Maybe HTMLNode
forall a. Maybe a
Nothing

-- | Gets the text content for an element.
htmlElemText :: HTMLNode -> Maybe Text
htmlElemText :: HTMLNode -> Maybe Text
htmlElemText (HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) =
  case (HTMLNode -> Bool) -> [HTMLNode] -> [HTMLNode]
forall a. (a -> Bool) -> [a] -> [a]
filter HTMLNode -> Bool
htmlNodeIsText [HTMLNode]
c of
    a :: [HTMLNode]
a@(HTMLNode
x:[HTMLNode]
xs) -> Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text)
-> ([HTMLNode] -> Text) -> [HTMLNode] -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
T.concat ([Text] -> Text) -> ([HTMLNode] -> [Text]) -> [HTMLNode] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HTMLNode -> Text) -> [HTMLNode] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map HTMLNode -> Text
htmlTextData ([HTMLNode] -> Maybe Text) -> [HTMLNode] -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [HTMLNode]
a
    [] -> Maybe Text
forall a. Maybe a
Nothing
htmlElemText HTMLNode
_ = Maybe Text
forall a. Maybe a
Nothing

-- | Finds the html element given a document.
htmlDocHtml :: HTMLNode -> Maybe HTMLNode
htmlDocHtml :: HTMLNode -> Maybe HTMLNode
htmlDocHtml = (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
htmlNodeFind ((HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Bool) -> HTMLNode -> Maybe HTMLNode
forall a b. (a -> b) -> a -> b
$ Text -> HTMLNode -> Bool
htmlElemHasName Text
"html"

-- | Finds the body element given a document.
htmlDocBody :: HTMLNode -> Maybe HTMLNode
htmlDocBody :: HTMLNode -> Maybe HTMLNode
htmlDocBody = HTMLNode -> Maybe HTMLNode
htmlDocHtml (HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Maybe HTMLNode) -> HTMLNode -> Maybe HTMLNode
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed Text
"body"

-- | Finds the head element given a document.
htmlDocHead :: HTMLNode -> Maybe HTMLNode
htmlDocHead :: HTMLNode -> Maybe HTMLNode
htmlDocHead = HTMLNode -> Maybe HTMLNode
htmlDocHtml (HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Maybe HTMLNode) -> HTMLNode -> Maybe HTMLNode
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed Text
"head"

-- | Finds the title for a document.
htmlDocTitle :: HTMLNode -> Maybe Text
htmlDocTitle :: HTMLNode -> Maybe Text
htmlDocTitle = HTMLNode -> Maybe HTMLNode
htmlDocHead
  (HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Maybe Text) -> HTMLNode -> Maybe Text
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> Text -> HTMLNode -> Maybe HTMLNode
htmlElemFindElemNamed Text
"title"
  (HTMLNode -> Maybe HTMLNode)
-> (HTMLNode -> Maybe Text) -> HTMLNode -> Maybe Text
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> HTMLNode -> Maybe Text
htmlElemText

-- | Maps a function over all the elements defined by a node.
htmlMapElem :: (HTMLNode -> HTMLNode) -> HTMLNode -> HTMLNode
htmlMapElem :: (HTMLNode -> HTMLNode) -> HTMLNode -> HTMLNode
htmlMapElem HTMLNode -> HTMLNode
f = Identity HTMLNode -> HTMLNode
forall a. Identity a -> a
runIdentity (Identity HTMLNode -> HTMLNode)
-> (HTMLNode -> Identity HTMLNode) -> HTMLNode -> HTMLNode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HTMLNode -> Identity HTMLNode) -> HTMLNode -> Identity HTMLNode
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m HTMLNode) -> HTMLNode -> m HTMLNode
htmlMapElemM (HTMLNode -> Identity HTMLNode
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HTMLNode -> Identity HTMLNode)
-> (HTMLNode -> HTMLNode) -> HTMLNode -> Identity HTMLNode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> HTMLNode
f)

-- | Maps a function over all the elements defined by a node.
htmlMapElemM :: Monad m => (HTMLNode -> m HTMLNode) -> HTMLNode -> m HTMLNode

-- htmlMapElemM f x@(HTMLElement {}) = do
--   HTMLElement n s a c <- f x
--   HTMLElement n s a <$> mapM (htmlMapElemM f) c
-- htmlMapElemM f x = pure x

htmlMapElemM :: (HTMLNode -> m HTMLNode) -> HTMLNode -> m HTMLNode
htmlMapElemM HTMLNode -> m HTMLNode
f HTMLNode
x =
  case HTMLNode
x of
    HTMLElement {} -> do
      HTMLNode
a <- HTMLNode -> m HTMLNode
f HTMLNode
x
      case HTMLNode
a of
        HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c ->
          Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a ([HTMLNode] -> HTMLNode) -> m [HTMLNode] -> m HTMLNode
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (HTMLNode -> m HTMLNode) -> [HTMLNode] -> m [HTMLNode]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((HTMLNode -> m HTMLNode) -> HTMLNode -> m HTMLNode
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m HTMLNode) -> HTMLNode -> m HTMLNode
htmlMapElemM HTMLNode -> m HTMLNode
f) [HTMLNode]
c
        HTMLNode
_otherwise ->
          HTMLNode -> m HTMLNode
forall (f :: * -> *) a. Applicative f => a -> f a
pure HTMLNode
a
    HTMLNode
_otherwise ->
      HTMLNode -> m HTMLNode
forall (f :: * -> *) a. Applicative f => a -> f a
pure HTMLNode
x

-- | Collapses a tree of elements based on a predicate.
htmlElemCollapse :: (HTMLNode -> Bool) -> HTMLNode -> [HTMLNode]
htmlElemCollapse :: (HTMLNode -> Bool) -> HTMLNode -> [HTMLNode]
htmlElemCollapse HTMLNode -> Bool
f = Identity [HTMLNode] -> [HTMLNode]
forall a. Identity a -> a
runIdentity (Identity [HTMLNode] -> [HTMLNode])
-> (HTMLNode -> Identity [HTMLNode]) -> HTMLNode -> [HTMLNode]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HTMLNode -> Identity Bool) -> HTMLNode -> Identity [HTMLNode]
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m Bool) -> HTMLNode -> m [HTMLNode]
htmlElemCollapseM (Bool -> Identity Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> Identity Bool)
-> (HTMLNode -> Bool) -> HTMLNode -> Identity Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HTMLNode -> Bool
f)

-- | Collapses a tree of elements based on a predicate.
htmlElemCollapseM :: Monad m => (HTMLNode -> m Bool) -> HTMLNode -> m [HTMLNode]
htmlElemCollapseM :: (HTMLNode -> m Bool) -> HTMLNode -> m [HTMLNode]
htmlElemCollapseM HTMLNode -> m Bool
f x :: HTMLNode
x@(HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c) = do
  [HTMLNode]
c' <- (HTMLNode -> m [HTMLNode]) -> [HTMLNode] -> m [HTMLNode]
forall (m :: * -> *) a b. Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM ((HTMLNode -> m Bool) -> HTMLNode -> m [HTMLNode]
forall (m :: * -> *).
Monad m =>
(HTMLNode -> m Bool) -> HTMLNode -> m [HTMLNode]
htmlElemCollapseM HTMLNode -> m Bool
f) [HTMLNode]
c
  m Bool -> m [HTMLNode] -> m [HTMLNode] -> m [HTMLNode]
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (HTMLNode -> m Bool
f HTMLNode
x) ([HTMLNode] -> m [HTMLNode]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [HTMLNode]
c') (m [HTMLNode] -> m [HTMLNode]) -> m [HTMLNode] -> m [HTMLNode]
forall a b. (a -> b) -> a -> b
$ [HTMLNode] -> m [HTMLNode]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [ Text -> HTMLNamespace -> [HTMLAttr] -> [HTMLNode] -> HTMLNode
HTMLElement Text
n HTMLNamespace
s [HTMLAttr]
a [HTMLNode]
c' ]
htmlElemCollapseM HTMLNode -> m Bool
_ HTMLNode
x = [HTMLNode] -> m [HTMLNode]
forall (f :: * -> *) a. Applicative f => a -> f a
pure [HTMLNode
x]