Skip to content

Commit 4b6f6bc

Browse files
authored
Merge pull request #282 from ELIXIR-Belgium/anchor-fix-2
Improve anchor link behavior and TOC
2 parents bd0f510 + 0f75135 commit 4b6f6bc

File tree

2 files changed

+60
-50
lines changed

2 files changed

+60
-50
lines changed

_includes/toc.html

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
<script>
22
$(document).ready(function () {
3-
$('#toc-contents').toc({ minimumHeaders: {{site.theme_variables.toc.min_headings | default: 1 }}, listType: 'ul', classes: { list: 'list-unstyled' }, noBackToTopLinks: true, showSpeed: 0, headers: '{{site.theme_variables.toc.headings | default: 'main h2' }}' , title: '<strong class="my-2">On this page</strong><hr class="my-2">' });
3+
// Ensure that the TOC is generated after the document is fully loaded
4+
$('#toc-contents').toc({
5+
minimumHeaders: {{ site.theme_variables.toc.min_headings | default: 1 }},
6+
listType: 'ul',
7+
classes: { list: 'list-unstyled' },
8+
showSpeed: 0,
9+
headers: '{{site.theme_variables.toc.headings | default: "main h2" }}',
10+
title: '<strong class="my-2">On this page</strong><hr class="my-2">'
11+
});
12+
// After generating the TOC, check the hash in the URL and scroll to the anchor if present
13+
if (window.location.hash) {
14+
var target = $(window.location.hash);
15+
if (target.length) {
16+
$('html, body').animate({
17+
scrollTop: target.offset().top
18+
}, 0);
19+
}
20+
}
21+
// Allow the browser to handle the scrolling to the anchor
22+
$('#toc-contents a').on('click', function (e) {
23+
e.preventDefault(); // Prevent the default link click behavior
24+
25+
var target = this.hash; // Get the hash (e.g., #heading-id)
26+
var $target = $(target); // Find the element with the corresponding ID
27+
28+
if ($target.length) {
29+
// Change the URL hash
30+
window.location.hash = target;
31+
}
32+
});
33+
434
});
535
</script>
636
<button id="btn-toc-hide" class="btn bg-light d-xl-none hover-primary mb-3" type="button" data-bs-toggle="collapse" data-bs-target="#toc-contents" aria-expanded="true" aria-controls="toc-contents">

assets/js/toc.js

Lines changed: 29 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
(function ($) {
33
$.fn.toc = function (options) {
44
var defaults = {
5-
noBackToTopLinks: false,
65
title: '<i>Jump to...</i>',
76
minimumHeaders: 3,
87
headers: 'h1, h2, h3, h4, h5, h6',
@@ -16,7 +15,7 @@
1615
toc: ''
1716
}
1817
},
19-
settings = $.extend(defaults, options);
18+
settings = $.extend(defaults, options);
2019

2120
function fixedEncodeURIComponent(str) {
2221
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
@@ -25,32 +24,32 @@
2524
}
2625

2726
function createLink(header) {
28-
var innerText = (header.textContent === undefined) ? header.innerText : header.textContent;
27+
var innerText = header.textContent || header.innerText;
2928
return "<a class='" + settings.classes.link + "' href='#" + fixedEncodeURIComponent(header.id) + "'>" + innerText + "</a>";
3029
}
3130

3231
var headers = $(settings.headers).filter(function () {
33-
// get all headers with an ID
34-
var previousSiblingName = $(this).prev().attr("name");
35-
if (!this.id && previousSiblingName) {
36-
this.id = $(this).attr("id", previousSiblingName.replace(/\./g, "-"));
32+
// Ensure headers have IDs
33+
if (!this.id) {
34+
this.id = $(this).text().trim().replace(/\s+/g, '-').toLowerCase();
3735
}
3836
return this.id;
39-
}), output = $(this);
37+
});
38+
39+
var output = $(this);
4040

4141
// Check if there are any headers
4242
if (!headers.length || headers.length < settings.minimumHeaders || !output.length) {
43-
4443
$('#main').removeClass("add-grid");
4544
$("#toc").hide();
4645
return; // Exit early if there are no headers
4746
}
4847

49-
if (0 === settings.showSpeed) {
48+
if (settings.showSpeed === 0) {
5049
settings.showEffect = 'none';
5150
}
5251

53-
$(this).addClass(settings.classes.toc)
52+
$(this).addClass(settings.classes.toc);
5453

5554
var render = {
5655
show: function () { output.hide().html(html).show(settings.showSpeed); },
@@ -61,47 +60,28 @@
6160

6261
var get_level = function (ele) { return parseInt(ele.nodeName.replace("H", ""), 10); };
6362
var highest_level = headers.map(function (_, ele) { return get_level(ele); }).get().sort()[0];
64-
var return_to_top = '<i class="icon-arrow-up back-to-top"> </i>';
63+
var level = get_level(headers[0]), this_level;
64+
var html = settings.title + " <" + settings.listType + " class=\"" + settings.classes.list + "\">";
6565

66-
var level = get_level(headers[0]),
67-
this_level,
68-
html = settings.title + " <" + settings.listType + " class=\"" + settings.classes.list + "\">";
69-
headers.on('click', function () {
70-
if (!settings.noBackToTopLinks) {
71-
window.location.hash = this.id;
72-
}
73-
})
74-
.addClass('clickable-header')
75-
.each(function (_, header) {
76-
this_level = get_level(header);
77-
if (!settings.noBackToTopLinks && this_level === highest_level) {
78-
$(header).addClass('top-level-header').after(return_to_top);
66+
headers.each(function (_, header) {
67+
this_level = get_level(header);
68+
if (this_level === level) { // same level as before; same indenting
69+
html += "<li class=\"" + settings.classes.item + "\">" + createLink(header);
70+
} else if (this_level <= level) { // higher level than before; end parent ol
71+
for (var i = this_level; i < level; i++) {
72+
html += "</li></" + settings.listType + ">"
7973
}
80-
if (this_level === level) // same level as before; same indenting
81-
html += "<li class=\"" + settings.classes.item + "\">" + createLink(header);
82-
else if (this_level <= level) { // higher level than before; end parent ol
83-
for (var i = this_level; i < level; i++) {
84-
html += "</li></" + settings.listType + ">"
85-
}
86-
html += "<li class=\"" + settings.classes.item + "\">" + createLink(header);
74+
html += "<li class=\"" + settings.classes.item + "\">" + createLink(header);
75+
} else if (this_level > level) { // lower level than before; expand the previous to contain a ol
76+
for (i = this_level; i > level; i--) {
77+
html += "<" + settings.listType + " class=\"" + settings.classes.list + "\">" +
78+
"<li class=\"" + settings.classes.item + "\">"
8779
}
88-
else if (this_level > level) { // lower level than before; expand the previous to contain a ol
89-
for (i = this_level; i > level; i--) {
90-
html += "<" + settings.listType + " class=\"" + settings.classes.list + "\">" +
91-
"<li class=\"" + settings.classes.item + "\">"
92-
}
93-
html += createLink(header);
94-
}
95-
level = this_level; // update for the next one
96-
});
80+
html += createLink(header);
81+
}
82+
level = this_level; // update for the next one
83+
});
9784
html += "</" + settings.listType + ">";
98-
if (!settings.noBackToTopLinks) {
99-
$(document).on('click', '.back-to-top', function () {
100-
$(window).scrollTop(0);
101-
window.location.hash = '';
102-
});
103-
}
104-
10585
render[settings.showEffect]();
10686
};
107-
})(jQuery);
87+
})(jQuery);

0 commit comments

Comments
 (0)