Autosave: 20260307-025028
This commit is contained in:
parent
7fd4f3f013
commit
ca9f149495
323
admin.php
323
admin.php
@ -632,6 +632,69 @@ if (isset($_GET["delete_project_log"])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle Unit CRUD
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["action"]) && $_POST["action"] === "upsert_unit") {
|
||||
$id = (int)$_POST["id"];
|
||||
$name = $_POST["name"];
|
||||
$slug = $_POST["slug"];
|
||||
$faction_id = !empty($_POST["faction_id"]) ? (int)$_POST["faction_id"] : null;
|
||||
$can_be_destroyed = isset($_POST["can_be_destroyed"]) ? 1 : 0;
|
||||
$can_be_captured = isset($_POST["can_be_captured"]) ? 1 : 0;
|
||||
$points_per_hit = (int)$_POST["points_per_hit"];
|
||||
$bonus_destruction = (int)$_POST["bonus_destruction"];
|
||||
$bonus_capture = (int)$_POST["bonus_capture"];
|
||||
$grid_data = $_POST["grid_data"];
|
||||
|
||||
$image_url = null;
|
||||
if ($id > 0) {
|
||||
$stmt_img = $db->prepare("SELECT image_url FROM units WHERE id = ?");
|
||||
$stmt_img->execute([$id]);
|
||||
$image_url = $stmt_img->fetchColumn();
|
||||
}
|
||||
|
||||
if (isset($_FILES["image"]) && $_FILES["image"]["error"] === UPLOAD_ERR_OK) {
|
||||
$ext = pathinfo($_FILES["image"]["name"], PATHINFO_EXTENSION);
|
||||
$filename = "unit_" . $slug . "_" . time() . "." . $ext;
|
||||
$target = "assets/images/units/" . $filename;
|
||||
if (!is_dir("assets/images/units/")) mkdir("assets/images/units/", 0775, true);
|
||||
if (move_uploaded_file($_FILES["image"]["tmp_name"], $target)) {
|
||||
$image_url = $target;
|
||||
}
|
||||
}
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare("UPDATE units SET name = ?, slug = ?, faction_id = ?, can_be_destroyed = ?, can_be_captured = ?, points_per_hit = ?, bonus_destruction = ?, bonus_capture = ?, grid_data = ?, image_url = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $slug, $faction_id, $can_be_destroyed, $can_be_captured, $points_per_hit, $bonus_destruction, $bonus_capture, $grid_data, $image_url, $id]);
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO units (name, slug, faction_id, can_be_destroyed, can_be_captured, points_per_hit, bonus_destruction, bonus_capture, grid_data, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $slug, $faction_id, $can_be_destroyed, $can_be_captured, $points_per_hit, $bonus_destruction, $bonus_capture, $grid_data, $image_url]);
|
||||
$id = $db->lastInsertId();
|
||||
}
|
||||
|
||||
// Handle Rewards
|
||||
$db->prepare("DELETE FROM unit_rewards WHERE unit_id = ?")->execute([$id]);
|
||||
if (isset($_POST["reward_action"]) && is_array($_POST["reward_action"])) {
|
||||
$ins_rw = $db->prepare("INSERT INTO unit_rewards (unit_id, action_type, resource_id, amount) VALUES (?, ?, ?, ?)");
|
||||
foreach ($_POST["reward_action"] as $idx => $action) {
|
||||
$res_id = (int)$_POST["reward_resource_id"][$idx];
|
||||
$amount = (int)$_POST["reward_amount"][$idx];
|
||||
if ($amount > 0) {
|
||||
$ins_rw->execute([$id, $action, $res_id, $amount]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header("Location: admin.php?tab=units&success=1");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_GET["delete_unit"])) {
|
||||
$id = (int)$_GET["delete_unit"];
|
||||
$db->prepare("DELETE FROM units WHERE id = ?")->execute([$id]);
|
||||
header("Location: admin.php?tab=units&success=1");
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- DATA FETCHING ---
|
||||
|
||||
$users_list = [];
|
||||
@ -645,6 +708,7 @@ $factions_list = [];
|
||||
$resources_list = [];
|
||||
$lootboxes_list = [];
|
||||
$project_logs_list = [];
|
||||
$units_list = [];
|
||||
$titles_list = [];
|
||||
$badges_list = [];
|
||||
$levels_list = [];
|
||||
@ -711,6 +775,16 @@ if ($tab === 'users') {
|
||||
$stmt = $db->query("SELECT value FROM guild_restrictions WHERE restriction_key = 'member_limit'");
|
||||
$guild_member_limit = $stmt->fetchColumn() ?: 50;
|
||||
}
|
||||
elseif ($tab === "units") {
|
||||
$units_list = $db->query("SELECT u.*, f.name as faction_name FROM units u LEFT JOIN factions f ON u.faction_id = f.id ORDER BY u.name ASC")->fetchAll();
|
||||
foreach ($units_list as &$unit) {
|
||||
$stmt_rw = $db->prepare("SELECT action_type, resource_id, amount FROM unit_rewards WHERE unit_id = ?");
|
||||
$stmt_rw->execute([$unit["id"]]);
|
||||
$unit["rewards"] = $stmt_rw->fetchAll();
|
||||
}
|
||||
unset($unit);
|
||||
$factions_list = $db->query("SELECT id, name FROM factions ORDER BY name ASC")->fetchAll();
|
||||
$resources_list = $db->query("SELECT id, name FROM game_resources ORDER BY name ASC")->fetchAll();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@ -762,10 +836,8 @@ if ($tab === 'users') {
|
||||
.toggle-container { display: flex; align-items: center; gap: 5px; font-size: 9px; color: #8c92a3; flex: 0 0 100px; }
|
||||
.switch { position: relative; display: inline-block; width: 40px; height: 20px; flex-shrink: 0; }
|
||||
.switch input { opacity: 0; width: 0; height: 0; }
|
||||
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #334155; transition: .4s; border-radius: 20px; }
|
||||
.slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; }
|
||||
input:checked + .slider { background-color: #a3be8c; }
|
||||
input:checked + .slider:before { transform: translateX(20px); }
|
||||
$factions_list = $db->query("SELECT id, name FROM factions ORDER BY name ASC")->fetchAll();
|
||||
$resources_list = $db->query("SELECT id, name FROM game_resources ORDER BY name ASC")->fetchAll();
|
||||
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
@ -792,6 +864,11 @@ if ($tab === 'users') {
|
||||
.ms-item { padding: 5px 8px; cursor: pointer; display: flex; align-items: center; gap: 8px; font-size: 11px; }
|
||||
.ms-item:hover { background: #2d3545; }
|
||||
.ms-item input { width: auto !important; }
|
||||
.unit-grid-container { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
|
||||
.unit-grid { display: grid; grid-template-columns: repeat(5, 40px); grid-template-rows: repeat(10, 40px); gap: 2px; background: #2d3545; padding: 2px; width: fit-content; }
|
||||
.unit-cell { width: 40px; height: 40px; background: #0f172a; cursor: pointer; border: 1px solid #334155; }
|
||||
.unit-cell.active { background: #88c0d0; }
|
||||
.unit-cell:hover { border-color: #88c0d0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -835,6 +912,7 @@ if ($tab === 'users') {
|
||||
<a href="?tab=factions" class="tab-link <?php echo $tab === 'factions' ? 'active' : ''; ?>"><i class="fa-solid fa-flag"></i> Factions</a>
|
||||
<a href="?tab=resources" class="tab-link <?php echo $tab === 'resources' ? 'active' : ''; ?>"><i class="fa-solid fa-gem"></i> Ressources</a>
|
||||
<a href="?tab=lootboxes" class="tab-link <?php echo $tab === 'lootboxes' ? 'active' : ''; ?>"><i class="fa-solid fa-box-open"></i> Lootboxes</a>
|
||||
<a href="?tab=units" class="tab-link <?php echo $tab === 'units' ? 'active' : ''; ?>"><i class="fa-solid fa-rocket"></i> Unité</a>
|
||||
</div>
|
||||
|
||||
<?php if ($tab === 'users'): ?>
|
||||
@ -870,6 +948,153 @@ if ($tab === 'users') {
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php elseif ($tab === 'units'): ?>
|
||||
<h3 style="color: #88c0d0;">Gestion des Unités</h3>
|
||||
<div class="form-card">
|
||||
<h4>Ajouter / Modifier une Unité</h4>
|
||||
<form method="POST" enctype="multipart/form-data" id="unitForm">
|
||||
<input type="hidden" name="action" value="upsert_unit">
|
||||
<input type="hidden" name="id" id="unit_id" value="0">
|
||||
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
||||
<div class="form-group" style="flex: 1; min-width: 250px;">
|
||||
<label>Nom de l'unité</label>
|
||||
<input type="text" name="name" id="unit_name" required placeholder="Chasseur Stellaire">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1; min-width: 200px;">
|
||||
<label>Slug (unique)</label>
|
||||
<input type="text" name="slug" id="unit_slug" required placeholder="chasseur_stellaire">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1; min-width: 200px;">
|
||||
<label>Faction</label>
|
||||
<select name="faction_id" id="unit_faction_id">
|
||||
<option value="">Aucune (Neutre)</option>
|
||||
<?php foreach ($factions_list as $f): ?>
|
||||
<option value="<?php echo $f['id']; ?>"><?php echo htmlspecialchars($f['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-end;">
|
||||
<div class="form-group" style="flex: 1; min-width: 250px;">
|
||||
<label>Image de l'unité</label>
|
||||
<input type="file" name="image" accept="image/*">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1; min-width: 200px;">
|
||||
<label>Points par coup (dégâts)</label>
|
||||
<input type="number" name="points_per_hit" id="unit_points_per_hit" value="1" min="0">
|
||||
</div>
|
||||
<div class="form-group" style="display: flex; gap: 20px; flex: 1; min-width: 200px; padding-bottom: 10px;">
|
||||
<label style="display: flex; align-items: center; gap: 5px; cursor: pointer;">
|
||||
<input type="checkbox" name="can_be_destroyed" id="unit_can_be_destroyed" value="1"> Destructible
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 5px; cursor: pointer;">
|
||||
<input type="checkbox" name="can_be_captured" id="unit_can_be_captured" value="1"> Capturable
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label>Bonus Destruction (Points)</label>
|
||||
<input type="number" name="bonus_destruction" id="unit_bonus_destruction" value="0" min="0">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label>Bonus Capture (Points)</label>
|
||||
<input type="number" name="bonus_capture" id="unit_bonus_capture" value="0" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Données de Grille (JSON ou format spécifique)</label>
|
||||
<div class="unit-grid-container">
|
||||
<div class="unit-grid" id="unitGrid"></div>
|
||||
<div style="font-size: 10px; color: #8c92a3;">Cliquez sur les cases pour définir la forme de l'unité (5x10).</div>
|
||||
<textarea name="grid_data" id="unit_grid_data" style="height: 40px; font-size: 10px;"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Récompenses additionnelles (Action / Ressource / Quantité)</label>
|
||||
<div id="unitRewardsContainer">
|
||||
<div class="sub-form-header">
|
||||
<div style="flex: 1;">Action</div>
|
||||
<div style="flex: 1;">Ressource</div>
|
||||
<div style="flex: 1;">Quantité</div>
|
||||
<div class="btn-del-row-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn" style="background: #4c566a; color: #fff; margin-top: 5px;" onclick="addUnitRewardRow()">+ AJOUTER UNE RÉCOMPENSE</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<button type="submit" class="btn btn-add">ENREGISTRER L'UNITÉ</button>
|
||||
<button type="button" class="btn" style="background: #4c566a; color: #fff;" onclick="resetUnitForm()">ANNULER</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Nom / Slug</th>
|
||||
<th>Faction</th>
|
||||
<th>Propriétés</th>
|
||||
<th>Récompenses</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($units_list)): ?>
|
||||
<tr><td colspan="6" style="text-align: center; color: #8c92a3;">Aucune unité configurée.</td></tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($units_list as $unit): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ($unit['image_url']): ?>
|
||||
<img src="<?php echo $unit['image_url']; ?>" style="width: 40px; height: 40px; object-fit: contain; background: #1a202c; border-radius: 4px;">
|
||||
<?php else: ?>
|
||||
<div style="width: 40px; height: 40px; background: #1a202c; border-radius: 4px; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fa-solid fa-rocket" style="color: #2d3545;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($unit['name']); ?></strong><br>
|
||||
<code style="font-size: 10px;"><?php echo htmlspecialchars($unit['slug']); ?></code>
|
||||
</td>
|
||||
<td>
|
||||
<span style="color: #88c0d0; font-weight: bold; font-size: 12px;">
|
||||
<?php echo $unit['faction_name'] ? htmlspecialchars($unit['faction_name']) : 'Neutre'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td style="font-size: 11px;">
|
||||
Pts/Coup: <?php echo $unit['points_per_hit']; ?><br>
|
||||
<?php if ($unit['can_be_destroyed']): ?><span style="color: #bf616a;">● Destructible</span><br><?php endif; ?>
|
||||
<?php if ($unit['can_be_captured']): ?><span style="color: #a3be8c;">● Capturable</span><?php endif; ?>
|
||||
</td>
|
||||
<td style="font-size: 10px;">
|
||||
<?php if ($unit['bonus_destruction'] > 0): ?>Destr: +<?php echo $unit['bonus_destruction']; ?> pts<br><?php endif; ?>
|
||||
<?php if ($unit['bonus_capture'] > 0): ?>Capt: +<?php echo $unit['bonus_capture']; ?> pts<br><?php endif; ?>
|
||||
<?php foreach ($unit['rewards'] as $rw): ?>
|
||||
<?php
|
||||
$rName = '?';
|
||||
foreach($resources_list as $res) { if($res['id'] == $rw['resource_id']) { $rName = $res['name']; break; } }
|
||||
?>
|
||||
<span style="color: #8c92a3;"><?php echo $rw['action_type'] === 'destroy' ? 'Destr' : 'Capt'; ?>:</span>
|
||||
+<?php echo $rw['amount']; ?> <?php echo htmlspecialchars($rName); ?><br>
|
||||
<?php endforeach; ?>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-edit" onclick='editUnit(<?php echo json_encode($unit, JSON_HEX_APOS); ?>)'>Editer</button>
|
||||
<a href="?tab=units&delete_unit=<?php echo $unit['id']; ?>" class="btn btn-del" onclick="return confirm('Supprimer cette unité ?')">Suppr</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php elseif ($tab === 'levels'): ?>
|
||||
<h3 style="color: #88c0d0;">Gestion des Niveaux</h3>
|
||||
<div class="form-card">
|
||||
@ -997,6 +1222,7 @@ if ($tab === 'users') {
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Visuel</th>
|
||||
<th>Nom</th>
|
||||
<th>Slug</th>
|
||||
<th>Type</th>
|
||||
@ -1861,7 +2087,7 @@ if ($tab === 'users') {
|
||||
<i class="fa-solid fa-gem fa-lg" style="color: #4c566a;"></i>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><img src="<?php echo htmlspecialchars($r["image_url"]); ?>" style="width:40px;"></td><td><strong><?php echo htmlspecialchars($r["name"]); ?></strong></td>
|
||||
<td><strong><?php echo htmlspecialchars($r["name"]); ?></strong></td>
|
||||
<td><code><?php echo htmlspecialchars($r['slug']); ?></code></td>
|
||||
<td style="text-align: center;">
|
||||
<?php if ($r['show_in_header']): ?>
|
||||
@ -1891,7 +2117,6 @@ if ($tab === 'users') {
|
||||
<label>Version</label>
|
||||
<input type="text" name="version" id="log_version" required placeholder="Ex: 1.0.1">
|
||||
</div>
|
||||
<div class="form-group" style="flex: 3;">
|
||||
<label>Titre</label>
|
||||
<input type="text" name="title" id="log_title" required placeholder="Ex: Mise à jour majeure">
|
||||
</div>
|
||||
@ -1953,6 +2178,60 @@ if ($tab === 'users') {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function addUnitRewardRow(action = 'destroy', resId = '', amount = '') {
|
||||
const container = document.getElementById('unitRewardsContainer');
|
||||
const row = document.createElement('div');
|
||||
row.className = 'sub-form-row';
|
||||
|
||||
let resOptions = '';
|
||||
<?php foreach ($resources_list as $res): ?>
|
||||
resOptions += '<option value="<?php echo $res['id']; ?>" ' + (resId == <?php echo $res['id']; ?> ? 'selected' : '') + '><?php echo addslashes($res['name']); ?></option>';
|
||||
<?php endforeach; ?>
|
||||
|
||||
row.innerHTML = `
|
||||
<select name="reward_action[]" style="flex: 1;">
|
||||
<option value="destroy" ${action === 'destroy' ? 'selected' : ''}>Détruire</option>
|
||||
<option value="capture" ${action === 'capture' ? 'selected' : ''}>Capturer</option>
|
||||
</select>
|
||||
<select name="reward_resource_id[]" style="flex: 1;" required>
|
||||
<option value="">-- Ressource --</option>
|
||||
${resOptions}
|
||||
</select>
|
||||
<input type="number" name="reward_amount[]" style="flex: 1;" value="${amount}" required placeholder="Qté">
|
||||
<div class="btn-del-row" onclick="this.parentElement.remove()">×</div>
|
||||
`;
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
function resetUnitForm() {
|
||||
document.getElementById('unitForm').reset();
|
||||
document.getElementById('unit_id').value = 0;
|
||||
setUnitGridFromData("");
|
||||
document.getElementById('unitRewardsContainer').innerHTML = '<div class="sub-form-header"><div style="flex: 1;">Action</div><div style="flex: 1;">Ressource</div><div style="flex: 1;">Quantité</div><div class="btn-del-row-placeholder"></div></div>';
|
||||
}
|
||||
|
||||
function editUnit(data) {
|
||||
resetUnitForm();
|
||||
document.getElementById('unit_id').value = data.id;
|
||||
document.getElementById('unit_name').value = data.name;
|
||||
document.getElementById('unit_slug').value = data.slug;
|
||||
document.getElementById('unit_faction_id').value = data.faction_id || '';
|
||||
document.getElementById('unit_points_per_hit').value = data.points_per_hit;
|
||||
document.getElementById('unit_can_be_destroyed').checked = data.can_be_destroyed == 1;
|
||||
document.getElementById('unit_can_be_captured').checked = data.can_be_captured == 1;
|
||||
document.getElementById('unit_bonus_destruction').value = data.bonus_destruction;
|
||||
document.getElementById('unit_bonus_capture').value = data.bonus_capture;
|
||||
setUnitGridFromData(data.grid_data);
|
||||
document.getElementById('unit_grid_data').value = data.grid_data;
|
||||
|
||||
if (data.rewards && data.rewards.length > 0) {
|
||||
data.rewards.forEach(r => {
|
||||
addUnitRewardRow(r.action_type, r.resource_id, r.amount);
|
||||
});
|
||||
}
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
function editLevel(data) {
|
||||
document.getElementById("level_id").value = data.id;
|
||||
document.getElementById("level_name").value = data.name;
|
||||
@ -2146,6 +2425,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function createUnitGrid() {
|
||||
const grid = document.getElementById("unitGrid");
|
||||
if (!grid) return;
|
||||
grid.innerHTML = "";
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const cell = document.createElement("div");
|
||||
cell.className = "unit-cell";
|
||||
cell.dataset.index = i;
|
||||
cell.onclick = function() {
|
||||
this.classList.toggle("active");
|
||||
updateUnitGridData();
|
||||
};
|
||||
grid.appendChild(cell);
|
||||
}
|
||||
}
|
||||
function updateUnitGridData() {
|
||||
const activeCells = Array.from(document.querySelectorAll(".unit-cell.active"))
|
||||
.map(c => c.dataset.index);
|
||||
document.getElementById("unit_grid_data").value = JSON.stringify(activeCells);
|
||||
}
|
||||
function setUnitGridFromData(data) {
|
||||
try {
|
||||
const activeCells = JSON.parse(data || "[]");
|
||||
document.querySelectorAll(".unit-cell").forEach(c => {
|
||||
c.classList.toggle("active", activeCells.includes(c.dataset.index) || activeCells.includes(parseInt(c.dataset.index)));
|
||||
});
|
||||
} catch (e) {
|
||||
document.querySelectorAll(".unit-cell").forEach(c => c.classList.remove("active"));
|
||||
}
|
||||
}
|
||||
|
||||
// --- SHARED RESOURCES ---
|
||||
const resourcesList = <?php echo json_encode($resources_list); ?>;
|
||||
|
||||
@ -2273,6 +2583,7 @@ function editStatus(data) {
|
||||
document.getElementById('badge_id').value = 0;
|
||||
document.getElementById('badge_preview_container').style.display = 'none';
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", createUnitGrid);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
36
db/migrate_units.php
Normal file
36
db/migrate_units.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
$db = db();
|
||||
|
||||
try {
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS units (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) NOT NULL UNIQUE,
|
||||
image_url VARCHAR(255) NULL,
|
||||
grid_data TEXT NULL,
|
||||
faction_id INT NULL,
|
||||
can_be_destroyed TINYINT(1) DEFAULT 0,
|
||||
can_be_captured TINYINT(1) DEFAULT 0,
|
||||
points_per_hit INT DEFAULT 1,
|
||||
bonus_destruction INT DEFAULT 0,
|
||||
bonus_capture INT DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (faction_id) REFERENCES factions(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS unit_rewards (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
unit_id INT NOT NULL,
|
||||
action_type ENUM('destroy', 'capture') NOT NULL,
|
||||
resource_id INT NOT NULL,
|
||||
amount INT NOT NULL,
|
||||
FOREIGN KEY (unit_id) REFERENCES units(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (resource_id) REFERENCES game_resources(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
||||
|
||||
echo "Migration completed: units and unit_rewards tables created.\n";
|
||||
} catch (PDOException $e) {
|
||||
die("Migration failed: " . $e->getMessage() . "\n");
|
||||
}
|
||||
|
||||
124
fix_admin.py
Normal file
124
fix_admin.py
Normal file
@ -0,0 +1,124 @@
|
||||
import sys
|
||||
import re
|
||||
|
||||
try:
|
||||
with open('admin.php', 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Remove any existing script tags and their contents
|
||||
content = re.sub(r'<script>.*?</script>', '', content, flags=re.DOTALL)
|
||||
content = content.replace('<script>', '').replace('</script>', '')
|
||||
|
||||
# Define the full script content
|
||||
script_content = r"""
|
||||
<script>
|
||||
function syncSlug(val, targetId) {
|
||||
const target = document.getElementById(targetId);
|
||||
if (target) {
|
||||
target.value = val.toLowerCase().normalize('NFD').replace(/[̀-ͤ]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
||||
if (typeof checkUnitFormValidity === 'function') checkUnitFormValidity();
|
||||
}
|
||||
}
|
||||
|
||||
// UNIT TAB JS
|
||||
const unitGridDataInput = document.getElementById('unit_grid_data');
|
||||
const unitGridCells = document.querySelectorAll('.grid-cell');
|
||||
|
||||
function initUnitGrid() {
|
||||
const grid = document.getElementById('unit_grid');
|
||||
if (grid) {
|
||||
const cells = grid.querySelectorAll('.grid-cell');
|
||||
cells.forEach(cell => {
|
||||
cell.addEventListener('click', () => {
|
||||
cell.classList.toggle('active');
|
||||
cell.style.background = cell.classList.contains('active') ? '#88c0d0' : '#0a0f1d';
|
||||
updateGridData();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateGridData() {
|
||||
const activeIndices = [];
|
||||
const cells = document.querySelectorAll('.grid-cell');
|
||||
cells.forEach(cell => { if (cell.classList.contains('active')) activeIndices.push(cell.getAttribute('data-index')); });
|
||||
const input = document.getElementById('unit_grid_data');
|
||||
if (input) input.value = JSON.stringify(activeIndices);
|
||||
checkUnitFormValidity();
|
||||
}
|
||||
|
||||
function checkUnitFormValidity() {
|
||||
const name = document.getElementById('unit_name')?.value;
|
||||
const slug = document.getElementById('unit_slug')?.value;
|
||||
const gridData = document.getElementById('unit_grid_data')?.value;
|
||||
const submitBtn = document.getElementById('unit_submit_btn');
|
||||
if (submitBtn) {
|
||||
const isValid = name && slug && gridData && gridData !== '[]' && gridData !== '';
|
||||
submitBtn.disabled = !isValid;
|
||||
submitBtn.style.opacity = isValid ? '1' : '0.5';
|
||||
}
|
||||
}
|
||||
|
||||
function resetUnitForm() {
|
||||
document.getElementById('unit_id').value = 0;
|
||||
const cells = document.querySelectorAll('.grid-cell');
|
||||
cells.forEach(cell => { cell.classList.remove('active'); cell.style.background = '#0a0f1d'; });
|
||||
const input = document.getElementById('unit_grid_data');
|
||||
if (input) input.value = '';
|
||||
document.querySelectorAll('.reward-input-destroy, .reward-input-capture').forEach(input => input.value = 0);
|
||||
checkUnitFormValidity();
|
||||
}
|
||||
|
||||
function editUnit(data) {
|
||||
document.getElementById('unit_id').value = data.id;
|
||||
document.getElementById('unit_name').value = data.name;
|
||||
document.getElementById('unit_slug').value = data.slug;
|
||||
document.getElementById('unit_faction_id').value = data.faction_id || "";
|
||||
document.getElementById('unit_can_be_destroyed').checked = data.can_be_destroyed == 1;
|
||||
document.getElementById('unit_can_be_captured').checked = data.can_be_captured == 1;
|
||||
document.getElementById('unit_points_per_hit').value = data.points_per_hit;
|
||||
document.getElementById('unit_bonus_destruction').value = data.bonus_destruction;
|
||||
document.getElementById('unit_bonus_capture').value = data.bonus_capture;
|
||||
|
||||
const indices = JSON.parse(data.grid_data || '[]');
|
||||
const cells = document.querySelectorAll('.grid-cell');
|
||||
cells.forEach(cell => {
|
||||
const active = indices.includes(cell.getAttribute('data-index'));
|
||||
cell.classList.toggle('active', active);
|
||||
cell.style.background = active ? '#88c0d0' : '#0a0f1d';
|
||||
});
|
||||
|
||||
const input = document.getElementById('unit_grid_data');
|
||||
if (input) input.value = data.grid_data;
|
||||
|
||||
document.querySelectorAll('.reward-input-destroy, .reward-input-capture').forEach(input => input.value = 0);
|
||||
if (data.rewards) {
|
||||
data.rewards.forEach(r => {
|
||||
const selector = r.action_type === 'destroy' ? '.reward-input-destroy' : '.reward-input-capture';
|
||||
const input = document.querySelector(selector + '[data-res-id="' + r.resource_id + '"]');
|
||||
if (input) input.value = r.amount;
|
||||
});
|
||||
}
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
checkUnitFormValidity();
|
||||
}
|
||||
|
||||
// Shared helpers
|
||||
function editLevel(d) { document.getElementById("level_id").value = d.id; document.getElementById("level_name").value = d.name; document.getElementById("level_slug").value = d.slug; document.getElementById("level_resource_id").value = d.resource_id; document.getElementById("level_required_quantity").value = d.required_quantity; window.scrollTo(0,0); }
|
||||
function editRank(r) { document.getElementById('rank_id').value = r.id; document.getElementById('rank_name').value = r.name; document.getElementById('rank_slug').value = r.slug; document.getElementById('rank_type').value = r.user_type; document.getElementById('rank_min').value = r.min_level || ''; document.getElementById('rank_max').value = r.max_level || ''; window.scrollTo(0,0); }
|
||||
function editStatus(s) { document.getElementById("st_id").value = s.id; document.getElementById("st_name").value = s.name; document.getElementById("st_slug").value = s.slug; document.getElementById("st_color").value = s.color.replace(';blink',''); document.getElementById("st_is_blinking").checked = s.color.includes(';blink'); window.scrollTo(0,0); }
|
||||
function editResource(r) { document.getElementById('res_id').value = r.id; document.getElementById('res_name').value = r.name; document.getElementById('res_slug').value = r.slug; document.getElementById('res_icon').value = r.icon; window.scrollTo(0,0); }
|
||||
function editFaction(f) { document.getElementById('fac_id').value = f.id; document.getElementById('fac_name').value = f.name; document.getElementById('fac_slug').value = f.slug; document.getElementById('fac_color').value = f.color; window.scrollTo(0,0); }
|
||||
function editObject(o) { document.getElementById('obj_id').value = o.id; document.getElementById('obj_name').value = o.name; document.getElementById('obj_slug').value = o.slug; window.scrollTo(0,0); }
|
||||
function resetObjectForm() { document.getElementById('obj_id').value = 0; }
|
||||
function resetLevelForm() { document.getElementById('level_id').value = 0; }
|
||||
function resetRankForm() { document.getElementById('rank_id').value = 0; }
|
||||
function resetStatusForm() { document.getElementById('st_id').value = 0; }
|
||||
function resetResourceForm() { document.getElementById('res_id').value = 0; }
|
||||
function resetFactionForm() { document.getElementById('fac_id').value = 0; }
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initUnitGrid();
|
||||
checkUnitFormValidity();
|
||||
});
|
||||
</script>
|
||||
21
fix_admin_mini.py
Normal file
21
fix_admin_mini.py
Normal file
@ -0,0 +1,21 @@
|
||||
import re
|
||||
with open('admin.php', 'r') as f: content = f.read()
|
||||
content = re.sub(r'<script>.*?</script>', '', content, flags=re.DOTALL)
|
||||
content = content.replace('<script>', '').replace('</script>', '')
|
||||
js = """
|
||||
<script>
|
||||
function syncSlug(v,t){const e=document.getElementById(t);if(e){e.value=v.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,'');if(typeof checkUnitFormValidity==='function')checkUnitFormValidity();}}
|
||||
function updateGridData(){const a=[];document.querySelectorAll('.grid-cell').forEach(c=>{if(c.classList.contains('active'))a.push(c.getAttribute('data-index'))});const i=document.getElementById('unit_grid_data');if(i)i.value=JSON.stringify(a);checkUnitFormValidity();}
|
||||
function checkUnitFormValidity(){const n=document.getElementById('unit_name')?.value,s=document.getElementById('unit_slug')?.value,g=document.getElementById('unit_grid_data')?.value,b=document.getElementById('unit_submit_btn');if(b){const v=n&&s&&g&&g!=='[]'&&g!=='';b.disabled=!v;b.style.opacity=v?'1':'0.5';}}
|
||||
function resetUnitForm(){document.getElementById('unit_id').value=0;document.querySelectorAll('.grid-cell').forEach(c=>{c.classList.remove('active');c.style.background='#0a0f1d'});document.getElementById('unit_grid_data').value='';document.querySelectorAll('.reward-input-destroy,.reward-input-capture').forEach(i=>i.value=0);checkUnitFormValidity();}
|
||||
function editUnit(d){document.getElementById('unit_id').value=d.id;document.getElementById('unit_name').value=d.name;document.getElementById('unit_slug').value=d.slug;document.getElementById('unit_faction_id').value=d.faction_id||"";document.getElementById('unit_can_be_destroyed').checked=d.can_be_destroyed==1;document.getElementById('unit_can_be_captured').checked=d.can_be_captured==1;document.getElementById('unit_points_per_hit').value=d.points_per_hit;document.getElementById('unit_bonus_destruction').value=d.bonus_destruction;document.getElementById('unit_bonus_capture').value=d.bonus_capture;const a=JSON.parse(d.grid_data||'[]')
|
||||
document.querySelectorAll('.grid-cell').forEach(c=>{const v=a.includes(c.getAttribute('data-index'));c.classList.toggle('active',v);c.style.background=v?'#88c0d0':'#0a0f1d'});document.getElementById('unit_grid_data').value=d.grid_data;document.querySelectorAll('.reward-input-destroy,.reward-input-capture').forEach(i=>i.value=0);if(d.rewards)d.rewards.forEach(r=>{const s=r.action_type==='destroy'?'.reward-input-destroy':'.reward-input-capture';const i=document.querySelector(s+'[data-res-id="'+r.resource_id+'"]');if(i)i.value=r.amount;});window.scrollTo({top:0,behavior:'smooth'});checkUnitFormValidity();}
|
||||
function editLevel(d){document.getElementById("level_id").value=d.id;document.getElementById("level_name").value=d.name;document.getElementById("level_slug").value=d.slug;document.getElementById("level_resource_id").value=d.resource_id;document.getElementById("level_required_quantity").value=d.required_quantity;window.scrollTo(0,0);}
|
||||
function editRank(r){document.getElementById('rank_id').value=r.id;document.getElementById('rank_name').value=r.name;document.getElementById('rank_slug').value=r.slug;document.getElementById('rank_type').value=r.user_type;document.getElementById('rank_min').value=r.min_level||"";document.getElementById('rank_max').value=r.max_level||"";window.scrollTo(0,0);}
|
||||
function editStatus(s){document.getElementById("st_id").value=s.id;document.getElementById("st_name").value=s.name;document.getElementById("st_slug").value=s.slug;document.getElementById("st_color").value=s.color.replace(';blink','');document.getElementById("st_is_blinking").checked=s.color.includes(';blink');window.scrollTo(0,0);}
|
||||
function editResource(r){document.getElementById('res_id').value=r.id;document.getElementById('res_name').value=r.name;document.getElementById('res_slug').value=r.slug;document.getElementById('res_icon').value=r.icon;window.scrollTo(0,0);}
|
||||
function editFaction(f){document.getElementById('fac_id').value=f.id;document.getElementById('fac_name').value=f.name;document.getElementById('fac_slug').value=f.slug;document.getElementById('fac_color').value=f.color;window.scrollTo(0,0);}
|
||||
function editObject(o){document.getElementById('obj_id').value=o.id;document.getElementById('obj_name').value=o.name;document.getElementById('obj_slug').value=o.slug;window.scrollTo(0,0);}
|
||||
function resetObjectForm(){document.getElementById('obj_id').value=0;}
|
||||
document.addEventListener('DOMContentLoaded',()=>{document.querySelectorAll('.grid-cell').forEach(c=>{c.addEventListener('click',()=>{c.classList.toggle('active');c.style.background=c.classList.contains('active')?'#88c0d0':'#0a0f1d';updateGridData();});});checkUnitFormValidity();});
|
||||
</script>
|
||||
5
fix_admin_v3.py
Normal file
5
fix_admin_v3.py
Normal file
@ -0,0 +1,5 @@
|
||||
import re
|
||||
with open('admin.php', 'r') as f: content = f.read()
|
||||
content = re.sub(r'<script>.*?</script>', '', content, flags=re.DOTALL)
|
||||
content = content.replace('<script>', '').replace('</script>', '')
|
||||
js = "<script>\nfunction syncSlug(v,t){const e=document.getElementById(t);if(e){e.value=v.toLowerCase().normalize('NFD').replace(/[\\u0300-\\u036f]/g,'').replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,'');if(typeof checkUnitFormValidity==='function')checkUnitFormValidity();}}\nfunction updateGridData(){const a=[];document.querySelectorAll('.grid-cell').forEach(c=>{if(c.classList.contains('active'))a.push(c.getAttribute('data-index'))});const i=document.getElementById('unit_grid_data');if(i)i.value=JSON.stringify(a);checkUnitFormValidity();}\nfunction checkUnitFormValidity(){const n=document.getElementById('unit_name')?.value,s=document.getElementById('unit_slug')?.value,g=document.getElementById('unit_grid_data')?.value,b=document.getElementById('unit_submit_btn');if(b){const v=n&&s&&g&&g!=='[]'&&g!=='';b.disabled=!v;b.style.opacity=v?'1':'0.5';}}\nfunction resetUnitForm(){document.getElementById('unit_id').value=0;document.querySelectorAll('.grid-cell').forEach(c=>{c.classList.remove('active');c.style.background='#0a0f1d'});document.getElementById('unit_grid_data').value='';document.querySelectorAll('.reward-input-destroy,.reward-input-capture').forEach(i=>i.value=0);checkUnitFormValidity();}\nfunction editUnit(d){document.getElementById('unit_id').value=d.id;document.getElementById('unit_name').value=d.name;document.getElementById('unit_slug').value=d.slug;document.getElementById('unit_faction_id').value=d.faction_id||"";document.getElementById('unit_can_be_destroyed').checked=d.can_be_destroyed==1;document.getElementById('unit_can_be_captured').checked=d.can_be_captured==1;document.getElementById('unit_points_per_hit').value=d.points_per_hit;document.getElementById('unit_bonus_destruction').value=d.bonus_destruction;document.getElementById('unit_bonus_capture').value=d.bonus_capture;const a=JSON.parse(d.grid_data||'[]');document.querySelectorAll('.grid-cell').forEach(c=>{const v=a.includes(c.getAttribute('data-index'));c.classList.toggle('active',v);c.style.background=v?'#88c0d0':'#0a0f1d'});document.getElementById('unit_grid_data').value=d.grid_data;document.querySelectorAll('.reward-input-destroy,.reward-input-capture').forEach(i=>i.value=0);if(d.rewards)d.rewards.forEach(r=>{const s=r.action_type==='destroy'?'.reward-input-destroy':'.reward-input-capture';const i=document.querySelector(s+'[data-res-id="'+r.resource_id+'"]');if(i)i.value=r.amount;});window.scrollTo({top:0,behavior:'smooth'});checkUnitFormValidity();}\nfunction editLevel(d){document.getElementById("level_id").value=d.id;document.getElementById("level_name").value=d.name;document.getElementById("level_slug").value=d.slug;document.getElementById("level_resource_id").value=d.resource_id;document.getElementById("level_required_quantity").value=d.required_quantity;window.scrollTo(0,0);}\nfunction editRank(r){document.getElementById('rank_id').value=r.id;document.getElementById('rank_name').value=r.name;document.getElementById('rank_slug').value=r.slug;document.getElementById('rank_type').value=r.user_type;document.getElementById('rank_min').value=r.min_level||"";document.getElementById('rank_max').value=r.max_level||"";window.scrollTo(0,0);}\nfunction editStatus(s){document.getElementById("st_id").value=s.id;document.getElementById("st_name").value=s.name;document.getElementById("st_slug").value=s.slug;document.getElementById("st_color").value=s.color.replace(';blink','');document.getElementById("st_is_blinking").checked=s.color.includes(';blink');window.scrollTo(0,0);}\nfunction editResource(r){document.getElementById('res_id').value=r.id;document.getElementById('res_name').value=r.name;document.getElementById('res_slug').value=r.slug;document.getElementById('res_icon').value=r.icon;window.scrollTo(0,0);}\nfunction editFaction(f){document.getElementById('fac_id').value=f.id;document.getElementById('fac_name').value=f.name;document.getElementById('fac_slug').value=f.slug;document.getElementById('fac_color').value=f.color;window.scrollTo(0,0);}\nfunction editObject(o){document.getElementById('obj_id').value=o.id;document.getElementById('obj_name').value=o.name;document.getElementById('obj_slug').value=o.slug;window.scrollTo(0,0);}\nfunction resetObjectForm(){document.getElementById('obj_id').value=0;}\ndocument.addEventListener('DOMContentLoaded',()=>{document.querySelectorAll('.grid-cell').forEach(c=>{c.addEventListener('click',()=>{c.classList.toggle('active');c.style.background=c.classList.contains('active')?'#88c0d0':'#0a0f1d';updateGridData();});});checkUnitFormValidity();});\n</script>" with open('admin.php', 'w') as f: f.write(content.replace('</body>', js + '\n</body>'))
|
||||
@ -1,155 +0,0 @@
|
||||
<?php
|
||||
$file = 'admin.php';
|
||||
$content = file_get_contents($file);
|
||||
|
||||
// 1. Update POST Handler
|
||||
$old_h = ' $is_empty_case = isset($_POST[\'is_empty_case\']) ? 1 : 0;
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare("UPDATE celestial_object_status_rules SET name = ?, status_id = ?, profile_id = ?, priority = ?, orbital_count_op = ?, orbital_count_val = ?, terrestrial_count_op = ?, terrestrial_count_val = ?, orbital_dominance = ?, terrestrial_dominance = ?, is_empty_case = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $id]);
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO celestial_object_status_rules (name, status_id, profile_id, priority, orbital_count_op, orbital_count_val, terrestrial_count_op, terrestrial_count_val, orbital_dominance, terrestrial_dominance, is_empty_case) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case]);
|
||||
}';
|
||||
|
||||
$new_h = ' $is_empty_case = isset($_POST[\'is_empty_case\']) ? 1 : 0;
|
||||
$combine_mode = $_POST[\'combine_mode\'] ?? \'OR\';
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare("UPDATE celestial_object_status_rules SET name = ?, status_id = ?, profile_id = ?, priority = ?, orbital_count_op = ?, orbital_count_val = ?, terrestrial_count_op = ?, terrestrial_count_val = ?, orbital_dominance = ?, terrestrial_dominance = ?, is_empty_case = ?, combine_mode = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $combine_mode, $id]);
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO celestial_object_status_rules (name, status_id, profile_id, priority, orbital_count_op, orbital_count_val, terrestrial_count_op, terrestrial_count_val, orbital_dominance, terrestrial_dominance, is_empty_case, combine_mode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $combine_mode]);
|
||||
}';
|
||||
|
||||
if (strpos($content, $old_h) !== false) {
|
||||
$content = str_replace($old_h, $new_h, $content);
|
||||
echo "Handler updated.\n";
|
||||
} else {
|
||||
echo "Handler NOT found (check whitespace/indentation).\n";
|
||||
}
|
||||
|
||||
// 2. Update UI
|
||||
$ui_block_start = '<div style="background: rgba(0,0,0,0.2); padding: 15px; border-radius: 4px; border: 1px solid #334155; margin-bottom: 15px;">';
|
||||
$ui_block_end = '<button type="submit" class="btn btn-add">ENREGISTRER LA RÈGLE</button>';
|
||||
|
||||
$pos_start = strpos($content, $ui_block_start);
|
||||
$pos_end = strpos($content, $ui_block_end, $pos_start);
|
||||
|
||||
if ($pos_start !== false && $pos_end !== false) {
|
||||
$new_ui = <<<'HTML'
|
||||
<div style="background: rgba(0,0,0,0.2); padding: 15px; border-radius: 4px; border: 1px solid #334155; margin-bottom: 15px;">
|
||||
<div style="display: flex; gap: 20px; align-items: stretch;">
|
||||
|
||||
<!-- COLONNE ORBITALE -->
|
||||
<div style="flex: 1; display: flex; flex-direction: column; gap: 15px; padding-right: 15px; border-right: 1px dashed #334155;">
|
||||
<div style="font-size: 11px; color: #88c0d0; font-weight: bold; text-align: center; border-bottom: 1px solid #334155; padding-bottom: 5px; margin-bottom: 5px;">EN ORBITE</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Nombre de factions</label>
|
||||
<div style="display: flex; gap: 5px;">
|
||||
<select name="orbital_count_op" id="rule_orb_op" style="width: 70px;">
|
||||
<option value="">-
|
||||
</option>
|
||||
<option value="=">=
|
||||
</option><option value=">">>
|
||||
</option><option value="<"><
|
||||
</option>
|
||||
<option value=">=">:=
|
||||
</option><option value="<="><=
|
||||
</option>
|
||||
</select>
|
||||
<input type="number" name="orbital_count_val" id="rule_orb_val" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Filtre Dominance</label>
|
||||
<div class="ms-container" id="ms_orb">
|
||||
<div class="ms-display" onclick="toggleMS('ms_orb_list')">Toutes / Peu importe</div>
|
||||
<div class="ms-dropdown" id="ms_orb_list">
|
||||
<label class="ms-item"><input type="checkbox" value="none" onchange="updateMSLabel('ms_orb')"> Aucune (Vide)</label>
|
||||
<?php foreach($factions_list as $f): if($f['name'] !== 'Aucune'): ?>
|
||||
<label class="ms-item"><input type="checkbox" value="<?php echo $f['id']; ?>" name="orbital_dominance[]" onchange="updateMSLabel('ms_orb')"> <?php echo htmlspecialchars($f['name']); ?></label>
|
||||
<?php endif; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- COLONNE COMBINAISON (MILIEU) -->
|
||||
<div style="flex: 0 0 100px; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 10px; background: rgba(136, 192, 208, 0.05); border-radius: 8px; border: 1px solid rgba(136, 192, 208, 0.2); padding: 10px;">
|
||||
<label style="font-size: 10px; color: #88c0d0; font-weight: bold; text-transform: uppercase;">Combinaison</label>
|
||||
<select name="combine_mode" id="rule_combine" style="width: 100%; text-align: center; font-weight: bold; color: #ebcb8b; background: #2e3440; border-color: #88c0d0;">
|
||||
<option value="OR">OU</option>
|
||||
<option value="AND">ET</option>
|
||||
</select>
|
||||
<div style="font-size: 9px; color: #d8dee9; text-align: center; opacity: 0.7;">(Orbital) [?] (Sol)</div>
|
||||
</div>
|
||||
|
||||
<!-- COLONNE SOL -->
|
||||
<div style="flex: 1; display: flex; flex-direction: column; gap: 15px; padding-left: 15px; border-left: 1px dashed #334155;">
|
||||
<div style="font-size: 11px; color: #88c0d0; font-weight: bold; text-align: center; border-bottom: 1px solid #334155; padding-bottom: 5px; margin-bottom: 5px;">AU SOL</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Nombre de factions</label>
|
||||
<div style="display: flex; gap: 5px;">
|
||||
<select name="terrestrial_count_op" id="rule_terr_op" style="width: 70px;">
|
||||
<option value="">-
|
||||
</option>
|
||||
<option value="=">=
|
||||
</option><option value=">">>
|
||||
</option><option value="<"><
|
||||
</option>
|
||||
<option value=">=">:=
|
||||
</option><option value="<="><=
|
||||
</option>
|
||||
</select>
|
||||
<input type="number" name="terrestrial_count_val" id="rule_terr_val" placeholder="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Filtre Dominance</label>
|
||||
<div class="ms-container" id="ms_terr">
|
||||
<div class="ms-display" onclick="toggleMS('ms_terr_list')">Toutes / Peu importe</div>
|
||||
<div class="ms-dropdown" id="ms_terr_list">
|
||||
<label class="ms-item"><input type="checkbox" value="none" onchange="updateMSLabel('ms_terr')"> Aucune (Vide)</label>
|
||||
<?php foreach($factions_list as $f): if($f['name'] !== 'Aucune'): ?>
|
||||
<label class="ms-item"><input type="checkbox" value="<?php echo $f['id']; ?>" name="terrestrial_dominance[]" onchange="updateMSLabel('ms_terr')"> <?php echo htmlspecialchars($f['name']); ?></label>
|
||||
<?php endif; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding-top: 15px; margin-top: 15px; border-top: 1px solid #334155;">
|
||||
<input type="checkbox" name="is_empty_case" id="rule_empty" style="width: auto;">
|
||||
<label for="rule_empty" style="margin-bottom: 0; color: #ebcb8b;">Cas "CASE VIDE" (Aucune faction nulle part)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
HTML;
|
||||
$content = substr($content, 0, $pos_start) . $new_ui . substr($content, $pos_end);
|
||||
echo "UI updated.\n";
|
||||
} else {
|
||||
echo "UI NOT found.\n";
|
||||
}
|
||||
|
||||
// 3. Update JS (resetRuleForm)
|
||||
if (strpos($content, "document.getElementById('rule_combine').value = 'OR';") === false) {
|
||||
$content = str_replace(
|
||||
"document.getElementById('rule_id').value = 0;",
|
||||
"document.getElementById('rule_id').value = 0; document.getElementById('rule_combine').value = 'OR';",
|
||||
$content
|
||||
);
|
||||
echo "JS updated.\n";
|
||||
}
|
||||
|
||||
file_put_contents($file, $content);
|
||||
echo "Done.\n";
|
||||
?>
|
||||
@ -1,285 +0,0 @@
|
||||
<?php
|
||||
$admin_path = 'admin.php';
|
||||
$content = file_get_contents($admin_path);
|
||||
|
||||
// 1. Add CSS
|
||||
$css = <<<'EOD'
|
||||
|
||||
/* Multi-select Dropdown */
|
||||
.multi-select-dropdown { position: relative; width: 100%; }
|
||||
.multi-select-btn { width: 100%; padding: 8px 10px; background: #0f172a; border: 1px solid #334155; border-radius: 4px; color: #eceff4; text-align: left; cursor: pointer; font-size: 13px; display: flex; justify-content: space-between; align-items: center; box-sizing: border-box; }
|
||||
.multi-select-menu { position: absolute; top: 100%; left: 0; right: 0; z-index: 1000; background: #1e293b; border: 1px solid #334155; border-radius: 4px; margin-top: 5px; display: none; max-height: 250px; overflow-y: auto; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); }
|
||||
.multi-select-menu.show { display: block; }
|
||||
.multi-select-header { padding: 8px 10px; border-bottom: 1px solid #334155; display: flex; gap: 10px; background: #0f172a; position: sticky; top: 0; z-index: 10; }
|
||||
.multi-select-header button { background: none; border: none; color: #88c0d0; font-size: 10px; cursor: pointer; padding: 0; text-transform: uppercase; font-weight: bold; }
|
||||
.multi-select-header button:hover { text-decoration: underline; }
|
||||
.multi-select-option { padding: 6px 10px; display: flex; align-items: center; gap: 10px; cursor: pointer; font-size: 12px; }
|
||||
.multi-select-option:hover { background: #334155; }
|
||||
.multi-select-option input { width: auto !important; margin: 0; cursor: pointer; }
|
||||
|
||||
EOD;
|
||||
|
||||
if (strpos($content, '/* Multi-select Dropdown */') === false) {
|
||||
$content = str_replace('</style>', $css . ' </style>', $content);
|
||||
}
|
||||
|
||||
// 2. Update POST Handler
|
||||
$new_rule_handler = <<<'EOD'
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_status_rule') {
|
||||
$id = (int)$_POST['id'];
|
||||
$name = $_POST['name'];
|
||||
$status_id = (int)$_POST['status_id'];
|
||||
$profile_id = (int)$_POST['profile_id'];
|
||||
$priority = (int)$_POST['priority'];
|
||||
|
||||
$orbital_count_op = $_POST['orbital_count_op'] ?: null;
|
||||
$orbital_count_val = $_POST['orbital_count_val'] !== '' ? (int)$_POST['orbital_count_val'] : null;
|
||||
$terrestrial_count_op = $_POST['terrestrial_count_op'] ?: null;
|
||||
$terrestrial_count_val = $_POST['terrestrial_count_val'] !== '' ? (int)$_POST['terrestrial_count_val'] : null;
|
||||
|
||||
// Multi-select Factions logic
|
||||
$orb_factions = $_POST['orbital_dominant_factions'] ?? [];
|
||||
$terr_factions = $_POST['ground_dominant_factions'] ?? [];
|
||||
|
||||
// If "any" is in the list, we clear the list to mean "no filter"
|
||||
if (in_array('any', $orb_factions)) $orb_factions = [];
|
||||
if (in_array('any', $terr_factions)) $terr_factions = [];
|
||||
|
||||
$orbital_dominance = !empty($orb_factions) ? implode(',', $orb_factions) : null;
|
||||
$terrestrial_dominance = !empty($terr_factions) ? implode(',', $terr_factions) : null;
|
||||
$is_empty_case = isset($_POST['is_empty_case']) ? 1 : 0;
|
||||
|
||||
// V2 Compat
|
||||
$orbital_dominance_mode = $orbital_dominance ? 'IN' : 'ANY';
|
||||
$terrestrial_dominance_mode = $terrestrial_dominance ? 'IN' : 'ANY';
|
||||
$orbital_dominance_factions = $orbital_dominance;
|
||||
$terrestrial_dominance_factions = $terrestrial_dominance;
|
||||
$orbital_dominance_include_none = (is_array($orb_factions) && in_array('none', $orb_factions)) ? 1 : 0;
|
||||
$orbital_dominance_include_player = (is_array($orb_factions) && in_array('2', $orb_factions)) ? 1 : 0;
|
||||
$terrestrial_dominance_include_none = (is_array($terr_factions) && in_array('none', $terr_factions)) ? 1 : 0;
|
||||
$terrestrial_dominance_include_player = (is_array($terr_factions) && in_array('2', $terr_factions)) ? 1 : 0;
|
||||
$dominance_diff_required = 0;
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare("UPDATE celestial_object_status_rules SET name = ?, status_id = ?, profile_id = ?, priority = ?, orbital_count_op = ?, orbital_count_val = ?, terrestrial_count_op = ?, terrestrial_count_val = ?, orbital_dominance = ?, terrestrial_dominance = ?, is_empty_case = ?, orbital_dominance_mode = ?, orbital_dominance_factions = ?, orbital_dominance_include_none = ?, orbital_dominance_include_player = ?, terrestrial_dominance_mode = ?, terrestrial_dominance_factions = ?, terrestrial_dominance_include_none = ?, terrestrial_dominance_include_player = ?, dominance_diff_required = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $orbital_dominance_mode, $orbital_dominance_factions, $orbital_dominance_include_none, $orbital_dominance_include_player, $terrestrial_dominance_mode, $terrestrial_dominance_factions, $terrestrial_dominance_include_none, $terrestrial_dominance_include_player, $dominance_diff_required, $id]);
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO celestial_object_status_rules (name, status_id, profile_id, priority, orbital_count_op, orbital_count_val, terrestrial_count_op, terrestrial_count_val, orbital_dominance, terrestrial_dominance, is_empty_case, orbital_dominance_mode, orbital_dominance_factions, orbital_dominance_include_none, orbital_dominance_include_player, terrestrial_dominance_mode, terrestrial_dominance_factions, terrestrial_dominance_include_none, terrestrial_dominance_include_player, dominance_diff_required) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominance, $terrestrial_dominance, $is_empty_case, $orbital_dominance_mode, $orbital_dominance_factions, $orbital_dominance_include_none, $orbital_dominance_include_player, $terrestrial_dominance_mode, $terrestrial_dominance_factions, $terrestrial_dominance_include_none, $terrestrial_dominance_include_player, $dominance_diff_required]);
|
||||
}
|
||||
header("Location: admin.php?tab=statuses&success=1");
|
||||
exit;
|
||||
EOD;
|
||||
|
||||
$content = preg_replace('/if \(\$_SERVER\[\'REQUEST_METHOD\'\] === \'POST\' && isset\(\$_POST\[\'action\'\]\) && \$_POST\[\'action\'\] === \'upsert_status_rule\'\) \{.*?header\(\"Location: admin\.php\?tab=statuses&success=1\"\);\n exit;/s', $new_rule_handler, $content);
|
||||
|
||||
// 3. Update UI Form
|
||||
$new_ui = <<<'EOD'
|
||||
<div style="display: flex; gap: 15px; align-items: flex-start; margin-bottom: 10px;">
|
||||
<div style="flex: 0 0 180px; font-size: 11px; color: #88c0d0; font-weight: bold; padding-top: 5px;">FACTION DOMINANTE :</div>
|
||||
<div class="form-group" style="flex: 1; margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">En Orbite</label>
|
||||
<div class="multi-select-dropdown" id="orb_dom_container">
|
||||
<div class="multi-select-btn" id="orb-factions-btn" onclick="toggleMultiSelect('orb-factions')">
|
||||
N'importe laquelle <i class="fa-solid fa-chevron-down"></i>
|
||||
</div>
|
||||
<div class="multi-select-menu" id="orb-factions-menu">
|
||||
<div class="multi-select-header">
|
||||
<button type="button" onclick="selectAllMultiSelect('orb-factions', true)">Tout sélectionner</button>
|
||||
<button type="button" onclick="selectAllMultiSelect('orb-factions', false)">Tout désélectionner</button>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="any" class="orb-factions-checkbox any-option" data-label="N'importe laquelle" onchange="handleAnyOption('orb-factions', this)">
|
||||
<span>N'importe laquelle</span>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="none" class="orb-factions-checkbox" data-label="Aucune (Vide)" onchange="updateMultiSelectDisplay('orb-factions')">
|
||||
<span>Aucune (Vide)</span>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="2" class="orb-factions-checkbox" data-label="Joueur (Terrien)" onchange="updateMultiSelectDisplay('orb-factions')">
|
||||
<span>Joueur (Terrien)</span>
|
||||
</div>
|
||||
<hr style="border: 0; border-top: 1px solid #334155; margin: 5px 0;">
|
||||
<?php foreach($factions_list as $f): if($f['id'] > 2): ?>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="<?php echo $f['id']; ?>" class="orb-factions-checkbox" data-label="<?php echo htmlspecialchars($f['name']); ?>" onchange="updateMultiSelectDisplay('orb-factions')">
|
||||
<span><?php echo htmlspecialchars($f['name']); ?></span>
|
||||
</div>
|
||||
<?php endif; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="flex: 1; margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Au Sol</label>
|
||||
<div class="multi-select-dropdown" id="terr_dom_container">
|
||||
<div class="multi-select-btn" id="terr-factions-btn" onclick="toggleMultiSelect('terr-factions')">
|
||||
N'importe laquelle <i class="fa-solid fa-chevron-down"></i>
|
||||
</div>
|
||||
<div class="multi-select-menu" id="terr-factions-menu">
|
||||
<div class="multi-select-header">
|
||||
<button type="button" onclick="selectAllMultiSelect('terr-factions', true)">Tout sélectionner</button>
|
||||
<button type="button" onclick="selectAllMultiSelect('terr-factions', false)">Tout désélectionner</button>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="any" class="terr-factions-checkbox any-option" data-label="N'importe laquelle" onchange="handleAnyOption('terr-factions', this)">
|
||||
<span>N'importe laquelle</span>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="none" class="terr-factions-checkbox" data-label="Aucune (Vide)" onchange="updateMultiSelectDisplay('terr-factions')">
|
||||
<span>Aucune (Vide)</span>
|
||||
</div>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="2" class="terr-factions-checkbox" data-label="Joueur (Terrien)" onchange="updateMultiSelectDisplay('terr-factions')">
|
||||
<span>Joueur (Terrien)</span>
|
||||
</div>
|
||||
<hr style="border: 0; border-top: 1px solid #334155; margin: 5px 0;">
|
||||
<?php foreach($factions_list as $f): if($f['id'] > 2): ?>
|
||||
<div class="multi-select-option" onclick="toggleCheckbox(event, this)">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="<?php echo $f['id']; ?>" class="terr-factions-checkbox" data-label="<?php echo htmlspecialchars($f['name']); ?>" onchange="updateMultiSelectDisplay('terr-factions')">
|
||||
<span><?php echo htmlspecialchars($f['name']); ?></span>
|
||||
</div>
|
||||
<?php endif; endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 20px; padding-top: 10px; border-top: 1px solid #334155;">
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<input type="checkbox" name="is_empty_case" id="rule_empty" style="width: auto;">
|
||||
<label for="rule_empty" style="margin-bottom: 0; color: #ebcb8b; font-size: 11px;">Cas "CASE VIDE"</label>
|
||||
</div>
|
||||
</div>
|
||||
EOD;
|
||||
|
||||
// Need to match exactly the old UI to replace it
|
||||
$old_ui_regex = '/<div style="display: flex; gap: 15px; align-items: flex-start; margin-bottom: 10px;">.*?FILTRE DOMINANCE :.*?Cas \"CASE VIDE\".*?<\/div>.*?<\/div>/s';
|
||||
// Actually, I'll use str_replace for blocks I know are there
|
||||
// I'll read admin.php around the UI block to be 100% sure of the string.
|
||||
|
||||
$js_additions = <<<'EOD'
|
||||
function toggleMultiSelect(id) {
|
||||
const menu = document.getElementById(id + '-menu');
|
||||
if(!menu) return;
|
||||
menu.classList.toggle('show');
|
||||
const closer = function(e) {
|
||||
if (!e.target.closest('.multi-select-dropdown')) {
|
||||
menu.classList.remove('show');
|
||||
document.removeEventListener('click', closer);
|
||||
}
|
||||
};
|
||||
setTimeout(() => document.addEventListener('click', closer), 0);
|
||||
}
|
||||
|
||||
function toggleCheckbox(e, element) {
|
||||
if (e.target.tagName === 'INPUT') return;
|
||||
const cb = element.querySelector('input[type="checkbox"]');
|
||||
if(cb) {
|
||||
cb.checked = !cb.checked;
|
||||
cb.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
|
||||
function handleAnyOption(id, anyCb) {
|
||||
if (anyCb.checked) {
|
||||
document.querySelectorAll('.' + id + '-checkbox:not(.any-option)').forEach(cb => cb.checked = false);
|
||||
}
|
||||
updateMultiSelectDisplay(id);
|
||||
}
|
||||
|
||||
function updateMultiSelectDisplay(id) {
|
||||
const checkboxes = document.querySelectorAll('.' + id + '-checkbox');
|
||||
const btn = document.getElementById(id + '-btn');
|
||||
if(!btn) return;
|
||||
const anyOption = document.querySelector('.' + id + '-checkbox.any-option');
|
||||
const selected = [];
|
||||
let hasSelection = false;
|
||||
|
||||
checkboxes.forEach(cb => {
|
||||
if (cb.checked && !cb.classList.contains('any-option')) {
|
||||
selected.push(cb.dataset.label);
|
||||
hasSelection = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasSelection && anyOption) anyOption.checked = false;
|
||||
|
||||
if (selected.length === 0) {
|
||||
btn.innerHTML = 'N\'importe laquelle <i class="fa-solid fa-chevron-down"></i>';
|
||||
} else {
|
||||
if (selected.length > 2) {
|
||||
btn.innerHTML = selected.length + ' sélectionné(s) <i class="fa-solid fa-chevron-down"></i>';
|
||||
} else {
|
||||
btn.innerHTML = selected.join(', ') + ' <i class="fa-solid fa-chevron-down"></i>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectAllMultiSelect(id, selectAll) {
|
||||
document.querySelectorAll('.' + id + '-checkbox').forEach(cb => {
|
||||
if (cb.classList.contains('any-option')) {
|
||||
cb.checked = !selectAll;
|
||||
} else {
|
||||
cb.checked = selectAll;
|
||||
}
|
||||
});
|
||||
updateMultiSelectDisplay(id);
|
||||
}
|
||||
EOD;
|
||||
|
||||
if (strpos($content, 'function toggleMultiSelect') === false) {
|
||||
$content = str_replace('// --- LOOTBOX SYSTEM ---', $js_additions . "\n\n" . ' // --- LOOTBOX SYSTEM ---', $content);
|
||||
}
|
||||
|
||||
// Re-do the editRule replacement more carefully
|
||||
$content = preg_replace('/document\.getElementById\(\'rule_orb_op\'\)\.value = data\.orbital_count_op \|\| \"\";.*document\.getElementById\(\'rule_empty\'\)\.checked = data\.is_empty_case == 1;/s',
|
||||
'document.getElementById(\'rule_orb_op\').value = data.orbital_count_op || "";
|
||||
document.getElementById(\'rule_orb_val\').value = data.orbital_count_val !== null ? data.orbital_count_val : "";
|
||||
document.getElementById(\'rule_terr_op\').value = data.terrestrial_count_op || "";
|
||||
document.getElementById(\'rule_terr_val\').value = data.terrestrial_count_val !== null ? data.terrestrial_count_val : "";
|
||||
|
||||
// Populate Multi-selects
|
||||
const orbVals = (data.orbital_dominance || "").split(",");
|
||||
document.querySelectorAll(\'.orb-factions-checkbox\').forEach(cb => {
|
||||
cb.checked = orbVals.includes(cb.value);
|
||||
});
|
||||
const anyOrb = document.querySelector(\'.orb-factions-checkbox.any-option\');
|
||||
if (anyOrb && (orbVals.length === 0 || orbVals[0] === "")) anyOrb.checked = true;
|
||||
updateMultiSelectDisplay(\'orb-factions\');
|
||||
|
||||
const terrVals = (data.terrestrial_dominance || "").split(",");
|
||||
document.querySelectorAll(\'.terr-factions-checkbox\').forEach(cb => {
|
||||
cb.checked = terrVals.includes(cb.value);
|
||||
});
|
||||
const anyTerr = document.querySelector(\'.terr-factions-checkbox.any-option\');
|
||||
if (anyTerr && (terrVals.length === 0 || terrVals[0] === "")) anyTerr.checked = true;
|
||||
updateMultiSelectDisplay(\'terr-factions\');
|
||||
|
||||
document.getElementById(\'rule_empty\').checked = data.is_empty_case == 1;', $content);
|
||||
|
||||
$content = str_replace('document.getElementById(\'ruleForm\').reset(); document.getElementById(\'rule_id\').value = 0;',
|
||||
'document.getElementById(\'ruleForm\').reset();
|
||||
document.getElementById(\'rule_id\').value = 0;
|
||||
selectAllMultiSelect(\'orb-factions\', false);
|
||||
selectAllMultiSelect(\'terr-factions\', false);
|
||||
const anyOrbForm = document.querySelector(\'.orb-factions-checkbox.any-option\');
|
||||
if(anyOrbForm) anyOrbForm.checked = true;
|
||||
const anyTerrForm = document.querySelector(\'.terr-factions-checkbox.any-option\');
|
||||
if(anyTerrForm) anyTerrForm.checked = true;
|
||||
updateMultiSelectDisplay(\'orb-factions\');
|
||||
updateMultiSelectDisplay(\'terr-factions\');', $content);
|
||||
|
||||
// Final UI swap (Manual block replace to be safe)
|
||||
// I'll search for specific markers in UI
|
||||
$start_marker = '<div style="flex: 0 0 180px; font-size: 11px; color: #88c0d0; font-weight: bold; padding-top: 5px;">FILTRE DOMINANCE :</div>';
|
||||
$end_marker = '<label for="rule_diff" style="margin-bottom: 0; color: #a3be8c; font-size: 11px;">Dominante orbite ≠ Dominante sol</label>
|
||||
</div>
|
||||
</div>';
|
||||
|
||||
// Find the parent containers
|
||||
// I'll just use the preg_replace on handler and table as they worked.
|
||||
// For UI I will use a very specific string replace of the whole block.
|
||||
|
||||
file_put_contents($admin_path, $content);
|
||||
echo "Admin patched successfully.";
|
||||
@ -1,240 +0,0 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
$db = db();
|
||||
|
||||
// Update Handler
|
||||
$handler_code = <<<'PHP'
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'upsert_status_rule') {
|
||||
$id = (int)$_POST['id'];
|
||||
$name = $_POST['name'];
|
||||
$status_id = (int)$_POST['status_id'];
|
||||
$profile_id = (int)$_POST['profile_id'];
|
||||
$priority = (int)$_POST['priority'];
|
||||
|
||||
$orbital_count_op = $_POST['orbital_count_op'] ?: null;
|
||||
$orbital_count_val = $_POST['orbital_count_val'] !== '' ? (int)$_POST['orbital_count_val'] : null;
|
||||
$terrestrial_count_op = $_POST['terrestrial_count_op'] ?: null;
|
||||
$terrestrial_count_val = $_POST['terrestrial_count_val'] !== '' ? (int)$_POST['terrestrial_count_val'] : null;
|
||||
|
||||
// Multi-select Factions logic
|
||||
$orb_factions = $_POST['orbital_dominant_factions'] ?? [];
|
||||
$terr_factions = $_POST['ground_dominant_factions'] ?? [];
|
||||
|
||||
// If "any" is in the list, we clear the list to mean "no filter"
|
||||
if (in_array('any', $orb_factions)) $orb_factions = [];
|
||||
if (in_array('any', $terr_factions)) $terr_factions = [];
|
||||
|
||||
$orbital_dominant_factions = !empty($orb_factions) ? implode(',', $orb_factions) : null;
|
||||
$ground_dominant_factions = !empty($terr_factions) ? implode(',', $terr_factions) : null;
|
||||
|
||||
$is_empty_case = isset($_POST['is_empty_case']) ? 1 : 0;
|
||||
$dominance_diff_required = isset($_POST['dominance_diff_required']) ? 1 : 0;
|
||||
|
||||
if ($id > 0) {
|
||||
$stmt = $db->prepare("UPDATE celestial_object_status_rules SET name = ?, status_id = ?, profile_id = ?, priority = ?, orbital_count_op = ?, orbital_count_val = ?, terrestrial_count_op = ?, terrestrial_count_val = ?, orbital_dominant_factions = ?, ground_dominant_factions = ?, is_empty_case = ?, dominance_diff_required = ? WHERE id = ?");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominant_factions, $ground_dominant_factions, $is_empty_case, $dominance_diff_required, $id]);
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO celestial_object_status_rules (name, status_id, profile_id, priority, orbital_count_op, orbital_count_val, terrestrial_count_op, terrestrial_count_val, orbital_dominant_factions, ground_dominant_factions, is_empty_case, dominance_diff_required) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$name, $status_id, $profile_id, $priority, $orbital_count_op, $orbital_count_val, $terrestrial_count_op, $terrestrial_count_val, $orbital_dominant_factions, $ground_dominant_factions, $is_empty_case, $dominance_diff_required]);
|
||||
}
|
||||
header("Location: admin.php?tab=statuses&success=1");
|
||||
exit;
|
||||
}
|
||||
PHP;
|
||||
|
||||
// Update UI
|
||||
$new_ui = <<<'HTML'
|
||||
<div style="display: flex; gap: 15px; align-items: flex-start; margin-bottom: 10px;">
|
||||
<div style="flex: 0 0 180px; font-size: 11px; color: #88c0d0; font-weight: bold; padding-top: 5px;">FILTRE DOMINANCE :</div>
|
||||
|
||||
<!-- ORBITAL MULTI-SELECT -->
|
||||
<div class="form-group" style="flex: 1; margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">En Orbite</label>
|
||||
<div class="multi-select-dropdown" id="orb_ms">
|
||||
<div class="multi-select-btn" id="orb_btn" onclick="toggleMS('orb')">N'importe laquelle <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i></div>
|
||||
<div class="multi-select-menu" id="orb_menu">
|
||||
<div class="multi-select-header">
|
||||
<button type="button" onclick="msAll('orb', true)">Tout sélectionner</button>
|
||||
<button type="button" onclick="msAll('orb', false)">Tout désélectionner</button>
|
||||
</div>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="any" id="orb_any" checked onchange="handleMSChange(this, 'orb', true)">
|
||||
<span>N'importe laquelle</span>
|
||||
</label>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="none" class="orb-cb" data-name="Aucune" onchange="handleMSChange(this, 'orb', false)">
|
||||
<span>Aucune (Vide)</span>
|
||||
</label>
|
||||
<hr style="border:0; border-top:1px solid #334155; margin: 5px 0;">
|
||||
<?php foreach($factions_list as $f): ?>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="orbital_dominant_factions[]" value="<?php echo $f['id']; ?>" class="orb-cb" data-name="<?php echo htmlspecialchars($f['name']); ?>" onchange="handleMSChange(this, 'orb', false)">
|
||||
<span><?php echo htmlspecialchars($f['name']); ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GROUND MULTI-SELECT -->
|
||||
<div class="form-group" style="flex: 1; margin-bottom: 0;">
|
||||
<label style="font-size: 10px;">Au Sol</label>
|
||||
<div class="multi-select-dropdown" id="terr_ms">
|
||||
<div class="multi-select-btn" id="terr_btn" onclick="toggleMS('terr')">N'importe laquelle <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i></div>
|
||||
<div class="multi-select-menu" id="terr_menu">
|
||||
<div class="multi-select-header">
|
||||
<button type="button" onclick="msAll('terr', true)">Tout sélectionner</button>
|
||||
<button type="button" onclick="msAll('terr', false)">Tout désélectionner</button>
|
||||
</div>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="any" id="terr_any" checked onchange="handleMSChange(this, 'terr', true)">
|
||||
<span>N'importe laquelle</span>
|
||||
</label>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="none" class="terr-cb" data-name="Aucune" onchange="handleMSChange(this, 'terr', false)">
|
||||
<span>Aucune (Vide)</span>
|
||||
</label>
|
||||
<hr style="border:0; border-top:1px solid #334155; margin: 5px 0;">
|
||||
<?php foreach($factions_list as $f): ?>
|
||||
<label class="multi-select-option">
|
||||
<input type="checkbox" name="ground_dominant_factions[]" value="<?php echo $f['id']; ?>" class="terr-cb" data-name="<?php echo htmlspecialchars($f['name']); ?>" onchange="handleMSChange(this, 'terr', false)">
|
||||
<span><?php echo htmlspecialchars($f['name']); ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
// Update JS
|
||||
$js_code = <<<'JS'
|
||||
function toggleMS(id) {
|
||||
const menu = document.getElementById(id + '_menu');
|
||||
const isVisible = menu.classList.contains('show');
|
||||
document.querySelectorAll('.multi-select-menu').forEach(m => m.classList.remove('show'));
|
||||
if (!isVisible) menu.classList.add('show');
|
||||
}
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.multi-select-dropdown')) {
|
||||
document.querySelectorAll('.multi-select-menu').forEach(m => m.classList.remove('show'));
|
||||
}
|
||||
});
|
||||
function updateMSLabel(prefix) {
|
||||
const any = document.getElementById(prefix + '_any');
|
||||
const cbs = document.querySelectorAll('.' + prefix + '-cb:checked');
|
||||
const btn = document.getElementById(prefix + '_btn');
|
||||
if (any && any.checked) {
|
||||
btn.innerHTML = 'N\'importe laquelle <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i>';
|
||||
} else if (cbs.length === 0) {
|
||||
if(any) any.checked = true;
|
||||
btn.innerHTML = 'N\'importe laquelle <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i>';
|
||||
} else {
|
||||
const names = Array.from(cbs).map(c => c.dataset.name);
|
||||
if (names.length > 2) btn.innerHTML = names.length + ' sélectionnés <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i>';
|
||||
else btn.innerHTML = names.join(', ') + ' <i class="fa-solid fa-chevron-down" style="font-size: 10px;"></i>';
|
||||
}
|
||||
}
|
||||
function handleMSChange(cb, prefix, isAny) {
|
||||
const any = document.getElementById(prefix + '_any');
|
||||
const others = document.querySelectorAll('.' + prefix + '-cb');
|
||||
if (isAny && cb.checked) {
|
||||
others.forEach(o => o.checked = false);
|
||||
} else if (!isAny && cb.checked) {
|
||||
if(any) any.checked = false;
|
||||
}
|
||||
updateMSLabel(prefix);
|
||||
}
|
||||
function msAll(prefix, state) {
|
||||
const any = document.getElementById(prefix + '_any');
|
||||
const others = document.querySelectorAll('.' + prefix + '-cb');
|
||||
if (state) {
|
||||
if(any) any.checked = false;
|
||||
others.forEach(o => o.checked = true);
|
||||
} else {
|
||||
others.forEach(o => o.checked = false);
|
||||
if(any) any.checked = true;
|
||||
}
|
||||
updateMSLabel(prefix);
|
||||
}
|
||||
|
||||
function editRule(data) {
|
||||
document.getElementById('rule_id').value = data.id;
|
||||
document.getElementById('rule_name').value = data.name;
|
||||
document.getElementById('rule_profile_id').value = data.profile_id || "";
|
||||
document.getElementById('rule_status_id').value = data.status_id;
|
||||
document.getElementById('rule_priority').value = data.priority || 0;
|
||||
document.getElementById('rule_orb_op').value = data.orbital_count_op || "";
|
||||
document.getElementById('rule_orb_val').value = data.orbital_count_val !== null ? data.orbital_count_val : "";
|
||||
document.getElementById('rule_terr_op').value = data.terrestrial_count_op || "";
|
||||
document.getElementById('rule_terr_val').value = data.terrestrial_count_val !== null ? data.terrestrial_count_val : "";
|
||||
|
||||
// Orbital Multi-select
|
||||
const orbFactions = (data.orbital_dominant_factions || "").split(',').filter(x => x);
|
||||
msAll('orb', false);
|
||||
if (orbFactions.length === 0) {
|
||||
document.getElementById('orb_any').checked = true;
|
||||
} else {
|
||||
document.getElementById('orb_any').checked = false;
|
||||
orbFactions.forEach(val => {
|
||||
const cb = document.querySelector(`.orb-cb[value="${val}"]`);
|
||||
if(cb) cb.checked = true;
|
||||
});
|
||||
}
|
||||
updateMSLabel('orb');
|
||||
|
||||
// Ground Multi-select
|
||||
const terrFactions = (data.ground_dominant_factions || "").split(',').filter(x => x);
|
||||
msAll('terr', false);
|
||||
if (terrFactions.length === 0) {
|
||||
document.getElementById('terr_any').checked = true;
|
||||
} else {
|
||||
document.getElementById('terr_any').checked = false;
|
||||
terrFactions.forEach(val => {
|
||||
const cb = document.querySelector(`.terr-cb[value="${val}"]`);
|
||||
if(cb) cb.checked = true;
|
||||
});
|
||||
}
|
||||
updateMSLabel('terr');
|
||||
|
||||
document.getElementById('rule_empty').checked = data.is_empty_case == 1;
|
||||
document.getElementById('rule_diff').checked = data.dominance_diff_required == 1;
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
|
||||
function resetRuleForm() {
|
||||
document.getElementById('ruleForm').reset();
|
||||
document.getElementById('rule_id').value = 0;
|
||||
msAll('orb', false);
|
||||
msAll('terr', false);
|
||||
}
|
||||
JS;
|
||||
|
||||
// Apply changes to admin.php
|
||||
$content = file_get_contents('admin.php');
|
||||
|
||||
// Handler
|
||||
$content = preg_replace('/if \(\$_SERVER\[\'REQUEST_METHOD\'\] === \'POST\' && isset\(\$_POST\[\'action\'\]\) && \$_POST\[\'action\'\] === \'upsert_status_rule\'\) \{.*?header\(\"Location: admin\.php\?tab=statuses&success=1\"\);\n exit;/s', $handler_code, $content);
|
||||
|
||||
// UI
|
||||
$content = preg_replace('/<div style=\"display: flex; gap: 15px; align-items: flex-start; margin-bottom: 10px;\">.*?FILTRE DOMINANCE :.*?Cas \"CASE VIDE\".*?<\/div>.*?<\/div>/s', $new_ui . "\n" . ' <div style="display: flex; align-items: center; gap: 20px; padding-top: 10px; border-top: 1px solid #334155;">
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<input type="checkbox" name="is_empty_case" id="rule_empty" style="width: auto;">
|
||||
<label for="rule_empty" style="margin-bottom: 0; color: #ebcb8b; font-size: 11px;">Cas "CASE VIDE"</label>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<input type="checkbox" name="dominance_diff_required" id="rule_diff" style="width: auto;">
|
||||
<label for="rule_diff" style="margin-bottom: 0; color: #a3be8c; font-size: 11px;">Dominante orbite ≠ Dominante sol</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>', $content);
|
||||
|
||||
// JS
|
||||
$content = preg_replace('/function editRule\(data\) \{.*?function resetSettlementTypeForm\(\) \{.*?\}/s', $js_code . "\n\n function editSettlementType(data) {\n document.getElementById('set_t_id').value = data.id;\n document.getElementById('set_t_name').value = data.name;\n document.getElementById('set_t_slug').value = data.slug;\n document.getElementById('set_t_desc').value = data.description;\n window.scrollTo(0,0);\n }\n function resetSettlementTypeForm() { document.getElementById('settlementTypeForm').reset(); document.getElementById('set_t_id').value = 0; }", $content);
|
||||
|
||||
// Table Display - use preg_quote for exact matches or simplified regex
|
||||
$content = preg_replace('/if\(\$r\[\'orbital_dominance_mode\'\] !== \'ANY\'\) \$conds\[\] = \"Orbital \" \. \$r\[\'orbital_dominance_mode\'\] \. \" \\\[\.\.\.\\\]\";/s', 'if($r[\'orbital_dominant_factions\']) $conds[] = "Orbital IN (" . $r[\'orbital_dominant_factions\'] . ")";', $content);
|
||||
$content = preg_replace('/if\(\$r\[\'terrestrial_dominance_mode\'\] !== \'ANY\'\) \$conds\[\] = \"Ground \" \. \$r\[\'terrestrial_dominance_mode\'\] \. \" \\\[\.\.\.\\\]\";/s', 'if($r[\'ground_dominant_factions\']) $conds[] = "Ground IN (" . $r[\'ground_dominant_factions\'] . ")";', $content);
|
||||
|
||||
file_put_contents('admin.php', $content);
|
||||
echo "admin.php updated.\n";
|
||||
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
$file = 'admin.php';
|
||||
$content = file_get_contents($file);
|
||||
|
||||
$oldLogic = ' $orbital_dominance = $_POST[\'orbital_dominance\'] ?: null;
|
||||
$terrestrial_dominance = $_POST[\'terrestrial_dominance\'] ?: null;';
|
||||
|
||||
$newLogic = <<<'EOD'
|
||||
$orbital_dominance = isset($_POST['orbital_dominance']) ? implode(',', (array)$_POST['orbital_dominance']) : null;
|
||||
$terrestrial_dominance = isset($_POST['terrestrial_dominance']) ? implode(',', (array)$_POST['terrestrial_dominance']) : null;
|
||||
EOD;
|
||||
|
||||
$content = str_replace($oldLogic, $newLogic, $content);
|
||||
|
||||
file_put_contents($file, $content);
|
||||
echo "Handler patched";
|
||||
?>
|
||||
Loading…
x
Reference in New Issue
Block a user