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

Input Interaction: restore collapsing selection before edge calc #14906

Merged
merged 5 commits into from
Apr 11, 2019

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Apr 10, 2019

Description

Fixes #14871.
Regression caused by #14871.

Specifically, the following code should not have been removed:

// Create copy of range for setting selection to find effective offset.
const range = selection.getRangeAt( 0 ).cloneRange();
// Collapse in direction of selection.
if ( ! selection.isCollapsed ) {
range.collapse( ! isSelectionForward( selection ) );
}

How has this been tested?

Screenshots

Types of changes

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.

@ellatrix ellatrix added [Type] Bug An existing feature does not function as intended [Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Type] Regression Related to a regression in the latest release labels Apr 10, 2019
@ellatrix ellatrix added this to the 5.5 (Gutenberg) milestone Apr 10, 2019
@ellatrix
Copy link
Member Author

Hm, I ran the e2e test against master, but it does not fail. Looking again.

@ellatrix ellatrix force-pushed the fix/input-interaction-uncollapsed-arrow-selection branch from 4d7e88b to 5d668f3 Compare April 10, 2019 14:15
@ellatrix
Copy link
Member Author

Fixed. Looks like it needed minimum three characters per line.

@ellatrix
Copy link
Member Author

I'm not sure why this code change makes 6fa60b2 needed, but this seems the correct behaviour to me now.

@ellatrix
Copy link
Member Author

The fixed test was introduced in caaf204, which also introduced the code that was removed. But again, the fixed test in this PR seems like the correct behaviour to me. Twice arrow up from a certain horizontal position should land the caret in the same horizontal position if possible.

@ellatrix
Copy link
Member Author

I think the reason is that the range is now cloned, before handing it to getRectangleFromRange.

getRectangleFromRange may unexpectedly modify the live range:

// If the collapsed range starts (and therefore ends) at an element node,
// `getClientRects` can be empty in some browsers. This can be resolved
// by adding a temporary text node with zero-width space to the range.
//
// See: https://stackoverflow.com/a/6847328/995445
if ( ! rect ) {
const padNode = document.createTextNode( '\u200b' );
range.insertNode( padNode );
rect = range.getClientRects()[ 0 ];
padNode.parentNode.removeChild( padNode );
}

@aduth
Copy link
Member

aduth commented Apr 10, 2019

Twice arrow up from a certain horizontal position should land the caret in the same horizontal position if possible.

Yes, I compared the results of the test steps on master and this branch before seeing your comment, and it very much seems like the correct / improved behavior (you can see in the comment box here on GitHub that a native textarea behaves the same).

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

Makes sense, tests well.

Not so sure about where cloneRange in getRectangleFromRange is necessary, but I don't think it can hurt anyways. I'll leave it to your discretion on my feedback.

packages/dom/src/dom.js Show resolved Hide resolved
@@ -209,6 +218,8 @@ export function getRectangleFromRange( range ) {
// See: https://stackoverflow.com/a/6847328/995445
if ( ! rect ) {
const padNode = document.createTextNode( '\u200b' );
// Do not modify to live range.
range = range.cloneRange();
Copy link
Member

Choose a reason for hiding this comment

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

It reminds me of some unrelated testing I'd been doing with Chrome line-ending bugginess, where Range#cloneRange wasn't actually avoiding mutations to the original:

https://codepen.io/aduth/pen/WPjQoW

(See comment: "// WIP: Buggy, collapses spaces (mutates original).")

I never did figure out what I was seeing with my demos. I raise only in case there's still a worry about mutating the cloned 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.

I've not tested the Codepen, but when you make this change in master, this test will also fail:

// Verify vertical traversal at offset. This has been buggy in the past
// where verticality on a blank newline would skip into previous block.
await page.keyboard.type( 'Foo' );
await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'ArrowUp' );
await pressKeyTimes( 'ArrowRight', 3 );
await pressKeyTimes( 'Delete', 6 );
await page.keyboard.type( ' text' );

It is true that cloning the range in isEdge will also prevent this issue, but I think it is safe to clone here is well in case it is called with a live range.

In my testing insertNode doesn't modify the original range.

@@ -209,6 +218,8 @@ export function getRectangleFromRange( range ) {
// See: https://stackoverflow.com/a/6847328/995445
if ( ! rect ) {
const padNode = document.createTextNode( '\u200b' );
// Do not modify to live range.
Copy link
Member

Choose a reason for hiding this comment

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

I'd kinda wonder why it matters, i.e. while true that we're mutating the range, we're also following up with a mutation to remove the added node, which means it should be effectively the same. I'm not entirely clear from the conversation of the pull request what impact this change is having.

Copy link
Member Author

Choose a reason for hiding this comment

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

We do update the DOM again, but not through the range API which may explain why its not restored.

@ellatrix ellatrix force-pushed the fix/input-interaction-uncollapsed-arrow-selection branch from 64d33d7 to ba32d64 Compare April 11, 2019 15:17
@ellatrix ellatrix force-pushed the fix/input-interaction-uncollapsed-arrow-selection branch from ba32d64 to 94c4b6b Compare April 11, 2019 15:18
@ellatrix ellatrix merged commit 8af16de into master Apr 11, 2019
@ellatrix ellatrix deleted the fix/input-interaction-uncollapsed-arrow-selection branch April 11, 2019 16:35
mchowning pushed a commit to mchowning/gutenberg that referenced this pull request Apr 15, 2019
…dPress#14906)

* Input Interaction: restore collapsing selection before edge calc

* Add e2e test

* Fix other e2e test

* Clean up

* Do not modify live range in getRectangleFromRange
aduth pushed a commit that referenced this pull request Apr 17, 2019
)

* Input Interaction: restore collapsing selection before edge calc

* Add e2e test

* Fix other e2e test

* Clean up

* Do not modify live range in getRectangleFromRange
aduth pushed a commit that referenced this pull request Apr 17, 2019
)

* Input Interaction: restore collapsing selection before edge calc

* Add e2e test

* Fix other e2e test

* Clean up

* Do not modify live range in getRectangleFromRange
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Writing Flow Block selection, navigation, splitting, merging, deletion... [Type] Bug An existing feature does not function as intended [Type] Regression Related to a regression in the latest release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Input Interaction: ArrowLeft in multi-line selection prematurely triggers multi-selection
2 participants