Knowing last heading (tree) from anywhere in the text

I wish there was a way to know under what heading I am at any point in the text, from render-link.html for instance. That would serve to construct a bibliography of all remote links in the page, ordered by headings. Much more palatable than a list of 50 links.

Yep. You can do that.

  • Feature 1: Page Store - add some lines of code in the heading markdown render hook that update a variable in the page store telling you what was the last heading (basically updating every time you have a heading, you can add multiple variables like level, title, link or whatever you want).
  • Feature 2: Shortcodes - let a shortcode read the values of those variables and “do something” with them. Or even in your render-link.html, like for instance add the last header as a data attribute for the link.

But - you mix up dynamic features of a browser and the static nature of GoHugo.

I think you want to use Javascript for that. There is something called IntersectionObserver in the browser APIs that knows what “observed” elements are currently visible in the browser. An implementation I recently did for a sidebar navigation that lights up the menu item that is currently visible is this:

window.addEventListener('DOMContentLoaded', () => {

  const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      const id = entry.target.getAttribute('id');
      const linkElement = document.querySelector(`#table-of-contents li a[href="#${id}"]`);

      if (linkElement && linkElement.parentElement) {
        if (entry.intersectionRatio > 0) {
          linkElement.parentElement.classList.add('active');
        } else {
          linkElement.parentElement.classList.remove('active');
        }
      }
    });
  });

  document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').forEach((section) => {
    observer.observe(section);
  });

});

You will step into traps like:

  • which of the n+1 headlines currently visible is the one I want to observe
  • what level of headline is to be observed
  • etc…

but once you figured all that out it works quite nice.

2 Likes

Thing is my use case is completely static: I have a single.csv template that means to generate a bibliography, in a file people can download. Once and done. JS would be way overkill and complex… I do not write, and barely read it. I’ll go with variables. I thought about it, but can’t figure out how to do it.
I would need to update it as if changing one element inside an array, as I would do in C or Ada.

Array(3) := "title of current heading Level 3";

But I can’t think of how to do this with a Store variable

I did not get “my use case is static”
The heading you are on in a page is dynamic while reading. Could even be more than one.

At page generation time Fragments might be the place to look at.

A more elaborated use case/example can help to assist

No, you are mistaken. Each link is between two headings and the list of links is not generated at run time, but when like all other pages, when the site is built.

I could do it in better languages but that one just makes your head hurt… Here’s an exemple:

## title 1
### subtitle 1
[link1](www.yahoo.fr "name of website 1")
sdfsdfds
[link2](www.google.fr "name of website 2")
### subtitle 2
sdfsdfsd
### subtitle 3
[link3](aol.fr "name of website 3")
## title 2
### subtitle 1
dsfsdf
### subtitle 2
[link4](www.doi.org "name of website 4")

That would translate into:

I. Title 1
	1. subtitle 1
	name of website 1: www.yahoo.fr
	name of website 2: www.google.fr
	3. subtitle 3
	name of website 3: aol.fr
II. Title 2
	2. subtitle 2
	name of website 4: www.doi.org