File "table0021_split_0021.php"
Full Path: /home/analogde/www/Chart burndown/table0021_split_0021.php
File size: 89.36 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/*
je veux que tu rajoute un bouton nommé snap qui a chaque fois que l'on clique dessus va appeler une fonction qui va venir lire le contenu de toutes les cellules de chaque ligne standand pour venir mettre à jour l'objet correspondant. de la meme façon, il faudra venir recupérer le contenu de toutes lles cellules de chaque ligne estimation pour venir remplir l'objet corresqondant. Enfin, on viendra afficher sur la console du navigateur le contenu des tous ces objets.
*/
function getWorkingDays($startDate, $endDate, $holidays = []) {
$start = strtotime($startDate);
$end = strtotime($endDate);
$workingDays = [];
setlocale(LC_TIME, 'fr_FR.UTF-8');
for ($currentDate = $start; $currentDate <= $end; $currentDate = strtotime("+1 day", $currentDate)) {
$dayOfWeek = date("N", $currentDate);
if ($dayOfWeek < 6 && !in_array(date("Y-m-d", $currentDate), $holidays)) {
$workingDays[] = [
'day' => date("d", $currentDate),
'day_of_week_initial' => strtoupper(strftime("%A", $currentDate)[0]),
'week_number' => date("W", $currentDate),
'full_date' => date("Y-m-d", $currentDate) // Ajout de la date complète
];
}
}
return $workingDays;
}
// Liste des jours fériés et fêtes religieuses à exclure (exemple pour la France, à compléter avec d'autres fêtes)
$holidays = [
"2025-01-01", // Jour de l'An
"2025-04-14", // Lundi de Pâques
"2025-05-01", // Fête du Travail
"2025-05-08", // Victoire 1945
"2025-07-14", // Bastille
"2025-08-15", // Assomption
"2025-11-01", // Toussaint
"2025-12-25", // Noël
"2026-01-01", // Jour de l'An
"2026-04-06", // Lundi de Pâques
// Ajouter d'autres jours fériés ici...
];
// Définir la période de début et de fin
$startDate = "2025-01-10";
$endDate = "2026-02-14";
// Appeler la fonction pour obtenir les jours ouvrés entre les deux dates
$workingDays = getWorkingDays($startDate, $endDate, $holidays);
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tableau Sticky - 3 Lignes Fixes</title>
<style>
.table-wrapper {
width: 100%;
height: calc(100vh - 100px);
overflow: auto;
border: 1px solid #ccc;
position: relative;
}
table {
border-collapse: collapse;
width: max-content;
table-layout: fixed;
}
th, td {
padding: 3px;
text-align: center;
height: 40px;
border: 1px solid #ccc;
white-space: nowrap;
min-width: 120px;
position: relative;
background-color: white;
box-sizing: border-box;
}
th {
background-color: #f2f2f2;
position: sticky;
top: 0;
z-index: 100;
}
th:first-child, td:first-child {
position: sticky;
left: 0;
z-index: 101;
background-color: white;
}
th:nth-child(2), td:nth-child(2) {
position: sticky;
left: 120px;
z-index: 100;
background-color: white;
}
th:nth-child(3), td:nth-child(3) {
position: sticky;
left: 240px;
z-index: 99;
background-color: white;
}
th:first-child::after, td:first-child::after,
th:nth-child(2)::after, td:nth-child(2)::after,
th:nth-child(3)::after, td:nth-child(3)::after {
content: "";
position: absolute;
right: 0;
top: 0;
width: 2px;
height: 100%;
background-color: #ccc;
z-index: 102;
}
tbody tr:nth-child(odd) {
background-color: #f9f9f9;
}
th:nth-child(n+4), td:nth-child(n+4) {
min-width: 40px;
max-width: 40px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.second-header th {
background-color: #f2f2f2;
position: sticky;
top: 40px;
z-index: 99;
}
.third-header th {
background-color: #f2f2f2;
position: sticky;
top: 80px;
z-index: 98;
}
.second-header th:first-child, .third-header th:first-child {
left: 0;
z-index: 101;
background-color: white;
}
.second-header th:nth-child(2), .third-header th:nth-child(2) {
left: 120px;
z-index: 100;
background-color: white;
}
.second-header th:nth-child(3), .third-header th:nth-child(3) {
left: 240px;
z-index: 99;
background-color: white;
}
thead tr:first-child th:first-child,
thead tr:first-child th:nth-child(2),
thead tr:first-child th:nth-child(3) {
z-index: 105;
background-color: #ddd;
}
.second-header th:first-child,
.second-header th:nth-child(2),
.second-header th:nth-child(3) {
z-index: 104;
}
.third-header th:first-child,
.third-header th:nth-child(2),
.third-header th:nth-child(3) {
z-index: 103;
}
thead tr:first-child th,
.second-header th,
.third-header th {
box-shadow: inset 0 -2px #aaa;
background-clip: padding-box;
padding-bottom: 2px;
margin-bottom: -2px;
z-index: 100;
}
.second-header th {
top: calc(40px + 2px);
margin-top: 2px;
}
.third-header th {
top: calc(80px + 2px);
margin-top: 2px;
}
.even-week {
background-color: #ffcc99 !important;
}
.odd-week {
background-color: #e6b3ff !important;
}
.fourth-header th {
background-color: #f2f2f2;
position: sticky;
top: 120px;
z-index: 97;
}
.fourth-header th:first-child {
left: 0;
z-index: 101;
background-color: white;
}
.fourth-header th:nth-child(2) {
left: 120px;
z-index: 100;
background-color: white;
}
.fourth-header th:nth-child(3) {
left: 240px;
z-index: 99;
background-color: white;
}
.fourth-header th:first-child,
.fourth-header th:nth-child(2),
.fourth-header th:nth-child(3) {
z-index: 102;
}
.fourth-header th {
top: calc(120px + 2px);
margin-top: 2px;
}
.fourth-header th {
box-shadow: inset 0 -2px #aaa;
background-clip: padding-box;
padding-bottom: 2px;
margin-bottom: -2px;
z-index: 97;
}
.month-even {
background-color: #99ccff !important;
}
.month-odd {
background-color: #ff9999 !important;
}
.btn {
margin-bottom: 20px;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: #45a049;
}
.btn-special {
background-color: #2196F3;
}
.btn-special:hover {
background-color: #1e88e5;
}
.btn-special:hover {
background-color: #1e88e5;
}
#contextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#contextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#contextMenu .dropdown-item:hover {
background: #f8f9fa;
}
#specialContextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#specialContextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#specialContextMenu .dropdown-item:hover {
background: #f8f9fa;
}
#colorContextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#colorContextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#colorContextMenu .dropdown-item:hover {
background: #f8f9fa;
}
.add-button {
background-color: orange;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
margin-left: 5px;
}
.editable-input {
width: 65px;
box-sizing: border-box;
}
.collapsed {
display: none;
}
#jsonOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
#logOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
.no-click {
pointer-events: none;
}
#debugOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
<div class="modal fade" id="confirmationModal" tabindex="-1" aria-labelledby="confirmationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmationModalLabel">Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Voulez-vous vraiment supprimer cette ligne ?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelDelete">Annuler</button>
<button type="button" class="btn btn-danger" id="confirmDelete">OK</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="successModal" tabindex="-1" aria-labelledby="successModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="successModalLabel">Succès</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Données sauvegardées avec succès !
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="closeSuccessModal">OK</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="messageModalLabel">Message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" id="messageModalBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<div id="colorContextMenu" class="dropdown-menu" style="display: none;">
<button class="dropdown-item" style="background-color: green;" data-color="green">Vert</button>
<button class="dropdown-item" style="background-color: blue;" data-color="blue">Bleu</button>
<button class="dropdown-item" style="background-color: red;" data-color="red">Rouge</button>
<button class="dropdown-item" style="background-color: yellow;" data-color="yellow">Jaune</button>
<button class="dropdown-item" style="background-color: orange;" data-color="orange">Orange</button>
<button class="dropdown-item" style="background-color: purple;" data-color="purple">Violet</button>
<button class="dropdown-item" style="background-color: pink;" data-color="pink">Rose</button>
<button class="dropdown-item" style="background-color: brown;" data-color="brown">Marron</button>
<button class="dropdown-item" style="background-color: cyan;" data-color="cyan">Cyan</button>
<button class="dropdown-item" style="background-color: gray;" data-color="gray">Gris</button>
</div>
<div class="modal fade" id="rangeSelectionModal" tabindex="-1" aria-labelledby="rangeSelectionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="rangeSelectionModalLabel">Sélection de Plage</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="startCellId">Cellule de Départ</label>
<input type="text" class="form-control" id="startCellId" disabled>
</div>
<div class="form-group">
<label for="endCellId">Cellule de Fin</label>
<input type="text" class="form-control" id="endCellId">
</div>
<div class="form-group">
<label for="rangeComboBox">Sélectionnez une valeur</label>
<select class="form-control" id="rangeComboBox">
</select>
</div>
<div id="rangeResult" class="form-group">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelRangeSelection">Annuler</button>
<button type="button" class="btn btn-primary" id="confirmRangeSelection">Valider</button>
</div>
</div>
</div>
</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th></th>
<th>plouf</th>
<th>cretin</th>
<?php foreach ($workingDays as $dateData): ?>
<th>
<?php echo $dateData['day']; ?> <br>
</th>
<?php endforeach; ?>
</tr>
<tr class="second-header">
<th></th>
<th>Valeur 1</th>
<th>Valeur 2</th>
<?php
$currentWeek = null;
$weekClass = "";
foreach ($workingDays as $dateData):
if ($currentWeek !== $dateData['week_number']) {
$currentWeek = $dateData['week_number'];
$weekClass = ($currentWeek % 2 === 0) ? 'even-week' : 'odd-week';
}
?>
<th class="<?= $weekClass; ?>"><?php echo $dateData['day_of_week_initial']; ?></th>
<?php endforeach; ?>
</tr>
<tr class="third-header">
<th></th>
<th>Info 1</th>
<th>Info 2</th>
<?php
$currentWeek = null;
$colspan = 0;
foreach ($workingDays as $index => $dateData):
if ($currentWeek !== $dateData['week_number']) {
if ($currentWeek !== null) {
$weekClass = $currentWeek % 2 === 0 ? 'even-week' : 'odd-week';
echo '<th class="' . $weekClass . '" colspan="' . $colspan . '">' . $currentWeek . '</th>';
}
$currentWeek = $dateData['week_number'];
$colspan = 1;
} else {
$colspan++;
}
endforeach;
if ($currentWeek !== null) {
$weekClass = $currentWeek % 2 === 0 ? 'even-week' : 'odd-week';
echo '<th class="' . $weekClass . '" colspan="' . $colspan . '">' . $currentWeek . '</th>';
}
?>
</tr>
<tr class="fourth-header">
<th></th>
<th>Label 1</th>
<th>Label 2</th>
<?php
$currentMonthYear = null;
$colspan = 0;
$monthClass = "";
$colorIndex = 0;
$colors = ['month-even', 'month-odd'];
foreach ($workingDays as $index => $dateData):
$monthYear = ucfirst(strftime("%B %Y", strtotime($dateData['full_date'])));
if ($currentMonthYear !== $monthYear) {
if ($currentMonthYear !== null) {
echo '<th class="' . $monthClass . '" colspan="' . $colspan . '">' . $currentMonthYear . '</th>';
}
$currentMonthYear = $monthYear;
$colspan = 1;
$monthClass = $colors[$colorIndex % 2];
$colorIndex++;
} else {
$colspan++;
}
endforeach;
if ($currentMonthYear !== null) {
echo '<th class="' . $monthClass . '" colspan="' . $colspan . '">' . $currentMonthYear . '</th>';
}
?>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<button id="addRowButton" class="btn">Ajouter une ligne</button>
<button id="addSpecialRowButton" class="btn btn-special">Ajouter une ligne spéciale</button>
<button id="testButton" class="btn">TEST</button>
<button id="queryButton" class="btn">Query</button>
<button id="memButton" class="btn">Mem</button>
<button id="snapButton" class="btn">Snap</button>
<button id="visualizeLinkButton" class="btn">Objet</button>
<button id="titiButton" class="btn">Titi</button>
<button id="saveToDBButton" class="btn">ENREGISTRER</button>
<button id="exportButton" class="btn">EXPORT</button>
<button id="importButton" class="btn">IMPORT</button>
<button id="saveButton" class="btn">Save</button>
<button id="readButton" class="btn">Read</button>
<button id="logButton" class="btn">Log</button>
<div id="generatedDataOutput"></div>
<div id="jsonOutput"></div>
<div id="debugOutput"></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const tableBody = document.querySelector("tbody");
let specialRowCounter = 1;
let rowCounter = 1;
let linkageCounter = 1;
const specialRowStates = {};
const associations = {};
const linkages = [];
const standardRowsData = [];
const estimationRowsData = [];
let currentCell = null;
let keydownHandled = false;
let alertShown = false;
const contextMenu = document.createElement("div");
contextMenu.id = "contextMenu";
contextMenu.classList.add("dropdown-menu");
contextMenu.style.display = "none";
document.body.appendChild(contextMenu);
const specialContextMenu = document.createElement("div");
specialContextMenu.id = "specialContextMenu";
specialContextMenu.classList.add("dropdown-menu");
specialContextMenu.style.display = "none";
document.body.appendChild(specialContextMenu);
const colorContextMenu = document.getElementById("colorContextMenu");
const colorButtons = colorContextMenu.querySelectorAll(".dropdown-item");
colorButtons.forEach(button => {
button.addEventListener("click", function () {
const color = this.getAttribute("data-color");
const cell = document.querySelector(".selected-cell");
if (cell) {
cell.style.backgroundColor = color;
cell.dataset.cellColor = color;
hideColorContextMenu();
updateRowData(cell);
}
});
});
function generateRandomId(length = 8) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
function addRow(afterRow = null) {
const rowNumber = tableBody.rows.length + 1;
const newRow = document.createElement("tr");
newRow.setAttribute("draggable", "true");
newRow.dataset.rowId = `standard-${generateRandomId()}`;
const rowData = {
id: newRow.dataset.rowId,
name: `Row ${rowNumber}`,
selectValue: "1",
count: "0",
cells: []
};
const firstCells = [`Row ${rowNumber}`, "", "0"];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${rowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = rowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = rowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, newRow);
});
}
newRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${rowData.id}-${i}`;
td.dataset.cellValue = "0";
td.dataset.cellColor = "white";
td.textContent = "0";
td.style.backgroundColor = "white";
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(newRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
newRow.appendChild(td);
rowData.cells.push({
value: "0",
color: "white"
});
}
if (afterRow) {
tableBody.insertBefore(newRow, afterRow.nextSibling);
} else {
tableBody.appendChild(newRow);
}
newRow.addEventListener("dragstart", dragStart);
newRow.addEventListener("dragover", dragOver);
newRow.addEventListener("drop", drop);
rowCounter++;
standardRowsData.push(rowData);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = `estimation-${generateRandomId()}`;
estimationRow.classList.add("estimation-row");
const estimationRowData = {
id: estimationRow.dataset.rowId,
name: `Estimation ${rowNumber}`,
selectValue: "1",
estimationValue: "0"
};
const estimationFirstCells = [`Estimation ${rowNumber}`, "", "0"];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${estimationRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = estimationRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = estimationRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
}
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
if (afterRow) {
tableBody.insertBefore(estimationRow, newRow.nextSibling);
} else {
tableBody.appendChild(estimationRow);
}
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
const linkage = {
linkageId: `linkage-${generateRandomId()}`,
standardRowId: newRow.dataset.rowId,
estimationRowId: estimationRow.dataset.rowId
};
linkages.push(linkage);
displayLinkages();
rowCounter++;
estimationRowsData.push(estimationRowData);
}
function updateRowData(element) {
const row = element.closest("tr");
const rowId = row.dataset.rowId;
if (rowId.startsWith("standard-")) {
let standardRowData = standardRowsData.find(data => data.id === rowId);
if (!standardRowData) {
standardRowData = {
id: rowId,
name: "",
selectValue: "",
count: "",
cells: []
};
standardRowsData.push(standardRowData);
}
const cells = row.querySelectorAll("td");
standardRowData.name = cells[0].querySelector("input").value;
standardRowData.selectValue = cells[1].querySelector("select").value;
standardRowData.count = cells[2].textContent.trim();
standardRowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
standardRowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
console.log(`Mise à jour de la ligne standard : ${rowId}`);
} else if (rowId.startsWith("estimation-")) {
let estimationRowData = estimationRowsData.find(data => data.id === rowId);
if (!estimationRowData) {
estimationRowData = {
id: rowId,
name: "",
selectValue: "",
estimationValue: ""
};
estimationRowsData.push(estimationRowData);
}
const cells = row.querySelectorAll("td");
estimationRowData.name = cells[0].querySelector("input").value;
estimationRowData.selectValue = cells[1].querySelector("select").value;
estimationRowData.estimationValue = cells[2].querySelector("input").value;
console.log(`Mise à jour de la ligne d'estimation : ${rowId}`);
}
const objetTache = createObjetTache();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
}
function displayLinkages() {
const debugOutputElement = document.getElementById("debugOutput");
debugOutputElement.textContent = JSON.stringify(linkages, null, 2);
}
function updateCountCell(row) {
const countCell = row.cells[2];
const count = Array.from(row.cells).slice(3).filter(cell => cell.dataset.cellValue === "1").length;
countCell.textContent = count;
}
function addSpecialRow(afterRow = null) {
const newRow = document.createElement("tr");
newRow.classList.add("special-row");
newRow.setAttribute("draggable", "true");
newRow.dataset.rowId = `special-${generateRandomId()}`;
const firstCell = document.createElement("td");
firstCell.classList.add("row-header");
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.placeholder = `Ligne spéciale ${specialRowCounter}`;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
input.classList.remove("editing");
input.style.width = "65px";
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
}
});
input.addEventListener("input", function () {
updateRowData(input);
});
const addButton = document.createElement("button");
addButton.classList.add("add-button");
addButton.textContent = "+";
addButton.addEventListener("click", function () {
toggleCollapse(newRow);
});
firstCell.appendChild(input);
firstCell.appendChild(addButton);
firstCell.addEventListener("contextmenu", function (event) {
event.preventDefault();
showSpecialContextMenu(event, newRow);
});
newRow.appendChild(firstCell);
const mergedCell = document.createElement("td");
mergedCell.colSpan = 2;
mergedCell.textContent = "";
newRow.appendChild(mergedCell);
const td = document.createElement("td");
td.textContent = `Ligne spéciale ${specialRowCounter} - Détails`;
td.colSpan = document.querySelector("thead tr:nth-child(2)").cells.length - 3;
newRow.appendChild(td);
if (afterRow) {
tableBody.insertBefore(newRow, afterRow.nextSibling);
} else {
tableBody.appendChild(newRow);
}
newRow.addEventListener("dragstart", dragStart);
newRow.addEventListener("dragover", dragOver);
newRow.addEventListener("drop", drop);
specialRowCounter++;
}
function displayRowId(row) {
const rowId = row.dataset.rowId;
alert(`Identifiant de la ligne : ${rowId}`);
}
function toggleCollapse(specialRow) {
const nextSpecialRow = getNextSpecialRow(specialRow);
const rowsToToggle = [];
let currentRow = specialRow.nextElementSibling;
while (currentRow && currentRow !== nextSpecialRow) {
if (!currentRow.classList.contains("special-row")) {
rowsToToggle.push(currentRow);
}
currentRow = currentRow.nextElementSibling;
}
rowsToToggle.forEach(row => {
row.classList.toggle("collapsed");
});
}
function getNextSpecialRow(specialRow) {
let currentRow = specialRow.nextElementSibling;
while (currentRow) {
if (currentRow.classList.contains("special-row")) {
return currentRow;
}
currentRow = currentRow.nextElementSibling;
}
return null;
}
function showContextMenu(event, row) {
contextMenu.innerHTML = `
<button class="dropdown-item" id="add-row">Ajouter une ligne</button>
<button class="dropdown-item text-danger" id="delete-row">Supprimer cette ligne</button>
<button class="dropdown-item" id="show-linkage">Afficher la liaison</button>
`;
contextMenu.style.top = `${event.clientY}px`;
contextMenu.style.left = `${event.clientX}px`;
contextMenu.style.display = "flex";
contextMenu.style.flexDirection = "column";
document.getElementById("add-row").addEventListener("click", function () {
addRow(row);
hideContextMenu();
});
document.getElementById("delete-row").addEventListener("click", function () {
showConfirmationModal(row);
hideContextMenu();
});
document.getElementById("show-linkage").addEventListener("click", function () {
const linkage = linkages.find(link => link.standardRowId === row.dataset.rowId || link.estimationRowId === row.dataset.rowId);
if (linkage) {
alert(`Liaison trouvée :\nID: ${linkage.linkageId}\nLigne standard: ${linkage.standardRowId}\nLigne estimation: ${linkage.estimationRowId}`);
} else {
alert("Aucune liaison trouvée pour cette ligne.");
}
hideContextMenu();
});
}
function showSpecialContextMenu(event, row) {
specialContextMenu.innerHTML = `
<button class="dropdown-item" id="add-special-row">Ajouter une ligne spéciale</button>
<button class="dropdown-item text-danger" id="delete-special-row">Supprimer cette ligne</button>
<label class="dropdown-item">
<input type="checkbox" id="special-checkbox"> Attacher
</label>
`;
specialContextMenu.style.top = `${event.clientY}px`;
specialContextMenu.style.left = `${event.clientX}px`;
specialContextMenu.style.display = "flex";
specialContextMenu.style.flexDirection = "column";
const checkbox = document.getElementById("special-checkbox");
const rowId = row.dataset.rowId;
let hasStandardRowsBelow = false;
let currentRow = row.nextElementSibling;
const standardRows = [];
while (currentRow && !currentRow.classList.contains("special-row")) {
if (!currentRow.classList.contains("special-row")) {
hasStandardRowsBelow = true;
standardRows.push(currentRow);
}
currentRow = currentRow.nextElementSibling;
}
if (hasStandardRowsBelow) {
checkbox.disabled = false;
} else {
checkbox.disabled = true;
checkbox.checked = false;
}
if (specialRowStates[rowId]) {
checkbox.checked = specialRowStates[rowId].checked;
}
checkbox.addEventListener("change", function () {
specialRowStates[rowId] = {
checked: checkbox.checked,
rows: standardRows
};
standardRows.forEach(standardRow => {
const firstCell = standardRow.querySelector("td:first-child");
if (checkbox.checked) {
firstCell.style.backgroundColor = "yellow";
standardRow.classList.add("no-drag");
} else {
firstCell.style.backgroundColor = "";
standardRow.classList.remove("no-drag");
}
});
if (checkbox.checked) {
associations[rowId] = standardRows.map(row => row.dataset.rowId);
} else {
delete associations[rowId];
}
console.log(`Lignes standards concernées : ${standardRows.map(row => row.rowIndex).join(", ")}`);
});
document.getElementById("add-special-row").addEventListener("click", function () {
addSpecialRow(row);
hideSpecialContextMenu();
});
document.getElementById("delete-special-row").addEventListener("click", function () {
showConfirmationModal(row);
hideSpecialContextMenu();
});
}
function showColorContextMenu(event, cell) {
colorContextMenu.style.top = `${event.clientY}px`;
colorContextMenu.style.left = `${event.clientX}px`;
colorContextMenu.style.display = "flex";
colorContextMenu.style.flexDirection = "column";
document.querySelectorAll(".selected-cell").forEach(c => c.classList.remove("selected-cell"));
cell.classList.add("selected-cell");
}
function queryTableData() {
const tableData = [];
const rows = tableBody.querySelectorAll("tr");
rows.forEach(row => {
const rowData = {};
const cells = row.querySelectorAll("td");
if (row.dataset.rowId.startsWith("special-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
} else if (row.dataset.rowId.startsWith("estimation-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
rowData.estimationValue = cells[2].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
} else {
rowData.id = row.dataset.rowId;
rowData.name = cells[0].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
rowData.count = cells[2].textContent.trim();
rowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
rowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
}
tableData.push(rowData);
});
displayQueryData(tableData);
}
function displayQueryData(data) {
const debugOutputElement = document.getElementById("debugOutput");
const queryDataText = data.map(rowData => {
if (rowData.id.startsWith("special-")) {
return `ID: ${rowData.id}\nName: ${rowData.name}\n`;
} else if (rowData.id.startsWith("estimation-")) {
return `ID: ${rowData.id}\nName: ${rowData.name}\nEstimation Value: ${rowData.estimationValue}\nSelect Value: ${rowData.selectValue}\n`;
} else {
return `ID: ${rowData.id}\nName: ${rowData.name}\nSelect Value: ${rowData.selectValue}\nCount: ${rowData.count}\nCells: ${rowData.cells ? rowData.cells.map(cell => `${cell.value} (${cell.color})`).join(", ") : ""}\n`;
}
}).join("\n");
debugOutputElement.textContent = queryDataText;
}
function showConfirmationModal(row) {
const modal = new bootstrap.Modal(document.getElementById('confirmationModal'));
modal.show();
document.getElementById('confirmDelete').addEventListener('click', function () {
const estimationRow = row.nextElementSibling.classList.contains("estimation-row") ? row.nextElementSibling : row.previousElementSibling;
row.remove();
estimationRow.remove();
const linkageIndex = linkages.findIndex(link => link.standardRowId === row.dataset.rowId || link.estimationRowId === row.dataset.rowId);
if (linkageIndex !== -1) {
linkages.splice(linkageIndex, 1);
}
regenerateTableAfterDeletion();
logRowContents(row);
logRowContents(estimationRow);
modal.hide();
});
document.getElementById('cancelDelete').addEventListener('click', function () {
modal.hide();
});
}
function regenerateTableAfterDeletion() {
tableBody.innerHTML = "";
linkages.forEach(linkage => {
const standardRow = document.createElement("tr");
standardRow.setAttribute("draggable", "true");
standardRow.dataset.rowId = linkage.standardRowId;
const firstCells = ["Row", "", "0"];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.standardRowId}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, standardRow);
});
}
standardRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.standardRowId}-${i}`;
td.dataset.cellValue = "0";
td.dataset.cellColor = "white";
td.textContent = "0";
td.style.backgroundColor = "white";
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(standardRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
standardRow.appendChild(td);
}
tableBody.appendChild(standardRow);
standardRow.addEventListener("dragstart", dragStart);
standardRow.addEventListener("dragover", dragOver);
standardRow.addEventListener("drop", drop);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = linkage.estimationRowId;
estimationRow.classList.add("estimation-row");
const estimationFirstCells = ["Estimation", "", "0"];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.estimationRowId}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = "Estimation";
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
tableBody.appendChild(estimationRow);
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
});
displayLinkages();
}
function showMessageModal(message) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = message;
modal.show();
}
document.addEventListener("click", function (event) {
if (!contextMenu.contains(event.target)) {
hideContextMenu();
}
if (!specialContextMenu.contains(event.target)) {
hideSpecialContextMenu();
}
if (!colorContextMenu.contains(event.target)) {
hideColorContextMenu();
}
const inputs = document.querySelectorAll(".editable-input");
inputs.forEach(input => {
if (!input.contains(event.target)) {
input.classList.remove("editing");
}
});
});
document.addEventListener("keydown", function (event) {
if (event.key === "Escape") {
hideContextMenu();
hideSpecialContextMenu();
hideColorContextMenu();
}
});
function hideContextMenu() {
contextMenu.style.display = "none";
}
function hideSpecialContextMenu() {
specialContextMenu.style.display = "none";
}
function hideColorContextMenu() {
colorContextMenu.style.display = "none";
}
document.getElementById("addRowButton").addEventListener("click", addRow);
document.getElementById("addSpecialRowButton").addEventListener("click", addSpecialRow);
document.getElementById("testButton").addEventListener("click", function () {
alert("Le bouton TEST a été cliqué !");
fetch("get_values.php")
.then(response => response.json())
.then(data => {
console.log("Données reçues :", data);
displayValues(data);
})
.catch(error => {
console.error("Erreur lors de la récupération des données :", error);
showMessageModal("Une erreur est survenue lors de la récupération des données.");
});
});
function displayValues(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const valuesText = data.map(row => row.join(", ")).join("\n");
jsonOutputElement.textContent = valuesText;
}
document.querySelectorAll("tbody tr td:first-child").forEach(td => {
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, td.parentElement);
});
});
function dragStart(event) {
const row = event.target.closest("tr");
if (row.classList.contains("no-drag")) {
event.preventDefault();
return;
}
event.dataTransfer.setData("text/plain", row.rowIndex);
row.classList.add("dragging");
}
function dragOver(event) {
event.preventDefault();
const draggingRow = document.querySelector(".dragging");
const targetRow = event.target.closest("tr");
if (targetRow && draggingRow !== targetRow && !targetRow.classList.contains("no-drag")) {
const rect = targetRow.getBoundingClientRect();
const offset = rect.top + (rect.height / 2);
if (event.clientY - offset > 0) {
tableBody.insertBefore(draggingRow, targetRow.nextSibling);
} else {
tableBody.insertBefore(draggingRow, targetRow);
}
}
}
function drop(event) {
event.preventDefault();
const draggingRow = document.querySelector(".dragging");
draggingRow.classList.remove("dragging");
if (draggingRow.classList.contains("special-row")) {
const specialRowId = draggingRow.dataset.rowId;
if (associations[specialRowId]) {
const associatedRowIds = associations[specialRowId];
associatedRowIds.forEach(rowId => {
const associatedRow = document.querySelector(`tr[data-row-id="${rowId}"]`);
if (associatedRow) {
tableBody.insertBefore(associatedRow, draggingRow.nextSibling);
}
});
}
}
}
function traceTable() {
const tableData = [];
const rows = tableBody.querySelectorAll("tr");
rows.forEach(row => {
const rowData = {};
const cells = row.querySelectorAll("td");
if (row.dataset.rowId.startsWith("special-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
} else if (row.dataset.rowId.startsWith("estimation-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
rowData.estimationValue = cells[2].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
} else {
rowData.id = row.dataset.rowId;
rowData.name = cells[0].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
rowData.count = cells[2].textContent.trim();
rowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
rowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
}
tableData.push(rowData);
});
return tableData;
}
function saveToDB() {
const tableData = traceTable();
if (tableData.length === 0) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = "Le tableau est vide. Veuillez ajouter des lignes avant de sauvegarder.";
modal.show();
return;
}
fetch("save_objets_002.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans la base de données !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
});
fetch("save_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans le fichier JSON !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
});
}
function loadFromDB() {
fetch("load_mysql.php")
.then(response => response.json())
.then(data => {
regenerateTable(data);
displayTableData(data);
displayJSONData(data);
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors du chargement des données.");
});
}
function displayJSONData(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const jsonOutput = JSON.stringify(data, null, 2);
jsonOutputElement.textContent = jsonOutput;
}
function regenerateTable(data) {
tableBody.innerHTML = "";
data.forEach(rowData => {
const rowId = rowData.id;
if (rowId.startsWith("special-")) {
addSpecialRow();
const specialRow = tableBody.lastElementChild;
specialRow.dataset.rowId = rowId;
specialRow.querySelector("input").value = rowData.name;
} else if (rowId.startsWith("estimation-")) {
addRow();
const estimationRow = tableBody.lastElementChild;
estimationRow.dataset.rowId = rowId;
const cells = estimationRow.querySelectorAll("td");
cells[0].querySelector("input").value = rowData.name;
cells[1].querySelector("select").value = rowData.selectValue;
cells[2].querySelector("input").value = rowData.estimationValue;
} else {
addRow();
const standardRow = tableBody.lastElementChild;
standardRow.dataset.rowId = rowId;
const cells = standardRow.querySelectorAll("td");
cells[0].querySelector("input").value = rowData.name;
cells[1].querySelector("select").value = rowData.selectValue;
cells[2].textContent = rowData.count;
rowData.cells.forEach((cellData, index) => {
const cell = cells[index + 3];
cell.dataset.cellValue = cellData.value;
cell.dataset.cellColor = cellData.color;
cell.textContent = cellData.value;
cell.style.backgroundColor = cellData.color;
});
}
});
}
function displayTableData(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const tableDataText = data.map(rowData => {
return `ID: ${rowData.id}\nName: ${rowData.name}\nSelect Value: ${rowData.selectValue}\nCount: ${rowData.count}\nCells: ${rowData.cells ? rowData.cells.map(cell => `${cell.value} (${cell.color})`).join(", ") : ""}\n`;
}).join("\n");
jsonOutputElement.textContent = tableDataText;
}
function openRangeSelectionModal(cell) {
const modal = new bootstrap.Modal(document.getElementById('rangeSelectionModal'));
const startCellIdInput = document.getElementById('startCellId');
const endCellIdInput = document.getElementById('endCellId');
const rangeResult = document.getElementById('rangeResult');
const rangeComboBox = document.getElementById('rangeComboBox');
rangeComboBox.innerHTML = "";
for (let i = 1; i <= 50; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = i;
rangeComboBox.appendChild(option);
}
rangeComboBox.addEventListener("change", function () {
const startCellId = startCellIdInput.value;
const startParts = startCellId.split('-');
const startNumber = parseInt(startParts[2], 10);
const comboValue = parseInt(rangeComboBox.value, 10);
const totalDays = startNumber + comboValue;
const endCellId = `${startParts[0]}-${startParts[1]}-${totalDays}`;
console.log("Valeur sélectionnée :", comboValue);
console.log("Nb jours :", totalDays);
rangeResult.textContent = `Nb jours : ${totalDays}`;
endCellIdInput.value = endCellId;
});
startCellIdInput.value = cell.dataset.cellId;
endCellIdInput.value = "";
rangeResult.textContent = "Nb jours : 0";
modal.show();
document.getElementById('confirmRangeSelection').addEventListener('click', function () {
const startCellId = startCellIdInput.value;
const endCellId = endCellIdInput.value;
const comboValue = rangeComboBox.value;
alert(startCellId + " " + endCellId);
updateCellRange(startCellId, endCellId, comboValue);
modal.hide();
});
document.getElementById('cancelRangeSelection').addEventListener('click', function () {
modal.hide();
});
const modalHeader = modal._dialog.querySelector('.modal-header');
let isDragging = false;
let offsetX, offsetY;
modalHeader.addEventListener('mousedown', function (event) {
isDragging = true;
offsetX = event.clientX - modal._dialog.offsetLeft;
offsetY = event.clientY - modal._dialog.offsetTop;
modal._dialog.style.pointerEvents = 'none';
});
document.addEventListener('mousemove', function (event) {
if (isDragging) {
modal._dialog.style.left = `${event.clientX - offsetX}px`;
modal._dialog.style.top = `${event.clientY - offsetY}px`;
}
});
document.addEventListener('mouseup', function () {
isDragging = false;
modal._dialog.style.pointerEvents = 'all';
});
endCellIdInput.addEventListener('input', function () {
const startParts = startCellIdInput.value.split('-');
const endParts = endCellIdInput.value.split('-');
if (startParts.length === 3 && endParts.length === 3 && startParts[0] === endParts[0] && startParts[1] === endParts[1]) {
const startValue = parseInt(startParts[2], 10);
const endValue = parseInt(endParts[2], 10);
console.log(" ++ " + startValue + " " + endValue);
const result = endValue - startValue;
rangeResult.textContent = `Nb jours : ${result} jours`;
if (result > 0) {
alert(`Nb jours : ${result} jours`);
}
} else {
rangeResult.textContent = "Nb jours : 0";
}
});
}
function updateCellRange(startCellId, endCellId) {
const startCell = document.querySelector(`td[data-cell-id="${startCellId}"]`);
const endCell = document.querySelector(`td[data-cell-id="${endCellId}"]`);
if (startCell && endCell && startCell.parentElement === endCell.parentElement) {
const startIndex = Array.from(startCell.parentElement.cells).indexOf(startCell);
const endIndex = Array.from(endCell.parentElement.cells).indexOf(endCell);
for (let i = startIndex; i <= endIndex; i++) {
const cell = startCell.parentElement.cells[i];
cell.dataset.cellValue = "1";
cell.textContent = "1";
cell.style.backgroundColor = "green";
cell.dataset.cellColor = "green";
updateRowData(cell);
}
updateCountCell(startCell.parentElement);
} else {
showMessageModal("Les cellules doivent être sur la même ligne.");
}
}
tableBody.addEventListener("mouseover", function (event) {
const cell = event.target.closest("td");
if (cell) {
currentCell = cell;
}
});
document.addEventListener("keydown", function (event) {
if (event.key === "p" && currentCell) {
openRangeSelectionModal(currentCell);
}
});
document.getElementById("saveButton").addEventListener("click", function () {
const tableData = traceTable();
const jsonOutput = JSON.stringify(tableData, null, 2);
const jsonOutputElement = document.getElementById("jsonOutput");
jsonOutputElement.textContent = jsonOutput;
saveToDB();
});
document.getElementById("readButton").addEventListener("click", loadFromDB);
document.getElementById("logButton").addEventListener("click", function () {
const tableData = traceTable();
displayJSONData(tableData);
});
document.getElementById("queryButton").addEventListener("click", queryTableData);
function displayObjets() {
console.log(standardRowsData);
console.log(estimationRowsData);
}
document.getElementById("memButton").addEventListener("click", displayObjets);
document.getElementById("saveToDBButton").addEventListener("click", function () {
const tableData = traceTable();
if (tableData.length === 0) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = "Le tableau est vide. Veuillez ajouter des lignes avant de sauvegarder.";
modal.show();
return;
}
fetch("save_objets_001.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans la base de données !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
});
fetch("save_to_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans le fichier JSON !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
});
});
function createObjetTache() {
const objetTache = linkages.map(linkage => {
const standardRowData = standardRowsData.find(row => row.id === linkage.standardRowId);
const estimationRowData = estimationRowsData.find(row => row.id === linkage.estimationRowId);
return {
linkageId: linkage.linkageId,
standardRow: {
id: standardRowData.id,
name: standardRowData.name,
selectValue: standardRowData.selectValue,
count: standardRowData.count,
cells: standardRowData.cells
},
estimationRow: {
id: estimationRowData.id,
name: estimationRowData.name,
selectValue: estimationRowData.selectValue,
estimationValue: estimationRowData.estimationValue
}
};
});
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
return objetTache;
}
document.getElementById("exportButton").addEventListener("click", function () {
const objetTache = createObjetTache();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
fetch("export02.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(objetTache)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données exportées avec succès dans le fichier zzz.json !");
} else {
showMessageModal("Une erreur est survenue lors de l'exportation des données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de l'exportation des données.");
});
});
document.getElementById("importButton").addEventListener("click", function () {
fetch("import02.php")
.then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Import");
purgeAndRegenerateTable(data.objetTache);
showMessageModal("Données importées avec succès !");
} else {
showMessageModal("Blabla Une erreur est survenue lors de l'importation des données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Riri Une erreur est survenue lors de l'importation des données.");
});
});
function purgeAndRegenerateTable(objetTache) {
standardRowsData.length = 0;
estimationRowsData.length = 0;
linkages.length = 0;
objetTache.forEach(linkage => {
standardRowsData.push(linkage.standardRow);
estimationRowsData.push(linkage.estimationRow);
linkages.push({
linkageId: linkage.linkageId,
standardRowId: linkage.standardRow.id,
estimationRowId: linkage.estimationRow.id
});
});
console.log("TRACE ++++++++++++++++++++++");
regenerateTableAfterImport();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
}
function regenerateTableAfterImport() {
tableBody.innerHTML = "";
linkages.forEach(linkage => {
const standardRowData = standardRowsData.find(row => row.id === linkage.standardRowId);
const estimationRowData = estimationRowsData.find(row => row.id === linkage.estimationRowId);
const standardRow = document.createElement("tr");
standardRow.setAttribute("draggable", "true");
standardRow.dataset.rowId = standardRowData.id;
const firstCells = [standardRowData.name, "", standardRowData.count];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${standardRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = standardRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = standardRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, standardRow);
});
}
standardRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${standardRowData.id}-${i}`;
td.dataset.cellValue = standardRowData.cells[i].value;
td.dataset.cellColor = standardRowData.cells[i].color;
td.textContent = standardRowData.cells[i].value;
td.style.backgroundColor = standardRowData.cells[i].color;
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(standardRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
standardRow.appendChild(td);
}
tableBody.appendChild(standardRow);
standardRow.addEventListener("dragstart", dragStart);
standardRow.addEventListener("dragover", dragOver);
standardRow.addEventListener("drop", drop);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = estimationRowData.id;
estimationRow.classList.add("estimation-row");
const estimationFirstCells = [estimationRowData.name, "", estimationRowData.estimationValue];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${estimationRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = estimationRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = estimationRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
tableBody.appendChild(estimationRow);
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
});
displayLinkages();
}
document.getElementById("snapButton").addEventListener("click", function () {
const tableData = traceTable();
console.log("Objet Tache :", JSON.stringify(tableData, null, 2));
});
});
</script>
</body>
</html>