File "source _0027_base022_005.php"

Full Path: /home/analogde/www/CURL/Dev tableau/Improve/source _0027_base022_005.php
File size: 48.56 KB
MIME-type: text/x-php
Charset: utf-8

<?php

/*
je pense que chaque cellule  d'un ligne  standard, c'est à dire de la quatrième cellule jusqu'à la dernière de la ligne, doit comporter un gestionnaire d'évènement qui lui est propre afin de le changement de la couleur de fond ne concerne que la cellule qui a été choisie. q'uen pense tu ? . Donne moi le code complet.
*/

/*
je voudrais que tu réalise certain ajustement. Le faut que chaque cellule d'une ligne standard à partie de la position 4 jusqu'à la dernière cellule de la ligne dispose d'une gestionnaire d'évenement qui lui soit propre. Pour cela du pour utiliser l'identifiant des cellules concernées qui se trouvent dans le tableau qui sauvegarde les objets relatifs au cellules. L'objectif est de pouvoir modifier les propriétés d'une cellule qui contient un 1 sans que cela impact les autres.
*/

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

echo ">>>>> " + count($workingDays);

?>

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

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

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

<!-- Success Modal Structure -->
<div class="modal fade" id="successModal" tabindex="-1" aria-labelledby="successModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="successModalLabel">Succès</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                Données sauvegardées avec succès !
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" id="closeSuccessModal">OK</button>
            </div>
        </div>
    </div>
</div>

<!-- Message Modal Structure -->
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="messageModalLabel">Message</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body" id="messageModalBody">
                <!-- Le contenu du message sera inséré ici -->
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
            </div>
        </div>
    </div>
</div>

<!-- Color Context Menu Structure -->
<div id="colorContextMenu" class="dropdown-menu" style="display: none;">
    <button class="dropdown-item" style="background-color: green;" data-color="green">Vert</button>
    <button class="dropdown-item" style="background-color: blue;" data-color="blue">Bleu</button>
    <button class="dropdown-item" style="background-color: red;" data-color="red">Rouge</button>
    <button class="dropdown-item" style="background-color: yellow;" data-color="yellow">Jaune</button>
    <button class="dropdown-item" style="background-color: orange;" data-color="orange">Orange</button>
    <button class="dropdown-item" style="background-color: purple;" data-color="purple">Violet</button>
    <button class="dropdown-item" style="background-color: pink;" data-color="pink">Rose</button>
    <button class="dropdown-item" style="background-color: brown;" data-color="brown">Marron</button>
    <button class="dropdown-item" style="background-color: cyan;" data-color="cyan">Cyan</button>
    <button class="dropdown-item" style="background-color: gray;" data-color="gray">Gris</button>
</div>

<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="saveToDBButton" class="btn">Save to DB</button>
<button id="traceButton" class="btn">Trace</button>
<button id="loadFromDBButton" class="btn">Load from DB</button>
<button id="runButton" class="btn">RUN</button>
<button id="saveButton" class="btn">Save</button>
<button id="readButton" class="btn">Read</button>
<button id="logButton" class="btn">Log</button> <!-- Nouveau bouton Log -->
<div id="generatedDataOutput"></div>

<div id="jsonOutput"></div>
<!--
<div id="logOutput"></div>
            -->
