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:
parent
7ab81e483a
commit
c02556a4e1
|
@ -0,0 +1,9 @@
|
||||||
|
require [
|
||||||
|
'jquery'
|
||||||
|
'compiled/calendar/CalendarEvent'
|
||||||
|
'compiled/calendar/EditEventView'
|
||||||
|
], ($, CalendarEvent, EditEventView) ->
|
||||||
|
|
||||||
|
$ ->
|
||||||
|
calendarEvent = new CalendarEvent(ENV.CALENDAR_EVENT)
|
||||||
|
new EditEventView(model: calendarEvent)
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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">
|
<div id="sidebar_content" class="rs-margin-all">
|
||||||
<% if @event && @event.start_at %>
|
<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="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="base_calendar_url" href="<%= calendar_url_for(@context) %>" style="display: none;"> </a>
|
<a class="base_calendar_url" href="<%= calendar_url_for(@context) %>" style="display: none;"> </a>
|
||||||
<% if can_do(@event, @current_user, :update) %>
|
<% if can_do(@event, @current_user, :update) %>
|
||||||
<div style="margin-top: 10px;">
|
<div style="margin-top: 10px;">
|
||||||
|
@ -21,3 +37,4 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render :partial => 'full_calendar_event', :object => @event %>
|
<%= render :partial => 'full_calendar_event', :object => @event %>
|
||||||
|
<% end %>
|
|
@ -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>
|
|
@ -228,6 +228,8 @@ stylesheets:
|
||||||
- public/stylesheets/compiled/slideshow.css
|
- public/stylesheets/compiled/slideshow.css
|
||||||
alerts:
|
alerts:
|
||||||
- public/stylesheets/compiled/alerts.css
|
- public/stylesheets/compiled/alerts.css
|
||||||
|
edit_calendar_event_full:
|
||||||
|
- public/stylesheets/compiled/calendar/editCalendarEventFull.css
|
||||||
tinymce:
|
tinymce:
|
||||||
- public/javascripts/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css
|
- public/javascripts/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css
|
||||||
- public/stylesheets/compiled/tiny_like_ck_with_external_tools.css
|
- public/stylesheets/compiled/tiny_like_ck_with_external_tools.css
|
||||||
|
|
|
@ -580,6 +580,7 @@ define([
|
||||||
},
|
},
|
||||||
attachToEditor: function($editor) {
|
attachToEditor: function($editor) {
|
||||||
wikiSidebar.editor = $($editor);
|
wikiSidebar.editor = $($editor);
|
||||||
|
return wikiSidebar;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue