Skip to content

FIX: improves text selection of posts #33143

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

Merged
merged 10 commits into from
Jun 12, 2025
Merged

Conversation

jjaffeux
Copy link
Contributor

@jjaffeux jjaffeux commented Jun 10, 2025

This commit is applying different techniques to make selecting text of a post less error prone:

  • ensure we only ever show the toolbar when the common ancestor of a range is cooked
  • ensures the menu is not interfering with text selection
  • do not compute the menu while selection is changing, only when pointer is released

The situation was very bad on android but it should also improve other situations.

Comment on lines -137 to -152
// ensure we selected content inside 1 post *only*
let postId;
for (let r = 0; r < selection.rangeCount; r++) {
const range = selection.getRangeAt(r);
const selectionStart = getElement(range.startContainer);
const ancestor = getElement(range.commonAncestorContainer);

if (!selectionStart.closest(".cooked")) {
return await this.hideToolbar();
}

postId ||= ancestor.closest(".boxed, .reply")?.dataset?.postId;

if (!ancestor.closest(".contents") || !postId) {
return await this.hideToolbar();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we now receive the cooked from the onSelectionChanged event

Comment on lines -155 to -159
const _selectedElement = getElement(selectedNode());
const cooked =
_selectedElement.querySelector(".cooked") ||
_selectedElement.closest(".cooked");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cooked is received from onSelectionChange event

@@ -220,7 +232,8 @@ export default class PostTextSelection extends Component {
// so we need more space
// - the end of the selection is not in viewport, in this case our menu will be shown at the top
// of the screen, so we need more space to avoid overlapping with the native menu
offset = 70;
const { isAndroid } = this.capabilities;
offset = isAndroid ? 90 : 70;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

THe menu needs more spacing on android

Copy link
Member

Choose a reason for hiding this comment

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

Should we just increase it everywhere for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just the native toolbar on android is bigger, but we can try the same if you think that's better

Comment on lines 760 to 761
&:not(.ios-device) body.-disable-global-text-selection {
// prevents hovering toolbar menu to confuse text selection on android
Copy link
Member

Choose a reason for hiding this comment

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

Can we just do the same thing on iOS for consistency? Or does it cause issues there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it does nothing on iOS I think so yes I can probably just add it too

This commit is applying different techniques to make selecting text of a post less error prone:
- disables text selection of all the page BUT the current post
- ensures the selection menu is not interfering with text selection
- ensures the d-header is not interfering with text selection

The situation was very bad on android but it should also improve other situations.
@jjaffeux jjaffeux force-pushed the better-text-selection-android branch from fe2750f to a929410 Compare June 11, 2025 16:25
Comment on lines -125 to -130
// ensure we never quote text in the post menu area
const postMenuArea = ancestor.querySelector(".post-menu-area");
if (postMenuArea) {
range.setEndBefore(postMenuArea);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we should decide this outside of this helper, setEndBefore is messing with browser behavior and can end up creating weird behaviors where the text selection is changing after cursor release, which is a very janky feeling.

Comment on lines 252 to 257
const parent =
range.commonAncestorContainer.nodeType === Node.TEXT_NODE
? range.commonAncestorContainer.parentNode
: range.commonAncestorContainer;

const cooked = parent.closest(".cooked");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is mostly my solution to ensure we don't show the toolbar when selecting outside of one post, if the common ancestor to a range selection is not a cooked, it means we are selecting outside of a post, or two posts, or a post and something else...

jjaffeux added a commit to discourse/discourse-ai that referenced this pull request Jun 11, 2025
This is needed for discourse/discourse#33143 as we now rely on this pointerup event.

const { isIOS, isWinphone, isAndroid } = this.capabilities;
const wait = isIOS || isWinphone || isAndroid ? INPUT_DELAY : 25;
this.selectionChangeHandler = discourseDebounce(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

now that we rely on pointerup and contextmenu and not selectionchange, we don't need debouncing anymore.

This reverts commit 51c9bb4.
}

// most importantly for android to prevent the quote menu to interfere with the text selection
[data-identifier="post-text-selection-toolbar"].-disable-pointer-events,
Copy link
Member

Choose a reason for hiding this comment

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

Would it be easy to make a class for this element? Selecting by a data attribute feels a little weird


// most importantly for android to prevent the quote menu to interfere with the text selection
[data-identifier="post-text-selection-toolbar"].-disable-pointer-events,
[data-identifier="post-text-selection-toolbar"].-disable-pointer-events * {
Copy link
Member

Choose a reason for hiding this comment

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

Does it work if we do this?

Suggested change
[data-identifier="post-text-selection-toolbar"].-disable-pointer-events * {
[data-identifier="post-text-selection-toolbar"].-disable-pointer-events {

If I'm understanding MDN correctly, pointer-events:none applies to children as long as they don't explicitly set pointer-events: auto 👀

@@ -323,6 +323,16 @@ blockquote {
margin-right: 0;
}

.d-header-wrap * {
Copy link
Member

Choose a reason for hiding this comment

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

Does it work without *? MDN page on user-select says:

the initial auto value makes it behave like it is inherited most of the time

jjaffeux added a commit to discourse/discourse-ai that referenced this pull request Jun 11, 2025
This is needed for discourse/discourse#33143 as we now rely on this pointerup event.
jjaffeux added a commit to discourse/discourse-ai that referenced this pull request Jun 11, 2025
This is needed for discourse/discourse#33143

Ideally we should move all these helpers to core, or improve the ones in core.
jjaffeux added a commit to discourse/discourse-ai that referenced this pull request Jun 12, 2025
This is needed for discourse/discourse#33143

Ideally we should move all these helpers to core, or improve the ones in core.
@jjaffeux jjaffeux merged commit 876dbe6 into main Jun 12, 2025
28 of 29 checks passed
@jjaffeux jjaffeux deleted the better-text-selection-android branch June 12, 2025 13:06
@discoursebot
Copy link

This pull request has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/i-can-only-quote-one-word/369911/1

jjaffeux added a commit that referenced this pull request Jun 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants