11import fieldHolder from 'components/FieldHolder/FieldHolder' ;
2- import moment from 'moment' ;
2+ import momentLib from 'moment' ;
33import modernizr from 'modernizr' ;
44import i18n from 'i18n' ;
55import PropTypes from 'prop-types' ;
6- import { Component as TextField } from '../TextField/TextField ' ;
6+ import { getInputProps as getInputFieldProps , render } from '../InputField/InputField ' ;
77
88const localFormat = 'L' ;
99
10- class DateField extends TextField {
11- render ( ) {
12- return super . render ( ) ;
13- }
14-
15- moment ( ...args ) {
16- moment . locale ( this . getLang ( ) ) ;
17- return moment ( ...args ) ;
18- }
19-
20- getLang ( ) {
21- const lang = this . asHTML5 ( ) ? this . props . isoLang : this . props . lang ;
22-
23- return lang || moment ( ) . locale ( ) ;
24- }
25-
26- /**
27- * If this field is to be rendered as a HTML5 date input
28- *
29- * @return {Boolean }
30- */
31- asHTML5 ( ) {
32- return this . props . data . html5 && this . hasNativeSupport ( ) ;
33- }
10+ /**
11+ * Check if this field has native html5 date support
12+ *
13+ * @return {Boolean }
14+ */
15+ const hasNativeSupport = ( props ) => props . modernizr . inputtypes . date ;
16+
17+ /**
18+ * If this field is to be rendered as a HTML5 date input
19+ *
20+ * @return {Boolean }
21+ */
22+ const asHTML5 = ( props , hasNativeSupportFn = hasNativeSupport ) => (
23+ props . data . html5 && hasNativeSupportFn ( props )
24+ ) ;
25+
26+ const getLang = ( props , hasNativeSupportFn = hasNativeSupport ) => {
27+ const lang = asHTML5 ( props , hasNativeSupportFn ) ? props . isoLang : props . lang ;
28+ return lang || momentLib ( ) . locale ( ) ;
29+ } ;
3430
35- /**
36- * Check if this field has native html5 date support
37- *
38- * @return {Boolean }
39- */
40- hasNativeSupport ( ) {
41- return this . props . modernizr . inputtypes . date ;
42- }
31+ const moment = ( props , hasNativeSupportFn = hasNativeSupport , ...momentArgs ) => {
32+ momentLib . locale ( getLang ( props , hasNativeSupportFn ) ) ;
33+ return momentLib ( ...momentArgs ) ;
34+ } ;
4335
44- getInputProps ( ) {
45- const placeholder = i18n . inject (
46- i18n . _t ( 'Admin.FormatExample' , 'Example: {format}' ) ,
47- { format : this . moment ( ) . endOf ( 'month' ) . format ( localFormat ) }
48- ) ;
49-
50- const value = this . asHTML5 ( )
51- ? this . props . value
52- : this . getLocalisedValue ( ) ;
53- const type = this . asHTML5 ( ) ? 'date' : 'text' ;
54- const props = {
55- ...super . getInputProps ( ) ,
56- type,
57- // `parse()` of redux-form `Field` should be used for parsing the
58- // localised input value to iso format to pass to redux store but `Field`
59- // is not accessible in this context.
60- value,
61- placeholder,
62- } ;
63-
64- return props ;
65- }
36+ const triggerChange = ( props , event , value ) => {
37+ props . onChange ( event , { id : props . id , value } ) ;
38+ } ;
6639
67- getLocalisedValue ( ) {
68- return this . convertToLocalised ( this . props . value ) ;
69- }
40+ const convertToIso = ( props , localDate ) => {
41+ let isoDate = '' ;
7042
71- isMultiline ( ) {
72- return false ;
43+ if ( localDate ) {
44+ // Input value can be in local format 'L' or ISO format
45+ const dateObject = moment ( props , hasNativeSupport , localDate , [ localFormat , 'YYYY-MM-DD' ] ) ;
46+ if ( dateObject . isValid ( ) ) {
47+ isoDate = dateObject . format ( 'YYYY-MM-DD' ) ;
48+ }
7349 }
7450
75- /**
76- * Handles changes to the text field's value.
77- *
78- * @param {Event } event
79- */
80- handleChange ( event ) {
81- const enteredValue = event . target . value ;
82- let isoValue = '' ;
83-
84- // When browser support input=date the date value is already in iso format and html5 is enabled
85- if ( this . asHTML5 ( ) ) {
86- isoValue = enteredValue ;
87- } else {
88- isoValue = this . convertToIso ( enteredValue ) ;
89- }
51+ return isoDate ;
52+ } ;
9053
91- if ( typeof this . props . onChange === 'function' ) {
92- this . triggerChange ( event , isoValue ) ;
54+ const convertToLocalised = ( props , isoDate ) => {
55+ let localDate = '' ;
56+ if ( isoDate ) {
57+ const dateObject = moment ( props , hasNativeSupport , isoDate ) ;
58+ if ( dateObject . isValid ( ) ) {
59+ localDate = dateObject . format ( localFormat ) ;
9360 }
9461 }
62+ return localDate ;
63+ } ;
9564
96- triggerChange ( event , value ) {
97- this . props . onChange ( event , { id : this . props . id , value } ) ;
65+ const getLocalisedValue = ( props , convertToLocalisedFn = convertToLocalised ) => (
66+ convertToLocalisedFn ( props , props . value )
67+ ) ;
68+
69+ const isMultiline = ( ) => false ;
70+
71+ /**
72+ * Handles changes to the text field's value.
73+ *
74+ * @param {Event } event
75+ */
76+ const handleChange = (
77+ props ,
78+ event ,
79+ asHTML5Fn = asHTML5 ,
80+ convertToIsoFn = convertToIso ,
81+ triggerChangeFn = triggerChange
82+ ) => {
83+ const enteredValue = event . target . value ;
84+ let isoValue = '' ;
85+
86+ // When browser support input=date the date value is already in iso format and html5 is enabled
87+ if ( asHTML5Fn ( props ) ) {
88+ isoValue = enteredValue ;
89+ } else {
90+ isoValue = convertToIsoFn ( props , enteredValue ) ;
9891 }
9992
100- convertToIso ( localDate ) {
101- let isoDate = '' ;
102-
103- if ( localDate ) {
104- // Input value can be in local format 'L' or ISO format
105- const dateObject = this . moment ( localDate , [ localFormat , 'YYYY-MM-DD' ] ) ;
106- if ( dateObject . isValid ( ) ) {
107- isoDate = dateObject . format ( 'YYYY-MM-DD' ) ;
108- }
109- }
110-
111- return isoDate ;
93+ if ( typeof props . onChange === 'function' ) {
94+ triggerChangeFn ( props , event , isoValue ) ;
11295 }
96+ } ;
11397
114- convertToLocalised ( isoDate ) {
115- let localDate = '' ;
116- if ( isoDate ) {
117- const dateObject = this . moment ( isoDate ) ;
118- if ( dateObject . isValid ( ) ) {
119- localDate = dateObject . format ( localFormat ) ;
120- }
121- }
122- return localDate ;
123- }
124- }
98+ const getInputProps = ( props , asHTML5Fn = asHTML5 , getLocalisedValueFn = getLocalisedValue ) => {
99+ const resolvedHandleChange = ( nextProps , event ) => (
100+ handleChange ( nextProps , event , asHTML5Fn , convertToIso , triggerChange )
101+ ) ;
102+ const placeholder = i18n . inject (
103+ i18n . _t ( 'Admin.FormatExample' , 'Example: {format}' ) ,
104+ { format : moment ( props , hasNativeSupport ) . endOf ( 'month' ) . format ( localFormat ) }
105+ ) ;
106+
107+ const value = asHTML5Fn ( props )
108+ ? props . value
109+ : getLocalisedValueFn ( props ) ;
110+ const type = asHTML5Fn ( props ) ? 'date' : 'text' ;
111+ const inputProps = getInputFieldProps ( props , resolvedHandleChange ) ;
112+ return {
113+ ...inputProps ,
114+ type,
115+ // `parse()` of redux-form `Field` should be used for parsing the
116+ // localised input value to iso format to pass to redux store but `Field`
117+ // is not accessible in this context.
118+ value,
119+ placeholder,
120+ } ;
121+ } ;
122+
123+ const DateField = ( _props ) => {
124+ const defaultProps = {
125+ attributes : { } ,
126+ className : '' ,
127+ data : { } ,
128+ extraClass : '' ,
129+ modernizr,
130+ type : 'text' ,
131+ value : '' ,
132+ } ;
133+
134+ const props = {
135+ ...defaultProps ,
136+ ..._props ,
137+ } ;
138+
139+ const inputProps = getInputProps ( props ) ;
140+ return render ( props , inputProps ) ;
141+ } ;
125142
126143DateField . propTypes = {
127144 lang : PropTypes . string ,
@@ -132,11 +149,21 @@ DateField.propTypes = {
132149 } ) ,
133150} ;
134151
135- DateField . defaultProps = {
136- modernizr,
137- data : { } ,
138- } ;
139-
140152export { DateField as Component } ;
141153
142154export default fieldHolder ( DateField ) ;
155+
156+ // Exported for use other form fields which can override or reuse this logic
157+ export {
158+ getInputProps ,
159+ isMultiline ,
160+ hasNativeSupport ,
161+ asHTML5 ,
162+ getLang ,
163+ triggerChange ,
164+ convertToLocalised ,
165+ convertToIso ,
166+ moment ,
167+ getLocalisedValue ,
168+ handleChange ,
169+ } ;
0 commit comments