File "tmp0026.php"

Full Path: /home/analogde/www/Design/Dev tableau/tmp0026.php
File size: 22.24 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%;
            max-height: 400px;
            overflow: auto;
            border: 1px solid #ccc;
            position: relative;
        }

        table {
            border-collapse: collapse;
            width: max-content;
            table-layout: fixed;
        }

        th, td {
            padding: 10px;
            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;
        }
    </style>
</head>
<body>

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

<script>
    document.addEventListener("DOMContentLoaded", function () {
        const tableBody = document.querySelector("tbody");
        let specialRowCounter = 1;

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

            const firstCells = ["Row " + rowNumber, "Data " + rowNumber + "-2", "cretin " + rowNumber];
            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.addEventListener("blur", function () {
                        input.classList.remove("editing");
                    });
                    input.addEventListener("keydown", function (event) {
                        if (event.key === "Escape") {
                            input.classList.remove("editing");
                            input.blur();
                        }
                    });
                    td.appendChild(input);
                } 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";
                });

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

        function addSpecialRow(afterRow = null) {
            const newRow = document.createElement("tr");
            newRow.classList.add("special-row");
            newRow.setAttribute("draggable", "true");

            const firstCells = [`Ligne spéciale ${specialRowCounter}`, `Spéciale ${specialRowCounter}-2`, `Spéciale ${specialRowCounter}-3`];
            firstCells.forEach((text, index) => {
                const td = document.createElement("td");
                td.textContent = text;

                if (index === 0) {
                    td.classList.add("row-header");
                    td.addEventListener("contextmenu", function (event) {
                        event.preventDefault();
                        showSpecialContextMenu(event, newRow);
                    });
                }

                newRow.appendChild(td);
            });

            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 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 () {
                row.remove();
                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>
            `;

            specialContextMenu.style.top = `${event.clientY}px`;
            specialContextMenu.style.left = `${event.clientX}px`;
            specialContextMenu.style.display = "flex";
            specialContextMenu.style.flexDirection = "column";

            document.getElementById("add-special-row").addEventListener("click", function () {
                addSpecialRow(row);
                hideSpecialContextMenu();
            });

            document.getElementById("delete-special-row").addEventListener("click", function () {
                row.remove();
                hideSpecialContextMenu();
            });
        }

        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) {
            event.dataTransfer.setData("text/plain", event.target.rowIndex);
            event.target.classList.add("dragging");
        }

        function dragOver(event) {
            event.preventDefault();
            const draggingRow = document.querySelector(".dragging");
            const targetRow = event.target.closest("tr");
            if (targetRow && draggingRow !== targetRow) {
                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");
        }
    });
</script>

</body>
</html>