New/Edit calendar event page with section support

closes: #7978

test plan:
with cal2 enabled:
* click on event in calendar, hit edit, click "more options"
* you should be at a new page.
* it should have transferred any new description,
  start/end date you entered
* if it's for a course, you should see a checkbox
  "different due date per section", if it's on your own
   or a group cal, should not see that checkbox
* creating event should save properly so:
* verify that all events show up on calendar2
* when you go back to edit any of those events on
  calendar the info should all load on this page again
* when you click "edit" on one of the section events
  on the calendar it should let you edit the info for
  all of the sections not just the one you clicked on.

with calendar 2 disabled:
* make sure you can still create events as you used
 to be able to

Change-Id: I3491a7dbf4103db2f8ae95c9acbdc49597552d2c
Reviewed-on: https://gerrit.instructure.com/10141
Reviewed-by: Jon Jensen <jon@instructure.com>
Tested-by: Hudson <hudson@instructure.com>
This commit is contained in:
Ryan Shaw 2012-04-18 15:44:14 -06:00
parent 7ab81e483a
commit c02556a4e1
8 changed files with 266 additions and 7 deletions

View File

@ -0,0 +1,9 @@
require [
'jquery'
'compiled/calendar/CalendarEvent'
'compiled/calendar/EditEventView'
], ($, CalendarEvent, EditEventView) ->
$ ->
calendarEvent = new CalendarEvent(ENV.CALENDAR_EVENT)
new EditEventView(model: calendarEvent)

View File

@ -0,0 +1,72 @@
define [
'jquery'
'underscore'
'Backbone'
'compiled/str/splitAssetString'
], ($, _, Backbone, splitAssetString) ->
class CalendarEvent extends Backbone.Model
urlRoot: '/api/v1/calendar_events/'
dateAttributes: ['created_at', 'end_at', 'start_at', 'updated_at']
_filterAttributes: (obj) ->
filtered = _(obj).pick 'start_at', 'end_at', 'title',
'description', 'context_code'
if obj.use_section_dates && obj.child_event_data
filtered.child_event_data = _.chain(obj.child_event_data)
.compact()
.filter(@_hasValidInputs)
.map(@_filterAttributes)
.value()
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)
toJSON: (forView) ->
json = super
if forView
json
else
{calendar_event: @_filterAttributes(json)}
fetch: (options = {}) ->
options = _.clone(options)
model = this
success = options.success
delete options.success
error = Backbone.wrapError(options.error, model, options)
delete options.error
if @get('id')
syncDfd = (this.sync || Backbone.sync).call(this, 'read', this, options)
if @get('sections_url')
sectionsDfd = $.getJSON @get('sections_url')
combinedSuccess = (syncArgs=[], sectionArgs=[]) ->
[syncResp, syncStatus, syncXhr] = syncArgs
[sectionsResp] = sectionArgs
calEventData = CalendarEvent.mergeSectionsIntoCalendarEvent(syncResp, sectionsResp)
return false unless model.set(model.parse(calEventData, syncXhr), options)
success?(model, calEventData)
$.when(syncDfd, sectionsDfd)
.fail(error)
.done(combinedSuccess)
@mergeSectionsIntoCalendarEvent = (eventData = {}, sections) ->
eventData.course_sections = sections
eventData.use_section_dates = !!eventData.child_events?.length
_(eventData.child_events).each (child, index) ->
# 'parse' turns string dates into Date objects
child = eventData.child_events[index] = CalendarEvent::parse(child)
sectionId = splitAssetString(child.context_code)[1]
section = _(sections).find (section) -> section.id == sectionId
section.event = child
eventData

View File

@ -0,0 +1,77 @@
define [
'jquery'
'underscore'
'i18n!calendar.edit'
'Backbone'
'jst/calendar/editCalendarEventFull'
'wikiSidebar'
'compiled/object/unflatten'
'tinymce.editor_box'
'compiled/tinymce'
], ($, _, I18n, Backbone, editCalendarEventFullTemplate, wikiSidebar, unflatten) ->
##
# View for editing a calendar event on it's own page
class EditCalendarEventView extends Backbone.View
el: $('#content')
template: editCalendarEventFullTemplate
events:
'submit form': 'submit'
'change [name="use_section_dates"]': 'toggleUseSectionDates'
'click .delete_link': 'destroyModel'
initialize: ->
@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)
@render()
@model.on 'change:use_section_dates', @toggleUsingSectionClass
render: =>
@$el.html @template(@model.toJSON('forView'))
@$(".date_field").date_field()
@$(".time_field").time_field()
$textarea = @$('textarea').editorBox()
wikiSidebar.init() unless wikiSidebar.inited
wikiSidebar.attachToEditor($textarea).show()
this
destroyModel: =>
msg = I18n.t "confirm_delete_calendar_event", "Are you sure you wan to delete this calendar event?"
if confirm(msg)
@$el.disableWhileLoading @model.destroy success: =>
@redirectWithMessage I18n.t('event_deleted', "%{event_title} deleted successfully", event_title: @model.get('title'))
# boilerplate that could be replaced with data bindings
toggleUsingSectionClass: =>
@$('#editCalendarEventFull').toggleClass 'use_section_dates', @model.get('use_section_dates')
toggleUseSectionDates: =>
@model.set 'use_section_dates', !@model.get('use_section_dates')
redirectWithMessage: (message) ->
$.flashMessage message
window.location = @model.get('return_to_url') if @model.get('return_to_url')
submit: (event) ->
event?.preventDefault()
eventData = unflatten @$el.getFormData()
# force use_section_dates to boolean, so it doesnt cause 'change' if it is '1'
eventData.use_section_dates = !!eventData.use_section_dates
_.each [eventData].concat(eventData.child_event_data), @setStartEnd
@$el.disableWhileLoading @model.save eventData, success: ->
@redirectWithMessage I18n.t 'event_saved', 'Event Saved Successfully'
setStartEnd: (obj) ->
return unless obj
obj.start_at = Date.parse obj.start_date+' '+obj.start_time
obj.end_at = Date.parse obj.start_date+' '+obj.end_time

View File

@ -0,0 +1,29 @@
@import environment.sass
#editCalendarEventFull
[name="description"]
width: 100%
min-height: 200px
[name="title"]
width: 100%
font-size: 21px
.date_start_end_row
+clearfix
border
th, td
vertical-align: top
span
float: left
padding: 0px 5px
min-height: 40px
label
font-weight: bold
.show_if_using_sections
display: none
&.use_section_dates
.show_if_using_sections
display: block
.hide_if_using_sections
display: none

View File

@ -1,12 +1,28 @@
<% content_for :page_title do %><%= @event.title || t(:page_title, "New Calendar Event") %><% end %>
<%
content_for :page_title, @event.title || t(:page_title, "New Calendar Event")
return_to_url = clean_return_to(params[:return_to] && params[:return_to].match(/calendar/) && params[:return_to]) || calendar_url_for(@context, :anchor => {:month => (@event.try_rescue(:start_at).try_rescue(:month)), :year => (@event.try_rescue(:start_at).try_rescue(:year))}.to_json)
<% content_for :right_side do %>
if @domain_root_account.enable_scheduler?
event_attrs = {
:id => @event.id,
:context_code => @context.asset_string,
:return_to_url => return_to_url
}
if @context.is_a? Course
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)
js_bundle :edit_calendar_event
jammit_css :tinymce, :edit_calendar_event_full
content_for :right_side, render(:partial => 'shared/wiki_sidebar')
else
content_for :right_side do
%>
<div id="sidebar_content" class="rs-margin-all">
<% if @event && @event.start_at %>
<a class="button button-sidebar-wide return_url calendar_url" href="<%= clean_return_to(params[:return_to] && params[:return_to].match(/calendar/) && params[:return_to]) || calendar_url_for(@context, :anchor => {:month => (@event.try_rescue(:start_at).try_rescue(:month)), :year => (@event.try_rescue(:start_at).try_rescue(:year))}.to_json) %>"><%= image_tag "back.png" %> <%= t 'links.back_to_calendar', "Back to Calendar" %></a>
<% else %>
<a class="button button-sidebar-wide return_url calendar_url" href="<%= clean_return_to(params[:return_to] && params[:return_to].match(/calendar/) && params[:return_to]) || calendar_url_for(@context, :anchor => {:month => (@event.try_rescue(:start_at).try_rescue(:month)), :year => (@event.try_rescue(:start_at).try_rescue(:year))}.to_json) %>"><%= image_tag "back.png" %> <%= t 'links.back_to_calendar', "Back to Calendar" %></a>
<% end %>
<a class="button button-sidebar-wide return_url calendar_url" href="<%= return_to_url %>"><%= image_tag "back.png" %> <%= t 'links.back_to_calendar', "Back to Calendar" %></a>
<a class="base_calendar_url" href="<%= calendar_url_for(@context) %>" style="display: none;">&nbsp;</a>
<% if can_do(@event, @current_user, :update) %>
<div style="margin-top: 10px;">
@ -21,3 +37,4 @@
<% end %>
<%= render :partial => 'full_calendar_event', :object => @event %>
<% end %>

