-
Notifications
You must be signed in to change notification settings - Fork 4.7k
RTC: Fix RichTextData deserialization #76607
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
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -122,6 +122,57 @@ function makeBlocksSerializable( blocks: Block[] ): Block[] { | |||
| } ); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Convert rich-text string attributes in a block back to RichTextData | ||||
| * instances. This is the inverse of makeBlockAttributesSerializable and is | ||||
| * needed when blocks are extracted from the CRDT document, where rich-text | ||||
| * values are stored as Y.Text (which serializes to plain strings via | ||||
| * toJSON()). Without this conversion, block edit components that rely on | ||||
| * RichTextData methods (e.g. `.text`) will receive a raw string and | ||||
| * malfunction. | ||||
| * | ||||
| * @param blockName The block type name, e.g. 'core/code'. | ||||
| * @param attributes The plain-object attributes from CRDT (toJSON). | ||||
| * @return Attributes with rich-text strings replaced by RichTextData. | ||||
| */ | ||||
| function deserializeBlockAttributeValues( | ||||
| blockName: string, | ||||
| attributes: BlockAttributes | ||||
| ): BlockAttributes { | ||||
| const newAttributes = { ...attributes }; | ||||
|
|
||||
| for ( const [ key, value ] of Object.entries( attributes ) ) { | ||||
| if ( | ||||
| isRichTextAttribute( blockName, key ) && | ||||
| typeof value === 'string' | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The deserialize function, if I'm reading it right, doesn't account for arrays the way the serialize function does (tables for instance). Wouldn't the new rich-text conversion not apply if this kind of text existed in a table? |
||||
| ) { | ||||
| newAttributes[ key ] = RichTextData.fromHTMLString( value ); | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following this call stack, we eventually land here:
Is this cheap enough (given the |
||||
| } | ||||
| } | ||||
|
|
||||
| return newAttributes; | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Convert blocks from their CRDT-serialized form back to the runtime form | ||||
| * expected by the block editor. This ensures that rich-text attributes are | ||||
| * RichTextData instances rather than raw strings. | ||||
| * | ||||
| * @param blocks Blocks as extracted from the CRDT document via toJSON(). | ||||
| * @return Blocks with rich-text attributes restored to RichTextData. | ||||
| */ | ||||
| export function deserializeBlockAttributes( blocks: Block[] ): Block[] { | ||||
| return blocks.map( ( block: Block ) => { | ||||
| const { name, innerBlocks, attributes, ...rest } = block; | ||||
| return { | ||||
| ...rest, | ||||
| name, | ||||
| attributes: deserializeBlockAttributeValues( name, attributes ), | ||||
| innerBlocks: deserializeBlockAttributes( innerBlocks ?? [] ), | ||||
| }; | ||||
| } ); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * @param {any} gblock | ||||
| * @param {Y.Map} yblock | ||||
|
|
||||
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 serialize function relies on the value being an instant of RichTextData while the deserialize relies on the attribute for the value mentioning that its rich-text. Would a block author always mention that schema type, or could they skip it and then this path wouldn't be triggered? Should we account for the less than ideal path?
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.
We have been assuming this contract will be upheld in general. We definitely should not go down the path of trying to predict the attribute type based on its value.
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.
Totally, we should follow the path of assuming that the contract will be upheld but I wanted to point it out 🙏🏾