blob: 81dec8019473bf811640e211a767b6c1096bff49 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5
6// Prevent triggering input change handlers on key events that don't
7// edit forms.
8export const NON_EDITING_KEY_EVENTS = new Set(['Enter', 'Tab', 'Escape',
9 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown']);
10const INPUT_TYPES_WITHOUT_TEXT_INPUT = [
11 'checkbox',
12 'radio',
13 'file',
14 'submit',
15 'button',
16 'image',
17];
18
19// TODO: Add a method to watch for property changes in one of a subset of
20// element properties.
21// Via: https://crrev.com/c/infra/infra/+/1762911/7/appengine/monorail/static_src/elements/help/mr-cue/mr-cue.js
22
23/**
24 * Checks if a keyboard event should be disabled when the user is typing.
25 *
26 * @param {HTMLElement} element is a dom node to run checks against.
27 * @return {boolean} Whether the dom node is an element that accepts key input.
28 */
29export function isTextInput(element) {
30 const tagName = element.tagName && element.tagName.toUpperCase();
31 if (tagName === 'INPUT') {
32 const type = element.type.toLowerCase();
33 if (INPUT_TYPES_WITHOUT_TEXT_INPUT.includes(type)) {
34 return false;
35 }
36 return true;
37 }
38 return tagName === 'SELECT' || tagName === 'TEXTAREA' ||
39 element.isContentEditable;
40}
41
42/**
43 * Helper to find the EventTarget that an Event originated from, even if that
44 * EventTarget is buried until multiple layers of ShadowDOM.
45 *
46 * @param {Event} event
47 * @return {EventTarget} The DOM node that the event came from. For example,
48 * if the input was a keypress, this might be the input element the user was
49 * typing into.
50 */
51export function findDeepEventTarget(event) {
52 /**
53 * Event.target finds the element the event came from, but only
54 * finds events that come from the highest ShadowDOM level. For
55 * example, an Event listener attached to "window" will have all
56 * Events originating from the SPA set to a target of <mr-app>.
57 */
58 const path = event.composedPath();
59 return path ? path[0] : event.target;
60}