708 lines
25 KiB
PHP
708 lines
25 KiB
PHP
<?php
|
||
require_once __DIR__ . '/db/auth.php';
|
||
require_once __DIR__ . '/db/config.php';
|
||
|
||
function index_scan_normalize_rarity(?string $rarity): string
|
||
{
|
||
return strtoupper(trim((string) $rarity));
|
||
}
|
||
|
||
function index_scan_rarity_class(?string $rarity): string
|
||
{
|
||
return match (index_scan_normalize_rarity($rarity)) {
|
||
'L' => 'scan-rarity-L',
|
||
'E' => 'scan-rarity-E',
|
||
'R' => 'scan-rarity-R',
|
||
'U' => 'scan-rarity-U',
|
||
'C' => 'scan-rarity-C',
|
||
default => 'scan-rarity-none',
|
||
};
|
||
}
|
||
|
||
function index_scan_rarity_label(?string $rarity): string
|
||
{
|
||
return match (index_scan_normalize_rarity($rarity)) {
|
||
'L' => 'Légendaire',
|
||
'E' => 'Épique',
|
||
'R' => 'Rare',
|
||
'U' => 'Peu commun',
|
||
'C' => 'Commun',
|
||
default => 'Non définie',
|
||
};
|
||
}
|
||
|
||
auth_start_session();
|
||
auth_bootstrap();
|
||
|
||
$session_cl_auth_user = isset($_SESSION['user']) ? (string) $_SESSION['user'] : '';
|
||
$session_cl_auth_right = isset($_SESSION['role']) ? (string) $_SESSION['role'] : '';
|
||
$is_authenticated = $session_cl_auth_user !== '';
|
||
|
||
$scan_reference_rows = [];
|
||
$scan_reference_max_occurrence = 0;
|
||
$scan_reference_error = null;
|
||
|
||
try {
|
||
$db = db();
|
||
$stmt_scan_reference = $db->query(
|
||
"SELECT o.cl_scobjs_id, o.cl_scobjs_name, o.cl_scobjs_rarity, m.cl_scmining_scan_value, m.cl_scmining_max_occurrence,
|
||
m.cl_scmining_can_manual, m.cl_scmining_can_land, m.cl_scmining_can_space
|
||
FROM tbl_scmining m
|
||
INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = m.cl_scmining_obj_id
|
||
ORDER BY
|
||
CASE UPPER(COALESCE(o.cl_scobjs_rarity, ''))
|
||
WHEN 'L' THEN 1
|
||
WHEN 'E' THEN 2
|
||
WHEN 'R' THEN 3
|
||
WHEN 'U' THEN 4
|
||
WHEN 'C' THEN 5
|
||
ELSE 6
|
||
END,
|
||
o.cl_scobjs_name ASC"
|
||
);
|
||
|
||
foreach ($stmt_scan_reference->fetchAll() as $row) {
|
||
$occurrence_count = max(1, (int) ($row['cl_scmining_max_occurrence'] ?? 1));
|
||
$scan_value = (int) ($row['cl_scmining_scan_value'] ?? 0);
|
||
$recovery_modes = [];
|
||
|
||
if (!empty($row['cl_scmining_can_manual'])) {
|
||
$recovery_modes[] = 'Manuel';
|
||
}
|
||
if (!empty($row['cl_scmining_can_land'])) {
|
||
$recovery_modes[] = 'Terrestre';
|
||
}
|
||
if (!empty($row['cl_scmining_can_space'])) {
|
||
$recovery_modes[] = 'Spatial';
|
||
}
|
||
|
||
$scan_steps = [];
|
||
for ($i = 1; $i <= $occurrence_count; $i++) {
|
||
$scan_steps[] = $scan_value * $i;
|
||
}
|
||
|
||
$scan_reference_rows[] = [
|
||
'id' => (string) ($row['cl_scobjs_id'] ?? ''),
|
||
'name' => (string) ($row['cl_scobjs_name'] ?? ''),
|
||
'rarity' => index_scan_normalize_rarity($row['cl_scobjs_rarity'] ?? ''),
|
||
'rarity_label' => index_scan_rarity_label($row['cl_scobjs_rarity'] ?? ''),
|
||
'rarity_class' => index_scan_rarity_class($row['cl_scobjs_rarity'] ?? ''),
|
||
'recovery_modes' => $recovery_modes,
|
||
'scan_steps' => $scan_steps,
|
||
'max_occurrence' => $occurrence_count,
|
||
];
|
||
|
||
$scan_reference_max_occurrence = max($scan_reference_max_occurrence, $occurrence_count);
|
||
}
|
||
} catch (Throwable $e) {
|
||
$scan_reference_error = 'Impossible de charger le tableau des signatures de scan pour le moment.';
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="keywords" content="BlackOps Agency, Star Citizen, Advocacy, UEE, Sécurité, Exploration, Renseignement, Patrouilles, Chasses de primes, Investigation, Neutralisation de menaces, Assistance humanitaire, Abordages, Réseaux anti-toxicité, Formation tactique, Entraînements, Coopération, Zones UEE, Systèmes inexplorés, Lore Star Citizen, Missions multi-joueurs, Protocole Arkange, Protocole Vigilance, Respect des lois impériales, Justice interstellaire, Criminalité galactique, Piraterie, XenoThreat, Vanduul, Sécurité spatiale, Leadership BlackOps, Collaboration stratégique, Combat spatial, Star Citizen gameplay, Exploration stratégique, Missions BlackOps Agency, Réputation UEE, Gestion des conflits, BlackOps, Agency, Recrutement Star Citizen, Zones de guerre, Star Citizen immersion.">
|
||
|
||
<title>Rapid Emergency & Action Combat Team / Star Citizen</title>
|
||
|
||
<link rel="stylesheet" type="text/css" href="css/styles.css">
|
||
<link rel="stylesheet" type="text/css" href="css/default.css" />
|
||
<link rel="stylesheet" type="text/css" href="css/component.css" />
|
||
<link rel="stylesheet" type="text/css" href="css/switch.css" />
|
||
<link rel="stylesheet" type="text/css" href="css/styles-modal.css" />
|
||
<script src="js/modernizr.custom.js"></script>
|
||
<style>
|
||
.modal-scan-reference {
|
||
width: 92%;
|
||
max-width: 1400px;
|
||
min-width: 960px;
|
||
}
|
||
|
||
.scan-reference-dialog {
|
||
background: linear-gradient(180deg, rgba(24, 28, 37, 0.98), rgba(11, 14, 20, 0.98));
|
||
border: 1px solid rgba(162, 155, 120, 0.35);
|
||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
.scan-reference-dialog h3 {
|
||
font-size: 1.8em;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
.scan-reference-dialog > div {
|
||
padding: 22px 26px 26px;
|
||
}
|
||
|
||
.scan-reference-intro,
|
||
.scan-reference-empty,
|
||
.scan-reference-error {
|
||
margin: 0 0 18px;
|
||
padding: 12px 14px !important;
|
||
border-radius: 10px;
|
||
font-size: 0.95em;
|
||
text-align: left !important;
|
||
}
|
||
|
||
.scan-reference-intro {
|
||
background: rgba(162, 155, 120, 0.12);
|
||
border: 1px solid rgba(162, 155, 120, 0.18);
|
||
}
|
||
|
||
.scan-reference-empty {
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||
}
|
||
|
||
.scan-reference-error {
|
||
background: rgba(140, 32, 32, 0.18);
|
||
border: 1px solid rgba(255, 88, 88, 0.25);
|
||
color: #ffbdbd;
|
||
}
|
||
|
||
.scan-reference-filter-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 14px;
|
||
margin: 0 0 14px;
|
||
padding: 10px 12px;
|
||
border: 1px solid rgba(162, 155, 120, 0.18);
|
||
border-radius: 10px;
|
||
background: rgba(162, 155, 120, 0.07);
|
||
}
|
||
|
||
.scan-reference-filter-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.scan-reference-filter-btn {
|
||
padding: 7px 12px;
|
||
border: 1px solid rgba(162, 155, 120, 0.35);
|
||
border-radius: 999px;
|
||
background: rgba(162, 155, 120, 0.14);
|
||
color: #f2eed9;
|
||
font-size: 0.60em;
|
||
font-weight: 700;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.scan-reference-filter-btn:hover,
|
||
.scan-reference-filter-btn:focus-visible {
|
||
background: rgba(162, 155, 120, 0.22);
|
||
outline: none;
|
||
}
|
||
|
||
.scan-reference-filter-btn.is-disabled {
|
||
opacity: 0.45;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.scan-reference-filter-status {
|
||
margin: 0;
|
||
font-size: 0.74em;
|
||
color: rgba(255, 255, 255, 0.72);
|
||
text-align: right;
|
||
}
|
||
|
||
.scan-reference-table-wrapper {
|
||
max-height: 65vh;
|
||
overflow: auto;
|
||
border: 1px solid rgba(162, 155, 120, 0.22);
|
||
border-radius: 12px;
|
||
background: rgba(6, 9, 14, 0.65);
|
||
}
|
||
|
||
.scan-reference-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
min-width: 880px;
|
||
font-size: 0.84em;
|
||
}
|
||
|
||
.scan-reference-table th,
|
||
.scan-reference-table td {
|
||
padding: 9px 11px;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||
vertical-align: middle;
|
||
text-align: left;
|
||
}
|
||
|
||
.scan-reference-table th {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 2;
|
||
background: rgba(18, 22, 30, 0.96);
|
||
text-transform: uppercase;
|
||
font-size: 0.74em;
|
||
letter-spacing: 0.08em;
|
||
color: #d7cfac;
|
||
}
|
||
|
||
.scan-reference-table tbody tr {
|
||
cursor: pointer;
|
||
transition: background 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
|
||
}
|
||
|
||
.scan-reference-table tbody tr:hover {
|
||
background: rgba(162, 155, 120, 0.08);
|
||
}
|
||
|
||
.scan-reference-table tbody tr.is-selected {
|
||
background: rgba(162, 155, 120, 0.16);
|
||
box-shadow: inset 0 0 0 1px rgba(162, 155, 120, 0.35);
|
||
}
|
||
|
||
.scan-reference-table tbody tr.is-hidden-by-filter {
|
||
display: none;
|
||
}
|
||
|
||
.scan-reference-name span {
|
||
display: block;
|
||
font-weight: 700;
|
||
font-size: 0.94em;
|
||
}
|
||
|
||
.scan-reference-recovery {
|
||
min-width: 180px;
|
||
}
|
||
|
||
.scan-reference-pill {
|
||
display: inline-block;
|
||
margin: 0 5px 5px 0;
|
||
padding: 4px 8px;
|
||
border-radius: 999px;
|
||
background: rgba(162, 155, 120, 0.16);
|
||
border: 1px solid rgba(162, 155, 120, 0.24);
|
||
font-size: 0.72em;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.scan-reference-value {
|
||
text-align: center;
|
||
font-variant-numeric: tabular-nums;
|
||
font-weight: 700;
|
||
font-size: 0.92em;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.scan-reference-muted {
|
||
color: rgba(255, 255, 255, 0.35);
|
||
}
|
||
|
||
.scan-rarity-L .scan-reference-name span,
|
||
.scan-rarity-L .scan-reference-value {
|
||
color: #ff8000;
|
||
}
|
||
|
||
.scan-rarity-E .scan-reference-name span,
|
||
.scan-rarity-E .scan-reference-value {
|
||
color: #a335ee;
|
||
}
|
||
|
||
.scan-rarity-R .scan-reference-name span,
|
||
.scan-rarity-R .scan-reference-value {
|
||
color: #4db2ff;
|
||
}
|
||
|
||
.scan-rarity-U .scan-reference-name span,
|
||
.scan-rarity-U .scan-reference-value {
|
||
color: #1eff00;
|
||
}
|
||
|
||
.scan-rarity-C .scan-reference-name span,
|
||
.scan-rarity-C .scan-reference-value {
|
||
color: #ffffff;
|
||
}
|
||
|
||
.scan-rarity-none .scan-reference-name span,
|
||
.scan-rarity-none .scan-reference-value {
|
||
color: #b5bcc8;
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.modal-scan-reference {
|
||
width: 96%;
|
||
min-width: 0;
|
||
}
|
||
|
||
.scan-reference-dialog h3 {
|
||
font-size: 1.2em;
|
||
}
|
||
|
||
.scan-reference-filter-bar {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.scan-reference-filter-status {
|
||
text-align: left;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="assets-div-menu">
|
||
<a href="#" class="md-trigger" data-modal="modal-ScanReference">Contenu à venir</a>
|
||
</div>
|
||
|
||
<div class="connexion-div-menu <?php echo $is_authenticated ? 'is-authenticated' : 'md-trigger'; ?>" data-login-label="Connexion" <?php echo $is_authenticated ? '' : 'data-modal="modal-Login"'; ?> id="accountPanel">
|
||
<span id="accountLabel"><?php echo htmlspecialchars($is_authenticated ? $session_cl_auth_user : 'Connexion', ENT_QUOTES, 'UTF-8'); ?></span>
|
||
<span class="connexion-actions" id="accountActions" <?php echo $is_authenticated ? '' : 'hidden'; ?>>
|
||
<a id="adminLink" href="admin.php" <?php echo $session_cl_auth_right === 'admin' ? '' : 'hidden'; ?>>Admin</a>
|
||
<a id="logoutLink" href="logout.php">Déconnexion</a>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="se-switch switch-center" role="group" aria-label="Choix entre FR et EN">
|
||
<a class="se-switch__btn is-active" href="index.php" data-site="se1" aria-current="page">🇫🇷</a>
|
||
<a class="se-switch__btn" href="index-en.php" data-site="se2">🇬🇧</a>
|
||
</div>
|
||
|
||
<div class="md-modal md-effect-1" id="modal-Login">
|
||
<div class="md-content">
|
||
<h3>
|
||
<img class="float-left" src="img/icon_bops.png" width="48" height="48" alt="" />
|
||
INTERFACE DE CONNEXION
|
||
<a class="frame-icon-close md-close float-right" href="#"><img src="img/icon_close.png" width="48" height="48" alt="" /></a>
|
||
</h3>
|
||
<div>
|
||
<p class="txt-center">Entrer vos identifiants pour acceder à l'espace sécurisé.*</p>
|
||
<form class="js-login-form" method="post" action="login.php">
|
||
<div>
|
||
<p class="txt-center"><input class="connexion-champ" id="idr" type="text" name="cl_auth_user" placeholder="RID" required /></p>
|
||
<p class="txt-center"><input class="connexion-champ" id="pwr" type="password" name="cl_auth_pass" placeholder="MOT DE PASSE" required /></p>
|
||
</div>
|
||
<div>
|
||
<p class="txt-center"><input class="connexion-bouton" type="submit" value="S'authentifier" /></p>
|
||
<p class="txt-center login-status" id="loginStatus" aria-live="polite"></p>
|
||
</div>
|
||
</form>
|
||
<p class="txt-center txt-s10">* Accès sous haute surveillance. En confirmant vos identifiants, vous acceptez les protocoles de sécurité de l'initiative R.E.A.C.T. Toute infraction aux protocoles est passible de sanctions.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="md-modal md-effect-1" id="modal-About">
|
||
<div class="md-content">
|
||
<h3>
|
||
<img class="float-left" src="img/icon_bops.png" width="48" height="48" alt="" />
|
||
EN SAVOIR PLUS
|
||
<a class="frame-icon-close md-close float-right" href="#"><img src="img/icon_close.png" width="48" height="48" alt="" /></a>
|
||
</h3>
|
||
<div>
|
||
<img class="float-left" src="img/fl_security.png" width="300" height="460" alt="" />
|
||
<p>La sécurité et la protection des intérêts impériaux sont des priorités absolues pour l’agence.</p>
|
||
<p>En tant que garante de l’ordre dans les zones sous juridiction de l’UEE, l’agence BOPS s'engage à prévenir, neutraliser et répondre efficacement à toutes les formes de menaces, qu'elles soient internes ou externes aux territoires de l'Empire.</p>
|
||
<p>Cette mission repose sur une approche combinant vigilance, réactivité et expertise tactique, afin d’assurer la stabilité, la sécurité des citoyens et le respect des lois impériales.</p>
|
||
<p>Chaque opération est conçue pour inspirer confiance aux populations locales tout en projetant une image de force et de discipline au sein de l’univers connu.</p>
|
||
<p class="ul-style">
|
||
— Surveillance active des secteurs critiques pour dissuader les menaces potentielles.</br>
|
||
— Protection rapprochée de convois, personnalités importantes ou cargaisons sensibles.</br>
|
||
— Neutralisation de vaisseaux hostiles ou suspects, avec récupération d’actifs stratégiques.</br>
|
||
— Ciblage et capture ou élimination de fugitifs dangereux, conformément aux lois impériales.</br>
|
||
— Protection des civils en détresse et aide aux infrastructures endommagées.</br>
|
||
— Collecte et analyse d’informations sur des activités suspectes, incidents ou organisations hostiles.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="md-modal md-effect-1 modal-scan-reference" id="modal-ScanReference">
|
||
<div class="md-content scan-reference-dialog">
|
||
<h3>
|
||
<img class="float-left" src="img/icon_bops.png" width="48" height="48" alt="" />
|
||
TABLEAU DES SIGNATURES DE SCAN
|
||
<a class="frame-icon-close md-close float-right" href="#"><img src="img/icon_close.png" width="48" height="48" alt="" /></a>
|
||
</h3>
|
||
<div>
|
||
|
||
<?php if ($scan_reference_error !== null): ?>
|
||
<p class="scan-reference-error"><?php echo htmlspecialchars($scan_reference_error, ENT_QUOTES, 'UTF-8'); ?></p>
|
||
<?php elseif ($scan_reference_rows === []): ?>
|
||
<p class="scan-reference-empty">Aucune donnée de scan n'est configurée pour le moment.</p>
|
||
<?php else: ?>
|
||
<div class="scan-reference-filter-bar">
|
||
<div class="scan-reference-filter-actions">
|
||
<button type="button" class="scan-reference-filter-btn" id="scanReferenceIsolateBtn">Isoler</button>
|
||
<button type="button" class="scan-reference-filter-btn" id="scanReferenceClearBtn">Supprimer le filtrage</button>
|
||
</div>
|
||
<p class="scan-reference-filter-status" id="scanReferenceFilterStatus">Clique sur les lignes à conserver puis sur « Isoler ».</p>
|
||
</div>
|
||
<div class="scan-reference-table-wrapper">
|
||
<table class="scan-reference-table" id="scanReferenceTable">
|
||
<thead>
|
||
<tr>
|
||
<th>Ressource</th>
|
||
<th>Récupérations</th>
|
||
<?php for ($occurrence = 1; $occurrence <= $scan_reference_max_occurrence; $occurrence++): ?>
|
||
<th>x <?php echo $occurrence; ?></th>
|
||
<?php endfor; ?>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($scan_reference_rows as $scan_reference_row): ?>
|
||
<tr class="scan-reference-row <?php echo htmlspecialchars($scan_reference_row['rarity_class'], ENT_QUOTES, 'UTF-8'); ?>" data-resource-id="<?php echo htmlspecialchars($scan_reference_row['id'], ENT_QUOTES, 'UTF-8'); ?>" data-resource-name="<?php echo htmlspecialchars($scan_reference_row['name'], ENT_QUOTES, 'UTF-8'); ?>">
|
||
<td class="scan-reference-name">
|
||
<span><?php echo htmlspecialchars($scan_reference_row['name'], ENT_QUOTES, 'UTF-8'); ?></span>
|
||
</td>
|
||
<td class="scan-reference-recovery">
|
||
<?php if ($scan_reference_row['recovery_modes'] !== []): ?>
|
||
<?php foreach ($scan_reference_row['recovery_modes'] as $recovery_mode): ?>
|
||
<span class="scan-reference-pill"><?php echo htmlspecialchars($recovery_mode, ENT_QUOTES, 'UTF-8'); ?></span>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<span class="scan-reference-muted">—</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<?php for ($occurrence = 1; $occurrence <= $scan_reference_max_occurrence; $occurrence++): ?>
|
||
<td class="scan-reference-value">
|
||
<?php echo array_key_exists($occurrence - 1, $scan_reference_row['scan_steps']) ? number_format((int) $scan_reference_row['scan_steps'][$occurrence - 1], 0, ',', ' ') : '<span class="scan-reference-muted">—</span>'; ?>
|
||
</td>
|
||
<?php endfor; ?>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="center-page-bops"></div>
|
||
|
||
<div class="center-div-menu">
|
||
<div class="padding50">
|
||
|
||
<p class="txt-center txt-bold txt-s40 small-caps padding25 txt-or">Rapid Emergency & Action Combat Team</p>
|
||
<!-- <p class="txt-center txt-bold txt-italic txt-s20 padding15 txt-or"><span class="padding5">SÉCURITÉ</span> —— <span class="padding5">INTELLIGENCE</span> —— <span class="padding5">SAUVETAGE</span></p> -->
|
||
<p class="txt-justify padding5">Fondée pour combattre la criminalité extrême à travers l’Univers, la R.E.A.C.T. est un label opérationnel indépendant. Nous unissons des pilotes dévoués de tous horizons pour neutraliser les menaces là où la loi fait défaut.</p>
|
||
<p class="txt-center txt-bold txt-s22 padding25 txt-or">—————— La R.E.A.C.T. n’est pas une organisation, mais un standard tactique ——————</p>
|
||
<p class="txt-justify padding5">C’est une initiative inter-organisations conçue pour les joueurs qui partagent la même vision : protéger les citoyens et les PNJs des entités hostiles. Porter l’insigne R.E.A.C.T. ne signifie pas quitter votre organisation ; cela signifie rejoindre un réseau d'intervention rapide.</p>
|
||
</div>
|
||
<div class="center-div-menu-flex txt-bold">
|
||
<div class="menu-item md-trigger" data-modal="modal-About"><a href="#">> EN SAVOIR PLUS <</a></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="black-filter"></div>
|
||
|
||
<!-- Vidéo de fond -->
|
||
<div class="video-container" aria-hidden="true">
|
||
<iframe
|
||
id="react-video"
|
||
src="https://www.youtube-nocookie.com/embed/tFDqWOqm1G8?controls=0&autoplay=1&mute=1&playsinline=1&loop=1&playlist=tFDqWOqm1G8&cc_load_policy=0&iv_load_policy=3&modestbranding=1&rel=0&enablejsapi=1"
|
||
title="Présentation R.E.A.C.T — YouTube"
|
||
loading="lazy"
|
||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen"
|
||
allowfullscreen
|
||
referrerpolicy="strict-origin-when-cross-origin">
|
||
</iframe>
|
||
</div>
|
||
|
||
<div class="md-overlay"></div><!-- the overlay element -->
|
||
|
||
<!-- classie.js by @desandro: https://github.com/desandro/classie -->
|
||
<script src="js/classie.js"></script>
|
||
<script src="js/modalEffects.js"></script>
|
||
<script src="js/auth.js"></script>
|
||
|
||
<!-- for the blur effect -->
|
||
<!-- by @derSchepp https://github.com/Schepp/CSS-Filters-Polyfill -->
|
||
<script>
|
||
// this is important for IEs
|
||
var polyfilter_scriptpath = '/js/';
|
||
</script>
|
||
<script src="js/cssParser.js"></script>
|
||
<script src="js/css-filters-polyfill.js"></script>
|
||
|
||
|
||
<script>
|
||
(function initScanReferenceFilter() {
|
||
const storageKey = 'scanReferenceIsolatedResources.v1';
|
||
const table = document.getElementById('scanReferenceTable');
|
||
const status = document.getElementById('scanReferenceFilterStatus');
|
||
const isolateButton = document.getElementById('scanReferenceIsolateBtn');
|
||
const clearButton = document.getElementById('scanReferenceClearBtn');
|
||
|
||
if (!table || !status || !isolateButton || !clearButton) {
|
||
return;
|
||
}
|
||
|
||
const rows = Array.from(table.querySelectorAll('.scan-reference-row'));
|
||
const selectedIds = new Set();
|
||
let activeFilterIds = [];
|
||
|
||
function saveFilter(ids) {
|
||
if (!Array.isArray(ids) || ids.length === 0) {
|
||
window.localStorage.removeItem(storageKey);
|
||
return;
|
||
}
|
||
|
||
window.localStorage.setItem(storageKey, JSON.stringify(ids));
|
||
}
|
||
|
||
function loadFilter() {
|
||
try {
|
||
const raw = window.localStorage.getItem(storageKey);
|
||
if (!raw) {
|
||
return [];
|
||
}
|
||
|
||
const parsed = JSON.parse(raw);
|
||
return Array.isArray(parsed) ? parsed.map(String).filter(Boolean) : [];
|
||
} catch (error) {
|
||
window.localStorage.removeItem(storageKey);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
function getVisibleCount() {
|
||
return rows.filter((row) => !row.classList.contains('is-hidden-by-filter')).length;
|
||
}
|
||
|
||
function refreshStatus() {
|
||
const selectedCount = selectedIds.size;
|
||
const visibleCount = getVisibleCount();
|
||
const totalCount = rows.length;
|
||
const filterIsActive = activeFilterIds.length > 0;
|
||
|
||
isolateButton.classList.toggle('is-disabled', selectedCount === 0);
|
||
isolateButton.disabled = selectedCount === 0;
|
||
clearButton.classList.toggle('is-disabled', !filterIsActive);
|
||
clearButton.disabled = !filterIsActive;
|
||
|
||
if (filterIsActive) {
|
||
status.textContent = 'Filtre actif : ' + visibleCount + ' ressource(s) affichée(s) sur ' + totalCount + '.';
|
||
return;
|
||
}
|
||
|
||
if (selectedCount > 0) {
|
||
status.textContent = selectedCount + ' ressource(s) sélectionnée(s). Clique sur « Isoler » pour n’afficher que celles-ci.';
|
||
return;
|
||
}
|
||
|
||
status.textContent = 'Clique sur les lignes à conserver puis sur « Isoler ».';
|
||
}
|
||
|
||
function applyFilter(ids) {
|
||
activeFilterIds = Array.isArray(ids) ? ids.map(String).filter(Boolean) : [];
|
||
const filterSet = new Set(activeFilterIds);
|
||
|
||
rows.forEach((row) => {
|
||
const rowId = String(row.dataset.resourceId || '');
|
||
const shouldHide = filterSet.size > 0 && !filterSet.has(rowId);
|
||
row.classList.toggle('is-hidden-by-filter', shouldHide);
|
||
});
|
||
|
||
refreshStatus();
|
||
}
|
||
|
||
function clearSelection() {
|
||
selectedIds.clear();
|
||
rows.forEach((row) => row.classList.remove('is-selected'));
|
||
refreshStatus();
|
||
}
|
||
|
||
rows.forEach((row) => {
|
||
row.addEventListener('click', function () {
|
||
const rowId = String(row.dataset.resourceId || '');
|
||
if (!rowId) {
|
||
return;
|
||
}
|
||
|
||
if (selectedIds.has(rowId)) {
|
||
selectedIds.delete(rowId);
|
||
row.classList.remove('is-selected');
|
||
} else {
|
||
selectedIds.add(rowId);
|
||
row.classList.add('is-selected');
|
||
}
|
||
|
||
refreshStatus();
|
||
});
|
||
});
|
||
|
||
isolateButton.addEventListener('click', function () {
|
||
if (selectedIds.size === 0) {
|
||
refreshStatus();
|
||
return;
|
||
}
|
||
|
||
const ids = Array.from(selectedIds);
|
||
saveFilter(ids);
|
||
applyFilter(ids);
|
||
clearSelection();
|
||
});
|
||
|
||
clearButton.addEventListener('click', function () {
|
||
saveFilter([]);
|
||
applyFilter([]);
|
||
});
|
||
|
||
|
||
applyFilter(loadFilter());
|
||
})();
|
||
</script>
|
||
|
||
<script>
|
||
// On ajoute dynamiquement l'origine à l'URL de l'iframe (recommandé par l'API YouTube)
|
||
(function attachOrigin(){
|
||
const iframe = document.getElementById('react-video');
|
||
const url = new URL(iframe.src);
|
||
if (!url.searchParams.has('origin')) {
|
||
url.searchParams.set('origin', window.location.origin);
|
||
iframe.src = url.toString();
|
||
}
|
||
})();
|
||
|
||
// Utilitaires pour parler au lecteur via postMessage (API YouTube)
|
||
function ytCommand(func, args = []) {
|
||
const iframe = document.getElementById('react-video');
|
||
if (!iframe || !iframe.contentWindow) return;
|
||
iframe.contentWindow.postMessage(JSON.stringify({ event: 'command', func, args }), '*');
|
||
}
|
||
|
||
// Au premier geste utilisateur : on remet le son et on met le volume à 50 %
|
||
function enableSoundOnce() {
|
||
ytCommand('unMute');
|
||
ytCommand('setVolume', [50]);
|
||
|
||
// Masquer le bouton
|
||
const btn = document.getElementById('unmute-btn');
|
||
if (btn) btn.style.display = 'none';
|
||
|
||
// Retirer les écouteurs pour ne pas répéter l’action
|
||
window.removeEventListener('pointerdown', enableSoundOnce);
|
||
window.removeEventListener('keydown', enableSoundOnce);
|
||
window.removeEventListener('touchstart', enableSoundOnce, { passive: true });
|
||
}
|
||
|
||
// Bouton dédié
|
||
// document.getElementById('unmute-btn').addEventListener('click', enableSoundOnce);
|
||
|
||
// …ou n’importe quel premier geste sur la page
|
||
//window.addEventListener('pointerdown', enableSoundOnce, { once: true });
|
||
//window.addEventListener('keydown', enableSoundOnce, { once: true });
|
||
//window.addEventListener('touchstart', enableSoundOnce, { once: true, passive: true });
|
||
</script>
|
||
<div class="footer txt-s12 txt-center">
|
||
<p>
|
||
<a href="https://robertsspaceindustries.com/en/orgs/REACT" target="_blank" title="Notre page RSI"><img src="img/icon09b.png" width="48" height="48" alt="" /></a>
|
||
<a href="https://discord.gg/dAvST8E7Mq" target="_blank" title="Notre Discord"><img src="img/icon08b.png" width="48" height="48" alt="" /></a>
|
||
<a href="https://robertsspaceindustries.com" target="_blank" title="RSI"><img src="img/icon10.png" width="48" height="48" alt="" /></a>
|
||
</p>
|
||
<p>Copyright © 2025-<?php echo date('Y'); ?> | www.react-sc.fr | Tous droits réservés.</p>
|
||
</div>
|
||
</body>
|
||
|
||
</html>
|