• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

worktile / slate-angular / 538f75c8-caf2-4d27-9bda-fd89bebf697f

31 Mar 2025 01:55AM CUT coverage: 46.776%. Remained the same
538f75c8-caf2-4d27-9bda-fd89bebf697f

push

circleci

pubuzhixing8
build: release 19.0.0

409 of 1075 branches covered (38.05%)

Branch coverage included in aggregate %.

1020 of 1980 relevant lines covered (51.52%)

43.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.57
/packages/src/custom-event/BeforeInputEventPlugin.ts
1
/**
2
 * Copyright (c) Facebook, Inc. and its affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7

8
import {
9
    TOP_BLUR,
10
    TOP_COMPOSITION_START,
11
    TOP_COMPOSITION_END,
12
    TOP_COMPOSITION_UPDATE,
13
    TOP_KEY_DOWN,
14
    TOP_KEY_PRESS,
15
    TOP_KEY_UP,
16
    TOP_MOUSE_DOWN,
17
    TOP_TEXT_INPUT,
18
    TOP_PASTE
19
} from './DOMTopLevelEventTypes';
20
import {
21
    getData as FallbackCompositionStateGetData,
22
    initialize as FallbackCompositionStateInitialize,
23
    reset as FallbackCompositionStateReset
24
} from './FallbackCompositionState';
25

26
const canUseDOM: boolean = !!(
1✔
27
    typeof window !== 'undefined' &&
3✔
28
    typeof window.document !== 'undefined' &&
29
    typeof window.document.createElement !== 'undefined'
30
);
31

32
const END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
1✔
33
const START_KEYCODE = 229;
1✔
34

35
const canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window;
1✔
36

37
let documentMode = null;
1✔
38
if (canUseDOM && 'documentMode' in document) {
1!
39
    documentMode = (document as any).documentMode;
×
40
}
41

42
// Webkit offers a very useful `textInput` event that can be used to
43
// directly represent `beforeInput`. The IE `textinput` event is not as
44
// useful, so we don't use it.
45
const canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode;
1✔
46

47
// In IE9+, we have access to composition events, but the data supplied
48
// by the native compositionend event may be incorrect. Japanese ideographic
49
// spaces, for instance (\u3000) are not recorded correctly.
50
const useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || (documentMode && documentMode > 8 && documentMode <= 11));
1!
51

52
const SPACEBAR_CODE = 32;
1✔
53
const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
1✔
54

55
// Events and their corresponding property names.
56
const eventTypes = {
1✔
57
    beforeInput: {
58
        phasedRegistrationNames: {
59
            bubbled: 'onBeforeInput',
60
            captured: 'onBeforeInputCapture'
61
        },
62
        dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE]
63
    }
64
};
65

66
// Track whether we've ever handled a keypress on the space key.
67
let hasSpaceKeypress = false;
1✔
68

69
/**
70
 * Return whether a native keypress event is assumed to be a command.
71
 * This is required because Firefox fires `keypress` events for key commands
72
 * (cut, copy, select-all, etc.) even though no character is inserted.
73
 */
74
function isKeypressCommand(nativeEvent) {
75
    return (
×
76
        (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
×
77
        // ctrlKey && altKey is equivalent to AltGr, and is not a command.
78
        !(nativeEvent.ctrlKey && nativeEvent.altKey)
×
79
    );
80
}
81

82
/**
83
 * Does our fallback mode think that this event is the end of composition?
84
 *
85
 */
86
function isFallbackCompositionEnd(topLevelType, nativeEvent) {
87
    switch (topLevelType) {
×
88
        case TOP_KEY_UP:
89
            // Command keys insert or clear IME input.
90
            return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
×
91
        case TOP_KEY_DOWN:
92
            // Expect IME keyCode on each keydown. If we get any other
93
            // code we must have exited earlier.
94
            return nativeEvent.keyCode !== START_KEYCODE;
×
95
        case TOP_KEY_PRESS:
96
        case TOP_MOUSE_DOWN:
97
        case TOP_BLUR:
98
            // Events are not possible without cancelling IME.
99
            return true;
×
100
        default:
101
            return false;
×
102
    }
103
}
104

105
/**
106
 * Google Input Tools provides composition data via a CustomEvent,
107
 * with the `data` property populated in the `detail` object. If this
108
 * is available on the event object, use it. If not, this is a plain
109
 * composition event and we have nothing special to extract.
110
 *
111
 */
112
function getDataFromCustomEvent(nativeEvent) {
113
    const detail = nativeEvent.detail;
×
114
    if (typeof detail === 'object' && 'data' in detail) {
×
115
        return detail.data;
×
116
    }
117
    return null;
×
118
}
119

120
/**
121
 * Check if a composition event was triggered by Korean IME.
122
 * Our fallback mode does not work well with IE's Korean IME,
123
 * so just use native composition events when Korean IME is used.
124
 * Although CompositionEvent.locale property is deprecated,
125
 * it is available in IE, where our fallback mode is enabled.
126
 *
127
 */
128
function isUsingKoreanIME(nativeEvent) {
129
    return nativeEvent.locale === 'ko';
×
130
}
131

132
// Track the current IME composition status, if any.
133
let isComposing = false;
1✔
134

135
function getNativeBeforeInputChars(topLevelType: any, nativeEvent) {
136
    switch (topLevelType) {
5!
137
        case TOP_COMPOSITION_END:
138
            return getDataFromCustomEvent(nativeEvent);
×
139
        case TOP_KEY_PRESS:
140
            /**
141
             * If native `textInput` events are available, our goal is to make
142
             * use of them. However, there is a special case: the spacebar key.
143
             * In Webkit, preventing default on a spacebar `textInput` event
144
             * cancels character insertion, but it *also* causes the browser
145
             * to fall back to its default spacebar behavior of scrolling the
146
             * page.
147
             *
148
             * Tracking at:
149
             * https://code.google.com/p/chromium/issues/detail?id=355103
150
             *
151
             * To avoid this issue, use the keypress event as if no `textInput`
152
             * event is available.
153
             */
154
            const which = nativeEvent.which;
×
155
            if (which !== SPACEBAR_CODE) {
×
156
                return null;
×
157
            }
158

159
            hasSpaceKeypress = true;
×
160
            return SPACEBAR_CHAR;
×
161

162
        case TOP_TEXT_INPUT:
163
            // Record the characters to be added to the DOM.
164
            const chars = nativeEvent.data;
×
165

166
            // If it's a spacebar character, assume that we have already handled
167
            // it at the keypress level and bail immediately. Android Chrome
168
            // doesn't give us keycodes, so we need to ignore it.
169
            if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
×
170
                return null;
×
171
            }
172

173
            return chars;
×
174

175
        default:
176
            // For other native event types, do nothing.
177
            return null;
5✔
178
    }
179
}
180

