diff --git a/app.js b/app.js index 3a0d349..4a52f3a 100644 --- a/app.js +++ b/app.js @@ -8,49 +8,49 @@ const NOW = new Date(); const timeTable = {}; function roomStatus(room, callback) { - return new Promise((resolve, _) => { - const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => { - const parser = new DOMParser(); - const doc = parser.parseFromString(xhr.responseText, 'text/html'); - const lessons = doc.querySelectorAll( - 'table.rsContentTable div.rsAptSimple'); - const parsed = []; + return new Promise((resolve, _) => { + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => { + const parser = new DOMParser(); + const doc = parser.parseFromString(xhr.responseText, 'text/html'); + const lessons = doc.querySelectorAll( + 'table.rsContentTable div.rsAptSimple'); + const parsed = []; - for (let lesson of lessons) { - const time = lesson.querySelector('span[id$=lblOrario]'); - const start = new Date(); - start.setHours(parseInt(time.innerText.substring(1,3))); - start.setMinutes(parseInt(time.innerText.substring(4,6))); - start.setSeconds(0); + for (let lesson of lessons) { + const time = lesson.querySelector('span[id$=lblOrario]'); + const start = new Date(); + start.setHours(parseInt(time.innerText.substring(1,3))); + start.setMinutes(parseInt(time.innerText.substring(4,6))); + start.setSeconds(0); - const end = new Date(); - end.setHours(parseInt(time.innerText.substring(7,9))); - end.setMinutes(parseInt(time.innerText.substring(10,12))); - end.setSeconds(0); + const end = new Date(); + end.setHours(parseInt(time.innerText.substring(7,9))); + end.setMinutes(parseInt(time.innerText.substring(10,12))); + end.setSeconds(0); - parsed.push({ - title: lesson.getAttribute('title'), - start: start, - end: end - }); - } - - resolve(parsed); + parsed.push({ + title: lesson.getAttribute('title'), + start: start, + end: end }); - xhr.open('GET', URL + room); - xhr.send(); + } + + resolve(parsed); }); + xhr.open('GET', URL + room); + xhr.send(); + }); } const ROOMS = [ - 'SI-003', - 'SI-015', - 'SI-004', - 'SI-006', - 'SI-013', - 'SI-007', - 'SI-008', + 'SI-003', + 'SI-015', + 'SI-004', + 'SI-006', + 'SI-013', + 'SI-007', + 'SI-008', ]; const ROOM_LIST = document.querySelector(".times"); @@ -59,100 +59,97 @@ const SLOT_TEMPLATE = document.getElementById("time-slot"); const FREE_SLOT_TEMPLATE = document.getElementById("time-free"); function getRoomNode() { - return document.importNode(ROOM_TEMPLATE.content, true); + return document.importNode(ROOM_TEMPLATE.content, true); } function formatTime(date) { - const twoDigits = (n) => { - return n < 10 ? "0" + n : n; - } + const twoDigits = (n) => { + return n < 10 ? "0" + n : n; + } - return twoDigits(date.getHours()) + ':' + - twoDigits(date.getMinutes()); + return twoDigits(date.getHours()) + ':' + + twoDigits(date.getMinutes()); } function colorRoom(roomTitle, node, time = NOW /* QuantumLeap */) { - const data = timeTable[roomTitle]; - if (data == undefined) { - return - } + const data = timeTable[roomTitle]; + if (data == undefined) { + return + } - const currentLecture = data.filter(d => d.start < time && d.end > time)[0]; - const isFree = currentLecture === void(0); - const block = document.getElementById(roomTitle); + const currentLecture = data.filter(d => d.start < time && d.end > time)[0]; + const isFree = currentLecture === void(0); + const block = document.getElementById(roomTitle); - block.className = block.className.replace(" room-in-use", "") - .replace(" room-free", ""); - block.className += isFree ? " room-free" : " room-in-use"; + block.className = block.className.replace(" room-in-use", "") + .replace(" room-free", ""); + block.className += isFree ? " room-free" : " room-in-use"; - block.querySelector('p').innerHTML = isFree ? 'Free' : - currentLecture.title + "
(" + formatTime(currentLecture.start) + " - " + - formatTime(currentLecture.end) + ")"; + block.querySelector('p').innerHTML = isFree ? 'Free' : + currentLecture.title + "
(" + formatTime(currentLecture.start) + " - " + + formatTime(currentLecture.end) + ")"; } async function buildRoomMarkup(roomTitle) { - const data = await roomStatus(roomTitle); - const room = getRoomNode(); - const title = room.querySelector('.room-title'); - title.innerHTML = roomTitle; - title.id = "schedule-" + roomTitle; - const list = room.querySelector('.list'); + const data = await roomStatus(roomTitle); + const room = getRoomNode(); + const title = room.querySelector('.room-title'); + title.innerHTML = roomTitle; + title.id = "schedule-" + roomTitle; + const list = room.querySelector('.list'); - for (const d of data) { - const slot = document.importNode(SLOT_TEMPLATE.content, true); - const title = slot.querySelector('.title'); - title.innerHTML = d.title; - const start = slot.querySelector('.start'); - start.innerHTML = formatTime(d.start); - const end = slot.querySelector('.end'); - end.innerHTML = formatTime(d.end); - list.appendChild(slot); - } + for (const d of data) { + const slot = document.importNode(SLOT_TEMPLATE.content, true); + const title = slot.querySelector('.title'); + title.innerHTML = d.title; + const start = slot.querySelector('.start'); + start.innerHTML = formatTime(d.start); + const end = slot.querySelector('.end'); + end.innerHTML = formatTime(d.end); + list.appendChild(slot); + } - timeTable[roomTitle] = data; - colorRoom(roomTitle, room); + timeTable[roomTitle] = data; + colorRoom(roomTitle, room); - if (data.length == 0) { - list.appendChild(document.importNode(FREE_SLOT_TEMPLATE.content, true)); - } + if (data.length == 0) { + list.appendChild(document.importNode(FREE_SLOT_TEMPLATE.content, true)); + } - ROOM_LIST.appendChild(room); + ROOM_LIST.appendChild(room); } function setTimePreview(date) { - const timePreview = document.getElementById('timepreviewer'); - timePreview.innerText = "Time: " + formatTime(date); + const timePreview = document.getElementById('timepreviewer'); + timePreview.innerText = "Time: " + formatTime(date); } function setupTimeMachine() { - const slider = document.getElementById('timemachine'); - slider.min = 8 * 60 + 30; - slider.max = 19 * 60 + 30; - - slider.addEventListener("input", (e) => { - const date = new Date(); - date.setHours(0); - date.setMinutes(slider.value); - const node = getRoomNode(); - - setTimePreview(date); - - ROOMS.forEach((roomTitle) => { - colorRoom(roomTitle, node, date); - }); - }); + const slider = document.getElementById('timemachine'); + slider.min = 8 * 60 + 30; + slider.max = 19 * 60 + 30; + slider.addEventListener("input", (e) => { const date = new Date(); - const mins = date.getHours() * 60 + date.getMinutes(); - slider.value = mins < slider.min ? slider.min : - mins > slider.max ? slider.max : mins; + date.setHours(0); + date.setMinutes(slider.value); + const node = getRoomNode(); + setTimePreview(date); + + ROOMS.forEach((roomTitle) => { + colorRoom(roomTitle, node, date); + }); + }); + + const date = new Date(); + const mins = date.getHours() * 60 + date.getMinutes(); + slider.value = mins < slider.min ? slider.min : + mins > slider.max ? slider.max : mins; + setTimePreview(date); } -(async () => { - for (const room of ROOMS) { - await buildRoomMarkup(room); - } -})(); +// Thanks to Andrea Gallidabino and his mastery checks for this +Promise.all(ROOMS.map(buildRoomMarkup)).catch(console.error); setupTimeMachine(); diff --git a/assets/index.css b/assets/index.css index 5e013f9..1681145 100644 --- a/assets/index.css +++ b/assets/index.css @@ -1,4 +1,5 @@ /* Inter font */ +/* vim: set ts=2 sw=2 et tw=80: */ @font-face { font-family: 'Inter'; @@ -6,7 +7,7 @@ font-weight: 400; font-display: swap; src: url("fonts/Inter-Regular.woff2") format("woff2"), - url("fonts/Inter-Regular.woff") format("woff"); + url("fonts/Inter-Regular.woff") format("woff"); } @font-face { @@ -15,243 +16,243 @@ font-weight: 800; font-display: swap; src: url("fonts/Inter-ExtraBold.woff2") format("woff2"), - url("fonts/Inter-ExtraBold.woff") format("woff"); + url("fonts/Inter-ExtraBold.woff") format("woff"); } /* Base */ * { - font-family: 'Inter', sans-serif; - color: #212529; + font-family: 'Inter', sans-serif; + color: #212529; } h1 { - text-align: center; - width: 100%; + text-align: center; + width: 100%; } h2 { - text-align: center; - width: 100%; + text-align: center; + width: 100%; } /* Slider */ input[type=range] { - -webkit-appearance: none; - border: 0; - height: 28px; - margin: 8px 0; - outline: none; - padding: 0 8px; - width: 100%; + -webkit-appearance: none; + border: 0; + height: 28px; + margin: 8px 0; + outline: none; + padding: 0 8px; + width: 100%; } input[type="range"]::-webkit-slider-runnable-track { - background: #b1b1bc; - border-radius: 2px; - height: 4px; + background: #b1b1bc; + border-radius: 2px; + height: 4px; } input[type="range"]::-moz-range-track { - background: #b1b1bc; - height: 4px; + background: #b1b1bc; + height: 4px; } input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - background: #212529; - border: 4px solid #ededf0; - border-radius: 50%; - cursor: pointer; - height: 28px; - margin-top: -12px; - width: 28px; + -webkit-appearance: none; + background: #212529; + border: 4px solid #ededf0; + border-radius: 50%; + cursor: pointer; + height: 28px; + margin-top: -12px; + width: 28px; } input[type="range"]::-moz-range-thumb { - background: #212529; - border: 4px solid #ededf0; - border-radius: 50%; - cursor: pointer; - height: 20px; - width: 20px; + background: #212529; + border: 4px solid #ededf0; + border-radius: 50%; + cursor: pointer; + height: 20px; + width: 20px; } input[type="range"]::-moz-focus-outer { - border: 0; + border: 0; } input[type="range"]::-moz-range-progress { - background: #212529; - border-radius: 4px; - height: 4px; + background: #212529; + border-radius: 4px; + height: 4px; } /* Room map */ .room-map { - display: flex; - flex-direction: row; - flex-wrap: wrap; - padding-left: 10vw; - padding-right: 10vw; - text-align: center; + display: flex; + flex-direction: row; + flex-wrap: wrap; + padding-left: 10vw; + padding-right: 10vw; + text-align: center; } .room { - margin: 0.5rem; - background: #ededf0; - border-radius: 6px; - padding: 0.5rem; - transition: all 0.5s ease; + margin: 0.5rem; + background: #ededf0; + border-radius: 6px; + padding: 0.5rem; + transition: all 0.5s ease; } .room:hover { - box-shadow: 0 4px 8px #0000002a; + box-shadow: 0 4px 8px #0000002a; } .room a { - text-decoration: none; + text-decoration: none; } .room h3 { - font-size: 1.6rem; - font-weight: 700; + font-size: 1.6rem; + font-weight: 700; } .room p { - font-size: 1.2rem; + font-size: 1.2rem; } .room-big { - flex: 1 1 100%; + flex: 1 1 100%; } .room-small { - flex: 1 1 45%; + flex: 1 1 45%; } .room-free { - background-color: #3FE1B0; + background-color: #3FE1B0; } .room-in-use { - background-color: #FF505F; + background-color: #FF505F; } @media screen and (max-width: 830px) { - .room { - padding: 0.2rem; - } + .room { + padding: 0.2rem; + } - .room-big { - flex: 1 1 80%; - } + .room-big { + flex: 1 1 80%; + } - .room-small { - flex: 1 1 35%; - } + .room-small { + flex: 1 1 35%; + } } /* Time */ .timepicker { - border: #00000033 solid 1px; - border-radius: 6px; - box-shadow: 0 1px 3px #0000001a; - display: flex; - flex-direction: column; - padding: 1rem; - margin: 2rem 5vw; - text-align: center; + border: #00000033 solid 1px; + border-radius: 6px; + box-shadow: 0 1px 3px #0000001a; + display: flex; + flex-direction: column; + padding: 1rem; + margin: 2rem 5vw; + text-align: center; } /* Schedule */ .schedule { - border: #00000033 solid 1px; - border-radius: 6px; - box-shadow: 0 1px 3px #0000001a; - padding: 1rem; - margin: 2rem 5vw; + border: #00000033 solid 1px; + border-radius: 6px; + box-shadow: 0 1px 3px #0000001a; + padding: 1rem; + margin: 2rem 5vw; } .schedule h2 { - font-weight: 800; - text-align: start; + font-weight: 800; + text-align: start; } /* Dark mode */ @media(prefers-color-scheme: dark) { - * { - color: #f9f9fa; - } + * { + color: #f9f9fa; + } - body { - background: #212529; - } + body { + background: #212529; + } - input[type="range"] { - background-color: #2d3339; - } + input[type="range"] { + background-color: #2d3339; + } - input[type="range"]::-webkit-slider-runnable-track { - background: #7a7a8b; - } + input[type="range"]::-webkit-slider-runnable-track { + background: #7a7a8b; + } - input[type="range"]::-moz-range-track { - background: #7a7a8b; - } + input[type="range"]::-moz-range-track { + background: #7a7a8b; + } - input[type="range"]::-webkit-slider-thumb { - background: #f9f9fa; - border: 4px solid #5e5e72; - } + input[type="range"]::-webkit-slider-thumb { + background: #f9f9fa; + border: 4px solid #5e5e72; + } - input[type="range"]::-moz-range-thumb { - background: #f9f9fa; - border: 4px solid #5e5e72; - } + input[type="range"]::-moz-range-thumb { + background: #f9f9fa; + border: 4px solid #5e5e72; + } - input[type="range"]::-moz-range-progress { - background: #f9f9fa; - } + input[type="range"]::-moz-range-progress { + background: #f9f9fa; + } - .room { - margin: 0.5rem; - background: #2d3339; - border-radius: 6px; - padding: 0.5rem; - transition: all 0.5s ease; - } + .room { + margin: 0.5rem; + background: #2d3339; + border-radius: 6px; + padding: 0.5rem; + transition: all 0.5s ease; + } - .room-free { - background-color: #3FE1B0; - } + .room-free { + background-color: #3FE1B0; + } - .room-free:hover { - box-shadow: 0 4px 8px #b3ffe333; - } + .room-free:hover { + box-shadow: 0 4px 8px #b3ffe333; + } - .room-in-use { - background-color: #ff6a75; - } + .room-in-use { + background-color: #ff6a75; + } - .room-in-use:hover { - box-shadow: 0 4px 8px #ff6a7533; - } + .room-in-use:hover { + box-shadow: 0 4px 8px #ff6a7533; + } - .timepicker { - border: #384047 solid 1px; - background-color: #2d3339; - box-shadow: 0 0 0 #00000000; - } + .timepicker { + border: #384047 solid 1px; + background-color: #2d3339; + box-shadow: 0 0 0 #00000000; + } - .schedule { - border: #384047 solid 1px; - background-color: #2d3339; - box-shadow: 0 0 0 #00000000; - } + .schedule { + border: #384047 solid 1px; + background-color: #2d3339; + box-shadow: 0 0 0 #00000000; + } } diff --git a/index.html b/index.html index 9860e6a..fae207f 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - + USI • Rooms availability @@ -10,86 +10,86 @@ - - + +

USI INF room availability

-

Loading...

- +

Loading...

+
-
- -

SI-003

-

???

-
-
- -
- -

SI-015

-

???

-
-
-
- -

SI-004

-

???

-
-
- -
- -

SI-006

-

???

-
-
- -
- -

SI-013

-

???

-
-
-
- -

SI-007

-

???

-
-
- -
- -

SI-008

-

???

-
-
+
+ +

SI-003

+

???

+
+
+ +
+ +

SI-015

+

???

+
+
+
+ +

SI-004

+

???

+
+
+ +
+ +

SI-006

+

???

+
+
+ +
+ +

SI-013

+

???

+
+
+
+ +

SI-007

+

???

+
+
+ +
+ +

SI-008

+

???

+
+
-

Schedule for today

-
-
+

Schedule for today

+
+
- + - + - +
- + diff --git a/manifest.json b/manifest.json index f5b0adf..3413bf6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,21 +1,23 @@ { - "short_name": "USI Rooms", - "name": "USI INF Rooms", - "icons": [ - { - "src": "./assets/images/icon-192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "./assets/images/icon-512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": "./index.html", - "background_color": "#fafafa", - "display": "standalone", - "scope": "./", - "theme_color": "#333333" + "_modeline": " vim: set ts=2 sw=2 et tw=80:", + + "short_name": "USI Rooms", + "name": "USI INF Rooms", + "icons": [ + { + "src": "./assets/images/icon-192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "./assets/images/icon-512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": "./index.html", + "background_color": "#fafafa", + "display": "standalone", + "scope": "./", + "theme_color": "#333333" }