From 8376d6298b8d9c2b94f28dc73b7a19410b580a62 Mon Sep 17 00:00:00 2001 From: Stefan Dresselhaus Date: Sat, 2 Sep 2017 16:44:20 +0200 Subject: [PATCH] Created library instead of binaries. Added doc. - Split things into Library and Binary - Library has all functionality - Binarys are just wrapper like "main = toJsonFilter foo" - Documented most things - Created haddock-documentation - added documentation to repository --- TODO.md | 6 + app/Clean.hs | 3 - app/Cols.hs | 77 +-- app/Media.hs | 180 +----- app/Quiz.hs | 37 +- app/Styling.hs | 71 +- doc/Text-Pandoc-Util-Filter-Cols.html | 19 + doc/Text-Pandoc-Util-Filter-Media.html | 10 + doc/Text-Pandoc-Util-Filter-Quiz.html | 4 + doc/Text-Pandoc-Util-Filter-Styling.html | 5 + doc/Text-Pandoc-Util-Filter.html | 19 + doc/doc-index.html | 4 + doc/haddock-util.js | 316 +++++++++ doc/hslogo-16.png | Bin 0 -> 1684 bytes doc/index.html | 4 + doc/mini_Text-Pandoc-Util-Filter-Cols.html | 4 + doc/mini_Text-Pandoc-Util-Filter-Media.html | 4 + doc/mini_Text-Pandoc-Util-Filter-Quiz.html | 4 + doc/mini_Text-Pandoc-Util-Filter-Styling.html | 4 + doc/mini_Text-Pandoc-Util-Filter.html | 4 + doc/minus.gif | Bin 0 -> 56 bytes doc/ocean.css | 612 ++++++++++++++++++ doc/pandoc-slide-filter.haddock | Bin 0 -> 12445 bytes doc/plus.gif | Bin 0 -> 59 bytes doc/src/Text.Pandoc.Util.Filter.Cols.html | 79 +++ doc/src/Text.Pandoc.Util.Filter.Media.html | 159 +++++ doc/src/Text.Pandoc.Util.Filter.Quiz.html | 40 ++ doc/src/Text.Pandoc.Util.Filter.Styling.html | 65 ++ doc/src/Text.Pandoc.Util.Filter.html | 103 +++ doc/src/highlight.js | 27 + doc/src/style.css | 55 ++ doc/synopsis.png | Bin 0 -> 11327 bytes pandoc-slide-filter.cabal | 19 +- src/Text/Pandoc/Util/Filter.hs | 102 +++ src/Text/Pandoc/Util/Filter/Cols.hs | 78 +++ src/Text/Pandoc/Util/Filter/Media.hs | 158 +++++ src/Text/Pandoc/Util/Filter/Quiz.hs | 39 ++ src/Text/Pandoc/Util/Filter/Styling.hs | 64 ++ 38 files changed, 2011 insertions(+), 364 deletions(-) create mode 100644 TODO.md create mode 100644 doc/Text-Pandoc-Util-Filter-Cols.html create mode 100644 doc/Text-Pandoc-Util-Filter-Media.html create mode 100644 doc/Text-Pandoc-Util-Filter-Quiz.html create mode 100644 doc/Text-Pandoc-Util-Filter-Styling.html create mode 100644 doc/Text-Pandoc-Util-Filter.html create mode 100644 doc/doc-index.html create mode 100644 doc/haddock-util.js create mode 100644 doc/hslogo-16.png create mode 100644 doc/index.html create mode 100644 doc/mini_Text-Pandoc-Util-Filter-Cols.html create mode 100644 doc/mini_Text-Pandoc-Util-Filter-Media.html create mode 100644 doc/mini_Text-Pandoc-Util-Filter-Quiz.html create mode 100644 doc/mini_Text-Pandoc-Util-Filter-Styling.html create mode 100644 doc/mini_Text-Pandoc-Util-Filter.html create mode 100644 doc/minus.gif create mode 100644 doc/ocean.css create mode 100644 doc/pandoc-slide-filter.haddock create mode 100644 doc/plus.gif create mode 100644 doc/src/Text.Pandoc.Util.Filter.Cols.html create mode 100644 doc/src/Text.Pandoc.Util.Filter.Media.html create mode 100644 doc/src/Text.Pandoc.Util.Filter.Quiz.html create mode 100644 doc/src/Text.Pandoc.Util.Filter.Styling.html create mode 100644 doc/src/Text.Pandoc.Util.Filter.html create mode 100644 doc/src/highlight.js create mode 100644 doc/src/style.css create mode 100644 doc/synopsis.png create mode 100644 src/Text/Pandoc/Util/Filter.hs create mode 100644 src/Text/Pandoc/Util/Filter/Cols.hs create mode 100644 src/Text/Pandoc/Util/Filter/Media.hs create mode 100644 src/Text/Pandoc/Util/Filter/Quiz.hs create mode 100644 src/Text/Pandoc/Util/Filter/Styling.hs diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..c701049 --- /dev/null +++ b/TODO.md @@ -0,0 +1,6 @@ + +- fragments in figure-Umgebung +- svg per default als img + - done +- reveal hat speziell html-attribute => herausfinden und in direct-controls rein + - in utils ~> müssen noch überall angepasst werden. diff --git a/app/Clean.hs b/app/Clean.hs index fcb5f71..1801343 100644 --- a/app/Clean.hs +++ b/app/Clean.hs @@ -2,9 +2,6 @@ {-# LANGUAGE ScopedTypeVariables #-} import Text.Pandoc.JSON -import Control.Exception -import Data.Monoid ((<>)) -import Data.List (partition, isInfixOf) main :: IO () main = toJSONFilter clean diff --git a/app/Cols.hs b/app/Cols.hs index d44db55..b9628b9 100644 --- a/app/Cols.hs +++ b/app/Cols.hs @@ -1,82 +1,9 @@ #!/usr/bin/env runhaskell -{-# LANGUAGE ScopedTypeVariables #-} import Text.Pandoc.JSON -import Text.Pandoc.Definition import Text.Pandoc.Generic (topDown) -import Control.Exception -import Data.Monoid ((<>)) -import Data.List (partition, elem) -import System.FilePath -import Debug.Trace (trace) -import Text.Read (readMaybe) -import Data.Maybe (fromMaybe) + +import Text.Pandoc.Util.Filter.Cols main :: IO () main = toJSONFilter (topDown cols :: Pandoc -> Pandoc) - - --- | This filter makes multi-column-layouts out of lvl-x-headings --- --- Syntax is --- --- ## a b --- --- yielding a 2-column-layout with aspects a:b i.e. 1:1 for 50/50-layout --- or 8:2 for 80/20 layout --- --- currently works for 2 and 3-columns, but extension is straight-forward. --- --- If you need multiple Block-Elements inside one column, just wrap them --- with a
: --- --- ## 2 5 --- ---
--- multiple things --- ``` --- foo --- ``` --- ![image](...) ---
--- --- second column here with only 1 element. --- -cols :: [Block] -> [Block] -cols (h@(Header 2 attr [Str wa,Space,Str wb]):a:b:rest) = - outerDiv:rest - where - wa' = fromMaybe 1 (readMaybe wa) :: Int - wb' = fromMaybe 1 (readMaybe wb) :: Int - total = wa' + wb' - pa = (100*wa') `div` total - pb = (100*wb') `div` total - outerDiv = Div attr [ makeDiv pa a - , makeDiv pb b - , clearDiv - ] -cols (h@(Header 3 attr [Str wa,Space,Str wb,Space,Str wc]):a:b:c:rest) = - outerDiv:rest - where - wa' = fromMaybe 1 (readMaybe wa) :: Int - wb' = fromMaybe 1 (readMaybe wb) :: Int - wc' = fromMaybe 1 (readMaybe wc) :: Int - total = wa' + wb' + wc' - pa = (100*wa') `div` total - pb = (100*wb') `div` total - pc = (100*wc') `div` total - outerDiv = Div attr [ makeDiv pa a - , makeDiv pb b - , makeDiv pc c - , clearDiv - ] -cols x = x - -makeDiv :: Int -> Block -> Block -makeDiv width content = Div ("", [], [("style","width:" <> show width <> "%;float:left")]) [content] - -clearDiv :: Block -clearDiv = Div ("", [], [("style", "clear: both")]) [Plain [toHtml " "]] - -toHtml :: String -> Inline -toHtml = RawInline (Format "html") diff --git a/app/Media.hs b/app/Media.hs index 242ac21..5f1277a 100644 --- a/app/Media.hs +++ b/app/Media.hs @@ -1,184 +1,6 @@ #!/usr/bin/env runhaskell -{-# LANGUAGE ScopedTypeVariables #-} - +import Text.Pandoc.Util.Filter.Media import Text.Pandoc.JSON -import Control.Exception -import Data.Monoid ((<>)) -import Data.List (partition, elem) -import Data.Char (toLower) -import System.FilePath main :: IO () main = toJSONFilter media - --- | File-extensions that should be treated as audio -audioExt :: [String] -audioExt = ["mp3","aac"] - --- | File-extensions that should be treated as video -videoExt :: [String] -videoExt = [ "avi" - , "mp4" - , "mov" - ] - --- | File-extensions that should be treated as image -imgExt :: [String] -imgExt = - [ "jpg" - , "jpeg" - , "png" - , "gif" - , "tif" - , "tiff" - , "bmp" - ] - --- | File-extensions that should be treated as demo and will be included --- in an iframe -demoExt :: [String] -demoExt = ["html", "htm"] - --- | main media-plugin. --- --- Will convert the following syntax --- --- --- - `![](foo.aac){#audio}` --- - `![](foo.mp4){#video}` --- - `![](foo.png){#img}` --- - `![](foo.svg){#svg}` --- - `![](foo.html){#demo}` --- --- HTML-id's maybe ommitted if the file-extension is in whitelist. --- --- If a type is detected by extension a custom id (not matching the extension) --- will be preserved. --- -media :: Inline -> IO [Inline] ---audio -media (Image (id',att,att') [] (filename,_)) - | id' == "audio" || (checkExtension filename audioExt) - = return $ [toHtml $ ""] - where - (direct, css) = classToPlain att -media (Image (id',att,att') alt (filename,_)) - | id' == "audio" || (checkExtension filename audioExt) - = return $ [toHtml $ "
"] - ++ [toHtml $ "
"] - ++ alt - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att ---videos -media (Image (id', att, att') [] (filename,_)) - | id' == "video" || (checkExtension filename videoExt) - = return $ [toHtml $ ""] - where - (direct, css) = classToPlain att -media (Image (id', att, att') alt (filename,_)) - | id' == "video" || (checkExtension filename videoExt) - = return $ [toHtml $ "
"] - ++ [toHtml $ ""] - ++ [toHtml $ "
"] - ++ alt - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att ---images -media (Image (id', att, att') [] (filename,_)) - | id' == "img" || (checkExtension filename imgExt) - = return $ [toHtml $ "
"] - ++ [toHtml $ " unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> ">"] - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att -media (Image (id', att, att') alt (filename,_)) - | id' == "img" || (checkExtension filename imgExt) - = return $ [toHtml $ "
"] - ++ [toHtml $ " unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> ">"] - ++ [toHtml $ "
"] - ++ alt - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att ---load svg and dump it in -media (Image (id', att, att') [] (filename,_)) - | id' == "svg" || (checkExtension filename ["svg"]) - = handle (\(fileerror :: IOException) -> return [toHtml $ "Could not read file: " <> filename <> "
" <> show fileerror]) $ - do - svg <- readFile filename - return $ [toHtml $ "
unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in.. - ++ [toHtml $ svg] - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att -media (Image (id', att, att') alt (filename,_)) - | id' == "svg" || (checkExtension filename ["svg"]) - = handle (\(fileerror :: IOException) -> return $ [toHtml $ "Could not read file: " <> filename <> "
" <> show filename]) $ - do - svg <- readFile filename - return $ [toHtml $ "
unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in.. - ++ [toHtml $ svg] - ++ [toHtml $ "
"] - ++ alt - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att ---html-demos etc. as IFrames -media (Image (id', att, att') [] (filename,_)) - | id' == "demo" || (checkExtension filename demoExt) - = return $ [toHtml $ ""] - where - (direct, css) = classToPlain att -media (Image (id', att, att') alt (filename,_)) - | id' == "demo" || (checkExtension filename demoExt) - = return $ [toHtml $ "
"] - ++ [toHtml $ ""] - ++ [toHtml $ "
"] - ++ alt - ++ [toHtml $ "
"] - where - (direct, css) = classToPlain att --- if not matched -media x = return [x] - - --- | converts Attributes to String for usage in HTML --- --- Also converts width=xxx and height=xxx to the --- corresponding style-attributes -attToString :: Attr -> String -attToString ("", classes, kvpairs) = "class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs') - where - kvpairs' = convertToStyle ["width","height","transform"] kvpairs -attToString (id', classes, kvpairs) = "id=\"" <> id' <> "\" class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs') - where - kvpairs' = convertToStyle ["width","height","transform"] kvpairs - -convertToStyle :: [String] -> [(String,String)] -> [(String,String)] -convertToStyle keys kvpairs = ("style", newstyle):rest - where - oldstyle = case filter (\(k,v) -> k == "style") kvpairs of - [] -> "" - [(_,st)] -> st - stylesToAdd = filter (\(k,v) -> k `elem` keys) kvpairs - rest = filter (\(k,v) -> not $ k `elem` keys) kvpairs - newstyle = concat ((\(k,v) -> k <> ":" <> v <> ";") <$> stylesToAdd) <> oldstyle - -checkExtension :: String -> [String] -> Bool -checkExtension fn exts = (fmap toLower . tail . takeExtension) fn `elem` exts - -idFilter :: String -> String -> String -idFilter a b - | a == b = "" - | otherwise = b - -classToPlain :: [String] -> ([String],[String]) -classToPlain = partition (`elem` [ "data-autoplay" - , "controls" - ] - ) - -toHtml :: String -> Inline -toHtml = RawInline (Format "html") diff --git a/app/Quiz.hs b/app/Quiz.hs index 92db5f3..e5a262f 100644 --- a/app/Quiz.hs +++ b/app/Quiz.hs @@ -2,40 +2,7 @@ {-# LANGUAGE ScopedTypeVariables #-} import Text.Pandoc.JSON -import Text.Pandoc.Walk -import Control.Exception -import Data.Monoid ((<>)) -import Data.List (partition) -import Data.Maybe (isNothing, mapMaybe, listToMaybe) +import Text.Pandoc.Util.Filter.Quiz main :: IO () -main = toJSONFilter quizLift - --- Move bottom-Up through the structure, find quiz-answers and remove the --- incorrect formattet ones from the Block they came from. -quizLift :: Block -> [Block] -quizLift pb@(Plain b) = fmap makeQuiz (query findQuiz pb) ++ [Plain (filter ((==) [] . findQuiz) b)] -quizLift pb@(Para b) = fmap makeQuiz (query findQuiz pb) ++ [Plain (filter ((==) [] . findQuiz) b)] -quizLift x = [x] - --- If we have []{.answer} then we have a quiz-answer --- maybe with a tooltip -findQuiz :: Inline -> [(Attr, [Inline], Maybe ([Inline],Attr))] -findQuiz (Span attributes@(id, att, att') answerText) - | "answer" `elem` att = [(attributes, answerText', tooltip)] - where - answerText' = filter (isNothing . findTooltip) answerText --filter everything that is a tooltip - tooltip = listToMaybe $ mapMaybe findTooltip answerText --get the first span that is labled tooltip -findQuiz x = [] - --- If we have []{.tooltip} we have a tooltip ;) --- we save the text and the attributes in a tuple -findTooltip :: Inline -> Maybe ([Inline],Attr) -findTooltip (Span attr@(_,att,_) tooltipText) - | "tooltip" `elem` att = Just (tooltipText, attr) -findTooltip _ = Nothing - --- Generate Divs for the quiz -makeQuiz :: (Attr, [Inline], Maybe ([Inline],Attr)) -> Block -makeQuiz (att, answer, Nothing) = Div att [Plain answer] -makeQuiz (att, answer, Just (tooltip,a)) = Div att [Plain answer, Div a [Plain tooltip]] +main = toJSONFilter quiz diff --git a/app/Styling.hs b/app/Styling.hs index f76d609..24843b3 100644 --- a/app/Styling.hs +++ b/app/Styling.hs @@ -1,77 +1,8 @@ #!/usr/bin/env runhaskell -{-# LANGUAGE ScopedTypeVariables #-} import Text.Pandoc.JSON import Text.Pandoc.Walk -import Control.Exception -import Data.Monoid ((<>)) -import Data.List (partition, isInfixOf) +import Text.Pandoc.Util.Filter.Styling main :: IO () main = toJSONFilter $ styling . walk inlineStyling - -styling :: Block -> IO [Block] -styling (Div ("col",att,att') inner) = return $ [toHtml $ "
unwords direct <> attToString ("",css,att') <> ">"] - ++ inner - ++ [toHtml"
"] - where - (direct, css) = classToPlain att -styling (CodeBlock (id,att,att') inner) = return $ [CodeBlock (id, addToAtt "data-trim" - . addToAtt "data-noescape" - $ att - , att') inner] -styling div@(Div (id,att,att') inner) - | "fragment" `elem` att = return [Div (id, att, addToStyle "display: block;" att') inner] - | "frame" `elem` att = return [Div (id, addToAtt "fragment" --insert fragment - . addToAtt "current-visible" --insert current-visible - . filter (/= "frame") --remove frame - $ att - , addToStyle "display: block;" att') inner] - | otherwise = return [div] -styling x = return [x] - - -inlineStyling :: Inline -> Inline -inlineStyling span@(Span (id, att, att') inner) - | "fragment" `elem` att = Span (id, att, addToStyle "display: inline-block;" att') inner - | "frame" `elem` att = Span (id, addToAtt "fragment" --insert fragment - . addToAtt "current-visible" --insert current-visible - . filter (/= "frame") --remove frame - $ att - , addToStyle "display: inline-block;" att') inner - | id == "vspace" = toInlineHtml $ "
unwords direct <> attToString ("",css,att') <> ">
" - | id == "hspace" = toInlineHtml $ " unwords direct <> attToString ("",css,att') <> ">" - | otherwise = span - where - (direct, css) = classToPlain att -inlineStyling x = x - -addToStyle :: String -> [(String, String)] -> [(String, String)] --- we are looking for style and inject -addToStyle toAdd (("style",val):as) = ("style", if toAdd `isInfixOf` val then val else val <> " " <> toAdd):as --- if we land here the current one is not style -> skip -addToStyle toAdd (a:as) = a:addToStyle toAdd as --- if we land here we have no more to skip -> add -addToStyle toAdd [] = [("style", toAdd)] - -addToAtt :: String -> [String] -> [String] -addToAtt toAdd (a:as) - | a == toAdd = toAdd:as - | otherwise = a:addToAtt toAdd as -addToAtt toAdd [] = [toAdd] - -attToString :: Attr -> String -attToString (ident, [], kvpairs) = ident <> " " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs) -attToString (ident, classes, kvpairs) = ident <> " class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs) - -classToPlain :: [String] -> ([String],[String]) -classToPlain = partition (`elem` [ "data-autoplay" - , "controls" - ] - ) - -toHtml :: String -> Block -toHtml = RawBlock (Format "html") - -toInlineHtml :: String -> Inline -toInlineHtml = RawInline (Format "html") diff --git a/doc/Text-Pandoc-Util-Filter-Cols.html b/doc/Text-Pandoc-Util-Filter-Cols.html new file mode 100644 index 0000000..e3dd7ea --- /dev/null +++ b/doc/Text-Pandoc-Util-Filter-Cols.html @@ -0,0 +1,19 @@ +Text.Pandoc.Util.Filter.Cols

pandoc-slide-filter-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Text.Pandoc.Util.Filter.Cols

Description

Conversion of lvl-x-headings to x-column-layouts in HTML + especially for use in revealjs-slides

Synopsis

Documentation

cols :: [Block] -> [Block] Source #

This filter makes multi-column-layouts out of lvl-x-headings

Syntax is

    ## a b
+

yielding a 2-column-layout with aspects a:b i.e. 1:1 for 50/50-layout + or 8:2 for 80/20 layout

currently works for 2 and 3-columns, but extension is straight-forward.

If you need multiple Block-Elements inside one column, just wrap them + with a <div>:

    ## 2 5
+
+    <div>
+    multiple things
+    ```
+    foo
+    ```
+    
+    </div>
+
+    second column here with only 1 element.
+
\ No newline at end of file diff --git a/doc/Text-Pandoc-Util-Filter-Media.html b/doc/Text-Pandoc-Util-Filter-Media.html new file mode 100644 index 0000000..0d20d9d --- /dev/null +++ b/doc/Text-Pandoc-Util-Filter-Media.html @@ -0,0 +1,10 @@ +Text.Pandoc.Util.Filter.Media

pandoc-slide-filter-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Text.Pandoc.Util.Filter.Media

Synopsis

Documentation

media :: Inline -> IO [Inline] Source #

main media-plugin.

Will convert the following syntax

![](foo.aac){#audio}
+![](foo.mp4){#video}
+![](foo.png){#img}
+![](foo.svg){#svg}
+![](foo.html){#demo}
+

HTML-id's maybe ommitted if the file-extension is in whitelist.

If a type is detected by extension a custom id (not matching the extension) + will be preserved.

\ No newline at end of file diff --git a/doc/Text-Pandoc-Util-Filter-Quiz.html b/doc/Text-Pandoc-Util-Filter-Quiz.html new file mode 100644 index 0000000..6f9d728 --- /dev/null +++ b/doc/Text-Pandoc-Util-Filter-Quiz.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter.Quiz

pandoc-slide-filter-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Text.Pandoc.Util.Filter.Quiz

Documentation

\ No newline at end of file diff --git a/doc/Text-Pandoc-Util-Filter-Styling.html b/doc/Text-Pandoc-Util-Filter-Styling.html new file mode 100644 index 0000000..b1b5bf4 --- /dev/null +++ b/doc/Text-Pandoc-Util-Filter-Styling.html @@ -0,0 +1,5 @@ +Text.Pandoc.Util.Filter.Styling

pandoc-slide-filter-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Text.Pandoc.Util.Filter.Styling

Documentation

styling :: Block -> IO [Block] Source #

Block-Styling

Special cases captured:

  • #col turns a div into a floating-div for multiple columns
  • CodeBlock gets attributes data-trim and data-noescape + automatically
  • .fragment and .frame work properly on divs

inlineStyling :: Inline -> Inline Source #

Inline-Styling

Special cases captured:

  • .fragment and .frame work properly on spans
  • .vspace inside span adds a vertical space with height=xxx
  • .hspace inside span adds a horizontal space with width=xxx
\ No newline at end of file diff --git a/doc/Text-Pandoc-Util-Filter.html b/doc/Text-Pandoc-Util-Filter.html new file mode 100644 index 0000000..a01e33c --- /dev/null +++ b/doc/Text-Pandoc-Util-Filter.html @@ -0,0 +1,19 @@ +Text.Pandoc.Util.Filter

pandoc-slide-filter-0.1.0.0

Safe HaskellNone
LanguageHaskell2010

Text.Pandoc.Util.Filter

Documentation

attToString :: Attr -> String Source #

converts Attributes to String for usage in HTML

Also converts width=xxx and height=xxx to the + corresponding style-attributes

revealjsSpecialAttrs :: [String] Source #

revealjs has some special attributes that has to be + passed to the html, but Pandoc only allows + key=value-attributes, so we have to abuse + .class to rewrite them.

The classes that get rewritten are listed here.

You probably want classToRevealAttr, as that + is a wrapper for splitting the class-attribute

classToRevealAttr :: [String] -> ([String], [String]) Source #

revealjs has some special attributes that has to be + passed to the html, but Pandoc only allows + key=value-attributes, so we have to abuse + .class to rewrite them.

This is a wrapper-function which just splits the list + into real classes and revealjsSpecialAttrs

toHtml :: String -> Inline Source #

small wrapper around RawInline (Format "html") + as this is less line-noise in the filters and the + intent is more clear.

toBlockHtml :: String -> Block Source #

small wrapper around Raw (Format "html") + as this is less line-noise in the filters and the + intent is more clear.

addToAtt :: Eq a => a -> [a] -> [a] Source #

adds a given String to the list if not in there; Does nothing if the + given String is already present.

addToStyle :: String -> [(String, String)] -> [(String, String)] Source #

adds given String to List of key-value-pairs (like in Attr) + in the "style"-Key.

Useful when trying to add CSS-styles directly to (generated) elements

\ No newline at end of file diff --git a/doc/doc-index.html b/doc/doc-index.html new file mode 100644 index 0000000..6cee2ff --- /dev/null +++ b/doc/doc-index.html @@ -0,0 +1,4 @@ +pandoc-slide-filter-0.1.0.0 (Index)

pandoc-slide-filter-0.1.0.0

\ No newline at end of file diff --git a/doc/haddock-util.js b/doc/haddock-util.js new file mode 100644 index 0000000..92d07d2 --- /dev/null +++ b/doc/haddock-util.js @@ -0,0 +1,316 @@ +// Haddock JavaScript utilities + +var rspace = /\s\s+/g, + rtrim = /^\s+|\s+$/g; + +function spaced(s) { return (" " + s + " ").replace(rspace, " "); } +function trim(s) { return s.replace(rtrim, ""); } + +function hasClass(elem, value) { + var className = spaced(elem.className || ""); + return className.indexOf( " " + value + " " ) >= 0; +} + +function addClass(elem, value) { + var className = spaced(elem.className || ""); + if ( className.indexOf( " " + value + " " ) < 0 ) { + elem.className = trim(className + " " + value); + } +} + +function removeClass(elem, value) { + var className = spaced(elem.className || ""); + className = className.replace(" " + value + " ", " "); + elem.className = trim(className); +} + +function toggleClass(elem, valueOn, valueOff, bool) { + if (bool == null) { bool = ! hasClass(elem, valueOn); } + if (bool) { + removeClass(elem, valueOff); + addClass(elem, valueOn); + } + else { + removeClass(elem, valueOn); + addClass(elem, valueOff); + } + return bool; +} + + +function makeClassToggle(valueOn, valueOff) +{ + return function(elem, bool) { + return toggleClass(elem, valueOn, valueOff, bool); + } +} + +toggleShow = makeClassToggle("show", "hide"); +toggleCollapser = makeClassToggle("collapser", "expander"); + +function toggleSection(id) +{ + var b = toggleShow(document.getElementById("section." + id)); + toggleCollapser(document.getElementById("control." + id), b); + rememberCollapsed(id, b); + return b; +} + +var collapsed = {}; +function rememberCollapsed(id, b) +{ + if(b) + delete collapsed[id] + else + collapsed[id] = null; + + var sections = []; + for(var i in collapsed) + { + if(collapsed.hasOwnProperty(i)) + sections.push(i); + } + // cookie specific to this page; don't use setCookie which sets path=/ + document.cookie = "collapsed=" + escape(sections.join('+')); +} + +function restoreCollapsed() +{ + var cookie = getCookie("collapsed"); + if(!cookie) + return; + + var ids = cookie.split('+'); + for(var i in ids) + { + if(document.getElementById("section." + ids[i])) + toggleSection(ids[i]); + } +} + +function setCookie(name, value) { + document.cookie = name + "=" + escape(value) + ";path=/;"; +} + +function clearCookie(name) { + document.cookie = name + "=;path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT;"; +} + +function getCookie(name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) { + return unescape(c.substring(nameEQ.length,c.length)); + } + } + return null; +} + + + +var max_results = 75; // 50 is not enough to search for map in the base libraries +var shown_range = null; +var last_search = null; + +function quick_search() +{ + perform_search(false); +} + +function full_search() +{ + perform_search(true); +} + + +function perform_search(full) +{ + var text = document.getElementById("searchbox").value.toLowerCase(); + if (text == last_search && !full) return; + last_search = text; + + var table = document.getElementById("indexlist"); + var status = document.getElementById("searchmsg"); + var children = table.firstChild.childNodes; + + // first figure out the first node with the prefix + var first = bisect(-1); + var last = (first == -1 ? -1 : bisect(1)); + + if (first == -1) + { + table.className = ""; + status.innerHTML = "No results found, displaying all"; + } + else if (first == 0 && last == children.length - 1) + { + table.className = ""; + status.innerHTML = ""; + } + else if (last - first >= max_results && !full) + { + table.className = ""; + status.innerHTML = "More than " + max_results + ", press Search to display"; + } + else + { + // decide what you need to clear/show + if (shown_range) + setclass(shown_range[0], shown_range[1], "indexrow"); + setclass(first, last, "indexshow"); + shown_range = [first, last]; + table.className = "indexsearch"; + status.innerHTML = ""; + } + + + function setclass(first, last, status) + { + for (var i = first; i <= last; i++) + { + children[i].className = status; + } + } + + + // do a binary search, treating 0 as ... + // return either -1 (no 0's found) or location of most far match + function bisect(dir) + { + var first = 0, finish = children.length - 1; + var mid, success = false; + + while (finish - first > 3) + { + mid = Math.floor((finish + first) / 2); + + var i = checkitem(mid); + if (i == 0) i = dir; + if (i == -1) + finish = mid; + else + first = mid; + } + var a = (dir == 1 ? first : finish); + var b = (dir == 1 ? finish : first); + for (var i = b; i != a - dir; i -= dir) + { + if (checkitem(i) == 0) return i; + } + return -1; + } + + + // from an index, decide what the result is + // 0 = match, -1 is lower, 1 is higher + function checkitem(i) + { + var s = getitem(i).toLowerCase().substr(0, text.length); + if (s == text) return 0; + else return (s > text ? -1 : 1); + } + + + // from an index, get its string + // this abstracts over alternates + function getitem(i) + { + for ( ; i >= 0; i--) + { + var s = children[i].firstChild.firstChild.data; + if (s.indexOf(' ') == -1) + return s; + } + return ""; // should never be reached + } +} + +function setSynopsis(filename) { + if (parent.window.synopsis && parent.window.synopsis.location) { + if (parent.window.synopsis.location.replace) { + // In Firefox this avoids adding the change to the history. + parent.window.synopsis.location.replace(filename); + } else { + parent.window.synopsis.location = filename; + } + } +} + +function addMenuItem(html) { + var menu = document.getElementById("page-menu"); + if (menu) { + var btn = menu.firstChild.cloneNode(false); + btn.innerHTML = html; + menu.appendChild(btn); + } +} + +function styles() { + var i, a, es = document.getElementsByTagName("link"), rs = []; + for (i = 0; a = es[i]; i++) { + if(a.rel.indexOf("style") != -1 && a.title) { + rs.push(a); + } + } + return rs; +} + +function addStyleMenu() { + var as = styles(); + var i, a, btns = ""; + for(i=0; a = as[i]; i++) { + btns += "
  • " + + a.title + "
  • " + } + if (as.length > 1) { + var h = "
    " + + "Style ▾" + + "
      " + btns + "
    " + + "
    "; + addMenuItem(h); + } +} + +function setActiveStyleSheet(title) { + var as = styles(); + var i, a, found; + for(i=0; a = as[i]; i++) { + a.disabled = true; + // need to do this always, some browsers are edge triggered + if(a.title == title) { + found = a; + } + } + if (found) { + found.disabled = false; + setCookie("haddock-style", title); + } + else { + as[0].disabled = false; + clearCookie("haddock-style"); + } + styleMenu(false); +} + +function resetStyle() { + var s = getCookie("haddock-style"); + if (s) setActiveStyleSheet(s); +} + + +function styleMenu(show) { + var m = document.getElementById('style-menu'); + if (m) toggleShow(m, show); +} + + +function pageLoad() { + addStyleMenu(); + resetStyle(); + restoreCollapsed(); +} + diff --git a/doc/hslogo-16.png b/doc/hslogo-16.png new file mode 100644 index 0000000000000000000000000000000000000000..0ff8579fbd897417b0d6dad6e920f8882138a7c0 GIT binary patch literal 1684 zcmV;F25b3=P)4Tx0C)j~RL^S@K@|QrZmG~B2wH0nvUrdpNm;9CMbtL^5n^i$+aIn^?(HA4aZWV5ov6ELTdbo0FI&wK{O>*+w4vx20?>!`FrQsdJlnHR>OPy zcd~b_n$otK2Za4V;76L-DzNVtaSB-y0*E}{p()372;bw_^6ZZ}PI-92wGS&j#91PI zKs7DSe@(bk%_Y-7gGe}(^>I=@oY#w#*Bu9GZf3^F5WP>3rn}7Ut74&?PWBFvy`A)a zPP5)V!Xd&78LdA?xQ(9mjMYElVd13a#D+Z_7&Y|xU=_C-srWU*6kiZcC!$nw*)9$7 zn6CX+@=AhmkT}X@VSsa5NKe;HZuq)~1$`#h6R+ZTR#D-3j}vF!)ZOnz+5)dI4jl{{ z44Mr{P!L4~VVJN`K!!XTF*LGrKO?IK8z<8w`3e3jI8lUGNUta*C8 zn(P`s>{pjD=7Kek#B;Fw@hxAK%$F&Q6vg9J^Xf~4by_hu-=A!MJ3Znq&n~srbFGPs zH&&aMXZ>nO`|hf|ljc?VPhR!${AbO?W8x_>CU%PFA&Hm8F7cAsOREdwU~R_;ot1_u z(ruCYB-LPGn!NQdT|ZlRy+(fw^-+`=%+gee_kY4FWHg<*4sZI8+sFJD270UUORdLHO0nA4V) z%{fwsET5CQ>B?eK%uw4yQc~9?*JVo2}ze(;aRcp*ceL#HUJSllrgm5wQKR zQu+C;QrUh^8rFfA`ftFz{YAidi-`aL010qNS#tmY4c7nw4c7reD4Tcy00T@(L_t(I z5sj2vNEA^R$7gqDc6T=2^@fUA2(c`MltuL5<|KW>RWz$&YbU@|M|{$E*8Tu-Ux!w z1Y*Dr&Ubfr&v-nZaaB{3ilRumrjPmk{sZvQEWlW+{o~IH|8)=s6c#X9S5s5d%J z4@)&QH5|xQY-)^L1n0pTRu0Lx9`08YTjTwn^6 z0;b1+aQ@)n;Em$q;=7BBi)v0zj&o^g>0Whp^_^5IbxIUP8C@y9;R?*Ouu}rmfxbU= zwtWVNke-m!=`7bYEhWpcI5#)9qp`8E0lr6IQ)ARL3Ui}Af@grj8aN1=r>Cb+prlzO zNfJs*N_tUm2ZL%5* zPmL2??da$TR904gL(VDAQ-Fv_Dk}Pdw*4T(%*f4MKLRg=4ekMjhe2mW zMFsBwg%ftWT}0kxRaIk1k7qJ8*#cKB;Ft{i`zVIs-Nqge;!!Ld7#O&Qqu7e0sJmP) z$MW*>L$vSB&dxp@iA3U9fo)-7!Czlr{|o7Hv{1oyg3xsu%gn@(b1>$;SM-ZaQ`HV=V0s;lr%d8bd;xY zGwNvm3=Iu=tyXIgtJnf@A(2S@M140N ew{UA~tMxaJq;$xaSSi*30000pandoc-slide-filter-0.1.0.0

    pandoc-slide-filter-0.1.0.0

    \ No newline at end of file diff --git a/doc/mini_Text-Pandoc-Util-Filter-Cols.html b/doc/mini_Text-Pandoc-Util-Filter-Cols.html new file mode 100644 index 0000000..82a9518 --- /dev/null +++ b/doc/mini_Text-Pandoc-Util-Filter-Cols.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter.Cols

    Text.Pandoc.Util.Filter.Cols

    \ No newline at end of file diff --git a/doc/mini_Text-Pandoc-Util-Filter-Media.html b/doc/mini_Text-Pandoc-Util-Filter-Media.html new file mode 100644 index 0000000..a594026 --- /dev/null +++ b/doc/mini_Text-Pandoc-Util-Filter-Media.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter.Media

    Text.Pandoc.Util.Filter.Media

    \ No newline at end of file diff --git a/doc/mini_Text-Pandoc-Util-Filter-Quiz.html b/doc/mini_Text-Pandoc-Util-Filter-Quiz.html new file mode 100644 index 0000000..ce16022 --- /dev/null +++ b/doc/mini_Text-Pandoc-Util-Filter-Quiz.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter.Quiz

    Text.Pandoc.Util.Filter.Quiz

    \ No newline at end of file diff --git a/doc/mini_Text-Pandoc-Util-Filter-Styling.html b/doc/mini_Text-Pandoc-Util-Filter-Styling.html new file mode 100644 index 0000000..8871214 --- /dev/null +++ b/doc/mini_Text-Pandoc-Util-Filter-Styling.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter.Styling

    Text.Pandoc.Util.Filter.Styling

    \ No newline at end of file diff --git a/doc/mini_Text-Pandoc-Util-Filter.html b/doc/mini_Text-Pandoc-Util-Filter.html new file mode 100644 index 0000000..e26eafe --- /dev/null +++ b/doc/mini_Text-Pandoc-Util-Filter.html @@ -0,0 +1,4 @@ +Text.Pandoc.Util.Filter

    Text.Pandoc.Util.Filter

    \ No newline at end of file diff --git a/doc/minus.gif b/doc/minus.gif new file mode 100644 index 0000000000000000000000000000000000000000..1deac2fe1a42e35b994f1b855488f392c50f6a89 GIT binary patch literal 56 zcmZ?wbhEHb .doc { + display: table-cell; + padding-left: 0.5em; + margin-bottom: 0.5em; +} + +.subs ul li > .doc p { + margin: 0; +} + +/* Render short-style data instances */ +.inst ul { + height: 100%; + padding: 0.5em; + margin: 0; +} + +.inst, .inst li { + list-style: none; + margin-left: 1em; +} + +/* Workaround for bug in Firefox (issue #384) */ +.inst-left { + float: left; +} + +.top p.src { + border-top: 1px solid #ccc; +} + +.subs, .doc { + /* use this selector for one level of indent */ + padding-left: 2em; +} + +.warning { + color: red; +} + +.arguments { + margin-top: -0.4em; +} +.arguments .caption { + display: none; +} + +.fields { padding-left: 1em; } + +.fields .caption { display: none; } + +.fields p { margin: 0 0; } + +/* this seems bulky to me +.methods, .constructors { + background: #f8f8f8; + border: 1px solid #eee; +} +*/ + +/* @end */ + +/* @group Auxillary Pages */ + + +.extension-list { + list-style-type: none; + margin-left: 0; +} + +#mini { + margin: 0 auto; + padding: 0 1em 1em; +} + +#mini > * { + font-size: 93%; /* 12pt */ +} + +#mini #module-list .caption, +#mini #module-header .caption { + font-size: 125%; /* 15pt */ +} + +#mini #interface h1, +#mini #interface h2, +#mini #interface h3, +#mini #interface h4 { + font-size: 109%; /* 13pt */ + margin: 1em 0 0; +} + +#mini #interface .top, +#mini #interface .src { + margin: 0; +} + +#mini #module-list ul { + list-style: none; + margin: 0; +} + +#alphabet ul { + list-style: none; + padding: 0; + margin: 0.5em 0 0; + text-align: center; +} + +#alphabet li { + display: inline; + margin: 0 0.25em; +} + +#alphabet a { + font-weight: bold; +} + +#index .caption, +#module-list .caption { font-size: 131%; /* 17pt */ } + +#index table { + margin-left: 2em; +} + +#index .src { + font-weight: bold; +} +#index .alt { + font-size: 77%; /* 10pt */ + font-style: italic; + padding-left: 2em; +} + +#index td + td { + padding-left: 1em; +} + +#module-list ul { + list-style: none; + margin: 0 0 0 2em; +} + +#module-list li { + clear: right; +} + +#module-list span.collapser, +#module-list span.expander { + background-position: 0 0.3em; +} + +#module-list .package { + float: right; +} + +/* @end */ diff --git a/doc/pandoc-slide-filter.haddock b/doc/pandoc-slide-filter.haddock new file mode 100644 index 0000000000000000000000000000000000000000..07b4959de0d9a6ec2a02e8bb3783b8ba0e620679 GIT binary patch literal 12445 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 C_gbz1 literal 0 HcmV?d00001 diff --git a/doc/plus.gif b/doc/plus.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d15c14173d23f664b955cd24f51c82f5f09d91d GIT binary patch literal 59 zcmZ?wbhEHbgbBX M^XE!9f*2UA0nx1yDgXcg literal 0 HcmV?d00001 diff --git a/doc/src/Text.Pandoc.Util.Filter.Cols.html b/doc/src/Text.Pandoc.Util.Filter.Cols.html new file mode 100644 index 0000000..c052980 --- /dev/null +++ b/doc/src/Text.Pandoc.Util.Filter.Cols.html @@ -0,0 +1,79 @@ +
    {-# LANGUAGE ScopedTypeVariables #-}
    +
    +-- | Conversion of lvl-x-headings to x-column-layouts in HTML
    +--   especially for use in revealjs-slides
    +module Text.Pandoc.Util.Filter.Cols
    +    (cols)
    +        where
    +
    +import Text.Pandoc.JSON
    +import Data.Monoid ((<>))
    +import Text.Read (readMaybe)
    +import Data.Maybe (fromMaybe)
    +import Text.Pandoc.Util.Filter
    +
    +-- | This filter makes multi-column-layouts out of lvl-x-headings
    +--
    +-- Syntax is
    +-- 
    +-- @
    +--     ## a b
    +-- @
    +--
    +-- yielding a 2-column-layout with aspects a:b i.e. 1:1 for 50/50-layout
    +-- or 8:2 for 80/20 layout
    +--
    +-- currently works for 2 and 3-columns, but extension is straight-forward.
    +--
    +-- If you need multiple Block-Elements inside one column, just wrap them
    +-- with a @\<div\>@:
    +--
    +-- @
    +--     ## 2 5
    +--
    +--     \<div\>
    +--     multiple things
    +--     ```
    +--     foo
    +--     ```
    +--     ![image](...)
    +--     \</div\>
    +--
    +--     second column here with only 1 element.
    +-- @
    +cols :: [Block] -> [Block]
    +cols (Header 2 attr [Str wa,Space,Str wb]:a:b:rest) =
    +  outerDiv:rest
    +    where
    +      wa' = fromMaybe 1 (readMaybe wa) :: Int
    +      wb' = fromMaybe 1 (readMaybe wb) :: Int
    +      total = wa' + wb'
    +      pa = (100*wa') `div` total
    +      pb = (100*wb') `div` total
    +      outerDiv = Div attr [ makeDiv pa a
    +                          , makeDiv pb b
    +                          , clearDiv
    +                          ]
    +cols (Header 3 attr [Str wa,Space,Str wb,Space,Str wc]:a:b:c:rest) =
    +  outerDiv:rest
    +    where
    +      wa' = fromMaybe 1 (readMaybe wa) :: Int
    +      wb' = fromMaybe 1 (readMaybe wb) :: Int
    +      wc' = fromMaybe 1 (readMaybe wc) :: Int
    +      total = wa' + wb' + wc'
    +      pa = (100*wa') `div` total
    +      pb = (100*wb') `div` total
    +      pc = (100*wc') `div` total
    +      outerDiv = Div attr [ makeDiv pa a
    +                          , makeDiv pb b
    +                          , makeDiv pc c
    +                          , clearDiv
    +                          ]
    +cols x = x
    +
    +makeDiv :: Int -> Block -> Block
    +makeDiv width content = Div ("", [], [("style","width:" <> show width <> "%;float:left")]) [content]
    +
    +clearDiv :: Block
    +clearDiv = Div ("", [], [("style", "clear: both")]) [Plain [toHtml "&nbsp;"]]
    +
    \ No newline at end of file diff --git a/doc/src/Text.Pandoc.Util.Filter.Media.html b/doc/src/Text.Pandoc.Util.Filter.Media.html new file mode 100644 index 0000000..8869272 --- /dev/null +++ b/doc/src/Text.Pandoc.Util.Filter.Media.html @@ -0,0 +1,159 @@ +
    {-# LANGUAGE ScopedTypeVariables #-}
    +
    +module Text.Pandoc.Util.Filter.Media
    +    (media)
    +        where
    +
    +import Text.Pandoc.JSON
    +import Control.Exception
    +import Data.Monoid ((<>))
    +import Data.Char (toLower)
    +import System.FilePath
    +
    +import Text.Pandoc.Util.Filter
    +
    +{-# ANN module "HLint: ignore Redundant $" #-} -- supress HLint-Warnings about $
    +
    +-- | File-extensions that should be treated as audio
    +audioExt :: [String]
    +audioExt = ["mp3","aac"]
    +
    +-- | File-extensions that should be treated as video
    +videoExt :: [String]
    +videoExt = [ "avi"
    +           , "mp4"
    +           , "mov"
    +           ]
    +
    +-- | File-extensions that should be treated as image
    +imgExt :: [String]
    +imgExt = 
    +  [ "jpg"
    +  , "jpeg"
    +  , "png"
    +  , "gif"
    +  , "tif"
    +  , "tiff"
    +  , "bmp"
    +  , "svg"
    +  ]
    +
    +-- | File-extensions that should be treated as demo and will be included
    +-- in an iframe
    +demoExt :: [String]
    +demoExt = ["html", "htm"]
    +
    +-- | main media-plugin.
    +--
    +-- Will convert the following syntax
    +--
    +-- @
    +-- ![](foo.aac){#audio}
    +-- ![](foo.mp4){#video}
    +-- ![](foo.png){#img}
    +-- ![](foo.svg){#svg}
    +-- ![](foo.html){#demo}
    +-- @
    +--
    +-- HTML-id's maybe ommitted if the file-extension is in whitelist.
    +--
    +-- If a type is detected by extension a custom id (not matching the extension)
    +-- will be preserved.
    +--
    +media :: Inline -> IO [Inline]
    +--audio
    +media (Image (id',att,att') [] (filename,_))
    +  | id' == "audio" || checkExtension filename audioExt
    +    = return $ [toHtml $ "<audio " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "audio" id',css,att') <> "></audio>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +media (Image (id',att,att') alt (filename,_))
    +  | id' == "audio" || checkExtension filename audioExt
    +    = return $ [toHtml $ "<figure><audio " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "audio" id',css,att') <> "></audio>"]
    +            <> [toHtml $ "<figcaption>"]
    +            <> alt
    +            <> [toHtml $ "</figcaption></figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +--videos
    +media (Image (id', att, att') [] (filename,_))
    +  | id' == "video" || checkExtension filename videoExt
    +    = return $ [toHtml $ "<video " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "video" id',css,att') <> "></video>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +media (Image (id', att, att') alt (filename,_))
    +  | id' == "video" || checkExtension filename videoExt
    +     = return $ [toHtml $ "<figure>"]
    +             <> [toHtml $ "<video " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "video" id',css,att') <> "></video>"]
    +             <> [toHtml $ "<figcaption>"]
    +             <> alt
    +             <> [toHtml $ "</figcaption></figure>"]
    +       where
    +         (direct, css) = classToRevealAttr att
    +--images
    +media (Image (id', att, att') [] (filename,_))
    +  | id' == "img" || checkExtension filename imgExt
    +    = return $ [toHtml $ "<figure>"]
    +            <> [toHtml $ "<img " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> "></img>"]
    +            <> [toHtml $ "</figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +media (Image (id', att, att') alt (filename,_))
    +  | id' == "img" || checkExtension filename imgExt
    +    = return $ [toHtml $ "<figure>"]
    +            <> [toHtml $ "<img " <> unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> "></img>"]
    +            <> [toHtml $ "<figcaption>"]
    +            <> alt
    +            <> [toHtml $ "</figcaption></figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +--load svg and dump it in
    +media (Image (id', att, att') [] (filename,_))
    +  | id' == "svg"
    +    = handle (\(fileerror :: IOException) -> return [toHtml $ "Could not read file: " <> filename <> "<br />" <> show fileerror]) $
    +                do
    +                  svg <- readFile filename
    +                  return $ [toHtml $ "<figure " <> unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in..
    +                        <> [toHtml $ svg]
    +                        <> [toHtml $ "</figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +media (Image (id', att, att') alt (filename,_))
    +  | id' == "svg"
    +    = handle (\(fileerror :: IOException) -> return [toHtml $ "Could not read file: " <> filename <> "<br />" <> show fileerror]) $
    +                do
    +                  svg <- readFile filename
    +                  return $ [toHtml $ "<figure " <> unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in..
    +                        <> [toHtml $ svg]
    +                        <> [toHtml $ "<figcaption>"]
    +                        <> alt
    +                        <> [toHtml $ "</figcaption></figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +--html-demos etc. as IFrames
    +media (Image (id', att, att') [] (filename,_))
    +  | id' == "demo" || checkExtension filename demoExt
    +    = return [toHtml $ "<iframe " <> unwords direct <> " src=\"" <> filename <> "?plugin\"" <> attToString (idFilter "demo" id', css, att') <> "></iframe>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +media (Image (id', att, att') alt (filename,_))
    +  | id' == "demo" || checkExtension filename demoExt
    +    = return $ [toHtml $ "<figure>"]
    +            <> [toHtml $ "<iframe " <> unwords direct <> " src=\"" <> filename <> "?plugin\"" <> attToString (idFilter "demo" id', css, att') <> "></iframe>"]
    +            <> [toHtml $ "<figcaption>"]
    +            <> alt
    +            <> [toHtml $ "</figcaption></figure>"]
    +      where
    +        (direct, css) = classToRevealAttr att
    +-- if not matched
    +media x = return [x]
    +
    +checkExtension :: String -> [String] -> Bool
    +checkExtension fn exts = (fmap toLower . tail . takeExtension) fn `elem` exts
    +
    +idFilter :: String -> String -> String
    +idFilter a b
    +  | a == b    = ""
    +  | otherwise = b
    +
    +
    \ No newline at end of file diff --git a/doc/src/Text.Pandoc.Util.Filter.Quiz.html b/doc/src/Text.Pandoc.Util.Filter.Quiz.html new file mode 100644 index 0000000..173a581 --- /dev/null +++ b/doc/src/Text.Pandoc.Util.Filter.Quiz.html @@ -0,0 +1,40 @@ +
    {-# LANGUAGE ScopedTypeVariables #-}
    +
    +module Text.Pandoc.Util.Filter.Quiz
    +    (quiz)
    +        where
    +
    +import Text.Pandoc.JSON
    +import Text.Pandoc.Walk
    +import Data.Monoid ((<>))
    +import Data.Maybe (isNothing, mapMaybe, listToMaybe)
    +
    +-- Move bottom-Up through the structure, find quiz-answers and remove the
    +-- incorrect formattet ones from the Block they came from.
    +quiz :: Block -> [Block]
    +quiz pb@(Plain b) = fmap makeQuiz (query findQuiz pb) <> [Plain (filter ((==) [] . findQuiz) b)]
    +quiz pb@(Para  b) = fmap makeQuiz (query findQuiz pb) <> [Plain (filter ((==) [] . findQuiz) b)]
    +quiz x = [x]
    +
    +-- If we have []{.answer} then we have a quiz-answer
    +-- maybe with a tooltip
    +findQuiz :: Inline -> [(Attr, [Inline], Maybe ([Inline],Attr))]
    +findQuiz (Span attributes@(_, att, _) answerText)
    +  | "answer" `elem` att     = [(attributes, answerText', tooltip)]
    +                where
    +                        answerText' = filter (isNothing . findTooltip) answerText   --filter everything that is a tooltip
    +                        tooltip     = listToMaybe $ mapMaybe findTooltip answerText --get the first span that is labled tooltip
    +findQuiz _ = []
    +
    +-- If we have []{.tooltip} we have a tooltip ;)
    +-- we save the text and the attributes in a tuple
    +findTooltip :: Inline -> Maybe ([Inline],Attr)
    +findTooltip (Span attr@(_,att,_) tooltipText)
    +  | "tooltip" `elem` att    = Just (tooltipText, attr)
    +findTooltip _ = Nothing
    +
    +-- Generate Divs for the quiz
    +makeQuiz :: (Attr, [Inline], Maybe ([Inline],Attr)) -> Block
    +makeQuiz (att, answer, Nothing) = Div att [Plain answer]
    +makeQuiz (att, answer, Just (tooltip,a)) = Div att [Plain answer, Div a [Plain tooltip]]
    +
    \ No newline at end of file diff --git a/doc/src/Text.Pandoc.Util.Filter.Styling.html b/doc/src/Text.Pandoc.Util.Filter.Styling.html new file mode 100644 index 0000000..cb97efb --- /dev/null +++ b/doc/src/Text.Pandoc.Util.Filter.Styling.html @@ -0,0 +1,65 @@ +
    {-# LANGUAGE ScopedTypeVariables #-}
    +
    +module Text.Pandoc.Util.Filter.Styling
    +    (styling, inlineStyling)
    +        where
    +
    +import Text.Pandoc.JSON
    +import Data.Monoid ((<>))
    +import Text.Pandoc.Util.Filter
    +import Prelude hiding (div, span)
    +
    +-- | Block-Styling
    +--
    +--   Special cases captured:
    +--
    +--   - #col turns a div into a floating-div for multiple columns
    +--   - CodeBlock gets attributes @data-trim@ and @data-noescape@
    +--     automatically
    +--   - .fragment and .frame work properly on divs
    +styling :: Block -> IO [Block]
    +styling (Div ("col",att,att') inner)   = return $ [toBlockHtml $ "<div style=\"float:left; margin-bottom:10px;\"" <> unwords direct <> attToString ("",css,att') <> ">"]
    +                                                        ++ inner
    +                                                        ++ [toBlockHtml"</div>"]
    +                                        where
    +                                                        (direct, css) = classToRevealAttr att
    +styling (CodeBlock (id',att,att') inner)   = return
    +                            [CodeBlock (id', addToAtt "data-trim"
    +                                           . addToAtt "data-noescape"
    +                                           $ att
    +                                           , att')
    +                                       inner]
    +styling div@(Div (id',att,att') inner)
    +  | "fragment" `elem` att = return [Div (id', att, addToStyle "display: block;" att') inner]
    +  | "frame" `elem` att    = return [Div (id', addToAtt "fragment"        --insert fragment
    +                                           . addToAtt "current-visible" --insert current-visible
    +                                           . filter (/= "frame")        --remove frame
    +                                           $ att
    +                                           , addToStyle "display: block;" att') inner]
    +  | otherwise             = return [div]
    +styling x = return [x]
    +
    +
    +-- | Inline-Styling
    +--
    +--   Special cases captured:
    +--
    +--   - .fragment and .frame work properly on spans
    +--   - .vspace inside span adds a vertical space with @height=xxx@
    +--   - .hspace inside span adds a horizontal space with @width=xxx@
    +inlineStyling :: Inline -> Inline
    +inlineStyling span@(Span (id', att, att') inner)
    +  | "fragment" `elem` att = Span (id', att, addToStyle "display: inline-block;" att') inner
    +  | "frame" `elem` att    = Span (id', addToAtt "fragment"        --insert fragment
    +                                    . addToAtt "current-visible" --insert current-visible
    +                                    . filter (/= "frame")        --remove frame
    +                                    $ att
    +                                    , addToStyle "display: inline-block;" att') inner
    +  | id' == "vspace"        = toHtml $ "<div style=\"clear:both;\"" <> unwords direct <> attToString ("",css,att') <> "></div>"
    +  | id' == "hspace"        = toHtml $ "<span " <> unwords direct <> attToString ("",css,att') <> "></span>"
    +  | otherwise             = span
    +                                where
    +                                        (direct, css) = classToRevealAttr att
    +inlineStyling x = x
    +
    +
    \ No newline at end of file diff --git a/doc/src/Text.Pandoc.Util.Filter.html b/doc/src/Text.Pandoc.Util.Filter.html new file mode 100644 index 0000000..30aa29d --- /dev/null +++ b/doc/src/Text.Pandoc.Util.Filter.html @@ -0,0 +1,103 @@ +
    module Text.Pandoc.Util.Filter
    +    ( attToString
    +    , revealjsSpecialAttrs
    +    , classToRevealAttr
    +    , toHtml
    +    , toBlockHtml
    +    , addToAtt
    +    , addToStyle
    +    )
    +   where
    +
    +import Text.Pandoc.Definition
    +import Data.Monoid
    +import Data.List (partition, isInfixOf)
    +
    +-- | adds a given String to the list if not in there; Does nothing if the
    +--   given String is already present.
    +addToAtt :: Eq a => a -> [a] -> [a]
    +addToAtt toAdd (a:as)
    +  | a == toAdd    = toAdd:as
    +  | otherwise     = a:addToAtt toAdd as
    +addToAtt toAdd [] = [toAdd]
    +
    +-- | adds given String to List of key-value-pairs (like in 'Attr')
    +--   in the \"style\"-Key.
    +--
    +--   Useful when trying to add CSS-styles directly to (generated) elements
    +addToStyle :: String -> [(String, String)] -> [(String, String)]
    +-- we are looking for style and inject
    +addToStyle toAdd (("style",val):as) = ("style", if toAdd `isInfixOf` val then val else val <> " " <> toAdd):as
    +-- if we land here the current one is not style -> skip
    +addToStyle toAdd (a:as)             = a:addToStyle toAdd as
    +-- if we land here we have no more to skip -> add
    +addToStyle toAdd []                 = [("style", toAdd)]
    +
    +-- | converts Attributes to String for usage in HTML
    +--
    +-- Also converts @width=xxx@ and @height=xxx@ to the
    +-- corresponding style-attributes
    +attToString :: Attr -> String
    +attToString ("", classes, kvpairs) = "class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs')
    +  where
    +    kvpairs' = convertToStyle ["width","height","transform"] kvpairs
    +attToString (id', classes, kvpairs) = "id=\"" <> id'  <> "\" class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs')
    +  where
    +    kvpairs' = convertToStyle ["width","height","transform"] kvpairs
    +
    +convertToStyle :: [String] -> [(String,String)] -> [(String,String)]
    +convertToStyle keys kvpairs = ("style", newstyle):rest
    +  where
    +    oldstyle = case filter (\(k,_) -> k == "style") kvpairs of
    +                 [(_,st)] -> st
    +                 _        -> ""
    +    stylesToAdd = filter (\(k,_) -> k    `elem` keys) kvpairs
    +    rest        = filter (\(k,_) -> k `notElem` keys) kvpairs
    +    newstyle = concat ((\(k,v) -> k <> ":" <> v <> ";") <$> stylesToAdd) <> oldstyle
    +
    +-- | revealjs has some special attributes that has to be
    +--   passed to the html, but Pandoc only allows
    +--   @key=value@-attributes, so we have to abuse
    +--   @.class@ to rewrite them.
    +--
    +--   The classes that get rewritten are listed here.
    +--
    +--   You probably want 'classToRevealAttr', as that
    +--   is a wrapper for splitting the class-attribute
    +revealjsSpecialAttrs :: [String]
    +revealjsSpecialAttrs = 
    +    [ "data-markdown"
    +    , "data-timing"
    +    , "data-template"
    +    , "data-autoplay"
    +    , "data-prevent-swipe"
    +    , "data-background-interactive"
    +    , "data-trim"
    +    , "data-noescape"
    +    , "data-ignore"
    +    , "controls"
    +    ]
    +
    +-- | revealjs has some special attributes that has to be
    +--   passed to the html, but Pandoc only allows
    +--   @key=value@-attributes, so we have to abuse
    +--   @.class@ to rewrite them.
    +--
    +--   This is a wrapper-function which just splits the list
    +--   into real classes and 'revealjsSpecialAttrs'
    +classToRevealAttr :: [String] -> ([String],[String])
    +classToRevealAttr = partition (`elem` revealjsSpecialAttrs)
    +
    +-- | small wrapper around @RawInline (Format "html")@
    +--   as this is less line-noise in the filters and the
    +--   intent is more clear.
    +toHtml :: String -> Inline
    +toHtml = RawInline (Format "html")
    +
    +
    +-- | small wrapper around @Raw (Format "html")@
    +--   as this is less line-noise in the filters and the
    +--   intent is more clear.
    +toBlockHtml :: String -> Block
    +toBlockHtml = RawBlock (Format "html")
    +
    \ No newline at end of file diff --git a/doc/src/highlight.js b/doc/src/highlight.js new file mode 100644 index 0000000..1e903bd --- /dev/null +++ b/doc/src/highlight.js @@ -0,0 +1,27 @@ + +var highlight = function (on) { + return function () { + var links = document.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + var that = links[i]; + + if (this.href != that.href) { + continue; + } + + if (on) { + that.classList.add("hover-highlight"); + } else { + that.classList.remove("hover-highlight"); + } + } + } +}; + +window.onload = function () { + var links = document.getElementsByTagName('a'); + for (var i = 0; i < links.length; i++) { + links[i].onmouseover = highlight(true); + links[i].onmouseout = highlight(false); + } +}; diff --git a/doc/src/style.css b/doc/src/style.css new file mode 100644 index 0000000..e83dc5e --- /dev/null +++ b/doc/src/style.css @@ -0,0 +1,55 @@ +body { + background-color: #fdf6e3; +} + +.hs-identifier { + color: #073642; +} + +.hs-identifier.hs-var { +} + +.hs-identifier.hs-type { + color: #5f5faf; +} + +.hs-keyword { + color: #af005f; +} + +.hs-string, .hs-char { + color: #cb4b16; +} + +.hs-number { + color: #268bd2; +} + +.hs-operator { + color: #d33682; +} + +.hs-glyph, .hs-special { + color: #dc322f; +} + +.hs-comment { + color: #8a8a8a; +} + +.hs-pragma { + color: #2aa198; +} + +.hs-cpp { + color: #859900; +} + +a:link, a:visited { + text-decoration: none; + border-bottom: 1px solid #eee8d5; +} + +a:hover, a.hover-highlight { + background-color: #eee8d5; +} diff --git a/doc/synopsis.png b/doc/synopsis.png new file mode 100644 index 0000000000000000000000000000000000000000..85fb86ec84907bcc86531dc82871948ff4d471fa GIT binary patch literal 11327 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 B5rhB$ literal 0 HcmV?d00001 diff --git a/pandoc-slide-filter.cabal b/pandoc-slide-filter.cabal index 0167c56..5fe8bb6 100644 --- a/pandoc-slide-filter.cabal +++ b/pandoc-slide-filter.cabal @@ -19,7 +19,7 @@ executable media ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , pandoc-types - , filepath + , pandoc-slide-filter default-language: Haskell2010 executable cols @@ -28,7 +28,7 @@ executable cols ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , pandoc-types - , filepath + , pandoc-slide-filter default-language: Haskell2010 executable styling @@ -37,6 +37,7 @@ executable styling ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , pandoc-types + , pandoc-slide-filter default-language: Haskell2010 executable quiz @@ -45,6 +46,7 @@ executable quiz ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , pandoc-types + , pandoc-slide-filter default-language: Haskell2010 executable clean @@ -53,8 +55,21 @@ executable clean ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , pandoc-types + , pandoc-slide-filter default-language: Haskell2010 +library + hs-source-dirs: src + build-depends: base + , pandoc-types + , filepath + default-language: Haskell2010 + exposed-modules: Text.Pandoc.Util.Filter + , Text.Pandoc.Util.Filter.Cols + , Text.Pandoc.Util.Filter.Media + , Text.Pandoc.Util.Filter.Styling + , Text.Pandoc.Util.Filter.Quiz + source-repository head type: git location: https://github.com/Drezil/pandoc-slide-filter diff --git a/src/Text/Pandoc/Util/Filter.hs b/src/Text/Pandoc/Util/Filter.hs new file mode 100644 index 0000000..5d8275b --- /dev/null +++ b/src/Text/Pandoc/Util/Filter.hs @@ -0,0 +1,102 @@ +module Text.Pandoc.Util.Filter + ( attToString + , revealjsSpecialAttrs + , classToRevealAttr + , toHtml + , toBlockHtml + , addToAtt + , addToStyle + ) + where + +import Text.Pandoc.Definition +import Data.Monoid +import Data.List (partition, isInfixOf) + +-- | adds a given String to the list if not in there; Does nothing if the +-- given String is already present. +addToAtt :: Eq a => a -> [a] -> [a] +addToAtt toAdd (a:as) + | a == toAdd = toAdd:as + | otherwise = a:addToAtt toAdd as +addToAtt toAdd [] = [toAdd] + +-- | adds given String to List of key-value-pairs (like in 'Attr') +-- in the \"style\"-Key. +-- +-- Useful when trying to add CSS-styles directly to (generated) elements +addToStyle :: String -> [(String, String)] -> [(String, String)] +-- we are looking for style and inject +addToStyle toAdd (("style",val):as) = ("style", if toAdd `isInfixOf` val then val else val <> " " <> toAdd):as +-- if we land here the current one is not style -> skip +addToStyle toAdd (a:as) = a:addToStyle toAdd as +-- if we land here we have no more to skip -> add +addToStyle toAdd [] = [("style", toAdd)] + +-- | converts Attributes to String for usage in HTML +-- +-- Also converts @width=xxx@ and @height=xxx@ to the +-- corresponding style-attributes +attToString :: Attr -> String +attToString ("", classes, kvpairs) = "class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs') + where + kvpairs' = convertToStyle ["width","height","transform"] kvpairs +attToString (id', classes, kvpairs) = "id=\"" <> id' <> "\" class=\"" <> unwords classes <> "\" " <> unwords ((\(k,v) -> k <> "=\"" <> v <> "\"") <$> kvpairs') + where + kvpairs' = convertToStyle ["width","height","transform"] kvpairs + +convertToStyle :: [String] -> [(String,String)] -> [(String,String)] +convertToStyle keys kvpairs = ("style", newstyle):rest + where + oldstyle = case filter (\(k,_) -> k == "style") kvpairs of + [(_,st)] -> st + _ -> "" + stylesToAdd = filter (\(k,_) -> k `elem` keys) kvpairs + rest = filter (\(k,_) -> k `notElem` keys) kvpairs + newstyle = concat ((\(k,v) -> k <> ":" <> v <> ";") <$> stylesToAdd) <> oldstyle + +-- | revealjs has some special attributes that has to be +-- passed to the html, but Pandoc only allows +-- @key=value@-attributes, so we have to abuse +-- @.class@ to rewrite them. +-- +-- The classes that get rewritten are listed here. +-- +-- You probably want 'classToRevealAttr', as that +-- is a wrapper for splitting the class-attribute +revealjsSpecialAttrs :: [String] +revealjsSpecialAttrs = + [ "data-markdown" + , "data-timing" + , "data-template" + , "data-autoplay" + , "data-prevent-swipe" + , "data-background-interactive" + , "data-trim" + , "data-noescape" + , "data-ignore" + , "controls" + ] + +-- | revealjs has some special attributes that has to be +-- passed to the html, but Pandoc only allows +-- @key=value@-attributes, so we have to abuse +-- @.class@ to rewrite them. +-- +-- This is a wrapper-function which just splits the list +-- into real classes and 'revealjsSpecialAttrs' +classToRevealAttr :: [String] -> ([String],[String]) +classToRevealAttr = partition (`elem` revealjsSpecialAttrs) + +-- | small wrapper around @RawInline (Format "html")@ +-- as this is less line-noise in the filters and the +-- intent is more clear. +toHtml :: String -> Inline +toHtml = RawInline (Format "html") + + +-- | small wrapper around @Raw (Format "html")@ +-- as this is less line-noise in the filters and the +-- intent is more clear. +toBlockHtml :: String -> Block +toBlockHtml = RawBlock (Format "html") diff --git a/src/Text/Pandoc/Util/Filter/Cols.hs b/src/Text/Pandoc/Util/Filter/Cols.hs new file mode 100644 index 0000000..7f5e2b5 --- /dev/null +++ b/src/Text/Pandoc/Util/Filter/Cols.hs @@ -0,0 +1,78 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +-- | Conversion of lvl-x-headings to x-column-layouts in HTML +-- especially for use in revealjs-slides +module Text.Pandoc.Util.Filter.Cols + (cols) + where + +import Text.Pandoc.JSON +import Data.Monoid ((<>)) +import Text.Read (readMaybe) +import Data.Maybe (fromMaybe) +import Text.Pandoc.Util.Filter + +-- | This filter makes multi-column-layouts out of lvl-x-headings +-- +-- Syntax is +-- +-- @ +-- ## a b +-- @ +-- +-- yielding a 2-column-layout with aspects a:b i.e. 1:1 for 50/50-layout +-- or 8:2 for 80/20 layout +-- +-- currently works for 2 and 3-columns, but extension is straight-forward. +-- +-- If you need multiple Block-Elements inside one column, just wrap them +-- with a @\@: +-- +-- @ +-- ## 2 5 +-- +-- \ +-- multiple things +-- ``` +-- foo +-- ``` +-- ![image](...) +-- \ +-- +-- second column here with only 1 element. +-- @ +cols :: [Block] -> [Block] +cols (Header 2 attr [Str wa,Space,Str wb]:a:b:rest) = + outerDiv:rest + where + wa' = fromMaybe 1 (readMaybe wa) :: Int + wb' = fromMaybe 1 (readMaybe wb) :: Int + total = wa' + wb' + pa = (100*wa') `div` total + pb = (100*wb') `div` total + outerDiv = Div attr [ makeDiv pa a + , makeDiv pb b + , clearDiv + ] +cols (Header 3 attr [Str wa,Space,Str wb,Space,Str wc]:a:b:c:rest) = + outerDiv:rest + where + wa' = fromMaybe 1 (readMaybe wa) :: Int + wb' = fromMaybe 1 (readMaybe wb) :: Int + wc' = fromMaybe 1 (readMaybe wc) :: Int + total = wa' + wb' + wc' + pa = (100*wa') `div` total + pb = (100*wb') `div` total + pc = (100*wc') `div` total + outerDiv = Div attr [ makeDiv pa a + , makeDiv pb b + , makeDiv pc c + , clearDiv + ] +cols x = x + +makeDiv :: Int -> Block -> Block +makeDiv width content = Div ("", [], [("style","width:" <> show width <> "%;float:left")]) [content] + +clearDiv :: Block +clearDiv = Div ("", [], [("style", "clear: both")]) [Plain [toHtml " "]] diff --git a/src/Text/Pandoc/Util/Filter/Media.hs b/src/Text/Pandoc/Util/Filter/Media.hs new file mode 100644 index 0000000..0865b8f --- /dev/null +++ b/src/Text/Pandoc/Util/Filter/Media.hs @@ -0,0 +1,158 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +module Text.Pandoc.Util.Filter.Media + (media) + where + +import Text.Pandoc.JSON +import Control.Exception +import Data.Monoid ((<>)) +import Data.Char (toLower) +import System.FilePath + +import Text.Pandoc.Util.Filter + +{-# ANN module "HLint: ignore Redundant $" #-} -- supress HLint-Warnings about $ + +-- | File-extensions that should be treated as audio +audioExt :: [String] +audioExt = ["mp3","aac"] + +-- | File-extensions that should be treated as video +videoExt :: [String] +videoExt = [ "avi" + , "mp4" + , "mov" + ] + +-- | File-extensions that should be treated as image +imgExt :: [String] +imgExt = + [ "jpg" + , "jpeg" + , "png" + , "gif" + , "tif" + , "tiff" + , "bmp" + , "svg" + ] + +-- | File-extensions that should be treated as demo and will be included +-- in an iframe +demoExt :: [String] +demoExt = ["html", "htm"] + +-- | main media-plugin. +-- +-- Will convert the following syntax +-- +-- @ +-- ![](foo.aac){#audio} +-- ![](foo.mp4){#video} +-- ![](foo.png){#img} +-- ![](foo.svg){#svg} +-- ![](foo.html){#demo} +-- @ +-- +-- HTML-id's maybe ommitted if the file-extension is in whitelist. +-- +-- If a type is detected by extension a custom id (not matching the extension) +-- will be preserved. +-- +media :: Inline -> IO [Inline] +--audio +media (Image (id',att,att') [] (filename,_)) + | id' == "audio" || checkExtension filename audioExt + = return $ [toHtml $ ""] + where + (direct, css) = classToRevealAttr att +media (Image (id',att,att') alt (filename,_)) + | id' == "audio" || checkExtension filename audioExt + = return $ [toHtml $ "
    "] + <> [toHtml $ "
    "] + <> alt + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +--videos +media (Image (id', att, att') [] (filename,_)) + | id' == "video" || checkExtension filename videoExt + = return $ [toHtml $ ""] + where + (direct, css) = classToRevealAttr att +media (Image (id', att, att') alt (filename,_)) + | id' == "video" || checkExtension filename videoExt + = return $ [toHtml $ "
    "] + <> [toHtml $ ""] + <> [toHtml $ "
    "] + <> alt + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +--images +media (Image (id', att, att') [] (filename,_)) + | id' == "img" || checkExtension filename imgExt + = return $ [toHtml $ "
    "] + <> [toHtml $ " unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> ">"] + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +media (Image (id', att, att') alt (filename,_)) + | id' == "img" || checkExtension filename imgExt + = return $ [toHtml $ "
    "] + <> [toHtml $ " unwords direct <> " src=\"" <> filename <> "\"" <> attToString (idFilter "img" id',css,att') <> ">"] + <> [toHtml $ "
    "] + <> alt + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +--load svg and dump it in +media (Image (id', att, att') [] (filename,_)) + | id' == "svg" + = handle (\(fileerror :: IOException) -> return [toHtml $ "Could not read file: " <> filename <> "
    " <> show fileerror]) $ + do + svg <- readFile filename + return $ [toHtml $ "
    unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in.. + <> [toHtml $ svg] + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +media (Image (id', att, att') alt (filename,_)) + | id' == "svg" + = handle (\(fileerror :: IOException) -> return [toHtml $ "Could not read file: " <> filename <> "
    " <> show fileerror]) $ + do + svg <- readFile filename + return $ [toHtml $ "
    unwords direct <> " " <> attToString (idFilter "svg" id', css, att') <> ">"] -- use attributes on figure, as svg gets dumped in.. + <> [toHtml $ svg] + <> [toHtml $ "
    "] + <> alt + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +--html-demos etc. as IFrames +media (Image (id', att, att') [] (filename,_)) + | id' == "demo" || checkExtension filename demoExt + = return [toHtml $ ""] + where + (direct, css) = classToRevealAttr att +media (Image (id', att, att') alt (filename,_)) + | id' == "demo" || checkExtension filename demoExt + = return $ [toHtml $ "
    "] + <> [toHtml $ ""] + <> [toHtml $ "
    "] + <> alt + <> [toHtml $ "
    "] + where + (direct, css) = classToRevealAttr att +-- if not matched +media x = return [x] + +checkExtension :: String -> [String] -> Bool +checkExtension fn exts = (fmap toLower . tail . takeExtension) fn `elem` exts + +idFilter :: String -> String -> String +idFilter a b + | a == b = "" + | otherwise = b + diff --git a/src/Text/Pandoc/Util/Filter/Quiz.hs b/src/Text/Pandoc/Util/Filter/Quiz.hs new file mode 100644 index 0000000..fb96de9 --- /dev/null +++ b/src/Text/Pandoc/Util/Filter/Quiz.hs @@ -0,0 +1,39 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +module Text.Pandoc.Util.Filter.Quiz + (quiz) + where + +import Text.Pandoc.JSON +import Text.Pandoc.Walk +import Data.Monoid ((<>)) +import Data.Maybe (isNothing, mapMaybe, listToMaybe) + +-- Move bottom-Up through the structure, find quiz-answers and remove the +-- incorrect formattet ones from the Block they came from. +quiz :: Block -> [Block] +quiz pb@(Plain b) = fmap makeQuiz (query findQuiz pb) <> [Plain (filter ((==) [] . findQuiz) b)] +quiz pb@(Para b) = fmap makeQuiz (query findQuiz pb) <> [Plain (filter ((==) [] . findQuiz) b)] +quiz x = [x] + +-- If we have []{.answer} then we have a quiz-answer +-- maybe with a tooltip +findQuiz :: Inline -> [(Attr, [Inline], Maybe ([Inline],Attr))] +findQuiz (Span attributes@(_, att, _) answerText) + | "answer" `elem` att = [(attributes, answerText', tooltip)] + where + answerText' = filter (isNothing . findTooltip) answerText --filter everything that is a tooltip + tooltip = listToMaybe $ mapMaybe findTooltip answerText --get the first span that is labled tooltip +findQuiz _ = [] + +-- If we have []{.tooltip} we have a tooltip ;) +-- we save the text and the attributes in a tuple +findTooltip :: Inline -> Maybe ([Inline],Attr) +findTooltip (Span attr@(_,att,_) tooltipText) + | "tooltip" `elem` att = Just (tooltipText, attr) +findTooltip _ = Nothing + +-- Generate Divs for the quiz +makeQuiz :: (Attr, [Inline], Maybe ([Inline],Attr)) -> Block +makeQuiz (att, answer, Nothing) = Div att [Plain answer] +makeQuiz (att, answer, Just (tooltip,a)) = Div att [Plain answer, Div a [Plain tooltip]] diff --git a/src/Text/Pandoc/Util/Filter/Styling.hs b/src/Text/Pandoc/Util/Filter/Styling.hs new file mode 100644 index 0000000..09d4c4f --- /dev/null +++ b/src/Text/Pandoc/Util/Filter/Styling.hs @@ -0,0 +1,64 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +module Text.Pandoc.Util.Filter.Styling + (styling, inlineStyling) + where + +import Text.Pandoc.JSON +import Data.Monoid ((<>)) +import Text.Pandoc.Util.Filter +import Prelude hiding (div, span) + +-- | Block-Styling +-- +-- Special cases captured: +-- +-- - #col turns a div into a floating-div for multiple columns +-- - CodeBlock gets attributes @data-trim@ and @data-noescape@ +-- automatically +-- - .fragment and .frame work properly on divs +styling :: Block -> IO [Block] +styling (Div ("col",att,att') inner) = return $ [toBlockHtml $ "
    unwords direct <> attToString ("",css,att') <> ">"] + ++ inner + ++ [toBlockHtml"
    "] + where + (direct, css) = classToRevealAttr att +styling (CodeBlock (id',att,att') inner) = return + [CodeBlock (id', addToAtt "data-trim" + . addToAtt "data-noescape" + $ att + , att') + inner] +styling div@(Div (id',att,att') inner) + | "fragment" `elem` att = return [Div (id', att, addToStyle "display: block;" att') inner] + | "frame" `elem` att = return [Div (id', addToAtt "fragment" --insert fragment + . addToAtt "current-visible" --insert current-visible + . filter (/= "frame") --remove frame + $ att + , addToStyle "display: block;" att') inner] + | otherwise = return [div] +styling x = return [x] + + +-- | Inline-Styling +-- +-- Special cases captured: +-- +-- - .fragment and .frame work properly on spans +-- - .vspace inside span adds a vertical space with @height=xxx@ +-- - .hspace inside span adds a horizontal space with @width=xxx@ +inlineStyling :: Inline -> Inline +inlineStyling span@(Span (id', att, att') inner) + | "fragment" `elem` att = Span (id', att, addToStyle "display: inline-block;" att') inner + | "frame" `elem` att = Span (id', addToAtt "fragment" --insert fragment + . addToAtt "current-visible" --insert current-visible + . filter (/= "frame") --remove frame + $ att + , addToStyle "display: inline-block;" att') inner + | id' == "vspace" = toHtml $ "
    unwords direct <> attToString ("",css,att') <> ">
    " + | id' == "hspace" = toHtml $ " unwords direct <> attToString ("",css,att') <> ">" + | otherwise = span + where + (direct, css) = classToRevealAttr att +inlineStyling x = x +