<!-- Zone de visualisation pour le log -->

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

    const colorContextMenu = document.getElementById("colorContextMenu");
    const colorButtons = colorContextMenu.querySelectorAll(".dropdown-item");

    colorButtons.forEach(button => {
        button.addEventListener("click", function () {
            const color = this.getAttribute("data-color");
            const cell = document.querySelector(".selected-cell");
            if (cell) {
                cell.style.backgroundColor = color;
                cell.dataset.cellColor = color; // Mettre à jour l'attribut de données
                hideColorContextMenu();
            }
        });
    });

    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");
            td.dataset.cellId = `cell-${rowCounter}-${index}`; // Attribuer un identifiant unique à chaque cellule
            if (index === 0) {
                const input = document.createElement("input");
                input.type = "text";
                input.classList.add("editable-input");
                input.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;

        console.log(" +++++ " + workingDaysCount);

        for (let i = 0; i < workingDaysCount -3; i++)
        {
            console.log(" ---- " + i);
            const td = document.createElement("td");
            td.dataset.cellId = `cell-${rowCounter}-${i + 3}`; // Attribuer un identifiant unique
            td.dataset.cellValue = "0"; // Stocker la valeur dans un attribut de données
            td.dataset.cellColor = "white"; // Stocker la couleur de fond dans un attribut de données
            td.textContent = "0";
            td.style.backgroundColor = "white";

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

            td.addEventListener("contextmenu", function (event) {
                event.preventDefault();
                if (td.dataset.cellValue === "1") {
                    showColorContextMenu(event, td);
                }
            });

            // Ajouter l'attribut title pour l'info-bulle uniquement pour les cellules des jours de travail
            td.title = `ID: ${td.dataset.cellId}`;

            newRow.appendChild(td);
        }

        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.dataset.cellValue === "1").length;
        countCell.textContent = count;
    }

    function addSpecialRow(afterRow = null) {
        const newRow = document.createElement("tr");
        newRow.classList.add("special-row");
        newRow.setAttribute("draggable", "true");
        newRow.dataset.rowId = `special-row-${specialRowCounter}`; // Attribuer un identifiant unique

        const firstCell = document.createElement("td");
        firstCell.classList.add("row-header");

        const input = document.createElement("input");
        input.type = "text";
        input.classList.add("editable-input");
        input.placeholder = `Ligne spéciale ${specialRowCounter}`;
        input.addEventListener("click", function (event) {
            event.stopPropagation();
            input.focus();
            input.style.width = "130px"; // Augmenter la largeur de l'input
            //displayRowId(newRow); // Afficher l'identifiant de la ligne
        });
        input.addEventListener("blur", function () {
            input.classList.remove("editing");
            input.style.width = "65px"; // Restaurer la largeur d'origine
        });
        input.addEventListener("keydown", function (event) {
            if (event.key === "Escape" || event.key === "Enter") {
                input.classList.remove("editing");
                input.blur();
                input.style.width = "65px"; // Restaurer la largeur d'origine
            }
        });

        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 showColorContextMenu(event, cell) {
        colorContextMenu.style.top = `${event.clientY}px`;
        colorContextMenu.style.left = `${event.clientX}px`;
        colorContextMenu.style.display = "flex";
        colorContextMenu.style.flexDirection = "column";

        // Marquer la cellule comme sélectionnée
        document.querySelectorAll(".selected-cell").forEach(c => c.classList.remove("selected-cell"));
        cell.classList.add("selected-cell");
    }

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

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

    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.querySelectorAll("tbody tr td:first-child").forEach(td => {
        td.addEventListener("contextmenu", function (event) {
            event.preventDefault();
            showContextMenu(event, td.parentElement);
        });
    });

    function dragStart(event) {
        const row = event.target.closest("tr");
        if (row.classList.contains("no-drag")) {
            event.preventDefault();
            return;
        }

        event.dataTransfer.setData("text/plain", row.rowIndex);
        row.classList.add("dragging");
    }

    function dragOver(event) {
        event.preventDefault();
        const draggingRow = document.querySelector(".dragging");
        const targetRow = event.target.closest("tr");

        if (targetRow && draggingRow !== targetRow && !targetRow.classList.contains("no-drag")) {
            const rect = targetRow.getBoundingClientRect();
            const offset = rect.top + (rect.height / 2);
            if (event.clientY - offset > 0) {
                tableBody.insertBefore(draggingRow, targetRow.nextSibling);
            } else {
                tableBody.insertBefore(draggingRow, targetRow);
            }
        }
    }

    function drop(event) {
        event.preventDefault();
        const draggingRow = document.querySelector(".dragging");
        draggingRow.classList.remove("dragging");

        // Si la ligne est une ligne spéciale, déplacer les lignes standards associées
        if (draggingRow.classList.contains("special-row")) {
            const specialRowId = draggingRow.dataset.rowId;
            if (associations[specialRowId]) {
                const associatedRowIds = associations[specialRowId];
                associatedRowIds.forEach(rowId => {
                    const associatedRow = document.querySelector(`tr[data-row-id="${rowId}"]`);
                    if (associatedRow) {
                        tableBody.insertBefore(associatedRow, draggingRow.nextSibling);
                    }
                });
            }
        }
    }

    function traceTable() {
        const tableData = [];
        const rows = tableBody.querySelectorAll("tr");

        rows.forEach(row => {
            const rowData = {}; // Créer un objet pour chaque ligne
            const cells = row.querySelectorAll("td");

            if (row.dataset.rowId.startsWith("special-row-")) {
                // Si c'est une ligne spéciale, prendre uniquement l'identifiant et le contenu de l'input text
                const inputCell = cells[0];
                const inputValue = inputCell.querySelector("input").value;
                rowData.id = row.dataset.rowId;
                rowData.name = inputValue;
            } else {
                // Pour les lignes standards, prendre toutes les cellules
                rowData.id = row.dataset.rowId;
                rowData.name = cells[0].querySelector("input").value;
                rowData.selectValue = cells[1].querySelector("select").value;
                rowData.count = cells[2].textContent.trim();
                rowData.cells = [];

                cells.forEach((cell, index) => {
                    if (index > 2) {
                        rowData.cells.push({
                            value: cell.dataset.cellValue,
                            color: cell.dataset.cellColor
                        });
                    }
                });
            }

            tableData.push(rowData); // Ajouter l'objet de la ligne au tableau global
        });

        return tableData; // Retourner les données du tableau
    }

    function saveToDB() {
        const tableData = traceTable(); // Utiliser traceTable pour obtenir les données du tableau

        if (tableData.length === 0) {
            // Afficher une fenêtre modale pour signaler que le tableau est vide
            const modal = new bootstrap.Modal(document.getElementById('messageModal'));
            const modalBody = document.getElementById('messageModalBody');
            modalBody.textContent = "Le tableau est vide. Veuillez ajouter des lignes avant de sauvegarder.";
            modal.show();
            return;
        }

        fetch("save_mysql.php", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(tableData) // Envoyer les données sous forme de JSON
        })
        .then(response => response.json())
        .then(data => {
            if (data.status === "success") {
                showMessageModal("Données sauvegardées avec succès !");
            } else {
                showMessageModal("Une erreur est survenue lors de la sauvegarde des données.");
            }
        })
        .catch(error => {
            console.error("Erreur :", error);
            showMessageModal("Une erreur est survenue lors de la sauvegarde des données.");
        });
    }

    function loadFromDB() {
        fetch("load_mysql.php")
            .then(response => response.json())
            .then(data => {
                regenerateTable(data);
                displayTableData(data);
                displayJSONData(data); // Afficher les données au format JSON
            })
            .catch(error => {
                console.error("Erreur :", error);
                showMessageModal("Une erreur est survenue lors du chargement des données.");
            });
    }

    function displayJSONData(data) {
        const jsonOutputElement = document.getElementById("jsonOutput");
        const jsonOutput = JSON.stringify(data, null, 2); // Convertir les données en JSON formaté
        jsonOutputElement.textContent = jsonOutput; // Afficher le contenu JSON au format texte
    }

    function regenerateTable(data) {
        tableBody.innerHTML = ""; // Vider le contenu actuel du tableau

        data.forEach(rowData => {
            const rowId = rowData.id;
            if (rowId.startsWith("special-row-")) {
                addSpecialRow();
                const specialRow = tableBody.lastElementChild;
                specialRow.dataset.rowId = rowId;
                specialRow.querySelector("input").value = rowData.name;
            } else {
                addRow();
                const standardRow = tableBody.lastElementChild;
                standardRow.dataset.rowId = rowId;
                const cells = standardRow.querySelectorAll("td");
                cells[0].querySelector("input").value = rowData.name;
                cells[1].querySelector("select").value = rowData.selectValue;
                cells[2].textContent = rowData.count;
                rowData.cells.forEach((cellData, index) => {
                    const cell = cells[index + 3];
                    cell.dataset.cellValue = cellData.value;
                    cell.dataset.cellColor = cellData.color;
                    cell.textContent = cellData.value;
                    cell.style.backgroundColor = cellData.color;
                });
            }
        });
    }

    function displayTableData(data) {
        const jsonOutputElement = document.getElementById("jsonOutput");
        const tableDataText = data.map(rowData => {
            return `ID: ${rowData.id}\nName: ${rowData.name}\nSelect Value: ${rowData.selectValue}\nCount: ${rowData.count}\nCells: ${rowData.cells ? rowData.cells.map(cell => `${cell.value} (${cell.color})`).join(", ") : ""}\n`;
        }).join("\n");
        jsonOutputElement.textContent = tableDataText; // Afficher le contenu au format texte
    }

    document.getElementById("saveToDBButton").addEventListener("click", saveToDB);

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

    document.getElementById("loadFromDBButton").addEventListener("click", loadFromDB);

    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({
                    value: cellValue,
                    color: cellValue === "1" ? "green" : "white"
                });
                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;
    }

    function displayGeneratedData(data) {
        const generatedDataOutput = document.getElementById("generatedDataOutput");
        const jsonOutput = JSON.stringify(data, null, 2);
        generatedDataOutput.textContent = jsonOutput;
    }

    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.dataset.cellValue = cellData.value;
                    cell.dataset.cellColor = cellData.color;
                    cell.textContent = cellData.value;
                    cell.style.backgroundColor = cellData.color;
                });
            }
        });
    }

    document.getElementById("runButton").addEventListener("click", purgeAndGenerate);

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

    document.getElementById("readButton").addEventListener("click", loadFromDB);

    document.getElementById("logButton").addEventListener("click", function () {
        const tableData = traceTable();
        displayJSONData(tableData); // Afficher les données JSON dans le div jsonOutput
    });
});
</script>

</body>
</html>