Conversation
|
Caution The Volto Team has suspended its review of new pull requests from first-time contributors until the release of Plone 7, which is preliminarily scheduled for the second quarter of 2026. Thanks for submitting your first pull request! You are awesome! 🤗 If you haven't done so already, read Welcome to the Plone community! 🎉 |
|
@Somilg11 you need to sign the Plone Contributor Agreement to merge this pull request. Learn about the Plone Contributor Agreement: https://plone.org/foundation/contributors-agreement If you have already signed the agreement, please allow a week for your agreement to be processed. If after a week you have not received an invitation, then please contact agreements@plone.org. |
The anchor of a heading was built from the text returned by `serializeNodesToText`, which trims every leaf of the node and joins them with whitespace, because it is meant for indexing. A heading that Slate splits into several leafs, either by inline formatting or by an inline link, therefore produced an anchor that did not match the one the Table of Contents block linked to, and the entry led nowhere. Build the anchor from the text of the heading as it is rendered instead, and report it as the third element of the `tocEntry` of the block, so that the Table of Contents block links to the anchor that the block actually renders, instead of slugging its stored plaintext. Blocks that report no anchor keep the previous behavior. Closes plone#8340
7a94673 to
3d11fb9
Compare
|
@Somilg11 you need to sign the Plone Contributor Agreement to merge this pull request. Learn about the Plone Contributor Agreement: https://plone.org/foundation/contributors-agreement If you have already signed the agreement, please allow a week for your agreement to be processed. If after a week you have not received an invitation, then please contact agreements@plone.org. |
Closes #8340
What happens
A Table of Contents block entry stops pointing to the correct heading when the heading contains inline formatting or a link. Clicking the entry does nothing because the link target does not match the
idof the heading it should scroll to.Examples reported in the issue:
idSubtitle 1: everything is okay#kaysubtitle-1-everything-is-okaySubtitle 2: everything is *not* okay#ot-okaysubtitle-2-everything-is-not-okaySubtitle 3: everything is [okay](/some-page)#kay-subtitle-3-everything-is-okayHeadings without inline formatting are not affected.
Why
The heading
idand the Table of Contents link were generated from two different representations of the same heading.The heading
idwas generated byserializeNodesToTextinTextBlockView, while the Table of Contents link was generated by slugging the stored plaintext of the block. Both paths usedserializeNodesToText, which is intended for indexing and trims whitespace around individual leaves and nodes, as described in its docstring.When a heading is split into multiple inline nodes, the two representations can differ. Applied to individual leaves, whitespace around formatted text is removed. Applied to the whole block, empty text nodes around inline elements can result in extra separators in the generated slug.
As a result, the heading and its Table of Contents entry end up with different anchors whenever the heading contains multiple inline nodes.
The fix
The anchor is now generated from the heading text as it is rendered, and the block containing the heading reports the anchor it actually uses.
getAnchor,getAnchorTextand the required serialization helpers inpackages/volto-slate/src/utils/toc.js. These concatenate the text from inline children without adding or removing whitespace, then collapse and trim the result before generating the anchor.TextBlockViewnow rendersgetAnchor(node)as the headingid.tocEntrynow reports the third element of the entry,[level, title, anchor], calculated from the current value instead of the stored plaintext.The
tocEntrychange is backwards compatible. Add-on blocks that continue to return the usual[level, title]format work exactly as before.serializeNodesToTextand the stored plaintext are unchanged.Anchors of headings without inline formatting remain unchanged, so existing working URLs are not affected. Only anchors that were already broken are changed.
Before and after
Clicking the Table of Contents entry for a heading containing an italic word:
comparison-italic-heading.pngClicking the Table of Contents entry for a heading containing a link:
comparison-heading-with-link.pngTests
packages/volto-slate/src/utils/toc.test.js, covering plain, italic, partially formatted and linked headings.packages/volto-slate/src/blocks/Text/TextBlockView.test.jsfor the renderedidand verifying that it matches the anchor used by the Table of Contents link.packages/volto/src/components/manage/Blocks/ToCfor passing the anchor through the entries, including blocks that do not report one.block-anchors.jsacceptance test that creates a heading with an italic word through the editor and follows its Table of Contents entry. It fails onmainwith:Local test runs