Popovers cause anchors that go to headers further down on the same page to break
Describe the bug
Ā Links to the anchor on the same pageĀ [[#Heading 5]] are not working when Popovers are enabled.
To Reproduce Steps to reproduce the behavior:
- Make sure that
enablePopoversconfig istrue. - Create a file with text couple screens long (so it can be scrolled) and multiple headings, like
# Heading 1(2, 3, ...). - Anywhere in this file create a wikilink to any heading, like
[[#Heading 5]]. - On hover popover shows the correct content for this heading.
- When link is clicked url in browser is changed to
http://localhost:8080/#heading-5, but autoscroll to that heading is not performed. - If
enablePopoversconfig isfalseanchor links work as expected.
Expected behavior When anchor link is clicked autoscroll is performed to that anchor.
Desktop (please complete the following information):
- Quartz Version: v4.2.2
nodeVersion: v20.11.0npmversion: 10.2.4- OS: MacOS
- Browser: chrome
Additional context Add any other context about the problem here.
I don't think this is supported in quartz yet. You can do this by providing the name to the heading.
i.e: [[page#heading 5]] should work for now.
it is already supported if enablePopovers is false )))
this variant [[page#heading 5]] also not working when popovers are enabled
wiki links with anchors are working with popovers only if they lead to different file
and I also found that popovers also break sometimes after clicking that anchor link, so popover starts showing content for different link) but this is more like undefined behavior
Not sure what you mean here, but enablePopover is set to true, and the link I set is to the header.
https://github.com/jackyzha0/quartz/assets/29749331/623e0563-9874-4a53-a1a5-6ab2b1397572
P/s: take a look at the URL, it resolve the correct link here.
https://github.com/jackyzha0/quartz/assets/23178940/b808f0f3-3f81-4960-a146-e19e100e1ca3
this is working as intended, sometimes it won't appear to scroll because the header is already in view or there is no more page left to scroll
Did you watch the video carefully? The link is to the same page and clicking on the link scrolls to the header
See also https://quartz.jzhao.xyz/features/explorer which has a lot of anchors to it's own headers
https://github.com/jackyzha0/quartz/assets/69584771/6be40aea-cff2-4391-8c03-73460d861737
This is with enabled popovers, is it enough to reproduce a bug or should I provide more info?
https://github.com/jackyzha0/quartz/assets/69584771/bc51fe62-b883-4306-9954-9aa4b3c076da
And this is how it works with disabled popovers (as expected i think)
can you also show the markdown code you wrote for this?
[[#Heading 5]]
[[#Heading 9]]
# Heading 1
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus egestas non quam vitae dapibus. Proin pulvinar dolor sit amet sagittis consectetur. Integer luctus aliquam rhoncus. Quisque ut est malesuada, hendrerit metus a, maximus odio. Praesent faucibus imperdiet vehicula. Mauris feugiat felis ut ex sollicitudin, quis fermentum odio dictum. Proin eu magna quam.
# Heading 2
Praesent nec ipsum facilisis, porta sapien quis, luctus nunc. Aliquam quam est, tempor sed est vel, porttitor ullamcorper lorem. Nam commodo vitae quam nec eleifend. Suspendisse ultricies ullamcorper posuere. Sed vel eros id augue efficitur tristique. Ut lacinia ex non eros vulputate, vel gravida dui porttitor. Nunc sapien lectus, consectetur non ex sed, tristique convallis magna. In quis facilisis augue. Vivamus sit amet nulla sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Ut semper metus ac scelerisque congue. Nulla blandit aliquam lectus eget mollis.
# Heading 3
Donec sagittis sapien sit amet felis vulputate gravida. Phasellus facilisis eleifend velit, in luctus eros ullamcorper nec. Morbi venenatis elementum scelerisque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec malesuada suscipit ipsum, nec mollis felis euismod ut. Donec cursus leo eros, eu accumsan purus pharetra a. In eleifend ex sit amet velit dictum faucibus. Cras urna odio, porta id pulvinar eu, pulvinar sit amet turpis.
# Heading 4
Nulla pulvinar tellus nec egestas interdum. Sed sit amet dolor nisi. Morbi purus lectus, viverra id ornare vel, porta quis erat. Vivamus a odio convallis, rhoncus elit sed, pretium mauris. Vivamus urna odio, fringilla et mollis non, laoreet ut ante. Cras sit amet dapibus justo, at lacinia odio. Aliquam sed lobortis elit. Duis nec felis leo. Nam nec quam egestas, placerat arcu sit amet, scelerisque magna. In diam tellus, condimentum ut rutrum sed, gravida fringilla purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas malesuada orci eu mollis laoreet. Pellentesque a semper lacus. Nunc in interdum est, ac hendrerit ligula. Nunc et arcu sed ipsum sollicitudin fermentum sed at ligula.
# Heading 5
Aliquam erat volutpat. Curabitur faucibus eleifend velit vitae aliquet. Sed eu euismod lacus. Nunc eros purus, volutpat id bibendum et, malesuada iaculis dui. Suspendisse rhoncus dolor at augue pulvinar egestas. Suspendisse potenti. Aenean lacinia libero in velit facilisis molestie. Etiam eu justo sed dui gravida condimentum. Sed placerat elit in lectus congue faucibus. Maecenas porta blandit erat non accumsan. Cras convallis, erat vel pharetra vehicula, urna est consequat urna, ac convallis purus nisl at elit. In hac habitasse platea dictumst.
# Heading 6
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus egestas non quam vitae dapibus. Proin pulvinar dolor sit amet sagittis consectetur. Integer luctus aliquam rhoncus. Quisque ut est malesuada, hendrerit metus a, maximus odio. Praesent faucibus imperdiet vehicula. Mauris feugiat felis ut ex sollicitudin, quis fermentum odio dictum. Proin eu magna quam.
# Heading 7
Praesent nec ipsum facilisis, porta sapien quis, luctus nunc. Aliquam quam est, tempor sed est vel, porttitor ullamcorper lorem. Nam commodo vitae quam nec eleifend. Suspendisse ultricies ullamcorper posuere. Sed vel eros id augue efficitur tristique. Ut lacinia ex non eros vulputate, vel gravida dui porttitor. Nunc sapien lectus, consectetur non ex sed, tristique convallis magna. In quis facilisis augue. Vivamus sit amet nulla sem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Ut semper metus ac scelerisque congue. Nulla blandit aliquam lectus eget mollis.
# Heading 8
Donec sagittis sapien sit amet felis vulputate gravida. Phasellus facilisis eleifend velit, in luctus eros ullamcorper nec. Morbi venenatis elementum scelerisque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec malesuada suscipit ipsum, nec mollis felis euismod ut. Donec cursus leo eros, eu accumsan purus pharetra a. In eleifend ex sit amet velit dictum faucibus. Cras urna odio, porta id pulvinar eu, pulvinar sit amet turpis.
# Heading 9
Nulla pulvinar tellus nec egestas interdum. Sed sit amet dolor nisi. Morbi purus lectus, viverra id ornare vel, porta quis erat. Vivamus a odio convallis, rhoncus elit sed, pretium mauris. Vivamus urna odio, fringilla et mollis non, laoreet ut ante. Cras sit amet dapibus justo, at lacinia odio. Aliquam sed lobortis elit. Duis nec felis leo. Nam nec quam egestas, placerat arcu sit amet, scelerisque magna. In diam tellus, condimentum ut rutrum sed, gravida fringilla purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas malesuada orci eu mollis laoreet. Pellentesque a semper lacus. Nunc in interdum est, ac hendrerit ligula. Nunc et arcu sed ipsum sollicitudin fermentum sed at ligula.
# Heading 10
Aliquam erat volutpat. Curabitur faucibus eleifend velit vitae aliquet. Sed eu euismod lacus. Nunc eros purus, volutpat id bibendum et, malesuada iaculis dui. Suspendisse rhoncus dolor at augue pulvinar egestas. Suspendisse potenti. Aenean lacinia libero in velit facilisis molestie. Etiam eu justo sed dui gravida condimentum. Sed placerat elit in lectus congue faucibus. Maecenas porta blandit erat non accumsan. Cras convallis, erat vel pharetra vehicula, urna est consequat urna, ac convallis purus nisl at elit. In hac habitasse platea dictumst.
[[#Heading 5]]
[[#Heading 9]]
Ugh cannot reproduce. The same thing you give me
https://github.com/jackyzha0/quartz/assets/29749331/b623f28a-2b96-42f4-a05a-d077d1d43126
very strange bug) by the way anchor links between pages work correctly, but across one page you've seen in the video) I'll try to debug what's wrong with my PC/browser/code/hands) where should I start from?
I tried again with fresh clone/fork following the guide and adding only one file (link). Bug is reproduced in all browsers (chrome/safari/mozilla) and OS (MacOS/Ubuntu/Android).
To Reproduce Steps to reproduce the behavior:
- Follow 4 steps from https://quartz.jzhao.xyz/#-get-started
- Add file https://github.com/makondratev/quartz/blob/popovers-break-anchors/content/index.md to content folder
- Run command to preview https://quartz.jzhao.xyz/build
- Open browser http://localhost:8080/ and click multiple times to different wikilinks like
[[#Heading 12]] [[index#Heading 14]]at the top of file and[[#Heading 2]] [[index#Heading 4]]at the bottom of file - After every click url changes correctly to the anchor was clicked, BUT scroll to that anchor is not performed (maybe a little scroll up to 50-100px)
Expected behavior When anchor link is clicked autoscroll is performed to that anchor.
Additional context
If enablePopovers config is false anchor links work as expected.
Desktop (please complete the following information):
- Quartz Version: v4.2.2
nodeVersion: v20.11.0npmversion: 10.2.4- OS: MacOS/Ubuntu/Android
- Browser: chrome/safari/mozilla
I'll try to debug quartz/components/scripts/popover.inline.ts but I don't know typescript and frontend)
Should I reopen the bug and copy this info to it?
Debug updates:
- if line 83
link.appendChild(popoverElement)of filequartz/components/scripts/popover.inline.tsis commented out, links start working
Are you sure you don't have any plugins that interfere with this?
Are you sure you don't have any plugins that interfere with this?
Absolutely sure. Bug is reproduced in different browsers and devices (including android). While debugging I noticed, that scroll is performed to the anchor link that is displayed in the popover (so it scrolls about 50-100px) So my understanding of bug right now is: when popover appears (with anchor inside it) browser thinks that popover is the main page and it scrolls up to this anchor inside popover. So I guess something wrong with positioning when popover appears.
Did you manage to reproduce the bug? I think it's not so easy to fix. As quick fix how can I disable popovers only for specific pages(they are full of wikilinks across one page)? Is there any frontmatter or js config option to disable popovers for page?
You need to be much more specific about describing the problem. I can reproduce it but it only happens for anchor links that link to something further down in the page (link going back up the doc are fine)
You need to be much more specific about describing the problem. I can reproduce it but it only happens for anchor links that link to something further down in the page (link going back up the doc are fine)
Sorry, this is my first time) I'll do my best in future. How can I help now? Should I provide more info? Thank you so much!
You need to be much more specific about describing the problem. I can reproduce it but it only happens for anchor links that link to something further down in the page (link going back up the doc are fine)
I suspect that if you hover over a heading link that points to a header on the same page (for example, #Heading9), that the position of said header is overridden by the position of the popover:
Hi,
I have the same issue as described by @makondratev and confirmed later also by @jackyzha0. @sabezero1 mentioned the anchor links inside the popover become the "new" link targets, which could come from this line in code: https://github.com/jackyzha0/quartz/blob/v4/quartz/components/scripts/popover.inline.ts#L87
elts.forEach((elt) => popoverInner.appendChild(elt))
It adds the content of the current file again with the same IDs for the headers at the current position (the place you hover over the link).
So you would have the same header IDs mulitple times in the current page, but the extra IDs from the popover will be placed before the original ones. Which could explain why the IDs of the popover headers will be used instead of the original IDs.
So, I guess the solution would be to remove/rewrite the header IDs in the popover. I can try it locally, but my typescript knowledge is bad.
@makondratev, I found a work-around to disable the popover for specific links - but that would mean you will use pure html. The data-no-popover="true" disables that feature:
So instead of [[#header1]] you could write: <a href="#header1" data-no-popover="true">header1</a>.
Hi,
I have the same issue as described by @makondratev and confirmed later also by @jackyzha0. @sabezero1 mentioned the anchor links inside the popover become the "new" link targets, which could come from this line in code: https://github.com/jackyzha0/quartz/blob/v4/quartz/components/scripts/popover.inline.ts#L87
elts.forEach((elt) => popoverInner.appendChild(elt))It adds the content of the current file again with the same IDs for the headers at the current position (the place you hover over the link).
So you would have the same header IDs mulitple times in the current page, but the extra IDs from the popover will be placed before the original ones. Which could explain why the IDs of the popover headers will be used instead of the original IDs.
So, I guess the solution would be to remove/rewrite the header IDs in the popover. I can try it locally, but my typescript knowledge is bad.
@makondratev, I found a work-around to disable the popover for specific links - but that would mean you will use pure html. The
data-no-popover="true"disables that feature:So instead of
[[#header1]]you could write:<a href="#header1" data-no-popover="true">header1</a>.
Thanks for looking into this. I'll look into into a potential fix. Based on what you wrote, I can think of a few ways that might be viable fixes.
As a side note, is it even desirable to have popover to heading on the current page? I would assume popovers serve to give a quick peek into another page's content.
Hi @saberzero1,
Based on what you wrote, I can think of a few ways that might be viable fixes.
Cool š.
I was able to remove the id attributes in the popovers with the result, that the popovers didn't show anymore the right content.
As a side note, is it even desirable to have popover to heading on theĀ currentĀ page?
For long pages it would make sense to have such a feature. For example, you have at the beginning of a page a list of keywords with a short description and a link to the place inside the same page with more details.
But yeah, I could restructure such page and split the content into multiple pages.
I can only speak for myself, but I would be okay with not having popovers for the same page.
It would be I guess also the easiest solution as a simple removal of the id attributes didn't help.
Hi,
I had the same issue. For anyone looking for a quick fix, here's a solution. If it seems appropriate, I can try to make it a pull request, but I'm a complete beginner with github, so I'm still trying to understand how to do it ^^'
Replacing "elts.forEach((elt) => popoverInner.appendChild(elt))" with the following code fixes the links :
// We generate a unique prefix for each popover.
uniquePrefix = `popover-${Math.random().toString(36).substr(2, 9)}-`
elts.forEach((elt) => {
const clonedElt = elt.cloneNode(true) as Element
// We then update all IDs within the cloned elements (including nested elements) by prepending this unique prefix.
clonedElt.querySelectorAll('[id]').forEach((el) => {
el.id = uniquePrefix + el.id
})
if (clonedElt.id) {
clonedElt.id = uniquePrefix + clonedElt.id
}
popoverInner.appendChild(clonedElt)
})
The popovers still have the issue that they don't display the correct element of the page, but it can be fixed by updating the " if (hash !== "") " part like that :
if (hash !== "") {
const originalId = hash.substring(1) // Remove the '#' from the hash to get the original ID
const newId = uniquePrefix + originalId // Reconstructs the new ID by adding the uniquePrefix defined earlier
const heading = popoverInner.querySelector(`#${newId}`) as HTMLElement | null
if (heading) {
// leave ~12px of buffer when scrolling to a heading
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: "instant" })
}
As a disclaimer, I don't have any experience in TypeScript. I just described the problem to Claude, gave it your conclusions and the problematic file, and it fixed it on the first try. Tested it and everything seems to work perfectly. I feel I didn't do much myself but if it can help other people than me, all the better !
Hi,
I had the same issue. For anyone looking for a quick fix, here's a solution. If it seems appropriate, I can try to make it a pull request, but I'm a complete beginner with github, so I'm still trying to understand how to do it ^^'
Replacing "elts.forEach((elt) => popoverInner.appendChild(elt))" with the following code fixes the links :
// We generate a unique prefix for each popover. uniquePrefix = `popover-${Math.random().toString(36).substr(2, 9)}-` elts.forEach((elt) => { const clonedElt = elt.cloneNode(true) as Element // We then update all IDs within the cloned elements (including nested elements) by prepending this unique prefix. clonedElt.querySelectorAll('[id]').forEach((el) => { el.id = uniquePrefix + el.id }) if (clonedElt.id) { clonedElt.id = uniquePrefix + clonedElt.id } popoverInner.appendChild(clonedElt) })The popovers still have the issue that they don't display the correct element of the page, but it can be fixed by updating the " if (hash !== "") " part like that :
if (hash !== "") { const originalId = hash.substring(1) // Remove the '#' from the hash to get the original ID const newId = uniquePrefix + originalId // Reconstructs the new ID by adding the uniquePrefix defined earlier const heading = popoverInner.querySelector(`#${newId}`) as HTMLElement | null if (heading) { // leave ~12px of buffer when scrolling to a heading popoverInner.scroll({ top: heading.offsetTop - 12, behavior: "instant" }) }As a disclaimer, I don't have any experience in TypeScript. I just described the problem to Claude, gave it your conclusions and the problematic file, and it fixed it on the first try. Tested it and everything seems to work perfectly. I feel I didn't do much myself but if it can help other people than me, all the better !
I'll look into it later today.