181
/**
182
 * For browsers that do not provide the `textInput` event, extract the
183
 * appropriate string to use for SyntheticInputEvent.
184
 *
185
 */
186
function getFallbackBeforeInputChars(topLevelType: any, nativeEvent) {
187
    // If we are currently composing (IME) and using a fallback to do so,
188
    // try to extract the composed characters from the fallback object.
189
    // If composition event is available, we extract a string only at
190
    // compositionevent, otherwise extract it at fallback events.
191
    if (isComposing) {
×
192
        if (topLevelType === TOP_COMPOSITION_END || (!canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent))) {
×
193
            const chars = FallbackCompositionStateGetData();
×
194
            FallbackCompositionStateReset();
×
195
            isComposing = false;
×
196
            return chars;
×
197
        }
198
        return null;
×
199
    }
200

201
    switch (topLevelType) {
×
202
        case TOP_PASTE:
203
            // If a paste event occurs after a keypress, throw out the input
204
            // chars. Paste events should not lead to BeforeInput events.
205
            return null;
×
206
        case TOP_KEY_PRESS:
207
            /**
208
             * As of v27, Firefox may fire keypress events even when no character
209
             * will be inserted. A few possibilities:
210
             *
211
             * - `which` is `0`. Arrow keys, Esc key, etc.
212
             *
213
             * - `which` is the pressed key code, but no char is available.
214
             *   Ex: 'AltGr + d` in Polish. There is no modified character for
215
             *   this key combination and no character is inserted into the
216
             *   document, but FF fires the keypress for char code `100` anyway.
217
             *   No `input` event will occur.
218
             *
219
             * - `which` is the pressed key code, but a command combination is
220
             *   being used. Ex: `Cmd+C`. No character is inserted, and no
221
             *   `input` event will occur.
222
             */
223
            if (!isKeypressCommand(nativeEvent)) {
×
224
                // IE fires the `keypress` event when a user types an emoji via
225
                // Touch keyboard of Windows.  In such a case, the `char` property
226
                // holds an emoji character like `\uD83D\uDE0A`.  Because its length
227
                // is 2, the property `which` does not represent an emoji correctly.
228
                // In such a case, we directly return the `char` property instead of
229
                // using `which`.
230
                if (nativeEvent.char && nativeEvent.char.length > 1) {
×
231
                    return nativeEvent.char;
×
232
                } else if (nativeEvent.which) {
×
233
                    return String.fromCharCode(nativeEvent.which);
×
234
                }
235
            }
236
            return null;
×
237
        case TOP_COMPOSITION_END:
238
            return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data;
×
239
        default:
240
            return null;
×
241
    }
242
}
243

244
/**
245
 * Extract a SyntheticInputEvent for `beforeInput`, based on either native
246
 * `textInput` or fallback behavior.
247
 *
248
 */
249
export function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
250
    let chars;
251

252
    if (canUseTextInputEvent) {
5!
253
        chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
5✔
254
    } else {
255
        chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
×
256
    }
257

258
    // If no characters are being inserted, no BeforeInput event should
259
    // be fired.
260
    if (!chars) {
5✔
261
        return null;
5✔
262
    }
263

264
    const beforeInputEvent = new BeforeInputEvent();
×
265
    beforeInputEvent.data = chars;
×
266
    beforeInputEvent.nativeEvent = nativeEvent;
×
267
    return beforeInputEvent;
×
268
}
269

270
/**
271
 * Create an `onBeforeInput` event to match
272
 * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
273
 *
274
 * This event plugin is based on the native `textInput` event
275
 * available in Chrome, Safari, Opera, and IE. This event fires after
276
 * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
277
 *
278
 * `beforeInput` is spec'd but not implemented in any browsers, and
279
 * the `input` event does not provide any useful information about what has
280
 * actually been added, contrary to the spec. Thus, `textInput` is the best
281
 * available event to identify the characters that have actually been inserted
282
 * into the target node.
283
 *
284
 * This plugin is also responsible for emitting `composition` events, thus
285
 * allowing us to share composition fallback code for both `beforeInput` and
286
 * `composition` event types.
287
 */
288
const BeforeInputEventPlugin = {
1✔
289
    extractEvents: (topLevelType, targetInst, nativeEvent, nativeEventTarget) => {
290
        return extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget);
×
291
    }
292
};
293

294
export class BeforeInputEvent {
295
    data: string;
296
    nativeEvent: Event;
297
}
298
export default BeforeInputEventPlugin;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc