Skip to content

Commit 016be2b

Browse files
Improve text selection in WKWebView on macOS
1 parent 15e3d7f commit 016be2b

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

highlight-helper.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,13 @@ function Highlighter(options = hhDefaultOptions) {
572572
const selection = getRestoredSelectionOrCaret(window.getSelection());
573573
const selectionRange = selection.type === 'None' ? null : selection.getRangeAt(0);
574574

575+
// In "Mac (Designed for iPad)" apps (iPad app running on macOS – most recently tested with macOS Sequoia 15.3.1), in-app webviews have several quirks related to text selection. One of these is text selection collapsing to a caret more often than expected. This code attempts to restore the previous selection range if it unexpectedly collapses to a caret in these scenarios:
576+
// 1. While dragging custom selection handles (happens randomly). TODO: Dragging custom selection handles in this environment is still sometimes a little jumpy.
577+
// 2. Just after clicking to activate a highlight (happens if it's the first click after the page loads).
578+
if (isWKWebView && !isTouchDevice && selection.type !== 'Range' && previousSelectionRange && (activeSelectionHandle || (previousSelectionRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) <= 0 && previousSelectionRange.compareBoundaryPoints(Range.END_TO_END, selectionRange) >= 0))) {
579+
selection.setBaseAndExtent(previousSelectionRange.startContainer, previousSelectionRange.startOffset, previousSelectionRange.endContainer, previousSelectionRange.endOffset);
580+
}
581+
575582
// Deactivate highlights when tapping or creating a selection outside of the previous selection range
576583
if (!activeSelectionHandle && previousSelectionRange && (selection.type !== 'Range' || previousSelectionRange.comparePoint(selectionRange.startContainer, selectionRange.startOffset) === 1 || previousSelectionRange.comparePoint(selectionRange.endContainer, selectionRange.endOffset) === -1)) {
577584
this.deactivateHighlights(false);
@@ -1207,13 +1214,14 @@ function Highlighter(options = hhDefaultOptions) {
12071214
let hhHighlighters = [];
12081215

12091216
// Check browser type
1210-
const isTouchDevice = navigator.maxTouchPoints && navigator.maxTouchPoints > 1;
1211-
const isSafari = /^((?!Chrome|Firefox|Android|Samsung).)*AppleWebKit/i.test(navigator.userAgent);
1217+
const isTouchDevice = navigator.maxTouchPoints > 0;
1218+
const isWebKit = /^((?!Chrome|Firefox|Android|Samsung).)*AppleWebKit/i.test(navigator.userAgent);
1219+
const isWKWebView = isWebKit && window.webkit?.messageHandlers;
12121220
const supportsHighlightApi = CSS.highlights;
12131221

12141222
// Workaround to allow programmatic text selection on tap in iOS Safari
12151223
// See https://stackoverflow.com/a/79261423/1349044
1216-
if (isTouchDevice && isSafari) {
1224+
if (isTouchDevice && isWebKit) {
12171225
const tempInput = document.createElement('input');
12181226
tempInput.style.position = 'fixed';
12191227
tempInput.style.top = 0;

0 commit comments

Comments
 (0)