File "table0021_split_0012.php"
Full Path: /home/analogde/www/Chart burndown/table0021_split_0012.php
File size: 93.72 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>
/* Votre CSS ici */
.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;
}
.even-week {
background-color: #ffcc99 !important;
}
.odd-week {
background-color: #e6b3ff !important;
}
.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>
<!-- Autres liens et méta-informations -->
<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>
<!-- Modal Structure -->
<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>
<!-- Success Modal Structure -->
<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>
<!-- Message Modal Structure -->
<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">
<!-- Le contenu du message sera inséré ici -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<!-- Color Context Menu Structure -->
<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>
<!-- Range Selection Modal Structure -->
<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">
<!-- Les options seront ajoutées ici par JavaScript -->
</select>
</div>
<div id="rangeResult" class="form-group">
<!-- Le résultat de la soustraction sera affiché ici -->
</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> <!-- Nouveau bouton TEST -->
<button id="queryButton" class="btn">Query</button> <!-- Nouveau bouton Query -->
<button id="memButton" class="btn">Mem</button> <!-- Nouveau bouton Mem -->
<button id="snapButton" class="btn">Snap</button> <!-- Nouveau bouton Snap -->
<button id="visualizeLinkButton" class="btn">Objet</button> <!-- Nouveau bouton Objet -->
<button id="titiButton" class="btn">Titi</button> <!-- Nouveau bouton Titi -->
<button id="saveToDBButton" class="btn">ENREGISTRER</button>
<button id="exportButton" class="btn">EXPORT</button> <!-- Nouveau bouton EXPORT -->
<button id="importButton" class="btn">IMPORT</button> <!-- Nouveau bouton IMPORT -->
<button id="saveButton" class="btn">Save</button>
<button id="readButton" class="btn">Read</button>
<button id="logButton" class="btn">Log</button> <!-- Nouveau bouton Log -->
<div id="generatedDataOutput"></div>
<div id="jsonOutput"></div>
<div id="debugOutput"></div>
<!--
<div id="logOutput"></div>
-->
<!-- Zone de visualisation pour le log -->
<script>
document.addEventListener("DOMContentLoaded", function () {
const tableBody = document.querySelector("tbody");
let specialRowCounter = 1;
let rowCounter = 1; // Compteur pour les identifiants uniques des lignes
let linkageCounter = 1; // Compteur pour les identifiants uniques des liaisons
const specialRowStates = {}; // Objet pour stocker l'état des lignes spéciales
const associations = {}; // Objet pour stocker les associations entre lignes spéciales et standards
const linkages = []; // Tableau pour stocker les objets de liaison
const standardRowsData = []; // Tableau pour stocker les objets de ligne standard
const estimationRowsData = []; // Tableau pour stocker les objets de ligne d'estimation
let currentCell = null;
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; // Mettre à jour l'attribut de données
hideColorContextMenu();
updateRowData(cell); // Mettre à jour les objets en mémoire
}
});
});
function addRow(afterRow = null) {
const rowNumber = tableBody.rows.length + 1;
const newRow = document.createElement("tr");
newRow.setAttribute("draggable", "true");
newRow.dataset.rowId = `standard-row-${rowCounter}`; // Attribuer un identifiant unique
// Créer un objet pour stocker les valeurs par défaut de la ligne standard
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-${rowCounter}-${index}`; // Attribuer un identifiant unique à chaque cellule
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"; // Augmenter la largeur de l'input
//displayRowId(newRow); // Afficher l'identifiant de la ligne
});
input.addEventListener("blur", function () {
alert("sortie"); // Ajouter l'alerte
input.classList.remove("editing");
input.style.width = "65px"; // Restaurer la largeur d'origine
updateRowData(input); // Mettre à jour les objets en mémoire
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
alert("sortie"); // Ajouter l'alerte
input.classList.remove("editing");
input.blur();
input.style.width = "65px"; // Restaurer la largeur d'origine
updateRowData(input); // Mettre à jour les objets en mémoire
}
});
input.addEventListener("input", function () {
// Ne rien faire ici
});
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 () {
alert("sortie"); // Ajouter l'alerte
updateRowData(select); // Mettre à jour les objets en mémoire
});
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-${rowCounter}-${i}`; // Attribuer un identifiant unique en commençant à l'indice 0
td.dataset.cellValue = "0"; // Stocker la valeur dans un attribut de données
td.dataset.cellColor = "white"; // Stocker la couleur de fond dans un attribut de données
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);
alert("sortie"); // Ajouter l'alerte
updateRowData(td); // Mettre à jour les objets en mémoire
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
// Ajouter l'attribut title pour l'info-bulle uniquement pour les cellules des jours de travail
td.title = `ID: ${td.dataset.cellId}`;
newRow.appendChild(td);
// Initialiser les cellules dans l'objet rowData
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++; // Incrémenter le compteur pour le prochain identifiant
// Ajouter l'objet de la ligne au tableau
standardRowsData.push(rowData);
// Ajouter une ligne d'estimation
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = `estimation-row-${rowCounter}`; // Attribuer un identifiant unique
estimationRow.classList.add("estimation-row");
// Créer un objet pour stocker les valeurs par défaut de la ligne d'estimation
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-${rowCounter}-${index}`; // Attribuer un identifiant unique à chaque cellule
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"; // Augmenter la largeur de l'input
//displayRowId(newRow); // Afficher l'identifiant de la ligne
});
input.addEventListener("blur", function () {
alert("sortie"); // Ajouter l'alerte
input.classList.remove("editing");
input.style.width = "65px"; // Restaurer la largeur d'origine
updateRowData(input); // Mettre à jour les objets en mémoire
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
alert("sortie"); // Ajouter l'alerte
input.classList.remove("editing");
input.blur();
input.style.width = "65px"; // Restaurer la largeur d'origine
updateRowData(input); // Mettre à jour les objets en mémoire
}
});
input.addEventListener("input", function () {
// Ne rien faire ici
});
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 () {
alert("sortie"); // Ajouter l'alerte
updateRowData(select); // Mettre à jour les objets en mémoire
});
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"; // Réinitialiser la valeur si elle n'est pas valide
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
}
alert("sortie"); // Ajouter l'alerte
updateRowData(input); // Mettre à jour les objets en mémoire
});
input.addEventListener("input", function () {
// Ne rien faire ici
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
// Ajouter une cellule fusionnée pour les cellules entre la quatrième et la dernière
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3; // Fusionner toutes les cellules entre la quatrième et la dernière
mergedCell.textContent = ""; // Aucune valeur à l'intérieur
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);
// Créer un objet de liaison et l'ajouter au tableau
const linkage = {
id: `linkage-${linkageCounter}`, // Attribuer un identifiant unique
standardRowId: newRow.dataset.rowId,
estimationRowId: estimationRow.dataset.rowId
};
linkages.push(linkage);
// Afficher le contenu du tableau de liaisons dans la zone d'affichage texte
displayLinkages();
rowCounter++; // Incrémenter le compteur pour le prochain identifiant
linkageCounter++; // Incrémenter le compteur pour le prochain identifiant de liaison
// Ajouter l'objet de la ligne d'estimation au tableau
estimationRowsData.push(estimationRowData);
}
function updateRowData(element) {
const row = element.closest("tr");
const rowId = row.dataset.rowId;
if (rowId.startsWith("standard-row-")) {
const rowData = standardRowsData.find(data => data.id === rowId);
if (rowData) {
const cells = row.querySelectorAll("td");
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
});
}
});
console.log(`Mise à jour de la ligne standard : ${rowId}`);
}
} else if (rowId.startsWith("estimation-row-")) {
const rowData = estimationRowsData.find(data => data.id === rowId);
if (rowData) {
const cells = row.querySelectorAll("td");
rowData.name = cells[0].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
rowData.estimationValue = cells[2].querySelector("input").value;
console.log(`Mise à jour de la ligne d'estimation : ${rowId}`);
}
}
// Mettre à jour l'objetTache et afficher son contenu détaillé dans la console
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-row-${specialRowCounter}`; // Attribuer un identifiant unique
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"; // Augmenter la largeur de l'input
//displayRowId(newRow); // Afficher l'identifiant de la ligne
});
input.addEventListener("blur", function () {
input.classList.remove("editing");
input.style.width = "65px"; // Restaurer la largeur d'origine
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
input.classList.remove("editing");
input.blur();
input.style.width = "65px"; // Restaurer la largeur d'origine
}
});
input.addEventListener("input", function () {
updateRowData(input); // Mettre à jour les objets en mémoire
});
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);
// Supprimer la deuxième cellule et modifier la troisième cellule pour qu'elle soit vide et ait un colspan de 2
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.id}\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;
// Vérifier s'il y a des lignes standards immédiatement en dessous de la ligne spéciale
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;
}
// Restaurer l'état de la case à cocher
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");
}
});
// Créer ou mettre à jour l'association
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";
// Marquer la cellule comme sélectionnée
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-row-")) {
// Si c'est une ligne spéciale, prendre uniquement l'identifiant et le contenu de l'input text
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-row-")) {
// Si c'est une ligne d'estimation, prendre l'identifiant et la valeur de l'input text
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; // Ajouter la valeur d'estimation
rowData.selectValue = cells[1].querySelector("select").value; // Ajouter la valeur de la combo box
} else {
// Pour les lignes standards, prendre toutes les cellules
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-row-")) {
return `ID: ${rowData.id}\nName: ${rowData.name}\n`;
} else if (rowData.id.startsWith("estimation-row-")) {
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();
// Trouver l'index de l'objet liaison dans le tableau linkages
const linkageIndex = linkages.findIndex(link => link.standardRowId === row.dataset.rowId || link.estimationRowId === row.dataset.rowId);
if (linkageIndex !== -1) {
// Supprimer l'objet du tableau linkages
linkages.splice(linkageIndex, 1);
}
// Régénérer le tableau après la suppression
regenerateTableAfterDeletion();
// Afficher les contenus des cellules de la ligne standard et de la ligne d'estimation
logRowContents(row);
const estimationRow = row.nextElementSibling.classList.contains("estimation-row") ? row.nextElementSibling : row.previousElementSibling;
console.log(">>>>>> " + estimationRow);
logRowContents(estimationRow);
modal.hide();
});
document.getElementById('cancelDelete').addEventListener('click', function () {
modal.hide();
});
}
function regenerateTableAfterDeletion() {
// Vider le contenu actuel du tableau
tableBody.innerHTML = "";
// Parcourir les objets de liaison restants et ajouter les lignes correspondantes
linkages.forEach(linkage => {
// Ajouter la ligne standard
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 () {
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";
}
});
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);
}
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);
});
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);
// Ajouter la ligne d'estimation
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 () {
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";
}
});
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);
}
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.");
}
});
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);
});
// Mettre à jour le contenu du tableau de liaisons dans la zone d'affichage texte
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");
}
});
});
// Ajouter un gestionnaire d'événements pour écouter les événements de touche
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 () {
// Exemple de comportement : afficher une alerte
alert("Le bouton TEST a été cliqué !");
fetch("get_values.php")
.then(response => response.json())
.then(data => {
// Traiter les données reçues
console.log("Données reçues :", data);
// Vous pouvez ajouter ici le comportement souhaité pour traiter les données
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.");
});
// Vous pouvez ajouter ici le comportement souhaité pour le bouton TEST
});
function displayValues(data) {
// Exemple de fonction pour afficher les valeurs reçues
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");
// Si la ligne est une ligne spéciale, déplacer les lignes standards associées
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 = {}; // Créer un objet pour chaque ligne
const cells = row.querySelectorAll("td");
if (row.dataset.rowId.startsWith("special-row-")) {
// Si c'est une ligne spéciale, prendre uniquement l'identifiant et le contenu de l'input text
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-row-")) {
// Si c'est une ligne d'estimation, prendre l'identifiant et la valeur de l'input text
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; // Ajouter la valeur d'estimation
rowData.selectValue = cells[1].querySelector("select").value; // Ajouter la valeur de la combo box
} else {
// Pour les lignes standards, prendre toutes les cellules
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); // Ajouter l'objet de la ligne au tableau global
});
return tableData; // Retourner les données du tableau
}
function saveToDB() {
const tableData = traceTable(); // Utiliser traceTable pour obtenir les données du tableau
if (tableData.length === 0) {
// Afficher une fenêtre modale pour signaler que le tableau est vide
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) // Envoyer les données sous forme de JSON
})
.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.");
});
// Sauvegarder les données dans un fichier JSON
fetch("save_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData) // Envoyer les données sous forme de JSON
})
.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); // Afficher les données au format JSON
})
.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); // Convertir les données en JSON formaté
jsonOutputElement.textContent = jsonOutput; // Afficher le contenu JSON au format texte
}
function regenerateTable(data) {
tableBody.innerHTML = ""; // Vider le contenu actuel du tableau
data.forEach(rowData => {
const rowId = rowData.id;
if (rowId.startsWith("special-row-")) {
addSpecialRow();
const specialRow = tableBody.lastElementChild;
specialRow.dataset.rowId = rowId;
specialRow.querySelector("input").value = rowData.name;
} else if (rowId.startsWith("estimation-row-")) {
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; // Ajouter la valeur d'estimation
} 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; // Afficher le contenu au format texte
}
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');
// Remplir la combo box avec les valeurs de 1 à 50
rangeComboBox.innerHTML = "";
for (let i = 1; i <= 50; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = i;
rangeComboBox.appendChild(option);
}
// Ajouter un gestionnaire d'événements pour écouter les changements de la combo box
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 = `cell-${startParts[0]}-${startParts[1]}-${totalDays}`;
const endCellId = `${startParts[0]}-${startParts[1]}-${totalDays}`;
console.log("Valeur sélectionnée :", comboValue);
console.log("Nb jours :", totalDays);
rangeResult.textContent = `Nb jours : ${totalDays}`;
// Mettre à jour l'input de fin avec la nouvelle valeur
endCellIdInput.value = endCellId;
});
startCellIdInput.value = cell.dataset.cellId;
endCellIdInput.value = "";
rangeResult.textContent = "Nb jours : 0"; // Initialiser le résultat
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();
});
// Ajouter la fonctionnalité de déplacement de la fenêtre modale
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';
});
// Mettre à jour le résultat de la soustraction en temps réel
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); // Mettre à jour les objets en mémoire
}
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; // Afficher le contenu JSON au format texte
saveToDB(); // Sauvegarder les données dans la base de données et le fichier JSON
});
document.getElementById("readButton").addEventListener("click", loadFromDB);
document.getElementById("logButton").addEventListener("click", function () {
const tableData = traceTable();
displayJSONData(tableData); // Afficher les données JSON dans le div jsonOutput
});
document.getElementById("queryButton").addEventListener("click", queryTableData);
function displayObjets() {
console.log(standardRowsData);
console.log(estimationRowsData); // Afficher les objets de ligne d'estimation
}
document.getElementById("memButton").addEventListener("click", displayObjets);
document.getElementById("saveToDBButton").addEventListener("click", function () {
const tableData = traceTable(); // Utiliser traceTable pour obtenir les données du tableau
if (tableData.length === 0) {
// Afficher une fenêtre modale pour signaler que le tableau est vide
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) // Envoyer les données sous forme de JSON
})
.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.");
});
// Sauvegarder les données dans un fichier JSON
fetch("save_to_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData) // Envoyer les données sous forme de JSON
})
.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 {
id: linkage.id,
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") {
purgeAndRegenerateTable(data.objetTache);
showMessageModal("Données importées avec succès !");
} else {
showMessageModal("Une erreur est survenue lors de l'importation des données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de l'importation des données.");
});
});
function purgeAndRegenerateTable(objetTache) {
// Purger les objets existants
standardRowsData.length = 0;
estimationRowsData.length = 0;
linkages.length = 0;
// Régénérer les objets à partir des données importées
objetTache.forEach(linkage => {
standardRowsData.push(linkage.standardRow);
estimationRowsData.push(linkage.estimationRow);
linkages.push({
id: linkage.id,
standardRowId: linkage.standardRow.id,
estimationRowId: linkage.estimationRow.id
});
});
// Régénérer les lignes du tableau HTML
regenerateTableAfterImport();
}
function regenerateTableAfterImport() {
tableBody.innerHTML = ""; // Vider le contenu actuel du tableau
linkages.forEach(linkage => {
const standardRowData = standardRowsData.find(row => row.id === linkage.standardRowId);
const estimationRowData = estimationRowsData.find(row => row.id === linkage.estimationRowId);
// Ajouter la ligne standard
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 () {
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";
}
});
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;
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);
});
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);
// Ajouter la ligne d'estimation
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 () {
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";
}
});
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;
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.");
}
});
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);
});
// Mettre à jour le contenu du tableau de liaisons dans la zone d'affichage texte
displayLinkages();
}
});
</script>
</body>
</html>