Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Footnotes (again): MVP #47682

Closed
wants to merge 18 commits into from
Closed

Footnotes (again): MVP #47682

wants to merge 18 commits into from

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Feb 2, 2023

What?

Builds on the dynamic data API. In this case, we do want a fallback the footnote content can be HTML, we store the footnote in between brackets as the fallback.


Old description:

This PR attempts to add footnotes again. For storing footnotes with use the [# ...] shortcode syntax.

  1. Creates a footnote format type and adds a shortcode property.
  2. Based on that, the block editor implementation of rich text knows that it must create an object for this shortcode. In the future we can expand this API to also work for other shortcodes. I suggest we mark it unstable/lock for now.
  3. When you click an inserted footnote, you can edit the text. To do:
    • Allow rich text in the note.
    • Maybe allow reusable blocks?
  4. On the front end, the shortcodes are parsed: they are replaced with inline markup, accumulated and output at the bottom as a list. This is fully replaceable by a plugin: they can decide to display footnotes differently. In the future we will also add a JS version of this to preview footnotes in their proper place in the post content block.

Even older description:

There's no standard way to do footnotes in HTML. There's a lot of different ways to display them: some people like them numbered at the bottom of the page, some people like them in a popover/tooltip style. It's even possible to place them on the side of the text (I really like this, but may be challenging to generalise with multiple notes on the same line). Some people like them to slide in inline. Some people even want multiple footnote variants. All of these ways requires different markup, and have accessibility challenges. I would love to have a system for footnotes that is not too opinionated where themes and plugins can decide to render them in unique ways.

Let's first think about the best way to store them. The least complex way seems to be inline, but it has a few disadvantages as well: while you can store HTML/rich text in them, you can't store blocks in them. So this doesn't work well if you want to have footnotes larger than a paragraph. It's a small use case, but I've seen many books that have longer (foot)notes.

Storing them somewhere else means that we need to save IDs (not just generate IDs on render time in case it's needed for a specific style). Saving IDs means they could go out of sync and out of order. And maybe external editors don't even know how to edit these. And where do we store them? Storing them at the bottom of the post content means we need to do some preprocessing before sending the content to the editor.

Let's now think about the best default way to render them. Ideally we have something that works whether you view the post on the front-end, RSS, email, JSON API etc., which means a way to render them without requiring JS and CSS. This may already be partially fixed by some ways of saving them. For example, if we save them as [# Some footnote here.], this raw content already conveys that it's a note without any PHP/JS/CSS processing.

But for the front-end, that's not nice enough. At first I thought a nice and easy way to render them by default is positioning the note fixed at the bottom of the page when the link is clicked. But with fixed positioning you can't inherit the width of content, so it's only possible to have them full-width. And when notes are larger, they start to take up a lot of screen space. This is only a good way to render them if you do it at the theme level.

So for the front-end, it seems that the easiest way to render them is at the bottom as a numbered list. This barely needs any additional CSS (whether we do the numbering in CSS or not is another question...). Themes/plugins can override the rendering in PHP or adjust it with JS.

How we do this in the editor is another issue. In the FSE, a good way to approach this is hook into the post content block, but for the post editor (which doesn't use the post content block yet), we'd need to hardcode the list at the bottom or add a temporary slot. That is, if we want it do be displayed at the bottom at all in the editor. It would be good to match the front-end (at the bottom), but we could also decide to let them be edited in popovers.

It will generally be complex to match the front-end: if a theme/plugin changes the way the footnotes are rendered in PHP, JS, or CSS, they will also need to find a way to do the same thing in the editor.

Other explorations

I quite like the idea of storing them in a shortcode-like way as [# ...]. We've anyway had discussions in the past about bringing back the shortcode syntax (in a limited way) for rich text tokens. It would be nice if we can autocomplete registered tokens when the user inputs [. I also like that [#] matches the default rendering of footnote links as [1]...

[] has great character level semantics: it's immediately obvious that the text it contains is a note.

Another thing that makes this so great is that it's easy to edit the rich text footnote in any other editor even if it has no footnote support. So you could edit the content through the JSON API and it will be fine with any visual editor.

Note that all of the following explorations are for inline storing and doesn't solve the problem of long footnotes.

HTML comments

This has also been a candidate for rich text tokens, so we could also consider it for footnotes. Like [# ... ], this needs to be replaced in PHP. The difference is that the footnote is invisible by default.

Span

Similar to [# ... ] in that the note is displayed inline, but there's no way of knowing it's a footnote.

Small

"The side comment element". Similar to span, but you can see it's different from the rest of the text. Looks strange though.

Ruby

Basically the way to do annotations in HTML. Seems like a good idea at first, but the default styling is not great. Also altering it in CSS is a pain, but positioning footnotes in general is CSS without some JS is a pain. I also think it's a bit verbose. See also: <ruby> HTML footnotes

Details

Also seemed like a great idea at first. I wasn't the first. The problem is that while you can style this element as inline displayed, you can't put them in paragraphs because it's always parsed as a block level element. Would have been great to have a native fallback for show/hiding the note.

Template

Like an HTML comment, it's a great way to store the note at a location in an invisible way, especially if it will be processed by JS later on.

Other links

Accessible footnotes with CSS

Some inspiration: https://openai.com/research/image-gpt

Why?

How?

Testing Instructions

Testing Instructions for Keyboard

Screenshots or screencast

@github-actions
Copy link

github-actions bot commented Feb 2, 2023

Size Change: +2.87 kB (0%)

Total Size: 1.35 MB

Filename Size Change
build/block-editor/index.min.js 201 kB +361 B (0%)
build/block-editor/style-rtl.css 14.5 kB +12 B (0%)
build/block-editor/style.css 14.5 kB +9 B (0%)
build/block-library/blocks/columns/style-rtl.css 409 B +3 B (+1%)
build/block-library/blocks/columns/style.css 409 B +3 B (+1%)
build/block-library/blocks/cover/editor-rtl.css 649 B +37 B (+6%) 🔍
build/block-library/blocks/cover/editor.css 651 B +38 B (+6%) 🔍
build/block-library/blocks/cover/style-rtl.css 1.61 kB +15 B (+1%)
build/block-library/blocks/cover/style.css 1.6 kB +15 B (+1%)
build/block-library/blocks/file/style-rtl.css 269 B +4 B (+2%)
build/block-library/blocks/file/style.css 270 B +5 B (+2%)
build/block-library/blocks/post-excerpt/style-rtl.css 141 B +7 B (+5%) 🔍
build/block-library/blocks/post-excerpt/style.css 141 B +7 B (+5%) 🔍
build/block-library/blocks/pullquote/style-rtl.css 335 B +9 B (+3%)
build/block-library/blocks/pullquote/style.css 335 B +10 B (+3%)
build/block-library/common-rtl.css 1.12 kB +3 B (0%)
build/block-library/common.css 1.12 kB +3 B (0%)
build/block-library/editor-rtl.css 11.7 kB +2 B (0%)
build/block-library/editor.css 11.6 kB +3 B (0%)
build/block-library/index.min.js 203 kB +419 B (0%)
build/block-library/style-rtl.css 12.8 kB +31 B (0%)
build/block-library/style.css 12.8 kB +30 B (0%)
build/blocks/index.min.js 51.1 kB -4 B (0%)
build/edit-post/index.min.js 34.9 kB -33 B (0%)
build/edit-site/index.min.js 63.7 kB +501 B (+1%)
build/edit-site/style-rtl.css 10.2 kB +65 B (+1%)
build/edit-site/style.css 10.2 kB +65 B (+1%)
build/edit-widgets/index.min.js 17.3 kB -3 B (0%)
build/editor/index.min.js 45.9 kB +12 B (0%)
build/format-library/index.min.js 7.96 kB +704 B (+10%) ⚠️
build/format-library/style-rtl.css 635 B +78 B (+14%) ⚠️
build/format-library/style.css 634 B +78 B (+14%) ⚠️
build/rich-text/index.min.js 11.5 kB +381 B (+3%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 993 B
build/annotations/index.min.js 2.78 kB
build/api-fetch/index.min.js 2.27 kB
build/autop/index.min.js 2.15 kB
build/blob/index.min.js 483 B
build/block-directory/index.min.js 7.2 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.11 kB
build/block-editor/content.css 4.1 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 91 B
build/block-library/blocks/avatar/style.css 91 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 628 B
build/block-library/blocks/button/style.css 627 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 300 B
build/block-library/blocks/file/editor.css 300 B
build/block-library/blocks/file/view.min.js 353 B
build/block-library/blocks/freeform/editor-rtl.css 2.44 kB
build/block-library/blocks/freeform/editor.css 2.44 kB
build/block-library/blocks/gallery/editor-rtl.css 984 B
build/block-library/blocks/gallery/editor.css 988 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 76 B
build/block-library/blocks/heading/style.css 76 B
build/block-library/blocks/html/editor-rtl.css 332 B
build/block-library/blocks/html/editor.css 333 B
build/block-library/blocks/image/editor-rtl.css 830 B
build/block-library/blocks/image/editor.css 829 B
build/block-library/blocks/image/style-rtl.css 652 B
build/block-library/blocks/image/style.css 652 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 507 B
build/block-library/blocks/media-text/style.css 505 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 716 B
build/block-library/blocks/navigation-link/editor.css 715 B
build/block-library/blocks/navigation-link/style-rtl.css 115 B
build/block-library/blocks/navigation-link/style.css 115 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.13 kB
build/block-library/blocks/navigation/editor.css 2.14 kB
build/block-library/blocks/navigation/style-rtl.css 2.22 kB
build/block-library/blocks/navigation/style.css 2.21 kB
build/block-library/blocks/navigation/view-modal.min.js 2.81 kB
build/block-library/blocks/navigation/view.min.js 447 B
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 401 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 174 B
build/block-library/blocks/paragraph/editor.css 174 B
build/block-library/blocks/paragraph/style-rtl.css 279 B
build/block-library/blocks/paragraph/style.css 281 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 501 B
build/block-library/blocks/post-comments-form/style.css 501 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-featured-image/editor-rtl.css 588 B
build/block-library/blocks/post-featured-image/editor.css 586 B
build/block-library/blocks/post-featured-image/style-rtl.css 322 B
build/block-library/blocks/post-featured-image/style.css 322 B
build/block-library/blocks/post-navigation-link/style-rtl.css 153 B
build/block-library/blocks/post-navigation-link/style.css 153 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 281 B
build/block-library/blocks/post-template/style.css 281 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 103 B
build/block-library/blocks/preformatted/style.css 103 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/theme-rtl.css 167 B
build/block-library/blocks/pullquote/theme.css 167 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 463 B
build/block-library/blocks/query/editor.css 463 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 165 B
build/block-library/blocks/search/editor.css 165 B
build/block-library/blocks/search/style-rtl.css 408 B
build/block-library/blocks/search/style.css 406 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 474 B
build/block-library/blocks/shortcode/editor.css 474 B
build/block-library/blocks/site-logo/editor-rtl.css 489 B
build/block-library/blocks/site-logo/editor.css 489 B
build/block-library/blocks/site-logo/style-rtl.css 203 B
build/block-library/blocks/site-logo/style.css 203 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 674 B
build/block-library/blocks/social-links/editor.css 673 B
build/block-library/blocks/social-links/style-rtl.css 1.4 kB
build/block-library/blocks/social-links/style.css 1.39 kB
build/block-library/blocks/spacer/editor-rtl.css 332 B
build/block-library/blocks/spacer/editor.css 332 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 433 B
build/block-library/blocks/table/editor.css 433 B
build/block-library/blocks/table/style-rtl.css 651 B
build/block-library/blocks/table/style.css 650 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 404 B
build/block-library/blocks/template-part/editor.css 404 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 179 B
build/block-library/blocks/video/style.css 179 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 478 B
build/block-library/reset.css 478 B
build/block-library/theme-rtl.css 698 B
build/block-library/theme.css 703 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.83 kB
build/components/index.min.js 208 kB
build/components/style-rtl.css 11.7 kB
build/components/style.css 11.7 kB
build/compose/index.min.js 12.4 kB
build/core-data/index.min.js 16.3 kB
build/customize-widgets/index.min.js 12.2 kB
build/customize-widgets/style-rtl.css 1.41 kB
build/customize-widgets/style.css 1.41 kB
build/data-controls/index.min.js 663 B
build/data/index.min.js 8.68 kB
build/date/index.min.js 40.4 kB
build/deprecated/index.min.js 518 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.72 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/style-rtl.css 7.6 kB
build/edit-post/style.css 7.59 kB
build/edit-widgets/style-rtl.css 4.56 kB
build/edit-widgets/style.css 4.56 kB
build/editor/style-rtl.css 3.49 kB
build/editor/style.css 3.48 kB
build/element/index.min.js 4.95 kB
build/escape-html/index.min.js 548 B
build/hooks/index.min.js 1.66 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.79 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.79 kB
build/keycodes/index.min.js 1.94 kB
build/list-reusable-blocks/index.min.js 2.14 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.99 kB
build/notices/index.min.js 977 B
build/plugins/index.min.js 1.94 kB
build/preferences-persistence/index.min.js 2.23 kB
build/preferences/index.min.js 1.35 kB
build/primitives/index.min.js 960 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 937 B
build/react-i18n/index.min.js 702 B
build/react-refresh-entry/index.min.js 8.44 kB
build/react-refresh-runtime/index.min.js 7.31 kB
build/redux-routine/index.min.js 2.75 kB
build/reusable-blocks/index.min.js 2.26 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/server-side-render/index.min.js 2.09 kB
build/shortcode/index.min.js 1.52 kB
build/style-engine/index.min.js 1.55 kB
build/token-list/index.min.js 650 B
build/url/index.min.js 3.74 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 1.09 kB
build/warning/index.min.js 280 B
build/widgets/index.min.js 7.3 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.06 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Feb 2, 2023

Flaky tests detected in 284a071b4493abd3b525b33a6d4e9c7a4d6b0d16.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4607359876
📝 Reported issues:

@ellatrix ellatrix mentioned this pull request Feb 2, 2023
6 tasks
@mcsf
Copy link
Contributor

mcsf commented Feb 13, 2023

Thanks for getting the discussion started here!

I like the idea of an inline approach whose intrinsic markup intuitively makes sense to the reader even in the absence of server-side or client-side processing. [# is nice! Why not enhance it with some minimal markup, like span? Here is a quick experiment:

https://jsfiddle.net/kd63cqrx/

<ruby> and <details> are interesting ideas, but IMO too messy for different reasons. Meanwhile, <template and <!-- sound like they would always need a reliable runtime (server- or client-side) to bring the footnotes to life.

@aristath
Copy link
Member

aristath commented Feb 14, 2023

This is a really exciting exploration, thank you @ellatrix!

I like the idea of an inline approach whose intrinsic markup intuitively makes sense to the reader even in the absence of server-side or client-side processing. [# is nice

+1 👍

Regarding rendering the footnotes and where to place them:
I think the most versatile approach would be to have a footnotes block, whose role will be to render the footnotes that have been inserted on the page as comments. This way, users can add them to the bottom of their page, a sidebar/column and so on.

@ellatrix
Copy link
Member Author

I don't think a footnotes block is a good idea.

  • The user can place it anywhere in places that don't make sense. What if it's in the middle of the content and there a footnotes behind it?
  • In case of post pagination, footnotes need to be accumulated at the end of every page. We can't rely on the user to onder a block before every page break.
  • What if you add footnotes and forget the block?
  • What if you want to switch to popover footnotes?

In my opinion it's better to automatically accumulate the footnotes. A block has additional benefits. The block would also just be a marker of where to insert the notes, it wouldn't actually contain the notes.

@ellatrix ellatrix changed the title Footnotes (again) Footnotes (again): MVP Mar 30, 2023
@ellatrix ellatrix requested a review from dcalhoun as a code owner March 30, 2023 07:56
$count = $notes[ $id ]['count'];

return (
'<sup><a class="note-link" href="#' . $id . '" id="' . $id . '-link-' . $count . '">[' . $index . ']</a></sup>'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Musing a bit here to explore ways this can be done with the HTML API. This is me playing with the idea and seeing how this need might be taken care of and lead the HTML API design…

This first one uses the Tag Processor in a way that's tightly coupled to internal details. It's not the way we want people to use the Tag Processor, but it's technically possible with what's in Core.

class FootNoteProcessor extends WP_HTML_Tag_Processor {
	public function replace_footnotes() {
		$notes = array();

		while ( $this->next_tag( 'data' ) ) {
			if ( 'core/footnote' !== $this->get_attribute( 'value' ) ) {
				continue;
			}

			// This bookmark stuff is internal. Possible to use it here now
			// like this, but not something intended to be used in practice
			// outside of the Processor classes.
			$this->set_bookmark( 'start' );
			$start = $this->bookmarks['start']->start;

			// Move to the very next tag token. If it isn't closing
			// the DATA tag then bail; it's not what we expect.
			if ( ! (
				$this->next_tag( array( 'tag_closers' => 'visit' ) ) &&
				'DATA' === $this->get_tag() &&
				$this->is_tag_closer()
			) ) {
				return false;
			}
			$this->set_bookmark( 'end' );

			// Grab the existing inner content.
			$note = substr(
				$this->html,
				$this->bookmarks['start']->end,
				$this->bookmarks['end']->start
			);

			$id = md5( $note );

			if ( isset( $notes[ $id ] ) ) {
				$notes[ $id ]['count'] += 1;
			} else {
				$notes[ $id ] = array(
					'note'  => $note,
					'count' => 1,
				);
			}

			// List starts at 1. If the note already exists, use the existing index.
			$index = 1 + array_search( $id, array_keys( $notes ), true );
			$count = $notes[ $id ]['count'];


			$footnote = new WP_HTML_Tag_Processor( "<sup><a>[{$index}]</a></sup>" );
			$footnote->next_tag( 'a' );
			$footnote->add_class( 'note-link' );
			$footnote->set_attribute( 'href', "#{$id}" );
			$footnote->set_attribute( 'id', "{$id}-link-{$count}" );

			// Replace the outer content with the new structure.
			$this->lexical_updates[] = new WP_HTML_Text_Replacement(
				$this->bookmarks['start']->start,
				$this->bookmarks['end']->end + 1,
				$footnote->get_updated_html()
			);

			$this->bookmarks['start']->start = $start;
			$this->bookmarks['start']->end   = $start;
			$this->seek( 'start' );
			$this->next_tag();
		}

		if ( empty( $notes ) ) {
			return true;
		}

		…
	}
}

$footnote_processor = new FootnoteProcessor( $block_html );
$footnote_processor->replace_footnotes();
$with_footnotes = $footnote_processor->get_updated_html();

The HTML processor should end up making this far less noisy and remove the internal coupling, but isn't available yet. I think that the code above will work today.

function replace_footnotes( $html ) {
	$p = new WP_HTML_Processor( $html );g
	$notes = array();

	while ( $p->select( 'data[value = "core/footnote"]' ) ) {
		$note = $p->get_inner_html();

		…

		$p->set_outer_html( $footnote->get_updated_html() );
	}

	if ( empty( $notes ) ) {
		return $p->get_updated_html();
	}

	…
}

And yesterday while exploring some unrelated bits I thought of an idea to use today's Tag Processor to generate the template in easier way, utilizing the funky HTML placeholder syntax I realized is possible through abuse of the "tag closer with invalid tag name is a comment" rule.

$footnote = wp_html_template(
	<<<HTML
	<sup>
		<a class="note-link" href="#</%id>" id="</%id>-link-</%count>">[</%index>]</a>
	</sup>
HTML,
	array(
		'id'    => $id,
		'index' => $index,
		'count' => $count
	)
);

@ellatrix ellatrix changed the base branch from trunk to try/rich-text-data April 4, 2023 13:19
@ellatrix ellatrix changed the base branch from try/rich-text-data to trunk April 13, 2023 09:53
@ellatrix
Copy link
Member Author

I order to preserve some earlier work, I created a new PR (#49797).

@ellatrix ellatrix closed this Apr 13, 2023
@ellatrix ellatrix deleted the try/footnotes-again branch April 13, 2023 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants