Custom JavaScript in Bookdown
I wanted some custom behavior in my bookdown project. Specifically, I wanted all the internal cross references to open in new tabs so that the reading flow is unbroken.
The Issue
With external references, bookdown’s formatting makes it easy to write:
[some website](theURL){target="_blank"}
which parses to
<a href="theURL" target="_blank">some website</a>
But the bookdown internal cross-reference works like:
[some cross reference][the section ID]
This doesn’t accept the additional {target="_blank"}
. So how to fix this?
JavaScript to the Rescue
JavaScript <script>
s in the HTML document allow you to modify the HTML after bookdown (well, pandoc actually) finishes rendering the output into HTML static files. My understanding is that this re-rendering and HTML addition is actually carried out by the browser when it encounters the <script></script>
tags in an HTML document.
First, I found this post, and the first answer there (this one) told me that I could use a very simple JS script to retroactively add all my nice target="_blank"
s:
var links = document.getElementsByTagName('a');
var len = links.length;
for(var i=0; i<len; i++)
{
links[i].target = "_blank";
}
This script gets all the <a></a>
link tags, and adds the code iteratively in a loop. If the link already had a target="_blank"
tag, it just overwrites it. Probably it would be “more correct” to ignore those that already have the tag, but it ain’t broke so I ain’t fixin it.
How do I get this thing to run?
I’m fairly new to JS, but luckily I found this post regarding JS and bookdown. Unfortunately the person was not answered, but their code told me I just needed to do three things in my bookdown project.
First, I needed to make a new file in the assets/styling/
folder called scripts.html
. I could put this file anywhere and call it anything, but I consider what I’m doing here “styling”. Now any other JS scripts I want in my project can go into assets/styling/scripts.html
.
Second, I just need to drop the above JS script into the new file with some HTML tags:
<script>
var links = document.getElementsByTagName('a');
var len = links.length;
for(var i=0; i<len; i++)
{
links[i].target = "_blank";
}
</script>
Lastly, I need to point the file out to bookdown, so that it will add the script to each HTML file, which will then later be interpreted by the browser. I just need to add the following to the _output.yml
file associated with my bookdown project:
bookdown::gitbook:
css: assets/styling/style.css
pandoc_args: ["--lua-filter=assets/styling/footnote.lua"]
includes:
in_header: assets/styling/style.html
after_body: assets/styling/scripts.html
# ...
Now the project includes my custom script added to every HTML page.