diff --git a/src/index.html b/src/index.html
index 6b36a88..d35eec8 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,8 +1,6 @@
-
-
w-timerer
diff --git a/src/index.js b/src/index.js
index ce79324..fd68996 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,81 +1,49 @@
-function updateTimes() {
- const travelTime = 1; // in hours
+const TRAVEL_TIME_HOURS = 1;
+const FIRST_HOUR = 13;
+const LAST_HOUR = 22;
- const now = new Date();
- const currentHours = now.getHours();
- const currentMinutes = now.getMinutes();
- const currentSeconds = now.getSeconds();
+let clockEl, dateEl;
+let diffNodes = [];
+let resizeTimer = null;
+let lastDayKey = "";
- const currentTimeElement = document.getElementById('currentTime');
- currentTimeElement.textContent = `${currentHours.toString().padStart(2, '0')}:${currentMinutes.toString().padStart(2, '0')}:${currentSeconds.toString().padStart(2, '0')}`;
-
- const targetTimesElement = document.getElementById('targetTimes');
- const leaveTimesElement = document.getElementById('leaveTimes');
- const timeDifferencesElement = document.getElementById('timeDifferences');
-
- targetTimesElement.innerHTML = '';
- leaveTimesElement.innerHTML = '';
- timeDifferencesElement.innerHTML = '';
-
- const ttBlock = document.createElement('span');
- ttBlock.className = 'time-block label-block';
- ttBlock.textContent = 'TT';
- targetTimesElement.appendChild(ttBlock);
-
- const ltBlock = document.createElement('span');
- ltBlock.className = 'time-block label-block';
- ltBlock.textContent = 'LT';
- leaveTimesElement.appendChild(ltBlock);
-
- const tdBlock = document.createElement('span');
- tdBlock.className = 'time-block label-block';
- tdBlock.textContent = 'TD';
- timeDifferencesElement.appendChild(tdBlock);
-
- const targetTimeBlocks = [];
- const leaveTimeBlocks = [];
- const diffTimeBlocks = [];
-
- for (let hour = 13; hour <= 22; hour++) {
- let leaveHour = hour - travelTime;
-
- const timeBlock = document.createElement('span');
- timeBlock.className = 'time-block';
- timeBlock.textContent = `${hour.toString().padStart(2, '0')}:00`;
- targetTimeBlocks.push(timeBlock);
-
- const leaveTimeBlock = document.createElement('span');
- leaveTimeBlock.className = 'time-block';
- leaveTimeBlock.textContent = `${(leaveHour).toString().padStart(2, '0')}:00`;
- leaveTimeBlocks.push(leaveTimeBlock);
-
- const targetTime = new Date();
- targetTime.setHours(leaveHour, 0, 0, 0);
-
- const diffBlock = document.createElement('span');
- diffBlock.className = 'time-block';
-
- const diffMs = targetTime - now;
- if (diffMs < 0) {
- const diffHours = -1 * Math.ceil(diffMs / (1000 * 60 * 60));
- const diffMinutes = -1 * Math.ceil((diffMs % (1000 * 60 * 60)) / (1000 * 60));
- diffBlock.textContent = `-${diffHours.toString().padStart(2, '0')}:${diffMinutes.toString().padStart(2, '0')}`;
- } else {
- const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
- const diffMinutes = Math.ceil((diffMs % (1000 * 60 * 60)) / (1000 * 60));
- diffBlock.textContent = `${diffHours.toString().padStart(2, '0')}:${diffMinutes.toString().padStart(2, '0')}`;
- }
-
- diffTimeBlocks.push(diffBlock);
- }
-
- distributeBlocks(targetTimesElement, targetTimeBlocks);
- distributeBlocks(leaveTimesElement, leaveTimeBlocks);
- distributeBlocks(timeDifferencesElement, diffTimeBlocks);
-
- updateCalendar();
+function pad2(n) {
+ return n < 10 ? "0" + n : "" + n;
}
+function formatClock(d) {
+ return pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" + pad2(d.getSeconds());
+}
+
+function formatDate(d) {
+ return pad2(d.getDate()) + "." + pad2(d.getMonth() + 1) + "." + d.getFullYear();
+}
+
+function diffText(targetMs, nowMs) {
+ const diffMs = targetMs - nowMs;
+ if (diffMs < 0) {
+ const diffHours = -1 * Math.ceil(diffMs / 3600000);
+ const diffMinutes = -1 * Math.ceil((diffMs % 3600000) / 60000);
+ return "-" + pad2(diffHours) + ":" + pad2(diffMinutes);
+ }
+ const diffHours = Math.floor(diffMs / 3600000);
+ const diffMinutes = Math.ceil((diffMs % 3600000) / 60000);
+ return pad2(diffHours) + ":" + pad2(diffMinutes);
+}
+
+function buildLabel(text) {
+ const span = document.createElement("span");
+ span.className = "time-block label-block";
+ span.textContent = text;
+ return span;
+}
+
+function buildTimeBlock(text) {
+ const span = document.createElement("span");
+ span.className = "time-block";
+ span.textContent = text;
+ return span;
+}
function distributeBlocks(container, blocks) {
const screenWidth = window.innerWidth;
@@ -85,86 +53,105 @@ function distributeBlocks(container, blocks) {
const availableWidth = screenWidth - labelWidth;
const blocksPerRow = Math.floor(availableWidth / blockWidth);
+ while (container.childNodes.length > 1) {
+ container.removeChild(container.lastChild);
+ }
+
if (blocksPerRow > blocks.length) {
- blocks.forEach(block => container.appendChild(block));
+ blocks.forEach(function (b) { container.appendChild(b); });
return;
}
const totalBlocks = blocks.length;
const halfBlocks = Math.ceil(totalBlocks / 2);
- const rowsContainer = document.createElement('div');
- rowsContainer.className = 'multi-rows-container';
+ const rowsContainer = document.createElement("div");
+ rowsContainer.className = "multi-rows-container";
- const topRow = document.createElement('div');
- topRow.className = 'time-row';
+ const topRow = document.createElement("div");
+ topRow.className = "time-row";
for (let i = 0; i < halfBlocks; i++) {
topRow.appendChild(blocks[i]);
}
rowsContainer.appendChild(topRow);
- const bottomRow = document.createElement('div');
- bottomRow.className = 'time-row';
+ const bottomRow = document.createElement("div");
+ bottomRow.className = "time-row";
for (let i = halfBlocks; i < totalBlocks; i++) {
bottomRow.appendChild(blocks[i]);
}
rowsContainer.appendChild(bottomRow);
- const label = container.firstChild;
container.appendChild(rowsContainer);
}
-function updateCalendar() {
+function buildTargetBlocks() {
+ const targetTimesElement = document.getElementById("targetTimes");
+ const leaveTimesElement = document.getElementById("leaveTimes");
+ const timeDifferencesElement = document.getElementById("timeDifferences");
+
+ targetTimesElement.appendChild(buildLabel("TT"));
+ leaveTimesElement.appendChild(buildLabel("LT"));
+ timeDifferencesElement.appendChild(buildLabel("TD"));
+
+ const targetBlocks = [];
+ const leaveBlocks = [];
+ const diffBlocks = [];
+
+ for (let hour = FIRST_HOUR; hour <= LAST_HOUR; hour++) {
+ const leaveHour = hour - TRAVEL_TIME_HOURS;
+
+ targetBlocks.push(buildTimeBlock(pad2(hour) + ":00"));
+ leaveBlocks.push(buildTimeBlock(pad2(leaveHour) + ":00"));
+ diffBlocks.push(buildTimeBlock(""));
+ }
+
+ distributeBlocks(targetTimesElement, targetBlocks);
+ distributeBlocks(leaveTimesElement, leaveBlocks);
+ distributeBlocks(timeDifferencesElement, diffBlocks);
+
+ diffNodes = diffBlocks;
+}
+
+function buildCalendar() {
+ const calendar = document.getElementById("calendar");
+ calendar.innerHTML = "";
+
const now = new Date();
- const currentDateElement = document.getElementById('currentDate');
+ const daysOfWeek = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
- const day = now.getDate().toString().padStart(2, '0');
- const month = (now.getMonth() + 1).toString().padStart(2, '0');
- const year = now.getFullYear();
- currentDateElement.textContent = `${day}.${month}.${year}`;
-
- const calendarElement = document.getElementById('calendar');
- calendarElement.innerHTML = '';
-
- const daysOfWeek = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
-
- const firstDayOfMonth = new Date(year, now.getMonth(), 1);
- let firstDayWeek = firstDayOfMonth.getDay();
- firstDayWeek = firstDayWeek === 0 ? 7 : firstDayWeek;
-
- const lastDayOfMonth = new Date(year, now.getMonth() + 1, 0);
- const daysInMonth = lastDayOfMonth.getDate();
-
- const lastDayOfPrevMonth = new Date(year, now.getMonth(), 0);
- const daysInPrevMonth = lastDayOfPrevMonth.getDate();
-
- const thead = document.createElement('thead');
- const headerRow = document.createElement('tr');
- daysOfWeek.forEach((day, index) => {
- const th = document.createElement('th');
+ const thead = document.createElement("thead");
+ const headerRow = document.createElement("tr");
+ daysOfWeek.forEach(function (day, index) {
+ const th = document.createElement("th");
th.textContent = day;
- th.className = 'calendar-weekday';
if (index === 5 || index === 6) {
- th.classList.add('weekend-text');
+ th.classList.add("weekend-text");
}
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
- calendarElement.appendChild(thead);
+ calendar.appendChild(thead);
- const tbody = document.createElement('tbody');
+ const tbody = document.createElement("tbody");
+ const year = now.getFullYear();
+ const month = now.getMonth();
+ const firstDayOfMonth = new Date(year, month, 1);
+ let firstDayWeek = firstDayOfMonth.getDay();
+ firstDayWeek = firstDayWeek === 0 ? 7 : firstDayWeek;
+
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
+ const daysInPrevMonth = new Date(year, month, 0).getDate();
let dayCounter = 1;
let nextMonthDayCounter = 1;
-
let startDay = daysInPrevMonth - firstDayWeek + 2;
- for (let row = 0; row < 5; row++) {
- const tr = document.createElement('tr');
-
+ const totalRows = Math.ceil((firstDayWeek - 1 + daysInMonth) / 7);
+ for (let row = 0; row < totalRows; row++) {
+ const tr = document.createElement("tr");
for (let col = 0; col < 7; col++) {
- const td = document.createElement('td');
- td.className = 'calendar-cell';
+ const td = document.createElement("td");
let cellDay;
let isCurrentMonth = true;
@@ -184,28 +171,100 @@ function updateCalendar() {
td.textContent = cellDay;
if (isCurrentMonth && cellDay === now.getDate()) {
- td.classList.add('today-text');
+ td.classList.add("today-text");
}
-
if (col === 5 || col === 6) {
- td.classList.add('weekend-text');
+ td.classList.add("weekend-text");
}
-
if (!isCurrentMonth) {
- td.classList.add('other-month');
+ td.classList.add("other-month");
}
-
tr.appendChild(td);
}
-
tbody.appendChild(tr);
}
-
- calendarElement.appendChild(tbody);
+ calendar.appendChild(tbody);
}
+function updateClock() {
+ const now = new Date();
+ clockEl.textContent = formatClock(now);
+ scheduleNextClockTick();
+}
-// Init
-updateTimes();
-setInterval(updateTimes, 200);
-window.addEventListener('resize', updateTimes);
+function scheduleNextClockTick() {
+ const delay = 1000 - new Date().getMilliseconds();
+ setTimeout(updateClock, delay);
+}
+
+function updateDiffs() {
+ const now = new Date();
+ for (let hour = FIRST_HOUR; hour <= LAST_HOUR; hour++) {
+ const target = new Date();
+ target.setHours(hour - TRAVEL_TIME_HOURS, 0, 0, 0);
+ diffNodes[hour - FIRST_HOUR].textContent = diffText(target.getTime(), now.getTime());
+ }
+ scheduleNextDiffTick();
+}
+
+function scheduleNextDiffTick() {
+ const now = new Date();
+ const msUntilNextMinute =
+ (60 - now.getSeconds()) * 1000 - now.getMilliseconds();
+ setTimeout(updateDiffs, msUntilNextMinute);
+}
+
+function checkDayChange() {
+ const now = new Date();
+ const key =
+ now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
+ if (key !== lastDayKey) {
+ lastDayKey = key;
+ dateEl.textContent = formatDate(now);
+ buildCalendar();
+ }
+}
+
+function init() {
+ clockEl = document.getElementById("currentTime");
+ dateEl = document.getElementById("currentDate");
+
+ buildTargetBlocks();
+ buildCalendar();
+
+ const now = new Date();
+ lastDayKey = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate();
+ dateEl.textContent = formatDate(now);
+
+ updateClock();
+ updateDiffs();
+
+ setInterval(checkDayChange, 60000);
+}
+
+function onResize() {
+ if (resizeTimer !== null) clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(function () {
+ resizeTimer = null;
+ const targetTimesElement = document.getElementById("targetTimes");
+ const leaveTimesElement = document.getElementById("leaveTimes");
+ const timeDifferencesElement = document.getElementById("timeDifferences");
+
+ const allBlocks = [].slice.call(
+ timeDifferencesElement.querySelectorAll(".time-block:not(.label-block)")
+ );
+ const targetBlocks = [].slice.call(
+ targetTimesElement.querySelectorAll(".time-block:not(.label-block)")
+ );
+ const leaveBlocks = [].slice.call(
+ leaveTimesElement.querySelectorAll(".time-block:not(.label-block)")
+ );
+
+ distributeBlocks(targetTimesElement, targetBlocks);
+ distributeBlocks(leaveTimesElement, leaveBlocks);
+ distributeBlocks(timeDifferencesElement, allBlocks);
+ }, 150);
+}
+
+init();
+window.addEventListener("resize", onResize);