View File

@ -0,0 +1,52 @@
<form id="editCalendarEventFull" class="{{#if use_section_dates}}use_section_dates{{/if}}">
<input class="title" name="title" placeholder="{{#t "event_title"}}Event Title{{/t}}"value="{{title}}"/>
<textarea name="description">{{description}}</textarea>
{{#if course_sections}}
<label><input type="checkbox" name="use_section_dates" value="1" {{#if use_section_dates}}checked{{/if}}>{{#t "different_date_for_each_section"}}Use a different date for each section{{/t}}</label>
{{/if}}
<div class="hide_if_using_sections date_start_end_row">
<span><input name="start_date" class="date_field" value="{{dateToString start_at "MMM d, yyyy"}}" placeholder="{{#t "date"}}Date{{/t}}"/></span>
<span><input name="start_time" class="time_field" {{#unless all_day}} value="{{dateToString start_at "h:mmtt"}}" {{/unless}} placeholder="{{#t "start_time"}}Start Time{{/t}}"/></span>
<span>{{#t "to"}}to{{/t}}</span>
<span><input name="end_time" class="time_field" {{#unless all_day}} value="{{dateToString end_at "h:mmtt"}}" {{/unless}} placeholder="{{#t "end_time"}}End Time{{/t}}"/></span>
</div>
{{#if course_sections}}
<table class="formtable show_if_using_sections">
{{#each course_sections}}
<tr class="date_start_end_row">
<th>
<label for="section_{{id}}_start_date">{{name}}</label>
</th>
<td>
<span><input id="section_{{id}}_start_date" name="child_event_data[{{id}}][start_date]" class="date_field" value="{{dateToString event.start_at "MMM d, yyyy"}}" placeholder="{{#t "date"}}Date{{/t}}"/></span>
<span><input name="child_event_data[{{id}}][start_time]" class="time_field" {{#unless all_day}} value="{{dateToString event.start_at "h:mmtt"}}" {{/unless}} placeholder="{{#t "start_time"}}Start Time{{/t}}"/></span>
<span>{{#t "to"}}to{{/t}}</span>
<span><input name="child_event_data[{{id}}][end_time]" class="time_field" {{#unless all_day}} value="{{dateToString event.end_at "h:mmtt"}}" {{/unless}} placeholder="{{#t "end_time"}}End Time{{/t}}"/></span>
<input type="hidden" name="child_event_data[{{id}}][context_code]" value="course_section_{{id}}">
</td>
</tr>
{{/each}}
</table>
{{/if}}
<div class="button-container">
<button type="submit" class="button {{#if url}} button-default {{/if}}">
{{#if newRecord}}
{{#t "buttons.create"}}Create Event{{/t}}
{{else}}
{{#t "buttons.update"}}Update Event{{/t}}
{{/if}}
</button>
{{#if url}}
<button type="button" class="button delete_link">{{#t "delete"}}Delete{{/t}}</button>
{{/if}}
{{#if return_to_url}}
<a href="{{return_to_url}}" class="button-secondary">{{#t "#buttons.cancel"}}Cancel{{/t}}</button>
{{/if}}
</div>
</form>

View File

@ -228,6 +228,8 @@ stylesheets:
- public/stylesheets/compiled/slideshow.css
alerts:
- public/stylesheets/compiled/alerts.css
edit_calendar_event_full:
- public/stylesheets/compiled/calendar/editCalendarEventFull.css
tinymce:
- public/javascripts/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css
- public/stylesheets/compiled/tiny_like_ck_with_external_tools.css

View File

@ -580,6 +580,7 @@ define([
},
attachToEditor: function($editor) {
wikiSidebar.editor = $($editor);
return wikiSidebar;
}
};