![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/public_html/js/ |
// AJAX Navigation System - Preserves Global Player State
// Handles seamless page transitions without breaking music playback
(function() {
'use strict';
let isNavigating = false;
let currentPage = null;
// Initialize AJAX navigation when DOM is ready
function initAjaxNavigation() {
console.log('🔄 Initializing AJAX Navigation');
// Get current page from URL
currentPage = getCurrentPageFromURL();
// Set up click handlers for navigation links
setupNavigationHandlers();
// Handle browser back/forward buttons
setupHistoryHandlers();
}
// Get current page info from URL
function getCurrentPageFromURL() {
const path = window.location.pathname;
const search = window.location.search;
if (path.includes('track.php')) return { type: 'track', url: path + search };
if (path.includes('artist_profile.php')) return { type: 'artist_profile', url: path + search };
if (path.includes('library.php')) return { type: 'library', url: path + search };
if (path.includes('community_fixed.php')) return { type: 'community_fixed', url: path + search };
// Removed artist_dashboard and artists from page detection - uses normal navigation
return { type: 'unknown', url: path + search };
}
// Set up click handlers for navigation links
function setupNavigationHandlers() {
document.addEventListener('click', function(e) {
const link = e.target.closest('a');
if (!link) return;
const href = link.getAttribute('href');
if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return;
// Additional safety: Force normal navigation for links with specific classes (check this FIRST)
if (link.classList.contains('no-ajax') || link.classList.contains('profile-username-link') || link.classList.contains('social-item') || link.classList.contains('nav-tab')) {
console.log('🔒 Link has no-ajax/nav-tab class - forcing normal navigation:', href);
return; // Don't prevent default, let it work normally
}
// CRITICAL FIX: Allow normal navigation for relative query string links (e.g., ?tab=tracks) when on artist_dashboard.php
const currentPath = window.location.pathname;
if (currentPath.includes('artist_dashboard.php') && href.startsWith('?')) {
console.log('🎵 Tab link clicked on artist_dashboard - allowing normal navigation:', href);
return; // Don't prevent default, let it work normally
}
// CRITICAL FIX: Allow normal navigation for track.php, artist_profile.php, community_fixed.php, artist_dashboard.php, and artists.php links
if (href.includes('track.php') || href.includes('artist_profile.php') || href.includes('community_fixed.php') || href.includes('artist_dashboard.php') || href.includes('artists.php')) {
console.log('🎵 Link clicked - allowing normal navigation:', href);
return; // Don't prevent default, let it work normally
}
// Check if this is a link we should handle with AJAX
if (shouldHandleWithAjax(href)) {
e.preventDefault();
navigateToPage(href);
}
});
}
// Determine if a link should be handled with AJAX
function shouldHandleWithAjax(href) {
// Handle internal PHP pages that should preserve global player
// CRITICAL FIX: Removed track.php, artist_profile.php, dashboard.php, community_fixed.php, artist_dashboard.php, and artists.php from AJAX handling
const ajaxPages = [
'/admin.php' // This one works
// Removed problematic pages: track, artist_profile, dashboard, community_fixed, artist_dashboard, artists, library, studio, events, charts, messages, notifications
];
return ajaxPages.some(page => href.includes(page));
}
// Navigate to a page using AJAX
function navigateToPage(href) {
if (isNavigating) {
console.log('🔄 Navigation already in progress, skipping');
return;
}
isNavigating = true;
const startTime = performance.now();
console.log('🔄 AJAX Navigation to:', href);
// Log navigation attempt
logNavigation(currentPage?.url || window.location.href, href, 'ajax');
// Show loading indicator
showLoadingIndicator();
// Parse the URL to get page type and parameters
const { pageType, params } = parsePageURL(href);
if (!pageType) {
console.error('❌ Unable to parse page type from:', href);
// Fallback to normal navigation
window.location.href = href;
return;
}
// Build AJAX request URL with cache-busting timestamp
const cacheBuster = '&_t=' + Date.now();
const ajaxUrl = '/ajax_load_page.php?page=' + pageType + '&' + new URLSearchParams(params).toString() + cacheBuster;
// Make AJAX request with cache-busting
fetch(ajaxUrl, {
cache: 'no-store',
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update page content
updatePageContent(data.content);
// Update browser history
updateBrowserHistory(href, data.title);
// Update current page tracking
currentPage = { type: pageType, url: href };
console.log('✅ AJAX Navigation successful to:', pageType);
// Log performance metrics
const loadTime = performance.now() - startTime;
logPerformance(pageType, loadTime, data.content.length);
// Trigger page-specific initialization if needed
triggerPageInit(pageType);
} else {
throw new Error(data.error || 'Unknown error');
}
})
.catch(error => {
console.error('❌ AJAX Navigation failed:', error);
// Fallback to normal navigation
window.location.href = href;
})
.finally(() => {
hideLoadingIndicator();
isNavigating = false;
});
}
// Parse URL to extract page type and parameters
function parsePageURL(href) {
try {
const url = new URL(href, window.location.origin);
const pathname = url.pathname;
const params = Object.fromEntries(url.searchParams.entries());
// CRITICAL FIX: Removed track.php, artist_profile.php, dashboard.php, community_fixed.php, artist_dashboard.php, and artists.php from AJAX parsing
if (pathname.includes('admin.php')) {
return { pageType: 'admin', params };
}
// Removed problematic pages: track, artist_profile, dashboard, community_fixed, artist_dashboard, artists, library, studio, events, charts, messages, notifications
return { pageType: null, params: {} };
} catch (e) {
console.error('❌ Error parsing URL:', href, e);
return { pageType: null, params: {} };
}
}
// Update the main page content - PRESERVE HEADER approach
function updatePageContent(content) {
try {
// Preserve global player
const globalPlayer = document.querySelector('#enhancedGlobalPlayer');
// Create a temporary container to parse the new content
const tempDiv = document.createElement('div');
tempDiv.innerHTML = content;
// Find the main content container
const mainContainer = document.querySelector('#pageContainer') || document.querySelector('.main-content') || document.querySelector('main');
if (mainContainer) {
// Extract main content from the response
let newMainContent = tempDiv.querySelector('#pageContainer') || tempDiv.querySelector('.main-content') || tempDiv.querySelector('main');
// Remove any style tags that might interfere with existing page styles
const styleTags = tempDiv.querySelectorAll('style');
styleTags.forEach(style => {
// Only remove styles that target body or might conflict
if (style.textContent.includes('body {') || style.textContent.includes('body::')) {
style.remove();
}
});
if (newMainContent) {
// Update only the main content area
mainContainer.innerHTML = newMainContent.innerHTML;
} else {
// Fallback: look for body content but preserve header
let newBodyContent = tempDiv.querySelector('body');
if (newBodyContent) {
// Extract main content from body, excluding header
const bodyMainContent = newBodyContent.querySelector('#pageContainer') || newBodyContent.querySelector('.main-content') || newBodyContent.querySelector('main');
if (bodyMainContent) {
mainContainer.innerHTML = bodyMainContent.innerHTML;
} else {
// Extract everything except header and footer
const header = newBodyContent.querySelector('header');
const footer = newBodyContent.querySelector('footer');
if (header) header.remove();
if (footer) footer.remove();
mainContainer.innerHTML = newBodyContent.innerHTML;
}
} else {
// If no body tag found, assume it's just content
mainContainer.innerHTML = content;
}
}
} else {
// Fallback: replace only main content, preserve header
let newBodyContent = tempDiv.querySelector('body');
if (newBodyContent) {
// Remove header and footer from new content
const header = newBodyContent.querySelector('header');
const footer = newBodyContent.querySelector('footer');
if (header) header.remove();
if (footer) footer.remove();
// Find the main content in the current page
const currentMain = document.querySelector('#pageContainer') || document.querySelector('.main-content') || document.querySelector('main');
if (currentMain) {
// Extract main content from new body
const newMain = newBodyContent.querySelector('#pageContainer') || newBodyContent.querySelector('.main-content') || newBodyContent.querySelector('main');
if (newMain) {
currentMain.innerHTML = newMain.innerHTML;
} else {
currentMain.innerHTML = newBodyContent.innerHTML;
}
} else {
// Last resort: replace body but preserve global player
document.body.innerHTML = newBodyContent.innerHTML;
if (globalPlayer) {
document.body.appendChild(globalPlayer);
}
}
} else {
// If no body tag found, assume it's just content
const currentMain = document.querySelector('#pageContainer') || document.querySelector('.main-content') || document.querySelector('main');
if (currentMain) {
currentMain.innerHTML = content;
} else {
document.body.innerHTML = content;
if (globalPlayer) {
document.body.appendChild(globalPlayer);
}
}
}
}
// Reinitialize any JavaScript that might be needed
reinitializePageScripts();
// Dispatch custom event for pages to reinitialize
document.dispatchEvent(new CustomEvent('ajaxPageLoaded', {
detail: { url: currentPage?.url || window.location.href }
}));
} catch (error) {
console.error('❌ Error updating page content:', error);
// Fallback to normal navigation
throw error;
}
}
// Update browser history for back/forward button support
function updateBrowserHistory(href, title) {
const state = {
page: currentPage?.type || 'unknown',
url: href,
timestamp: Date.now()
};
// Update page title
document.title = title + ' - SoundStudioPro';
// Push new state to history
history.pushState(state, title, href);
}
// Handle browser back/forward buttons
function setupHistoryHandlers() {
window.addEventListener('popstate', function(e) {
if (e.state && e.state.url) {
console.log('🔄 Browser back/forward to:', e.state.url);
navigateToPage(e.state.url);
} else {
// Fallback: reload page
window.location.reload();
}
});
}
// Show loading indicator during navigation
function showLoadingIndicator() {
// Add loading overlay if it doesn't exist
if (!document.getElementById('ajax-loading')) {
const loading = document.createElement('div');
loading.id = 'ajax-loading';
loading.innerHTML = `
<div class="loading-overlay">
<div class="loading-spinner">
<i class="fas fa-spinner fa-spin"></i>
<span>Loading...</span>
</div>
</div>
`;
loading.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.3);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
`;
document.body.appendChild(loading);
}
document.getElementById('ajax-loading').style.display = 'flex';
}
// Hide loading indicator
function hideLoadingIndicator() {
const loading = document.getElementById('ajax-loading');
if (loading) {
loading.style.display = 'none';
}
}
// Reinitialize page scripts after content update
function reinitializePageScripts() {
// Reinitialize any page-specific JavaScript
// This is called after AJAX content is loaded
// Re-setup cart functionality if present
if (typeof window.setupCartHandlers === 'function') {
window.setupCartHandlers();
}
// Re-setup dashboard play buttons if present
if (document.querySelector('.play-track-btn')) {
console.log('🎵 Dashboard: Reinitializing play buttons after AJAX');
// Play buttons will work automatically with onclick handlers
}
// Re-setup any other dynamic elements
// Add more reinitialization calls as needed
}
// Trigger page-specific initialization
function triggerPageInit(pageType) {
// Dispatch custom event for page-specific scripts
const event = new CustomEvent('ajaxPageLoaded', {
detail: { pageType: pageType }
});
document.dispatchEvent(event);
}
// Public API
window.ajaxNavigation = {
navigateToPage: navigateToPage,
getCurrentPage: () => currentPage,
isNavigating: () => isNavigating
};
// Performance and usage logging
function logNavigation(fromPage, toPage, method) {
// Log navigation for analytics (optional)
if (typeof fetch !== 'undefined') {
fetch('/ajax_monitor.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: new URLSearchParams({
action: 'log_navigation',
from_page: fromPage,
to_page: toPage,
method: method
})
}).catch(() => {}); // Fail silently
}
}
function logPerformance(page, loadTime, contentSize) {
// Log performance metrics (optional)
if (typeof fetch !== 'undefined') {
fetch('/ajax_monitor.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: new URLSearchParams({
action: 'log_performance',
page: page,
load_time: loadTime.toFixed(2),
content_size: contentSize
})
}).catch(() => {}); // Fail silently
}
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAjaxNavigation);
} else {
initAjaxNavigation();
}
})();