I have script which creates table of content based on h2, h3
tags. In the code below it searches h2
tags and create links based on that.
Problem is when any other tag span
inside h2
tag, it ignores that h2
tag and does not create link for the same. I guess problem lies in the regex /<h([\d]).*>\s*[\d]*\s?[.]?\s?([^<] )<\/h([\d])>/gi
Since I am not good with regex, couldn't fix it.
$(document).ready(function() {
var toc = "";
var level = 0;
var maxLevel = 3;
if (document.getElementById("contents") != null) {
document.getElementById("contents").innerHTML =
document.getElementById("contents").innerHTML.replace(
/<h([\d]).*>\s*[\d]*\s?[.]?\s?([^<] )<\/h([\d])>/gi,
function(str, openLevel, titleText, closeLevel) {
if (openLevel > maxLevel) {
return str;
}
if (openLevel > level) {
toc = (new Array(2)).join("<ol>");
} else if (openLevel < level) {
toc = (new Array(level - openLevel 1)).join("</ol>");
}
level = parseInt(openLevel);
var anchor = titleText.replace(/[^a-zA-Z] /g, "-");
toc = "<li><a href=\"#" anchor "\">" titleText
"</a></li>";
return "<a name=\"" anchor "\">"
"<h" openLevel "\">" str "</h" closeLevel ">" "</a>";
}
);
if (level) {
toc = (new Array(level 1)).join("</ol>");
}
document.getElementById("toc").innerHTML = toc;
}
});
.blink {
animation: blinker 1s step-start infinite;
color: #ff0000;
font-weight: bold;
font-size: 0.85em;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
<head>
<script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
</head>
<body>
<div id="toc">
<div id="contents">
<h2>What is JS?</h2>
<h2 style="margin-top:1em;">Python Jobs - <span >New!</span></h2>
<h2 style="margin-top:1em;">
What is Python?
</h2><h3>Introduction</h3>
</div>
</div>
</body>
CodePudding user response:
You can do it without regex
$(document).ready(function() {
const toc = document.createElement('ol');
if (document.getElementById("contents") != null) {
document.getElementById("contents").append(toc);
document.querySelectorAll("#contents h2").forEach((title) => {
const item = document.createElement('li');
const link = document.createElement('a');
if (title.getAttribute('id') === null) {
title.setAttribute('id', 'id-' Math.random().toString(16).substr(2, 6));
}
link.innerText = title.innerText;
link.setAttribute('href', '#' title.getAttribute('id'));
item.append(link);
toc.append(item);
});
}
});
.blink {
animation: blinker 1s step-start infinite;
color: #ff0000;
font-weight: bold;
font-size: 0.85em;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
<head>
<script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
</head>
<body>
<div id="toc">
<div id="contents">
<h2>What is JS?</h2>
<h2 style="margin-top:1em;">Python Jobs - <span >New!</span></h2>
<h2 style="margin-top:1em;">
What is Python?
</h2>
</div>
</div>
</body>
Edit
You can still follow the hierarchy
$(document).ready(function() {
const toc = document.createElement('ol');
let last = toc;
if (document.getElementById("contents") != null) {
document.getElementById("contents").append(toc);
document.querySelectorAll("#contents h2, #contents h3").forEach((title) => {
const item = document.createElement('li');
const link = document.createElement('a');
if (title.getAttribute('id') === null) {
title.setAttribute('id', 'id-' Math.random().toString(16).substr(2, 6));
}
link.innerText = title.innerText;
link.setAttribute('href', '#' title.getAttribute('id'));
item.append(link);
if (title.tagName === 'H2') {
toc.append(item);
last = item;
} else {
let ol = last.querySelector('ol');
if (!ol) {
ol = document.createElement('ol');
last.append(ol);
}
ol.append(item);
}
});
}
});
.blink {
animation: blinker 1s step-start infinite;
color: #ff0000;
font-weight: bold;
font-size: 0.85em;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
<head>
<script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
</head>
<body>
<div id="toc">
<div id="contents">
<h2>What is JS?</h2>
<h3>A programing language</h3>
<h2 style="margin-top:1em;">Python Jobs - <span >New!</span></h2>
<h2 style="margin-top:1em;">
What is Python?
</h2>
<h3>A cool programing language</h3>
</div>
</div>
</body>
CodePudding user response:
The snippet here creates an html collection of all the h2 tags inside the .contents
div.
It then loops through the collection, extracting the .innerText
of each (so ignoring the spans and other tags) before building a link from the `.replaced' text (to fill in non alphabet characters with dashes.
If you hover over the links created and examine the status bar, you will see they are valid links (you may need to refine your .replace to format them exactly as required but this gives a working principle to follow.
let h2Collection = document.getElementById('contents').getElementsByTagName('h2');
// h2Collection is an array-like collection of h1 elements contained in the #contents div;
let links = [];
for (let i=0; i<h2Collection.length; i ) {
links.push(`<a href="http://www.whateversite.com/${h2Collection[i].innerText.replace(/[^a-zA-Z] /g, "-")}.html">${h2Collection[i].innerText}</a>`)
} // next i h2element;
document.getElementById('output').innerHTML = links.join('<p>');
.blink {
animation: blinker 1s step-start infinite;
color: #ff0000;
font-weight: bold;
font-size: 0.85em;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
<div id="toc">
<div id="contents">
<h2>What is <span style="color:red">JS?</span></h2>
<h2 style="margin-top:1em;">Python Jobs - <span >New!</span></h2>
<h2 style="margin-top:1em;">
What is Python?
</h2>
</div>
<div id=output></div>
</div>