~alcinnz/rhapsode

362b4f07b55d3fb955b29430dbf7da909f2c2b63 — Adrian Cochrane 5 years ago 7157dd6
Render CSS counters into the webpage!
2 files changed, 62 insertions(+), 3 deletions(-)

M src/Main.hs
M src/StyleTree.hs
M src/Main.hs => src/Main.hs +58 -2
@@ 13,7 13,7 @@ import qualified Data.ByteString.Lazy.Char8 as C8
import qualified Text.HTML.DOM as HTML
import qualified Text.XML as XML
import           Data.Text as Txt (pack, unpack, Text(..), append,
        words, unwords, head, last, stripStart, stripEnd)
        words, unwords, head, last, stripStart, stripEnd, intercalate)

import qualified Data.CSS.Syntax.StyleSheet as CSS
import qualified Data.CSS.Style as Style


@@ 39,7 39,7 @@ main = do
    let html = XML.documentRoot $ HTML.parseLBS $ HTTP.responseBody response
    style <- retreiveStyles html manager $ fromJust $ parseURI url
    let transcript = stylize style html
    C8.putStrLn $ renderElLBS $ styleToSSML transcript
    C8.putStrLn $ renderElLBS $ styleToSSML $ applyCounters transcript

renderElLBS el = XML.renderLBS XML.def $ XML.Document {
        XML.documentPrologue = XML.Prologue [] Nothing [],


@@ 71,3 71,59 @@ stylize styles html = H2C.traversePrepopulatedStyles buildChild buildNode buildT
            | otherwise = Just [Style.temp {content = content self}]
        buildNode self children = self {children = children}
        buildText _ txt = Style.temp {content = [Content txt]}

--------
---- Counters
--------
treeOrder :: (c -> c -> [Integer] -> StyleTree -> (c, StyleTree)) ->
        c -> c -> [Integer] -> [StyleTree] -> (c, [StyleTree])
treeOrder cb prevContext context (num:path) (node:nodes) = (tailContext, node' {children = children'} : nodes')
    where
        (selfContext, node') = cb prevContext context (num:path) node
        (childContext, children') = treeOrder cb selfContext selfContext (0:num:path) $ children node
        (tailContext, nodes') = treeOrder cb selfContext childContext (num + 1:path) nodes
treeOrder _ _ context _ [] = (context, [])
treeOrder _ _ _ [] _ = error "Invalid path during tree traversal!"

inheritCounters path counterSource valueSource = M.intersectionWith cb valueSource counterSource -- indexed by name & el-path
    where cb val source = [counter | path `elem` [p | (p, _) <- source], counter@(path, _) <- val]
instantiateCounter counters path name val = M.insertWith appendCounter name [(path, val)] counters
    where
        appendCounter new (old@((_:oldPath), _):olds)
            | oldPath == tail path = new ++ olds
            | otherwise =  new ++ (old:olds)
instantiateCounters path instruct counters = foldl cb counters instruct
    where cb counters' (name, value) = instantiateCounter counters' path name value
incrementCounter counters path name val = M.insertWith addCounter name [(path, val)] counters
    where addCounter ((_, new):_) ((path, old):rest) = (path, new + old):rest
incrementCounters path instruct counters = foldl cb counters instruct
    where cb counters' (name, value) = incrementCounter counters' path name value
setCounter counters path name val = M.insertWith setCounter' name [(path, val)] counters
    where setCounter' ((_, val):_) ((path, _):rest) = (path, val):rest
setCounters path instruct counters = foldl cb counters instruct
    where cb counters' (name, value) = setCounter counters' path name value

renderCounter counters (Content txt) = Content txt
renderCounter counters (Counter name)
    | Just ((_, count):_) <- name `M.lookup` counters = Content $ Txt.pack $ show count
    | otherwise = Content ""
renderCounter counters (Counters name sep)
    | Just counter <- name `M.lookup` counters = Content $ Txt.intercalate sep [
            Txt.pack $ show count | (_, count) <- reverse counter
        ]
    | otherwise = Content ""
renderCounters node counters = (counters, node {
        content = map (renderCounter counters) $ content node,
        counterSet = [(name, value) | (name, ((_, value):_)) <- M.toList counters]
    })

applyCounters root = root {
        children = snd $ treeOrder cb M.empty M.empty [0] $ children root
    } where
        cb :: M.Map Text [([Integer], Integer)] -> M.Map Text [([Integer], Integer)] ->
            [Integer] -> StyleTree -> (M.Map Text [([Integer], Integer)], StyleTree)
        cb counterSource valueSource path node = renderCounters node $
            setCounters path (counterSet node) $
            incrementCounters path (counterIncrement node) $
            instantiateCounters path (counterReset node) $
            inheritCounters path counterSource valueSource

M src/StyleTree.hs => src/StyleTree.hs +4 -1
@@ 67,7 67,7 @@ parseCue [Url source, Dimension _ n "dB"] = Just $ Cue source $ Just $ Unit' "dB
parseCue [Ident "none"] = Just NoCue
parseCue _ = Nothing

data StyleLeaf = Content {value :: Text} deriving Eq
data StyleLeaf = Content {value :: Text} | Counter Text | Counters Text Text deriving Eq

parseCounters _ [Ident "none"] = Just []
parseCounters _ [] = Just []


@@ 202,6 202,9 @@ instance Style.PropertyParser StyleTree where
    longhand _ self "cue-after" toks = (\val -> self {cueAfter = val}) <$> parseCue toks

    longhand _ self "content" [String txt] = Just self {content = [Content txt]}
    longhand _ self "content" [Function "counter", Ident c, LeftParen] = Just self {content = [Counter c]}
    longhand _ self "content" [Function "counters", Ident c, Comma, String sep, LeftParen] =
        Just self {content = [Counters c sep]}

    longhand _ self "counter-reset" toks = (\val -> self {counterReset = val}) <$> parseCounters 0 toks
    longhand _ self "counter-increment" toks = (\val -> self {counterIncrement = val}) <$> parseCounters 1 toks