From edab5b9197c13f0c8539746b734174dff0ab7d76 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sat, 19 Sep 2015 23:24:11 +0200 Subject: [PATCH] Moved to new datetime and date ui element. --- .../_application_controller_form.js.coffee | 513 ++---------------- .../controllers/_ui_element/date.js.coffee | 239 ++++---- .../_ui_element/datetime.js.coffee | 323 ++++++----- .../app/views/generic/date.jst.eco | 23 +- .../app/views/generic/datetime.jst.eco | 30 +- public/assets/tests/form-validation.js | 102 ++-- 6 files changed, 448 insertions(+), 782 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index a0e836fd1..814710ae0 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -226,53 +226,7 @@ class App.ControllerForm extends App.Controller if App.UiElement[attribute.tag] item = App.UiElement[attribute.tag].render(attribute, @params, @) - - # ticket attribute selection - else if attribute.tag is 'ticket_attribute_selection' - - # list of possible attributes - item = $( - App.view('generic/ticket_attribute_manage')( - attribute: attribute - ) - ) - - addShownAttribute = ( key, value ) => - parts = key.split(/::/) - key = parts[0] - type = parts[1] - if key is 'tickets.number' - attribute_config = { - name: attribute.name + '::tickets.number' - display: 'Number' - tag: 'input' - type: 'text' - null: false - value: value - remove: true - } - else if key is 'tickets.title' - attribute_config = { - name: attribute.name + '::tickets.title' - display: 'Title' - tag: 'input' - type: 'text' - null: false - value: value - remove: true - } - else if key is 'tickets.group_id' - attribute_config = { - name: attribute.name + '::tickets.group_id' - display: 'Group' - tag: 'select' - multiple: true - null: false - nulloption: false - relation: 'Group' - value: value - remove: true - } + ### else if key is 'tickets.owner_id' || key is 'tickets.customer_id' display = 'Owner' name = 'owner_id' @@ -332,344 +286,7 @@ class App.ControllerForm extends App.Controller } ) all } - else if key is 'tickets.state_id' - attribute_config = { - name: attribute.name + '::tickets.state_id' - display: 'State' - tag: 'select' - multiple: true - null: false - nulloption: false - relation: 'TicketState' - value: value - translate: true - remove: true - } - else if key is 'tickets.priority_id' - attribute_config = { - name: attribute.name + '::tickets.priority_id' - display: 'Priority' - tag: 'select' - multiple: true - null: false - nulloption: false - relation: 'TicketPriority' - value: value - translate: true - remove: true - } - else if key is 'tickets.created_at' && ( type is '<>' || value.count ) - attribute_config = { - name: attribute.name + '::tickets.created_at' - display: 'Created (before / last)' - tag: 'time_before_last' - value: value - translate: true - remove: true - } - else if key is 'tickets.created_at' && ( type is '><' || 0 ) - attribute_config = { - name: attribute.name + '::tickets.created_at' - display: 'Created (between)' - tag: 'time_range' - value: value - translate: true - remove: true - } - else if key is 'tickets.close_time' && ( type is '<>' || value.count ) - attribute_config = { - name: attribute.name + '::tickets.close_time' - display: 'Closed (before / last)' - tag: 'time_before_last' - value: value - translate: true - remove: true - } - else if key is 'tickets.close_time' && ( type is '><' || 0 ) - attribute_config = { - name: attribute.name + '::tickets.close_time' - display: 'Closed (between)' - tag: 'time_range' - value: value - translate: true - remove: true - } - else if key is 'tickets.updated_at' && ( type is '<>' || value.count ) - attribute_config = { - name: attribute.name + '::tickets.updated_at' - display: 'Updated (before / last)' - tag: 'time_before_last' - value: value - translate: true - remove: true - } - else if key is 'tickets.updated_at' && ( type is '><' || 0 ) - attribute_config = { - name: attribute.name + '::tickets.updated_at' - display: 'Updated (between)' - tag: 'time_range' - value: value - translate: true - remove: true - } - else if key is 'tickets.escalation_time' && ( type is '<>' || value.count ) - attribute_config = { - name: attribute.name + '::tickets.escalation_time' - display: 'Escalation (before / last)' - tag: 'time_before_last' - value: value - translate: true - remove: true - } - else if key is 'tickets.escalation_time' && ( type is '><' || 0 ) - attribute_config = { - name: attribute.name + '::tickets.escalation_time' - display: 'Escatlation (between)' - tag: 'time_range' - value: value - translate: true - remove: true - } - else - attribute_config = { - name: attribute.name + '::' + key - display: 'FIXME!' - tag: 'input' - type: 'text' - value: value - remove: true - } - - item.find('select[name=ticket_attribute_list] option[value="' + key + '"]').hide().prop('disabled', true) - - itemSub = @formGenItem( attribute_config ) - itemSub.find('.glyphicon-minus').bind('click', (e) -> - e.preventDefault() - value = $(e.target).closest('.controls').find('[name]').attr('name') - if value - value = value.replace("#{attribute.name}::", '') - $(e.target).closest('.sub_attribute').find('select[name=ticket_attribute_list] option[value="' + value + '"]').show().prop('disabled', false) - $(@).parent().parent().parent().remove() - ) -# itemSub.append('') - item.find('.ticket_attribute_item').append( itemSub ) - - # list of existing attributes - attribute_config = { - name: 'ticket_attribute_list' - display: 'Add Attribute' - tag: 'select' - multiple: false - null: false -# nulloption: true - options: [ - { - value: '' - name: '-- Ticket --' - selected: false - disable: true - }, - { - value: 'tickets.number' - name: 'Number' - selected: false - disable: false - }, - { - value: 'tickets.title' - name: 'Title' - selected: false - disable: false - }, - { - value: 'tickets.group_id' - name: 'Group' - selected: false - disable: false - }, - { - value: 'tickets.state_id' - name: 'State' - selected: false - disable: false - }, - { - value: 'tickets.priority_id' - name: 'Priority' - selected: true - disable: false - }, - { - value: 'tickets.owner_id' - name: 'Owner' - selected: true - disable: false - }, - #{ - # value: 'tickets.created_at::<>' - # name: 'Created (before/last)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.created_at::><' - # name: 'Created (between)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.close_time::<>' - # name: 'Closed (before/last)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.close_time::><' - # name: 'Closed (between)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.updated_at::<>' - # name: 'Updated (before/last)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.updated_at::><' - # name: 'Updated (between)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.escalation_time::<>' - # name: 'Escalation (before/last)' - # selected: true - # disable: false - #}, - #{ - # value: 'tickets.escalation_time::><' - # name: 'Escalation (between)' - # selected: true - # disable: false - #}, -# # { -# value: 'tag' -# name: 'Tag' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.created_before' -# name: 'Erstell vor' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.created_after' -# name: 'Erstell nach' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.created_between' -# name: 'Erstell zwischen' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.closed_before' -# name: 'Geschlossen vor' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.closed_after' -# name: 'Geschlossen nach' -# selected: true -# disable: false -# }, -# { -# value: 'tickets.closed_between' -# name: 'Geschlossen zwischen' -# selected: true -# disable: false -# }, -# { -# value: '-a' -# name: '-- ' + App.i18n.translateInline('Article') + ' --' -# selected: false -# disable: true -# }, -# { -# value: 'ticket_articles.from' -# name: 'From' -# selected: true -# disable: false -# }, -# { -# value: 'ticket_articles.to' -# name: 'To' -# selected: true -# disable: false -# }, -# { -# value: 'ticket_articles.cc' -# name: 'Cc' -# selected: true -# disable: false -# }, -# { -# value: 'ticket_articles.subject' -# name: 'Subject' -# selected: true -# disable: false -# }, -# { -# value: 'ticket_articles.body' -# name: 'Text' -# selected: true -# disable: false -# }, - { - value: '-c' - name: '-- ' + App.i18n.translateInline('Customer') + ' --' - selected: false - disable: true - }, - { - value: 'customers.id' - name: 'Customer' - selected: true - disable: false - }, - { - value: 'organization.id' - name: 'Organization' - selected: true - disable: false - }, - ] - default: '' - translate: true - class: 'medium' - add: true - } - list = @formGenItem( attribute_config ) - - list.find('.glyphicon-plus').bind('click', (e) -> - e.preventDefault() - value = $(e.target).closest('.controls').find('[name=ticket_attribute_list]').val() - addShownAttribute( value, '' ) - ) - item.find('.ticket_attribute_list').prepend( list ) - - # list of shown attributes - show = [] - if attribute.value - for key, value of attribute.value - addShownAttribute( key, value ) - + ### else throw "Invalid UiElement.#{attribute.tag}" @@ -844,88 +461,52 @@ class App.ControllerForm extends App.Controller # get boolean if key.substr(0,9) is '{boolean}' - newKey = key.substr( 9, key.length ) - param[ newKey ] = param[ key ] - delete param[ key ] - if param[ newKey ] && param[ newKey ].toString() is 'true' - param[ newKey ] = true + newKey = key.substr(9, key.length) + if param[key] && param[key].toString() is 'true' + param[newKey] = true else - param[ newKey ] = false + param[newKey] = false + delete param[key] # get {date} else if key.substr(0,6) is '{date}' - newKey = key.substr( 6, key.length ) - namespace = newKey.split '___' - - if !param[ namespace[0] ] - dateKey = "{date}#{namespace[0]}___" - year = param[ "#{dateKey}year" ] - month = param[ "#{dateKey}month" ] - day = param[ "#{dateKey}day" ] - - if lookupForm.find('[data-name = "' + namespace[0] + '"]').hasClass('is-hidden') - param[ namespace[0] ] = null - else if year && month && day && day + newKey = key.substr(6, key.length) + if lookupForm.find("[data-name=\"#{newKey}\"]").hasClass('is-hidden') + param[newKey] = null + else if param[key] + try + time = new Date( Date.parse( "#{param[key]}T00:00:00Z" ) ) format = (number) -> if parseInt(number) < 10 number = "0#{number}" number - try - time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T00:00:00Z" ) ) - if time && time.toString() is 'Invalid Date' - throw "Invalid Date #{year}-#{format(month)}-#{format(day)}" - param[ namespace[0] ] = "#{time.getUTCFullYear()}-#{format(time.getUTCMonth()+1)}-#{format(time.getUTCDate())}" - catch err - param[ namespace[0] ] = 'invalid' - console.log('ERR', err) - else - param[ namespace[0] ] = undefined - - #console.log('T', time, time.getHours(), time.getMinutes()) - - delete param[ "#{dateKey}year" ] - delete param[ "#{dateKey}month" ] - delete param[ "#{dateKey}day" ] + if time is 'Invalid Date' + throw "Invalid Date #{param[key]}" + param[newKey] = "#{time.getUTCFullYear()}-#{format(time.getUTCMonth()+1)}-#{format(time.getUTCDate())}" + catch err + param[newKey] = "invalid #{param[key]}" + console.log('ERR', err) + else + param[newKey] = undefined + delete param[key] # get {datetime} else if key.substr(0,10) is '{datetime}' - newKey = key.substr( 10, key.length ) - namespace = newKey.split '___' - - if !param[ namespace[0] ] - datetimeKey = "{datetime}#{namespace[0]}___" - year = param[ "#{datetimeKey}year" ] - month = param[ "#{datetimeKey}month" ] - day = param[ "#{datetimeKey}day" ] - hour = param[ "#{datetimeKey}hour" ] - minute = param[ "#{datetimeKey}minute" ] - - if lookupForm.find('[data-name="' + namespace[0] + '"]').hasClass('is-hidden') - param[ namespace[0] ] = null - else if year && month && day && hour && minute - format = (number) -> - if parseInt(number) < 10 - number = "0#{number}" - number - try - time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z" ) ) - if time && time.toString() is 'Invalid Date' - throw "Invalid Date #{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z" - time.setMinutes( time.getMinutes() + time.getTimezoneOffset() ) - param[ namespace[0] ] = time.toISOString() - catch err - param[ namespace[0] ] = 'invalid' - console.log('ERR', err) - else - param[ namespace[0] ] = undefined - - #console.log('T', time, time.getHours(), time.getMinutes()) - - delete param[ "#{datetimeKey}year" ] - delete param[ "#{datetimeKey}month" ] - delete param[ "#{datetimeKey}day" ] - delete param[ "#{datetimeKey}hour" ] - delete param[ "#{datetimeKey}minute" ] + newKey = key.substr(10, key.length) + if lookupForm.find("[data-name=\"#{newKey}\"]").hasClass('is-hidden') + param[newKey] = null + else if param[key] + try + time = new Date( Date.parse( param[key] ) ) + if time is 'Invalid Datetime' + throw "Invalid Datetime #{param[key]}" + param[newKey] = time.toISOString().replace(/:\d\d\.\d\d\dZ$/, ':00Z') + catch err + param[newKey] = "invalid #{param[key]}" + console.log('ERR', err) + else + param[newKey] = undefined + delete param[key] # split :: fields, build objects inputSelectObject = {} @@ -1027,15 +608,21 @@ class App.ControllerForm extends App.Controller # show new errors for key, msg of data.errors - # use native fields - item = lookupForm.find('[name="' + key + '"]').closest('.form-group') - item.addClass('has-error') - item.find('.help-inline').html(msg) + # generic validation + itemGeneric = lookupForm.find('[name="' + key + '"]').closest('.form-group') + itemGeneric.addClass('has-error') + itemGeneric.find('.help-inline').html(msg) # use meta fields - item = lookupForm.find('[data-name="' + key + '"]').closest('.form-group') - item.addClass('has-error') - item.find('.help-inline').html(msg) + itemMeta = lookupForm.find('[data-name="' + key + '"]').closest('.form-group') + itemMeta.addClass('has-error') + itemMeta.find('.help-inline').html(msg) + + # use native fields + itemGeneric = lookupForm.find('[name="' + key + '"]').closest('.form-control') + itemGeneric.trigger('validate') + itemMeta = lookupForm.find('[data-name="' + key + '"]').closest('.form-control') + itemMeta.trigger('validate') # set autofocus by delay to make validation testable App.Delay.set( diff --git a/app/assets/javascripts/app/controllers/_ui_element/date.js.coffee b/app/assets/javascripts/app/controllers/_ui_element/date.js.coffee index f8b9db2ac..7256d2e54 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/date.js.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/date.js.coffee @@ -1,20 +1,23 @@ class App.UiElement.date - @render: (attribute) -> + @render: (attributeOrig) -> - # set data type - if attribute.name - attribute.nameRaw = attribute.name - attribute.name = '{date}' + attribute.name + attribute = _.clone(attributeOrig) + attribute.nameRaw = attribute.name + attribute.name = "{date}#{attribute.name}" + + # get time object if attribute.value - if typeof( attribute.value ) is 'string' - unixtime = new Date( Date.parse( "#{attribute.value}T00:00:00Z" ) ) + if typeof attribute.value is 'string' + time = new Date( Date.parse( "#{attribute.value}T00:00:00Z" ) ) else - unixtime = new Date( attribute.value ) - year = unixtime.getUTCFullYear() - month = unixtime.getUTCMonth() + 1 - day = unixtime.getUTCDate() - hour = unixtime.getUTCHours() - minute = unixtime.getUTCMinutes() + time = new Date( attribute.value ) + + # time items + year = time.getUTCFullYear() + month = time.getUTCMonth() + 1 + day = time.getUTCDate() + + # create element item = $( App.view('generic/date')( attribute: attribute year: year @@ -22,118 +25,152 @@ class App.UiElement.date day: day ) ) - setNewTime = (diff, el, reset) -> - name = $(el).closest('.form-group').find('[data-name]').attr('data-name') - - # remove old validation - item.find('.has-error').removeClass('has-error') - item.closest('.form-group').find('.help-inline').html('') - - day = item.closest('.form-group').find("[name=\"{date}#{name}___day\"]").val() - month = item.closest('.form-group').find("[name=\"{date}#{name}___month\"]").val() - year = item.closest('.form-group').find("[name=\"{date}#{name}___year\"]").val() - format = (number) -> - if parseInt(number) < 10 - number = "0#{number}" - number - if !reset && (year isnt '' && month isnt '' && day isnt '') - time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T00:00:00Z" ) ) - time.setMinutes( time.getMinutes() + diff + time.getTimezoneOffset() ) - else - time = new Date() - time.setMinutes( time.getMinutes() + diff ) - item.closest('.form-group').find("[name=\"{date}#{name}___day\"]").val( time.getDate() ) - item.closest('.form-group').find("[name=\"{date}#{name}___month\"]").val( time.getMonth()+1 ) - item.closest('.form-group').find("[name=\"{date}#{name}___year\"]").val( time.getFullYear() ) - - item.find('.js-today').bind('click', (e) -> + # start bindings + item.find('.js-today').bind('click', (e) => e.preventDefault() - setNewTime(0, @, true) + @setNewTime(item, attribute, 0, true) + @validation(item, attribute) ) - item.find('.js-plus-day').bind('click', (e) -> + item.find('.js-plus-day').bind('click', (e) => e.preventDefault() - setNewTime(60 * 24, @) + @setNewTime(item, attribute, 60 * 24) + @validation(item, attribute) ) - item.find('.js-minus-day').bind('click', (e) -> + item.find('.js-minus-day').bind('click', (e) => e.preventDefault() - setNewTime(-60 * 24, @) + @setNewTime(item, attribute, -60 * 24) + @validation(item, attribute) ) - item.find('.js-plus-week').bind('click', (e) -> + item.find('.js-plus-week').bind('click', (e) => e.preventDefault() - setNewTime(60 * 24 * 7, @) + @setNewTime(item, attribute, 60 * 24 * 7) + @validation(item, attribute) ) - item.find('.js-minus-week').bind('click', (e) -> + item.find('.js-minus-week').bind('click', (e) => e.preventDefault() - setNewTime(-60 * 24 * 7, @) + @setNewTime(item, attribute, -60 * 24 * 7) + @validation(item, attribute) ) + item.find('input').bind('keyup blur focus change', (e) => + @setNewTime(item, attribute, 0) + @validation(item, attribute, true) + ) + item.bind('validate', (e) => + @validation(item, attribute) + ) + #setShadowTimestamp() + @setNewTime(item, attribute, 0) - item.find('input').bind('keyup blur focus change', (e) -> + item - # do validation - name = $(@).attr('name') - if name - fieldPrefix = name.split('___')[0] + @format: (number) -> + if parseInt(number) < 10 + number = "0#{number}" + number - # remove old validation - item.find('.has-error').removeClass('has-error') - item.closest('.form-group').find('.help-inline').html('') + @setNewTime: (item, attribute, diff, reset = false) -> - day = item.closest('.form-group').find("[name=\"#{fieldPrefix}___day\"]").val() - month = item.closest('.form-group').find("[name=\"#{fieldPrefix}___month\"]").val() - year = item.closest('.form-group').find("[name=\"#{fieldPrefix}___year\"]").val() + # remove old validation + #item.find('.has-error').removeClass('has-error') + #item.closest('.form-group').find('.help-inline').html('') - # validate exists - errors = {} - if !day + if reset + time = new Date() + time.setMinutes( time.getMinutes() + diff ) + @setParams(item, attribute, time) + return + + params = @getParams(item) + return if params.year is '' && params.month is '' && params.day is '' && params.hour is '' && params.day is '' + time = new Date( Date.parse( "#{params.year}-#{@format(params.month)}-#{@format(params.day)}T00:00:00Z" ) ) + time.setMinutes( time.getMinutes() + diff ) + return if !time + @setParams(item, attribute, time) + + @setShadowTimestamp: (item, attribute, time) -> + timestamp = '' + if time + timestamp = time.toISOString().replace(/T\d\d:\d\d:\d\d\.\d\d\dZ$/, '') + item.find("[name=\"#{attribute.name}\"]").val(timestamp) + + @setParams: (item, attribute, time) -> + if time.toString() is 'Invalid Date' + @setShadowTimestamp(item, attribute) + return + + day = time.getDate() + month = time.getMonth()+1 + year = time.getFullYear() + item.find('[data-item=day]').val(day) + item.find('[data-item=month]').val(month) + item.find('[data-item=year]').val(year) + @setShadowTimestamp(item, attribute, time) + + @getParams: (item) -> + params = {} + params.day = item.find('[data-item=day]').val() + params.month = item.find('[data-item=month]').val() + params.year = item.find('[data-item=year]').val() + params + + @validation: (item, attribute, runtime) -> + + # remove old validation + 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('') + + params = @getParams(item) + + # check required attributes + errors = {} + if !runtime && !attribute.null + if params.day is '' errors.day = 'missing' - if !month + if params.month is '' errors.month = 'missing' - if !year + if params.year is '' errors.year = 'missing' - # ranges - if day - daysInMonth = 31 - if month && year - daysInMonth = new Date(year, month, 0).getDate(); + # ranges + if params.day + daysInMonth = 31 + if params.month && params.year + daysInMonth = new Date(params.year, params.month, 0).getDate() - if parseInt(day).toString() is 'NaN' - errors.day = 'invalid' - else if parseInt(day) > daysInMonth || parseInt(day) < 1 - errors.day = 'invalid' + if isNaN( Number(params.day) ) + errors.day = 'invalid' + else if Number(params.day) > daysInMonth || Number(params.day) < 1 + errors.day = 'invalid' - if month - if parseInt(month).toString() is 'NaN' - errors.month = 'invalid' - else if parseInt(month) > 12 || parseInt(month) < 1 - errors.month = 'invalid' + if params.month + if isNaN( Number(params.month) ) + errors.month = 'invalid' + else if Number(params.month) > 12 || Number(params.month) < 1 + errors.month = 'invalid' - if year - if parseInt(year).toString() is 'NaN' - errors.year = 'invalid' - else if parseInt(year) > 2100 || parseInt(year) < 2001 - errors.year = 'invalid' + if params.year + if isNaN( Number(params.year) ) + errors.year = 'invalid' + else if Number(params.year) > 2200 || Number(params.year) < 2001 + errors.year = 'invalid' - if !_.isEmpty(errors) - # if field is required, if not do not show error - if year is '' && day is '' && month - if attribute.null - e.preventDefault() - e.stopPropagation() - return - else - item.closest('.form-group').find('.help-inline').text( 'is required' ) + #formGroup = item.closest('.form-group') + formGroup = item + if !_.isEmpty(errors) - # show invalid options - for key, value of errors - item.closest('.form-group').addClass('has-error') - item.closest('.form-group').find("[name=\"#{fieldPrefix}___#{key}\"]").addClass('has-error') - #item.closest('.form-group').find('.help-inline').text( value ) - - e.preventDefault() - e.stopPropagation() + # if field is required, if not do not show error + if params.year is '' && params.day is '' && params.month is '' + return if attribute.null + item.closest('.form-group').addClass('has-error') + item.closest('.form-group').find('.help-inline').text( 'is required' ) return - ) - item \ No newline at end of file + # show invalid options + for key, value of errors + formGroup.addClass('has-error') + formGroup.find("[data-item=#{key}]").addClass('has-error') + + return diff --git a/app/assets/javascripts/app/controllers/_ui_element/datetime.js.coffee b/app/assets/javascripts/app/controllers/_ui_element/datetime.js.coffee index e806b76f4..2f1c8decb 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/datetime.js.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/datetime.js.coffee @@ -1,20 +1,25 @@ class App.UiElement.datetime - @render: (attribute) -> + @render: (attributeOrig) -> - # set data type - if attribute.name - attribute.nameRaw = attribute.name - attribute.name = '{datetime}' + attribute.name + attribute = _.clone(attributeOrig) + attribute.nameRaw = attribute.name + attribute.name = "{datetime}#{attribute.name}" + + # get time object if attribute.value - if typeof( attribute.value ) is 'string' - unixtime = new Date( Date.parse( attribute.value ) ) + if typeof attribute.value is 'string' + time = new Date( Date.parse( attribute.value ) ) else - unixtime = new Date( attribute.value ) - year = unixtime.getFullYear() - month = unixtime.getMonth() + 1 - day = unixtime.getDate() - hour = unixtime.getHours() - minute = unixtime.getMinutes() + time = new Date( attribute.value ) + + # time items + year = time.getFullYear() + month = time.getMonth() + 1 + day = time.getDate() + hour = time.getHours() + minute = time.getMinutes() + + # create element item = $( App.view('generic/datetime')( attribute: attribute year: year @@ -24,149 +29,183 @@ class App.UiElement.datetime minute: minute ) ) - setNewTime = (diff, el, reset) -> - name = $(el).closest('.form-group').find('[data-name]').attr('data-name') - - # remove old validation - item.find('.has-error').removeClass('has-error') - item.closest('.form-group').find('.help-inline').html('') - - day = item.closest('.form-group').find("[name=\"{datetime}#{name}___day\"]").val() - month = item.closest('.form-group').find("[name=\"{datetime}#{name}___month\"]").val() - year = item.closest('.form-group').find("[name=\"{datetime}#{name}___year\"]").val() - hour = item.closest('.form-group').find("[name=\"{datetime}#{name}___hour\"]").val() - minute = item.closest('.form-group').find("[name=\"{datetime}#{name}___minute\"]").val() - format = (number) -> - if parseInt(number) < 10 - number = "0#{number}" - number - if !reset && (year isnt '' && month isnt '' && day isnt '' && hour isnt '' && day isnt '') - time = new Date( Date.parse( "#{year}-#{format(month)}-#{format(day)}T#{format(hour)}:#{format(minute)}:00Z" ) ) - time.setMinutes( time.getMinutes() + diff + time.getTimezoneOffset() ) - else - time = new Date() - time.setMinutes( time.getMinutes() + diff ) - #console.log('T', time, time.getHours(), time.getMinutes()) - item.closest('.form-group').find("[name=\"{datetime}#{name}___day\"]").val( time.getDate() ) - item.closest('.form-group').find("[name=\"{datetime}#{name}___month\"]").val( time.getMonth()+1 ) - item.closest('.form-group').find("[name=\"{datetime}#{name}___year\"]").val( time.getFullYear() ) - item.closest('.form-group').find("[name=\"{datetime}#{name}___hour\"]").val( time.getHours() ) - item.closest('.form-group').find("[name=\"{datetime}#{name}___minute\"]").val( time.getMinutes() ) - - item.find('.js-today').bind('click', (e) -> + # start bindings + item.find('.js-today').bind('click', (e) => e.preventDefault() - setNewTime(0, @, true) + @setNewTime(item, attribute, 0, true) + @validation(item, attribute) ) - item.find('.js-plus-hour').bind('click', (e) -> + item.find('.js-plus-hour').bind('click', (e) => e.preventDefault() - setNewTime(60, @) + @setNewTime(item, attribute, 60) + @validation(item, attribute) ) - item.find('.js-minus-hour').bind('click', (e) -> + item.find('.js-minus-hour').bind('click', (e) => e.preventDefault() - setNewTime(-60, @) + @setNewTime(item, attribute, -60) + @validation(item, attribute) ) - item.find('.js-plus-day').bind('click', (e) -> + item.find('.js-plus-day').bind('click', (e) => e.preventDefault() - setNewTime(60 * 24, @) + @setNewTime(item, attribute, 60 * 24) + @validation(item, attribute) ) - item.find('.js-minus-day').bind('click', (e) -> + item.find('.js-minus-day').bind('click', (e) => e.preventDefault() - setNewTime(-60 * 24, @) + @setNewTime(item, attribute, -60 * 24) + @validation(item, attribute) ) - item.find('.js-plus-week').bind('click', (e) -> + item.find('.js-plus-week').bind('click', (e) => e.preventDefault() - setNewTime(60 * 24 * 7, @) + @setNewTime(item, attribute, 60 * 24 * 7) + @validation(item, attribute) ) - item.find('.js-minus-week').bind('click', (e) -> + item.find('.js-minus-week').bind('click', (e) => e.preventDefault() - setNewTime(-60 * 24 * 7, @) + @setNewTime(item, attribute, -60 * 24 * 7) + @validation(item, attribute) ) - - item.find('input').bind('keyup blur focus change', (e) -> - - # do validation - name = $(@).attr('name') - if name - fieldPrefix = name.split('___')[0] - - # remove old validation - item.find('.has-error').removeClass('has-error') - item.closest('.form-group').find('.help-inline').html('') - - day = item.closest('.form-group').find("[name=\"#{fieldPrefix}___day\"]").val() - month = item.closest('.form-group').find("[name=\"#{fieldPrefix}___month\"]").val() - year = item.closest('.form-group').find("[name=\"#{fieldPrefix}___year\"]").val() - hour = item.closest('.form-group').find("[name=\"#{fieldPrefix}___hour\"]").val() - minute = item.closest('.form-group').find("[name=\"#{fieldPrefix}___minute\"]").val() - - # validate exists - errors = {} - if !day - errors.day = 'missing' - if !month - errors.month = 'missing' - if !year - errors.year = 'missing' - if !hour - errors.hour = 'missing' - if !minute - errors.minute = 'missing' - - # ranges - if day - daysInMonth = 31 - if month && year - daysInMonth = new Date(year, month, 0).getDate(); - - if parseInt(day).toString() is 'NaN' - errors.day = 'invalid' - else if parseInt(day) > daysInMonth || parseInt(day) < 1 - errors.day = 'invalid' - - if month - if parseInt(month).toString() is 'NaN' - errors.month = 'invalid' - else if parseInt(month) > 12 || parseInt(month) < 1 - errors.month = 'invalid' - - if year - if parseInt(year).toString() is 'NaN' - errors.year = 'invalid' - else if parseInt(year) > 2100 || parseInt(year) < 2001 - errors.year = 'invalid' - - if hour - if parseInt(hour).toString() is 'NaN' - errors.hour = 'invalid' - else if parseInt(hour) > 23 || parseInt(hour) < 0 - errors.hour = 'invalid' - - if minute - if parseInt(minute).toString() is 'NaN' - errors.minute = 'invalid' - else if parseInt(minute) > 59 - errors.minute = 'invalid' - - if !_.isEmpty(errors) - - # if field is required, if not do not show error - if year is '' && day is '' && month is '' && hour is '' && minute is '' - if attribute.null - e.preventDefault() - e.stopPropagation() - return - else - item.closest('.form-group').find('.help-inline').text( 'is required' ) - - # show invalid options - for key, value of errors - item.closest('.form-group').addClass('has-error') - item.closest('.form-group').find("[name=\"#{fieldPrefix}___#{key}\"]").addClass('has-error') - #item.closest('.form-group').find('.help-inline').text( value ) - - e.preventDefault() - e.stopPropagation() - return + item.find('input').bind('keyup blur focus change', (e) => + @setNewTime(item, attribute, 0) + @validation(item, attribute, true) ) + item.bind('validate', (e) => + @validation(item, attribute) + ) + #setShadowTimestamp() + @setNewTime(item, attribute, 0) item + + @format: (number) -> + if parseInt(number) < 10 + number = "0#{number}" + number + + @setNewTime: (item, attribute, diff, reset = false) -> + + # remove old validation + #item.find('.has-error').removeClass('has-error') + #item.closest('.form-group').find('.help-inline').html('') + + if reset + time = new Date() + time.setMinutes( time.getMinutes() + diff ) + @setParams(item, attribute, time) + return + + params = @getParams(item) + return if params.year is '' && params.month is '' && params.day is '' && params.hour is '' && params.day is '' + time = new Date( Date.parse( "#{params.year}-#{@format(params.month)}-#{@format(params.day)}T#{@format(params.hour)}:#{@format(params.minute)}:00Z" ) ) + time.setMinutes( time.getMinutes() + diff + time.getTimezoneOffset() ) + return if !time + @setParams(item, attribute, time) + + @setShadowTimestamp: (item, attribute, time) -> + timestamp = '' + if time + timestamp = time.toISOString().replace(/\d\d\.\d\d\dZ$/, '00.000Z') + item.find("[name=\"#{attribute.name}\"]").val(timestamp) + + @setParams: (item, attribute, time) -> + if time.toString() is 'Invalid Date' + @setShadowTimestamp(item, attribute) + return + + day = time.getDate() + month = time.getMonth()+1 + year = time.getFullYear() + hour = time.getHours() + minute = time.getMinutes() + item.find('[data-item=day]').val(day) + item.find('[data-item=month]').val(month) + item.find('[data-item=year]').val(year) + item.find('[data-item=hour]').val(hour) + item.find('[data-item=minute]').val(minute) + @setShadowTimestamp(item, attribute, time) + + @getParams: (item) -> + params = {} + params.day = item.find('[data-item=day]').val() + params.month = item.find('[data-item=month]').val() + params.year = item.find('[data-item=year]').val() + params.hour = item.find('[data-item=hour]').val() + params.minute = item.find('[data-item=minute]').val() + params + + @validation: (item, attribute, runtime) -> + + # remove old validation + 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('') + + params = @getParams(item) + + # check required attributes + errors = {} + if !runtime && !attribute.null + if params.day is '' + errors.day = 'missing' + if params.month is '' + errors.month = 'missing' + if params.year is '' + errors.year = 'missing' + if params.hour is '' + errors.hour = 'missing' + if params.minute is '' + errors.minute = 'missing' + + # ranges + if params.day + daysInMonth = 31 + if params.month && params.year + daysInMonth = new Date(params.year, params.month, 0).getDate() + + if isNaN( Number(params.day) ) + errors.day = 'invalid' + else if Number(params.day) > daysInMonth || Number(params.day) < 1 + errors.day = 'invalid' + + if params.month + if isNaN( Number(params.month) ) + errors.month = 'invalid' + else if Number(params.month) > 12 || Number(params.month) < 1 + errors.month = 'invalid' + + if params.year + if isNaN( Number(params.year) ) + errors.year = 'invalid' + else if Number(params.year) > 2200 || Number(params.year) < 2001 + errors.year = 'invalid' + + if params.hour + if isNaN( Number(params.hour) ) + errors.hour = 'invalid' + else if parseInt(params.hour) > 23 || parseInt(params.hour) < 0 + errors.hour = 'invalid' + + if params.minute + if isNaN( Number(params.minute) ) + errors.minute = 'invalid' + else if Number(params.minute) > 59 + errors.minute = 'invalid' + + #formGroup = item.closest('.form-group') + formGroup = item + if !_.isEmpty(errors) + + # if field is required, if not do not show error + if params.year is '' && params.day is '' && params.month is '' && params.hour is '' && params.minute is '' + return if attribute.null + item.closest('.form-group').addClass('has-error') + item.closest('.form-group').find('.help-inline').text( 'is required' ) + return + + # show invalid options + for key, value of errors + formGroup.addClass('has-error') + formGroup.find("[data-item=#{key}]").addClass('has-error') + + return diff --git a/app/assets/javascripts/app/views/generic/date.jst.eco b/app/assets/javascripts/app/views/generic/date.jst.eco index fe42d59ef..63471172b 100644 --- a/app/assets/javascripts/app/views/generic/date.jst.eco +++ b/app/assets/javascripts/app/views/generic/date.jst.eco @@ -1,14 +1,15 @@ -
- +
+ + . - + . - +
-
-<%- @T('today') %> -| --1 +1 <%- @T('day') %> -| --7 +7 <%- @T('days') %> -
\ No newline at end of file +<% if !@attribute.disable_feature: %> + + <%- @T('today') %> | + -1 +1 <%- @T('day') %> | + -7 +7 <%- @T('days') %> + +<% end %> \ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/datetime.jst.eco b/app/assets/javascripts/app/views/generic/datetime.jst.eco index 15b2a5e84..efa1686d4 100644 --- a/app/assets/javascripts/app/views/generic/datetime.jst.eco +++ b/app/assets/javascripts/app/views/generic/datetime.jst.eco @@ -1,19 +1,19 @@ -
- +
+ + . - + . - - + + : - +
-
-<%- @T('now') %> -| --1 +1 <%- @T('hour') %> -| --1 +1 <%- @T('day') %> -| --7 +7 <%- @T('days') %> -
\ No newline at end of file +<% if !@attribute.disable_feature: %> + + <%- @T('now') %> | + -1 +1 <%- @T('hour') %> | + -1 +1 <%- @T('day') %> | + -7 +7 <%- @T('days') %> + +<% end %> \ No newline at end of file diff --git a/public/assets/tests/form-validation.js b/public/assets/tests/form-validation.js index ef2403093..71f6c7aa9 100644 --- a/public/assets/tests/form-validation.js +++ b/public/assets/tests/form-validation.js @@ -1,4 +1,4 @@ -test( "form validation check", function() { +test( 'form validation check', function() { $('#forms').append('

form params check

') @@ -45,21 +45,19 @@ test( "form validation check", function() { equal( el.find('[data-name="richtext1"]').val(), '', 'check richtext1 value') //equal( el.find('[data-name="richtext1"]').prop('required'), true, 'check richtext1 required') - - params = App.ControllerForm.params( el ) errors = form.validate(params) test_errors = { - input1: "is required", - password1: "is required", - textarea1: "is required", - select1: "is required", - selectmulti1: "is required", - autocompletion1: "is required", - richtext1: "is required", - datetime1: "is required", - date1: "is required", + input1: 'is required', + password1: 'is required', + textarea1: 'is required', + select1: 'is required', + selectmulti1: 'is required', + autocompletion1: 'is required', + richtext1: 'is required', + datetime1: 'is required', + date1: 'is required', } deepEqual( errors, test_errors, 'validation errors check' ) @@ -94,7 +92,7 @@ test( "form validation check", function() { }); -test( "datetime validation check", function() { +test( 'datetime validation check', function() { $('#forms').append('

datetime validation check

') @@ -119,7 +117,7 @@ test( "datetime validation check", function() { errors = form.validate(params) test_errors = { - datetime1: "is required", + datetime1: 'is required', } deepEqual( errors, test_errors, 'validation errors check' ) App.ControllerForm.validate( { errors: errors, form: el } ) @@ -129,14 +127,14 @@ test( "datetime validation check", function() { //equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), '', 'check datetime1 error message') // set new values - el.find('[name="{datetime}datetime1___day"]').val('1') - el.find('[name="{datetime}datetime1___month"]').val('1') - el.find('[name="{datetime}datetime1___year"]').val('2015') - el.find('[name="{datetime}datetime1___hour"]').val('12') - el.find('[name="{datetime}datetime1___minute"]').val('42') + el.find('[data-name="datetime1"] [data-item="day"]').val(1).trigger('blur') + el.find('[data-name="datetime1"] [data-item="month"]').val(1).trigger('blur') + el.find('[data-name="datetime1"] [data-item="year"]').val(2015).trigger('blur') + el.find('[data-name="datetime1"] [data-item="hour"]').val(12).trigger('blur') + el.find('[data-name="datetime1"] [data-item="minute"]').val(42).trigger('blur') // check params - timeStamp = new Date( Date.parse("2015-01-01T12:42:00.000Z") ) + timeStamp = new Date( Date.parse('2015-01-01T12:42:00.000Z') ) timeStamp.setMinutes( timeStamp.getMinutes() + timeStamp.getTimezoneOffset() ) params = App.ControllerForm.params( el ) test_params = { @@ -153,30 +151,32 @@ test( "datetime validation check", function() { equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), false, 'check datetime1 has-error') equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), '', 'check datetime1 error message') - el.find('[name="{datetime}datetime1___day"]').val('47').blur() - deepEqual( el.find('[name="{datetime}datetime1___day"]').hasClass('has-error'), true ) - el.find('[name="{datetime}datetime1___month"]').val('1').blur() - deepEqual( el.find('[name="{datetime}datetime1___month"]').hasClass('has-error'), false ) - el.find('[name="{datetime}datetime1___year"]').val('2015').blur() - deepEqual( el.find('[name="{datetime}datetime1___year"]').hasClass('has-error'), false ) - el.find('[name="{datetime}datetime1___hour"]').val('12').blur() - deepEqual( el.find('[name="{datetime}datetime1___hour"]').hasClass('has-error'), false ) - el.find('[name="{datetime}datetime1___minute"]').val('42').blur() - deepEqual( el.find('[name="{datetime}datetime1___minute"]').hasClass('has-error'), false ) + el.find('[data-name="datetime1"] [data-item="day"]').val('47').trigger('blur') + deepEqual( el.find('[data-name="datetime1"] [data-item="day"]').hasClass('has-error'), true ) + el.find('[data-name="datetime1"] [data-item="month"]').val('1').trigger('blur') + deepEqual( el.find('[data-name="datetime1"] [data-item="month"]').hasClass('has-error'), false ) + el.find('[data-name="datetime1"] [data-item="year"]').val('2015').trigger('blur') + deepEqual( el.find('[data-name="datetime1"] [data-item="year"]').hasClass('has-error'), false ) + el.find('[data-name="datetime1"] [data-item="hour"]').val('12').trigger('blur') + deepEqual( el.find('[data-name="datetime1"] [data-item="hour"]').hasClass('has-error'), false ) + el.find('[data-name="datetime1"] [data-item="minute"]').val('42').trigger('blur') + deepEqual( el.find('[data-name="datetime1"] [data-item="minute"]').hasClass('has-error'), false ) params = App.ControllerForm.params( el ) errors = form.validate(params) test_errors = { - datetime1: "invalid", + datetime1: 'is required', } deepEqual( errors, test_errors, 'validation errors check' ) App.ControllerForm.validate( { errors: errors, form: el } ) - equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), true, 'check datetime1 has-error') - equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), 'invalid', 'check datetime1 error message') + equal( el.find('[data-name="datetime1"]').closest('.form-group').hasClass('has-error'), false, 'check datetime1 no has-error') + equal( el.find('[data-name="datetime1"] [data-item="day"]').hasClass('has-error'), true, 'check datetime1 no has-error') + equal( el.find('[data-name="datetime1"] [data-item="month"]').hasClass('has-error'), false, 'check datetime1 no has-error') + equal( el.find('[data-name="datetime1"]').closest('.form-group').find('.help-inline').text(), '', 'check datetime1 error message') }); -test( "date validation check", function() { +test( 'date validation check', function() { $('#forms').append('

date validation check

') @@ -203,24 +203,23 @@ test( "date validation check", function() { errors = form.validate(params) test_errors = { - date1: "is required", + date1: 'is required', } deepEqual( errors, test_errors, 'validation errors check' ) App.ControllerForm.validate( { errors: errors, form: el } ) equal( el.find('[data-name="date1"]').closest('.form-group').hasClass('has-error'), true, 'check date1 has-error') - //equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), '', 'check date1 error message') equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), 'is required', 'check date1 error message') // set new values - el.find('[name="{date}date1___day"]').val('1') - el.find('[name="{date}date1___month"]').val('1') - el.find('[name="{date}date1___year"]').val('2015') + el.find('[data-name="date1"] [data-item="day"]').val('1').trigger('blur') + el.find('[data-name="date1"] [data-item="month"]').val('1').trigger('blur') + el.find('[data-name="date1"] [data-item="year"]').val('2015').trigger('blur') // check params params = App.ControllerForm.params( el ) test_params = { - date1: "2015-01-01", + date1: '2015-01-01', } deepEqual( params, test_params, 'params check' ) @@ -233,29 +232,32 @@ test( "date validation check", function() { equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), '', 'check date1 error message') // set invalid values - el.find('[name="{date}date1___day"]').val('47').blur() - deepEqual( el.find('[name="{date}date1___day"]').hasClass('has-error'), true ) - el.find('[name="{date}date1___month"]').val('1').blur() - deepEqual( el.find('[name="{date}date1___month"]').hasClass('has-error'), false ) - el.find('[name="{date}date1___year"]').val('2015').blur() - deepEqual( el.find('[name="{date}date1___year"]').hasClass('has-error'), false ) + el.find('[data-name="date1"] [data-item="day"]').val('47').trigger('blur') + deepEqual( el.find('[data-name="date1"] [data-item="day"]').hasClass('has-error'), true ) + el.find('[data-name="date1"] [data-item="month"]').val('1').trigger('blur') + deepEqual( el.find('[data-name="date1"] [data-item="month"]').hasClass('has-error'), false ) + el.find('[data-name="date1"] [data-item="year"]').val('2015').trigger('blur') + deepEqual( el.find('[data-name="date1"] [data-item="year"]').hasClass('has-error'), false ) // check params params = App.ControllerForm.params( el ) test_params = { - date1: 'invalid', + date1: undefined, } deepEqual( params, test_params, 'params check' ) // check errors errors = form.validate(params) test_errors = { - date1: 'invalid', + date1: 'is required', } deepEqual( errors, test_errors, 'validation errors check' ) App.ControllerForm.validate( { errors: errors, form: el } ) - equal( el.find('[data-name="date1"]').closest('.form-group').hasClass('has-error'), true, 'check date1 has-error') - equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), 'invalid', 'check date1 error message') + + equal( el.find('[data-name="date1"]').closest('.form-group').hasClass('has-error'), false, 'check date1 no has-error') + equal( el.find('[data-name="date1"] [data-item="day"]').hasClass('has-error'), true, 'check date1 no has-error') + equal( el.find('[data-name="date1"] [data-item="month"]').hasClass('has-error'), false, 'check date1 no has-error') + equal( el.find('[data-name="date1"]').closest('.form-group').find('.help-inline').text(), '', 'check date1 error message') });