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

RichTextData: use a private property #58557

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/rich-text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ _Returns_

The RichTextData class is used to instantiate a wrapper around rich text values, with methods that can be used to transform or manipulate the data.

- Create an emtpy instance: `new RichTextData()`.
- Create one from an html string: `RichTextData.fromHTMLString(
- Create an empty instance: `new RichTextData()`.
- Create one from an HTML string: `RichTextData.fromHTMLString(
'<em>hello</em>' )`.
- Create one from a wrapper HTMLElement: `RichTextData.fromHTMLElement(
document.querySelector( 'p' ) )`.
Expand Down
28 changes: 10 additions & 18 deletions packages/rich-text/src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,12 @@ function toFormat( { tagName, attributes } ) {
};
}

// Ideally we use a private property.
const RichTextInternalData = Symbol( 'RichTextInternalData' );

/**
* The RichTextData class is used to instantiate a wrapper around rich text
* values, with methods that can be used to transform or manipulate the data.
*
* - Create an emtpy instance: `new RichTextData()`.
* - Create one from an html string: `RichTextData.fromHTMLString(
* - Create an empty instance: `new RichTextData()`.
* - Create one from an HTML string: `RichTextData.fromHTMLString(
* '<em>hello</em>' )`.
* - Create one from a wrapper HTMLElement: `RichTextData.fromHTMLElement(
* document.querySelector( 'p' ) )`.
Expand All @@ -117,6 +114,8 @@ const RichTextInternalData = Symbol( 'RichTextInternalData' );
* @todo Add methods to manipulate the data, such as applyFormat, slice etc.
*/
export class RichTextData {
#value;

static empty() {
return new RichTextData();
}
Expand All @@ -138,22 +137,15 @@ export class RichTextData {
return richTextData;
}
constructor( init = createEmptyValue() ) {
// Setting text, formats, and replacements as enumerable properties
// unfortunately visualises these in the e2e tests. As long as the class
// instance doesn't have any enumerable properties, it will be
// visualised as a string.
Object.defineProperty( this, RichTextInternalData, { value: init } );
this.#value = init;
}
toPlainText() {
return getTextContent( this[ RichTextInternalData ] );
return getTextContent( this.#value );
}
// We could expose `toHTMLElement` at some point as well, but we'd only use
// it internally.
toHTMLString() {
return (
this.originalHTML ||
toHTMLString( { value: this[ RichTextInternalData ] } )
);
return this.originalHTML || toHTMLString( { value: this.#value } );
Copy link
Member Author

Choose a reason for hiding this comment

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

The way how originalHTML is defined in fromHTMLElement is not entirely correct. It effectively creates a live binding between the htmlElement and the RichTextData value. If the element's contents change, then toHTMLString() will read the latest .innerHTML value in the getter.

Other parts of the RichTextData value are however not live: the toPlainText method, the .text getter, etc. The object's content can be inconsistent and out of sync.

Copy link
Member

Choose a reason for hiding this comment

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

RichTextData should not be mutable

Copy link
Member Author

Choose a reason for hiding this comment

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

Then we need to read htmlElement.innerHTML only once in RichTextData constructor, not on every call of .toHTMLString.

Copy link
Member

Choose a reason for hiding this comment

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

We do it only once in the static method? originalHTML is a value not a getter?

Copy link
Member

Choose a reason for hiding this comment

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

Or do you mean toHTMLString()? We shouldn't calculate it in the constructor for performance, we sure we could cache it here for the next call

Copy link
Member

Choose a reason for hiding this comment

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

(We only want to serialise when it's needed)

Copy link
Member Author

Choose a reason for hiding this comment

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

originalHTML is a value not a getter?

Oh, somehow I overlooked this 🙂 It's alright then.

}
valueOf() {
return this.toHTMLString();
Expand All @@ -168,13 +160,13 @@ export class RichTextData {
return this.text.length;
}
get formats() {
return this[ RichTextInternalData ].formats;
return this.#value.formats;
}
get replacements() {
return this[ RichTextInternalData ].replacements;
return this.#value.replacements;
}
get text() {
return this[ RichTextInternalData ].text;
return this.#value.text;
}
}

Expand Down
Loading