-
Notifications
You must be signed in to change notification settings - Fork 657
/
Copy pathinput_hoc.jsx
124 lines (108 loc) · 4.16 KB
/
input_hoc.jsx
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
import React from 'react';
import { connect } from 'react-redux';
import createReactClass from 'create-react-class';
import uuid from 'uuid';
import { has } from 'lodash-es';
import { addValidation, setValid, setInvalid } from '../../actions/validation_actions';
// This needs to be implemented as a mixin for state reasons.
// If there's a good way for high-order components to set state on
// children like this then let's use it.
const getValidation = (key, validations) => {
if (validations[key] && validations[key].changed) {
return validations[key].valid;
}
return true;
};
const mapStateToProps = state => ({
validations: state.validations.validations,
errorQueue: state.validations.errorQueue
});
const mapDispatchToProps = {
addValidation,
setValid,
setInvalid,
};
const InputHOC = (Component) => {
const validatingComponent = createReactClass({
displayName: `Input${Component.displayName}`,
// value passed is HOC's state value
getInitialState() {
return { value: this.props.value };
},
shouldComponentUpdate(nextProps, nextState) {
if (this.state.value === nextState.value
&& this.state.id === nextState.id
&& this.state.invalid === nextState.invalid
&& this.props.editable === nextProps.editable
&& nextProps.rerenderHoc !== true
&& this.props._value === nextProps._value) {
return false;
}
return true;
},
// onChange will now be handled by the HOC component
onChange(e, originalEvent) {
let value;
// Workaround to ensure that we don't render checkboxes with a string value instead of boolean
if (Component.displayName === 'Checkbox') {
value = /true/.test(e.target.value);
} else {
value = e.target.value;
}
if (value !== this.state.value) {
return this.setState({ value }, function () {
this.props.onChange(this.props.value_key, value, originalEvent);
return this.validate();
});
}
},
UNSAFE_componentWillReceiveProps(props) {
const valid = getValidation(props.value_key, props.validations);
return this.setState(
{
value: props.value,
invalid: !valid,
id: props.id || this.state.id || uuid.v4() // create a UUID if no id prop
}, function () {
if (valid && this.props.required && (!props.value || props.value === null || props.value.length === 0)) {
return this.props.addValidation(this.props.value_key, I18n.t('application.field_required'));
}
}
);
},
validate() {
if (this.props.required || this.props.validation) {
const filled = (this.state.value && this.state.value.length > 0);
let charcheck;
if (this.props.validation instanceof RegExp) {
charcheck = (new RegExp(this.props.validation)).test(this.state.value);
} else if (typeof (this.props.validation) === 'function') {
charcheck = this.props.validation(this.state.value);
}
if (this.props.required && !filled) {
if (has(this.props, 'disableSave')) {
this.props.disableSave(true);
}
return this.props.setInvalid(this.props.value_key, I18n.t('application.field_required'));
} else if (this.props.validation && !charcheck) {
const invalidMessage = this.props.invalidMessage || I18n.t('application.field_invalid_characters');
return this.props.setInvalid(this.props.value_key, invalidMessage);
}
return this.props.setValid(this.props.value_key);
}
},
focus() {
if (this.props.onFocus) { return this.props.onFocus(); }
},
blur() {
if (this.props.onBlur) { return this.props.onBlur(); }
},
render() {
// Don't allow uneccessary props to pass through
const { value, validation, onChange, invalidMessage, required, ...passThroughProps } = this.props;
return (<Component {...passThroughProps} {...this.state} onChange={this.onChange} onFocus={this.focus} onBlur={this.blur} />);
}
});
return connect(mapStateToProps, mapDispatchToProps)(validatingComponent);
};
export default InputHOC;