class WorkTimeManager extends Listenable { constructor() { super(); this.loadPeriodsRequest = new Request(OnTime.REQUEST_URI + "Periods", "GET", this.loadedPeriods.bind(this), this.loadedPeriodsError.bind(this)); this.loadPeriods(); } loadPeriods() { this.loadPeriodsRequest.send(); } loadedPeriods(periods) { this.periods = [ ]; for (var i = 0; i < periods.length; i++) { this.addPeriod(periods[i], false); } } loadedPeriodsError(request, status, error) { alert("Could not load the work time periods. Please refresh the page and try again."); } /** * Returns all work time periods for the given day. * Includes periods that only touch the day. Periods going past midnight for example will also be returned. * The time is ignored. */ getPeriodsForDay(dayIndex) { if (!this.periods) { return [ ]; } var dayStartGmt = Time.getTimestampForLocalDayIndex(dayIndex); var matchingPeriods = [ ]; for (var i = 0; i < this.periods.length; i++) { var checkingPeriod = this.periods[i]; var endTime = checkingPeriod.end_time; if (!endTime) { endTime = new Date().getTime(); } if ((checkingPeriod.start_time >= dayStartGmt && checkingPeriod.start_time < dayStartGmt + Time.ONE_DAY && endTime != dayStartGmt) || (endTime > dayStartGmt && endTime <= dayStartGmt + Time.ONE_DAY && checkingPeriod.start_time != dayStartGmt + Time.ONE_DAY) || (checkingPeriod.start_time < dayStartGmt && endTime > dayStartGmt + Time.ONE_DAY)) { matchingPeriods.push(checkingPeriod); } } return matchingPeriods; } /** * Returns the work time period for the given period key. */ getPeriod(periodKey) { for (var i = this.periods.length - 1; i >= 0; i--) { if (this.periods[i].period_key == periodKey) { return this.periods[i]; } } return null; } /** * Adds a new period. * Passing the optional flag as false will cause the addition not to be published to the server. */ addPeriod(period, tellServer = true) { if (tellServer) { this.addingPeriod = period; new Request(OnTime.REQUEST_URI + "Period/Create", "POST", this.addPeriodCallback.bind(this), this.addPeriodErrorCallback.bind(this)).send(period); } else { this.addPeriodCallback(period); } } /** * Deletes the period with the given key. */ deletePeriod(periodKey) { var index = -1; for (var i = 0; i < this.periods.length; i++) { if (this.periods[i].period_key == periodKey) { index = i; break; } } if (index == -1) { console.error("Trying to delete a period which does not exist. The period key is " + periodKey + "."); return; } this.deletingPeriodKey = periodKey; new Request(OnTime.REQUEST_URI + "Period/Delete", "POST", this.deletePeriodCallback.bind(this), this.deletePeriodErrorCallback.bind(this)).send({ period_key: periodKey }); } deletePeriodCallback(data) { //Interpret this as an error if the period was not properly reported as deleted by the server. if (!data.deleted) { this.deletePeriodErrorCallback(null, null, null); return; } var index = -1; for (var i = 0; i < this.periods.length; i++) { if (this.periods[i].period_key == data.period_key) { index = i; break; } } if (index != -1) { this.periods.splice(index, 1); } var periodDeletedEvent = new Event("perioddeleted"); periodDeletedEvent.periodKey = data.period_key; this.dispatchEvent(periodDeletedEvent); this.deletingPeriodKey = null; } /** * Called when an error occurs upon server-sided deletion of the period. * Will fire the perioddeleteerror event to let everyone know. */ deletePeriodErrorCallback(request, status, error) { alert("There was an error while deleting the time period."); var periodDeleteError = new Event("perioddeleteerror"); periodDeleteError.periodKey = this.deletingPeriodKey; this.dispatchEvent(periodDeleteError); this.deletingPeriodKey = null; } /** * Just adds a new period without an end timestamp. */ startPeriod(card) { this.addPeriod({ start_time: new Date().getTime(), end_time: null, card_key: card.card_key, card_title: card.title, notes: card.description }); } /** * Called when the newly created period has arrived with the server. * The data parameter holds the effective period complete with key and start time. * The times are represented by milliseconds since 1970. */ addPeriodCallback(data) { this.periods.push(data); var newPeriodEvent = new Event("periodadded"); newPeriodEvent.period = data; this.dispatchEvent(newPeriodEvent); if (!data.end_time) { var periodStartedEvent = new Event("periodstarted"); periodStartedEvent.period = data; this.dispatchEvent(periodStartedEvent); } this.addingPeriod = null; } /** * Called when an error occurs upon server-sided creation of the period. * Will fire the periodadderror event to let everyone know. */ addPeriodErrorCallback(request, status, error) { alert("There was an error while adding the new time period."); var periodAddError = new Event("periodadderror"); periodAddError.period = this.addingPeriod; this.dispatchEvent(periodAddError); this.addingPeriod = null; } /** * Will set an end time to the period and send it to the server as an update. */ endPeriod(period) { if (period.end_time) { alert("You cannot end this period because it has already been ended."); console.error("Trying to end a period that has already been ended."); return; } var index = -1; for (var i = this.periods.length - 1; i >= 0; i--) { if (this.periods[i].period_key == period.period_key) { index = i; break; } } if (index == -1) { console.error("Trying to end a non-existing period."); return; } this.endingPeriod = true; this.updatePeriod({ period_key: this.periods[index].period_key, card_key: this.periods[index].card_key, card_title: this.periods[index].card_title, start_time: this.periods[index].start_time, end_time: new Date().getTime(), notes: this.periods[index].notes }); } /** * Propagates the changes made in the given period object to the server. */ updatePeriod(period) { this.changingPeriod = period; new Request(OnTime.REQUEST_URI + "Period", "POST", this.updatePeriodCallback.bind(this), this.updatePeriodErrorCallback.bind(this)).send(period); } /** * Called when a period has been updated successfully. */ updatePeriodCallback(data) { var found = false; for (var i = 0; i < this.periods.length; i++) { if (this.periods[i].period_key == data.period_key) { //Check if this is an ending update. if (!this.periods[i].end_time && data.end_time) { var periodEndedEvent = new Event("periodended"); periodEndedEvent.period = data; this.dispatchEvent(periodEndedEvent); } this.periods[i] = data; found = true; break; } } if (!found) { console.warn("An updated period did not exist in the periods array. It was added, but this is an unwanted behavior."); this.periods.push(data); } var periodChangedEvent = new Event("periodchanged"); periodChangedEvent.period = data; this.dispatchEvent(periodChangedEvent); this.changingPeriod = null; this.endingPeriod = false; } updatePeriodErrorCallback(request, status, error) { var periodChangeErrorEvent = new Event("periodchangeerror"); periodChangeErrorEvent.period = this.changingPeriod; this.dispatchEvent(periodChangeErrorEvent); if (this.endingPeriod) { this.changingPeriod.end_time = null; } this.changingPeriod = null; this.endingPeriod = false; } }