File "tmp0027__base019.php"

Full Path: /home/analogde/www/Design/Dev tableau/tmp0027__base019.php
File size: 45.26 KB
MIME-type: text/x-php
Charset: utf-8

<?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;
}

// Liste des jours fériés et fêtes religieuses à exclure (exemple pour la France, à compléter avec d'autres fêtes)
$holidays = [
    "2025-01-01", // Jour de l'An
    "2025-04-14", // Lundi de Pâques
    "2025-05-01", // Fête du Travail
    "2025-05-08", // Victoire 1945
    "2025-07-14", // Bastille
    "2025-08-15", // Assomption
    "2025-11-01", // Toussaint
    "2025-12-25", // Noël
    "2026-01-01", // Jour de l'An
    "2026-04-06", // Lundi de Pâques
    // Ajouter d'autres jours fériés ici...
];

// Définir la période de début et de fin
$startDate = "2025-01-10";
$endDate = "2026-02-14";

// Appeler la fonction pour obtenir les jours ouvrés entre les deux dates
$workingDays = getWorkingDays($startDate, $endDate, $holidays);

?>


<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tableau Sticky - 3 Lignes Fixes</title>
    <style>
        .table-wrapper {
            width: 100%;
            height: calc(100vh - 100px); /* Ajustez les 100px selon la hauteur des autres éléments de la page */
            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;
            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;
        }

        #addRowButton {
            margin-bottom: 20px;
            padding: 10px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }

        #addRowButton:hover {
            background-color: #45a049;
        }

        #addSpecialRowButton {
            margin-bottom: 20px;
            padding: 10px;
            background-color: #2196F3;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }

        #addSpecialRowButton:hover {
            background-color: #1e88e5;
        }

        .special-row {
            background-color: #f0f0f0;
        }

        #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;
        }

        .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;
        }
    </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">&times;</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="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">Ajouter une ligne</button>
<button id="addSpecialRowButton">Ajouter une ligne spéciale</button>
<button id="saveToDBButton">Save to DB</button>
<button id="traceButton">Trace</button>
<button id="loadFromDBButton">Load from DB</button>

<button id="runButton">RUN</button>

<button id="saveButton">Save</button>
<button id="readButton">Read</button>
<div id="generatedDataOutput"></div>

<div id="jsonOutput"></div>

<script>

