Compare commits
2 commits
4941ce5aaf
...
f4864e1c02
Author | SHA1 | Date | |
---|---|---|---|
f4864e1c02 | |||
d14988146b |
2 changed files with 262 additions and 43 deletions
|
@ -42,4 +42,8 @@ ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[title] {
|
||||||
|
cursor: help;
|
||||||
}
|
}
|
|
@ -37,6 +37,7 @@
|
||||||
}
|
}
|
||||||
table#view_table thead th {
|
table#view_table thead th {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
vertical-align: bottom;
|
||||||
}
|
}
|
||||||
table#view_table thead th:first-child {
|
table#view_table thead th:first-child {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -44,6 +45,14 @@
|
||||||
table#view_table thead th.me {
|
table#view_table thead th.me {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
table#view_table thead th img {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
border-radius: 50%;
|
||||||
|
max-width: 4em;
|
||||||
|
max-height: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
table#view_table tbody tr {
|
table#view_table tbody tr {
|
||||||
border-bottom: 1px solid #dddddd;
|
border-bottom: 1px solid #dddddd;
|
||||||
|
@ -55,6 +64,8 @@
|
||||||
table#view_table tbody th span {
|
table#view_table tbody th span {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 0.33em;
|
||||||
}
|
}
|
||||||
table#view_table tbody tr:nth-of-type(odd) {
|
table#view_table tbody tr:nth-of-type(odd) {
|
||||||
background-color: var(--colour_lightgrey);
|
background-color: var(--colour_lightgrey);
|
||||||
|
@ -113,68 +124,272 @@
|
||||||
<body>
|
<body>
|
||||||
<table id="view_table">
|
<table id="view_table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr id="view_table_thead_headers">
|
||||||
<th>
|
<th id="view_table_thead_name"></th>
|
||||||
<!-- Group name -->
|
|
||||||
Les abeilles en test
|
|
||||||
</th>
|
|
||||||
<!-- For-each group member -->
|
<!-- For-each group member -->
|
||||||
<th>Alice</th>
|
|
||||||
<th class="me">Moi (Loulou)</th>
|
|
||||||
<th>Bob</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<!-- For-each date -->
|
<!-- For-each date -->
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
Date #1
|
|
||||||
<br>
|
|
||||||
<span title="1🏠 + 1🚅">🇸🇪 2</span>
|
|
||||||
<span title="1🏠">🗼 1</span>
|
|
||||||
</th>
|
|
||||||
<!-- For-each group member -->
|
|
||||||
<td>
|
|
||||||
<span class="where">
|
|
||||||
🗼
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td class="me">
|
|
||||||
<span class="where">
|
|
||||||
🇸🇪
|
|
||||||
<i class="modifier modifier-bottom modifier-cross">🚅</i>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<span class="where">
|
|
||||||
🥨
|
|
||||||
<i class="modifier modifier-top modifier-cross">🏠</i>
|
|
||||||
<i class="modifier modifier-bottom modifier-cross">🚅</i>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th id="view_table_tfoot_total"></th>
|
||||||
<!-- Total -->
|
|
||||||
3 group members
|
|
||||||
</th>
|
|
||||||
|
|
||||||
<!-- Colspan = number of members -->
|
<!-- Colspan = number of members -->
|
||||||
<th colspan="3"></th>
|
<th id="view_table_tfoot_filler"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
So far, this group has planned between 2022-08-01 and 2024-11-25.
|
So far, this group has planned between
|
||||||
|
<span id="view_first_filled_date"></span>
|
||||||
|
and
|
||||||
|
<span id="view_last_filled_date"></span>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="index.html">Take me home!</a>
|
<a href="index.html">Take me home!</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<template id="row_date">
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<!-- For-each group member = availability -->
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
<template id="cell_availability">
|
||||||
|
<td>
|
||||||
|
<span class="where"></span>
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
<template id="modifier_cannot_host">
|
||||||
|
<i class="modifier modifier-top modifier-cross" title="Cannot host">🏠</i>
|
||||||
|
</template>
|
||||||
|
<template id="modifier_cannot_travel">
|
||||||
|
<i class="modifier modifier-bottom modifier-cross" title="Cannot travel">🚅</i>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var userUid = 1;
|
||||||
|
var viewData = {
|
||||||
|
view: {
|
||||||
|
name: "Le groupe des abeilles",
|
||||||
|
numberOfGroupMembers: 3,
|
||||||
|
firstFilledDate: "2023-05-06",
|
||||||
|
lastFilledDate: "2025-01-31"
|
||||||
|
},
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
uid: 1,
|
||||||
|
displayName: "Louis",
|
||||||
|
avatar: "https://static.david-david-studio.com/image/24511.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: 2,
|
||||||
|
displayName: "Mathilde",
|
||||||
|
avatar: "https://tinder.com/static/tinder.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: 3,
|
||||||
|
displayName: "Louis",
|
||||||
|
avatar: "https://www.aprifel.com/wp-content/uploads/2019/02/potiron.jpg"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dates: [
|
||||||
|
{
|
||||||
|
date: "2024-08-01",
|
||||||
|
membersAvailability: [
|
||||||
|
{
|
||||||
|
memberUid: 1,
|
||||||
|
location: "🇸🇪",
|
||||||
|
canHost: true,
|
||||||
|
canTravel: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
memberUid: 2,
|
||||||
|
location: "🗼",
|
||||||
|
canHost: true,
|
||||||
|
canTravel: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
memberUid: 3,
|
||||||
|
location: "🥨",
|
||||||
|
canHost: true,
|
||||||
|
canTravel: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
date: "2024-08-02",
|
||||||
|
membersAvailability: [
|
||||||
|
{
|
||||||
|
memberUid: 1,
|
||||||
|
location: "🗼",
|
||||||
|
canHost: false,
|
||||||
|
canTravel: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
memberUid: 2,
|
||||||
|
location: "🗼",
|
||||||
|
canHost: true,
|
||||||
|
canTravel: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
memberUid: 3,
|
||||||
|
location: "🥨",
|
||||||
|
canHost: true,
|
||||||
|
canTravel: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
function data2dom(data) {
|
||||||
|
// Retrieve common DOM elements
|
||||||
|
var headerRow = document.getElementById("view_table_thead_headers");
|
||||||
|
var tbody = document.getElementById("view_table").querySelector("tbody");
|
||||||
|
|
||||||
|
// Prepared data
|
||||||
|
var numberOfDisplayedMembers = data.members.length;
|
||||||
|
|
||||||
|
// Static: update header
|
||||||
|
document.getElementById("view_table_thead_name").textContent = data.view.name;
|
||||||
|
|
||||||
|
// Static: update footer
|
||||||
|
let strViewMembersCount = data.view.numberOfGroupMembers + " group member";
|
||||||
|
if(data.view.numberOfGroupMembers > 1) strViewMembersCount += "s";
|
||||||
|
document.getElementById("view_table_tfoot_total").textContent = strViewMembersCount;
|
||||||
|
document.getElementById("view_table_tfoot_filler").setAttribute("colspan", numberOfDisplayedMembers);
|
||||||
|
|
||||||
|
// Static: update below table
|
||||||
|
document.getElementById("view_first_filled_date").textContent = data.view.firstFilledDate;
|
||||||
|
document.getElementById("view_last_filled_date").textContent = data.view.lastFilledDate;
|
||||||
|
|
||||||
|
// For each member
|
||||||
|
data.members.forEach(element => {
|
||||||
|
let newCell = document.createElement("th");
|
||||||
|
let displayName;
|
||||||
|
|
||||||
|
if(element.uid == userUid) {
|
||||||
|
displayName = "Me (" + element.displayName + ")";
|
||||||
|
newCell.classList.add("me");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
displayName = element.displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(element.avatar) {
|
||||||
|
let newAvatar = document.createElement("img");
|
||||||
|
newAvatar.setAttribute("src", element.avatar);
|
||||||
|
newAvatar.setAttribute("alt", "Photo for " + element.displayName);
|
||||||
|
newCell.appendChild(newAvatar);
|
||||||
|
}
|
||||||
|
let newTextData = document.createTextNode(displayName);
|
||||||
|
newCell.appendChild(newTextData);
|
||||||
|
|
||||||
|
headerRow.appendChild(newCell);
|
||||||
|
});
|
||||||
|
// For each date
|
||||||
|
const rowDateTemplate = document.getElementById("row_date");
|
||||||
|
const cellAvailabilityTemplate = document.getElementById("cell_availability");
|
||||||
|
const modifierCannotHostTemplate = document.getElementById("modifier_cannot_host");
|
||||||
|
const modifierCannotTravelTemplate = document.getElementById("modifier_cannot_travel");
|
||||||
|
data.dates.forEach(element => {
|
||||||
|
let clonedRow = rowDateTemplate.content.cloneNode(true);
|
||||||
|
|
||||||
|
let header = clonedRow.querySelector("th");
|
||||||
|
let headerName = document.createTextNode(element.date);
|
||||||
|
header.appendChild(headerName);
|
||||||
|
|
||||||
|
let locations = [];
|
||||||
|
element.membersAvailability.forEach(availability => {
|
||||||
|
// Creating the DOM
|
||||||
|
let clonedCell = cellAvailabilityTemplate.content.cloneNode(true);
|
||||||
|
if(userUid == availability.memberUid) {
|
||||||
|
clonedCell.children[0].classList.add("me");
|
||||||
|
}
|
||||||
|
let whereSpan = clonedCell.querySelector("span.where");
|
||||||
|
let locationText = document.createTextNode(availability.location);
|
||||||
|
whereSpan.appendChild(locationText);
|
||||||
|
|
||||||
|
if(!availability.canHost) {
|
||||||
|
let clonedModifier = modifierCannotHostTemplate.content.cloneNode(true);
|
||||||
|
whereSpan.appendChild(clonedModifier);
|
||||||
|
}
|
||||||
|
if(!availability.canTravel) {
|
||||||
|
let clonedModifier = modifierCannotTravelTemplate.content.cloneNode(true);
|
||||||
|
whereSpan.appendChild(clonedModifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedRow.children[0].appendChild(clonedCell);
|
||||||
|
|
||||||
|
// Aggregating data per location, for totals
|
||||||
|
let existingLocations = locations.filter(e => e.location === availability.location);
|
||||||
|
if(existingLocations.length < 1) {
|
||||||
|
locations.push({
|
||||||
|
location: availability.location,
|
||||||
|
membersAvailable: 0,
|
||||||
|
hostsAvailable: 0,
|
||||||
|
travellersAvailable: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update other locations if member can travel
|
||||||
|
element.membersAvailability.forEach(availability => {
|
||||||
|
locations.forEach(existingLocation => {
|
||||||
|
if(existingLocation.location == availability.location) {
|
||||||
|
existingLocation.membersAvailable++;
|
||||||
|
if(availability.canHost) {
|
||||||
|
existingLocation.hostsAvailable++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(availability.canTravel) {
|
||||||
|
existingLocation.membersAvailable++;
|
||||||
|
existingLocation.travellersAvailable++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if(locations.length > 0) {
|
||||||
|
header.appendChild(document.createElement("br"));
|
||||||
|
}
|
||||||
|
locations.sort((a, b) => {
|
||||||
|
if(a.membersAvailable > b.membersAvailable) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if(a.membersAvailable < b.membersAvailable) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}).forEach(location => {
|
||||||
|
let spanLocation = document.createElement("span");
|
||||||
|
spanLocation.textContent = location.location + location.membersAvailable;
|
||||||
|
|
||||||
|
let title = [location.location + ": "];
|
||||||
|
if(location.hostsAvailable > 0) {
|
||||||
|
title.push(location.hostsAvailable + "🏠");
|
||||||
|
}
|
||||||
|
if(location.travellersAvailable > 0) {
|
||||||
|
title.push(location.travellersAvailable + "🚅");
|
||||||
|
}
|
||||||
|
let neitherHostNorTraveller = location.membersAvailable - location.hostsAvailable - location.travellersAvailable;
|
||||||
|
if(neitherHostNorTraveller > 0) {
|
||||||
|
title.push(neitherHostNorTraveller);
|
||||||
|
}
|
||||||
|
spanLocation.setAttribute("title", title.join(" "));
|
||||||
|
|
||||||
|
header.appendChild(spanLocation);
|
||||||
|
});
|
||||||
|
|
||||||
|
tbody.appendChild(clonedRow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
data2dom(viewData);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in a new issue