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

Fix stripHTML to preserve leading spaces #35457

Closed
wants to merge 7 commits into from

Conversation

getdave
Copy link
Contributor

@getdave getdave commented Oct 8, 2021

Description

In #33849 I discovered that stripHTML() will also strip any leading space characters from the string.

I believe this is because the DOM Parser will ignore any space character coming after the DocType.

I don't believe this is the functionality we would want (or expect) from this utility, but let me know if I'm wrong.

This PR captures any spaces at the start of the string and then restores them to the string after the DOMParser has completed. This preserves the original whitespace on the string.

I also added some unit tests - although I'm surprised they worked because I didn't think Jest would have access to the window 🤔

How has this been tested?

Pop open dev tools Console and type in the following (this simulates what we are currently doing in trunk):

new window.DOMParser().parseFromString(
    '    a string with leading spaces',
    'text/html'
).body.textContent

Notice how the leading spaces are stripped off.

Now run the unit tests on this PR:

npm run test-unit:watch packages/dom/src/dom/test/strip-html.js

Note how the leading spaces in the tests are now preserved.

Check implementation is suitable.

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • I've tested my changes with keyboard and screen readers.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR (please manually search all *.native.js files for terms that need renaming or removal).

@getdave getdave added [Type] Bug An existing feature does not function as intended [Package] Rich text /packages/rich-text labels Oct 8, 2021
@getdave getdave requested review from gwwar and ellatrix October 8, 2021 10:45
@getdave getdave self-assigned this Oct 8, 2021
@github-actions
Copy link

github-actions bot commented Oct 8, 2021

Size Change: +422 B (0%)

Total Size: 1.07 MB

