mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
fix(modes): deep-linked mode scripts fail when body not yet parsed
ensureModeScript() used document.body.appendChild() to load lazy mode scripts, but the preload for ?mode= query params runs in <head> before <body> exists, causing all deep-linked modes to silently fail. Also fix cross-mode handoffs (BT→BT Locate, WiFi→WiFi Locate, Spy Stations→Waterfall) that assumed target module was already loaded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
<!-- Scan Mode Tabs -->
|
||||
<div class="section">
|
||||
<h3>Signal Source</h3>
|
||||
<div class="wifi-scan-mode-tabs" style="display: flex; gap: 4px;">
|
||||
<button id="wifiScanModeQuick" class="wifi-mode-tab active" style="flex: 1; padding: 8px; font-size: 11px; background: var(--accent-green); color: #000; border: none; border-radius: 4px; cursor: pointer;">
|
||||
<div class="wifi-scan-mode-tabs" role="tablist" aria-label="Scan mode" style="display: flex; gap: 4px;">
|
||||
<button id="wifiScanModeQuick" class="wifi-mode-tab active" role="tab" aria-selected="true" style="flex: 1; padding: 8px; font-size: 11px; background: var(--accent-green); color: #000; border: none; border-radius: 4px; cursor: pointer;">
|
||||
Quick Scan
|
||||
</button>
|
||||
<button id="wifiScanModeDeep" class="wifi-mode-tab" style="flex: 1; padding: 8px; font-size: 11px; background: var(--bg-tertiary); color: #888; border: 1px solid var(--border-color); border-radius: 4px; cursor: pointer;">
|
||||
<button id="wifiScanModeDeep" class="wifi-mode-tab" role="tab" aria-selected="false" style="flex: 1; padding: 8px; font-size: 11px; background: var(--bg-tertiary); color: #888; border: 1px solid var(--border-color); border-radius: 4px; cursor: pointer;">
|
||||
Deep Scan
|
||||
</button>
|
||||
</div>
|
||||
@@ -121,7 +121,7 @@
|
||||
<label for="deauthCount">Deauth Count</label>
|
||||
<input type="text" id="deauthCount" value="5" placeholder="5">
|
||||
</div>
|
||||
<button class="preset-btn" onclick="sendDeauth()" style="width: 100%; border-color: var(--accent-red); color: var(--accent-red);">
|
||||
<button class="preset-btn btn-danger-outline" onclick="sendDeauth()" style="width: 100%;">
|
||||
Send Deauth
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<nav class="mode-nav" id="mainNav">
|
||||
{# Signals Group #}
|
||||
<div class="mode-nav-dropdown" data-group="signals">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('signals')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('signals')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12h4l3-8 3 16 3-8h4"/><path d="M22 12h-1"/><path d="M1 12h1"/></svg></span>
|
||||
<span class="nav-label">Signals</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
{# Tracking Group #}
|
||||
<div class="mode-nav-dropdown" data-group="tracking">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('tracking')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('tracking')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg></span>
|
||||
<span class="nav-label">Tracking</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
{# Space Group #}
|
||||
<div class="mode-nav-dropdown" data-group="space">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('space')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('space')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg></span>
|
||||
<span class="nav-label">Space</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -114,7 +114,7 @@
|
||||
|
||||
{# Wireless Group #}
|
||||
<div class="mode-nav-dropdown" data-group="wireless">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('wireless')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('wireless')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><circle cx="12" cy="20" r="1" fill="currentColor" stroke="none"/></svg></span>
|
||||
<span class="nav-label">Wireless</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
{# Intel Group #}
|
||||
<div class="mode-nav-dropdown" data-group="intel">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('intel')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('intel')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></span>
|
||||
<span class="nav-label">Intel</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
{# System Group #}
|
||||
<div class="mode-nav-dropdown" data-group="system">
|
||||
<button type="button" class="mode-nav-dropdown-btn"{% if is_index_page %} onclick="toggleNavDropdown('system')"{% endif %}>
|
||||
<button type="button" class="mode-nav-dropdown-btn" aria-expanded="false"{% if is_index_page %} onclick="toggleNavDropdown('system')"{% endif %}>
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg></span>
|
||||
<span class="nav-label">System</span>
|
||||
<span class="dropdown-arrow icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
{# Dynamic dashboard button (shown when in satellite mode) #}
|
||||
<div class="mode-nav-actions">
|
||||
<a href="/satellite/dashboard" target="_blank" class="nav-action-btn" id="satelliteDashboardBtn">
|
||||
<a href="/satellite/dashboard" target="_blank" class="nav-action-btn" id="satelliteDashboardBtn" style="display: none;">
|
||||
<span class="nav-icon icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg></span>
|
||||
<span class="nav-label">Full Dashboard</span>
|
||||
</a>
|
||||
@@ -362,16 +362,84 @@
|
||||
|
||||
// Close other dropdowns
|
||||
document.querySelectorAll('.mode-nav-dropdown.open').forEach(d => {
|
||||
if (d !== dropdown) d.classList.remove('open');
|
||||
if (d !== dropdown) {
|
||||
d.classList.remove('open');
|
||||
const btn = d.querySelector('.mode-nav-dropdown-btn');
|
||||
if (btn) btn.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.classList.toggle('open');
|
||||
const isOpen = dropdown.classList.toggle('open');
|
||||
const btn = dropdown.querySelector('.mode-nav-dropdown-btn');
|
||||
if (btn) btn.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||
|
||||
// Focus first menu item when opening
|
||||
if (isOpen) {
|
||||
const firstItem = dropdown.querySelector('.mode-nav-dropdown-menu button, .mode-nav-dropdown-menu a');
|
||||
if (firstItem) firstItem.focus();
|
||||
}
|
||||
};
|
||||
|
||||
// Close dropdowns when clicking outside
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.mode-nav-dropdown')) {
|
||||
document.querySelectorAll('.mode-nav-dropdown.open').forEach(d => d.classList.remove('open'));
|
||||
document.querySelectorAll('.mode-nav-dropdown.open').forEach(d => {
|
||||
d.classList.remove('open');
|
||||
const btn = d.querySelector('.mode-nav-dropdown-btn');
|
||||
if (btn) btn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Keyboard support for dropdown buttons and menu items
|
||||
document.addEventListener('keydown', function(e) {
|
||||
const dropdown = e.target.closest('.mode-nav-dropdown');
|
||||
if (!dropdown) return;
|
||||
|
||||
const btn = dropdown.querySelector('.mode-nav-dropdown-btn');
|
||||
const menu = dropdown.querySelector('.mode-nav-dropdown-menu');
|
||||
if (!menu) return;
|
||||
const items = Array.from(menu.querySelectorAll('button, a'));
|
||||
|
||||
if (e.target === btn || e.target.closest('.mode-nav-dropdown-btn')) {
|
||||
// On the dropdown trigger button
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
const group = dropdown.getAttribute('data-group');
|
||||
if (group) toggleNavDropdown(group);
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
if (!dropdown.classList.contains('open')) {
|
||||
const group = dropdown.getAttribute('data-group');
|
||||
if (group) toggleNavDropdown(group);
|
||||
}
|
||||
if (items.length) items[0].focus();
|
||||
} else if (e.key === 'Escape') {
|
||||
dropdown.classList.remove('open');
|
||||
if (btn) {
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
btn.focus();
|
||||
}
|
||||
}
|
||||
} else if (items.includes(e.target)) {
|
||||
// Inside the dropdown menu
|
||||
const idx = items.indexOf(e.target);
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
items[(idx + 1) % items.length].focus();
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
items[(idx - 1 + items.length) % items.length].focus();
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
dropdown.classList.remove('open');
|
||||
if (btn) {
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
btn.focus();
|
||||
}
|
||||
} else if (e.key === 'Enter' || e.key === ' ') {
|
||||
// Default behavior (click) is fine for links/buttons
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user