upskill-event-manager/assets/js/feature-detection.js
Ben 89872ec998 fix: resolve registration form display and event edit issues
- 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>
2025-08-24 08:27:17 -03:00

397 lines
No EOL
10 KiB
JavaScript

/**
* Feature Detection System
* Detects browser capabilities instead of relying on user agent strings
*
* @package HVAC_Community_Events
* @since 2.0.0
*/
var HVACFeatureDetection = (function() {
'use strict';
var features = {};
var _hasRunDetection = false;
/**
* Detect all features
*/
function detectAll() {
if (_hasRunDetection) {
return features;
}
console.log('[Feature Detection] Running capability tests...');
features = {
// Storage capabilities
localStorage: testLocalStorage(),
sessionStorage: testSessionStorage(),
cookies: navigator.cookieEnabled || false,
indexedDB: testIndexedDB(),
// JavaScript features
es6: testES6Support(),
promises: typeof Promise !== 'undefined',
fetch: typeof fetch !== 'undefined',
async: testAsyncSupport(),
// DOM features
mutationObserver: 'MutationObserver' in window,
intersectionObserver: 'IntersectionObserver' in window,
resizeObserver: 'ResizeObserver' in window,
// CSS features
cssGrid: testCSSSupport('display', 'grid'),
cssFlexbox: testCSSSupport('display', 'flex'),
cssVariables: testCSSVariables(),
cssTransforms: testCSSSupport('transform', 'translateX(1px)'),
cssTransitions: testCSSSupport('transition', 'all 0.3s'),
cssFilters: testCSSSupport('filter', 'blur(1px)'),
// Media features
webGL: testWebGL(),
canvas: testCanvas(),
svg: testSVG(),
webAudio: 'AudioContext' in window || 'webkitAudioContext' in window,
// Network features
serviceWorker: 'serviceWorker' in navigator,
webSockets: 'WebSocket' in window,
webRTC: testWebRTC(),
// Input features
touch: testTouch(),
pointer: 'PointerEvent' in window,
// Performance features
performanceAPI: 'performance' in window,
navigationTiming: !!(window.performance && window.performance.timing),
// Safari-specific issues
safariPrivateBrowsing: testSafariPrivateBrowsing(),
safariITP: testSafariITP()
};
_hasRunDetection = true;
console.log('[Feature Detection] Capabilities detected:', features);
return features;
}
/**
* Test localStorage availability
*/
function testLocalStorage() {
try {
var test = '__test__';
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
/**
* Test sessionStorage availability
*/
function testSessionStorage() {
try {
var test = '__test__';
sessionStorage.setItem(test, test);
sessionStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
/**
* Test IndexedDB availability
*/
function testIndexedDB() {
try {
return !!(window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB);
} catch(e) {
return false;
}
}
/**
* Test ES6 support
*/
function testES6Support() {
try {
// Test arrow functions
eval('(() => {})');
// Test template literals
eval('`test`');
// Test let/const
eval('let a = 1; const b = 2;');
// Test destructuring
eval('const {a, b} = {a: 1, b: 2}');
return true;
} catch(e) {
return false;
}
}
/**
* Test async/await support
*/
function testAsyncSupport() {
try {
eval('(async function() {})');
return true;
} catch(e) {
return false;
}
}
/**
* Test CSS support
*/
function testCSSSupport(property, value) {
// Use CSS.supports if available
if (window.CSS && window.CSS.supports) {
return CSS.supports(property, value);
}
// Fallback method
var el = document.createElement('div');
el.style.cssText = property + ':' + value;
return el.style[property] !== '';
}
/**
* Test CSS variables support
*/
function testCSSVariables() {
return testCSSSupport('--test', '1px');
}
/**
* Test WebGL support
*/
function testWebGL() {
try {
var canvas = document.createElement('canvas');
return !!(window.WebGLRenderingContext &&
(canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
} catch(e) {
return false;
}
}
/**
* Test Canvas support
*/
function testCanvas() {
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
/**
* Test SVG support
*/
function testSVG() {
return !!(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
}
/**
* Test WebRTC support
*/
function testWebRTC() {
return !!(window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection);
}
/**
* Test touch support
*/
function testTouch() {
return ('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0);
}
/**
* Test Safari private browsing mode
*/
function testSafariPrivateBrowsing() {
try {
// Safari private mode throws quota exceeded immediately
localStorage.setItem('__private_test__', '1');
localStorage.removeItem('__private_test__');
return false;
} catch(e) {
// Check if it's quota exceeded error
if (e.code === 22 || e.code === 1014 || e.name === 'QuotaExceededError') {
return true;
}
return false;
}
}
/**
* Test Safari ITP restrictions
*/
function testSafariITP() {
// Check if this looks like Safari
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
if (!isSafari) {
return false;
}
// Safari with ITP has specific storage restrictions
// This is a heuristic check
try {
// Check if third-party cookies are blocked
var testCookie = '__itp_test__=1;SameSite=None;Secure';
document.cookie = testCookie;
var hasITP = document.cookie.indexOf('__itp_test__') === -1;
// Clean up
if (!hasITP) {
document.cookie = '__itp_test__=;expires=Thu, 01 Jan 1970 00:00:00 UTC;';
}
return hasITP;
} catch(e) {
return false;
}
}
/**
* Get feature support level
*/
function getSupportLevel() {
if (!_hasRunDetection) {
detectAll();
}
var critical = [
'localStorage',
'sessionStorage',
'cookies',
'es6',
'promises',
'mutationObserver',
'cssFlexbox'
];
var enhanced = [
'fetch',
'async',
'intersectionObserver',
'cssGrid',
'cssVariables'
];
var allCritical = critical.every(function(feature) {
return features[feature];
});
var allEnhanced = enhanced.every(function(feature) {
return features[feature];
});
if (!allCritical) {
return 'minimal';
} else if (!allEnhanced) {
return 'basic';
} else {
return 'full';
}
}
/**
* Check if feature is supported
*/
function isSupported(feature) {
if (!_hasRunDetection) {
detectAll();
}
return !!features[feature];
}
/**
* Get recommended polyfills
*/
function getRecommendedPolyfills() {
if (!_hasRunDetection) {
detectAll();
}
var polyfills = [];
if (!features.promises) {
polyfills.push('promise-polyfill');
}
if (!features.fetch) {
polyfills.push('whatwg-fetch');
}
if (!features.intersectionObserver) {
polyfills.push('intersection-observer');
}
if (!features.cssVariables) {
polyfills.push('css-vars-ponyfill');
}
return polyfills;
}
/**
* Initialize and run detection
*/
function init() {
detectAll();
// Add data attributes to body for CSS targeting
var body = document.body;
if (body) {
body.setAttribute('data-feature-level', getSupportLevel());
// Add specific feature flags
if (features.safariPrivateBrowsing) {
body.setAttribute('data-safari-private', 'true');
}
if (features.safariITP) {
body.setAttribute('data-safari-itp', 'true');
}
if (!features.es6) {
body.setAttribute('data-legacy-js', 'true');
}
}
return features;
}
// Public API
return {
init: init,
detectAll: detectAll,
isSupported: isSupported,
getSupportLevel: getSupportLevel,
getRecommendedPolyfills: getRecommendedPolyfills,
features: function() { return features; }
};
})();
// Initialize on DOM ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
HVACFeatureDetection.init();
});
} else {
HVACFeatureDetection.init();
}
// Make globally available
window.HVACFeatureDetection = HVACFeatureDetection;