document.addEventListener("DOMContentLoaded", function () {
            const tableBody = document.querySelector("tbody");
            let specialRowCounter = 1;
            let rowCounter = 1; // Compteur pour les identifiants uniques des lignes
            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 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);

            function addRow(afterRow = null) {
                const rowNumber = tableBody.rows.length + 1;
                const newRow = document.createElement("tr");
                newRow.setAttribute("draggable", "true");
                newRow.dataset.rowId = `row-${rowCounter}`; // Attribuer un identifiant unique

                const firstCells = ["Row " + rowNumber, "", "0"];
                firstCells.forEach((text, index) => {
                    const td = document.createElement("td");
                    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"; // 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
                            }
                        });
                        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, 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; i++) {
                    const td = document.createElement("td");
                    td.textContent = "0";
                    td.style.backgroundColor = "white";

                    td.addEventListener("click", function () {
                        td.textContent = td.textContent === "0" ? "1" : "0";
                        td.style.backgroundColor = td.textContent === "1" ? "green" : "white";
                        updateCountCell(newRow);
                    });

                    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);

                rowCounter++; // Incrémenter le compteur pour le prochain identifiant
            }

            function updateCountCell(row) {
                const countCell = row.cells[2];
                const count = Array.from(row.cells).slice(3).filter(cell => cell.textContent === "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
                    }
                });

                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>
                `;

                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();
                });
            }

            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"> Attache
                    </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érifie 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 showConfirmationModal(row) {
                const modal = new bootstrap.Modal(document.getElementById('confirmationModal'));
                modal.show();

                document.getElementById('confirmDelete').addEventListener('click', function () {
                    row.remove();
                    modal.hide();
                });

                document.getElementById('cancelDelete').addEventListener('click', function () {
                    modal.hide();
                });
            }

            document.addEventListener("click", function (event) {
                if (!contextMenu.contains(event.target)) {
                    hideContextMenu();
                }
                if (!specialContextMenu.contains(event.target)) {
                    hideSpecialContextMenu();
                }
                const inputs = document.querySelectorAll(".editable-input");
                inputs.forEach(input => {
                    if (!input.contains(event.target)) {
                        input.classList.remove("editing");
                    }
                });
            });

            function hideContextMenu() {
                contextMenu.style.display = "none";
            }

            function hideSpecialContextMenu() {
                specialContextMenu.style.display = "none";
            }

            document.getElementById("addRowButton").addEventListener("click", addRow);
            document.getElementById("addSpecialRowButton").addEventListener("click", addSpecialRow);

            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);
                            }
                        });
                    }
                }
            }

            // Ajouter un bouton pour afficher les associations
            const displayButton = document.createElement("button");
            displayButton.textContent = "Afficher les associations";
            displayButton.disabled = true; // Désactiver le bouton
            document.body.appendChild(displayButton);

            displayButton.addEventListener("click", function () {
                const associationsContainer = document.createElement("div");
                associationsContainer.innerHTML = "<h3>Associations entre lignes spéciales et standards :</h3>";

                for (const specialRowId in associations) {
                    const standardRowIds = associations[specialRowId];
                    const associationItem = document.createElement("p");
                    associationItem.textContent = `Ligne spéciale ${specialRowId} associée aux lignes standards : ${standardRowIds.join(", ")}`;
                    associationsContainer.appendChild(associationItem);
                }

                document.body.appendChild(associationsContainer);
            });

            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 {
                        // 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(cell.textContent.trim());
                            }
                        });
                    }

                    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

                fetch("save_mysql.php", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json"
                    },
                    body: JSON.stringify(tableData)
                })
                .then(response => response.json())
                .then(data => {
                    alert("Données sauvegardées avec succès !");
                })
                .catch(error => {
                    console.error("Erreur :", error);
                });
            }

            function loadFromDB() {
                fetch("load_mysql.php")
                    .then(response => response.json())
                    .then(data => {
                        regenerateTable(data);
                        displayTableData(data);
                    })
                    .catch(error => {
                        console.error("Erreur :", error);
                    });
            }

            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 {
                        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.textContent = cellData;
                            cell.style.backgroundColor = cellData === "1" ? "green" : "white";
                        });
                    }
                });
            }

            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.join(", ") : ""}\n`;
                }).join("\n");
                jsonOutputElement.textContent = tableDataText; // Afficher le contenu au format texte
            }

            // Ajouter un gestionnaire d'événements pour le bouton "Save to DB"
            document.getElementById("saveToDBButton").addEventListener("click", saveToDB);

            // Ajouter un gestionnaire d'événements pour le bouton "Trace"
            document.getElementById("traceButton").addEventListener("click", function () {
                const tableData = traceTable();
                const jsonOutput = JSON.stringify(tableData, null, 2);
                const jsonOutputElement = document.getElementById("jsonOutput");
                jsonOutputElement.textContent = ""; // Effacer le contenu précédent
                jsonOutputElement.textContent = jsonOutput; // Ajouter le nouveau contenu JSON
            });

            // Ajouter un gestionnaire d'événements pour le bouton "Load from DB"
            document.getElementById("loadFromDBButton").addEventListener("click", loadFromDB);

            // Fonction pour générer des données aléatoires
            function generateRandomData() {
                const randomData = [];

                // Générer deux lignes standard
                for (let i = 0; i < 2; i++) {
                    const rowData = {
                        id: `row-${rowCounter + i}`,
                        name: `Row ${rowCounter + i}`,
                        selectValue: Math.floor(Math.random() * 10) + 1,
                        count: "0",
                        cells: []
                    };
                    const workingDaysCount = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)").length;
                    for (let j = 0; j < workingDaysCount; j++) {
                        const cellValue = Math.random() < 0.5 ? "0" : "1";
                        rowData.cells.push(cellValue);
                        if (cellValue === "1") {
                            rowData.count = (parseInt(rowData.count) + 1).toString();
                        }
                    }
                    randomData.push(rowData);
                }

                // Générer une ligne spéciale
                const specialRowData = {
                    id: `special-row-${specialRowCounter}`,
                    name: `Ligne spéciale ${specialRowCounter}`
                };
                randomData.push(specialRowData);

                return randomData;
            }

            // Fonction pour afficher les données générées dans la zone d'affichage
            function displayGeneratedData(data) {
                const generatedDataOutput = document.getElementById("generatedDataOutput");
                const jsonOutput = JSON.stringify(data, null, 2);
                generatedDataOutput.textContent = jsonOutput;
            }

            // Fonction pour purger les anciennes lignes et générer de nouvelles lignes
            function purgeAndGenerate() {
                tableBody.innerHTML = ""; // Vider le contenu actuel du tableau
                rowCounter = 1; // Réinitialiser le compteur de lignes
                specialRowCounter = 1; // Réinitialiser le compteur de lignes spéciales

                const randomData = generateRandomData();
                displayGeneratedData(randomData);

                // Ajouter les lignes générées au tableau
                randomData.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 {
                        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.textContent = cellData;
                            cell.style.backgroundColor = cellData === "1" ? "green" : "white";
                        });
                    }
                });
            }

            // Ajouter un gestionnaire d'événements pour le bouton "RUN"
            document.getElementById("runButton").addEventListener("click", purgeAndGenerate);

            // Ajouter un gestionnaire d'événements pour le bouton "Save"
            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
            });

            // Ajouter un gestionnaire d'événements pour le bouton "Read"
            document.getElementById("readButton").addEventListener("click", loadFromDB);
        });

</script>

</body>
</html>