diff --git a/admin.php b/admin.php index 8a114a6..0809218 100644 --- a/admin.php +++ b/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(); ?> @@ -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; } @@ -835,6 +912,7 @@ if ($tab === 'users') { Factions Ressources Lootboxes + Unité @@ -870,6 +948,153 @@ if ($tab === 'users') { + +

Gestion des Unités

+
+

Ajouter / Modifier une Unité

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
Cliquez sur les cases pour définir la forme de l'unité (5x10).
+ +
+
+ +
+ +
+
+
Action
+
Ressource
+
Quantité
+
+
+
+ +
+ +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ImageNom / SlugFactionPropriétésRécompensesActions
Aucune unité configurée.
+ + + +
+ +
+ +
+
+ +
+ + + + + Pts/Coup:
+ ● Destructible
+ ● Capturable +
+ 0): ?>Destr: + pts
+ 0): ?>Capt: + pts
+ + + : + +
+ +
+ + Suppr +

Gestion des Niveaux

@@ -997,6 +1222,7 @@ if ($tab === 'users') { + @@ -1861,7 +2087,7 @@ if ($tab === 'users') { - +
Visuel Nom Slug Type " style="width:40px;"> @@ -1891,7 +2117,6 @@ if ($tab === 'users') { -
@@ -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 = ''; + + resOptions += ''; + + + row.innerHTML = ` + + + +
×
+ `; + container.appendChild(row); + } + + function resetUnitForm() { + document.getElementById('unitForm').reset(); + document.getElementById('unit_id').value = 0; + setUnitGridFromData(""); + document.getElementById('unitRewardsContainer').innerHTML = '
Action
Ressource
Quantité
'; + } + + 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() { \ No newline at end of file diff --git a/db/migrate_units.php b/db/migrate_units.php new file mode 100644 index 0000000..050360a --- /dev/null +++ b/db/migrate_units.php @@ -0,0 +1,36 @@ +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"); +} + diff --git a/fix_admin.py b/fix_admin.py new file mode 100644 index 0000000..bf3b855 --- /dev/null +++ b/fix_admin.py @@ -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'', '', content, flags=re.DOTALL) + content = content.replace('', '') + + # Define the full script content + script_content = r""" + diff --git a/fix_admin_mini.py b/fix_admin_mini.py new file mode 100644 index 0000000..99c8715 --- /dev/null +++ b/fix_admin_mini.py @@ -0,0 +1,21 @@ +import re +with open('admin.php', 'r') as f: content = f.read() +content = re.sub(r'', '', content, flags=re.DOTALL) +content = content.replace('', '') +js = """ + diff --git a/fix_admin_v3.py b/fix_admin_v3.py new file mode 100644 index 0000000..2dce43b --- /dev/null +++ b/fix_admin_v3.py @@ -0,0 +1,5 @@ +import re +with open('admin.php', 'r') as f: content = f.read() +content = re.sub(r'', '', content, flags=re.DOTALL) +content = content.replace('', '') +js = "" with open('admin.php', 'w') as f: f.write(content.replace('', js + '\n')) diff --git a/patch_admin_final.php b/patch_admin_final.php deleted file mode 100644 index 40b32e2..0000000 --- a/patch_admin_final.php +++ /dev/null @@ -1,155 +0,0 @@ - 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 = '
'; -$ui_block_end = ''; - -$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' -
-
- - -
-
EN ORBITE
- -
- -
- - -
-
- -
- -
-
Toutes / Peu importe
-
- - - - -
-
-
-
- - -
- - -
(Orbital) [?] (Sol)
-
- - -
-
AU SOL
- -
- -
- - -
-
- -
- -
-
Toutes / Peu importe
-
- - - - -
-
-
-
-
- -
- - -
-
- - -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"; -?> diff --git a/patch_admin_minimal.php b/patch_admin_minimal.php deleted file mode 100644 index 3f3bf29..0000000 --- a/patch_admin_minimal.php +++ /dev/null @@ -1,285 +0,0 @@ -', $css . ' ', $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' -
-
FACTION DOMINANTE :
-
- -
-
- N'importe laquelle -
-
-
- - -
-
- - N'importe laquelle -
-
- - Aucune (Vide) -
-
- - Joueur (Terrien) -
-
- 2): ?> -
- - -
- -
-
-
-
- -
-
- N'importe laquelle -
-
-
- - -
-
- - N'importe laquelle -
-
- - Aucune (Vide) -
-
- - Joueur (Terrien) -
-
- 2): ?> -
- - -
- -
-
-
-
- -
-
- - -
-
-EOD; - -// Need to match exactly the old UI to replace it -$old_ui_regex = '/
.*?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 '; - } else { - if (selected.length > 2) { - btn.innerHTML = selected.length + ' sélectionné(s) '; - } else { - btn.innerHTML = selected.join(', ') + ' '; - } - } - } - - 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 = '
FILTRE DOMINANCE :
'; -$end_marker = ' -
-
'; - -// 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."; diff --git a/patch_admin_v4.php b/patch_admin_v4.php deleted file mode 100644 index b06bda1..0000000 --- a/patch_admin_v4.php +++ /dev/null @@ -1,240 +0,0 @@ - 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' -
-
FILTRE DOMINANCE :
- - -
- -
-
N'importe laquelle
-
-
- - -
- - -
- - - -
-
-
- - -
- -
-
N'importe laquelle
-
-
- - -
- - -
- - - -
-
-
-
-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 '; - } else if (cbs.length === 0) { - if(any) any.checked = true; - btn.innerHTML = 'N\'importe laquelle '; - } else { - const names = Array.from(cbs).map(c => c.dataset.name); - if (names.length > 2) btn.innerHTML = names.length + ' sélectionnés '; - else btn.innerHTML = names.join(', ') + ' '; - } - } - 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('/
.*?FILTRE DOMINANCE :.*?Cas \"CASE VIDE\".*?<\/div>.*?<\/div>/s', $new_ui . "\n" . '
-
- - -
-
- - -
-
-
', $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"; \ No newline at end of file diff --git a/patch_handler_v2.php b/patch_handler_v2.php deleted file mode 100644 index 2deb70c..0000000 --- a/patch_handler_v2.php +++ /dev/null @@ -1,17 +0,0 @@ - \ No newline at end of file