forked from react/react
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathFormActionEventPlugin.js
More file actions
124 lines (113 loc) · 3.85 KB
/
Copy pathFormActionEventPlugin.js
File metadata and controls
124 lines (113 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import type {AnyNativeEvent} from '../PluginModuleType';
import type {DOMEventName} from '../DOMEventNames';
import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {getFiberCurrentPropsFromNode} from '../../client/ReactDOMComponentTree';
import {startHostTransition} from 'react-reconciler/src/ReactFiberReconciler';
import {SyntheticEvent} from '../SyntheticEvent';
/**
* This plugin invokes action functions on forms, inputs and buttons if
* the form doesn't prevent default.
*/
function extractEvents(
dispatchQueue: DispatchQueue,
domEventName: DOMEventName,
maybeTargetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
) {
if (domEventName !== 'submit') {
return;
}
if (!maybeTargetInst || maybeTargetInst.stateNode !== nativeEventTarget) {
// If we're inside a parent root that itself is a parent of this root, then
// its deepest target won't be the actual form that's being submitted.
return;
}
const formInst = maybeTargetInst;
const form: HTMLFormElement = (nativeEventTarget: any);
let action = (getFiberCurrentPropsFromNode(form): any).action;
let submitter: null | HTMLInputElement | HTMLButtonElement =
(nativeEvent: any).submitter;
let submitterAction;
if (submitter) {
const submitterProps = getFiberCurrentPropsFromNode(submitter);
submitterAction = submitterProps
? (submitterProps: any).formAction
: submitter.getAttribute('formAction');
if (submitterAction != null) {
// The submitter overrides the form action.
action = submitterAction;
// If the action is a function, we don't want to pass its name
// value to the FormData since it's controlled by the server.
submitter = null;
}
}
if (typeof action !== 'function') {
return;
}
const event = new SyntheticEvent(
'action',
'action',
null,
nativeEvent,
nativeEventTarget,
);
function submitForm() {
if (nativeEvent.defaultPrevented) {
// We let earlier events to prevent the action from submitting.
return;
}
// Prevent native navigation.
event.preventDefault();
let formData;
if (submitter) {
// The submitter's value should be included in the FormData.
// It should be in the document order in the form.
// Since the FormData constructor invokes the formdata event it also
// needs to be available before that happens so after construction it's too
// late. We use a temporary fake node for the duration of this event.
// TODO: FormData takes a second argument that it's the submitter but this
// is fairly new so not all browsers support it yet. Switch to that technique
// when available.
const temp = submitter.ownerDocument.createElement('input');
temp.name = submitter.name;
temp.value = submitter.value;
(submitter.parentNode: any).insertBefore(temp, submitter);
formData = new FormData(form);
(temp.parentNode: any).removeChild(temp);
} else {
formData = new FormData(form);
}
startHostTransition(formInst, action, formData);
}
dispatchQueue.push({
event,
listeners: [
{
instance: null,
listener: submitForm,
currentTarget: form,
},
],
});
}
export {extractEvents};
export function dispatchReplayedFormAction(
formInst: Fiber,
action: FormData => void | Promise<void>,
formData: FormData,
): void {
startHostTransition(formInst, action, formData);
}