Fixes #1693 pending till date issue

This commit is contained in:
Mantas 2018-06-07 15:04:47 +03:00 committed by Mantas Masalskis
parent ada6efa3bc
commit 3545893c3d
5 changed files with 239 additions and 313 deletions

View file

@ -0,0 +1,156 @@
# coffeelint: disable=camel_case_classes
# Base class for providing date picker. Must be extended
class App.UiElement.basedate
@templateName: ->
throw 'Must override in a subclass'
@render: (attributeOrig) ->
attribute = _.clone(attributeOrig)
attribute.nameRaw = attribute.name
attribute.name = "{#{@templateName()}}#{attribute.name}"
item = $( App.view("generic/#{@templateName()}")(
attribute: attribute
) )
# set our custom template
$.fn.datepicker.defaults.template = App.view('generic/datepicker')()
# apply date widgets
$.fn.datepicker.dates['custom'] = @buildCustomDates()
@applyPickers(item, attribute)
@bindEvents(item, attribute)
item
@log: (name, args...) ->
App.Log.debug "Ui.element.#{@templateName()}.#{name}", args...
@applyPickers: (item, attribute) ->
item.find('.js-datepicker').datepicker(
weekStart: 1
autoclose: true
todayBtn: 'linked'
todayHighlight: true
format: App.i18n.timeFormat().date
rtl: App.i18n.dir() is 'rtl'
container: item
language: 'custom'
)
@setNewTimeInitial(item, attribute)
# observer changes / update needed to forece rerender to get correct today shown
@bindEvents: (item, attribute) ->
item
.find('input')
.bind('focus', (e) ->
item.find('.js-datepicker').datepicker('rerender')
).bind('keyup blur change', (e) =>
@setNewTime(item, attribute, 0)
@validation(item, attribute, true)
)
item.bind('validate', (e) =>
@validation(item, attribute)
)
@setNewTime: (item, attribute, tolerant = false) ->
currentInput = @currentInput(item, attribute)
return if !currentInput
if !@validateInput(currentInput)
item.find("[name=\"#{attribute.name}\"]").val('')
return
item.find("[name=\"#{attribute.name}\"]").val(@buildTimestamp(currentInput))
# returns array with date or false if cannot get date
@currentInput: (item, attribute) ->
datetime = item.find('.js-datepicker').datepicker('getDate')
if !datetime || datetime.toString() is 'Invalid Date'
item.find("[name=\"#{attribute.name}\"]").val('')
return false
@log 'setNewTime', datetime
year = datetime.getFullYear()
month = datetime.getMonth() + 1
day = datetime.getDate()
date = "#{App.Utils.formatTime(year)}-#{App.Utils.formatTime(month,2)}-#{App.Utils.formatTime(day,2)}"
[date]
@validateInput: (currentInput) ->
currentInput[0] isnt ''
@buildTimestamp: (currentInput) ->
throw 'Must override in a subclass'
@dateSetter: ->
throw 'Must override in a subclass'
@setNewTimeInitial: (item, attribute) ->
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
@log 'setNewTimeInitial', timestamp
if !timestamp
@setNoTimestamp(item)
return
timeObject = new Date( Date.parse( timestamp ) )
@log 'setNewTimeInitial', timestamp, timeObject
@setTimestamp(item, timeObject)
item.find('.js-datepicker').datepicker('update')
@setNoTimestamp: (item) ->
return
@setTimestamp: (item, timeObject) ->
item.find('.js-datepicker').datepicker(@dateSetter(), timeObject)
@validation: (item, attribute, runtime) ->
# remove old validation
if attribute.validationContainer is 'self'
item.find('.js-datepicker').removeClass('has-error')
else
item.closest('.form-group').removeClass('has-error')
item.find('.has-error').removeClass('has-error')
item.find('.help-inline').html('')
item.closest('.form-group').find('.help-inline').html('')
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
# check required attributes
errors = {}
if !timestamp
if !attribute.null
errors[attribute.name] = 'missing'
else
timeObject = new Date( Date.parse( timestamp ) )
@log 'validation', errors
return if _.isEmpty(errors)
# show invalid options
if attribute.validationContainer is 'self'
item.find('.js-datepicker').addClass('has-error')
else
formGroup = item.closest('.form-group')
for key, value of errors
formGroup.addClass('has-error')
@buildCustomDates: ->
data = {
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
daysMin: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
months: ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'],
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
today: 'today',
clear: 'clear'
}
App.i18n.translateDeep(data)

View file

