Skip to content

Instantly share code, notes, and snippets.

@jandudulski
Created June 14, 2011 09:48
Show Gist options
  • Save jandudulski/1024600 to your computer and use it in GitHub Desktop.
Save jandudulski/1024600 to your computer and use it in GitHub Desktop.
RangeDatepicker
<form id="search" data-range="1" data-offset="5">
<div class="wrapper">
<label>
First date:
<input type="text" value="" class="calendar first" readonly="readonly" />
</label>
<input type="hidden" value="" name="day" data-type="day" />
<input type="hidden" value="" name="month_1" data-type="month" />
</div>
<div class="wrapper">
<label>
Second date:
<input type="text" value="" class="calendar second" readonly="readonly" />
</label>
<input type="hidden" value="" name="retDay" data-type="day" />
<input type="hidden" value="" name="month_2" data-type="month" />
</div>
</form>
new RangeDatepicker(
'#search',
dateFormat: 'dd.mm.yy',
maxDate: '+1y',
numberOfMonths: 2
)
# My first coffee script, so any critic comments are welcome :)
#
# I needed wrapper for jQuery UI Datepicker
# that would handle range between two dates,
# alternative fields for specific date formats
# and triggering secondary input when first date selected
class RangeDatepicker
_form = undefined
_minFirstDate = undefined
_minSecondDate = undefined
_firstInput = undefined
_secondInput = undefined
_firstDate = undefined
_secondDate = undefined
getRange = ->
parseInt(_form.attr('data-range'), 10)
getOffset = ->
parseInt(_form.attr('data-offset'), 10)
setMinDate = (input, inst) ->
minDate: if inst.input.hasClass('first') then _minFirstDate else _minSecondDate
setAltField = (input, date, type) ->
switch type
when 'day' then input.val(date.getDate())
when 'month' then input.val(date.getMonth() + 1)
when 'year' then input.val(date.getFullYear())
when 'month-year' then input.val("#{if date.getMonth() < 9 then '0' else ''}#{date.getMonth() + 1}-#{date.getFullYear()}")
setAltFields = (input, date) ->
for elem in input.parents('.wrapper:first').children('input[data-type]')
$elem = $(elem)
setAltField($elem, date, $elem.attr('data-type'))
onSelect = (dateText, inst) ->
d = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)
# which input?
if (inst.input.hasClass('first'))
# save date
_firstDate = d
# second minimal date = firstDate + range
_minSecondDate = new Date(_firstDate.getFullYear(), _firstDate.getMonth(), _firstDate.getDate() + getRange())
# check if current second date is before min
if (_minSecondDate > _secondDate)
# save date and set it
_secondDate = _minSecondDate
_secondInput.datepicker('setDate', _secondDate)
setAltFields(_secondInput, _secondDate)
# set focus on second input
# timeout for strange issue with closing
setTimeout((-> _secondInput.focus()), 0)
else
# save date
_secondDate = d
# don't forget about alterantive fields
setAltFields(inst.input, d)
init: (_, input) =>
$input = $(input)
# init datepicker for calendar inputs
$input.datepicker @options
# set default dates
$input.datepicker('setDate', (if $input.hasClass('first') then _minFirstDate else _minSecondDate))
if $input.hasClass('first')
_firstInput = $input
setAltFields($input, _minFirstDate)
else
_secondInput = $input
setAltFields($input, _minSecondDate)
return $input
constructor: (form, @options) ->
_form = $(form)
today = new Date()
# min first date = today + min day offset
_minFirstDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + getOffset())
# min second date = first date + range offset
_minSecondDate = new Date(_minFirstDate.getFullYear(), _minFirstDate.getMonth(), _minFirstDate.getDate() + getRange())
# selected dates
_firstDate = _minFirstDate
_secondDate = _minSecondDate
@options['beforeShow'] = setMinDate
@options['onSelect'] = onSelect
_form.find('.calendar').map(@init)
# export to global namespace
(exports ? this).RangeDatepicker = RangeDatepicker
@lukaszkorecki
Copy link

Uwagi stylistyczne:

  1. nie potrzebujesz tych zmiennych zaczynających się od _ - Coffeescript zrobi to za ciebie (pamiętaj o @)
  2. setAltField mogło by spokojnie używać switch...when
  3. w init, możesz spokojnie wywalić return na końcu (tak jak w Ruby)

@jandudulski
Copy link
Author

ad 1 początkowo używałem @ ale:
a) to w zasadzie nie są publiczne metody
b) w pewnym momencie miałem spore problemy z contextem i zdecydowałem wywalić wszystko jako prywatne klasy

ad 2 ślepota boli. chciałem użyć, ale nie mogłem się doszukać na stronie... chlast!
ad 3 mogę, ale jakoś brzydko mi wygląda samotny $input :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment