fix calendar event creation creating undated events

test plan:
 - preconfiguration variants:
   - with & without user set to a different timezone
   - with & without different locales (e.g. Japanese)
 * navigate to the calendar
 * click on a day to begin creating an event
 * fill in the date and start/end times
   - with & without valid start/end times
 * click 'More Options'
   - ensure the edit page includes start/end times as typed
   - correct invalid start/end times, if necessary
 * click 'Update Event'
   - ensure the event appears on the calendar with the correct date/time
 * click on a day to begin creating another event
 * fill in the date and start/end times
 * click 'Submit'
   - ensure the event appears on the calendar with the correct date/time

fixes CNVS-11067

Change-Id: I31f6b1d7550b166a90c45d3f02132379c6dd7459
Reviewed-on: https://gerrit.instructure.com/40374
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Joel Hough <joel@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Steven Shepherd <sshepherd@instructure.com>
Product-Review: Janelle Seegmiller <jseegmiller@instructure.com>
This commit is contained in:
Mark Severson 2014-09-02 10:25:54 -06:00
parent c00c732f54
commit 80e06448bf
4 changed files with 92 additions and 42 deletions

View File

@ -23,8 +23,8 @@ define [
filtered
_hasValidInputs: (o) ->
# has a date, and either has both a start and end time or neither
o.start_date && (!!o.start_time == !!o.end_time)
# has a start_at or has a date and either has both a start and end time or neither
(!!o.start_at) || (o.start_date && (!!o.start_time == !!o.end_time))
toJSON: ->
{calendar_event: @_filterAttributes(super)}

View File

@ -1,5 +1,7 @@
define [
'jquery'
'underscore'
'timezone'
'compiled/calendar/commonEventFactory'
'compiled/calendar/TimeBlockList'
'jst/calendar/editCalendarEvent'
@ -7,7 +9,7 @@ define [
'jquery.instructure_forms'
'jquery.instructure_misc_helpers'
'vendor/date'
], ($, commonEventFactory, TimeBlockList, editCalendarEventTemplate) ->
], ($, _, tz, commonEventFactory, TimeBlockList, editCalendarEventTemplate) ->
class EditCalendarEventDetails
constructor: (selector, @event, @contextChangeCB, @closeCB) ->
@ -40,18 +42,44 @@ define [
activate: () =>
@form.find("select.context_id").change()
getFormData: =>
data = @form.getFormData(object_name: 'calendar_event')
data = _.omit(data, 'date', 'start_time', 'end_time')
date = @form.find('input[name=date]').data('date')
if date
start_time = @form.find('input[name=start_time]').data('date')
start_at = date.toString('yyyy-MM-dd')
start_at += start_time.toString(' HH:mm') if start_time
data.start_at = tz.parse(start_at)
end_time = @form.find('input[name=end_time]').data('date')
end_at = date.toString('yyyy-MM-dd')
end_at += end_time.toString(' HH:mm') if end_time
data.end_at = tz.parse(end_at)
data
moreOptionsClick: (jsEvent) =>
return if @event.object.parent_event_id
jsEvent.preventDefault()
pieces = $(jsEvent.target).attr('href').split("#")
data = $("#edit_calendar_event_form").getFormData(object_name: 'calendar_event')
params = {}
params = return_to: window.location.href
data = @getFormData()
# override parsed input with user input (for 'More Options' only)
data.start_date = @form.find('input[name=date]').val()
data.start_time = @form.find('input[name=start_time]').val()
data.end_time = @form.find('input[name=end_time]').val()
if data.title then params['title'] = data.title
if data.location_name then params['location_name'] = data.location_name
if data.date
params['start_at'] = "#{data.date} #{data.start_time || ''}"
params['end_at'] = "#{data.date} #{data.end_time || ''}"
params['return_to'] = window.location.href
if data.start_date then params['start_date'] = data.start_date
if data.start_time then params['start_time'] = data.start_time
if data.end_time then params['end_time'] = data.end_time
pieces = $(jsEvent.target).attr('href').split("#")
pieces[0] += "?" + $.param(params)
window.location.href = pieces.join("#")
@ -119,23 +147,13 @@ define [
formSubmit: (jsEvent) =>
jsEvent.preventDefault()
data = @form.getFormData({ object_name: 'calendar_event' })
if data.date
start_date = Date.parse "#{data.date} #{data.start_time}"
data.end_time ?= data.start_time
end_date = Date.parse "#{data.date} #{data.end_time}"
else
start_date = null
end_date = null
if data.location_name
location_name = data.location_name
else
location_name = ''
data = @getFormData()
location_name = data.location_name || ''
params = {
'calendar_event[title]': data.title ? @event.title
'calendar_event[start_at]': if start_date then $.unfudgeDateForProfileTimezone(start_date).toISOString() else ''
'calendar_event[end_at]': if end_date then $.unfudgeDateForProfileTimezone(end_date).toISOString() else ''
'calendar_event[start_at]': if data.start_at then data.start_at.toISOString() else ''
'calendar_event[end_at]': if data.end_at then data.end_at.toISOString() else ''
'calendar_event[location_name]': location_name
}
@ -144,16 +162,18 @@ define [
objectData =
calendar_event:
title: params['calendar_event[title]']
start_at: if start_date then start_date.toISOString() else null
end_at: if end_date then end_date.toISOString() else null
start_at: if data.start_at then data.start_at.toISOString() else null
end_at: if data.end_at then data.end_at.toISOString() else null
location_name: location_name
context_code: @form.find(".context_id").val()
newEvent = commonEventFactory(objectData, @event.possibleContexts())
newEvent.save(params)
else
@event.title = params['calendar_event[title]']
@event.start = start_date
@event.end = end_date
# I know this seems backward, fudging a date before saving, but the
# event gets all out-of-whack if it's not...
@event.start = $.fudgeDateForProfileTimezone(data.start_at)
@event.end = $.fudgeDateForProfileTimezone(data.end_at)
@event.location_name = location_name
@event.save(params)

View File

@ -2,14 +2,16 @@ define [
'jquery'
'underscore'
'i18n!calendar.edit'
'timezone'
'Backbone'
'jst/calendar/editCalendarEventFull'
'compiled/views/calendar/MissingDateDialogView'
'wikiSidebar'
'compiled/object/unflatten'
'compiled/util/deparam'
'tinymce.editor_box'
'compiled/tinymce'
], ($, _, I18n, Backbone, editCalendarEventFullTemplate, MissingDateDialogView, wikiSidebar, unflatten) ->
], ($, _, I18n, tz, Backbone, editCalendarEventFullTemplate, MissingDateDialogView, wikiSidebar, unflatten, deparam) ->
##
# View for editing a calendar event on it's own page
@ -28,13 +30,21 @@ define [
initialize: ->
super
@model.fetch().done =>
if ENV.NEW_CALENDAR_EVENT_ATTRIBUTES
attrs = @model.parse(ENV.NEW_CALENDAR_EVENT_ATTRIBUTES)
# if start and end are at the beginning of a day, assume it is an all day date
attrs.all_day = !!attrs.start_at?.equals(attrs.end_at) and attrs.start_at.equals(attrs.start_at.clearTime())
@model.set(attrs)
picked_params = _.pick(deparam(), 'start_date', 'start_time', 'end_time', 'title', 'description', 'location_name', 'location_address')
attrs = @model.parse(picked_params)
# if start and end are at the beginning of a day, assume it is an all day date
attrs.all_day = !!attrs.start_at?.equals(attrs.end_at) and attrs.start_at.equals(attrs.start_at.clearTime())
@model.set(attrs)
@render()
# populate inputs with params passed through the url
_.each _.keys(picked_params), (key) =>
$e = @$el.find("input[name='#{key}']")
$e.val(picked_params[key])
$e.change()
@model.on 'change:use_section_dates', @toggleUsingSectionClass
render: =>
@ -78,9 +88,8 @@ define [
submit: (event) ->
event?.preventDefault()
eventData = unflatten @$el.getFormData()
eventData = unflatten @getFormData()
eventData.use_section_dates = eventData.use_section_dates is '1'
_.each [eventData].concat(eventData.child_event_data), @setStartEnd
delete eventData.child_event_data if eventData.remove_child_events == '1'
if $('#use_section_dates').prop('checked')
@ -102,10 +111,33 @@ define [
@$el.disableWhileLoading @model.save eventData, success: =>
@redirectWithMessage I18n.t 'event_saved', 'Event Saved Successfully'
setStartEnd: (obj) ->
return unless obj
obj.start_at = $.unfudgeDateForProfileTimezone(Date.parse obj.start_date+' '+obj.start_time)
obj.end_at = $.unfudgeDateForProfileTimezone(Date.parse obj.start_date+' '+obj.end_time)
getFormData: ->
data = @$el.getFormData()
# pull the true, parsed dates from the inputs to calculate start_at and end_at correctly
keys = _.filter _.keys(data), ( (key) -> /start_date/.test(key) )
_.each keys, (start_date_key) =>
start_time_key = start_date_key.replace(/start_date/, 'start_time')
end_time_key = start_date_key.replace(/start_date/, 'end_time')
start_at_key = start_date_key.replace(/start_date/, 'start_at')
end_at_key = start_date_key.replace(/start_date/, 'end_at')
start_date = @$el.find("[name='#{start_date_key}']").data('date')
start_time = @$el.find("[name='#{start_time_key}']").data('date')
end_time = @$el.find("[name='#{end_time_key}']").data('date')
return unless start_date
data = _.omit(data, start_date_key, start_time_key, end_time_key)
start_at = start_date.toString('yyyy-MM-dd')
start_at += start_time.toString(' HH:mm') if start_time
data[start_at_key] = tz.parse(start_at)
end_at = start_date.toString('yyyy-MM-dd')
end_at += end_time.toString(' HH:mm') if end_time
data[end_at_key] = tz.parse(end_at)
data
@type: 'event'
@title: -> super 'event', 'Event'

View File

@ -12,8 +12,6 @@
event_attrs[:sections_url] = context_url(@context, :api_v1_context_sections_url)
end
js_env :CALENDAR_EVENT => event_attrs
# TODO: we should just do this in the JS
js_env :NEW_CALENDAR_EVENT_ATTRIBUTES => params.slice(:start_at, :end_at, :title, :description, :location_name)
js_bundle :edit_calendar_event
jammit_css :tinymce, :edit_calendar_event_full