Compare commits

..

No commits in common. "5d0e70ed6ce2a021a398a7ef3fe2d55be2a25ff0" and "c775d6b9e9c7825500507c93c54eabfe73ec8f0a" have entirely different histories.

5 changed files with 12 additions and 143 deletions

View File

@ -537,104 +537,7 @@ function displayWarnings() {
} }
} }
const personInfoDiv = document.getElementById('personInfo');
const personStartTime = document.getElementById('person_start_time');
const personEndTime = document.getElementById('person_end_time');
const personDays = document.getElementById('person_days');
function displayPersonInfoDiv() {
const singlePerson = hash.person && hash.person.name;
personInfoDiv.style.display = singlePerson ? '' : 'none';
if (!singlePerson) return;
const info = schedule.infoFor(hash.person);
personStartTime.value = new utils.Time(info.start_time ?? schedule.start_time).inputValue;
personEndTime.value = new utils.Time(info.end_time ?? schedule.end_time).inputValue;
personStartTime.step = schedule.granularity.total_seconds;
personEndTime.step = schedule.granularity.total_seconds;
utils.clearChildren(personDays);
for (const day of utils.allDays.filter(d => schedule.all_days.includes(d)
|| info.days && info.days.includes(d))) {
const dayLabel = document.createElement('label');
const dayName = utils.DayString(day);
const dayCheckbox = document.createElement('input');
dayCheckbox.type = 'checkbox';
dayCheckbox.checked = (info.days ?? schedule.all_days).includes(day);
dayCheckbox.addEventListener('change', async e => {
let newDays = info.days;
if (!e.target.checked) {
if (schedule.assignments.some(a => a.hasPersonExplicitlyOnDay(hash.person, day))) {
alert("Cannot remove schedule for " + dayName
+ " because " + hash.person.name
+ " is in events on that day.");
e.target.checked = true;
return;
}
if (!newDays) newDays = [...schedule.all_days];
newDays.splice(schedule.all_days.indexOf(day), 1);
} else {
newDays = schedule.all_days.filter(d => (info.days ?? schedule.all_days).includes(d) || d === day);
}
if (newDays && utils.setEqual(newDays, schedule.all_days)) {
newDays = undefined;
}
schedule.setInfoFor(hash.person, {days: newDays});
await saveSchedule();
});
dayLabel.appendChild(dayCheckbox);
dayLabel.appendChild(document.createTextNode(dayName));
personDays.appendChild(dayLabel);
}
}
personStartTime.addEventListener('change', utils.debounceAsync(async e => {
const newStartTime = utils.Time.fromInputValue(e.target.value);
const assignments = schedule.assignments.filter(a => a.hasPersonExplicitlyOnAnyDay(hash.person));
if (assignments) {
const earliestStart = 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 for "
+ hash.person.name + " starts at "
+ earliestStart.to12HourString() + ".");
return;
}
}
schedule.setInfoFor(hash.person, {start_time:
newStartTime.cmp(schedule.start_time) !== 0
? newStartTime.asJsonObject()
: undefined});
await saveSchedule();
}, 1000));
personEndTime.addEventListener('change', utils.debounceAsync(async e => {
const newEndTime = utils.Time.fromInputValue(e.target.value);
const assignments = schedule.assignments.filter(a => a.hasPersonExplicitlyOnAnyDay(hash.person));
if (assignments) {
const latestEnd = 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 for "
+ hash.person.name + " ends at "
+ latestEnd.to12HourString() + ".");
return;
}
}
schedule.setInfoFor(hash.person, {end_time:
newEndTime.cmp(schedule.end_time) !== 0
? newEndTime.asJsonObject()
: undefined});
await saveSchedule();
}, 1000));
function displaySchedule() { function displaySchedule() {
displayPersonInfoDiv();
utils.clearChildren(schedulesDiv); utils.clearChildren(schedulesDiv);
if (hash.day && !schedule.all_days.includes(hash.day)) { if (hash.day && !schedule.all_days.includes(hash.day)) {
updateHash({day: undefined}); updateHash({day: undefined});
@ -663,7 +566,7 @@ document.getElementById('changeTitle').addEventListener('click', async e => {
await saveSchedule(); await saveSchedule();
}); });
schStartTime.addEventListener('change', utils.debounceAsync(async e => { schStartTime.addEventListener('change', async e => {
const newStartTime = utils.Time.fromInputValue(e.target.value); const newStartTime = utils.Time.fromInputValue(e.target.value);
if (schedule.assignments) { if (schedule.assignments) {
const earliestStart = schedule.assignments.map(a => a.start_time).sort((a, b) => a.cmp(b))[0]; const earliestStart = schedule.assignments.map(a => a.start_time).sort((a, b) => a.cmp(b))[0];
@ -676,9 +579,9 @@ schStartTime.addEventListener('change', utils.debounceAsync(async e => {
} }
schedule.start_time = newStartTime; schedule.start_time = newStartTime;
await saveSchedule(); await saveSchedule();
}, 1000)); });
schEndTime.addEventListener('change', utils.debounceAsync(async e => { schEndTime.addEventListener('change', async e => {
const newEndTime = utils.Time.fromInputValue(e.target.value); const newEndTime = utils.Time.fromInputValue(e.target.value);
if (schedule.assignments) { if (schedule.assignments) {
const latestEnd = schedule.assignments.map(a => a.end_time).sort((a, b) => b.cmp(a))[0]; const latestEnd = schedule.assignments.map(a => a.end_time).sort((a, b) => b.cmp(a))[0];
@ -691,9 +594,9 @@ schEndTime.addEventListener('change', utils.debounceAsync(async e => {
} }
schedule.end_time = newEndTime; schedule.end_time = newEndTime;
await saveSchedule(); await saveSchedule();
}, 1000)); });
schGranularity.addEventListener('change', utils.debounceAsync(async e => { schGranularity.addEventListener('change', async e => {
const newGranularity = utils.Time.fromInputValue(e.target.value) const newGranularity = utils.Time.fromInputValue(e.target.value)
.durationSinceMidnight; .durationSinceMidnight;
const schDuration = schedule.timeRange.duration; const schDuration = schedule.timeRange.duration;
@ -707,7 +610,7 @@ schGranularity.addEventListener('change', utils.debounceAsync(async e => {
} }
schedule.granularity = newGranularity; schedule.granularity = newGranularity;
await saveSchedule(); await saveSchedule();
}, 1000)); });
const personInput = document.getElementById('person'); const personInput = document.getElementById('person');
@ -1010,15 +913,15 @@ assignmentForm.location.addEventListener('change', async e => {
await saveSchedule(); await saveSchedule();
}); });
assignmentForm.start_time.addEventListener('change', utils.debounceAsync(async e => { assignmentForm.start_time.addEventListener('change', async e => {
selectedAssignment.start_time = utils.Time.fromInputValue(e.target.value); selectedAssignment.start_time = utils.Time.fromInputValue(e.target.value);
await saveSchedule(); await saveSchedule();
}, 1000)); });
assignmentForm.end_time.addEventListener('change', utils.debounceAsync(async e => { assignmentForm.end_time.addEventListener('change', async e => {
selectedAssignment.end_time = utils.Time.fromInputValue(e.target.value); selectedAssignment.end_time = utils.Time.fromInputValue(e.target.value);
await saveSchedule(); await saveSchedule();
}, 1000)); });
assignmentForm.squishable.addEventListener('change', async e => { assignmentForm.squishable.addEventListener('change', async e => {
selectedAssignment.squishable = e.target.checked; selectedAssignment.squishable = e.target.checked;

View File

@ -110,7 +110,7 @@ export default class Assignment {
return false; return false;
} }
hasPersonExplicitlyOnAnyDay(person) { hasPersonExplicitlyOnAnyDay(person, day) {
const kind = person.kind === 'student' ? 'students' : person.kind; const kind = person.kind === 'student' ? 'students' : person.kind;
return Object.values(this.people_by_day) return Object.values(this.people_by_day)
.some(byDay => byDay[kind].includes(person.name)); .some(byDay => byDay[kind].includes(person.name));

View File

@ -58,11 +58,6 @@
<label>Days: <select id="displayDays"></select></label> <label>Days: <select id="displayDays"></select></label>
<label>People: <select id="displayPeople"></select></label> <label>People: <select id="displayPeople"></select></label>
</div> </div>
<div id="personInfo" class="forms noprint" style="display: none">
<label>Start time: <input type="time" id="person_start_time"></label><br>
<label>End time: <input type="time" id="person_end_time"></label><br>
Days: <span id="person_days"></span><br>
</div>
<div id="warningsSection" class="warningsSection noprint" style="display: none"> <div id="warningsSection" class="warningsSection noprint" style="display: none">
<input type="checkbox" id="showWarnings" class="foldCheckbox" /> <input type="checkbox" id="showWarnings" class="foldCheckbox" />
<h4 class="warningHeader foldCheckboxHeader"> <h4 class="warningHeader foldCheckboxHeader">

View File

@ -87,13 +87,6 @@ export default class Schedule {
return person ? this.people_info[person.kind === 'student' ? 'students' : person.kind][person.name] ?? {} : {}; return person ? this.people_info[person.kind === 'student' ? 'students' : person.kind][person.name] ?? {} : {};
} }
setInfoFor(person, args) {
const kind = person.kind === 'student' ? 'students' : person.kind;
const newInfo = {...this.infoFor(person), ...args};
this.people_info[kind][person.name] =
Object.values(newInfo).some(i => i !== undefined) ? newInfo : undefined;
}
gridFor(person, day, versionName) { gridFor(person, day, versionName) {
const assignments = this.filterAssignments(person, day); const assignments = this.filterAssignments(person, day);
const forStudent = person && person.kind === 'student'; const forStudent = person && person.kind === 'student';

View File

@ -6,7 +6,7 @@ export class Time {
} }
static fromInputValue(str) { static fromInputValue(str) {
const parts = str.split(':').map(part => parseInt(part)); const parts = str.split(':');
return new Time({hour: parts[0], minute: parts[1], second: parts[2]}); return new Time({hour: parts[0], minute: parts[1], second: parts[2]});
} }
@ -184,25 +184,3 @@ export function setEqual(setA, setB) {
if (setA.size != setB.size) return false; if (setA.size != setB.size) return false;
return setDifference(setA, setB).size === 0; return setDifference(setA, setB).size === 0;
} }
// From https://stackoverflow.com/a/68227965
export function debounceAsync(task, ms) {
function deferred() {
let cancel, promise = new Promise((resolve, reject) => {
cancel = reject
setTimeout(resolve, ms)
})
return { promise, cancel }
}
let t = { promise: null, cancel: _ => void 0 }
return async (...args) => {
try {
t.cancel()
t = deferred()
await t.promise
await task(...args)
}
catch (_) { /* prevent memory leak */ }
}
}