== User Story
As a reader, I want to be able to know which section I am on at all times, so that I have better context of what I am reading
== Design spec
==== Prototype of final version ====
https://di-toc-phase2.web.app/Hokusai
=== States
| no highlighted section | top-level section highlighted | subsection highlighted
| {F34914613, height=400} | {F34914607, height=400} | {F34914610, height=400}
**Active section definition:**
- When a top-level section is highlighted, only that link should be highlighted
- When a subsection is highlighted, that link along with it's corresponding top-level link should be highlighted.
- Only one section (top-level or top-level + subsection) should be highlighted at any given time.
=== UI Behaviour
**On Scroll**
While scrolling the page, the ToC will:
- "Stick" to the top of the page when scrolling down the page.
- "activate" the link that corresponds to the current section.
**On click**
When clicking a link in the ToC:
- The page will jump to the corresponding heading
- "activate" the link that corresponds to the current section.
== The current "section" problem
The main challenge in highlighting the "current section" of an article is that our content HTML does not contain actual sections, instead it's a flat series of paragraphs and headings (as opposed to parsoid or the mobile formatter, which have sections).
When implementing the [[ https://en-toc.wmcloud.org/wiki/Main_Page | user-facing prototype ]], [[ https://css-tricks.com/table-of-contents-with-intersectionobserver/ | several ]] [[ https://codepen.io/j4n/details/XWaRgKZ | approaches ]] to this problem were considered, however, leaning heavily on intersection observer was problematic because as explained in [[ https://stackoverflow.com/questions/61951380/intersection-observer-fails-sometimes-when-i-scroll-fast | this stackOverflow question ]], intersection observer is not optimized for "high velocity" contexts (i.e fast scrolling), and therefore, is prone to missing section titles when they scroll by quickly.
The most reliable solution turns out to be looping through each heading and returning **the last heading that is at or above the top of the page** as the current section.
```lang=js
const headings = document.getElementById( 'bodyContent' ).querySelectorAll( 'h1,h2,h3,h4,h5,h6' );
[ ...headings ] // Convert to array.
.reverse() // Reverse because find gives us the first match, we want the last one.
.find( h => h.getBoundingClientRect().top <= 0 ); // If the heading is at or above the top of the page, then that's our current section.
```
Initially, this check was run during a scroll event, however, it's proven to be equally effective when running as an intersection observer callback with no `rootMargin` (which seems to increase the probability that the observer will catch the headings).
```lang=js
const headings = [ ...document.getElementById( 'bodyContent' ).querySelectorAll( 'h1,h2,h3,h4,h5,h6' ) ].reverse();
function findCurrent() {
const h = headings.find( h => h.getBoundingClientRect().top <= 0 );
// console.log( h ? h.innerText : 'no active section, at top of page' );
return h;
}
let observer = new IntersectionObserver( findCurrent );
headings.forEach( h => observer.observe( h ) );
```
=== Linking the active section to headings
Setting the active section in the ToC requires matching the current article section heading with a link somewhere in the ToC.
Section headings //should// have `id` attributes that match the `href` value of the ToC links, however, there could be complications caused by unicode-encoding and mediawiki specific formatting that could produce invalid `id` attributes or attributes that don't match the`href`.
(We've been here before T238385)
This time around, we //could// try `CSS.escape` to guard against these issues (it's [[ https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape | not spec compliant ]], but has decent browser support:
```lang=js
tocElement.querySelector( `a[href="#${CSS.escape( currentSectionHeading.id )}"]` );
```
**Proof of concept (browser extension)**
https://github.com/jandre3000/desktop-improvements-extension/blob/993193a2e56e5f5081a230fa5ffbfb2743b183de/app/content/prototypes/tableOfContents/toc.js#L275
== Acceptance criteria
[] The section that a user currently has open (defined as having scrolled past the heading section for that section but before the heading section for the following section) should appear in bold
[] If a page has subsections, the subsection name and the section name should appear as bold whens scrolled to
== QA Steps
Please perform the following steps in Chrome, Edge, Firefox, and Safari to ensure browser compatibility.
=== When user scrolls through sections ===
1) Login and visit https://en.wikipedia.beta.wmflabs.org/wiki/Cat?tableofcontents=1
2) As you are scrolling past the top of headings (h1, h2, h3, h4, h5, h6) in the content, verify that the relevant section is bolded in the table of contents. Per the acceptance criteria, if the section is a subsection, the parent section should also be bolded in the Table of contents. Please test different scroll speeds while doing this (e.g. slow scrolling and fast scrolling) and ensure nothing is obviously broken.
=== When user clicks on a top level section in the TOC ===
1) Login and visit https://en.wikipedia.beta.wmflabs.org/wiki/Dog?tableofcontents=1
2) Click on "External Links" in the Table of contents.
3) Verify that "External Links" in the Table of contents is bolded
=== When user clicks on a child section in the TOC ===
1) Login and visit https://en.wikipedia.beta.wmflabs.org/wiki/Dog?tableofcontents=1
2) Click on "Coat" in the Table of contents.
3) Verify that "Coat" in the Table of contents is bolded (child section ) and the top level section, "Biology" is bolded
== QA Results - Beta
| **AC** | **Status** | **Details** |
| ----- | ----- | ----- |
| 1 | ✅ | T297614#7687656 |
| 2 | ❌ | T297614#7687656 |
| 3 | ✅ | T297614#7687656 |