I will show a solution with tex4ht
. I used your sample text and added some math samples from the internet. You can see the complete resulting webpage on my Github page. All code is also hosted on Github.
You have four wishes, some of them can be solved using external Javascript tools, for others we must create custom JS scripts.
tex4ht
can be configured using .cfg
file. This file has special structure:
...
\Preamble{xhtml,list of options}
...
\begin{document}
...
\EndPreamble
we can require some packages before \Preamble
command, which we may use for some helper packages. In our example, we may need two packages:
- one for fixes some issues with Memoir under
tex4ht
- other with some helper macros
you need recently updated TeX Live for latest bug fixes for tex4ht
Memoir support, in this case you need only fo fix this issue with double Bibliography entry in the TOC.
This can be fixed with mem4hack.sty
:
\renewcommand\@memb@bchap{\chapter*{\bibname}\bibmark\prebibhook}
the other supporting package is tools.sty
:
\newcommand\AddFile[1]{\special{t4ht+@File: #1}}%
\newcommand\AddCss[1]{%
\AddFile{#1}%
\Configure{@HEAD}{\HCode{<link rel="stylesheet" type="text/css" href="#1" />}}
}
\newcommand\AddJs[1]{%
\AddFile{#1}%
\Configure{@HEAD}{\HCode{\Hnewline<script type="text/javascript" src="#1"></script>}}
}
This simplifies inclusion of CSS
and JS
files in your project.
Regarding used libraries, we can use mathjax
for math support and
hypothes.is
for annotating. Unfortunately, this doesn't work with local pages, you have to use a webserver (but you can install it on your local computer, you don't need actual server).
Math example:
annotation examples:
For sidebar, you can make a standalone file for each chapter, with local TOC for sections and subsections. So you can make sidebar containing this TOC and links to previous and next chapter.
The code is here js/sidebar.js
:
document.addEventListener("DOMContentLoaded", function() {
// Code
// select local TOC
var menu = q(".chapterTOCS")[0];
var menuopened = "^^^";
var m = createEl("a","menu",menuopened);
var toolbar = createEl("div","toolbar");
var sidebar = createEl("div","sidebar","");
var crosslinks = q(".crosslinks")[0];
var setText = function(node,a){
var text = document.createTextNode(a);
node.removeChild(node.childNodes[0]);
node.appendChild(text);
}
var switchMenu = function(){
// switch menu state
menu.className = hiddenswitch ? "chapterTOCS red" : "chapterTOCS hiddentoc";
var text = hiddenswitch ? menuopened:"TOC" ;
// set menu class to changed state
setText(m, text);
hiddenswitch = !hiddenswitch;
}
// pass reference to new container and crosslinks
var transfromCrosslinks = function(newcrosslinks,el){
// find all crosslinks
var links = el.querySelectorAll("a");
var newcrs = {}
// make table with link text as name
for(i=0;i!=links.length;i++){
var text = links[i].firstChild.nodeValue;
newcrs[text] = links[i];
}
// select next, prev and up nodes and replace text with unicode arrows
// is a node doesn't exist, create span with blanklink class
var next = newcrs["next"] || createEl("span","blanklink",">")
setText(next,"⇨");
var prev = newcrs["prev"]|| createEl("span","blanklink",">")
setText(prev,"⇦");
setText(newcrs["up"],"⇧");
// add crosslinks to a toolbar
newcrosslinks.appendChild(prev);
newcrosslinks.appendChild(newcrs["up"]);
newcrosslinks.appendChild(next);
crosslinks.remove();
return newcrosslinks;
}
// add elements to the sidebar depending on existence of a local TOC and
// crosslinks
if(crosslinks){
transfromCrosslinks(toolbar,crosslinks);
// add sidebat only if it doesn't exist already
if(!menu) sidebar.appendChild(toolbar);
//m.appendChild(newcrosslinks);
}
if(menu) {
toolbar.appendChild(m);
sidebar.appendChild(toolbar);
sidebar.appendChild(menu);
}
q("body")[0].appendChild(sidebar);
var hiddenswitch = false
m.on("click",switchMenu,false);
//menu.insertBefore(m,menu.childNodes[0]);
}, false);
this uses standard Javascript DOM functions, only small library js/fw.js
is being used:
// basic DOM functions
// based on http://blog.adtile.me/2014/01/16/a-dive-into-plain-javascript/
var q = document.querySelectorAll.bind(document);
Element.prototype.on = Element.prototype.addEventListener;
var createEl = function(el, cls, text){
var x = document.createElement(el);
x.setAttribute("class",cls);
if(text) {
var t = document.createTextNode(text);
x.appendChild(t);
}
return x;
}
The TOC
can be hidden by click on the ^^^
text.
For bibliography, we can load bibliography page using AJAX
and show the citations in a window when you point a cursor over a citation. Window can be closed by clicking anywhere in the document.
File js/bib.js
:
var bibdoc = null;
var isBibbox = function(){
return q("#bibbox").length>0;
}
var makeBibTooltip = function(bib,id,el){
if(!isBibbox()){
var xxx = bib.querySelector(id).parentNode.cloneNode(true);
var parentpos = el.getBoundingClientRect();
var tip = document.createElement("div");
tip.setAttribute("id", "bibbox")
tip.style.position = "fixed";
tip.style.top = parentpos.bottom+ 10+"px";
tip.style.left = parentpos.left+ 10 +"px" ;
tip.appendChild(xxx);
document.body.appendChild(tip);
}
}
var getBibDoc = function(url,id,el){
if(!bibdoc){
var ajax = new XMLHttpRequest();
console.log("Load ajax"+url)
bibdoc = ajax.open("GET",url,true);
ajax.send();
ajax.onreadystatechange = function(){
if(ajax.readyState == 4 && ajax.status==200 && !bibdoc){
var res = ajax.responseText;
bibdoc = createEl("div","bib");
bibdoc.innerHTML = res;
makeBibTooltip(bibdoc,id,el);
}
}
}else{
makeBibTooltip(bibdoc,id,el);
}
}
document.addEventListener("DOMContentLoaded", function() {
var bibs = q("span.cite");
for(i=0;i<bibs.length;i++){
bibs[i].on("mouseover", function(e){
var el = e.currentTarget;
var link = el.querySelector("a");
var hash = link.hash;
var href = link.getAttribute("href");
getBibDoc(href,hash,el);
//var target = bib.querySelector("body");
//console.log("nazdar "+ target);
});
}
});
document.addEventListener("click",function(){
if(isBibbox()){
var bibbox = q("#bibbox");
for(i=0;i<bibbox.length;i++){
bibbox[i].remove();
}
}
});
We can also make a better typography, I really like Viljami Salminen's
responsive CSS boilerplate. Use the css/scale.css
file.
We can put it all together now, make file myconfig.cfg
:
\RequirePackage{mem4hack}
\RequirePackage{tools}
\Preamble{xhtml,2,mathml}
\Configure{@HEAD}{\HCode{\Hnewline<script type="text/javascript"\Hnewline
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=MML_HTMLorMML"\Hnewline
></script>\Hnewline}}
\Configure{@HEAD}{\HCode{\Hnewline<script async defer src="http://hypothes.is/embed.js"></script>}}
\AddCss{css/scale.css}
\AddJs{js/fw.js}
\AddJs{js/sidebar.js}
\AddJs{js/bib.js}
% fix sublist indentation
\Css{li li{margin-left:2em;}}
\Css{dd dl{margin-left:2em;}}
% we can use helper macros to use variables in the CSS
\def\numcalc#1{\the\numexpr #1\relax}
\def\sidebarwidth{18}
% sidebar is on a fixed position. you should play with this
\Css{.sidebar{position:fixed;width:\sidebarwidth em;top:3em;left:100\%;margin-left:-\numcalc{\sidebarwidth+2}em;}}
% fix local TOC formating
\Css{.sidebar .sectionToc,.sidebar .subsectionToc{display:block;margin-top:-1em;margin-bottom:0px;}}
\Css{.sidebar .chapterTOCS br{display:none;}}
% we can turn off the local TOC
\Css{.hiddentoc{display:none;}}
% TOC switch formatting
\Css{.menu{margin-left:1em;}}
\Css{.menu red{font-size:0,7em;vertical-align:sub;}}
% toolbar displays links to previous and next chapters and TOC switcher
\Css{.toolbar{font-size:1.3em;background-color:\#fed;}}
% tooltip which displays bibliographic record when you point
% a cursor on a citation
\Css{\#bibbox{border:1px solid black;background-color:\#fed;width:25em;}}
% make standalone page for each chapter. make local TOC for contained sections
% and subsections
\TocAt{chapter,section,subsection}
\begin{document}
% we can delete normal TOC, it is created automatically by tex4ht and it
% would be duplicated
\makeatletter
\renewcommand\tableofcontents{\@ifstar{}{}}
\makeatother
\EndPreamble
In the \Preamble
command, options for tex4ht
are specified. xhtml
requests xhtml
output, 2
breaks document into standalone web page at every \chapter
(1
would break it at every part, 3
at every section ...), mathml
requests conversion of math to mathml
.
Configurations should go after \Preamble
command.
Internal js
and CSS
files are included using \AddJs
resp. \AddCss
commands. mathjax
and hypothes.is
are included using links to external pages, which is configured using
\Configure{@HEAD}{...}
this configuration add stuff to the html <head>
element.
You can add CSS
styles using \Css
command. The included styles are pretty basic, you may want to (and really should) modify them for better look, concentrated only on functionality, not aesthetics)
Now you can compile your file using
htlatex thesis myconfig
or better, use make4ht which is
alternative build system for tex4ht
. This build file will copy all used files
to /var/www/html/reyman/
directory, so you can open in your browser this
address: localhost/reyman/thesis.html
and everything should work. If you have Unix like system, Apache web server and
write permissions to that directory. File thesis.mk4
:
local mkutils = require "mkutils"
local outdir = "/var/www/html/reyman/"
if mode == "draft" then
Make:htlatex {}
else
Make:add("bibtex", "bibtex ${input}")
Make:htlatex {}
Make:bibtex {}
Make:htlatex {}
Make:htlatex {}
end
Make:match(".*$", function(file, par)
mkutils.copy(file, outdir .. file)
return false, "Copy html to destination "..outdir
end)
Compile with
make4ht -u -c myconfig thesis
to speedup the compilation, you can use
make4ht -um draft -c myconfig thesis
which will compile the document only once with LaTeX and it will skip the bibtex
.
You can see the result on my Github page
tex4ht
, we just need some sample document to work with