| 1 | {{define "title"}}{{.Title}}{{end}} |
| 2 | {{define "content"}} |
| 3 | <header rst-page-header> |
| 4 | <div rst-page-header-titles> |
| 5 | <h1>{{.Data.Heading}}</h1> |
| 6 | </div> |
| 7 | </header> |
| 8 | |
| 9 | {{with .Data.Error}} |
| 10 | {{template "callout" dict "Tone" "negative" "Body" . "Alert" true}} |
| 11 | {{end}} |
| 12 | |
| 13 | <form rst-form method="post" action="{{.Data.Action}}"> |
| 14 | {{if and .Data.Series .Data.Occurrence}} |
| 15 | <input type="hidden" name="occurrence" value="{{.Data.Occurrence}}"> |
| 16 | {{/* Asked BEFORE the fields, not after: which occurrences this |
| 17 | applies to changes what every field below means. "Just this one" |
| 18 | is first and checked, because an edit that silently changed a |
| 19 | year of standups is the most expensive default in the app. */}} |
| 20 | {{template "choice-field" dict |
| 21 | "Legend" "This repeats. What should this change?" |
| 22 | "Name" "scope" |
| 23 | "Type" "radio" |
| 24 | "Options" (list |
| 25 | (dict "Value" "this" "Title" "Just this one" |
| 26 | "Desc" "The rest of the series keeps its current time and details." |
| 27 | "Checked" true) |
| 28 | (dict "Value" "following" "Title" "This one and everything after it" |
| 29 | "Desc" "Earlier occurrences are left alone. The series is split in two from here.") |
| 30 | (dict "Value" "all" "Title" "Every occurrence" |
| 31 | "Desc" "Past ones included."))}} |
| 32 | {{end}} |
| 33 | {{template "field" dict |
| 34 | "ID" "title" "Name" "title" "Label" "What is it?" |
| 35 | "Value" .Data.EventTitle "Required" true "Autofocus" true |
| 36 | "Error" (if_eq .Data.ErrorField "title" .Data.Error)}} |
| 37 | |
| 38 | {{if .Data.Booked}} |
| 39 | {{/* A BOOKED meeting's scheduling belongs to the person who booked |
| 40 | it (booking spec B18). The controls are shown disabled, and the |
| 41 | stored values ride along as hidden inputs — a disabled control |
| 42 | submits nothing, and a title-only save has to submit exactly |
| 43 | what is stored to pass the comparison (B25). tz is the EVENT's |
| 44 | own, not the host's profile zone. */}} |
| 45 | <input type="hidden" name="start" value="{{.Data.StartLocal}}"> |
| 46 | <input type="hidden" name="end" value="{{.Data.EndLocal}}"> |
| 47 | <input type="hidden" name="tz" value="{{.Data.TZ}}"> |
| 48 | <input type="hidden" name="kind" value="{{.Data.Kind}}"> |
| 49 | <input type="hidden" name="repeat" value="none"> |
| 50 | {{if .Data.AllDay}}<input type="hidden" name="all_day" value="1">{{end}} |
| 51 | <div rst-field cal-booked-lock> |
| 52 | <label rst-field-label for="start-locked">Starts</label> |
| 53 | <input rst-input id="start-locked" type="datetime-local" value="{{.Data.StartLocal}}" disabled> |
| 54 | <label rst-field-label for="end-locked">Ends</label> |
| 55 | <input rst-input id="end-locked" type="datetime-local" value="{{.Data.EndLocal}}" disabled> |
| 56 | <label rst-field-label for="tz-locked">Zone</label> |
| 57 | <input rst-input="short" id="tz-locked" type="text" value="{{.Data.TZ}}" disabled> |
| 58 | <label rst-field-label for="kind-locked">Kind</label> |
| 59 | <input rst-input="short" id="kind-locked" type="text" value="{{.Data.Kind}}" disabled> |
| 60 | <label rst-switch><input type="checkbox" disabled{{if .Data.AllDay}} checked{{end}}><span rst-switch-track aria-hidden="true"></span> All day</label> |
| 61 | <label rst-field-label for="repeat-locked">Repeats</label> |
| 62 | <input rst-input="short" id="repeat-locked" type="text" value="Never" disabled> |
| 63 | <small rst-field-hint>This is a booked meeting{{with .Data.BookedBy}} with {{.}}{{end}}. Its time is changed by the person who booked it, or by cancelling and letting them rebook.</small> |
| 64 | {{with (if_eq .Data.ErrorField "start" .Data.Error)}}<small rst-field-error>{{.}}</small>{{end}} |
| 65 | </div> |
| 66 | {{else}} |
| 67 | {{/* Three kinds, one radio group, and the descriptions say what the |
| 68 | difference actually is — because "meeting / commitment / note" |
| 69 | without them is three words nobody can choose between. They |
| 70 | differ in reminder defaults, in whether they count toward the |
| 71 | day's booked hours, and in how they draw. */}} |
| 72 | {{template "choice-field" dict |
| 73 | "Legend" "What kind of thing?" |
| 74 | "Name" "kind" |
| 75 | "Type" "radio" |
| 76 | "Options" (list |
| 77 | (dict "Value" "meeting" "Title" "A meeting" |
| 78 | "Desc" "Other people are in it. Being late matters." |
| 79 | "Checked" (eq .Data.Kind "meeting")) |
| 80 | (dict "Value" "commitment" "Title" "A commitment" |
| 81 | "Desc" "Time you have promised yourself. It fills the day, but only you are inconvenienced when it moves." |
| 82 | "Checked" (eq .Data.Kind "commitment")) |
| 83 | (dict "Value" "note" "Title" "A note" |
| 84 | "Desc" "True of the day without occupying any of it — a birthday, a deadline, a bin collection." |
| 85 | "Checked" (eq .Data.Kind "note")))}} |
| 86 | |
| 87 | {{template "field-check" dict |
| 88 | "Name" "all_day" "Value" "1" "Label" "All day" "Checked" .Data.AllDay}} |
| 89 | |
| 90 | {{/* An all-day event's times are DATES, and a datetime-local input |
| 91 | refuses a bare date: it renders blank, and the form then cannot |
| 92 | be saved without retyping both. So an all-day event gets date |
| 93 | inputs. Ticking All day without script cannot swap the input, |
| 94 | which is why readEventForm takes either shape. |
| 95 | datetime.js enhances both into a picker with natural-language |
| 96 | parsing. Without it they are ordinary inputs, which is a |
| 97 | working floor. */}} |
| 98 | {{if .Data.AllDay}} |
| 99 | {{template "field-date" dict |
| 100 | "Name" "start" "Label" "Starts" "Value" .Data.StartLocal "Required" true |
| 101 | "Error" (if_eq .Data.ErrorField "start" .Data.Error)}} |
| 102 | {{template "field-date" dict |
| 103 | "Name" "end" "Label" "Ends" "Value" .Data.EndLocal "Required" true |
| 104 | "Hint" "The end is exclusive: an all-day event on the 2nd ends on the 3rd." |
| 105 | "Error" (if_eq .Data.ErrorField "end" .Data.Error)}} |
| 106 | {{else}} |
| 107 | {{template "field-datetime" dict |
| 108 | "Name" "start" "Label" "Starts" "Value" .Data.StartLocal "Required" true |
| 109 | "Error" (if_eq .Data.ErrorField "start" .Data.Error)}} |
| 110 | {{template "field-datetime" dict |
| 111 | "Name" "end" "Label" "Ends" "Value" .Data.EndLocal "Required" true |
| 112 | "Hint" "The end is exclusive: an all-day event on the 2nd ends on the 3rd." |
| 113 | "Error" (if_eq .Data.ErrorField "end" .Data.Error)}} |
| 114 | {{end}} |
| 115 | |
| 116 | {{template "field-select" dict |
| 117 | "ID" "repeat" "Name" "repeat" "Label" "Repeats" |
| 118 | "Options" (repeatOptions .Data.StartLocal .Data.TZ .Data.AllDay .Data.Repeat)}} |
| 119 | |
| 120 | {{template "field-date" dict |
| 121 | "Name" "repeat_end" "Label" "Repeat until" "Value" .Data.RepeatEnd |
| 122 | "Hint" "Leave empty for a series with no end."}} |
| 123 | {{end}} |
| 124 | |
| 125 | {{template "field" dict |
| 126 | "ID" "location" "Name" "location" "Label" "Where" "Value" .Data.Location}} |
| 127 | |
| 128 | {{template "field-textarea" dict |
| 129 | "Name" "notes" "Label" "Notes" "Value" .Data.Notes "Rows" 4}} |
| 130 | |
| 131 | {{template "field-select" dict |
| 132 | "ID" "calendar_id" "Name" "calendar_id" "Label" "Calendar" |
| 133 | "Options" (calendarOptions .Data.Calendars .Data.CalendarID)}} |
| 134 | |
| 135 | {{template "field-select" dict |
| 136 | "ID" "status" "Name" "status" "Label" "Status" |
| 137 | "Error" (if_eq .Data.ErrorField "status" .Data.Error) |
| 138 | "Options" (list |
| 139 | (dict "Value" "confirmed" "Label" "Confirmed" "Selected" (eq .Data.Status "confirmed")) |
| 140 | (dict "Value" "tentative" "Label" "Tentative" "Selected" (eq .Data.Status "tentative")) |
| 141 | (dict "Value" "cancelled" "Label" "Cancelled" "Selected" (eq .Data.Status "cancelled")))}} |
| 142 | |
| 143 | {{template "form-foot" dict |
| 144 | "Submit" .Data.Submit |
| 145 | "CancelHref" (eventCancelHref .Data.EventID) |
| 146 | "CancelLabel" "Cancel"}} |
| 147 | </form> |
| 148 | {{end}} |
| 149 | |