ldx-widgets
Version:
widgets
238 lines (197 loc) • 6 kB
text/coffeescript
React = require 'react'
require 'classlist-polyfill'
ReactDatepicker = React.createFactory(require 'react-datepicker')
SelectInput = React.createFactory(require './select_input_2')
moment = require 'moment'
{div, span, input} = React.DOM
DatePicker = React.createClass
displayName: 'DatePicker'
propTypes:
placeholderText: React.PropTypes.oneOfType [
React.PropTypes.string
React.PropTypes.number
]
dateFormat: React.PropTypes.string
className: React.PropTypes.string
minDate: React.PropTypes.object
maxDate: React.PropTypes.object
onChange: React.PropTypes.func.isRequired
tabIndex: React.PropTypes.number
selected: React.PropTypes.oneOfType [
React.PropTypes.string
React.PropTypes.object
]
getDefaultProps: ->
placeholderText: 'Select a date'
dateFormat: 'MM/DD/YYYY'
className: null
includeTime: no # yes to include time selection
returnDateString: null # pass a date format string to get that format from the getValue method
getInitialState: ->
{selected} = @props
@getDateState selected
getDateState: (selected = moment()) ->
{
selected: moment(selected.format('YYYYMMDD'), 'YYYYMMDD')
inputDate: ''
hours: selected.format('h')
minutes: selected.format('mm')
ampm: selected.format('a')
}
componentWillMount: ->
{includeTime} = @props
return unless includeTime
@hoursOptions = [{
label: '12'
value: '12'
}]
@hoursOptions.push(
label: hour
value: hour
) for hour in [1..11]
@minuteOptions = []
for minute in [0..59]
if minute < 10 then minute = "0#{minute}"
@minuteOptions.push(
label: minute
value: minute
)
@ampmOptions = [
{
label: 'am'
value: 'am'
}
{
label: 'pm'
value: 'pm'
}
]
componentWillReceiveProps: (nextProps) ->
{selected} = @props
if selected?.format('YYYYMMDDhmma') isnt nextProps.selected?.format('YYYYMMDDhmma')
@setState(@getDateState(nextProps.selected))
render: ->
{placeholderText, className, dateFormat, minDate, maxDate, onChange, tabIndex, includeTime} = @props
{selected, inputDate, hours, minutes, ampm} = @state
if selected
# Allow the value to be set from either a Moment object or a string
switch typeof selected
when 'string'
value = moment(selected).format(dateFormat)
selected = moment(selected, dateFormat)
when 'object'
value = selected.format(dateFormat)
mainClass = 'datepicker-wrapper'
mainClass += ' include-time' if includeTime
mainClass += " #{className}" if className?
div {
className: mainClass
}, [
input {
key: 'input'
ref: 'input'
type: 'text'
placeholder: placeholderText
value: inputDate or value
onChange: @handleChange
onKeyDown: @handleKeyDown
onBlur: @handleBlur
onFocus: @handleFocus
tabIndex: tabIndex
}
ReactDatepicker {
key: 'datepicker'
ref: 'datepicker'
selected: selected
onChange: @handleDateChange
dateFormat: dateFormat
minDate: minDate
maxDate: maxDate
}
div {
key: 'time'
className: 'time-wrapper'
}, [
SelectInput {
key: 'hours'
ref: 'hours'
value: hours
className: 'time-sel'
options: @hoursOptions
onChange: @handleChange
}
span {key: 'colon', className: 'colon'}, ':'
SelectInput {
key: 'minutes'
ref: 'minutes'
value: minutes
className: 'time-sel'
options: @minuteOptions
onChange: @handleChange
}
SelectInput {
key: 'ampm'
ref: 'ampm'
value: ampm
className: 'time-sel ampm'
options: @ampmOptions
onChange: @handleChange
}
] if includeTime
]
hideCalendar: ->
# Hide the datepicker popup
@refs.datepicker.setOpen no
handleFocus: ->
# Show the datepicker popup
@refs.datepicker.handleFocus()
handleChange: (cb, blur) ->
{includeTime, onChange} = @props
setData =
inputDate: @refs.input.value
if includeTime
setData.hours = @refs.hours.getValue()
setData.minutes = @refs.minutes.getValue()
setData.ampm = @refs.ampm.getValue()
@setState setData, ->
cb?(null, blur)
onChange?()
handleBlur: ->
@handleChange(@handleKeyDown, true)
handleKeyDown: (e, blur) ->
{value} = @refs.input
{minDate, maxDate, dateFormat} = @props
inputDate = moment(value, dateFormat)
unixInputDate = inputDate.unix()
state = {}
# Validate the value and enter key was pressed
if inputDate.isValid() and (e?.key in ['Enter', 'Tab'] or not e?)
# Check to make sure the date is in the valid range
if minDate? and unixInputDate <= minDate.unix()
inputAdjusted = true
inputDate = minDate
if maxDate? and unixInputDate >= maxDate.unix()
inputAdjusted = true
inputDate = maxDate
if inputAdjusted then state.inputDate = inputDate.format(dateFormat)
state.selected = inputDate
@setState state
, ->
@props.onChange?()
@hideCalendar() unless blur
handleDateChange: (date) ->
@setState
selected: date
inputDate: ''
, ->
@props.onChange?()
getValue: ->
{returnDateString, includeTime} = @props
{selected} = @state
if includeTime
{hours, minutes, ampm} = @state
dateString = selected.format 'YYYYMMDD'
dateString += "#{hours}:#{minutes}#{ampm}"
selected = moment(dateString, 'YYYYMMDDh:mma')
if returnDateString? then selected.format(returnDateString) else selected
module.exports = DatePicker