-
Notifications
You must be signed in to change notification settings - Fork 183
Touch Plugin - Handle the entire flow of touch selection (not rely on browser) #3157
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
Conversation
…ick as general mouse event instead of pointer
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.
Pull Request Overview
This PR refactors the touch selection handling to eliminate cursor flashing and improve touch interaction by handling the entire touch selection flow instead of relying on the browser's default behavior.
Key changes:
- Replace the complex
repositionTouchSelectionfunction with direct selection handling in the TouchPlugin - Move touch event handling from pointer up to pointer down events for immediate response
- Replace
pointerDoubleClickevent with a standarddoubleClickevent
Reviewed Changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/roosterjs-content-model-types/lib/index.ts | Exports DoubleClickEvent, removes PointerDoubleClickEvent |
| packages/roosterjs-content-model-types/lib/event/PointerEvent.ts | Adds originalEvent property, removes PointerDoubleClickEvent |
| packages/roosterjs-content-model-types/lib/event/PluginEventType.ts | Changes from pointerDoubleClick to doubleClick |
| packages/roosterjs-content-model-types/lib/event/PluginEvent.ts | Updates type imports to use DoubleClickEvent |
| packages/roosterjs-content-model-types/lib/event/MouseEvent.ts | Adds DoubleClickEvent interface |
| packages/roosterjs-content-model-plugins/test/touch/TouchPluginTest.ts | Removes outdated test file |
| packages/roosterjs-content-model-plugins/lib/touch/repositionTouchSelection.ts | Removes complex repositioning logic |
| packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts | Complete rewrite with inline selection handling |
| packages/roosterjs-content-model-core/lib/corePlugin/domEvent/DOMEventPlugin.ts | Simplifies event handling, removes pointer timing logic |
| packages/roosterjs-content-model-api/lib/modelApi/selection/adjustWordSelection.ts | Marks function as internal |
| packages/roosterjs-content-model-api/lib/index.ts | Removes adjustWordSelection from public exports |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-core/lib/corePlugin/domEvent/DOMEventPlugin.ts
Outdated
Show resolved
Hide resolved
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.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/roosterjs-content-model-plugins/lib/utils/getNodePositionFromEvent.ts
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/utils/getNodePositionFromEvent.ts
Show resolved
Hide resolved
| while (start > 0 && /\w/.test(text[start - 1])) { | ||
| start--; | ||
| } | ||
|
|
||
| // Move end forward to find word end | ||
| while (end < text.length && /\w/.test(text[end])) { |
Copilot
AI
Sep 17, 2025
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 regex /\w/ only matches ASCII word characters (a-z, A-Z, 0-9, _) and doesn't handle Unicode word characters like accented letters or characters from other languages. Consider using a more comprehensive word boundary detection approach for international text support.
| while (start > 0 && /\w/.test(text[start - 1])) { | |
| start--; | |
| } | |
| // Move end forward to find word end | |
| while (end < text.length && /\w/.test(text[end])) { | |
| while (start > 0 && /[\p{L}\p{N}_]/u.test(text[start - 1])) { | |
| start--; | |
| } | |
| // Move end forward to find word end | |
| while (end < text.length && /[\p{L}\p{N}_]/u.test(text[end])) { |
| while (start > 0 && /\w/.test(text[start - 1])) { | ||
| start--; | ||
| } | ||
|
|
||
| // Move end forward to find word end | ||
| while (end < text.length && /\w/.test(text[end])) { |
Copilot
AI
Sep 17, 2025
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 regex /\w/ only matches ASCII word characters (a-z, A-Z, 0-9, _) and doesn't handle Unicode word characters like accented letters or characters from other languages. Consider using a more comprehensive word boundary detection approach for international text support.
| while (start > 0 && /\w/.test(text[start - 1])) { | |
| start--; | |
| } | |
| // Move end forward to find word end | |
| while (end < text.length && /\w/.test(text[end])) { | |
| while ( | |
| start > 0 && | |
| /[\p{L}\p{N}_]/u.test(text[start - 1]) | |
| ) { | |
| start--; | |
| } | |
| // Move end forward to find word end | |
| while ( | |
| end < text.length && | |
| /[\p{L}\p{N}_]/u.test(text[end]) | |
| ) { |
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.
Pull Request Overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
| if (caretPosition) { | ||
| const { node, offset } = caretPosition; | ||
| const nodeTextContent = node.textContent || ''; | ||
| const wordAtFocus = nodeTextContent[offset]; |
Copilot
AI
Sep 17, 2025
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.
Accessing nodeTextContent[offset] without bounds checking could cause runtime errors if offset is greater than or equal to the text length. Add bounds checking before accessing the character.
| const wordAtFocus = nodeTextContent[offset]; | |
| let wordAtFocus: string | undefined = undefined; | |
| if ( | |
| offset >= 0 && | |
| offset < nodeTextContent.length | |
| ) { | |
| wordAtFocus = nodeTextContent[offset]; | |
| } |
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
packages/roosterjs-content-model-plugins/lib/touch/TouchPlugin.ts
Outdated
Show resolved
Hide resolved
…m/microsoft/roosterjs into u/nguyenvi/touch-reimplementation
If we let browser define selection first, the cursor will be placed in the touched position then being moved by our touch plugin handler. This would cause cursor flashing and moving.
Therefore, to avoid that issue, we have to handle the entire flow of touch selection but not rely on browser.
Changes in PR:
adjustWordSelectionsince it is relied on selection after browser moving the cursormouseDownhandler instead ofmouseUphandlersetTimeoutto recognize double click and prevent default event behavior inside Touch Plugin -> to avoid impact other scenariosMouseEventso better define it is inMouseEventinstead ofPointerEventgetNodePositionFromEventto get the node atx,yvalue provided by eventPrevious PRs: