Compare commits
2 Commits
729b477d44
...
763a6a77c5
Author | SHA1 | Date | |
---|---|---|---|
763a6a77c5 | |||
b9f2254c87 |
86
www/app.js
86
www/app.js
|
@ -117,20 +117,54 @@ async function cloneSchedule(includeAssignments) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('cloneSch').addEventListener('click', async e => {
|
document.getElementById('cloneSch').addEventListener('click', async e => {
|
||||||
cloneSchedule(true);
|
await cloneSchedule(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('cloneSchNoAssignments').addEventListener('click', async e => {
|
document.getElementById('cloneSchNoAssignments').addEventListener('click', async e => {
|
||||||
cloneSchedule(false);
|
await cloneSchedule(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
const titleInput = document.getElementById('title');
|
const titleInput = document.getElementById('title');
|
||||||
|
const schStartTime = document.getElementById('sch_start_time')
|
||||||
|
const schEndTime = document.getElementById('sch_end_time')
|
||||||
|
const schGranularity = document.getElementById('granularity')
|
||||||
let allowEdits = false;
|
let allowEdits = false;
|
||||||
async function updateScheduleSettings() {
|
async function updateScheduleSettings() {
|
||||||
await updateBackupsList();
|
await updateBackupsList();
|
||||||
|
|
||||||
titleInput.value = schedule.base_title;
|
titleInput.value = schedule.base_title;
|
||||||
titleInput.disabled = !allowEdits;
|
schStartTime.value = schedule.start_time.inputValue;
|
||||||
|
schEndTime.value = schedule.end_time.inputValue;
|
||||||
|
schGranularity.value = schedule.granularity.inputValue;
|
||||||
|
|
||||||
|
const daysSpan = document.getElementById('sch-days');
|
||||||
|
utils.clearChildren(daysSpan);
|
||||||
|
for (const day of utils.allDays) {
|
||||||
|
const dayLabel = document.createElement('label');
|
||||||
|
const dayName = utils.DayString(day);
|
||||||
|
const dayCheckbox = document.createElement('input');
|
||||||
|
|
||||||
|
dayCheckbox.type = 'checkbox';
|
||||||
|
dayCheckbox.checked = schedule.all_days.includes(day);
|
||||||
|
dayCheckbox.addEventListener('change', async e => {
|
||||||
|
if (!e.target.checked) {
|
||||||
|
if (schedule.assignments.some(a => day in a.people_by_day)) {
|
||||||
|
alert("Cannot remove schedule for " + dayName
|
||||||
|
+ " because there are events on that day.");
|
||||||
|
e.target.checked = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
schedule.all_days.splice(schedule.all_days.indexOf(day), 1);
|
||||||
|
} else {
|
||||||
|
schedule.all_days = utils.allDays.filter(d => schedule.all_days.includes(d) || d === day)
|
||||||
|
}
|
||||||
|
await saveSchedule();
|
||||||
|
});
|
||||||
|
|
||||||
|
dayLabel.appendChild(dayCheckbox);
|
||||||
|
dayLabel.appendChild(document.createTextNode(dayName));
|
||||||
|
daysSpan.appendChild(dayLabel);
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('scheduleMetadata')
|
document.getElementById('scheduleMetadata')
|
||||||
.querySelectorAll('*')
|
.querySelectorAll('*')
|
||||||
|
@ -292,6 +326,52 @@ document.getElementById('changeTitle').addEventListener('click', async e => {
|
||||||
await saveSchedule();
|
await saveSchedule();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
schStartTime.addEventListener('change', async e => {
|
||||||
|
const newStartTime = utils.Time.fromInputValue(e.target.value);
|
||||||
|
if (schedule.assignments) {
|
||||||
|
const earliestStart = schedule.assignments.map(a => a.start_time).sort((a, b) => a.cmp(b))[0];
|
||||||
|
if (earliestStart.cmp(newStartTime) < 0) {
|
||||||
|
alert("Cannot change start time to " + newStartTime.to12HourString()
|
||||||
|
+ " because it is after the earliest assignment starts at "
|
||||||
|
+ earliestStart.to12HourString() + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
schedule.start_time = newStartTime;
|
||||||
|
await saveSchedule();
|
||||||
|
});
|
||||||
|
|
||||||
|
schEndTime.addEventListener('change', async e => {
|
||||||
|
const newEndTime = utils.Time.fromInputValue(e.target.value);
|
||||||
|
if (schedule.assignments) {
|
||||||
|
const latestEnd = schedule.assignments.map(a => a.end_time).sort((a, b) => b.cmp(a))[0];
|
||||||
|
if (latestEnd.cmp(newEndTime) > 0) {
|
||||||
|
alert("Cannot change end time to " + newEndTime.to12HourString()
|
||||||
|
+ " because it is before the latest assignment ends at "
|
||||||
|
+ latestEnd.to12HourString() + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
schedule.end_time = newEndTime;
|
||||||
|
await saveSchedule();
|
||||||
|
});
|
||||||
|
|
||||||
|
schGranularity.addEventListener('change', async e => {
|
||||||
|
const newGranularity = utils.Time.fromInputValue(e.target.value)
|
||||||
|
.durationSinceMidnight;
|
||||||
|
const schDuration = schedule.timeRange.duration;
|
||||||
|
const newNumRows = schDuration.dividedBy(newGranularity);
|
||||||
|
if (!Number.isInteger(newNumRows)) {
|
||||||
|
alert("Cannot change granularity to " + newGranularity.toString()
|
||||||
|
+ " because it is does not divide the " + schDuration.toString()
|
||||||
|
+ " duration from " + schedule.start_time.to12HourString()
|
||||||
|
+ " to " + schedule.end_time.to12HourString() + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
schedule.granularity = newGranularity;
|
||||||
|
await saveSchedule();
|
||||||
|
});
|
||||||
|
|
||||||
const personInput = document.getElementById('person');
|
const personInput = document.getElementById('person');
|
||||||
|
|
||||||
document.getElementById('addStudent').addEventListener('click', async e => {
|
document.getElementById('addStudent').addEventListener('click', async e => {
|
||||||
|
|
|
@ -39,6 +39,10 @@
|
||||||
<div id="scheduleMetadata">
|
<div id="scheduleMetadata">
|
||||||
<label>Title: <input id="title"></label>
|
<label>Title: <input id="title"></label>
|
||||||
<button id="changeTitle">Change Title</button><br>
|
<button id="changeTitle">Change Title</button><br>
|
||||||
|
<label>Start time: <input type="time" id="sch_start_time"></label><br>
|
||||||
|
<label>End time: <input type="time" id="sch_end_time"></label><br>
|
||||||
|
<label>Granularity: <input type="time" id="granularity"></label><br>
|
||||||
|
Days: <span id="sch-days"></span><br>
|
||||||
<label>Name: <input id="person"></label>
|
<label>Name: <input id="person"></label>
|
||||||
<button id="addTeacher">Add Teacher</button>
|
<button id="addTeacher">Add Teacher</button>
|
||||||
<button id="addStaff">Add Staff</button>
|
<button id="addStaff">Add Staff</button>
|
||||||
|
|
|
@ -57,6 +57,10 @@ export default class Schedule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get timeRange() {
|
||||||
|
return new utils.TimeRange(this);
|
||||||
|
}
|
||||||
|
|
||||||
fullGridFor(day) {
|
fullGridFor(day) {
|
||||||
function timestampString(date) {
|
function timestampString(date) {
|
||||||
function f(format) {
|
function f(format) {
|
||||||
|
|
50
www/utils.js
50
www/utils.js
|
@ -57,10 +57,17 @@ export class Time {
|
||||||
|
|
||||||
export class Duration {
|
export class Duration {
|
||||||
constructor(obj) {
|
constructor(obj) {
|
||||||
this.hour = obj.hour ?? 0;
|
if (obj.total_seconds) {
|
||||||
this.minute = obj.minute ?? 0;
|
this.total_seconds = obj.total_seconds;
|
||||||
this.second = obj.second ?? 0;
|
this.hour = Math.floor(obj.total_seconds / 60 / 60);
|
||||||
this.total_seconds = ((this.hour * 60) + this.minute) * 60 + this.second;
|
this.minute = Math.floor(obj.total_seconds / 60) % 60;
|
||||||
|
this.second = obj.total_seconds % 60;
|
||||||
|
} else {
|
||||||
|
this.hour = obj.hour ?? 0;
|
||||||
|
this.minute = obj.minute ?? 0;
|
||||||
|
this.second = obj.second ?? 0;
|
||||||
|
this.total_seconds = ((this.hour * 60) + this.minute) * 60 + this.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asJsonObject() {
|
asJsonObject() {
|
||||||
|
@ -82,6 +89,25 @@ export class Duration {
|
||||||
const hour = Math.floor(total / 60 / 60);
|
const hour = Math.floor(total / 60 / 60);
|
||||||
return new Duration({hour, minute, second});
|
return new Duration({hour, minute, second});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
let res = "";
|
||||||
|
if (this.hour) {
|
||||||
|
res += this.hour + (this.hour === 1 ? " hour" : " hours ");
|
||||||
|
}
|
||||||
|
if (this.minute) {
|
||||||
|
res += this.minute + (this.minute === 1 ? " minute" : " minutes ");
|
||||||
|
}
|
||||||
|
if (this.second) {
|
||||||
|
res += this.second + (this.second === 1 ? " second" : " seconds");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.total_seconds === 0 ? "0 seconds" : res.trimEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
get inputValue() {
|
||||||
|
return new Time({}).plus(this).inputValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TimeRange {
|
export class TimeRange {
|
||||||
|
@ -92,9 +118,9 @@ export class TimeRange {
|
||||||
|
|
||||||
get duration() {
|
get duration() {
|
||||||
return new Duration({
|
return new Duration({
|
||||||
'hour': this.end_time.hour - this.start_time.hour,
|
'total_seconds': 60 * 60 * (this.end_time.hour - this.start_time.hour)
|
||||||
'minute': this.end_time.minute - this.start_time.minute,
|
+ 60 * (this.end_time.minute - this.start_time.minute)
|
||||||
'second': this.end_time.second - this.start_time.second,
|
+ this.end_time.second - this.start_time.second,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +132,7 @@ export class TimeRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DayString(day) {
|
const dayDictionary = {
|
||||||
return {
|
|
||||||
'M': 'Monday',
|
'M': 'Monday',
|
||||||
'T': 'Tuesday',
|
'T': 'Tuesday',
|
||||||
'W': 'Wednesday',
|
'W': 'Wednesday',
|
||||||
|
@ -115,9 +140,14 @@ export function DayString(day) {
|
||||||
'F': 'Friday',
|
'F': 'Friday',
|
||||||
'S': 'Saturday',
|
'S': 'Saturday',
|
||||||
'U': 'Sunday',
|
'U': 'Sunday',
|
||||||
}[day];
|
};
|
||||||
|
|
||||||
|
export function DayString(day) {
|
||||||
|
return dayDictionary[day];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const allDays = Object.keys(dayDictionary);
|
||||||
|
|
||||||
export function clearChildren(el) {
|
export function clearChildren(el) {
|
||||||
while (el.firstChild) el.removeChild(el.lastChild);
|
while (el.firstChild) el.removeChild(el.lastChild);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user