{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_GHC -Wall #-} -- | mathjax functionality. -- -- some assets -- -- -- -- FIXME: Mathjax inside svg doesn't quite work, and needs to be structured around the foreign object construct. module Web.Rep.Mathjax ( mathjaxPage, mathjax27Page, mathjaxSvgPage, mathjax27SvgPage, ) where import Control.Lens import Lucid import NumHask.Prelude import Text.InterpolatedString.Perl6 import Web.Rep.Page mathjax3Lib :: Html () mathjax3Lib = with (script_ mempty) [ src_ "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-svg.js", id_ "MathJax-script", async_ "" ] mathjax27Lib :: Html () mathjax27Lib = with (script_ mempty) [ src_ "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_SVG" ] jqueryLib :: Html () jqueryLib = with (script_ mempty) [ src_ "https://code.jquery.com/jquery-3.3.1.slim.min.js", integrity_ "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo", crossorigin_ "anonymous" ] -- | A 'Page' that loads mathjax mathjaxPage :: Page mathjaxPage = mempty & #jsGlobal .~ RepJsText scriptMathjaxConfig & #libsJs .~ [ mathjax3Lib ] -- | A 'Page' that loads the mathjax 2.7 js library mathjax27Page :: Page mathjax27Page = mempty & #jsOnLoad .~ RepJsText scriptMathjaxConfig & #libsJs .~ [ mathjax27Lib ] -- | A 'Page' that tries to enable mathjax inside svg (which is tricky). mathjaxSvgPage :: Text -> Page mathjaxSvgPage cl = mempty & #jsGlobal .~ RepJsText (scriptMathjaxConfigSvg cl) & #libsJs .~ [ mathjax3Lib, jqueryLib ] -- | A 'Page' that tries to enable mathjax 2.7 inside svg. mathjax27SvgPage :: Text -> Page mathjax27SvgPage cl = mempty & #jsGlobal .~ RepJsText (scriptMathjax27ConfigSvg cl) & #libsJs .~ [ mathjax27Lib, jqueryLib ] scriptMathjaxConfig :: Text scriptMathjaxConfig = [q| MathJax = { tex: { inlineMath: [ ['$','$'], ["\\(","\\)"] ] } }; |] -- | Mathjax applies within an svg element as normal, but results in an svg element inside a text element which is not allowed, hence the extra scripting. -- http://bl.ocks.org/larsenmtl/86077bddc91c3de8d3db6a53216b2f47 scriptMathjax27ConfigSvg :: Text -> Text scriptMathjax27ConfigSvg cl = [qq| setTimeout(() => \{ MathJax.Hub.Config(\{ tex2jax: \{ inlineMath: [ ['$','$'], ["\\(","\\)"] ], processEscapes: true } }); MathJax.Hub.Register.StartupHook("End", function() \{ setTimeout(() => \{ $('.{cl}').each(function()\{ var m = $('text>span>svg'); m.remove(); $(this).append(m); }); }, 1); }); }, 1); |] -- | Mathjax applies within an svg element as normal, but results in an svg element inside a text element which is not allowed, hence the extra scripting. -- http://bl.ocks.org/larsenmtl/86077bddc91c3de8d3db6a53216b2f47 scriptMathjaxConfigSvg :: Text -> Text scriptMathjaxConfigSvg cl = [qq| window.MathJax = \{ tex: \{ inlineMath: [ ['$','$'], ["\\(","\\)"] ] }, startup: \{ ready: () => \{ MathJax.startup.defaultReady(); MathJax.startup.promise.then(() => \{ var xs = document.querySelectorAll('.{cl}'); xs.forEach((x) => \{ x.querySelectorAll('text').forEach((t) => \{t.querySelectorAll('mjx-container>svg').forEach((s) => \{ Array.from(t.attributes).forEach((a) => s.setAttribute(a.name, a.value)); x.appendChild(s); }); }); }); }); } } }; |]