-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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 rich text value for nested lists #10799
Conversation
0f202f7
to
85fc26d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anywhere we've said that the multi line support is only intended for lists? Based on the prop name multilineTag
, I would expect that no, it's not just for lists, but any tag. However, everything we build around it seems to be specifically only to support lists. Why is that?
packages/rich-text/src/to-dom.js
Outdated
@@ -110,6 +105,33 @@ function remove( node ) { | |||
return node.parentNode.removeChild( node ); | |||
} | |||
|
|||
function createBogusBR( doc ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If 'br' is an abbreviation of "break" (unsure), correct capitalization would be createBogusBr
packages/rich-text/src/to-dom.js
Outdated
return br; | ||
} | ||
|
||
function pad( node ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is being padded, and with what. This isn't obvious.
packages/rich-text/src/to-tree.js
Outdated
if ( format.type === 'ol' || format.type === 'ul' ) { | ||
accumulator.push( format ); | ||
accumulator.push( multilineFormat ); | ||
} else if ( character !== '\u2028' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we give this magic string a named constant? Out of context, it means nothing to me.
packages/rich-text/src/to-dom.js
Outdated
@@ -110,6 +105,33 @@ function remove( node ) { | |||
return node.parentNode.removeChild( node ); | |||
} | |||
|
|||
function createBogusBR( doc ) { | |||
const br = doc.createElement( 'br' ); | |||
br.setAttribute( 'data-mce-bogus', '1' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure it's known / been discussed before, but this is quite the implied dependency to TinyMCE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to RichText
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea of a "line padding" something which is broadly applicable to support rich text editing? Still seems a bit oriented to TinyMCE specifically, even if not directly by name in the rich-text
package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it something that could be contained within the createEmpty
procedure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea of a "line padding" something which is broadly applicable to support rich text editing?
Yes, it's not specific to TinyMCE. It should be part of the output to edit so you can always place the caret correctly in empty lines.
packages/rich-text/src/to-dom.js
Outdated
function pad( node ) { | ||
const length = node.childNodes.length; | ||
|
||
// Optimise for speed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As opposed to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to do a better review of this later. It's a very domain-specific change, which makes it a bit harder to get into.
packages/rich-text/src/create.js
Outdated
@@ -363,6 +377,7 @@ function createFromMultilineElement( { | |||
unwrapNode, | |||
filterString, | |||
removeAttribute, | |||
startSeparator = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New arg missing in JSDoc
packages/rich-text/src/create.js
Outdated
@@ -391,7 +406,7 @@ function createFromMultilineElement( { | |||
} ); | |||
|
|||
// Multiline value text should be separated by a double line break. | |||
if ( index !== 0 ) { | |||
if ( index !== 0 || startSeparator === true ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps shouldPrependSeparator
would be a better name? should
signals a boolean, and with prepend it seems clearer to me.
packages/rich-text/src/to-dom.js
Outdated
return br; | ||
} | ||
|
||
function pad( node ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is a little hard to decipher. Perhaps defining some terminology if terminology is needed (e.g. padding), and making the high-level purpose evident.
It's not, its for both |
This comment has been minimized.
This comment has been minimized.
e3f9229
to
c08ce51
Compare
28df82f
to
381d0c7
Compare
* | ||
* @return {string} HTML string. | ||
*/ | ||
export function toHTMLString( value, multilineTag ) { | ||
const tree = toTree( value, multilineTag, { | ||
export function toHTMLString( value, multilineTag, multilineWrapperTags ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
toDOM( { value, multilineTag, multilineWrapperTags } );
✅
toTree( { value, multilineTag, multilineWrapperTags } );
✅
toHTMLString( value, multilineTag, multilineWrapperTags );
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that toHTMLString
is now a public API. Fine to change it though, and make sure everything keeps working.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@aduth, thanks, looking at the issues. |
@aduth It's because we're handling ENTER behaviour, but not BACKSPACE. I pushed a fix, which I'm still polishing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested and works well for me 👍
Code-wise, it's a bit complex for me to dive in. cc @aduth since you reviewed earlier.
Thanks @youknowriad! I'll wait for a second review as well before merging. |
export function toHTMLString( value, multilineTag ) { | ||
const tree = toTree( value, multilineTag, { | ||
export function toHTMLString( { value, multilineTag, multilineWrapperTags } ) { | ||
// Check other arguments for back compact. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we going to deprecate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Typo: compact
-> compat
(or backward compatibility
since I'm not sure what we gain in abbreviating)
const isHorizontalNavigation = keyCode === LEFT || keyCode === RIGHT; | ||
if ( isHorizontalNavigation ) { | ||
this.onHorizontalNavigationKeyDown( event ); | ||
} | ||
|
||
if ( keyCode === DELETE || keyCode === BACKSPACE ) { | ||
if ( this.multilineTag ) { | ||
const record = this.createRecord(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea what any of this logic is doing. I would think we're unnecessarily handling backspaces / deletes when removing and not already at the extent of where a line separator would occur. Is that not true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean? Do you mean that we're calling this when we're the selection is not at the edge of a line? We need to have the value to check if we are in the first place, so I don't see a problem with this.
* the selection if none are provided. | ||
* | ||
* @param {Object} value Value to modify. | ||
* @param {number} startIndex Start index. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Mis-alignment of spaces for description (two too far).
import { LINE_SEPARATOR } from '../special-characters'; | ||
import { getSparseArrayLength } from './helpers'; | ||
|
||
describe( 'removePreviousLineSeparator', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the expected behavior of an uncollapsed selection? I'd expect it to be different, at least based on the behavior of backspace in a traditional textarea field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add tests for it as well. I guess it shouldn't remove the line.
/** | ||
* Internal dependencies | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no consistency to the newline placement after these blocks. While technically against the standard, most else of the application omits the newline. We should at the very least be consistent within the same file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I thought there should be a newline in between, so I try to be consistent with that. It would be good to have a linting rule for it.
6fdef17
to
d30fc17
Compare
Looks like the feedback is addressed and the PR still works properly, let's merge when the tests pass. |
There's just a export function getSelectionEnd( { end } ) {
return end;
} We can add more tests separately if needed. I think this is a big improvement for multiline values. Let's merge and iterate. I'll keep an eye on any bugs popping up. |
edit - Ignore this, the issue seems to have been caused by #10723, must have still had the broken build loaded when testing this PR. This change seems to have resulted in this bug: Looking into it now, seems a pretty urgent one to fix. The bug seems to be caused by unstableOnFocus not triggering in RichText - the table cells are not always being selected when they're clicked on. |
Description
A big part of the added lines are unit and e2e tests.
How has this been tested?
See #10701.
Screenshots
Types of changes
Bug fix.
Checklist: