Commit 2d17ce94 authored by Henrik Tramberend's avatar Henrik Tramberend
Browse files

Merge branch 'master' into henrik-winter-2020

parents cf343ddd f7eda79d
project-name: Decker
controls: 0
exclude-directories:
- app
- attic
......@@ -16,6 +17,4 @@ exclude-directories:
- users-guide
static-resource-dirs:
- test/static
publish:
rsync:
destination: henrik@tramberend.beuth-hochschule.de:/var/www/public/decker
- test/decks/geometry/static
......@@ -69,7 +69,7 @@ server:
stack run -- decker --server --port 8888 --bind localhost decks
css:
cd resource/support/css && make css
cd resource/support/css && make -B css
clean:
stack clean
......
This diff is collapsed.
This diff is collapsed.
......@@ -32,6 +32,7 @@ function deckerStart() {
if (!printMode) {
setTimeout(continueWhereYouLeftOff, 500);
}
renderSvgMath();
}
function prepareTaskLists() {
......@@ -292,6 +293,22 @@ function continueWhereYouLeftOff() {
}
}
// TODO: Make geometry.js into a proper module and arrange it to be loaded after
// TODO: MathJax.
function renderSvgMath() {
// Create a copy of the script with type 'geometry' that has type 'module' and
// will be executed immediately. Defers script execution until after MathJax
// has been initialized. Deletes the original 'geometry' script.
let scripts = document.querySelectorAll("script[type=geometry]");
for (let script of scripts) {
let js = document.createElement("script");
js.setAttribute("type", "module");
js.innerText = script.innerText;
script.insertAdjacentElement("beforebegin", js);
script.parentNode.removeChild(script);
}
}
// List of predicates that all must return true for a requested reload to
// actually be performed.
let reloadInhibitors = [];
......
......@@ -605,7 +605,7 @@ function buildInterface() {
.submitComment(
engine.deckId,
slideId,
user.value,
engine.token.admin || user.value,
text.value,
text.commentId,
window.location.toString()
......
......@@ -186,6 +186,9 @@ $for(style)$
$style$
</style>
$endfor$
$for(template.include-js)$
<script src="$template.include-js$"></script>
$endfor$
</head>
<body data-deckid="$deck-id$">
$for(include-before)$
......@@ -315,8 +318,8 @@ $endif$
prepareExaminer();
</script>
$for(template.include-js)$
<script src="$template.include-js$"></script>
$for(template.include-js)$
<script src="$template.include-js$"></script>
$endfor$
<script>
......
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
......@@ -11,10 +12,10 @@ module Text.Decker.Filter.Decker where
import Relude
import Text.Decker.Filter.Header
import Text.Decker.Filter.Image
import Text.Decker.Filter.Local
import Text.Decker.Filter.Monad
import Text.Decker.Filter.Image
import Text.Decker.Filter.Util
import Text.Decker.Filter.Util (forceBlock, oneImagePerLine)
import Text.Decker.Internal.Common
import Text.Pandoc hiding (lookupMeta)
import Text.Pandoc.Walk
......@@ -115,7 +116,7 @@ mediaInlineFilter inline = return inline
-- and meta data via `gets` and `puts`.
runFilter ::
Walkable a Pandoc =>
Disposition ->
Disposition ->
WriterOptions ->
(a -> Filter a) ->
Pandoc ->
......@@ -135,4 +136,3 @@ runFilter' dispo options meta filter x =
extIn :: Maybe Text -> [Text] -> Bool
extIn (Just ext) list = ext `elem` list
extIn Nothing _ = False
......@@ -8,9 +8,9 @@ import Data.Maybe
import Data.Monoid
import Relude
import Text.Decker.Filter.Attrib
import Text.Decker.Filter.Image
import Text.Decker.Filter.Local
import Text.Decker.Filter.Monad
import Text.Decker.Filter.Image
import Text.Decker.Internal.Common
import Text.Decker.Internal.Exception
import Text.Pandoc
......
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}
......@@ -27,6 +28,35 @@ import Text.Printf
import Text.URI (URI)
import qualified Text.URI as URI
-- |  Generates an HTML error message for Image inlines from the image
-- source and the actual exception. The Image element is rendered back
-- to Markdown format and included in the error message.
inlineError :: Inline -> SomeException -> Filter Inline
inlineError img@Image {} (SomeException e) = do
imgMarkup <- inlinesToMarkdown [img]
renderHtml $
H.div ! A.class_ "decker image error" $ do
H.h2 ! A.class_ "title" $ do
H.i ! A.class_ "fa fa-exclamation-triangle" $ ""
H.text " Decker error"
H.p ! A.class_ "message" $ toHtml (displayException e)
H.p $ H.text "encountered while processing"
H.pre ! A.class_ "markup" $ H.code ! A.class_ "markup" $ toHtml imgMarkup
inlineError _ _ = bug $ InternalException "inlineError: non image argument "
blockError :: Block -> SomeException -> Filter Block
blockError code@CodeBlock {} (SomeException e) = do
codeMarkup <- blocksToMarkdown [code]
renderHtml $
H.div ! A.class_ "decker image error" $ do
H.h2 ! A.class_ "title" $ do
H.i ! A.class_ "fa fa-exclamation-triangle" $ ""
H.text " Decker error"
H.p ! A.class_ "message" $ toHtml (displayException e)
H.p $ H.text "encountered while processing"
H.pre ! A.class_ "markup" $ H.code ! A.class_ "markup" $ toHtml codeMarkup
blockError _ _ = bug $ InternalException "blockError: non code argument "
imageTransformers :: Map MediaT (URI -> [Inline] -> Attrib Html)
imageTransformers =
Map.fromList
......@@ -38,8 +68,8 @@ imageTransformers =
(VideoT, videoHtml),
(StreamT, streamHtml'),
(AudioT, audioHtml),
(RenderT, renderCodeHtml)
-- , (ExamQuestT, examQuestHtml)
(RenderT, renderCodeHtml),
(JavascriptT, javascriptHtml)
]
transformImage :: Inline -> [Inline] -> Filter Inline
......@@ -68,7 +98,7 @@ transformImages images caption = do
H.div ! A.class_ "decker image-row" $ toHtml $ map toHtml imageRow
H.figcaption captionHtml
language = find (`elem` ["dot", "gnuplot", "tex"])
language cls = find (`elem` ["dot", "gnuplot", "tex"]) cls
-- TODO this is incomplete
-- - captions are just swallowed but never rendered.
......@@ -76,18 +106,24 @@ language = find (`elem` ["dot", "gnuplot", "tex"])
transformCodeBlock :: Block -> [Inline] -> Filter Block
transformCodeBlock code@(CodeBlock attr@(_, classes, _) text) caption =
handle (blockError code) $
case language classes of
Just ext
| "render" `elem` classes ->
runAttr attr (transform ext) >>= renderHtml
_ -> return code
if
| all (`elem` classes) ["dot", "render"] ->
runAttr attr (transform "dot") >>= renderHtml
| all (`elem` classes) ["gnuplot", "render"] ->
runAttr attr (transform "gnuplot") >>= renderHtml
| all (`elem` classes) ["tex", "render"] ->
runAttr attr (transform "tex") >>= renderHtml
| all (`elem` classes) ["javascript", "run"] ->
runAttr attr (renderJavascriptHtml text) >>= renderHtml
| otherwise -> return code
where
transform :: Text -> Attrib Html
transform ext = do
dropClass ext
let crc = printf "%08x" (calc_crc32 $ toString text)
let path =
transientDir </> "code" </> intercalate "-" ["code", crc]
transientDir </> "code"
</> intercalate "-" ["code", crc]
<.> toString ext
exists <- liftIO $ doesFileExist path
unless exists $
......@@ -229,6 +265,18 @@ svgHtml uri caption = do
injectBorder >> takeSizeIf isPercent >> takeUsual
mkFigureTag svgTag captionHtml <$> extractAttr
javascriptHtml :: URI -> [Inline] -> Attrib Html
javascriptHtml uri caption = do
uri <- lift $ transformUri uri ""
javascript <- lift $ readLocalUri uri
case caption of
[] -> renderJavascriptHtml javascript
caption -> do
captionHtml <- lift $ inlinesToHtml caption
javascriptTag <- renderJavascriptHtml javascript
injectBorder >> takeSizeIf isPercent >> takeUsual
mkFigureTag javascriptTag captionHtml <$> extractAttr
mviewHtml :: URI -> [Inline] -> Attrib Html
mviewHtml uri caption = do
uri <- lift $ transformUri uri ""
......@@ -312,49 +360,10 @@ renderCodeHtml uri caption = do
injectBorder >> takeSizeIf isPercent >> takeUsual
mkFigureTag imageTag captionHtml <$> extractAttr
-- |  Generates an HTML error message for Image inlines from the image
-- source and the actual exception. The Image element is rendered back
-- to Markdown format and included in the error message.
inlineError :: Inline -> SomeException -> Filter Inline
inlineError img@Image {} (SomeException e) = do
imgMarkup <- inlinesToMarkdown [img]
renderHtml $
H.div ! A.class_ "decker image error" $ do
H.h2 ! A.class_ "title" $ do
H.i ! A.class_ "fa fa-exclamation-triangle" $ ""
H.text " Decker error"
H.p ! A.class_ "message" $ toHtml (displayException e)
H.p $ H.text "encountered while processing"
H.pre ! A.class_ "markup" $ H.code ! A.class_ "markup" $ toHtml imgMarkup
inlineError _ _ = bug $ InternalException "inlineError: non image argument "
blockError :: Block -> SomeException -> Filter Block
blockError code@CodeBlock {} (SomeException e) = do
codeMarkup <- blocksToMarkdown [code]
renderHtml $
H.div ! A.class_ "decker image error" $ do
H.h2 ! A.class_ "title" $ do
H.i ! A.class_ "fa fa-exclamation-triangle" $ ""
H.text " Decker error"
H.p ! A.class_ "message" $ toHtml (displayException e)
H.p $ H.text "encountered while processing"
H.pre ! A.class_ "markup" $ H.code ! A.class_ "markup" $ toHtml codeMarkup
blockError _ _ = bug $ InternalException "blockError: non code argument "
{--
examQuestHtml :: URI -> [Inline] -> Attrib Html
examQuestHtml uri caption = do
uri <- lift $ transformUri uri ""
source <- lift $ readLocalUri uri
let result = Y.decodeEither' (encodeUtf8 source)
case result of
Left err -> throwM $ InternalException $ show err
Right question -> do
quiz <- liftIO $ toQuiz question
liftIO $ putStrLn $ groom quiz
let block = renderQuizzes quiz
opts <- lift $ gets options
case runPure (writeHtml5 opts (Pandoc nullMeta [block])) of
Left err -> throwM $ InternalException $ show err
Right html -> return html
--}
renderJavascriptHtml :: Text -> Attrib Html
renderJavascriptHtml code = do
id <- liftIO randomId
let anchor = "let anchor = document.getElementById(\"" <> id <> "\");\n"
return $ do
H.div ! A.id (toValue id) ! A.class_ "geometry" $ ""
H.script ! A.class_ "geometry" ! A.type_ "geometry" $ toHtml (anchor <> code)
......@@ -10,6 +10,7 @@ import Data.Digest.Pure.MD5
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Relude
import System.Random
import Text.Blaze.Html
import qualified Text.Blaze.Html.Renderer.Pretty as Pretty
import qualified Text.Blaze.Html.Renderer.Text as Text
......@@ -62,6 +63,8 @@ yamlExt = ["yaml", "yml"]
renderExt = ["dot", "gnuplot", "tex"]
javascriptExt = ["js"]
mviewExt = ["off", "obj", "stl", "ply", "pmp"]
streamScheme = ["youtube", "vimeo", "twitch", "veer", "veer-photo"]
......@@ -76,6 +79,7 @@ data MediaT
| EmbedSvgT
| MviewT
| RenderT
| JavascriptT
| StreamT
| ExamQuestT
deriving (Show, Eq, Ord)
......@@ -84,18 +88,20 @@ classifyMedia :: URI -> Attr -> MediaT
classifyMedia uri (_, classes, _) =
let ext = uriPathExtension uri
scheme = uriScheme uri
in if | ext `maybeElem` svgExt && "embed" `elem` classes -> EmbedSvgT
| ext `maybeElem` renderExt && "render" `elem` classes -> RenderT
| ext `maybeElem` imageExt || "image" `elem` classes -> ImageT
| ext `maybeElem` videoExt || "video" `elem` classes -> VideoT
| ext `maybeElem` audioExt || "audio" `elem` classes -> AudioT
| ext `maybeElem` iframeExt || "iframe" `elem` classes -> IframeT
| ext `maybeElem` pdfExt || "pdf" `elem` classes -> PdfT
| ext `maybeElem` mviewExt || "mview" `elem` classes -> MviewT
| ext `maybeElem` codeExt || "code" `elem` classes -> CodeT
| ext `maybeElem` yamlExt && "question" `elem` classes -> ExamQuestT
| scheme `maybeElem` streamScheme -> StreamT
| otherwise -> ImageT
in if
| ext `maybeElem` svgExt && "embed" `elem` classes -> EmbedSvgT
| ext `maybeElem` renderExt && "render" `elem` classes -> RenderT
| ext `maybeElem` javascriptExt && "run" `elem` classes -> JavascriptT
| ext `maybeElem` imageExt || "image" `elem` classes -> ImageT
| ext `maybeElem` videoExt || "video" `elem` classes -> VideoT
| ext `maybeElem` audioExt || "audio" `elem` classes -> AudioT
| ext `maybeElem` iframeExt || "iframe" `elem` classes -> IframeT
| ext `maybeElem` pdfExt || "pdf" `elem` classes -> PdfT
| ext `maybeElem` mviewExt || "mview" `elem` classes -> MviewT
| ext `maybeElem` codeExt || "code" `elem` classes -> CodeT
| ext `maybeElem` yamlExt && "question" `elem` classes -> ExamQuestT
| scheme `maybeElem` streamScheme -> StreamT
| otherwise -> ImageT
maybeElem :: Eq a => Maybe a -> [a] -> Bool
maybeElem (Just x) xs = x `elem` xs
......@@ -297,5 +303,8 @@ hash9String text = take 9 $ show $ md5 $ encodeUtf8 text
hash9 :: Text -> Text
hash9 text = Text.pack $ take 9 $ show $ md5 $ encodeUtf8 text
randomId :: IO Text
randomId = Text.pack . take 9 . show . md5 . show <$> (randomIO :: IO Int)
single :: a -> [a]
single x = [x]
---
title: ES6 Modules in Code Blocks
---
# By hand
::: {#sh62fss45f}
:::
<script type="module">
let anchor = document.getElementById("sh62fss45f");
import * as mod from "/test/static/es6.js";
mod.hello(anchor, "green");
</script>
# One more
::: {#sh62fss45e}
:::
<script type="module">
let anchor = document.getElementById("sh62fss45e");
import * as mod from "/test/static/es6.js";
mod.hello(anchor, "red");
</script>
# Decker inline
``` {.javascript .run}
import * as mod from "/test/static/es6.js";
mod.hello(anchor, "orange");
```
Caption: Fuck YEAH!
# Decker include
![Fuck YEAH!](/test/static/es6-blue.js){.run width="100%"}
import * as g from "./static/geometry.js";
let p1 = g.point(60, 60, "drag");
let p2 = g.point(540, 60);
let p3 = g.point(540, 340);
let p4 = g.point(60, 340, "drag");
let l1 = g.line(p1, p2);
let l2 = g.line(p2, p3);
let l3 = g.line(p3, p4);
let segment = g.bezier(p1, p2, p3, p4);
g.renderSvg(anchor, 600, 400, g.group(segment, l1, l2, l3));
---
template:
css: ./static/geometry.css
title: ES6 Modules in Code Blocks
---
# Code Blocks with a *`run`* class
## Markdown
<style>
#the-markdown-2 {
background-color: #fa6;
}
#generated-html-4 {
background-color: #fa6;
}
</style>
```` {#the-markdown .markdown}
``` {.javascript .run}
console.log("Hello", anchor);
```
````
## HTML
``` {#generated-html .html}
<div id="06c02d29c"></div>
<script type="module">
let anchor = document.getElementById("06c02d29c");
console.log("Hello", anchor);
</script>
```
------------------------------------------------------------------------
# Code Blocks with a *`run`* class
## Import any ES6 module(s)
```` {.markdown}
``` {.javascript .run}
import * as g from "./static/geometry.js";
let segment = g.bezier(
g.point(60, 60),
g.point(540, 60, "drag"),
g.point(540, 340, "drag"),
g.point(60, 340)
);
g.renderSvg(anchor, 600, 400, segment);
```
````
------------------------------------------------------------------------
# Bezier segment {.columns}
## {.left}
``` {.javascript .run}
import * as g from "./static/geometry.js";
let segment = g.bezier(
g.point(60, 60),
g.point(540, 60, "drag"),
g.point(540, 340, "drag"),
g.point(60, 340)
);
g.renderSvg(anchor, 600, 400, segment);
```
## {.right .fragment}
![Make sure to drag the green ones!](./bezier.js){.run width="100%"}
------------------------------------------------------------------------
# Intersection
##
![](./intersection.js){.run width="100%"}
------------------------------------------------------------------------
# Mirror {.columns}
## {.left}
![](./mirror.js){.run width="100%"}
## {.right .fragment}
![$\mathbf{d}_r=-\mathbf{d}_i+2(\mathbf{d}_i\cdot{\mathbf{n}})\mathbf{n}$](./unfold.js){.run
width="100%"}
------------------------------------------------------------------------
# Labels
``` {.javascript .run}
import * as g from "./static/geometry.js";
let p = g.point(100,350, "drag");
let q = g.point(300,350, "drag");
let r = g.point(600,350, "drag");
let s = g.point(900,350, "drag");
g.renderSvg(anchor, 1200, 500, g.group(
g.label(g.point(100,100), "A", "n"),
g.label(g.point(200,100), "B", "ne"),
g.label(g.point(300,100), "C", "e"),
g.label(g.point(400,100), "D", "se"),
g.label(g.point(500,100), "E", "s"),
g.label(g.point(600,100), "F", "sw"),
g.label(g.point(700,100), "G", "w"),
g.label(g.point(800,100), "H", "nw"),
g.mlabel(g.point(100,200), "A", "n"),
g.mlabel(g.point(200,200), "B", "ne"),
g.mlabel(g.point(300,200), "C", "e"),
g.mlabel(g.point(400,200), "D", "se"),
g.mlabel(g.point(500,200), "E", "s"),
g.mlabel(g.point(600,200), "F", "sw"),
g.mlabel(g.point(700,200), "G", "w"),
g.mlabel(g.point(800,200), "H", "nw"),
g.mlabel(p, "A", "n"),
g.mlabel(p, "B", "ne"),
g.mlabel(p, "C", "e"),
g.mlabel(p, "D", "se"),
g.mlabel(p, "E", "s"),
g.mlabel(p, "F", "sw"),
g.mlabel(p, "G", "w"),
g.mlabel(p, "H", "nw"),
g.label(q, "A", "n" ),
g.label(q, "B", "ne"),
g.label(q, "C", "e" ),
g.label(q, "D", "se"),
g.label(q, "E", "s" ),
g.label(q, "F", "sw"),
g.label(q, "G", "w" ),
g.label(q, "H", "nw"),
g.mlabel(r, "A", "n" ),
g.mlabel(r, "BBBB", "ne"),
g.mlabel(r, "CCCC", "e" ),
g.mlabel(r, "DDDD", "se"),
g.mlabel(r, "E", "s" ),
g.mlabel(r, "FFFF", "sw"),
g.mlabel(r, "GGGG", "w" ),
g.mlabel(r, "HHHH", "nw"),
g.label(s, "A", "n" ),
g.label(s, "BBBB", "ne"),
g.label(s, "CCCC", "e" ),
g.label(s, "DDDD", "se"),
g.label(s, "E", "s" ),
g.label(s, "FFFF", "sw"),
g.label(s, "GGGG", "w" ),
g.label(s, "HHHH", "nw"),
));
```
# Infinite Line
``` {.javascript .run}
import * as g from "./static/geometry.js";
let p = g.point(100,150, "drag");
let q = g.point(400,150, "drag");
g.renderSvg(anchor, 500, 300, g.group(
g.line(p, q, "infinite")
));
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Geometry</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" media="screen" href="geometry.css" />
<script src="d3.v6.min.js"></script>
</head>
<body>
<div id="drawing"></div>
<script type="module">
import {
point,
label,
line,