[Tex/LaTex] Best workflows or tools to generate an html web page from a complex latex document like thesis

conversioncsshtmlpandocthesis

I'm really interested to publish my thesis on a website HTML + CSS (when it's done) augmented with tools to annotate it, like the philoweb initative (see here, and here).

I know the universal converter Pandoc or the latex2html, but i'm interested to know if others tools exists, or if some users already create a batch workflow to make this conversion automaticaly.

Perhaps it can be a community wiki question ?

Updated list (16 april 2015) :

MWE creation :

I propose a first link to collaborate on a complex MWE to test these tools, which contain all complex elements you want :

Link to public MWE on sharelatex

Things to transform and eventually beautify with some js :

  • Math
  • Complex Side Caption
  • Bibliography
  • Public annotation

Example of great conversion :

Best Answer

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:

enter image description here

annotation examples:

enter image description here enter image description here

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;
}

enter image description here

The TOC can be hidden by click on the ^^^ text.

enter image description here

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();
    }
  }
});

enter image description here

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

Related Question