SCRIPT FOR SCRIPT_AUTO_RUNNER TO MAKE SICP TEXTBOOK MORE READABLE
Overview
If you find an English expression that feel incorrect or awkward, please let me know.
Message box of Disqus is under the article.
Or my E-Mail is here.
ABOUT THIS ARTICLE
Brief Summary
We use ScriptAutoRunner for execution environment.
Hello, I'm dede.
In this article, I'll introduce a way to make SICP textbook, which is available to the public on the web, more readable
by using a short script.
WHAT'S SICP
ABOUT
SICP textbook is one of the most famous and effective CS books.
It describes frequent patterns in computer programming, such as recursive procedures and the benefits of modularity.
PUBLISHED WEB SITE
Here is a published content in web site equivalent to its book version.
SOME PROBREMS
About above web site I found myself a bit difficult to read in several respects.
- The book uses Scheme, one of the variations of lisp language, but code blocks are not syntax-highlighted so are not very readable.
- The texts in footnote are a bit small.
I wrote a JS script to modify their design which runs on browser.
Normally in order to run self-made Javascript code on browser, we take a way either to run it interactively in developer-console or to register the code as a Bookmarklet and run it.
But both of them have a disadvantage that we must run it whenever we reload the page.
However there is a useful extension with respect to Chrome.
WHAT'S SCRIPT_AUTO_RUNNER
This is a useful Chrome extension in which we register a pair of specific domain string and script code we want to run, and whenever we open/reload a page of target domain the code runs automatically.
CREATION ENVIRONMENT AND USED TOOL
- Google Chrome version: 101.0.4951.67
- highlight.js v11.5.1
SCRIPT CODE
WHOLE CODE
Here is a whole code.
Following sections describe meaning of each and its behavior.
1// if document is not fully loaded, load event take the place
2if (document.readyState === "complete") {
3 restyleSICP();
4} else {
5 window.addEventListener("load", restyleSICP);
6}
7
8function restyleSICP() {
9 // only in specific paths this script runs
10 if (!window.location.pathname.startsWith("/sites/default/files/sicp/full-text/book")) return;
11 highlightSchemeCode();
12 expandFootnote();
13}
14
15function highlightSchemeCode() {
16 // exclude elements which contain some img elements
17 const targetTts = Array.from(document.querySelectorAll("p > tt:first-child:last-child")).filter(e => !e.querySelector("img"));
18
19 for (const tt of targetTts) {
20 const pre = document.createElement("pre");
21 const code = document.createElement("code");
22
23 code.classList.add("language-scheme");
24 code.innerHTML = tt.innerHTML;
25
26 // replace tt element with pre + code elements
27 pre.append(code);
28 tt.before(pre);
29 tt.remove();
30 }
31
32 const link = document.createElement("link");
33 link.rel = "stylesheet";
34 link.href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/a11y-dark.min.css";
35
36 const hlScr = document.createElement("script");
37 hlScr.src = "//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js";
38 hlScr.onload = () => {
39 hljs.configure({
40 ignoreUnescapedHTML: true
41 });
42 const schemeScr = document.createElement("script");
43 schemeScr.src = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/scheme.min.js";
44 schemeScr.onload = () => hljs.highlightAll();
45 document.head.append(schemeScr);
46
47 }
48 document.head.append(link, hlScr);
49
50
51}
52
53function expandFootnote() {
54 document.querySelector(".footnote").style.fontSize = "1rem";
55}
LAUNCHING
1// if document is not fully loaded, load event take the place
2if (document.readyState === "complete") {
3 restyleSICP();
4} else {
5 window.addEventListener("load", restyleSICP);
6}
The running timing of main processing is diferrent between the case in which DOM reading of the page is not yet complete and the case in which it has already been complete.
CHECK IF RUN OR NOT
1function restyleSICP() {
2 // only in specific paths this script runs
3 if (!window.location.pathname.startsWith("/sites/default/files/sicp/full-text/book")) return;
4 // ...
5}
Unfortunately ScriptAutoRunner allows us to specify a domain but not a path, so we check if it can run Subsequent processing or not by fetching the page's url.
HIGHLIGHTING
1function highlightSchemeCode() {
2 // exclude elements which contain some img elements
3 const targetTts = Array.from(document.querySelectorAll("p > tt:first-child:last-child")).filter(e => !e.querySelector("img"));
4
5 for (const tt of targetTts) {
6 const pre = document.createElement("pre");
7 const code = document.createElement("code");
8
9 code.classList.add("language-scheme");
10 code.innerHTML = tt.innerHTML;
11
12 // replace tt element with pre + code elements
13 pre.append(code);
14 tt.before(pre);
15 tt.remove();
16 }
17
18
All Page's Elements corresponding to Scheme code block are tt elements.
We search them and replace pre element + code element so that highlight.js finds them as a highlighting target.
Some code blocks contains img elementsm and We exclude them because highlighting is not effective for them.
1const link = document.createElement("link");
2 link.rel = "stylesheet";
3 link.href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/a11y-dark.min.css";
4
5 const hlScr = document.createElement("script");
6 hlScr.src = "//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js";
7 hlScr.onload = () => {
8 hljs.configure({
9 ignoreUnescapedHTML: true
10 });
11 const schemeScr = document.createElement("script");
12 schemeScr.src = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/scheme.min.js";
13 schemeScr.onload = () => hljs.highlightAll();
14 document.head.append(schemeScr);
15
16 }
17 document.head.append(link, hlScr);
18
19
20}
Via CDN we read main script of hl and optional script for Scheme successively and when all completed highlightAll
runs.
RESTYLE A FOOTNOTE
1function expandFootnote() {
2 document.querySelector(".footnote").style.fontSize = "1rem";
3}