Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
VirtualKeyboardSample
/
Chart burndown
:
table0021_split_0022.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php 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; } function getFrenchHolidays($year) { $easterDate = easter_date($year); $holidays = []; // Jours fériés fixes $holidays[] = "$year-01-01"; // Jour de l'An $holidays[] = "$year-05-01"; // Fête du Travail $holidays[] = "$year-05-08"; // Victoire 1945 $holidays[] = "$year-07-14"; // Fête Nationale $holidays[] = "$year-08-15"; // Assomption $holidays[] = "$year-11-01"; // Toussaint $holidays[] = "$year-11-11"; // Armistice $holidays[] = "$year-12-25"; // Noël // Jours fériés variables (calculés à partir de Pâques) $easter = new DateTime("@$easterDate"); $easter->setTimezone(new DateTimeZone(date_default_timezone_get())); $holidays[] = $easter->format("Y-m-d"); // Pâques (non férié officiellement mais utile) $holidays[] = $easter->modify('+1 day')->format("Y-m-d"); // Lundi de Pâques $holidays[] = $easter->modify('+38 days')->format("Y-m-d"); // Ascension $holidays[] = $easter->modify('+11 days')->format("Y-m-d"); // Lundi de Pentecôte return $holidays; } $year = 2025; $holidays = []; $holidays = getFrenchHolidays($year); // Liste des jours fériés et fêtes religieuses à exclure (exemple pour la France, à compléter avec d'autres fêtes) $old_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; input.classList.remove("editing"); input.blur(); input.style.width = "65px"; console.clear; 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"; console.clear; 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; input.classList.remove("editing"); input.blur(); input.style.width = "65px"; console.clear; 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"; console.clear; 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); } } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); */ const input = document.createElement("input"); input.type = "text"; input.classList.add("editable-input"); input.value = "1"; //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.blur(); input.style.width = "65px"; console.clear; //updateRowData(input); const value = parseInt(input.value, 10); if (isNaN(value) || value < 1 || value > 365) { input.value = "1"; 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; input.classList.remove("editing"); input.blur(); input.style.width = "65px"; console.clear; ; //updateRowData(input); const value = parseInt(input.value, 10); if (isNaN(value) || value < 1 || value > 365) { input.value = "1"; 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); } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); 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); } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); 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 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); } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); 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); } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); 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); } } }); input.addEventListener("mousedown", function (event) { event.stopPropagation(); }); 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>