Files
railsgoat/app/views/layouts/shared/_header.html.erb
T
Ken Johnson 0c4533a88a Fix modal not displaying by disposing stale instances
Fixed modal showing backdrop but not the modal itself by explicitly
disposing old instances and adding a timing delay.

Changes:
- Dispose of existing modal instance before creating new one
- Create fresh modal with explicit options (backdrop, keyboard, focus)
- Add 10ms setTimeout before show() to ensure DOM readiness
- Remove getOrCreateInstance which was causing conflicts

The modal was creating a backdrop but staying display:none because
getOrCreateInstance was returning a stale modal instance that couldn't
properly transition. Disposing and recreating fixes this.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 01:45:07 -05:00

185 lines
6.9 KiB
Plaintext
Executable File

<% if current_user %>
<!-- Authenticated Header -->
<header class="rg-header">
<div class="container-fluid h-100">
<div class="row h-100 align-items-center">
<div class="col-auto">
<a href="<%= home_dashboard_index_path %>" class="rg-brand">
<i class="bi bi-shield-fill-exclamation"></i> RailsGoat
</a>
</div>
<div class="col"></div>
<div class="col-auto">
<div class="d-flex align-items-center gap-3">
<!-- Font Size Controls -->
<div class="btn-group btn-group-sm" role="group" aria-label="Font size controls">
<a href="/dashboard/home?font=8pt" class="btn btn-outline-secondary" style="font-size: 10pt;" title="Small font" aria-label="Small font">
<i class="bi bi-type"></i>
</a>
<a href="/dashboard/home?font=200%25" class="btn btn-outline-secondary" style="font-size: 14pt;" title="Large font" aria-label="Large font">
<i class="bi bi-type"></i>
</a>
</div>
<!-- Tutorial Link -->
<%= button_to "https://github.com/OWASP/railsgoat/wiki", {
method: "get",
class: "btn btn-sm btn-outline-primary",
onclick: "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank'); return false;"
} do %>
<i class="bi bi-book"></i> Tutorials
<% end %>
<!-- User Dropdown -->
<div class="dropdown">
<button class="btn btn-link text-decoration-none dropdown-toggle d-flex align-items-center gap-2" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
<i class="bi bi-person-fill text-white"></i>
</div>
<!--
VULNERABILITY: XSS via html_safe
I'm going to use HTML safe because we had some weird stuff
going on with funny chars and jquery, plus it says safe so I'm guessing
nothing bad will happen
-->
<span class="text-dark"><%= current_user.first_name.html_safe %></span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<%= link_to user_account_settings_path(user_id: current_user.id), class: "dropdown-item" do %>
<i class="bi bi-gear"></i> Account Settings
<% end %>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<%= link_to logout_path, class: "dropdown-item text-danger" do %>
<i class="bi bi-box-arrow-right"></i> Logout
<% end %>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</header>
<% else %>
<!-- Unauthenticated Header -->
<header class="rg-header">
<div class="container-fluid h-100">
<div class="row h-100 align-items-center">
<div class="col-auto">
<span class="rg-brand">
<i class="bi bi-shield-fill-exclamation"></i> RailsGoat
</span>
</div>
<div class="col"></div>
<div class="col-auto">
<div class="d-flex align-items-center gap-2">
<button type="button" id="show_creds_btn" class="btn btn-sm btn-warning">
<i class="bi bi-key"></i> Demo Credentials
</button>
<%= button_to "https://github.com/OWASP/railsgoat/wiki", {
method: "get",
class: "btn btn-sm btn-outline-primary",
onclick: "window.open('https://github.com/OWASP/railsgoat/wiki', '_blank'); return false;"
} do %>
<i class="bi bi-book"></i> Tutorials
<% end %>
<%= button_to signup_path, {
class: "btn btn-sm btn-primary",
method: "get"
} do %>
<i class="bi bi-person-plus"></i> Sign Up
<% end %>
<%= button_to login_path, {
class: "btn btn-sm btn-outline-primary",
method: "get"
} do %>
<i class="bi bi-box-arrow-in-right"></i> Login
<% end %>
</div>
</div>
</div>
</div>
</header>
<!-- Credentials Modal -->
<div class="modal fade" id="credentialsModal" tabindex="-1" aria-labelledby="credentialsModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="credentialsModalLabel">
<i class="bi bi-key"></i> Demo Credentials
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="modal_content" class="modal-body">
<!-- Content loaded via AJAX -->
</div>
</div>
</div>
</div>
<script>
function initCredentialsModal() {
const showCredsBtn = document.getElementById('show_creds_btn');
const modalElement = document.getElementById('credentialsModal');
if (showCredsBtn && modalElement) {
// Remove any existing listeners by cloning
const newBtn = showCredsBtn.cloneNode(true);
showCredsBtn.parentNode.replaceChild(newBtn, showCredsBtn);
newBtn.addEventListener('click', function(event) {
event.preventDefault();
fetch('<%= credentials_tutorials_path %>')
.then(response => response.text())
.then(html => {
document.getElementById('modal_content').innerHTML = html;
// Dispose of any existing modal instance first
const existingModal = bootstrap.Modal.getInstance(modalElement);
if (existingModal) {
existingModal.dispose();
}
// Create fresh modal instance and show
const modal = new bootstrap.Modal(modalElement, {
backdrop: true,
keyboard: true,
focus: true
});
// Force show after a small delay to ensure DOM is ready
setTimeout(() => {
modal.show();
}, 10);
})
.catch(error => {
console.error('Error loading credentials:', error);
document.getElementById('modal_content').innerHTML = '<p class="text-danger">Error loading credentials. Please try again.</p>';
const modal = new bootstrap.Modal(modalElement);
modal.show();
});
});
}
}
// Handle both initial load and Turbolinks navigation
document.addEventListener('DOMContentLoaded', initCredentialsModal);
document.addEventListener('turbolinks:load', initCredentialsModal);
</script>
<% end %>