Skip to content

Conversation

@aduth
Copy link
Member

@aduth aduth commented Jun 30, 2018

Closes #6640

This pull request seeks to optimize the RichText component to avoid needing to keep a focusPosition state. This state was used exclusively for the positioning of the link popover overlay, and was calculated on every NodeChange event in TinyMCE (which occurs fairly frequently). Its use of Element#getBoundingClientRect would also trigger browser relayout, thus being prone to layout thrashing (source). This revised implementation introduces a new component which is responsible for positioning itself relative the current selection at the time of its own mount. Therefore, it's only calculating its position when the link overlay is actually used.

Testing instructions:

Verify there are no regressions in the display of the link format popover.

This was challenging to implement automated tests for, since JSDOM supports neither window.getComputedStyle nor HTMLElement#offsetParent. End-to-end tests may be wise for link additions, but the specific behavior here is relevant mostly to visual appearance, and we currently have no precedent for visual regression testing (though it may be worth exploring).

@aduth aduth added [Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable [Type] Performance Related to performance efforts labels Jun 30, 2018
this.setState( { formats, selectedNodeId: this.state.selectedNodeId + 1 } );

if ( this.props.isViewportSmall ) {
let rect;
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needing to be calculated at every node change event? Do we need to scroll every time on that event? Cc @mcsf.

Copy link
Member Author

Choose a reason for hiding this comment

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

It almost certainly doesn't need to be. There's definitely room for improvement here, but I considered it outside the scope of the current task.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good, I like the smaller PRs :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm sure there's room for improvement. When we looked in #5769, there was no proper way to detect when the insertion of a character fills the whole width of a text container and forces the caret into a "new line" (a different height in the same container). 'nodechange' is definitely too generic, but per the comment, on nodechange we can work with the finalized TinyMCE instance and scroll to proper position.

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps the same kind of reasoning we're seeing in this PR (let's manage this ourselves with our vdom abstraction so as to batch positioning writes and reads) can be applied to the caret-tracking scrolling feature.

@ellatrix
Copy link
Member

ellatrix commented Jul 3, 2018

The only thing I can find here is that the position is not updated after inserting a link without selection:

screen shot 2018-07-03 at 17 55 19

But that certainly better than current master:

screen shot 2018-07-03 at 17 58 23

@aduth aduth force-pushed the remove/rich-text-focus-position branch from 797afe9 to c3fe6ce Compare July 3, 2018 17:24
Copy link
Contributor

@mcsf mcsf left a comment

Choose a reason for hiding this comment

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

Looks great!

const selection = window.getSelection();

// Get position relative viewport.
const rect = getRectangleFromRange( selection.getRangeAt( 0 ) );
Copy link
Contributor

Choose a reason for hiding this comment

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

Though improbable in the context in which we expect to use this component, should we guard against IndexSizeError by checking selection.rangeCount > 0 first?

Copy link
Member Author

Choose a reason for hiding this comment

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

Though improbable in the context in which we expect to use this component, should we guard against IndexSizeError by checking selection.rangeCount > 0 first?

Yep, seems very reasonable. Updated in the rebased 6eed870.

this.setState( { formats, selectedNodeId: this.state.selectedNodeId + 1 } );

if ( this.props.isViewportSmall ) {
let rect;
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps the same kind of reasoning we're seeing in this PR (let's manage this ourselves with our vdom abstraction so as to batch positioning writes and reads) can be applied to the caret-tracking scrolling feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

💯

@aduth aduth force-pushed the remove/rich-text-focus-position branch from c3fe6ce to 6eed870 Compare July 3, 2018 18:00
@aduth aduth merged commit bf09112 into master Jul 3, 2018
@aduth aduth deleted the remove/rich-text-focus-position branch July 3, 2018 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Rich Text Related to the Rich Text component that allows developers to render a contenteditable [Type] Performance Related to performance efforts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants