Fix inline script issues

This commit is contained in:
DariusIII
2025-10-31 10:32:09 +01:00
parent ef32c35570
commit 6ecfe79580
4 changed files with 282 additions and 3104 deletions
+255 -2867
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -38,7 +38,7 @@
@endif
</div>
<div class="flex flex-wrap gap-2">
<a href="{{ url('/getnzb/' . $release->guid) }}" class="download-nzb px-4 py-2 bg-green-600 dark:bg-green-700 text-white rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition inline-flex items-center" onclick="showToast('Downloading NZB...', 'success')">
<a href="{{ url('/getnzb/' . $release->guid) }}" class="download-nzb px-4 py-2 bg-green-600 dark:bg-green-700 text-white rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition inline-flex items-center">
<i class="fas fa-download mr-2"></i> Download NZB
</a>
<a href="#" class="add-to-cart px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition inline-flex items-center" data-guid="{{ $release->guid }}">
@@ -83,7 +83,7 @@
@if($hasPreviewImage)
<!-- Preview image -->
<div>
<div class="block cursor-pointer" onclick="openImageModal('{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}', 'Preview Image')">
<div class="block cursor-pointer image-modal-trigger" data-image-url="{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}" data-image-title="Preview Image">
<img src="{{ url('/covers/preview/' . $release->guid . '_thumb.jpg') }}"
alt="Preview"
class="w-full h-auto rounded-lg shadow-md hover:shadow-lg transition"
@@ -96,7 +96,7 @@
@if($hasSampleImage)
<!-- Sample image -->
<div>
<div class="block cursor-pointer" onclick="openImageModal('{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}', 'Sample Image')">
<div class="block cursor-pointer image-modal-trigger" data-image-url="{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}" data-image-title="Sample Image">
<img src="{{ url('/covers/sample/' . $release->guid . '_thumb.jpg') }}"
alt="Sample"
class="w-full h-auto rounded-lg shadow-md hover:shadow-lg transition"
@@ -922,9 +922,9 @@
@endsection
<!-- Image Modal -->
<div id="imageModal" class="fixed inset-0 bg-transparent hidden items-center justify-center p-4">
<div class="relative max-w-7xl w-full h-full flex items-center justify-center">
<button type="button" onclick="closeImageModal()" class="absolute top-4 right-4 text-white hover:text-gray-300 text-4xl font-bold z-10 bg-black bg-opacity-70 rounded-full w-12 h-12 flex items-center justify-center shadow-lg">
<div id="imageModal" class="image-modal-backdrop hidden">
<div class="image-modal-container">
<button type="button" class="image-modal-close" data-close-image-modal>
<i class="fas fa-times"></i>
</button>
<div class="text-center">
+19 -162
View File
@@ -17,8 +17,8 @@
@vite(['resources/css/app.css', 'resources/js/app.js'])
@stack('styles')
<!-- Dark Mode Script (must be inline to prevent flash) -->
<script>
<!-- Dark Mode Script (must use nonce to prevent flash) -->
<script nonce="{{ csp_nonce() }}">
// Initialize theme before page renders to prevent flash
(function() {
@auth
@@ -153,167 +153,24 @@
@stack('scripts')
<script>
// Theme management with system preference support
(function() {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
<!-- Theme Management Data (moved to csp-safe.js) -->
<div id="current-theme-data"
data-theme="{{ auth()->check() ? (auth()->user()->theme_preference ?? 'light') : 'light' }}"
data-authenticated="{{ auth()->check() ? 'true' : 'false' }}"
data-update-url="{{ route('profile.update-theme') }}"
style="display: none;">
</div>
function applyTheme(themePreference) {
const html = document.documentElement;
if (themePreference === 'system') {
if (mediaQuery.matches) {
html.classList.add('dark');
} else {
html.classList.remove('dark');
}
} else if (themePreference === 'dark') {
html.classList.add('dark');
} else {
html.classList.remove('dark');
}
}
function updateThemeButton(theme) {
const themeIcon = document.getElementById('theme-icon');
const themeLabel = document.getElementById('theme-label');
const themeToggle = document.getElementById('theme-toggle');
const icons = {
'light': 'fa-sun',
'dark': 'fa-moon',
'system': 'fa-desktop'
};
const labels = {
'light': 'Light',
'dark': 'Dark',
'system': 'System'
};
const titles = {
'light': 'Light Mode',
'dark': 'Dark Mode',
'system': 'System Mode'
};
if (themeIcon) {
// Remove all possible icon classes first
themeIcon.classList.remove('fa-sun', 'fa-moon', 'fa-desktop');
// Add the correct icon class
themeIcon.classList.add(icons[theme]);
}
if (themeLabel) {
themeLabel.textContent = labels[theme];
}
if (themeToggle) {
themeToggle.setAttribute('title', titles[theme]);
}
}
// Listen for OS theme changes
mediaQuery.addEventListener('change', () => {
@auth
const userThemePreference = '{{ auth()->user()->theme_preference ?? 'light' }}';
if (userThemePreference === 'system') {
applyTheme('system');
}
@else
const theme = localStorage.getItem('theme') || 'light';
if (theme === 'system') {
applyTheme('system');
}
@endauth
});
// Listen for custom theme change events from sidebar
document.addEventListener('themeChanged', function(e) {
if (e.detail && e.detail.theme) {
updateThemeButton(e.detail.theme);
applyTheme(e.detail.theme);
@auth
currentTheme = e.detail.theme;
@else
currentTheme = e.detail.theme;
@endauth
}
});
// Dark mode toggle - cycles through light -> dark -> system
const themeToggle = document.getElementById('theme-toggle');
@auth
let currentTheme = '{{ auth()->user()->theme_preference ?? 'light' }}';
@else
let currentTheme = localStorage.getItem('theme') || 'light';
@endauth
themeToggle?.addEventListener('click', function() {
let nextTheme;
// Cycle through: light -> dark -> system -> light
if (currentTheme === 'light') {
nextTheme = 'dark';
} else if (currentTheme === 'dark') {
nextTheme = 'system';
} else {
nextTheme = 'light';
}
applyTheme(nextTheme);
updateThemeButton(nextTheme);
@auth
// Save to backend for authenticated users
fetch('{{ route('profile.update-theme') }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ theme_preference: nextTheme })
}).then(response => response.json())
.then(data => {
if (data.success) {
currentTheme = nextTheme;
// Dispatch event to update sidebar
document.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme: nextTheme } }));
}
});
@else
localStorage.setItem('theme', nextTheme);
currentTheme = nextTheme;
// Dispatch event to update sidebar
document.dispatchEvent(new CustomEvent('themeChanged', { detail: { theme: nextTheme } }));
@endauth
});
// Mobile sidebar toggle
document.getElementById('mobile-sidebar-toggle')?.addEventListener('click', function() {
document.getElementById('sidebar')?.classList.toggle('hidden');
});
// Display flash messages as toast notifications
@if(session('success'))
window.showToast('{{ session('success') }}', 'success');
@endif
@if(session('error'))
@if(is_array(session('error')))
@foreach(session('error') as $error)
window.showToast('{{ $error }}', 'error');
@endforeach
@else
window.showToast('{{ session('error') }}', 'error');
@endif
@endif
@if(session('warning'))
window.showToast('{{ session('warning') }}', 'warning');
@endif
@if(session('info'))
window.showToast('{{ session('info') }}', 'info');
@endif
})();
</script>
<!-- Flash Messages Data (moved to csp-safe.js) -->
<div id="flash-messages-data"
data-messages="{{ json_encode([
'success' => session('success'),
'error' => session('error'),
'warning' => session('warning'),
'info' => session('info')
]) }}"
style="display: none;">
</div>
</body>
</html>
+2 -69
View File
@@ -1,71 +1,4 @@
{{-- Cart functionality JavaScript --}}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle add to cart button clicks
document.addEventListener('click', function(e) {
// Check if clicked element or its parent is a cart button
const cartBtn = e.target.closest('.add-to-cart');
if (cartBtn) {
e.preventDefault();
// Get the GUID from the button's data attribute
const guid = cartBtn.dataset.guid;
const iconElement = cartBtn.querySelector('.icon_cart');
if (!guid) {
console.error('No GUID found for cart item');
return;
}
// Prevent double-clicking
if (iconElement && iconElement.classList.contains('icon_cart_clicked')) {
return;
}
// Send AJAX request to add item to cart
fetch('/cart/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ id: guid })
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Visual feedback
if (iconElement) {
iconElement.classList.remove('fa-shopping-basket');
iconElement.classList.add('fa-check', 'icon_cart_clicked');
// Reset icon after 2 seconds
setTimeout(() => {
iconElement.classList.remove('fa-check', 'icon_cart_clicked');
iconElement.classList.add('fa-shopping-basket');
}, 2000);
}
// Update cart count if element exists
const cartCount = document.querySelector('.cart-count');
if (cartCount && data.cartCount) {
cartCount.textContent = data.cartCount;
}
// Show success notification
window.showToast('Added to cart successfully!', 'success');
} else {
window.showToast('Failed to add item to cart', 'error');
}
})
.catch(error => {
console.error('Error adding to cart:', error);
window.showToast('An error occurred', 'error');
});
}
});
});
</script>
{{-- All cart functionality has been moved to resources/js/csp-safe.js for CSP compliance --}}
{{-- See initCartFunctionality() function --}}