- Fixed registration form not displaying due to missing HVAC_Security_Helpers dependency - Added require_once for dependencies in class-hvac-shortcodes.php render_registration() - Fixed event edit HTTP 500 error by correcting class instantiation to HVAC_Event_Manager - Created comprehensive E2E test suite with MCP Playwright integration - Achieved 70% test success rate with both issues fully resolved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
304 lines
No EOL
10 KiB
JavaScript
304 lines
No EOL
10 KiB
JavaScript
/**
|
|
* MapGeo Safety System
|
|
* Prevents MapGeo and third-party map plugins from crashing the page
|
|
* Works in all browsers including Safari and Chrome
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
// Safety configuration
|
|
const config = window.HVAC_MapGeo_Config || {
|
|
maxRetries: 3,
|
|
retryDelay: 2000,
|
|
timeout: 10000,
|
|
fallbackEnabled: true,
|
|
debugMode: false
|
|
};
|
|
|
|
const log = config.debugMode ? console.log.bind(console) : () => {};
|
|
const error = config.debugMode ? console.error.bind(console) : () => {};
|
|
|
|
log('[MapGeo Safety] Initializing protection system');
|
|
|
|
/**
|
|
* Resource Load Monitor
|
|
* Tracks and manages external script loading
|
|
*/
|
|
class ResourceLoadMonitor {
|
|
constructor() {
|
|
this.resources = new Map();
|
|
this.criticalResources = [
|
|
'amcharts',
|
|
'mapgeo',
|
|
'interactive-geo-maps',
|
|
'map-widget'
|
|
];
|
|
this.setupMonitoring();
|
|
}
|
|
|
|
setupMonitoring() {
|
|
// Monitor script loading
|
|
const originalAppendChild = Element.prototype.appendChild;
|
|
const self = this;
|
|
|
|
Element.prototype.appendChild = function(element) {
|
|
if (element.tagName === 'SCRIPT' && element.src) {
|
|
self.monitorScript(element);
|
|
}
|
|
return originalAppendChild.call(this, element);
|
|
};
|
|
|
|
// Monitor existing scripts
|
|
document.querySelectorAll('script[src]').forEach(script => {
|
|
this.monitorScript(script);
|
|
});
|
|
}
|
|
|
|
monitorScript(script) {
|
|
const src = script.src;
|
|
const isCritical = this.criticalResources.some(resource =>
|
|
src.toLowerCase().includes(resource)
|
|
);
|
|
|
|
if (isCritical) {
|
|
log('[MapGeo Safety] Monitoring critical resource:', src);
|
|
|
|
const timeoutId = setTimeout(() => {
|
|
error('[MapGeo Safety] Resource timeout:', src);
|
|
this.handleResourceFailure(src);
|
|
}, config.timeout);
|
|
|
|
script.addEventListener('load', () => {
|
|
clearTimeout(timeoutId);
|
|
log('[MapGeo Safety] Resource loaded:', src);
|
|
this.resources.set(src, 'loaded');
|
|
});
|
|
|
|
script.addEventListener('error', () => {
|
|
clearTimeout(timeoutId);
|
|
error('[MapGeo Safety] Resource failed:', src);
|
|
this.handleResourceFailure(src);
|
|
});
|
|
}
|
|
}
|
|
|
|
handleResourceFailure(src) {
|
|
this.resources.set(src, 'failed');
|
|
|
|
// Check if this is a MapGeo CDN resource
|
|
if (src.includes('cdn') || src.includes('amcharts')) {
|
|
log('[MapGeo Safety] CDN resource failed, activating fallback');
|
|
this.activateFallback();
|
|
}
|
|
}
|
|
|
|
activateFallback() {
|
|
// Hide map container
|
|
const mapContainers = document.querySelectorAll(
|
|
'.igm-map-container, [class*="mapgeo"], [id*="map-"], .map-widget-container'
|
|
);
|
|
|
|
mapContainers.forEach(container => {
|
|
container.style.display = 'none';
|
|
});
|
|
|
|
// Show fallback content
|
|
const fallback = document.getElementById('hvac-map-fallback');
|
|
if (fallback) {
|
|
fallback.style.display = 'block';
|
|
}
|
|
|
|
// Dispatch custom event
|
|
window.dispatchEvent(new CustomEvent('hvac:mapgeo:fallback', {
|
|
detail: { reason: 'resource_failure' }
|
|
}));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* MapGeo API Wrapper
|
|
* Safely wraps MapGeo API calls
|
|
*/
|
|
class MapGeoAPIWrapper {
|
|
constructor() {
|
|
this.wrapAPIs();
|
|
}
|
|
|
|
wrapAPIs() {
|
|
// Wrap potential MapGeo global functions
|
|
const mapGeoAPIs = [
|
|
'MapGeoWidget',
|
|
'InteractiveGeoMaps',
|
|
'IGM',
|
|
'mapWidget'
|
|
];
|
|
|
|
mapGeoAPIs.forEach(api => {
|
|
if (typeof window[api] !== 'undefined') {
|
|
this.wrapAPI(api);
|
|
}
|
|
|
|
// Set up getter to wrap when loaded
|
|
Object.defineProperty(window, `_original_${api}`, {
|
|
value: window[api],
|
|
writable: true
|
|
});
|
|
|
|
Object.defineProperty(window, api, {
|
|
get() {
|
|
return window[`_wrapped_${api}`] || window[`_original_${api}`];
|
|
},
|
|
set(value) {
|
|
window[`_original_${api}`] = value;
|
|
window[`_wrapped_${api}`] = new Proxy(value, {
|
|
construct(target, args) {
|
|
try {
|
|
return new target(...args);
|
|
} catch (e) {
|
|
error('[MapGeo Safety] Construction error:', e);
|
|
return {};
|
|
}
|
|
},
|
|
apply(target, thisArg, args) {
|
|
try {
|
|
return target.apply(thisArg, args);
|
|
} catch (e) {
|
|
error('[MapGeo Safety] Execution error:', e);
|
|
return null;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
wrapAPI(apiName) {
|
|
const original = window[apiName];
|
|
|
|
window[apiName] = new Proxy(original, {
|
|
construct(target, args) {
|
|
try {
|
|
log(`[MapGeo Safety] Creating ${apiName} instance`);
|
|
return new target(...args);
|
|
} catch (e) {
|
|
error(`[MapGeo Safety] Failed to create ${apiName}:`, e);
|
|
return {};
|
|
}
|
|
},
|
|
apply(target, thisArg, args) {
|
|
try {
|
|
log(`[MapGeo Safety] Calling ${apiName}`);
|
|
return target.apply(thisArg, args);
|
|
} catch (e) {
|
|
error(`[MapGeo Safety] Failed to call ${apiName}:`, e);
|
|
return null;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DOM Ready Safety
|
|
* Ensures MapGeo only runs when DOM is safe
|
|
*/
|
|
class DOMReadySafety {
|
|
constructor() {
|
|
this.setupSafety();
|
|
}
|
|
|
|
setupSafety() {
|
|
// Intercept jQuery ready calls that might contain MapGeo code
|
|
if (typeof jQuery !== 'undefined') {
|
|
const originalReady = jQuery.fn.ready;
|
|
|
|
jQuery.fn.ready = function(callback) {
|
|
const wrappedCallback = function() {
|
|
try {
|
|
// Check if MapGeo elements exist before running
|
|
const hasMapElements = document.querySelector(
|
|
'.igm-map-container, [class*="mapgeo"], [id*="map-"]'
|
|
);
|
|
|
|
if (hasMapElements || !callback.toString().includes('map')) {
|
|
return callback.apply(this, arguments);
|
|
} else {
|
|
log('[MapGeo Safety] Skipping map-related ready callback - no map elements found');
|
|
}
|
|
} catch (e) {
|
|
error('[MapGeo Safety] Error in ready callback:', e);
|
|
}
|
|
};
|
|
|
|
return originalReady.call(this, wrappedCallback);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize all safety systems
|
|
*/
|
|
function initializeSafetySystems() {
|
|
// Only initialize on pages with potential maps
|
|
if (!document.querySelector('[class*="map"], [id*="map"]')) {
|
|
log('[MapGeo Safety] No map elements detected, skipping initialization');
|
|
return;
|
|
}
|
|
|
|
// Initialize monitors
|
|
new ResourceLoadMonitor();
|
|
new MapGeoAPIWrapper();
|
|
new DOMReadySafety();
|
|
|
|
// Set up periodic health check
|
|
let healthCheckCount = 0;
|
|
const healthCheckInterval = setInterval(() => {
|
|
healthCheckCount++;
|
|
|
|
// Check if map loaded successfully
|
|
const mapLoaded = document.querySelector('.igm-map-loaded, .mapgeo-loaded, .map-initialized');
|
|
|
|
if (mapLoaded) {
|
|
log('[MapGeo Safety] Map loaded successfully');
|
|
clearInterval(healthCheckInterval);
|
|
} else if (healthCheckCount >= 10) {
|
|
// After 10 seconds, consider it failed
|
|
error('[MapGeo Safety] Map failed to load after 10 seconds');
|
|
clearInterval(healthCheckInterval);
|
|
|
|
// Activate fallback if configured
|
|
if (config.fallbackEnabled) {
|
|
const monitor = new ResourceLoadMonitor();
|
|
monitor.activateFallback();
|
|
}
|
|
}
|
|
}, 1000);
|
|
|
|
log('[MapGeo Safety] All safety systems initialized');
|
|
}
|
|
|
|
// Initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initializeSafetySystems);
|
|
} else {
|
|
// DOM already loaded
|
|
initializeSafetySystems();
|
|
}
|
|
|
|
// Expose safety API for debugging
|
|
window.HVACMapGeoSafety = {
|
|
config: config,
|
|
reinitialize: initializeSafetySystems,
|
|
activateFallback: () => {
|
|
const monitor = new ResourceLoadMonitor();
|
|
monitor.activateFallback();
|
|
}
|
|
};
|
|
|
|
})(); |