Using Javascript for a more portable web page??!!

Posted on February 18, 2016
Tags: software, hakyll

Viewable With Any Browser

I previously lamented about web pages that don’t display properly in Lynx, and I included a link to the Viewable With Any Browser campaign. However, I discovered that my own web pages (rendered by Pandoc by way of Hakyll) don’t look that great in Lynx, either, at least not when it comes to code listings.

In a modern graphical browser, the code listings look great:

Line-numbered code listing viewed with Google Chrome

But in Lynx, not so great:

Line-numbered code listing viewed with Lynx

Pandoc generates the following HTML:

<div class="sourceCode"><table class="sourceCode haskell numberLines"><tr class="sourceCode"><td class="lineNumbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="sourceCode"><pre><code class="sourceCode haskell"><span class="st">#!/usr/bin/runhaskell</span>

<span class="kw">import </span><span class="dt">System.Entropy</span>
<span class="kw">import </span><span class="dt">Data.Binary.Get</span>
<span class="kw">import qualified</span> <span class="dt">Data.ByteString.Lazy</span> <span class="kw">as</span> <span class="dt">B</span>

main <span class="fu">=</span> <span class="kw">do</span>
  bytes <span class="ot">&lt;-</span> getEntropy <span class="dv">4</span>
  print (runGet getWord32be <span class="fu">$</span> B.fromChunks [bytes])</code></pre></td></tr></table></div>

which is a table with one row and two columns. One column is for the line numbers, and the other column is for the code. Unfortunately, although I believe Lynx has some minimal support for tables, it does not seem to properly support rows which are more than one line high.

What I’d like to do is just feed the <pre> with the source code to Lynx, omitting the surrounding table and the line numbers. But I still want to get nice line numbers in browsers that can support it.

So, I implemented a huge hack. I’m using “supports Javascript” as a proxy for “supports multiline table rows,” which obviously isn’t correct, but it does work when comparing a modern graphical browser with Lynx. Further increasing the hackishness, I use Javascript’s document.write to insert the surrounding table and line numbers in a browser that supports Javascript.

(The use of document.write also means that I have to serve my pages as HTML, not XHTML, since XHTML doesn’t allow use of document.write.)

The HTML now looks like this:

<div class="sourceCode"><script>document.write(
'\x3ctable class=\x22sourceCode haskell numberL',
'ines\x22\x3e\x3ctr class=\x22sourceCode\x22\x3e\x3ctd class=\x22',
'lineNumbers\x22\x3e\x3cpre\x3e1\n2\n3\n4\n5\n6\n7\n8\n9\n\x3c/pr',
'e\x3e\x3c/td\x3e\x3ctd class=\x22sourceCode\x22\x3e'
)</script><pre><code class="sourceCode haskell"><span class="st">#!/usr/bin/runhaskell</span>

<span class="kw">import </span><span class="dt">System.Entropy</span>
<span class="kw">import </span><span class="dt">Data.Binary.Get</span>
<span class="kw">import qualified</span> <span class="dt">Data.ByteString.Lazy</span> <span class="kw">as</span> <span class="dt">B</span>

main <span class="fu">=</span> <span class="kw">do</span>
  bytes <span class="ot">&lt;-</span> getEntropy <span class="dv">4</span>
  print (runGet getWord32be <span class="fu">$</span> B.fromChunks [bytes])</code></pre><script>document.write(
'\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e'
)</script></div>

Eww, gross. But the result looks the same as before in Chrome, and it now looks better in Lynx:

Line numbers are now omitted when viewed with Lynx

There is still one problem. For reasons unknown to me, <pre> blocks in Lynx have a blank line after them but not before them, causing the code listing to be uncomfortably squished against the previous paragraph.

I solved this problem by inserting an empty <p> before the <pre>. (I tried <br> first, but for unknown reasons, that did not work.) Once again, I want this hack to only take effect in Lynx, and not a modern graphical browser. Instead of Javascript, this time it’s CSS to the rescue. I just put style="display: none;" on the dummy paragraph, and it’s ignored by modern graphical browsers. But since Lynx doesn’t support CSS, it now adds a blank line before my code listing:

Now there is a blank line before the code listing when viewed with Lynx

I have mixed feelings about these hacks, since I don’t like them, but I do like the results. I don’t see a better way to achieve this without doing server-side browser sniffing. And browser sniffing itself is an ugly hack, plus it would somewhat defeat the goal of having a static site.