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

feat: Ignore touch on more interactive elements #1678

Merged

Conversation

StarScape
Copy link
Contributor

Fixes #1654. Added in every interactive element I could think of, including contenteditable.

@birtles
Copy link
Member

birtles commented Mar 19, 2024

@StarScape Looks great, thank you!

I wonder if we should re-use isContentEditableNode() from src/utils/dom-utils.ts to test for content editable nodes since I think we could get taps on elements whose ancestor is contenteditable and we'd still want to ignore touches in that case.

While we're at it, maybe we should factor out an isInteractiveElement function for this? The dom-utils.ts file has other functions like isEditableNode etc. so it seems like it would fit in there. (As a side note, in that file we tend to test nodes by looking at their nodeType and tagName properties instead of using instanceof simply so that the functions work cross-frame. I don't think we actually need isInteractiveElement to work cross-frame at this point but if we're adding it to dom-utils.ts maybe we should avoid instanceof just to be consistent.)

@StarScape StarScape force-pushed the 1654-prevent-lookup-on-interactive-elements branch from bee244c to 472280e Compare March 19, 2024 15:29
@StarScape
Copy link
Contributor Author

@birtles All great points! I've done what you suggested. Note I just modified the previous commit rather than creating another one—this is a simple enough change I don't think it warrants 2 commits in the history.

Copy link
Member

@birtles birtles left a comment

Choose a reason for hiding this comment

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

Thanks! Looks great.

Comment on lines 46 to 58
export function isInteractiveElement(elem: Element) {
return (
elem.tagName === 'A' ||
elem.tagName === 'BUTTON' ||
elem.tagName === 'INPUT' ||
elem.tagName === 'TEXTAREA' ||
elem.tagName === 'SELECT' ||
elem.tagName === 'DATALIST' ||
elem.tagName === 'OPTGROUP' ||
elem.tagName === 'OPTION' ||
isContentEditableNode(elem)
);
Copy link
Member

Choose a reason for hiding this comment

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

Nit: If we make this take Node | null like many of the other functions in this file the call site will become a lot simpler.

Suggested change
export function isInteractiveElement(elem: Element) {
return (
elem.tagName === 'A' ||
elem.tagName === 'BUTTON' ||
elem.tagName === 'INPUT' ||
elem.tagName === 'TEXTAREA' ||
elem.tagName === 'SELECT' ||
elem.tagName === 'DATALIST' ||
elem.tagName === 'OPTGROUP' ||
elem.tagName === 'OPTION' ||
isContentEditableNode(elem)
);
export function isInteractiveElement(elem: Node | null) {
return (
isElement(elem) &&
(elem.tagName === 'A' ||
elem.tagName === 'BUTTON' ||
elem.tagName === 'INPUT' ||
elem.tagName === 'TEXTAREA' ||
elem.tagName === 'SELECT' ||
elem.tagName === 'DATALIST' ||
elem.tagName === 'OPTGROUP' ||
elem.tagName === 'OPTION' ||
isContentEditableNode(elem))
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, agreed. Though I think we'll want to move the isContentEditableNode call up to, since, AFAIK, the event target could still be a non-element Node, like a text node, inside of a content editable. I think we'd still want to prevent a tap in those cases.

Though now that I type it out, I'm not sure if the browser will ever have text nodes as event targets?

Comment on lines 306 to 308
possibleTargetElem != null &&
possibleTargetElem.nodeType === Node.ELEMENT_NODE &&
isInteractiveElement(possibleTargetElem)
Copy link
Member

Choose a reason for hiding this comment

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

With the suggestion below, I think this will become just:

Suggested change
possibleTargetElem != null &&
possibleTargetElem.nodeType === Node.ELEMENT_NODE &&
isInteractiveElement(possibleTargetElem)
isInteractiveElement(possibleTargetElem)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep! One addition I missed previously: I have to do a type guard to with instanceof Node to make the call type check. As far as I can tell that's the only way to refine the EventTarget interface into Node in a type safe way (I could be wrong about that, I'm no TypeScript expert). My previous code with the as assertion wasn't actually safe, whoops 😬 .

The instanceof usage does lose the cross-frame capability, though. Not sure if that matters for particular this listener?

@birtles
Copy link
Member

birtles commented Mar 20, 2024

@birtles All great points! I've done what you suggested. Note I just modified the previous commit rather than creating another one—this is a simple enough change I don't think it warrants 2 commits in the history.

Thank you! Yep, I agree.

@StarScape StarScape force-pushed the 1654-prevent-lookup-on-interactive-elements branch from 472280e to 455d21d Compare March 20, 2024 20:52
Copy link
Member

@birtles birtles left a comment

Choose a reason for hiding this comment

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

Perfect! Thank you!

@birtles birtles enabled auto-merge (rebase) March 21, 2024 06:46
@birtles birtles merged commit 1c596b3 into birchill:main Mar 21, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

We shouldn't lookup words when tapping a text box
2 participants