@ -1,161 +1,11 @@
# coffeelint: disable=camel_case_classes # coffeelint: disable=camel_case_classes
class App.UiElement.date # Provides date-only picker
@render: (attributeOrig) -> class App.UiElement.date extends App.UiElement.basedate
@templateName: ->
'date'
attribute = _.clone(attributeOrig) @buildTimestamp: (currentInput) ->
attribute.nameRaw = attribute.name currentInput[0]
attribute.name = "{date}#{attribute.name}"
item = $( App.view('generic/date')( @dateSetter: ->
attribute: attribute 'setUTCDate'
) )
# set our custom template
$.fn.datepicker.defaults.template = App.view('generic/datepicker')()
# apply date widgets
$.fn.datepicker.dates['custom'] =
days: [
App.i18n.translateInline('Sunday'),
App.i18n.translateInline('Monday'),
App.i18n.translateInline('Tuesday'),
App.i18n.translateInline('Wednesday'),
App.i18n.translateInline('Thursday'),
App.i18n.translateInline('Friday'),
App.i18n.translateInline('Saturday'),
App.i18n.translateInline('Sunday'),
],
daysMin: [
App.i18n.translateInline('Sun'),
App.i18n.translateInline('Mon'),
App.i18n.translateInline('Tue'),
App.i18n.translateInline('Wed'),
App.i18n.translateInline('Thu'),
App.i18n.translateInline('Fri'),
App.i18n.translateInline('Sat'),
App.i18n.translateInline('Sun')
],
daysShort: [
App.i18n.translateInline('Sun'),
App.i18n.translateInline('Mon'),
App.i18n.translateInline('Tue'),
App.i18n.translateInline('Wed'),
App.i18n.translateInline('Thu'),
App.i18n.translateInline('Fri'),
App.i18n.translateInline('Sat'),
App.i18n.translateInline('Sun')
],
months: [
App.i18n.translateInline('January'),
App.i18n.translateInline('February'),
App.i18n.translateInline('March'),
App.i18n.translateInline('April'),
App.i18n.translateInline('May'),
App.i18n.translateInline('June'),
App.i18n.translateInline('July'),
App.i18n.translateInline('August'),
App.i18n.translateInline('September'),
App.i18n.translateInline('October'),
App.i18n.translateInline('November'),
App.i18n.translateInline('December'),
],
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
today: App.i18n.translateInline('today'),
clear: App.i18n.translateInline('clear')
currentDate = undefined
item.find('.js-datepicker').datepicker(
weekStart: 1
autoclose: true
todayBtn: 'linked'
todayHighlight: true
format: App.i18n.timeFormat().date
rtl: App.i18n.dir() is 'rtl'
container: item
language: 'custom'
)
# set initial date time
@setNewTimeInitial(item, attribute)
# observer changes / update needed to forece rerender to get correct today shown
item.find('input').bind('focus', (e) ->
item.find('.js-datepicker').datepicker('rerender')
)
item.find('input').bind('keyup blur change', (e) =>
@setNewTime(item, attribute, 0)
@validation(item, attribute, true)
)
item.bind('validate', (e) =>
@validation(item, attribute)
)
item
@setNewTime: (item, attribute, tolerant = false) ->
datetime = item.find('.js-datepicker').datepicker('getDate')
if !datetime || datetime.toString() is 'Invalid Date'
App.Log.debug 'UiElement.date.setNewTime', datetime
item.find("[name=\"#{attribute.name}\"]").val('')
return
App.Log.debug 'UiElement.date.setNewTime', datetime
year = datetime.getFullYear()
month = datetime.getMonth() + 1
day = datetime.getDate()
date = "#{App.Utils.formatTime(year)}-#{App.Utils.formatTime(month,2)}-#{App.Utils.formatTime(day,2)}"
if date is ''
item.find("[name=\"#{attribute.name}\"]").val('')
return
App.Log.debug 'UiElement.date.setNewTime', date
item.find("[name=\"#{attribute.name}\"]").val(date)
@setNewTimeInitial: (item, attribute) ->
App.Log.debug 'UiElement.date.setNewTimeInitial', timestamp
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
return if !timestamp
timeObject = new Date( Date.parse( timestamp ) )
hour = timeObject.getHours()
minute = timeObject.getMinutes()
App.Log.debug 'UiElement.date.setNewTimeInitial', timestamp, timeObject
item.find('.js-datepicker').datepicker('setUTCDate', timeObject)
item.find('.js-datepicker').datepicker('update')
@validation: (item, attribute, runtime) ->
# remove old validation
if attribute.validationContainer is 'self'
item.find('.js-datepicker').removeClass('has-error')
else
item.closest('.form-group').removeClass('has-error')
item.find('.has-error').removeClass('has-error')
item.find('.help-inline').html('')
item.closest('.form-group').find('.help-inline').html('')
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
# check required attributes
errors = {}
if !timestamp
if !attribute.null
errors[attribute.name] = 'missing'
else
timeObject = new Date( Date.parse( timestamp ) )
App.Log.debug 'UiElement.date.validation', errors
return if _.isEmpty(errors)
# show invalid options
if attribute.validationContainer is 'self'
item.find('.js-datepicker').addClass('has-error')
else
formGroup = item.closest('.form-group')
for key, value of errors
formGroup.addClass('has-error')