Filename Size Change
build/block-library/index.min.js 147 kB +494 B (0%)
build/dom/index.min.js 4.47 kB +18 B (0%)
build/reusable-blocks/index.min.js 2.19 kB -90 B (-4%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 931 B
build/admin-manifest/index.min.js 1.09 kB
build/annotations/index.min.js 2.7 kB
build/api-fetch/index.min.js 2.21 kB
build/autop/index.min.js 2.08 kB
build/blob/index.min.js 459 B
build/block-directory/index.min.js 6.2 kB
build/block-directory/style-rtl.css 1.01 kB
build/block-directory/style.css 1.01 kB
build/block-editor/default-editor-styles-rtl.css 378 B
build/block-editor/default-editor-styles.css 378 B
build/block-editor/index.min.js 135 kB
build/block-editor/style-rtl.css 13.9 kB
build/block-editor/style.css 13.9 kB
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 65 B
build/block-library/blocks/archives/style.css 65 B
build/block-library/blocks/audio/editor-rtl.css 58 B
build/block-library/blocks/audio/editor.css 58 B
build/block-library/blocks/audio/style-rtl.css 111 B
build/block-library/blocks/audio/style.css 111 B
build/block-library/blocks/audio/theme-rtl.css 125 B
build/block-library/blocks/audio/theme.css 125 B
build/block-library/blocks/block/editor-rtl.css 161 B
build/block-library/blocks/block/editor.css 161 B
build/block-library/blocks/button/editor-rtl.css 474 B
build/block-library/blocks/button/editor.css 474 B
build/block-library/blocks/button/style-rtl.css 600 B
build/block-library/blocks/button/style.css 600 B
build/block-library/blocks/buttons/editor-rtl.css 315 B
build/block-library/blocks/buttons/editor.css 315 B
build/block-library/blocks/buttons/style-rtl.css 370 B
build/block-library/blocks/buttons/style.css 370 B
build/block-library/blocks/calendar/style-rtl.css 207 B
build/block-library/blocks/calendar/style.css 207 B
build/block-library/blocks/categories/editor-rtl.css 84 B
build/block-library/blocks/categories/editor.css 83 B
build/block-library/blocks/categories/style-rtl.css 79 B
build/block-library/blocks/categories/style.css 79 B
build/block-library/blocks/code/style-rtl.css 90 B
build/block-library/blocks/code/style.css 90 B
build/block-library/blocks/code/theme-rtl.css 131 B
build/block-library/blocks/code/theme.css 131 B
build/block-library/blocks/columns/editor-rtl.css 206 B
build/block-library/blocks/columns/editor.css 205 B
build/block-library/blocks/columns/style-rtl.css 497 B
build/block-library/blocks/columns/style.css 496 B
build/block-library/blocks/cover/editor-rtl.css 666 B
build/block-library/blocks/cover/editor.css 670 B
build/block-library/blocks/cover/style-rtl.css 1.24 kB
build/block-library/blocks/cover/style.css 1.24 kB
build/block-library/blocks/embed/editor-rtl.css 488 B
build/block-library/blocks/embed/editor.css 488 B
build/block-library/blocks/embed/style-rtl.css 417 B
build/block-library/blocks/embed/style.css 417 B
build/block-library/blocks/embed/theme-rtl.css 124 B
build/block-library/blocks/embed/theme.css 124 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/style-rtl.css 255 B
build/block-library/blocks/file/style.css 255 B
build/block-library/blocks/file/view.min.js 322 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 977 B
build/block-library/blocks/gallery/editor.css 982 B
build/block-library/blocks/gallery/style-rtl.css 1.6 kB
build/block-library/blocks/gallery/style.css 1.59 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 159 B
build/block-library/blocks/group/editor.css 159 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 114 B
build/block-library/blocks/heading/style.css 114 B
build/block-library/blocks/home-link/style-rtl.css 247 B
build/block-library/blocks/home-link/style.css 247 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 731 B
build/block-library/blocks/image/editor.css 730 B
build/block-library/blocks/image/style-rtl.css 491 B
build/block-library/blocks/image/style.css 494 B
build/block-library/blocks/image/theme-rtl.css 124 B
build/block-library/blocks/image/theme.css 124 B
build/block-library/blocks/latest-comments/style-rtl.css 284 B
build/block-library/blocks/latest-comments/style.css 284 B
build/block-library/blocks/latest-posts/editor-rtl.css 137 B
build/block-library/blocks/latest-posts/editor.css 137 B
build/block-library/blocks/latest-posts/style-rtl.css 528 B
build/block-library/blocks/latest-posts/style.css 527 B
build/block-library/blocks/list/style-rtl.css 94 B
build/block-library/blocks/list/style.css 94 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 493 B
build/block-library/blocks/media-text/style.css 490 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 568 B
build/block-library/blocks/navigation-link/editor.css 570 B
build/block-library/blocks/navigation-link/style-rtl.css 94 B
build/block-library/blocks/navigation-link/style.css 94 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 300 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation-submenu/style-rtl.css 195 B
build/block-library/blocks/navigation-submenu/style.css 195 B
build/block-library/blocks/navigation-submenu/view.min.js 343 B
build/block-library/blocks/navigation/editor-rtl.css 1.72 kB
build/block-library/blocks/navigation/editor.css 1.72 kB
build/block-library/blocks/navigation/style-rtl.css 1.62 kB
build/block-library/blocks/navigation/style.css 1.61 kB
build/block-library/blocks/navigation/view.min.js 2.74 kB
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 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 198 B
build/block-library/blocks/page-list/style.css 198 B
build/block-library/blocks/paragraph/editor-rtl.css 157 B
build/block-library/blocks/paragraph/editor.css 157 B
build/block-library/blocks/paragraph/style-rtl.css 273 B
build/block-library/blocks/paragraph/style.css 273 B
build/block-library/blocks/post-author/editor-rtl.css 210 B
build/block-library/blocks/post-author/editor.css 210 B
build/block-library/blocks/post-author/style-rtl.css 182 B
build/block-library/blocks/post-author/style.css 181 B
build/block-library/blocks/post-comments-form/style-rtl.css 140 B
build/block-library/blocks/post-comments-form/style.css 140 B
build/block-library/blocks/post-comments/style-rtl.css 360 B
build/block-library/blocks/post-comments/style.css 359 B
build/block-library/blocks/post-excerpt/editor-rtl.css 73 B
build/block-library/blocks/post-excerpt/editor.css 73 B
build/block-library/blocks/post-excerpt/style-rtl.css 69 B
build/block-library/blocks/post-excerpt/style.css 69 B
build/block-library/blocks/post-featured-image/editor-rtl.css 396 B
build/block-library/blocks/post-featured-image/editor.css 397 B
build/block-library/blocks/post-featured-image/style-rtl.css 146 B
build/block-library/blocks/post-featured-image/style.css 146 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 391 B
build/block-library/blocks/post-template/style.css 392 B
build/block-library/blocks/post-terms/style-rtl.css 73 B
build/block-library/blocks/post-terms/style.css 73 B
build/block-library/blocks/post-title/style-rtl.css 60 B
build/block-library/blocks/post-title/style.css 60 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 198 B
build/block-library/blocks/pullquote/editor.css 198 B
build/block-library/blocks/pullquote/style-rtl.css 378 B
build/block-library/blocks/pullquote/style.css 378 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 262 B
build/block-library/blocks/query-pagination/editor.css 255 B
build/block-library/blocks/query-pagination/style-rtl.css 234 B
build/block-library/blocks/query-pagination/style.css 231 B
build/block-library/blocks/query-title/editor-rtl.css 85 B
build/block-library/blocks/query-title/editor.css 85 B
build/block-library/blocks/query/editor-rtl.css 131 B
build/block-library/blocks/query/editor.css 132 B
build/block-library/blocks/quote/style-rtl.css 187 B
build/block-library/blocks/quote/style.css 187 B
build/block-library/blocks/quote/theme-rtl.css 220 B
build/block-library/blocks/quote/theme.css 222 B
build/block-library/blocks/rss/editor-rtl.css 202 B
build/block-library/blocks/rss/editor.css 204 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 374 B
build/block-library/blocks/search/style.css 375 B
build/block-library/blocks/search/theme-rtl.css 64 B
build/block-library/blocks/search/theme.css 64 B
build/block-library/blocks/separator/editor-rtl.css 99 B
build/block-library/blocks/separator/editor.css 99 B
build/block-library/blocks/separator/style-rtl.css 250 B
build/block-library/blocks/separator/style.css 250 B
build/block-library/blocks/separator/theme-rtl.css 172 B
build/block-library/blocks/separator/theme.css 172 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 769 B
build/block-library/blocks/site-logo/editor.css 769 B
build/block-library/blocks/site-logo/style-rtl.css 165 B
build/block-library/blocks/site-logo/style.css 165 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 84 B
build/block-library/blocks/site-title/editor.css 84 B
build/block-library/blocks/social-link/editor-rtl.css 165 B
build/block-library/blocks/social-link/editor.css 165 B
build/block-library/blocks/social-links/editor-rtl.css 812 B
build/block-library/blocks/social-links/editor.css 811 B
build/block-library/blocks/social-links/style-rtl.css 1.3 kB
build/block-library/blocks/social-links/style.css 1.3 kB
build/block-library/blocks/spacer/editor-rtl.css 307 B
build/block-library/blocks/spacer/editor.css 307 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 471 B
build/block-library/blocks/table/editor.css 472 B
build/block-library/blocks/table/style-rtl.css 481 B
build/block-library/blocks/table/style.css 481 B
build/block-library/blocks/table/theme-rtl.css 188 B
build/block-library/blocks/table/theme.css 188 B
build/block-library/blocks/tag-cloud/style-rtl.css 146 B
build/block-library/blocks/tag-cloud/style.css 146 B
build/block-library/blocks/template-part/editor-rtl.css 636 B
build/block-library/blocks/template-part/editor.css 635 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/term-description/editor-rtl.css 90 B
build/block-library/blocks/term-description/editor.css 90 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 87 B
build/block-library/blocks/verse/style.css 87 B
build/block-library/blocks/video/editor-rtl.css 571 B
build/block-library/blocks/video/editor.css 572 B
build/block-library/blocks/video/style-rtl.css 173 B
build/block-library/blocks/video/style.css 173 B
build/block-library/blocks/video/theme-rtl.css 124 B
build/block-library/blocks/video/theme.css 124 B
build/block-library/common-rtl.css 853 B
build/block-library/common.css 849 B
build/block-library/editor-rtl.css 9.89 kB
build/block-library/editor.css 9.89 kB
build/block-library/reset-rtl.css 474 B
build/block-library/reset.css 474 B
build/block-library/style-rtl.css 10.4 kB
build/block-library/style.css 10.5 kB
build/block-library/theme-rtl.css 665 B
build/block-library/theme.css 669 B
build/block-serialization-default-parser/index.min.js 1.09 kB
build/block-serialization-spec-parser/index.min.js 2.79 kB
build/blocks/index.min.js 45.7 kB
build/components/index.min.js 214 kB
build/components/style-rtl.css 15.9 kB
build/components/style.css 15.9 kB
build/compose/index.min.js 10.3 kB
build/core-data/index.min.js 12.4 kB
build/customize-widgets/index.min.js 11.2 kB
build/customize-widgets/style-rtl.css 1.5 kB
build/customize-widgets/style.css 1.49 kB
build/data-controls/index.min.js 614 B
build/data/index.min.js 7.1 kB
build/date/index.min.js 31.5 kB
build/deprecated/index.min.js 428 B
build/dom-ready/index.min.js 304 B
build/edit-navigation/index.min.js 15.3 kB
build/edit-navigation/style-rtl.css 3.74 kB
build/edit-navigation/style.css 3.74 kB
build/edit-post/classic-rtl.css 492 B
build/edit-post/classic.css 494 B
build/edit-post/index.min.js 29.2 kB
build/edit-post/style-rtl.css 7.2 kB
build/edit-post/style.css 7.19 kB
build/edit-site/index.min.js 29.4 kB
build/edit-site/style-rtl.css 5.5 kB
build/edit-site/style.css 5.5 kB
build/edit-widgets/index.min.js 15.7 kB
build/edit-widgets/style-rtl.css 4.1 kB
build/edit-widgets/style.css 4.1 kB
build/editor/index.min.js 37.5 kB
build/editor/style-rtl.css 3.76 kB
build/editor/style.css 3.75 kB
build/element/index.min.js 3.17 kB
build/escape-html/index.min.js 517 B
build/format-library/index.min.js 5.93 kB
build/format-library/style-rtl.css 571 B
build/format-library/style.css 571 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 424 B
build/i18n/index.min.js 3.6 kB
build/is-shallow-equal/index.min.js 501 B
build/keyboard-shortcuts/index.min.js 1.72 kB
build/keycodes/index.min.js 1.3 kB
build/list-reusable-blocks/index.min.js 1.85 kB
build/list-reusable-blocks/style-rtl.css 838 B
build/list-reusable-blocks/style.css 838 B
build/media-utils/index.min.js 2.92 kB
build/notices/index.min.js 845 B
build/nux/index.min.js 2.03 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 743 B
build/plugins/index.min.js 1.83 kB
build/primitives/index.min.js 921 B
build/priority-queue/index.min.js 582 B
build/react-i18n/index.min.js 671 B
build/redux-routine/index.min.js 2.63 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.6 kB
build/server-side-render/index.min.js 1.5 kB
build/shortcode/index.min.js 1.48 kB
build/token-list/index.min.js 562 B
build/url/index.min.js 1.74 kB
build/viewport/index.min.js 1.02 kB
build/warning/index.min.js 248 B
build/widgets/index.min.js 7.11 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

@adamziel
Copy link
Contributor

adamziel commented Oct 8, 2021

Just flagging that /(^\s+)/g will also match \n , \t and so on – that may be fine, but if it's not then you may want to match specific characters instead of an entire class.

Copy link
Member

@kevin940726 kevin940726 left a comment

Choose a reason for hiding this comment

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

That's good to know!

I believe jest works because jsdom has included polyfill maybe?

packages/dom/src/dom/strip-html.js Outdated Show resolved Hide resolved
expect( stripHTML( input ) ).toBe( output );
} );

it( 'should preserve leading spaces', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Let's also add some tests with \t, \n, and multiline html.

@ellatrix
Copy link
Member

ellatrix commented Oct 8, 2021

That's just how HTML works. Leading should collapse. What's the use case in preserving them? Worth noting that any consecutive spacing elsewhere will also collapse.

@getdave
Copy link
Contributor Author

getdave commented Oct 8, 2021

Thanks your perspective here @ellatrix. Clearly I don't want to introduce a fix for something that doesn't need a fix. However please can you help me to understand the following?

What's the use case in preserving them?

My expectation was that if I use a utility called stripHTML then it should strip HTML from a string (and nothing else).

I wouldn't expect it to strip spaces from the string.

The use case was removing HTML tags coming from the <RichText /> component used on the Nav block so they are not shown in the proposed new text <input /> element of the <LinkControl />.

That's just how HTML works

With respect, I would have thought that how HTML works really isn't really something the consumer should have to be aware of. If I use a utility, I expect it to do what it says on the tin.

Update: here's strip_tags - [what I believe to be] a similar utility in PHP for comparison. It does not strip whitespace:

https://3v4l.org/Qcl17

However, I note the "tags" vs "html". Is that difference in nomenclature significant?

@ellatrix
Copy link
Member

ellatrix commented Oct 8, 2021

Sure, if we're just looking to strip HTML tags, maybe we shouldn't parse it as HTML? While this fixes preserving leading and trailing whitespace, it doesn't preserve whitespace elsewhere.

The use case was removing HTML tags coming from the component used on the Nav block so they are not shown in the proposed new text element of the .

I'm not sure I get why any HTML needs to be stripped? If you're displaying the value in an input field and this value needs to be plain text, how did any HTML tags end up in this value?

@kevin940726
Copy link
Member

From what I understand so far, perhaps this shouldn't be handled in stripHTML at all, but rather should be handled in <LinkControl> or similar places. I agree that the purpose of stripHTML is not that clear though, maybe it should be called as something like getHTMLTextContent.

We could also add an optional option collapseWhitespaces in stripHTML, but as I said before, I'm not sure that's the right call either.

@getdave
Copy link
Contributor Author

getdave commented Oct 11, 2021

I'm not sure I get why any HTML needs to be stripped? If you're displaying the value in an input field and this value needs to be plain text, how did any HTML tags end up in this value?

@ellatrix Here's the scenario I was running in to.

Screen.Capture.on.2021-10-11.at.12-13-24.mov

Thinking about this more, I'm now conflicted. Should LinkControl need to handle this or should the consumer be responsible for not passing a string containing HTML?

No longer conflicted. LinkControl shouldn't care. It's the Nav Link block (the consumer) that should strip the HTML formatting.

In the future we can get cleverer about preserving the HTML tags coming from the <RichText /> on the Nav Link block.

...it doesn't preserve whitespace elsewhere

In what scenarios does this occur?

@adamziel
Copy link
Contributor

adamziel commented Oct 11, 2021

From what I understand so far, perhaps this shouldn't be handled in stripHTML at all, but rather should be handled in <LinkControl> or similar places. I agree that the purpose of stripHTML is not that clear though, maybe it should be called as something like getHTMLTextContent.

@kevin940726 what goes in favor of removing the whitespace characters in stripHTML?

Sure, if we're just looking to strip HTML tags, maybe we shouldn't parse it as HTML?

@ellatrix An alternative is to use regular expressions, but that sounds like a lot of extra effort and a gateway to accidental XSS issues. Parsing is easy and handles that for free, except the whitespaces.

@ellatrix
Copy link
Member

An alternative is to use regular expressions, but that sounds like a lot of extra effort and a gateway to accidental XSS issues. Parsing is easy and handles that for free, except the whitespaces.

Sure, that's true. I'm still wondering why we need to strip HTML here though. Where does this HTML come from? If it's from Rich Text and we no HTML should be added, then it sounds like we need Plain Text instead?

@getdave
Copy link
Contributor Author

getdave commented Oct 11, 2021

I'm still wondering why we need to strip HTML here though. Where does this HTML come from? If it's from Rich Text and we no HTML should be added, then it sounds like we need Plain Text instead?

Here is where the string that contains HTML is provided to the component which is storing the value that ultimately gets passed to <LinkControl />

<RichText
ref={ ref }
identifier="label"
className="wp-block-navigation-item__label"
value={ label }
onChange={ ( labelValue ) =>
setAttributes( { label: labelValue } )
}

We need to use rich formatting in the Nav Link block because a user might want to make link items bold or italic or whatever.

@gwwar
Copy link
Contributor

gwwar commented Oct 11, 2021

Here's the scenario I was running in to.

@getdave what if we strip formatting when editing via the split url/text control? Seeing html tags in a text field is pretty distracting in general, and I think it's pretty quick to reapply formatting in the rich text editor if folks need it.

@ellatrix
Copy link
Member

We need to use rich formatting in the Nav Link block because a user might want to make link items bold or italic or whatever.

So we allow the user to add bold etc., but then we strip it when they use the link control? And if they edit the text there, the changes will be saved and the bold will be lost? Or is that text purely read-only in the link control? If it's editable, it should be a rich text field as well?

@getdave
Copy link
Contributor Author

getdave commented Oct 12, 2021

Thanks for continuing to discuss the best solution here.

Just so we know, the <LinkControl /> split text/url field work is being handled in #33849.

@jasmussen has said he feels comfortable that if we're editing the link text using the Link UI then it's ok to loose the formatting.

The alternative would be for the Link UI to "know" about RichText or have the ability to display with a formatting toolbar (ie: what Ella says about "it should be a rich text field as well").

Personally I think for v1 we should to simply strip the HTML tags from the Nav Link block text when we pass it to the Link UI. This will cause loss of formatting but that's relatively minor for now.

For a v2 we could then explore changing the text control in LinkControl to become RichText field in order that we can handle more values with formatting.

Do we agree that is an acceptable route forward for #33849?

Circling back to this PR however - shall I:

  1. Close this PR and accept that stripHTML also implies removing whitespace (we should probably update the docs to reflect that)? We will then manually strip the HTML in the Nav Link block code instead.
  2. Pursue this PR "as is" because stripHTML doesn't imply "remove whitespace"?

I'm currently concerned about #2 because I still don't quite understand @ellatrix's statement below:

...it doesn't preserve whitespace elsewhere

How can I replicate this?

@ellatrix
Copy link
Member

I really think the requirement to switch types from HTML to plain text is weird and requires extra consideration. I think we should drop that requirement. Either:

  1. Use plain text for everything.
  2. Use rich text for everything.
  3. User rich text and when editing the raw value, allow editing in HTML.

(3) should be a good enough compromise. The cases that someone has formatting in the value should be rare, and if they do, it's fine to have raw HTML in the text field. If that's not good, then simply render the value with rich text? We don't need to add formatting buttons there, just allow the rich text value to be edited.

@jasmussen
Copy link
Contributor

jasmussen commented Oct 12, 2021

@jasmussen has said he feels comfortable that if we're editing the link text using the Link UI then it's ok to loose the formatting.

Yes indeed, to me it is a separation of concerns:

  • When you are editing in the canvas, you are editing rich text, and have rich text tools available to you. You can edit URLs, their labels, and their formatting, and it behaves as expected.
  • When you edit inside the URL dialog, you are using a separate affordance that is intentionally created for convenience, and is not rich text.

To clarify the flow, it is most definitely a "split" flow:
Split URL

Shown above, the first is the page list selector for navigation items. You click the plus, the URL dialog opens, and lets you choose a destination. The second shows up when you click a link item after the fact. The same separation exists: inside the dialog it's not rich text. Outside, it is.

This is similar to how Google Docs does it:

docs

To me this isn't a question about whether to keep formatting or not, it's about whether to have the extra label editing affordance or not. I find it to be valuable, enough that it's okay for any formatting to be lost when using that interface. Keep in mind we have save revisions, and visible undo buttons for it, and the case where bold or italic is lost when editing here feels like it would be rare.

@ellatrix
Copy link
Member

ellatrix commented Oct 12, 2021

Ok, sounds good.

May I ask what the value is in preserving leading and trailing spaces? When the value is used in HTML, there leading spaces won't appear on the front-end anyway.

Screenshot 2021-10-12 at 13 51 03

@getdave
Copy link
Contributor Author

getdave commented Oct 12, 2021

May I ask what the value is in preserving leading and trailing spaces? When the value is used in HTML, there leading spaces won't appear on the front-end anyway.

In a paragraph block (for example) you might create a link which contains whitespace. When you are editing the text of that link it needs to include the whitespace in order that you can:

  • Preserve it.
  • Remove it.
  • Adjust it.
Screen.Capture.on.2021-10-11.at.12-35-58.1.mov

Update: I just realised this doesn't apply to the Nav block which uses HTML in the value. In which case...I guess we won't need to preserve leading/trailing spaces there.

Does the question still stand about whether stripHTML should remove leading/trailing whitespace?

@ellatrix
Copy link
Member

In a paragraph block (for example) you might create a link which contains whitespace. When you are editing the text of that link it needs to include the whitespace in order that you can:

Worth noting that this will collapse to one space on the front-end. Rich text currently preserves the spaces for editing purposes, but ideally it should also just collapse the whitespace.

What you're looking is the same function but with more context. E.g. when the container is an inline element, stripHTML will preserve the whitespace:

wp.dom.__unstableStripHTML('<a>  test</a>')
=== '  test'

Perhaps we need to allow specifying the container for stripping HTML?

@jasmussen
Copy link
Contributor

Probably part of the effort was inspired by this edgecase where I was stress testing the poor PR, in case it adds context to the leading/trailing space discussion.

@ellatrix
Copy link
Member

I created #35539 as an alternative.

@getdave
Copy link
Contributor Author

getdave commented Oct 12, 2021

Worth noting that this will collapse to one space on the front-end.

I see it does indeed do that:

Screen.Capture.on.2021-10-12.at.13-25-24.mov

ellatrix added a commit that referenced this pull request Oct 13, 2021
@getdave
Copy link
Contributor Author

getdave commented Oct 13, 2021

Closing in favour of #35539

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Rich text /packages/rich-text [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants