(Similar to How to refer a css property value from another element or How to get a DOM element's ::before content with JavaScript?)
I have a HTML page with headings (H1 to H3), and I've added the usual CSS rules to automatically prepend a hierarchical number to the headings. That works nicely.
I also wrote some JavaScript that populates an empty span
element with a table of contents derived from the page headings' textContent
.
That works nicely, too.
However the table of contents lacks the numbers automatically assigned.
I saw some code to retrieve the :before
part of an element using JavaScript, but that gives the style rules in my case (e.g. for a <H3>
: counter(c_h1) "." counter(c_h2) "." counter(c_h3) " "
), and not the value built from those style rules (e.g.: 1.3.1
).
So I think that does not help me anything in JavaScript.
Is there any way to have the same heading numbers in the TOC created by JavaScript as those automatically added by CSS rules?
Example
.pp {
font-family: sans-serif
}
h1,
h2,
h3 {
font-family: sans-serif;
page-break-after: avoid;
break-after: avoid
}
/* counters */
:root {
counter-reset: c_h1 0 c_h2 0 c_h3 0 c_h4 0
}
h1:before {
counter-reset: c_h2 0 c_h3 0 c_h4 0;
counter-increment: c_h1;
content: counter(c_h1)" "
}
h2:before {
counter-reset: c_h3 0 c_h4 0;
counter-increment: c_h2;
content: counter(c_h1)"."counter(c_h2)" "
}
h3:before {
counter-reset: c_h4 0;
counter-increment: c_h3;
content: counter(c_h1)"."counter(c_h2)"."counter(c_h3)" "
}
/* table of contents */
span.toc:not(:empty) {
border-style: solid;
border-width: thin;
border-color: black;
padding: 1ex;
margin-top: 1em;
margin-bottom: 1em;
display: inline-block
}
div.toc-title {
font-family: sans-serif;
font-weight: bold;
padding-bottom: 1ex
}
div.toc-H1 {
padding-left: 1em
}
div.toc-H2 {
padding-left: 2em
}
div.toc-H3 {
padding-left: 3em
}
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de-DE" xml:lang="de-DE">
<head>
<title>Example</title>
<script>
"use strict";
// Create table of contents from headings
function make_TOC(target_ID) {
const candidate = /^H[1-9]$/i; {
let list = document.getElementsByTagName("H1");
let toc = document.getElementById(target_ID);
let seq = 0;
var e;
if (list.length > 0) {
e = list.item(0);
let div = document.createElement("div");
div.setAttribute("class", "toc-title");
div.textContent = "Inhaltsverzeichnis";
toc.appendChild(div);
}
while (e !== null) {
let n = e.tagName;
if (n.search(candidate) !== -1) {
let div = document.createElement("div");
let link = document.createElement("a");
let id = e.id;
div.setAttribute("class", "toc-" + n);
div.appendChild(link);
link.textContent = e.textContent;
if (id === "") { // add id
id = "H." + ++seq;
e.id = id;
}
link.setAttribute("href", "#" + id);
toc.appendChild(div);
}
e = e.nextElementSibling;
}
}
}
</script>
</head>
<body>
<span class="toc" id="toc"></span>
<h1 class="pp">H1: D...</h1>
<h2 class="pp">H2: Z...</h2>
<p class="pp">D...</p>
<ul class="pp">
<li class="pp">B...</li>
<li class="pp">U...</li>
</ul>
<p class="pp">D...</p>
<h2 class="pp">H2: C...</h2>
<p class="pp">D...</p>
<p class="pp">A...</p>
<h2 class="pp">H2: E...</h2>
<h3 class="pp">H3: S...</h3>
<p class="pp">U...</p>
<h3 class="pp">H3: R...</h3>
<p class="pp">S...</p>
<h3 class="pp">H3: L...</h3>
<p class="pp">S...</p>
<h3 class="pp">H3: W...</h3>
<p class="pp">N...</p>
<script type="text/javascript">
make_TOC("toc")
</script>
</body>
</html>
So here is how the example should be displayed (indent is done via classes and CSS, my JavaScript knowledge is poor, also):