Skip to content

Commit 8bba91c

Browse files
authored
Merge pull request #1 from andreybeloboka/implement-mask-support
Implement mask support
2 parents 2a83208 + ccb806b commit 8bba91c

File tree

9 files changed

+2175
-1740
lines changed

9 files changed

+2175
-1740
lines changed

DateTime.js

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var assign = require('object-assign'),
55
createClass = require('create-react-class'),
66
moment = require('moment'),
77
React = require('react'),
8+
defaultMaskComponent = require('react-bootstrap-maskedinput').default,
89
CalendarContainer = require('./src/CalendarContainer'),
910
onClickOutside = require('react-onclickoutside').default
1011
;
@@ -33,18 +34,29 @@ var Datetime = createClass({
3334
utc: TYPES.bool,
3435
displayTimeZone: TYPES.string,
3536
input: TYPES.bool,
37+
mask: TYPES.object,
3638
// dateFormat: TYPES.string | TYPES.bool,
3739
// timeFormat: TYPES.string | TYPES.bool,
3840
inputProps: TYPES.object,
41+
disableOnBlurInputOnOpen: TYPES.bool,
3942
timeConstraints: TYPES.object,
4043
viewMode: TYPES.oneOf([viewModes.YEARS, viewModes.MONTHS, viewModes.DAYS, viewModes.TIME]),
4144
isValidDate: TYPES.func,
45+
isValidUnix: TYPES.func,
4246
open: TYPES.bool,
4347
strictParsing: TYPES.bool,
4448
closeOnSelect: TYPES.bool,
4549
closeOnTab: TYPES.bool
4650
},
4751

52+
isUnfilled: function(value) {
53+
return typeof value === 'string' && value.split('').find(function( char ) {
54+
return char === '_';
55+
});
56+
},
57+
isWithMask: function() {
58+
return this.props.mask && this.props.mask.maskedProps;
59+
},
4860
getInitialState: function() {
4961
this.checkTZ( this.props );
5062

@@ -59,6 +71,39 @@ var Datetime = createClass({
5971
return state;
6072
},
6173

74+
renderPagination: function(props) {
75+
var type = props.type, renderRange = props.renderRange,
76+
params = props.params || {};
77+
78+
var isValidUnix = this.props.isValidUnix;
79+
var viewDate = params.viewDate || this.state.viewDate;
80+
var validatePagination = this.props.validatePagination;
81+
var addValue = {}, subtractValue = {};
82+
83+
Object.defineProperty(addValue, type, {
84+
value: viewDate[type](),
85+
enumerable: true,
86+
});
87+
Object.defineProperty(subtractValue, type, {
88+
value: viewDate[type](),
89+
enumerable: true,
90+
});
91+
92+
var nextDatesTab = viewDate.clone().startOf(type).add(params.add || renderRange, type);
93+
var prevDatesTab = viewDate.clone().endOf(type).startOf('days').subtract(params.subtract || renderRange, type);
94+
var nextDate = true;
95+
var prevDate = true;
96+
97+
if ((typeof isValidUnix === 'function') && validatePagination) {
98+
nextDate = isValidUnix(nextDatesTab);
99+
prevDate = isValidUnix(prevDatesTab);
100+
}
101+
return [
102+
React.createElement('th', { key: 'prev', className: 'rdtPrev' + (prevDate ? '' : ' disabled'), onClick: prevDate ? this.subtractTime( renderRange, type ) : null }, React.createElement('span', {}, '‹' )),
103+
React.createElement('th', { key: 'next', className: 'rdtNext' + (nextDate ? '' : ' disabled'), onClick: nextDate ? this.addTime( renderRange, type ) : null }, React.createElement('span', {}, '›' ))
104+
];
105+
},
106+
62107
parseDate: function (date, formats) {
63108
var parsedDate;
64109

@@ -76,11 +121,19 @@ var Datetime = createClass({
76121
getStateFromProps: function( props ) {
77122
var formats = this.getFormats( props ),
78123
date = props.value || props.defaultValue,
124+
isValidUnix = props.isValidUnix,
125+
validatePagination = props.validatePagination,
79126
selectedDate, viewDate, updateOn, inputValue
80127
;
81128

82129
selectedDate = this.parseDate(date, formats);
83130

131+
if ((typeof isValidUnix === 'function') && validatePagination) {
132+
if (selectedDate && !isValidUnix(selectedDate)) {
133+
selectedDate = null;
134+
}
135+
}
136+
84137
viewDate = this.parseDate(props.viewDate, formats);
85138

86139
viewDate = selectedDate ?
@@ -152,7 +205,13 @@ var Datetime = createClass({
152205

153206
if ( nextProps.value !== this.props.value ||
154207
formats.datetime !== this.getFormats( this.props ).datetime ) {
155-
updatedState = this.getStateFromProps( nextProps );
208+
if (this.isWithMask()) {
209+
if (!this.isUnfilled()) {
210+
updatedState = this.getStateFromProps( nextProps );
211+
}
212+
} else {
213+
updatedState = this.getStateFromProps( nextProps );
214+
}
156215
}
157216

158217
if ( updatedState.open === undefined ) {
@@ -216,20 +275,32 @@ var Datetime = createClass({
216275
},
217276

218277
onInputChange: function( e ) {
219-
var value = e.target === null ? e : e.target.value,
220-
localMoment = this.localMoment( value, this.state.inputFormat ),
221-
update = { inputValue: value }
222-
;
278+
var value = e.target === null ? e : e.target.value;
279+
var withMask = this.isWithMask();
280+
281+
if ( withMask ) {
282+
// to be determined if it needed or not
283+
// if (!value) {
284+
// return;
285+
// }
286+
if ( this.isUnfilled(value) ) {
287+
return this.props.onChange(value);
288+
}
289+
}
223290

224-
if ( localMoment.isValid() && !this.props.value ) {
291+
var localMoment = this.localMoment( value, this.state.inputFormat ),
292+
update = { inputValue: value };
293+
294+
if ( localMoment.isValid() && !this.props.value) {
225295
update.selectedDate = localMoment;
226296
update.viewDate = localMoment.clone().startOf('month');
227297
} else {
228298
update.selectedDate = null;
229299
}
230300

231301
return this.setState( update, function() {
232-
return this.props.onChange( localMoment.isValid() ? localMoment : this.state.inputValue );
302+
var editedValue = withMask ? value : this.state.inputValue;
303+
return this.props.onChange(localMoment.isValid() ? localMoment : editedValue );
233304
});
234305
},
235306

@@ -239,6 +310,16 @@ var Datetime = createClass({
239310
}
240311
},
241312

313+
onInputBlur: function ( ) {
314+
var me = this;
315+
return function( e ) {
316+
if ( me.props.disableInputOnBlurOnOpen && me.state.open) {
317+
return;
318+
}
319+
return typeof me.props.inputProps.onBlur === 'function' && me.props.inputProps.onBlur( e );
320+
};
321+
},
322+
242323
showView: function( view ) {
243324
var me = this;
244325
return function() {
@@ -369,6 +450,7 @@ var Datetime = createClass({
369450

370451
openCalendar: function( e ) {
371452
if ( !this.state.open ) {
453+
e.persist();
372454
this.setState({ open: true }, function() {
373455
this.props.onFocus( e );
374456
});
@@ -416,9 +498,9 @@ var Datetime = createClass({
416498
},
417499

418500
componentProps: {
419-
fromProps: ['value', 'isValidDate', 'renderDay', 'renderMonth', 'renderYear', 'timeConstraints'],
501+
fromProps: ['value', 'isValidDate', 'isValidUnix', 'renderDay', 'renderMonth', 'renderYear', 'timeConstraints', 'validatePagination'],
420502
fromState: ['viewDate', 'selectedDate', 'updateOn'],
421-
fromThis: ['setDate', 'setTime', 'showView', 'addTime', 'subtractTime', 'updateSelectedDate', 'localMoment', 'handleClickOutside']
503+
fromThis: ['setDate', 'setTime', 'showView', 'addTime', 'subtractTime', 'updateSelectedDate', 'localMoment', 'handleClickOutside', 'renderPagination']
422504
},
423505

424506
getComponentProps: function() {
@@ -483,6 +565,14 @@ var Datetime = createClass({
483565

484566
if ( this.props.renderInput ) {
485567
children = [ React.createElement('div', { key: 'i' }, this.props.renderInput( finalInputProps, this.openCalendar, this.closeCalendar )) ];
568+
} else if ( this.isWithMask() ) {
569+
children = [
570+
React.createElement( this.props.mask.maskComponent || defaultMaskComponent, assign(
571+
this.props.mask.maskedProps,
572+
finalInputProps,
573+
{ key: 'i', onBlur: this.onInputBlur() }
574+
)
575+
)];
486576
} else {
487577
children = [ React.createElement('input', assign({ key: 'i' }, finalInputProps ))];
488578
}

css/react-datetime.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@
107107
vertical-align: top;
108108
}
109109

110+
.rdtPicker th.rdtNext.disabled,
111+
.rdtPicker th.rdtPrev.disabled {
112+
color: #777;
113+
cursor: not-allowed;
114+
background: none;
115+
border-color: #ddd;
116+
opacity: 0.5;
117+
}
118+
110119
.rdtPrev span,
111120
.rdtNext span {
112121
display: block;

0 commit comments

Comments
 (0)