diff --git a/js/calendar.js b/js/calendar.js index 7c6ea0050..c6a6e688f 100644 --- a/js/calendar.js +++ b/js/calendar.js @@ -25,6 +25,14 @@ ipcRenderer.on('PREFERENCE_SAVED', function(event, inputs) { applyTheme(preferences.theme); }); +/* + * Get nofified when waivers get updated. + */ +ipcRenderer.on('WAIVER_SAVED', function() { + calendar.loadInternalWaiveStore(); + calendar.redraw(); +}); + /* * Returns true if the notification is enabled in preferences. */ diff --git a/js/classes/Calendar.js b/js/classes/Calendar.js index e56c70aa3..bc36c0c8b 100644 --- a/js/classes/Calendar.js +++ b/js/classes/Calendar.js @@ -11,7 +11,7 @@ const { validateTime } = require('../time-math.js'); const { showDay } = require('../user-preferences.js'); -const { getDateStr } = require('../date-aux.js'); +const { getDateStr, getMonthLength } = require('../date-aux.js'); const { formatDayId, sendWaiverDay, @@ -36,6 +36,8 @@ class Calendar { this.month = this.today.getMonth(); this.year = this.today.getFullYear(); this.workingDays = 0; + this.loadInternalStore(); + this.loadInternalWaiveStore(); this.updatePreferences(preferences); this._initCalendar(); } @@ -45,9 +47,24 @@ class Calendar { */ _initCalendar() { this._generateTemplate(); + + $('#punch-button').click(() => { this.punchDate(); }); + $('#next-month').click(() => { this.nextMonth(); }); + $('#prev-month').click(() => { this.prevMonth(); }); + $('#current-month').click(() => { this.goToCurrentDate(); }); + + this._draw(); + } + + /* + * Draws elements of the Calendar that depend on data. + */ + _draw() { + this.updateTableHeader(); + this.updateTableBody(); this.updateBasedOnDB(); - if (!showDay(this.today.getFullYear(), this.today.getMonth(), this.today.getDate())) { + if (!this.showDay(this.today.getFullYear(), this.today.getMonth(), this.today.getDate())) { $('#punch-button').prop('disabled', true); ipcRenderer.send('TOGGLE_TRAY_PUNCH_TIME', false); } else { @@ -62,22 +79,6 @@ class Calendar { calendar.updateTimeDayCallback(this.id, this.value); }); - $('#punch-button').off('click').on('click', function() { - calendar.punchDate(); - }); - - $('#next-month').off('click').on('click', function() { - calendar.nextMonth(); - }); - - $('#prev-month').off('click').on('click', function() { - calendar.prevMonth(); - }); - - $('#current-month').off('click').on('click', function() { - calendar.goToCurrentDate(); - }); - $('.waiver-trigger').off('click').on('click', function() { const dayId = $(this).closest('tr').attr('id').substr(3); const waiverDay = formatDayId(dayId); @@ -89,15 +90,55 @@ class Calendar { /* * Updates data displayed based on the database. */ - _setData(key) { - var value = ''; - if (store.has(key)) { - value = store.get(key); + _setTableData(day, month, key) { + var idTag = this.year + '-' + month + '-' + day + '-' + key; + + var value = this._getStore(day, month, this.year, key); + if (value === undefined) { + value = ''; } - $('#' + key).val(value); + $('#' + idTag).val(value); return value; } + /* + * Gets value from internal store. + */ + _getStore(day, month, year, key) { + var idTag = year + '-' + month + '-' + day + '-' + key; + + return this.internalStore[idTag]; + } + + /* + * Saves value on store and updates internal store. + */ + _setStore(day, month, year, key, newValue) { + var idTag = year + '-' + month + '-' + day + '-' + key; + + this.internalStore[idTag] = newValue; + store.set(idTag, newValue); + } + + /* + * Removes value from store and from internal store. + */ + _removeStore(day, month, year, key) { + var idTag = year + '-' + month + '-' + day + '-' + key; + + this.internalStore[idTag] = undefined; + store.delete(idTag); + } + + /* + * Gets value from internal waiver store. + */ + _getWaiverStore(day, month, year) { + let dayKey = getDateStr(new Date(year, month, day)); + + return this.internalWaiverStore[dayKey]; + } + /* * Generates the calendar HTML view. */ @@ -175,10 +216,9 @@ class Calendar { weekDay = currentDay.getDay(), today = new Date(), isToday = (today.getDate() === day && today.getMonth() === month && today.getFullYear() === year), - trID = ('tr-' + year + '-' + month + '-' + day), - dateStr = getDateStr(currentDay); + trID = ('tr-' + year + '-' + month + '-' + day); - if (!showDay(year, month, day)) { + if (!this.showDay(year, month, day)) { if (!this.hideNonWorkingDays) { return '' + '' + this.options.dayAbbrs[weekDay] + '' + @@ -190,8 +230,8 @@ class Calendar { } } - if (waivedWorkdays.has(dateStr)) { - var waivedInfo = waivedWorkdays.get(dateStr); + var waivedInfo = this._getWaiverStore(day, month, year); + if (waivedInfo !== undefined) { var summaryStr = 'Waived day: ' + waivedInfo['reason']; var waivedLineHtmlCode = '' + @@ -228,10 +268,10 @@ class Calendar { /* * Returns the header of the page, with the image, name and a message. */ - _getPageHeader(year, month) { + _getPageHeader() { var todayBut = ''; var leftBut = ''; - var rigthBut = ''; + var rightBut = ''; return '
'+ '
' + '
Time to Leave
' + @@ -239,8 +279,8 @@ class Calendar { '
' + '' + '' + - '' + - '' + + '' + + '' + '' + '
' + leftBut + '
' + this.options.months[month] + ' ' + year + '
' + rigthBut + '
' + rightBut + '' + todayBut + '
'; } @@ -267,12 +307,12 @@ class Calendar { */ _getBalanceRowPosition() { if (this.year !== this.today.getFullYear() || this.month !== this.today.getMonth()) { - return this.getMonthLength(); + return getMonthLength(this.year, this.month); } var balanceRowPosition = 0; for (var day = 1; day < this.today.getDate(); ++day) { - if (showDay(this.year, this.month, day)) { + if (this.showDay(this.year, this.month, day)) { balanceRowPosition = day; } } @@ -281,14 +321,27 @@ class Calendar { } /* - * Returns the code of the body of the page. + * Returns the template code of the body of the page. */ _getBody() { - var monthLength = this.getMonthLength(); var html = '
'; html += this._getPageHeader(this.year, this.month); html += ''; html += Calendar._getTableHeaderCode(); + html += ''; + html += ''; + html += '

'; + html += '
'; + + return html; + } + + /* + * Returns the code of the table body of the calendar. + */ + generateTableBody() { + var html; + var monthLength = getMonthLength(this.year, this.month); var balanceRowPosition = this._getBalanceRowPosition(); for (var day = 1; day <= monthLength; ++day) { @@ -297,14 +350,31 @@ class Calendar { html += Calendar._getBalanceRowCode(); } } - html += '
'; - html += ''; - return html; } + /* + * Updates the code of the table header of the calendar, to be called on demand. + */ + updateTableHeader() { + $('#month-year').html(this.options.months[this.month] + ' ' + this.year); + } + + /* + * Updates the code of the table body of the calendar, to be called on demand. + */ + updateTableBody() { + $('#calendar-table-body').html(this.generateTableBody()); + } + + reload() { + this.loadInternalStore(); + this.loadInternalWaiveStore(); + this.redraw(); + } + redraw() { - this._initCalendar(); + this._draw(); } /* @@ -317,7 +387,7 @@ class Calendar { } else { this.month += 1; } - this._initCalendar(this.month, this.year); + this.redraw(); } /* @@ -330,7 +400,7 @@ class Calendar { } else { this.month -= 1; } - this._initCalendar(this.month, this.year); + this.redraw(); } /* @@ -339,7 +409,7 @@ class Calendar { goToCurrentDate() { this.month = this.today.getMonth(); this.year = this.today.getFullYear(); - this._initCalendar(this.month, this.year); + this.redraw(); } /* @@ -356,14 +426,6 @@ class Calendar { return this.month; } - /* - * Gets month length of displayed calendar. - */ - getMonthLength() { - var d = new Date(this.year, this.month+1, 0); - return d.getDate(); - } - /* * Returns how many "hours per day" were set in preferences. */ @@ -376,11 +438,51 @@ class Calendar { * @param {Object.} preferences */ updatePreferences(preferences) { + this.preferences = preferences; this.countToday = preferences['count-today']; this.hideNonWorkingDays = preferences['hide-non-working-days']; this.hoursPerDay = preferences['hours-per-day']; } + /** + * Stores year data in memory to make operations faster + */ + loadInternalStore() { + this.internalStore = {}; + + for (const entry of store) { + const key = entry[0]; + const value = entry[1]; + + this.internalStore[key] = value; + } + } + + /** + * Stores waiver data in memory to make operations faster + */ + loadInternalWaiveStore() { + this.internalWaiverStore = {}; + + for (const entry of waivedWorkdays) { + const date = entry[0]; + const reason = entry[1]['reason']; + const hours = entry[1]['hours']; + + this.internalWaiverStore[date] = { + 'hours': hours, + 'reason': reason + }; + } + } + + /* + * Calls showDay from user-preferences.js passing the last preferences set. + */ + showDay(year, month, day) { + return showDay(year, month, day, this.preferences); + } + /* * Adds the next missing entry on the actual day and updates calendar. */ @@ -394,7 +496,7 @@ class Calendar { if (this.getMonth() !== month || this.getYear() !== year || - !showDay(year, month, day)) { + !this.showDay(year, month, day)) { return; } @@ -425,13 +527,13 @@ class Calendar { */ updateBalance() { var now = new Date(), - monthLength = this.getMonthLength(), + monthLength = getMonthLength(this.year, this.month), workingDaysToCompute = 0, monthTotalWorked = '00:00'; var countDays = false; for (var day = 1; day <= monthLength; ++day) { - if (!showDay(this.year, this.month, day)) { + if (!this.showDay(this.year, this.month, day)) { continue; } var isToday = (now.getDate() === day && now.getMonth() === this.month && now.getFullYear() === this.year); @@ -465,33 +567,30 @@ class Calendar { * Updates data displayed based on the database. */ updateBasedOnDB() { - var monthLength = this.getMonthLength(); + var monthLength = getMonthLength(this.year, this.month); var monthTotal = '00:00'; this.workingDays = 0; var stopCountingMonthStats = false; for (var day = 1; day <= monthLength; ++day) { - if (!showDay(this.year, this.month, day)) { + if (!this.showDay(this.year, this.month, day)) { continue; } - var currentDay = new Date(this.year, this.month, day), - dateStr = getDateStr(currentDay); - var dayTotal = null; var dayStr = this.year + '-' + this.month + '-' + day + '-'; - if (waivedWorkdays.has(dateStr)) { - var waivedInfo = waivedWorkdays.get(dateStr); + var waivedInfo = this._getWaiverStore(day, this.month, this.year); + if (waivedInfo !== undefined) { var waivedDayTotal = waivedInfo['hours']; $('#' + dayStr + 'day-total').val(waivedDayTotal); dayTotal = waivedDayTotal; } else { - var lunchBegin = this._setData(dayStr + 'lunch-begin'); - var lunchEnd = this._setData(dayStr + 'lunch-end'); - this._setData(dayStr + 'lunch-total'); - var dayBegin = this._setData(dayStr + 'day-begin'); - var dayEnd = this._setData(dayStr + 'day-end'); - dayTotal = this._setData(dayStr + 'day-total'); + var lunchBegin = this._setTableData(day, this.month, 'lunch-begin'); + var lunchEnd = this._setTableData(day, this.month, 'lunch-end'); + this._setTableData(day, this.month, 'lunch-total'); + var dayBegin = this._setTableData(day, this.month, 'day-begin'); + var dayEnd = this._setTableData(day, this.month, 'day-end'); + dayTotal = this._setTableData(day, this.month, 'day-total'); this.colorErrorLine(this.year, this.month, day, dayBegin, lunchBegin, lunchEnd, dayEnd); } @@ -531,13 +630,13 @@ class Calendar { * Update contents of the "time to leave" bar. */ updateLeaveBy() { - if (!showDay(this.today.getFullYear(), this.today.getMonth(), this.today.getDate()) || + if (!this.showDay(this.today.getFullYear(), this.today.getMonth(), this.today.getDate()) || this.today.getMonth() !== this.getMonth() || this.today.getFullYear() !== this.getYear() || - waivedWorkdays.has(getDateStr(this.today))) { + this._getWaiverStore(this.today.getDate(), this.month, this.year)) { return; } - var [dayBegin, lunchBegin, lunchEnd, dayEnd] = this.getDaysEntriesFromHTML(this.today.getFullYear(), this.today.getMonth(), this.today.getDate()); + var [dayBegin, lunchBegin, lunchEnd, dayEnd] = this.getDaysEntries(this.today.getMonth(), this.today.getDate()); var dayKey = this.today.getFullYear() + '-' + this.today.getMonth() + '-' + this.today.getDate() + '-'; if (validateTime(dayBegin)) { var leaveBy = sumTime(dayBegin, this.getHoursPerDay()); @@ -550,7 +649,7 @@ class Calendar { $('#leave-by').val(''); } - if (dayBegin.length && lunchBegin.length && lunchEnd.length && dayEnd.length) { + if (dayBegin !== undefined && lunchBegin !== undefined && lunchEnd !== undefined && dayEnd !== undefined) { //All entries computed $('#punch-button').prop('disabled', true); ipcRenderer.send('TOGGLE_TRAY_PUNCH_TIME', false); @@ -593,19 +692,18 @@ class Calendar { */ updateTimeDay(year, month, day, key, newValue) { var baseStr = year + '-' + month + '-' + day + '-'; - var dayStr = baseStr + key; - var oldValue = store.get(dayStr); + var oldValue = this._getStore(day, month, year, key); if (validateTime(newValue)) { - store.set(dayStr, newValue); + this._setStore(day, month, year, key, newValue); } else if (oldValue && validateTime(oldValue)) { - store.delete(dayStr); + this._removeStore(day, month, year, key); } - var oldDayTotal = store.get(baseStr + 'day-total'); + var oldDayTotal = this._getStore(day, month, year, 'day-total'); //update totals - var [dayBegin, lunchBegin, lunchEnd, dayEnd] = this.getDaysEntries(year, month, day); + var [dayBegin, lunchBegin, lunchEnd, dayEnd] = this.getDaysEntries(month, day); //compute lunch time var lunchTime = ''; @@ -628,16 +726,16 @@ class Calendar { } if (lunchTime.length > 0) { - store.set(baseStr + 'lunch-total', lunchTime); + this._setStore(day, month, year, 'lunch-total', lunchTime); } else { - store.delete(baseStr + 'lunch-total'); + this._removeStore(day, month, year, 'lunch-total'); } $('#' + baseStr + 'lunch-total').val(lunchTime); if (dayTotal.length > 0) { - store.set(baseStr + 'day-total', dayTotal); + this._setStore(day, month, year, 'day-total', dayTotal); } else { - store.delete(baseStr + 'day-total'); + this._removeStore(day, month, year, 'day-total'); } $('#' + baseStr + 'day-total').val(dayTotal); @@ -655,25 +753,13 @@ class Calendar { } /* - * Returns the entry values for the day, from the DB. - */ - getDaysEntries(year, month, day) { - var dayStr = year + '-' + month + '-' + day + '-'; - return [store.get(dayStr + 'day-begin'), - store.get(dayStr + 'lunch-begin'), - store.get(dayStr + 'lunch-end'), - store.get(dayStr + 'day-end')]; - } - - /* - * Returns the entry values for the day, from HTML (for performance). + * Returns the entry values for the day, from the internal store. */ - getDaysEntriesFromHTML(year, month, day) { - var dayStr = year + '-' + month + '-' + day + '-'; - return [$('#' + dayStr + 'day-begin').val(), - $('#' + dayStr + 'lunch-begin').val(), - $('#' + dayStr + 'lunch-end').val(), - $('#' + dayStr + 'day-end').val()]; + getDaysEntries(month, day) { + return [this._getStore(day, month, this.year, 'day-begin'), + this._getStore(day, month, this.year, 'lunch-begin'), + this._getStore(day, month, this.year, 'lunch-end'), + this._getStore(day, month, this.year, 'day-end')]; } /* diff --git a/js/date-aux.js b/js/date-aux.js index d6ba8816f..51bcc6447 100644 --- a/js/date-aux.js +++ b/js/date-aux.js @@ -9,6 +9,14 @@ function getDateStr(date) { } } +/* + * Given a a year and month, returns how many days the month has + */ +function getMonthLength(year, month) { + var d = new Date(year, month+1, 0); + return d.getDate(); +} + module.exports = { - getDateStr + getDateStr, getMonthLength }; diff --git a/js/user-preferences.js b/js/user-preferences.js index 1225d91ce..e54d39ef7 100644 --- a/js/user-preferences.js +++ b/js/user-preferences.js @@ -145,8 +145,10 @@ function getLoadedOrDerivedUserPreferences() { /* * Returns true if we should display week day. */ -function showWeekDay(weekDay) { - var preferences = getLoadedOrDerivedUserPreferences(); +function showWeekDay(weekDay, preferences = undefined) { + if (preferences === undefined) { + preferences = getLoadedOrDerivedUserPreferences(); + } switch (weekDay) { case 0: return preferences['working-days-sunday']; case 1: return preferences['working-days-monday']; @@ -162,9 +164,9 @@ function showWeekDay(weekDay) { * Returns true if we should display day. * @note: The month should be 0-based (i.e.: 0 is Jan, 11 is Dec). */ -function showDay(year, month, day) { +function showDay(year, month, day, preferences = undefined) { var currentDay = new Date(year, month, day), weekDay = currentDay.getDay(); - return showWeekDay(weekDay); + return showWeekDay(weekDay, preferences); } module.exports = { diff --git a/main.js b/main.js index b187f016d..ac6dd3b17 100644 --- a/main.js +++ b/main.js @@ -141,8 +141,7 @@ function createWindow() { waiverWindow.show(); waiverWindow.on('close', function() { waiverWindow = null; - // Reload only the calendar itself to avoid a flash - win.webContents.executeJavaScript('calendar.redraw()'); + win.webContents.send('WAIVER_SAVED'); }); }, }, @@ -259,7 +258,7 @@ function createWindow() { const importResult = importDatabaseFromFile(response); if (importResult['result']) { // Reload only the calendar itself to avoid a flash - win.webContents.executeJavaScript('calendar.redraw()'); + win.webContents.executeJavaScript('calendar.reload()'); dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { title: 'Time to Leave', @@ -304,7 +303,7 @@ function createWindow() { store.clear(); waivedWorkdays.clear(); // Reload only the calendar itself to avoid a flash - win.webContents.executeJavaScript('calendar.redraw()'); + win.webContents.executeJavaScript('calendar.reload()'); dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { title: 'Time to Leave',