File "table0021_split_0022.php"
Full Path: /home/analogde/www/VirtualKeyboardSample/Chart burndown/table0021_split_0022.php
File size: 93.7 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;
}
function getFrenchHolidays($year) {
$easterDate = easter_date($year);
$holidays = [];
// Jours fériés fixes
$holidays[] = "$year-01-01"; // Jour de l'An
$holidays[] = "$year-05-01"; // Fête du Travail
$holidays[] = "$year-05-08"; // Victoire 1945
$holidays[] = "$year-07-14"; // Fête Nationale
$holidays[] = "$year-08-15"; // Assomption
$holidays[] = "$year-11-01"; // Toussaint
$holidays[] = "$year-11-11"; // Armistice
$holidays[] = "$year-12-25"; // Noël
// Jours fériés variables (calculés à partir de Pâques)
$easter = new DateTime("@$easterDate");
$easter->setTimezone(new DateTimeZone(date_default_timezone_get()));
$holidays[] = $easter->format("Y-m-d"); // Pâques (non férié officiellement mais utile)
$holidays[] = $easter->modify('+1 day')->format("Y-m-d"); // Lundi de Pâques
$holidays[] = $easter->modify('+38 days')->format("Y-m-d"); // Ascension
$holidays[] = $easter->modify('+11 days')->format("Y-m-d"); // Lundi de Pentecôte
return $holidays;
}
$year = 2025;
$holidays = [];
$holidays = getFrenchHolidays($year);
// Liste des jours fériés et fêtes religieuses à exclure (exemple pour la France, à compléter avec d'autres fêtes)
$old_holidays = [
"2025-01-01", // Jour de l'An
"2025-04-14", // Lundi de Pâques
"2025-05-01", // Fête du Travail
"2025-05-08", // Victoire 1945
"2025-07-14", // Bastille
"2025-08-15", // Assomption
"2025-11-01", // Toussaint
"2025-12-25", // Noël
"2026-01-01", // Jour de l'An
"2026-04-06", // Lundi de Pâques
// Ajouter d'autres jours fériés ici...
];
// Définir la période de début et de fin
$startDate = "2025-01-10";
$endDate = "2026-02-14";
// Appeler la fonction pour obtenir les jours ouvrés entre les deux dates
$workingDays = getWorkingDays($startDate, $endDate, $holidays);
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tableau Sticky - 3 Lignes Fixes</title>
<style>
.table-wrapper {
width: 100%;
height: calc(100vh - 100px);
overflow: auto;
border: 1px solid #ccc;
position: relative;
}
table {
border-collapse: collapse;
width: max-content;
table-layout: fixed;
}
th, td {
padding: 3px;
text-align: center;
height: 40px;
border: 1px solid #ccc;
white-space: nowrap;
min-width: 120px;
position: relative;
background-color: white;
box-sizing: border-box;
}
th {
background-color: #f2f2f2;
position: sticky;
top: 0;
z-index: 100;
}
th:first-child, td:first-child {
position: sticky;
left: 0;
z-index: 101;
background-color: white;
}
th:nth-child(2), td:nth-child(2) {
position: sticky;
left: 120px;
z-index: 100;
background-color: white;
}
th:nth-child(3), td:nth-child(3) {
position: sticky;
left: 240px;
z-index: 99;
background-color: white;
}
th:first-child::after, td:first-child::after,
th:nth-child(2)::after, td:nth-child(2)::after,
th:nth-child(3)::after, td:nth-child(3)::after {
content: "";
position: absolute;
right: 0;
top: 0;
width: 2px;
height: 100%;
background-color: #ccc;
z-index: 102;
}
tbody tr:nth-child(odd) {
background-color: #f9f9f9;
}
th:nth-child(n+4), td:nth-child(n+4) {
min-width: 40px;
max-width: 40px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.second-header th {
background-color: #f2f2f2;
position: sticky;
top: 40px;
z-index: 99;
}
.third-header th {
background-color: #f2f2f2;
position: sticky;
top: 80px;
z-index: 98;
}
.second-header th:first-child, .third-header th:first-child {
left: 0;
z-index: 101;
background-color: white;
}
.second-header th:nth-child(2), .third-header th:nth-child(2) {
left: 120px;
z-index: 100;
background-color: white;
}
.second-header th:nth-child(3), .third-header th:nth-child(3) {
left: 240px;
z-index: 99;
background-color: white;
}
thead tr:first-child th:first-child,
thead tr:first-child th:nth-child(2),
thead tr:first-child th:nth-child(3) {
z-index: 105;
background-color: #ddd;
}
.second-header th:first-child,
.second-header th:nth-child(2),
.second-header th:nth-child(3) {
z-index: 104;
}
.third-header th:first-child,
.third-header th:nth-child(2),
.third-header th:nth-child(3) {
z-index: 103;
}
thead tr:first-child th,
.second-header th,
.third-header th {
box-shadow: inset 0 -2px #aaa;
background-clip: padding-box;
padding-bottom: 2px;
margin-bottom: -2px;
z-index: 100;
}
.second-header th {
top: calc(40px + 2px);
margin-top: 2px;
}
.third-header th {
top: calc(80px + 2px);
margin-top: 2px;
}
.even-week {
background-color: #ffcc99 !important;
}
.odd-week {
background-color: #e6b3ff !important;
}
.fourth-header th {
background-color: #f2f2f2;
position: sticky;
top: 120px;
z-index: 97;
}
.fourth-header th:first-child {
left: 0;
z-index: 101;
background-color: white;
}
.fourth-header th:nth-child(2) {
left: 120px;
z-index: 100;
background-color: white;
}
.fourth-header th:nth-child(3) {
left: 240px;
z-index: 99;
background-color: white;
}
.fourth-header th:first-child,
.fourth-header th:nth-child(2),
.fourth-header th:nth-child(3) {
z-index: 102;
}
.fourth-header th {
top: calc(120px + 2px);
margin-top: 2px;
}
.fourth-header th {
box-shadow: inset 0 -2px #aaa;
background-clip: padding-box;
padding-bottom: 2px;
margin-bottom: -2px;
z-index: 97;
}
.month-even {
background-color: #99ccff !important;
}
.month-odd {
background-color: #ff9999 !important;
}
.btn {
margin-bottom: 20px;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
font-size: 16px;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: #45a049;
}
.btn-special {
background-color: #2196F3;
}
.btn-special:hover {
background-color: #1e88e5;
}
.btn-special:hover {
background-color: #1e88e5;
}
#contextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#contextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#contextMenu .dropdown-item:hover {
background: #f8f9fa;
}
#specialContextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#specialContextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#specialContextMenu .dropdown-item:hover {
background: #f8f9fa;
}
#colorContextMenu {
position: absolute;
display: none;
flex-direction: column;
background: white;
border: 1px solid #ccc;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
z-index: 1000;
min-width: 180px;
}
#colorContextMenu .dropdown-item {
display: block;
width: 100%;
padding: 8px 12px;
text-align: left;
color: #333;
cursor: pointer;
}
#colorContextMenu .dropdown-item:hover {
background: #f8f9fa;
}
.add-button {
background-color: orange;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
margin-left: 5px;
}
.editable-input {
width: 65px;
box-sizing: border-box;
}
.collapsed {
display: none;
}
#jsonOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
#logOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
.no-click {
pointer-events: none;
}
#debugOutput {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
background-color: #f9f9f9;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
<div class="modal fade" id="confirmationModal" tabindex="-1" aria-labelledby="confirmationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmationModalLabel">Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Voulez-vous vraiment supprimer cette ligne ?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelDelete">Annuler</button>
<button type="button" class="btn btn-danger" id="confirmDelete">OK</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="successModal" tabindex="-1" aria-labelledby="successModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="successModalLabel">Succès</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Données sauvegardées avec succès !
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="closeSuccessModal">OK</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="messageModalLabel">Message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" id="messageModalBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
<div id="colorContextMenu" class="dropdown-menu" style="display: none;">
<button class="dropdown-item" style="background-color: green;" data-color="green">Vert</button>
<button class="dropdown-item" style="background-color: blue;" data-color="blue">Bleu</button>
<button class="dropdown-item" style="background-color: red;" data-color="red">Rouge</button>
<button class="dropdown-item" style="background-color: yellow;" data-color="yellow">Jaune</button>
<button class="dropdown-item" style="background-color: orange;" data-color="orange">Orange</button>
<button class="dropdown-item" style="background-color: purple;" data-color="purple">Violet</button>
<button class="dropdown-item" style="background-color: pink;" data-color="pink">Rose</button>
<button class="dropdown-item" style="background-color: brown;" data-color="brown">Marron</button>
<button class="dropdown-item" style="background-color: cyan;" data-color="cyan">Cyan</button>
<button class="dropdown-item" style="background-color: gray;" data-color="gray">Gris</button>
</div>
<div class="modal fade" id="rangeSelectionModal" tabindex="-1" aria-labelledby="rangeSelectionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="rangeSelectionModalLabel">Sélection de Plage</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="startCellId">Cellule de Départ</label>
<input type="text" class="form-control" id="startCellId" disabled>
</div>
<div class="form-group">
<label for="endCellId">Cellule de Fin</label>
<input type="text" class="form-control" id="endCellId">
</div>
<div class="form-group">
<label for="rangeComboBox">Sélectionnez une valeur</label>
<select class="form-control" id="rangeComboBox">
</select>
</div>
<div id="rangeResult" class="form-group">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="cancelRangeSelection">Annuler</button>
<button type="button" class="btn btn-primary" id="confirmRangeSelection">Valider</button>
</div>
</div>
</div>
</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th></th>
<th>plouf</th>
<th>cretin</th>
<?php foreach ($workingDays as $dateData): ?>
<th>
<?php echo $dateData['day']; ?> <br>
</th>
<?php endforeach; ?>
</tr>
<tr class="second-header">
<th></th>
<th>Valeur 1</th>
<th>Valeur 2</th>
<?php
$currentWeek = null;
$weekClass = "";
foreach ($workingDays as $dateData):
if ($currentWeek !== $dateData['week_number']) {
$currentWeek = $dateData['week_number'];
$weekClass = ($currentWeek % 2 === 0) ? 'even-week' : 'odd-week';
}
?>
<th class="<?= $weekClass; ?>"><?php echo $dateData['day_of_week_initial']; ?></th>
<?php endforeach; ?>
</tr>
<tr class="third-header">
<th></th>
<th>Info 1</th>
<th>Info 2</th>
<?php
$currentWeek = null;
$colspan = 0;
foreach ($workingDays as $index => $dateData):
if ($currentWeek !== $dateData['week_number']) {
if ($currentWeek !== null) {
$weekClass = $currentWeek % 2 === 0 ? 'even-week' : 'odd-week';
echo '<th class="' . $weekClass . '" colspan="' . $colspan . '">' . $currentWeek . '</th>';
}
$currentWeek = $dateData['week_number'];
$colspan = 1;
} else {
$colspan++;
}
endforeach;
if ($currentWeek !== null) {
$weekClass = $currentWeek % 2 === 0 ? 'even-week' : 'odd-week';
echo '<th class="' . $weekClass . '" colspan="' . $colspan . '">' . $currentWeek . '</th>';
}
?>
</tr>
<tr class="fourth-header">
<th></th>
<th>Label 1</th>
<th>Label 2</th>
<?php
$currentMonthYear = null;
$colspan = 0;
$monthClass = "";
$colorIndex = 0;
$colors = ['month-even', 'month-odd'];
foreach ($workingDays as $index => $dateData):
$monthYear = ucfirst(strftime("%B %Y", strtotime($dateData['full_date'])));
if ($currentMonthYear !== $monthYear) {
if ($currentMonthYear !== null) {
echo '<th class="' . $monthClass . '" colspan="' . $colspan . '">' . $currentMonthYear . '</th>';
}
$currentMonthYear = $monthYear;
$colspan = 1;
$monthClass = $colors[$colorIndex % 2];
$colorIndex++;
} else {
$colspan++;
}
endforeach;
if ($currentMonthYear !== null) {
echo '<th class="' . $monthClass . '" colspan="' . $colspan . '">' . $currentMonthYear . '</th>';
}
?>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<button id="addRowButton" class="btn">Ajouter une ligne</button>
<button id="addSpecialRowButton" class="btn btn-special">Ajouter une ligne spéciale</button>
<button id="testButton" class="btn">TEST</button>
<button id="queryButton" class="btn">Query</button>
<button id="memButton" class="btn">Mem</button>
<button id="snapButton" class="btn">Snap</button>
<button id="visualizeLinkButton" class="btn">Objet</button>
<button id="titiButton" class="btn">Titi</button>
<button id="saveToDBButton" class="btn">ENREGISTRER</button>
<button id="exportButton" class="btn">EXPORT</button>
<button id="importButton" class="btn">IMPORT</button>
<button id="saveButton" class="btn">Save</button>
<button id="readButton" class="btn">Read</button>
<button id="logButton" class="btn">Log</button>
<div id="generatedDataOutput"></div>
<div id="jsonOutput"></div>
<div id="debugOutput"></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const tableBody = document.querySelector("tbody");
let specialRowCounter = 1;
let rowCounter = 1;
let linkageCounter = 1;
const specialRowStates = {};
const associations = {};
const linkages = [];
const standardRowsData = [];
const estimationRowsData = [];
let currentCell = null;
let keydownHandled = false;
let alertShown = false;
const contextMenu = document.createElement("div");
contextMenu.id = "contextMenu";
contextMenu.classList.add("dropdown-menu");
contextMenu.style.display = "none";
document.body.appendChild(contextMenu);
const specialContextMenu = document.createElement("div");
specialContextMenu.id = "specialContextMenu";
specialContextMenu.classList.add("dropdown-menu");
specialContextMenu.style.display = "none";
document.body.appendChild(specialContextMenu);
const colorContextMenu = document.getElementById("colorContextMenu");
const colorButtons = colorContextMenu.querySelectorAll(".dropdown-item");
colorButtons.forEach(button => {
button.addEventListener("click", function () {
const color = this.getAttribute("data-color");
const cell = document.querySelector(".selected-cell");
if (cell) {
cell.style.backgroundColor = color;
cell.dataset.cellColor = color;
hideColorContextMenu();
updateRowData(cell);
}
});
});
function generateRandomId(length = 8) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
function addRow(afterRow = null) {
const rowNumber = tableBody.rows.length + 1;
const newRow = document.createElement("tr");
newRow.setAttribute("draggable", "true");
newRow.dataset.rowId = `standard-${generateRandomId()}`;
const rowData = {
id: newRow.dataset.rowId,
name: `Row ${rowNumber}`,
selectValue: "1",
count: "0",
cells: []
};
const firstCells = [`Row ${rowNumber}`, "", "0"];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${rowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = rowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = rowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, newRow);
});
}
newRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${rowData.id}-${i}`;
td.dataset.cellValue = "0";
td.dataset.cellColor = "white";
td.textContent = "0";
td.style.backgroundColor = "white";
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(newRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
newRow.appendChild(td);
rowData.cells.push({
value: "0",
color: "white"
});
}
if (afterRow) {
tableBody.insertBefore(newRow, afterRow.nextSibling);
} else {
tableBody.appendChild(newRow);
}
newRow.addEventListener("dragstart", dragStart);
newRow.addEventListener("dragover", dragOver);
newRow.addEventListener("drop", drop);
rowCounter++;
standardRowsData.push(rowData);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = `estimation-${generateRandomId()}`;
estimationRow.classList.add("estimation-row");
const estimationRowData = {
id: estimationRow.dataset.rowId,
name: `Estimation ${rowNumber}`,
selectValue: "1",
estimationValue: "0"
};
const estimationFirstCells = [`Estimation ${rowNumber}`, "", "0"];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${estimationRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = estimationRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = estimationRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
/* const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
*/
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = "1"; //estimationRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
//updateRowData(input);
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "1";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
console.clear;
;
//updateRowData(input);
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "1";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
}
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
if (afterRow) {
tableBody.insertBefore(estimationRow, newRow.nextSibling);
} else {
tableBody.appendChild(estimationRow);
}
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
const linkage = {
linkageId: `linkage-${generateRandomId()}`,
standardRowId: newRow.dataset.rowId,
estimationRowId: estimationRow.dataset.rowId
};
linkages.push(linkage);
displayLinkages();
rowCounter++;
estimationRowsData.push(estimationRowData);
}
function updateRowData(element) {
const row = element.closest("tr");
const rowId = row.dataset.rowId;
if (rowId.startsWith("standard-")) {
let standardRowData = standardRowsData.find(data => data.id === rowId);
if (!standardRowData) {
standardRowData = {
id: rowId,
name: "",
selectValue: "",
count: "",
cells: []
};
standardRowsData.push(standardRowData);
}
const cells = row.querySelectorAll("td");
standardRowData.name = cells[0].querySelector("input").value;
standardRowData.selectValue = cells[1].querySelector("select").value;
standardRowData.count = cells[2].textContent.trim();
standardRowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
standardRowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
console.log(`Mise à jour de la ligne standard : ${rowId}`);
} else if (rowId.startsWith("estimation-")) {
let estimationRowData = estimationRowsData.find(data => data.id === rowId);
if (!estimationRowData) {
estimationRowData = {
id: rowId,
name: "",
selectValue: "",
estimationValue: ""
};
estimationRowsData.push(estimationRowData);
}
const cells = row.querySelectorAll("td");
estimationRowData.name = cells[0].querySelector("input").value;
estimationRowData.selectValue = cells[1].querySelector("select").value;
estimationRowData.estimationValue = cells[2].querySelector("input").value;
console.log(`Mise à jour de la ligne d'estimation : ${rowId}`);
}
const objetTache = createObjetTache();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
}
function displayLinkages() {
const debugOutputElement = document.getElementById("debugOutput");
debugOutputElement.textContent = JSON.stringify(linkages, null, 2);
}
function updateCountCell(row) {
const countCell = row.cells[2];
const count = Array.from(row.cells).slice(3).filter(cell => cell.dataset.cellValue === "1").length;
countCell.textContent = count;
}
function addSpecialRow(afterRow = null) {
const newRow = document.createElement("tr");
newRow.classList.add("special-row");
newRow.setAttribute("draggable", "true");
newRow.dataset.rowId = `special-${generateRandomId()}`;
const firstCell = document.createElement("td");
firstCell.classList.add("row-header");
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.placeholder = `Ligne spéciale ${specialRowCounter}`;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
input.classList.remove("editing");
input.style.width = "65px";
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
}
});
input.addEventListener("input", function () {
updateRowData(input);
});
const addButton = document.createElement("button");
addButton.classList.add("add-button");
addButton.textContent = "+";
addButton.addEventListener("click", function () {
toggleCollapse(newRow);
});
firstCell.appendChild(input);
firstCell.appendChild(addButton);
firstCell.addEventListener("contextmenu", function (event) {
event.preventDefault();
showSpecialContextMenu(event, newRow);
});
newRow.appendChild(firstCell);
const mergedCell = document.createElement("td");
mergedCell.colSpan = 2;
mergedCell.textContent = "";
newRow.appendChild(mergedCell);
const td = document.createElement("td");
td.textContent = `Ligne spéciale ${specialRowCounter} - Détails`;
td.colSpan = document.querySelector("thead tr:nth-child(2)").cells.length - 3;
newRow.appendChild(td);
if (afterRow) {
tableBody.insertBefore(newRow, afterRow.nextSibling);
} else {
tableBody.appendChild(newRow);
}
newRow.addEventListener("dragstart", dragStart);
newRow.addEventListener("dragover", dragOver);
newRow.addEventListener("drop", drop);
specialRowCounter++;
}
function displayRowId(row) {
const rowId = row.dataset.rowId;
alert(`Identifiant de la ligne : ${rowId}`);
}
function toggleCollapse(specialRow) {
const nextSpecialRow = getNextSpecialRow(specialRow);
const rowsToToggle = [];
let currentRow = specialRow.nextElementSibling;
while (currentRow && currentRow !== nextSpecialRow) {
if (!currentRow.classList.contains("special-row")) {
rowsToToggle.push(currentRow);
}
currentRow = currentRow.nextElementSibling;
}
rowsToToggle.forEach(row => {
row.classList.toggle("collapsed");
});
}
function getNextSpecialRow(specialRow) {
let currentRow = specialRow.nextElementSibling;
while (currentRow) {
if (currentRow.classList.contains("special-row")) {
return currentRow;
}
currentRow = currentRow.nextElementSibling;
}
return null;
}
function showContextMenu(event, row) {
contextMenu.innerHTML = `
<button class="dropdown-item" id="add-row">Ajouter une ligne</button>
<button class="dropdown-item text-danger" id="delete-row">Supprimer cette ligne</button>
<button class="dropdown-item" id="show-linkage">Afficher la liaison</button>
`;
contextMenu.style.top = `${event.clientY}px`;
contextMenu.style.left = `${event.clientX}px`;
contextMenu.style.display = "flex";
contextMenu.style.flexDirection = "column";
document.getElementById("add-row").addEventListener("click", function () {
addRow(row);
hideContextMenu();
});
document.getElementById("delete-row").addEventListener("click", function () {
showConfirmationModal(row);
hideContextMenu();
});
document.getElementById("show-linkage").addEventListener("click", function () {
const linkage = linkages.find(link => link.standardRowId === row.dataset.rowId || link.estimationRowId === row.dataset.rowId);
if (linkage) {
alert(`Liaison trouvée :\nID: ${linkage.linkageId}\nLigne standard: ${linkage.standardRowId}\nLigne estimation: ${linkage.estimationRowId}`);
} else {
alert("Aucune liaison trouvée pour cette ligne.");
}
hideContextMenu();
});
}
function showSpecialContextMenu(event, row) {
specialContextMenu.innerHTML = `
<button class="dropdown-item" id="add-special-row">Ajouter une ligne spéciale</button>
<button class="dropdown-item text-danger" id="delete-special-row">Supprimer cette ligne</button>
<label class="dropdown-item">
<input type="checkbox" id="special-checkbox"> Attacher
</label>
`;
specialContextMenu.style.top = `${event.clientY}px`;
specialContextMenu.style.left = `${event.clientX}px`;
specialContextMenu.style.display = "flex";
specialContextMenu.style.flexDirection = "column";
const checkbox = document.getElementById("special-checkbox");
const rowId = row.dataset.rowId;
let hasStandardRowsBelow = false;
let currentRow = row.nextElementSibling;
const standardRows = [];
while (currentRow && !currentRow.classList.contains("special-row")) {
if (!currentRow.classList.contains("special-row")) {
hasStandardRowsBelow = true;
standardRows.push(currentRow);
}
currentRow = currentRow.nextElementSibling;
}
if (hasStandardRowsBelow) {
checkbox.disabled = false;
} else {
checkbox.disabled = true;
checkbox.checked = false;
}
if (specialRowStates[rowId]) {
checkbox.checked = specialRowStates[rowId].checked;
}
checkbox.addEventListener("change", function () {
specialRowStates[rowId] = {
checked: checkbox.checked,
rows: standardRows
};
standardRows.forEach(standardRow => {
const firstCell = standardRow.querySelector("td:first-child");
if (checkbox.checked) {
firstCell.style.backgroundColor = "yellow";
standardRow.classList.add("no-drag");
} else {
firstCell.style.backgroundColor = "";
standardRow.classList.remove("no-drag");
}
});
if (checkbox.checked) {
associations[rowId] = standardRows.map(row => row.dataset.rowId);
} else {
delete associations[rowId];
}
console.log(`Lignes standards concernées : ${standardRows.map(row => row.rowIndex).join(", ")}`);
});
document.getElementById("add-special-row").addEventListener("click", function () {
addSpecialRow(row);
hideSpecialContextMenu();
});
document.getElementById("delete-special-row").addEventListener("click", function () {
showConfirmationModal(row);
hideSpecialContextMenu();
});
}
function showColorContextMenu(event, cell) {
colorContextMenu.style.top = `${event.clientY}px`;
colorContextMenu.style.left = `${event.clientX}px`;
colorContextMenu.style.display = "flex";
colorContextMenu.style.flexDirection = "column";
document.querySelectorAll(".selected-cell").forEach(c => c.classList.remove("selected-cell"));
cell.classList.add("selected-cell");
}
function queryTableData() {
const tableData = [];
const rows = tableBody.querySelectorAll("tr");
rows.forEach(row => {
const rowData = {};
const cells = row.querySelectorAll("td");
if (row.dataset.rowId.startsWith("special-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
} else if (row.dataset.rowId.startsWith("estimation-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
rowData.estimationValue = cells[2].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
} else {
rowData.id = row.dataset.rowId;
rowData.name = cells[0].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
rowData.count = cells[2].textContent.trim();
rowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
rowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
}
tableData.push(rowData);
});
displayQueryData(tableData);
}
function displayQueryData(data) {
const debugOutputElement = document.getElementById("debugOutput");
const queryDataText = data.map(rowData => {
if (rowData.id.startsWith("special-")) {
return `ID: ${rowData.id}\nName: ${rowData.name}\n`;
} else if (rowData.id.startsWith("estimation-")) {
return `ID: ${rowData.id}\nName: ${rowData.name}\nEstimation Value: ${rowData.estimationValue}\nSelect Value: ${rowData.selectValue}\n`;
} else {
return `ID: ${rowData.id}\nName: ${rowData.name}\nSelect Value: ${rowData.selectValue}\nCount: ${rowData.count}\nCells: ${rowData.cells ? rowData.cells.map(cell => `${cell.value} (${cell.color})`).join(", ") : ""}\n`;
}
}).join("\n");
debugOutputElement.textContent = queryDataText;
}
function showConfirmationModal(row) {
const modal = new bootstrap.Modal(document.getElementById('confirmationModal'));
modal.show();
document.getElementById('confirmDelete').addEventListener('click', function () {
const estimationRow = row.nextElementSibling.classList.contains("estimation-row") ? row.nextElementSibling : row.previousElementSibling;
row.remove();
estimationRow.remove();
const linkageIndex = linkages.findIndex(link => link.standardRowId === row.dataset.rowId || link.estimationRowId === row.dataset.rowId);
if (linkageIndex !== -1) {
linkages.splice(linkageIndex, 1);
}
regenerateTableAfterDeletion();
logRowContents(row);
logRowContents(estimationRow);
modal.hide();
});
document.getElementById('cancelDelete').addEventListener('click', function () {
modal.hide();
});
}
function regenerateTableAfterDeletion() {
tableBody.innerHTML = "";
linkages.forEach(linkage => {
const standardRow = document.createElement("tr");
standardRow.setAttribute("draggable", "true");
standardRow.dataset.rowId = linkage.standardRowId;
const firstCells = ["Row", "", "0"];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.standardRowId}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, standardRow);
});
}
standardRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.standardRowId}-${i}`;
td.dataset.cellValue = "0";
td.dataset.cellColor = "white";
td.textContent = "0";
td.style.backgroundColor = "white";
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(standardRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
standardRow.appendChild(td);
}
tableBody.appendChild(standardRow);
standardRow.addEventListener("dragstart", dragStart);
standardRow.addEventListener("dragover", dragOver);
standardRow.addEventListener("drop", drop);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = linkage.estimationRowId;
estimationRow.classList.add("estimation-row");
const estimationFirstCells = ["Estimation", "", "0"];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${linkage.estimationRowId}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = "Estimation";
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
tableBody.appendChild(estimationRow);
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
});
displayLinkages();
}
function showMessageModal(message) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = message;
modal.show();
}
document.addEventListener("click", function (event) {
if (!contextMenu.contains(event.target)) {
hideContextMenu();
}
if (!specialContextMenu.contains(event.target)) {
hideSpecialContextMenu();
}
if (!colorContextMenu.contains(event.target)) {
hideColorContextMenu();
}
const inputs = document.querySelectorAll(".editable-input");
inputs.forEach(input => {
if (!input.contains(event.target)) {
input.classList.remove("editing");
}
});
});
document.addEventListener("keydown", function (event) {
if (event.key === "Escape") {
hideContextMenu();
hideSpecialContextMenu();
hideColorContextMenu();
}
});
function hideContextMenu() {
contextMenu.style.display = "none";
}
function hideSpecialContextMenu() {
specialContextMenu.style.display = "none";
}
function hideColorContextMenu() {
colorContextMenu.style.display = "none";
}
document.getElementById("addRowButton").addEventListener("click", addRow);
document.getElementById("addSpecialRowButton").addEventListener("click", addSpecialRow);
document.getElementById("testButton").addEventListener("click", function () {
alert("Le bouton TEST a été cliqué !");
fetch("get_values.php")
.then(response => response.json())
.then(data => {
console.log("Données reçues :", data);
displayValues(data);
})
.catch(error => {
console.error("Erreur lors de la récupération des données :", error);
showMessageModal("Une erreur est survenue lors de la récupération des données.");
});
});
function displayValues(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const valuesText = data.map(row => row.join(", ")).join("\n");
jsonOutputElement.textContent = valuesText;
}
document.querySelectorAll("tbody tr td:first-child").forEach(td => {
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, td.parentElement);
});
});
function dragStart(event) {
const row = event.target.closest("tr");
if (row.classList.contains("no-drag")) {
event.preventDefault();
return;
}
event.dataTransfer.setData("text/plain", row.rowIndex);
row.classList.add("dragging");
}
function dragOver(event) {
event.preventDefault();
const draggingRow = document.querySelector(".dragging");
const targetRow = event.target.closest("tr");
if (targetRow && draggingRow !== targetRow && !targetRow.classList.contains("no-drag")) {
const rect = targetRow.getBoundingClientRect();
const offset = rect.top + (rect.height / 2);
if (event.clientY - offset > 0) {
tableBody.insertBefore(draggingRow, targetRow.nextSibling);
} else {
tableBody.insertBefore(draggingRow, targetRow);
}
}
}
function drop(event) {
event.preventDefault();
const draggingRow = document.querySelector(".dragging");
draggingRow.classList.remove("dragging");
if (draggingRow.classList.contains("special-row")) {
const specialRowId = draggingRow.dataset.rowId;
if (associations[specialRowId]) {
const associatedRowIds = associations[specialRowId];
associatedRowIds.forEach(rowId => {
const associatedRow = document.querySelector(`tr[data-row-id="${rowId}"]`);
if (associatedRow) {
tableBody.insertBefore(associatedRow, draggingRow.nextSibling);
}
});
}
}
}
function traceTable() {
const tableData = [];
const rows = tableBody.querySelectorAll("tr");
rows.forEach(row => {
const rowData = {};
const cells = row.querySelectorAll("td");
if (row.dataset.rowId.startsWith("special-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
} else if (row.dataset.rowId.startsWith("estimation-")) {
const inputCell = cells[0];
const inputValue = inputCell.querySelector("input").value;
rowData.id = row.dataset.rowId;
rowData.name = inputValue;
rowData.estimationValue = cells[2].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
} else {
rowData.id = row.dataset.rowId;
rowData.name = cells[0].querySelector("input").value;
rowData.selectValue = cells[1].querySelector("select").value;
rowData.count = cells[2].textContent.trim();
rowData.cells = [];
cells.forEach((cell, index) => {
if (index > 2) {
rowData.cells.push({
value: cell.dataset.cellValue,
color: cell.dataset.cellColor
});
}
});
}
tableData.push(rowData);
});
return tableData;
}
function saveToDB() {
const tableData = traceTable();
if (tableData.length === 0) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = "Le tableau est vide. Veuillez ajouter des lignes avant de sauvegarder.";
modal.show();
return;
}
fetch("save_objets_002.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans la base de données !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
});
fetch("save_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans le fichier JSON !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
});
}
function loadFromDB() {
fetch("load_mysql.php")
.then(response => response.json())
.then(data => {
regenerateTable(data);
displayTableData(data);
displayJSONData(data);
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors du chargement des données.");
});
}
function displayJSONData(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const jsonOutput = JSON.stringify(data, null, 2);
jsonOutputElement.textContent = jsonOutput;
}
function regenerateTable(data) {
tableBody.innerHTML = "";
data.forEach(rowData => {
const rowId = rowData.id;
if (rowId.startsWith("special-")) {
addSpecialRow();
const specialRow = tableBody.lastElementChild;
specialRow.dataset.rowId = rowId;
specialRow.querySelector("input").value = rowData.name;
} else if (rowId.startsWith("estimation-")) {
addRow();
const estimationRow = tableBody.lastElementChild;
estimationRow.dataset.rowId = rowId;
const cells = estimationRow.querySelectorAll("td");
cells[0].querySelector("input").value = rowData.name;
cells[1].querySelector("select").value = rowData.selectValue;
cells[2].querySelector("input").value = rowData.estimationValue;
} else {
addRow();
const standardRow = tableBody.lastElementChild;
standardRow.dataset.rowId = rowId;
const cells = standardRow.querySelectorAll("td");
cells[0].querySelector("input").value = rowData.name;
cells[1].querySelector("select").value = rowData.selectValue;
cells[2].textContent = rowData.count;
rowData.cells.forEach((cellData, index) => {
const cell = cells[index + 3];
cell.dataset.cellValue = cellData.value;
cell.dataset.cellColor = cellData.color;
cell.textContent = cellData.value;
cell.style.backgroundColor = cellData.color;
});
}
});
}
function displayTableData(data) {
const jsonOutputElement = document.getElementById("jsonOutput");
const tableDataText = data.map(rowData => {
return `ID: ${rowData.id}\nName: ${rowData.name}\nSelect Value: ${rowData.selectValue}\nCount: ${rowData.count}\nCells: ${rowData.cells ? rowData.cells.map(cell => `${cell.value} (${cell.color})`).join(", ") : ""}\n`;
}).join("\n");
jsonOutputElement.textContent = tableDataText;
}
function openRangeSelectionModal(cell) {
const modal = new bootstrap.Modal(document.getElementById('rangeSelectionModal'));
const startCellIdInput = document.getElementById('startCellId');
const endCellIdInput = document.getElementById('endCellId');
const rangeResult = document.getElementById('rangeResult');
const rangeComboBox = document.getElementById('rangeComboBox');
rangeComboBox.innerHTML = "";
for (let i = 1; i <= 50; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = i;
rangeComboBox.appendChild(option);
}
rangeComboBox.addEventListener("change", function () {
const startCellId = startCellIdInput.value;
const startParts = startCellId.split('-');
const startNumber = parseInt(startParts[2], 10);
const comboValue = parseInt(rangeComboBox.value, 10);
const totalDays = startNumber + comboValue;
const endCellId = `${startParts[0]}-${startParts[1]}-${totalDays}`;
console.log("Valeur sélectionnée :", comboValue);
console.log("Nb jours :", totalDays);
rangeResult.textContent = `Nb jours : ${totalDays}`;
endCellIdInput.value = endCellId;
});
startCellIdInput.value = cell.dataset.cellId;
endCellIdInput.value = "";
rangeResult.textContent = "Nb jours : 0";
modal.show();
document.getElementById('confirmRangeSelection').addEventListener('click', function () {
const startCellId = startCellIdInput.value;
const endCellId = endCellIdInput.value;
const comboValue = rangeComboBox.value;
alert(startCellId + " " + endCellId);
updateCellRange(startCellId, endCellId, comboValue);
modal.hide();
});
document.getElementById('cancelRangeSelection').addEventListener('click', function () {
modal.hide();
});
const modalHeader = modal._dialog.querySelector('.modal-header');
let isDragging = false;
let offsetX, offsetY;
modalHeader.addEventListener('mousedown', function (event) {
isDragging = true;
offsetX = event.clientX - modal._dialog.offsetLeft;
offsetY = event.clientY - modal._dialog.offsetTop;
modal._dialog.style.pointerEvents = 'none';
});
document.addEventListener('mousemove', function (event) {
if (isDragging) {
modal._dialog.style.left = `${event.clientX - offsetX}px`;
modal._dialog.style.top = `${event.clientY - offsetY}px`;
}
});
document.addEventListener('mouseup', function () {
isDragging = false;
modal._dialog.style.pointerEvents = 'all';
});
endCellIdInput.addEventListener('input', function () {
const startParts = startCellIdInput.value.split('-');
const endParts = endCellIdInput.value.split('-');
if (startParts.length === 3 && endParts.length === 3 && startParts[0] === endParts[0] && startParts[1] === endParts[1]) {
const startValue = parseInt(startParts[2], 10);
const endValue = parseInt(endParts[2], 10);
console.log(" ++ " + startValue + " " + endValue);
const result = endValue - startValue;
rangeResult.textContent = `Nb jours : ${result} jours`;
if (result > 0) {
alert(`Nb jours : ${result} jours`);
}
} else {
rangeResult.textContent = "Nb jours : 0";
}
});
}
function updateCellRange(startCellId, endCellId) {
const startCell = document.querySelector(`td[data-cell-id="${startCellId}"]`);
const endCell = document.querySelector(`td[data-cell-id="${endCellId}"]`);
if (startCell && endCell && startCell.parentElement === endCell.parentElement) {
const startIndex = Array.from(startCell.parentElement.cells).indexOf(startCell);
const endIndex = Array.from(endCell.parentElement.cells).indexOf(endCell);
for (let i = startIndex; i <= endIndex; i++) {
const cell = startCell.parentElement.cells[i];
cell.dataset.cellValue = "1";
cell.textContent = "1";
cell.style.backgroundColor = "green";
cell.dataset.cellColor = "green";
updateRowData(cell);
}
updateCountCell(startCell.parentElement);
} else {
showMessageModal("Les cellules doivent être sur la même ligne.");
}
}
tableBody.addEventListener("mouseover", function (event) {
const cell = event.target.closest("td");
if (cell) {
currentCell = cell;
}
});
document.addEventListener("keydown", function (event) {
if (event.key === "p" && currentCell) {
openRangeSelectionModal(currentCell);
}
});
document.getElementById("saveButton").addEventListener("click", function () {
const tableData = traceTable();
const jsonOutput = JSON.stringify(tableData, null, 2);
const jsonOutputElement = document.getElementById("jsonOutput");
jsonOutputElement.textContent = jsonOutput;
saveToDB();
});
document.getElementById("readButton").addEventListener("click", loadFromDB);
document.getElementById("logButton").addEventListener("click", function () {
const tableData = traceTable();
displayJSONData(tableData);
});
document.getElementById("queryButton").addEventListener("click", queryTableData);
function displayObjets() {
console.log(standardRowsData);
console.log(estimationRowsData);
}
document.getElementById("memButton").addEventListener("click", displayObjets);
document.getElementById("saveToDBButton").addEventListener("click", function () {
const tableData = traceTable();
if (tableData.length === 0) {
const modal = new bootstrap.Modal(document.getElementById('messageModal'));
const modalBody = document.getElementById('messageModalBody');
modalBody.textContent = "Le tableau est vide. Veuillez ajouter des lignes avant de sauvegarder.";
modal.show();
return;
}
fetch("save_objets_001.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans la base de données !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans la base de données.");
});
fetch("save_to_json.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(tableData)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données sauvegardées avec succès dans le fichier JSON !");
} else {
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de la sauvegarde des données dans le fichier JSON.");
});
});
function createObjetTache() {
const objetTache = linkages.map(linkage => {
const standardRowData = standardRowsData.find(row => row.id === linkage.standardRowId);
const estimationRowData = estimationRowsData.find(row => row.id === linkage.estimationRowId);
return {
linkageId: linkage.linkageId,
standardRow: {
id: standardRowData.id,
name: standardRowData.name,
selectValue: standardRowData.selectValue,
count: standardRowData.count,
cells: standardRowData.cells
},
estimationRow: {
id: estimationRowData.id,
name: estimationRowData.name,
selectValue: estimationRowData.selectValue,
estimationValue: estimationRowData.estimationValue
}
};
});
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
return objetTache;
}
document.getElementById("exportButton").addEventListener("click", function () {
const objetTache = createObjetTache();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
fetch("export02.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(objetTache)
})
.then(response => response.json())
.then(data => {
if (data.status === "success") {
showMessageModal("Données exportées avec succès dans le fichier json.");
} else {
showMessageModal("Une erreur est survenue lors de l'exportation des données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Une erreur est survenue lors de l'exportation des données.");
});
});
document.getElementById("importButton").addEventListener("click", function () {
fetch("import02.php")
.then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Import");
purgeAndRegenerateTable(data.objetTache);
showMessageModal("Données importées avec succès.");
} else {
showMessageModal("Blabla Une erreur est survenue lors de l'importation des données.");
}
})
.catch(error => {
console.error("Erreur :", error);
showMessageModal("Riri Une erreur est survenue lors de l'importation des données.");
});
});
function purgeAndRegenerateTable(objetTache) {
standardRowsData.length = 0;
estimationRowsData.length = 0;
linkages.length = 0;
objetTache.forEach(linkage => {
standardRowsData.push(linkage.standardRow);
estimationRowsData.push(linkage.estimationRow);
linkages.push({
linkageId: linkage.linkageId,
standardRowId: linkage.standardRow.id,
estimationRowId: linkage.estimationRow.id
});
});
console.log("TRACE ++++++++++++++++++++++");
regenerateTableAfterImport();
console.log("Objet Tache :", JSON.stringify(objetTache, null, 2));
}
function regenerateTableAfterImport() {
tableBody.innerHTML = "";
linkages.forEach(linkage => {
const standardRowData = standardRowsData.find(row => row.id === linkage.standardRowId);
const estimationRowData = estimationRowsData.find(row => row.id === linkage.estimationRowId);
const standardRow = document.createElement("tr");
standardRow.setAttribute("draggable", "true");
standardRow.dataset.rowId = standardRowData.id;
const firstCells = [standardRowData.name, "", standardRowData.count];
firstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${standardRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = standardRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = standardRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
td.textContent = text;
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, standardRow);
});
}
standardRow.appendChild(td);
});
const headerCells = document.querySelectorAll("thead tr:nth-child(2) th:not(.weekend):not(.holiday)");
const workingDaysCount = headerCells.length;
for (let i = 0; i < workingDaysCount - 3; i++) {
const td = document.createElement("td");
td.dataset.cellId = `cell-${standardRowData.id}-${i}`;
td.dataset.cellValue = standardRowData.cells[i].value;
td.dataset.cellColor = standardRowData.cells[i].color;
td.textContent = standardRowData.cells[i].value;
td.style.backgroundColor = standardRowData.cells[i].color;
td.addEventListener("click", function () {
const newValue = td.dataset.cellValue === "0" ? "1" : "0";
td.dataset.cellValue = newValue;
td.textContent = newValue;
td.style.backgroundColor = newValue === "1" ? "green" : "white";
td.dataset.cellColor = newValue === "1" ? "green" : "white";
updateCountCell(standardRow);
updateRowData(td);
});
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
if (td.dataset.cellValue === "1") {
showColorContextMenu(event, td);
}
});
td.title = `ID: ${td.dataset.cellId}`;
standardRow.appendChild(td);
}
tableBody.appendChild(standardRow);
standardRow.addEventListener("dragstart", dragStart);
standardRow.addEventListener("dragover", dragOver);
standardRow.addEventListener("drop", drop);
const estimationRow = document.createElement("tr");
estimationRow.setAttribute("draggable", "true");
estimationRow.dataset.rowId = estimationRowData.id;
estimationRow.classList.add("estimation-row");
const estimationFirstCells = [estimationRowData.name, "", estimationRowData.estimationValue];
estimationFirstCells.forEach((text, index) => {
const td = document.createElement("td");
td.dataset.cellId = `cell-${estimationRowData.id}-${index}`;
if (index === 0) {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = estimationRowData.name;
input.addEventListener("click", function (event) {
event.stopPropagation();
input.focus();
input.style.width = "130px";
});
input.addEventListener("blur", function () {
if (!keydownHandled && !alertShown) {
alertShown = true;
input.classList.remove("editing");
input.style.width = "65px";
updateRowData(input);
}
keydownHandled = false;
alertShown = false;
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
keydownHandled = true;
if (!alertShown) {
alertShown = true;
input.classList.remove("editing");
input.blur();
input.style.width = "65px";
updateRowData(input);
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
td.appendChild(input);
} else if (index === 1) {
const select = document.createElement("select");
for (let i = 1; i <= 10; i++) {
const option = document.createElement("option");
option.value = i;
option.textContent = `Option ${i}`;
select.appendChild(option);
}
select.value = estimationRowData.selectValue;
select.addEventListener("change", function () {
updateRowData(select);
});
td.appendChild(select);
} else {
const input = document.createElement("input");
input.type = "text";
input.classList.add("editable-input");
input.value = text;
input.addEventListener("blur", function () {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
});
input.addEventListener("keydown", function (event) {
if (event.key === "Escape" || event.key === "Enter") {
const value = parseInt(input.value, 10);
if (isNaN(value) || value < 1 || value > 365) {
input.value = "0";
showMessageModal("La valeur doit être un nombre entier compris entre 1 et 365.");
} else {
updateRowData(input);
}
}
});
input.addEventListener("mousedown", function (event) {
event.stopPropagation();
});
td.appendChild(input);
}
if (index === 0) {
td.classList.add("row-header");
td.addEventListener("contextmenu", function (event) {
event.preventDefault();
showContextMenu(event, estimationRow);
});
}
estimationRow.appendChild(td);
});
const mergedCell = document.createElement("td");
mergedCell.colSpan = workingDaysCount - 3;
mergedCell.textContent = "";
mergedCell.classList.add("no-click");
estimationRow.appendChild(mergedCell);
tableBody.appendChild(estimationRow);
estimationRow.addEventListener("dragstart", dragStart);
estimationRow.addEventListener("dragover", dragOver);
estimationRow.addEventListener("drop", drop);
});
displayLinkages();
}
document.getElementById("snapButton").addEventListener("click", function () {
const tableData = traceTable();
console.log("Objet Tache :", JSON.stringify(tableData, null, 2));
});
});
</script>
</body>
</html>