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

worktile / slate-angular / 543eb906-9e4d-47ae-b0a3-bf4f680c78ba

pending completion
543eb906-9e4d-47ae-b0a3-bf4f680c78ba

push

circleci

Maple13
build: optimizing angular 15 upgrade

267 of 876 branches covered (30.48%)

Branch coverage included in aggregate %.

682 of 1485 relevant lines covered (45.93%)

30.73 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

174
            return chars;
×
175

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

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

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

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

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

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

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

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

295
export class BeforeInputEvent {
296
    data: string;
297
    nativeEvent: Event;
298
}
299
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