View file

@ -1,174 +1,45 @@
# coffeelint: disable=camel_case_classes # coffeelint: disable=camel_case_classes
class App.UiElement.datetime # Provides full date and time picker
@render: (attributeOrig) -> class App.UiElement.datetime extends App.UiElement.basedate
@templateName: ->
'datetime'
attribute = _.clone(attributeOrig) @applyPickers: (item, attribute) ->
attribute.nameRaw = attribute.name super(item, attribute)
attribute.name = "{datetime}#{attribute.name}"
item = $( App.view('generic/datetime')(
attribute: attribute
) )
# set our custom template
$.fn.datepicker.defaults.template = App.view('generic/datepicker')()
# apply date widgets
$.fn.datepicker.dates['custom'] =
days: [
App.i18n.translateInline('Sunday'),
App.i18n.translateInline('Monday'),
App.i18n.translateInline('Tuesday'),
App.i18n.translateInline('Wednesday'),
App.i18n.translateInline('Thursday'),
App.i18n.translateInline('Friday'),
App.i18n.translateInline('Saturday'),
App.i18n.translateInline('Sunday'),
],
daysMin: [
App.i18n.translateInline('Sun'),
App.i18n.translateInline('Mon'),
App.i18n.translateInline('Tue'),
App.i18n.translateInline('Wed'),
App.i18n.translateInline('Thu'),
App.i18n.translateInline('Fri'),
App.i18n.translateInline('Sat'),
App.i18n.translateInline('Sun')
],
daysShort: [
App.i18n.translateInline('Sun'),
App.i18n.translateInline('Mon'),
App.i18n.translateInline('Tue'),
App.i18n.translateInline('Wed'),
App.i18n.translateInline('Thu'),
App.i18n.translateInline('Fri'),
App.i18n.translateInline('Sat'),
App.i18n.translateInline('Sun')
],
months: [
App.i18n.translateInline('January'),
App.i18n.translateInline('February'),
App.i18n.translateInline('March'),
App.i18n.translateInline('April'),
App.i18n.translateInline('May'),
App.i18n.translateInline('June'),
App.i18n.translateInline('July'),
App.i18n.translateInline('August'),
App.i18n.translateInline('September'),
App.i18n.translateInline('October'),
App.i18n.translateInline('November'),
App.i18n.translateInline('December'),
],
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
today: App.i18n.translateInline('today'),
clear: App.i18n.translateInline('clear')
currentDate = undefined
item.find('.js-datepicker').datepicker(
weekStart: 1
autoclose: true
todayBtn: 'linked'
todayHighlight: true
format: App.i18n.timeFormat().date
rtl: App.i18n.dir() is 'rtl'
container: item
language: 'custom'
)
# set initial date time
@setNewTimeInitial(item, attribute)
# apply time widgets
item.find('.js-timepicker').timepicker() item.find('.js-timepicker').timepicker()
# observer changes / update needed to forece rerender to get correct today shown
item.find('input').bind('focus', (e) ->
item.find('.js-datepicker').datepicker('rerender')
)
item.find('input').bind('keyup blur change', (e) =>
@setNewTime(item, attribute, 0)
@validation(item, attribute, true)
)
item.bind('validate', (e) =>
@validation(item, attribute)
)
item # returns array with date and time or false if cannot get date
@currentInput: (item, attribute) ->
result = super(item, attribute)
@setNewTime: (item, attribute, tolerant = false) -> if _.isArray(result)
result.push item.find('.js-timepicker').val()
datetime = item.find('.js-datepicker').datepicker('getDate') result
if !datetime || datetime.toString() is 'Invalid Date'
App.Log.debug 'UiElement.datetime.setNewTime', datetime
item.find("[name=\"#{attribute.name}\"]").val('')
return
App.Log.debug 'UiElement.datetime.setNewTime', datetime @validateInput: (currentInput) ->
year = datetime.getFullYear() currentInput[0] isnt '' || currentInput[1] isnt ''
month = datetime.getMonth() + 1
day = datetime.getDate()
date = "#{App.Utils.formatTime(year)}-#{App.Utils.formatTime(month,2)}-#{App.Utils.formatTime(day,2)}"
time = item.find('.js-timepicker').val()
if date is '' || time is '' @setNoTimestamp: (item) ->
item.find("[name=\"#{attribute.name}\"]").val('') item.find('.js-timepicker').val('08:00')
return
timestamp = "#{date}T#{time}:00.000Z" @setTimestamp: (item, timeObject) ->
time = new Date( Date.parse(timestamp) ) super(item, timeObject)
time.setMinutes( time.getMinutes() + time.getTimezoneOffset() )
App.Log.debug 'UiElement.datetime.setNewTime', time.toString()
timestamp = time.toISOString().replace(/\d\d\.\d\d\dZ$/, '00.000Z')
item.find("[name=\"#{attribute.name}\"]").val(timestamp)
@setNewTimeInitial: (item, attribute) ->
App.Log.debug 'UiElement.datetime.setNewTimeInitial', timestamp
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
if !timestamp
item.find('.js-timepicker').val('08:00')
return
timeObject = new Date( Date.parse( timestamp ) )
hour = timeObject.getHours() hour = timeObject.getHours()
minute = timeObject.getMinutes() minute = timeObject.getMinutes()
time = "#{App.Utils.formatTime(hour,2)}:#{App.Utils.formatTime(minute,2)}" time = "#{App.Utils.formatTime(hour,2)}:#{App.Utils.formatTime(minute,2)}"
App.Log.debug 'UiElement.datetime.setNewTimeInitial', timestamp, timeObject
item.find('.js-datepicker').datepicker('setUTCDate', timeObject)
item.find('.js-timepicker').val(time) item.find('.js-timepicker').val(time)
item.find('.js-datepicker').datepicker('update')
@validation: (item, attribute, runtime) ->
# remove old validation
if attribute.validationContainer is 'self'
item.find('.js-datepicker').removeClass('has-error')
else
item.closest('.form-group').removeClass('has-error')
item.find('.has-error').removeClass('has-error')
item.find('.help-inline').html('')
item.closest('.form-group').find('.help-inline').html('')
timestamp = item.find("[name=\"#{attribute.name}\"]").val()
# check required attributes
errors = {}
if !timestamp
if !attribute.null
errors[attribute.name] = 'missing'
else
timeObject = new Date( Date.parse( timestamp ) )
App.Log.debug 'UiElement.datetime.validation', errors
return if _.isEmpty(errors)
# show invalid options
if attribute.validationContainer is 'self'
item.find('.js-datepicker').addClass('has-error')
else
formGroup = item.closest('.form-group')
for key, value of errors
formGroup.addClass('has-error')
@buildTimestamp: (currentInput) ->
timestamp = "#{currentInput[0]}T#{currentInput[1]}:00.000Z"
time = new Date( Date.parse(timestamp) )
time.setMinutes( time.getMinutes() + time.getTimezoneOffset() )
@log 'setNewTime', time.toString()
time.toISOString().replace(/\d\d\.\d\d\dZ$/, '00.000Z')
@dateSetter: ->
'setDate'

View file

@ -5,6 +5,11 @@ class App.i18n
@init: (args) -> @init: (args) ->
_instance ?= new _i18nSingleton(args) _instance ?= new _i18nSingleton(args)
@translateDeep: (input, args...) ->
if _instance == undefined
_instance ?= new _i18nSingleton()
_instance.translateDeep(input, args)
@translateContent: (string, args...) -> @translateContent: (string, args...) ->
if _instance == undefined if _instance == undefined
_instance ?= new _i18nSingleton() _instance ?= new _i18nSingleton()
@ -203,6 +208,19 @@ class _i18nSingleton extends Spine.Module
return string if !string return string if !string
@translate(string, args, true) @translate(string, args, true)
translateDeep: (input, args) =>
if _.isArray(input)
_.map input, (item) =>
@translateDeep(item, args)
else if _.isObject(input)
_.reduce _.keys(input), (memo, item) =>
memo[item] = @translateDeep(input[item])
memo
, {}
else
@translateInline(input, args)
translateContent: (string, args) => translateContent: (string, args) =>
return string if !string return string if !string

View file

@ -1,3 +1,34 @@
// date picker timezone conversion for display
test("date picker", function() {
Date.prototype.getTimezoneOffset2 = Date.prototype.getTimezoneOffset
Date.prototype.getTimezoneOffset = function() { return -360 }
obj_date_time = {
name: 'test',
value: '2018-04-06T20:45:00.000Z'
}
el_date_time = App.UiElement.datetime.render(obj_date_time)
date_time_parsed = new Date(Date.parse(obj_date_time.value))
date_time_input = el_date_time.find('.js-datepicker').datepicker('getDate')
equal(date_time_parsed.getDate(), date_time_input.getDate(), 'datetime matching day')
obj_date = {
name: 'test',
value: '2018-06-06'
}
el_date = App.UiElement.date.render(obj_date)
date_parsed = new Date(Date.parse(obj_date.value))
date_input = el_date.find('.js-datepicker').datepicker('getUTCDate')
equal(date_parsed.getDate(), date_input.getDate(), 'date matching day')
Date.prototype.getTimezoneOffset = Date.prototype.getTimezoneOffset2
Date.prototype.getTimezoneOffset2 = undefined
})
// pretty date // pretty date
test("check pretty date", function() { test("check pretty date", function() {
var current = new Date() var current = new Date()