Files
michaelschiemer/src/Application/Controller/api-manager.view.php
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

1530 lines
55 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<main class="demo-container">
<section class="hero-section">
<h1>🚀 API Manager Demo</h1>
<p class="hero-description">Zentrale Verwaltung aller Web APIs für moderne Browser-Features</p>
</section>
<div class="demo-grid">
<!-- API Manager Status -->
<section class="demo-card">
<h2>📊 API Manager Status</h2>
<button class="btn btn-primary" onclick="initializeAPIManager()">Initialize API Manager</button>
<button class="btn btn-secondary" onclick="getAPIManagerStatus()">Get Status</button>
<div id="api-manager-status" class="results-box"></div>
</section>
<!-- Observer APIs -->
<section class="demo-card">
<h2>👀 Observer APIs</h2>
<div class="button-group">
<h3>Intersection Observer</h3>
<button class="btn btn-primary" onclick="createIntersectionObserver()">Create Observer</button>
<button class="btn btn-secondary" onclick="addObserverTarget()">Add Target</button>
<div class="observer-target" id="intersection-target" style="height: 100px; background: #f0f0f0; margin: 10px 0; padding: 20px; text-align: center;">
Target Element - Scroll to observe
</div>
</div>
<div class="button-group">
<h3>Resize Observer</h3>
<button class="btn btn-primary" onclick="createResizeObserver()">Create Resize Observer</button>
<button class="btn btn-secondary" onclick="testResize()">Test Resize</button>
<div class="resizable-target" id="resize-target" style="width: 200px; height: 100px; background: #e0e0ff; margin: 10px 0; padding: 10px; resize: both; overflow: auto;">
Resize me to see the observer in action
</div>
</div>
<div class="button-group">
<h3>Mutation Observer</h3>
<button class="btn btn-primary" onclick="createMutationObserver()">Create Mutation Observer</button>
<button class="btn btn-secondary" onclick="triggerMutation()">Trigger Mutation</button>
<div id="mutation-target" style="background: #ffe0e0; margin: 10px 0; padding: 10px;">
Original content - will be modified
</div>
</div>
<div id="observer-results" class="results-box"></div>
</section>
<!-- Media APIs -->
<section class="demo-card">
<h2>📹 Media APIs</h2>
<div class="button-group">
<h3>Camera & Microphone</h3>
<button class="btn btn-primary" onclick="requestCameraAccess()">Request Camera</button>
<button class="btn btn-primary" onclick="requestMicrophoneAccess()">Request Microphone</button>
<button class="btn btn-success" onclick="startVideoCall()">Start Video Call</button>
<button class="btn btn-danger" onclick="stopMediaStreams()">Stop All Streams</button>
<video id="camera-preview" width="200" height="150" autoplay muted style="background: #000; display: none; margin: 10px 0;"></video>
</div>
<div class="button-group">
<h3>Screen Sharing</h3>
<button class="btn btn-primary" onclick="startScreenShare()">Start Screen Share</button>
<button class="btn btn-secondary" onclick="stopScreenShare()">Stop Screen Share</button>
<video id="screen-preview" width="300" height="200" autoplay muted style="background: #000; display: none; margin: 10px 0;"></video>
</div>
<div id="media-results" class="results-box"></div>
</section>
<!-- Storage APIs -->
<section class="demo-card">
<h2>💾 Storage APIs</h2>
<div class="button-group">
<h3>IndexedDB</h3>
<button class="btn btn-primary" onclick="initializeIndexedDB()">Initialize IndexedDB</button>
<button class="btn btn-secondary" onclick="storeDataIndexedDB()">Store Test Data</button>
<button class="btn btn-secondary" onclick="retrieveDataIndexedDB()">Retrieve Data</button>
<button class="btn btn-outline" onclick="clearIndexedDB()">Clear Database</button>
</div>
<div class="button-group">
<h3>Cache API</h3>
<button class="btn btn-primary" onclick="initializeCacheAPI()">Initialize Cache</button>
<button class="btn btn-secondary" onclick="cacheResources()">Cache Resources</button>
<button class="btn btn-secondary" onclick="retrieveCachedData()">Retrieve Cached</button>
<button class="btn btn-outline" onclick="clearCache()">Clear Cache</button>
</div>
<div class="button-group">
<h3>Local Storage</h3>
<button class="btn btn-primary" onclick="testLocalStorage()">Test Local Storage</button>
<button class="btn btn-secondary" onclick="testSessionStorage()">Test Session Storage</button>
<button class="btn btn-outline" onclick="getStorageInfo()">Get Storage Info</button>
</div>
<div id="storage-results" class="results-box"></div>
</section>
<!-- Device APIs -->
<section class="demo-card">
<h2>📱 Device APIs</h2>
<div class="button-group">
<h3>Geolocation</h3>
<button class="btn btn-primary" onclick="getCurrentLocation()">Get Current Location</button>
<button class="btn btn-secondary" onclick="watchPosition()">Watch Position</button>
<button class="btn btn-outline" onclick="stopWatchingPosition()">Stop Watching</button>
</div>
<div class="button-group">
<h3>Device Sensors</h3>
<button class="btn btn-primary" onclick="getDeviceMotion()">Device Motion</button>
<button class="btn btn-secondary" onclick="getDeviceOrientation()">Device Orientation</button>
<button class="btn btn-secondary" onclick="testVibration()">Test Vibration</button>
</div>
<div class="button-group">
<h3>Network Information</h3>
<button class="btn btn-primary" onclick="getNetworkInfo()">Get Network Info</button>
<button class="btn btn-secondary" onclick="monitorConnection()">Monitor Connection</button>
</div>
<div id="device-results" class="results-box"></div>
</section>
<!-- Web Animations API -->
<section class="demo-card">
<h2> Web Animations API</h2>
<div class="button-group">
<h3>Basic Animations</h3>
<button class="btn btn-primary" onclick="createBasicAnimation()">Basic Animation</button>
<button class="btn btn-secondary" onclick="createKeyframeAnimation()">Keyframe Animation</button>
<button class="btn btn-secondary" onclick="createComplexAnimation()">Complex Animation</button>
<div class="animation-target" id="animation-box" style="width: 100px; height: 100px; background: #4CAF50; margin: 20px auto; border-radius: 8px;"></div>
</div>
<div class="button-group">
<h3>Animation Controls</h3>
<button class="btn btn-success" onclick="playAnimations()">Play All</button>
<button class="btn btn-warning" onclick="pauseAnimations()">Pause All</button>
<button class="btn btn-danger" onclick="cancelAnimations()">Cancel All</button>
<button class="btn btn-outline" onclick="getAnimationStatus()">Get Status</button>
</div>
<div id="animation-results" class="results-box"></div>
</section>
<!-- Worker APIs -->
<section class="demo-card">
<h2>⚙️ Worker APIs</h2>
<div class="button-group">
<h3>Web Worker</h3>
<button class="btn btn-primary" onclick="createWebWorker()">Create Web Worker</button>
<button class="btn btn-secondary" onclick="sendWorkerMessage()">Send Message</button>
<button class="btn btn-outline" onclick="terminateWorker()">Terminate Worker</button>
</div>
<div class="button-group">
<h3>Service Worker</h3>
<button class="btn btn-primary" onclick="registerServiceWorker()">Register Service Worker</button>
<button class="btn btn-secondary" onclick="updateServiceWorker()">Update Service Worker</button>
<button class="btn btn-outline" onclick="getServiceWorkerStatus()">Get SW Status</button>
</div>
<div id="worker-results" class="results-box"></div>
</section>
<!-- Performance APIs -->
<section class="demo-card">
<h2> Performance APIs</h2>
<div class="button-group">
<h3>Performance Monitoring</h3>
<button class="btn btn-primary" onclick="measurePerformance()">Measure Performance</button>
<button class="btn btn-secondary" onclick="getPerformanceEntries()">Get Performance Entries</button>
<button class="btn btn-secondary" onclick="createPerformanceMark()">Create Performance Mark</button>
</div>
<div class="button-group">
<h3>Resource Timing</h3>
<button class="btn btn-primary" onclick="getResourceTiming()">Get Resource Timing</button>
<button class="btn btn-secondary" onclick="measureNavigationTiming()">Navigation Timing</button>
<button class="btn btn-outline" onclick="clearPerformanceData()">Clear Performance Data</button>
</div>
<div id="performance-results" class="results-box"></div>
</section>
<!-- Comprehensive Test -->
<section class="demo-card full-width">
<h2>🧪 Comprehensive API Test</h2>
<div class="button-group">
<button class="btn btn-success" onclick="runFullAPITest()">Run Full API Test Suite</button>
<button class="btn btn-primary" onclick="createIntegratedWorkflow()">Create Integrated Workflow</button>
<button class="btn btn-outline" onclick="generateAPIReport()">Generate API Report</button>
</div>
<div id="comprehensive-results" class="results-box"></div>
</section>
</div>
</main>
<style>
.demo-container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem 1rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.hero-section {
text-align: center;
margin-bottom: 3rem;
padding: 2rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 12px;
}
.hero-section h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
font-weight: 700;
}
.hero-description {
font-size: 1.2rem;
opacity: 0.9;
margin: 0;
}
.demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 2rem;
margin-bottom: 2rem;
}
.demo-card {
background: white;
border-radius: 12px;
padding: 2rem;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
border: 1px solid #e0e0e0;
}
.demo-card.full-width {
grid-column: 1 / -1;
}
.demo-card h2 {
color: #333;
margin-bottom: 1.5rem;
font-size: 1.5rem;
font-weight: 600;
border-bottom: 2px solid #f0f0f0;
padding-bottom: 0.5rem;
}
.demo-card h3 {
color: #555;
margin: 1.5rem 0 1rem 0;
font-size: 1.1rem;
font-weight: 500;
}
.button-group {
margin-bottom: 1.5rem;
}
.button-group:last-of-type {
margin-bottom: 1rem;
}
.btn {
display: inline-block;
padding: 0.75rem 1rem;
margin: 0.25rem 0.5rem 0.25rem 0;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
text-decoration: none;
transition: all 0.2s ease;
min-width: 120px;
text-align: center;
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-primary:hover {
background: #0056b3;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-secondary:hover {
background: #545b62;
}
.btn-success {
background: #28a745;
color: white;
}
.btn-success:hover {
background: #1e7e34;
}
.btn-warning {
background: #ffc107;
color: #212529;
}
.btn-warning:hover {
background: #d39e00;
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn-danger:hover {
background: #bd2130;
}
.btn-info {
background: #17a2b8;
color: white;
}
.btn-info:hover {
background: #117a8b;
}
.btn-outline {
background: transparent;
color: #666;
border: 2px solid #ddd;
}
.btn-outline:hover {
background: #f8f9fa;
border-color: #aaa;
}
.results-box {
margin-top: 1rem;
padding: 1rem;
background: #f8f9fa;
border-radius: 6px;
border: 1px solid #dee2e6;
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
font-size: 0.85rem;
line-height: 1.5;
max-height: 300px;
overflow-y: auto;
}
.results-box:empty {
display: none;
}
.form-group {
margin-bottom: 1.5rem;
}
.input-group {
margin-bottom: 1rem;
}
.input-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #555;
}
.input-group input {
width: 100%;
padding: 0.75rem;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 1rem;
}
.input-group input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
}
.observer-target,
.resizable-target,
.animation-target {
transition: all 0.3s ease;
}
.observer-target.observed {
background: #d4edda !important;
border: 2px solid #28a745;
}
.resizable-target.resizing {
background: #d1ecf1 !important;
border: 2px solid #17a2b8;
}
.status-indicator {
display: inline-block;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
margin-left: 0.5rem;
}
.status-supported {
background: #d4edda;
color: #155724;
}
.status-unsupported {
background: #f8d7da;
color: #721c24;
}
.status-granted {
background: #d1ecf1;
color: #0c5460;
}
/* Responsive Design */
@media (max-width: 768px) {
.demo-grid {
grid-template-columns: 1fr;
}
.demo-container {
padding: 1rem 0.5rem;
}
.demo-card {
padding: 1.5rem;
}
.btn {
min-width: 100px;
font-size: 0.8rem;
padding: 0.6rem 0.8rem;
}
}
</style>
<script>
// Initialize variables
let apiManager = null;
let observers = {
intersection: null,
resize: null,
mutation: null
};
let mediaStreams = [];
let animations = [];
let workers = {
web: null,
service: null
};
let positionWatcher = null;
// Wait for DOM and framework to load
document.addEventListener('DOMContentLoaded', function() {
// Check if API Manager is available
if (typeof window.API !== 'undefined') {
displayResult('api-manager-status', '✅ API Manager is available and ready to use');
} else {
displayResult('api-manager-status', '⚠️ API Manager not yet loaded. Click "Initialize" to try again.');
}
});
// Utility function to display results
function displayResult(containerId, message, type = 'info') {
const container = document.getElementById(containerId);
if (!container) return;
const timestamp = new Date().toLocaleTimeString();
const colorClass = type === 'error' ? 'color: #dc3545' :
type === 'success' ? 'color: #28a745' :
type === 'warning' ? 'color: #ffc107' : 'color: #17a2b8';
container.innerHTML += `<div style="${colorClass}; margin-bottom: 0.5rem;">
[${timestamp}] ${message}
</div>`;
container.scrollTop = container.scrollHeight;
}
function clearResults(containerId) {
const container = document.getElementById(containerId);
if (container) container.innerHTML = '';
}
// API Manager Functions
function initializeAPIManager() {
try {
if (window.API) {
apiManager = window.API;
displayResult('api-manager-status', '✅ API Manager initialized successfully', 'success');
displayResult('api-manager-status', JSON.stringify({
hasPermissions: !!apiManager.permissions,
hasBiometric: !!apiManager.biometric,
hasObserver: !!apiManager.observer,
hasMedia: !!apiManager.media,
hasStorage: !!apiManager.storage,
hasDevice: !!apiManager.device,
hasAnimation: !!apiManager.animation,
hasWorker: !!apiManager.worker,
hasPerformance: !!apiManager.performance
}, null, 2));
} else {
displayResult('api-manager-status', '❌ API Manager not available in window.API', 'error');
}
} catch (error) {
displayResult('api-manager-status', `❌ Error initializing API Manager: ${error.message}`, 'error');
}
}
function getAPIManagerStatus() {
try {
if (!apiManager) {
displayResult('api-manager-status', '⚠️ API Manager not initialized', 'warning');
return;
}
const status = {
initialized: true,
modules: Object.keys(apiManager).filter(key => typeof apiManager[key] === 'object'),
config: apiManager.config || 'No config available'
};
displayResult('api-manager-status', JSON.stringify(status, null, 2), 'success');
} catch (error) {
displayResult('api-manager-status', `❌ Error getting status: ${error.message}`, 'error');
}
}
// Observer API Functions
function createIntersectionObserver() {
try {
if (!apiManager?.observer) {
displayResult('observer-results', '❌ Observer API not available', 'error');
return;
}
const target = document.getElementById('intersection-target');
if (!target) {
displayResult('observer-results', '❌ Target element not found', 'error');
return;
}
observers.intersection = apiManager.observer.intersection([target], (entries) => {
entries.forEach(entry => {
const isVisible = entry.isIntersecting;
entry.element.classList.toggle('observed', isVisible);
displayResult('observer-results', `📍 Intersection: ${isVisible ? 'Visible' : 'Hidden'} (ratio: ${entry.intersectionRatio.toFixed(2)})`);
});
}, {
threshold: [0, 0.5, 1.0],
rootMargin: '0px'
});
displayResult('observer-results', '✅ Intersection Observer created and observing target', 'success');
} catch (error) {
displayResult('observer-results', `❌ Error creating Intersection Observer: ${error.message}`, 'error');
}
}
function addObserverTarget() {
displayResult('observer-results', '📝 Scroll up/down to see the intersection observer in action');
}
function createResizeObserver() {
try {
if (!apiManager?.observer) {
displayResult('observer-results', '❌ Observer API not available', 'error');
return;
}
const target = document.getElementById('resize-target');
if (!target) {
displayResult('observer-results', '❌ Resize target not found', 'error');
return;
}
observers.resize = apiManager.observer.resize([target], (entries) => {
entries.forEach(entry => {
const { width, height } = entry.dimensions;
entry.element.classList.add('resizing');
setTimeout(() => entry.element.classList.remove('resizing'), 300);
displayResult('observer-results', `📐 Resize: ${Math.round(width)}x${Math.round(height)}px`);
});
});
displayResult('observer-results', '✅ Resize Observer created and observing target', 'success');
} catch (error) {
displayResult('observer-results', `❌ Error creating Resize Observer: ${error.message}`, 'error');
}
}
function testResize() {
const target = document.getElementById('resize-target');
if (target) {
const newWidth = Math.random() * 300 + 150;
const newHeight = Math.random() * 200 + 100;
target.style.width = `${newWidth}px`;
target.style.height = `${newHeight}px`;
displayResult('observer-results', `🔄 Programmatically resized to ${Math.round(newWidth)}x${Math.round(newHeight)}px`);
}
}
function createMutationObserver() {
try {
if (!apiManager?.observer) {
displayResult('observer-results', '❌ Observer API not available', 'error');
return;
}
const target = document.getElementById('mutation-target');
if (!target) {
displayResult('observer-results', '❌ Mutation target not found', 'error');
return;
}
observers.mutation = apiManager.observer.mutation(target, (mutations) => {
mutations.forEach(mutation => {
displayResult('observer-results', `🔄 Mutation: ${mutation.type} on ${mutation.target.tagName || 'text'}`);
});
}, {
childList: true,
attributes: true,
subtree: true,
characterData: true
});
displayResult('observer-results', '✅ Mutation Observer created and observing target', 'success');
} catch (error) {
displayResult('observer-results', `❌ Error creating Mutation Observer: ${error.message}`, 'error');
}
}
function triggerMutation() {
const target = document.getElementById('mutation-target');
if (target) {
const timestamp = new Date().toLocaleTimeString();
target.innerHTML = `Modified content at ${timestamp}`;
target.setAttribute('data-modified', timestamp);
}
}
// Media API Functions
async function requestCameraAccess() {
try {
if (!apiManager?.media) {
displayResult('media-results', '❌ Media API not available', 'error');
return;
}
const stream = await apiManager.media.getUserMedia({ video: true });
mediaStreams.push(stream);
const video = document.getElementById('camera-preview');
video.srcObject = stream;
video.style.display = 'block';
displayResult('media-results', '✅ Camera access granted and preview started', 'success');
} catch (error) {
displayResult('media-results', `❌ Camera access failed: ${error.message}`, 'error');
}
}
async function requestMicrophoneAccess() {
try {
if (!apiManager?.media) {
displayResult('media-results', '❌ Media API not available', 'error');
return;
}
const stream = await apiManager.media.getUserMedia({ audio: true });
mediaStreams.push(stream);
displayResult('media-results', '✅ Microphone access granted', 'success');
} catch (error) {
displayResult('media-results', `❌ Microphone access failed: ${error.message}`, 'error');
}
}
async function startVideoCall() {
try {
if (!apiManager?.media) {
displayResult('media-results', '❌ Media API not available', 'error');
return;
}
const stream = await apiManager.media.getUserMedia({
video: { width: 1280, height: 720 },
audio: true
});
mediaStreams.push(stream);
const video = document.getElementById('camera-preview');
video.srcObject = stream;
video.style.display = 'block';
displayResult('media-results', '✅ Video call stream started with audio/video', 'success');
} catch (error) {
displayResult('media-results', `❌ Video call failed: ${error.message}`, 'error');
}
}
async function startScreenShare() {
try {
if (!apiManager?.media) {
displayResult('media-results', '❌ Media API not available', 'error');
return;
}
const stream = await apiManager.media.getDisplayMedia({ video: true });
mediaStreams.push(stream);
const video = document.getElementById('screen-preview');
video.srcObject = stream;
video.style.display = 'block';
displayResult('media-results', '✅ Screen sharing started', 'success');
} catch (error) {
displayResult('media-results', `❌ Screen sharing failed: ${error.message}`, 'error');
}
}
function stopScreenShare() {
const video = document.getElementById('screen-preview');
if (video.srcObject) {
video.srcObject.getTracks().forEach(track => track.stop());
video.srcObject = null;
video.style.display = 'none';
displayResult('media-results', '✅ Screen sharing stopped', 'success');
}
}
function stopMediaStreams() {
mediaStreams.forEach(stream => {
stream.getTracks().forEach(track => track.stop());
});
mediaStreams = [];
document.getElementById('camera-preview').style.display = 'none';
document.getElementById('screen-preview').style.display = 'none';
displayResult('media-results', '✅ All media streams stopped', 'success');
}
// Storage API Functions
async function initializeIndexedDB() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
await apiManager.storage.indexedDB.open('APITestDB', 1, (db, oldVersion) => {
if (oldVersion < 1) {
const store = db.createObjectStore('testData', { keyPath: 'id', autoIncrement: true });
store.createIndex('timestamp', 'timestamp', { unique: false });
}
});
displayResult('storage-results', '✅ IndexedDB initialized successfully', 'success');
} catch (error) {
displayResult('storage-results', `❌ IndexedDB initialization failed: ${error.message}`, 'error');
}
}
async function storeDataIndexedDB() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
const testData = {
message: 'Hello from IndexedDB!',
timestamp: Date.now(),
randomValue: Math.random()
};
await apiManager.storage.indexedDB.set('testData', testData);
displayResult('storage-results', `✅ Data stored in IndexedDB: ${JSON.stringify(testData)}`, 'success');
} catch (error) {
displayResult('storage-results', `❌ IndexedDB store failed: ${error.message}`, 'error');
}
}
async function retrieveDataIndexedDB() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
const data = await apiManager.storage.indexedDB.getAll('testData');
displayResult('storage-results', `✅ Retrieved from IndexedDB: ${JSON.stringify(data, null, 2)}`, 'success');
} catch (error) {
displayResult('storage-results', `❌ IndexedDB retrieval failed: ${error.message}`, 'error');
}
}
async function clearIndexedDB() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
await apiManager.storage.indexedDB.clear('testData');
displayResult('storage-results', '✅ IndexedDB cleared', 'success');
} catch (error) {
displayResult('storage-results', `❌ IndexedDB clear failed: ${error.message}`, 'error');
}
}
async function initializeCacheAPI() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
await apiManager.storage.cache.open('api-test-cache');
displayResult('storage-results', '✅ Cache API initialized', 'success');
} catch (error) {
displayResult('storage-results', `❌ Cache API initialization failed: ${error.message}`, 'error');
}
}
async function cacheResources() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
const cache = await apiManager.storage.cache.open('api-test-cache');
await cache.addAll([
'/css/admin.css',
'/js/chat.js'
]);
displayResult('storage-results', '✅ Resources cached successfully', 'success');
} catch (error) {
displayResult('storage-results', `❌ Resource caching failed: ${error.message}`, 'error');
}
}
async function retrieveCachedData() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
const cache = await apiManager.storage.cache.open('api-test-cache');
const keys = await cache.keys();
displayResult('storage-results', `✅ Cached resources: ${keys.map(req => req.url).join(', ')}`, 'success');
} catch (error) {
displayResult('storage-results', `❌ Cache retrieval failed: ${error.message}`, 'error');
}
}
async function clearCache() {
try {
if (!apiManager?.storage) {
displayResult('storage-results', '❌ Storage API not available', 'error');
return;
}
await caches.delete('api-test-cache');
displayResult('storage-results', '✅ Cache cleared', 'success');
} catch (error) {
displayResult('storage-results', `❌ Cache clear failed: ${error.message}`, 'error');
}
}
function testLocalStorage() {
try {
const testData = { message: 'Hello from localStorage!', timestamp: Date.now() };
localStorage.setItem('apiTest', JSON.stringify(testData));
const retrieved = JSON.parse(localStorage.getItem('apiTest'));
displayResult('storage-results', `✅ LocalStorage test: ${JSON.stringify(retrieved)}`, 'success');
} catch (error) {
displayResult('storage-results', `❌ LocalStorage test failed: ${error.message}`, 'error');
}
}
function testSessionStorage() {
try {
const testData = { message: 'Hello from sessionStorage!', timestamp: Date.now() };
sessionStorage.setItem('apiTest', JSON.stringify(testData));
const retrieved = JSON.parse(sessionStorage.getItem('apiTest'));
displayResult('storage-results', `✅ SessionStorage test: ${JSON.stringify(retrieved)}`, 'success');
} catch (error) {
displayResult('storage-results', `❌ SessionStorage test failed: ${error.message}`, 'error');
}
}
async function getStorageInfo() {
try {
if ('storage' in navigator && 'estimate' in navigator.storage) {
const estimate = await navigator.storage.estimate();
displayResult('storage-results', `📊 Storage: ${(estimate.usage / 1024 / 1024).toFixed(2)}MB used / ${(estimate.quota / 1024 / 1024).toFixed(2)}MB total`, 'success');
} else {
displayResult('storage-results', '❌ Storage estimation not supported', 'error');
}
} catch (error) {
displayResult('storage-results', `❌ Storage info failed: ${error.message}`, 'error');
}
}
// Device API Functions
async function getCurrentLocation() {
try {
if (!apiManager?.device) {
displayResult('device-results', '❌ Device API not available', 'error');
return;
}
const position = await apiManager.device.geolocation.getCurrent();
const { latitude, longitude, accuracy } = position;
displayResult('device-results', `📍 Location: ${latitude.toFixed(6)}, ${longitude.toFixed(6)} (±${accuracy}m)`, 'success');
} catch (error) {
displayResult('device-results', `❌ Geolocation failed: ${error.message}`, 'error');
}
}
function watchPosition() {
try {
if (!apiManager?.device) {
displayResult('device-results', '❌ Device API not available', 'error');
return;
}
const watcher = apiManager.device.geolocation.watch(
(position) => {
if (position.error) {
displayResult('device-results', `❌ Position watch error: ${position.error.message}`, 'error');
} else {
displayResult('device-results', `👀 Watching: ${position.latitude.toFixed(6)}, ${position.longitude.toFixed(6)} (±${position.accuracy}m)`);
}
}
);
positionWatcher = watcher;
displayResult('device-results', '✅ Started watching position', 'success');
} catch (error) {
displayResult('device-results', `❌ Position watch failed: ${error.message}`, 'error');
}
}
function stopWatchingPosition() {
if (positionWatcher) {
positionWatcher.stop();
positionWatcher = null;
displayResult('device-results', '✅ Stopped watching position', 'success');
}
}
function getDeviceMotion() {
if ('DeviceMotionEvent' in window) {
const handler = (event) => {
const acc = event.accelerationIncludingGravity;
if (acc) {
displayResult('device-results', `📱 Motion: x:${acc.x?.toFixed(2)}, y:${acc.y?.toFixed(2)}, z:${acc.z?.toFixed(2)}`);
window.removeEventListener('devicemotion', handler);
}
};
window.addEventListener('devicemotion', handler);
setTimeout(() => window.removeEventListener('devicemotion', handler), 5000);
displayResult('device-results', '✅ Listening for device motion (5s)...', 'success');
} else {
displayResult('device-results', '❌ Device Motion not supported', 'error');
}
}
function getDeviceOrientation() {
if ('DeviceOrientationEvent' in window) {
const handler = (event) => {
displayResult('device-results', `🧭 Orientation: α:${event.alpha?.toFixed(1)}°, β:${event.beta?.toFixed(1)}°, γ:${event.gamma?.toFixed(1)}°`);
window.removeEventListener('deviceorientation', handler);
};
window.addEventListener('deviceorientation', handler);
setTimeout(() => window.removeEventListener('deviceorientation', handler), 5000);
displayResult('device-results', '✅ Listening for device orientation (5s)...', 'success');
} else {
displayResult('device-results', '❌ Device Orientation not supported', 'error');
}
}
function testVibration() {
if ('vibrate' in navigator) {
navigator.vibrate([200, 100, 200]);
displayResult('device-results', '✅ Vibration triggered', 'success');
} else {
displayResult('device-results', '❌ Vibration not supported', 'error');
}
}
function getNetworkInfo() {
if ('connection' in navigator) {
const conn = navigator.connection;
displayResult('device-results', `🌐 Network: ${conn.effectiveType}, ${conn.downlink}Mbps, rtt:${conn.rtt}ms`, 'success');
} else {
displayResult('device-results', '❌ Network Information API not supported', 'error');
}
}
function monitorConnection() {
const updateStatus = () => {
const status = navigator.onLine ? 'Online' : 'Offline';
displayResult('device-results', `🔌 Connection: ${status}`);
};
updateStatus();
window.addEventListener('online', updateStatus);
window.addEventListener('offline', updateStatus);
displayResult('device-results', '✅ Monitoring connection status', 'success');
}
// Web Animations API Functions
function createBasicAnimation() {
try {
if (!apiManager?.animation) {
displayResult('animation-results', '❌ Animation API not available', 'error');
return;
}
const target = document.getElementById('animation-box');
const animation = apiManager.animation.animate(target, [
{ transform: 'translateX(0px)', backgroundColor: '#4CAF50' },
{ transform: 'translateX(200px)', backgroundColor: '#2196F3' },
{ transform: 'translateX(0px)', backgroundColor: '#4CAF50' }
], {
duration: 2000,
easing: 'ease-in-out'
});
animations.push(animation);
displayResult('animation-results', '✅ Basic animation created and started', 'success');
} catch (error) {
displayResult('animation-results', `❌ Basic animation failed: ${error.message}`, 'error');
}
}
function createKeyframeAnimation() {
try {
if (!apiManager?.animation) {
displayResult('animation-results', '❌ Animation API not available', 'error');
return;
}
const target = document.getElementById('animation-box');
const animation = apiManager.animation.animate(target, [
{ transform: 'scale(1) rotate(0deg)', borderRadius: '8px' },
{ transform: 'scale(1.5) rotate(180deg)', borderRadius: '50%' },
{ transform: 'scale(1) rotate(360deg)', borderRadius: '8px' }
], {
duration: 3000,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
iterations: 2
});
animations.push(animation);
displayResult('animation-results', '✅ Keyframe animation created', 'success');
} catch (error) {
displayResult('animation-results', `❌ Keyframe animation failed: ${error.message}`, 'error');
}
}
function createComplexAnimation() {
try {
if (!apiManager?.animation) {
displayResult('animation-results', '❌ Animation API not available', 'error');
return;
}
const target = document.getElementById('animation-box');
// Multiple simultaneous animations
const moveAnimation = apiManager.animation.animate(target, [
{ transform: 'translateY(0px)' },
{ transform: 'translateY(-100px)' },
{ transform: 'translateY(0px)' }
], {
duration: 2000,
easing: 'ease-out'
});
const colorAnimation = apiManager.animation.animate(target, [
{ backgroundColor: '#4CAF50' },
{ backgroundColor: '#FF9800' },
{ backgroundColor: '#E91E63' },
{ backgroundColor: '#4CAF50' }
], {
duration: 2500,
easing: 'linear'
});
animations.push(moveAnimation, colorAnimation);
displayResult('animation-results', '✅ Complex multi-animation created', 'success');
} catch (error) {
displayResult('animation-results', `❌ Complex animation failed: ${error.message}`, 'error');
}
}
function playAnimations() {
try {
animations.forEach(animation => {
if (animation.playState === 'paused' || animation.playState === 'finished') {
animation.play();
}
});
displayResult('animation-results', `✅ Playing ${animations.length} animations`, 'success');
} catch (error) {
displayResult('animation-results', `❌ Play animations failed: ${error.message}`, 'error');
}
}
function pauseAnimations() {
try {
animations.forEach(animation => {
if (animation.playState === 'running') {
animation.pause();
}
});
displayResult('animation-results', `✅ Paused ${animations.length} animations`, 'success');
} catch (error) {
displayResult('animation-results', `❌ Pause animations failed: ${error.message}`, 'error');
}
}
function cancelAnimations() {
try {
animations.forEach(animation => animation.cancel());
animations = [];
displayResult('animation-results', '✅ All animations cancelled', 'success');
} catch (error) {
displayResult('animation-results', `❌ Cancel animations failed: ${error.message}`, 'error');
}
}
function getAnimationStatus() {
try {
const statuses = animations.map((anim, index) => `#${index + 1}: ${anim.playState}`);
displayResult('animation-results', `📊 Animation Status: ${statuses.join(', ')}`, 'success');
} catch (error) {
displayResult('animation-results', `❌ Get animation status failed: ${error.message}`, 'error');
}
}
// Worker API Functions
function createWebWorker() {
try {
if (!apiManager?.worker) {
displayResult('worker-results', '❌ Worker API not available', 'error');
return;
}
// Create an inline worker for demonstration
const workerCode = `
self.onmessage = function(e) {
const result = e.data * e.data;
self.postMessage({ original: e.data, squared: result });
};
`;
const blob = new Blob([workerCode], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
workers.web = new Worker(workerUrl);
workers.web.onmessage = (e) => {
displayResult('worker-results', `📨 Worker response: ${e.data.original}² = ${e.data.squared}`);
};
displayResult('worker-results', '✅ Web Worker created successfully', 'success');
URL.revokeObjectURL(workerUrl);
} catch (error) {
displayResult('worker-results', `❌ Web Worker creation failed: ${error.message}`, 'error');
}
}
function sendWorkerMessage() {
try {
if (!workers.web) {
displayResult('worker-results', '❌ No Web Worker available', 'error');
return;
}
const randomNumber = Math.floor(Math.random() * 100);
workers.web.postMessage(randomNumber);
displayResult('worker-results', `📤 Sent to worker: ${randomNumber}`, 'success');
} catch (error) {
displayResult('worker-results', `❌ Send worker message failed: ${error.message}`, 'error');
}
}
function terminateWorker() {
try {
if (workers.web) {
workers.web.terminate();
workers.web = null;
displayResult('worker-results', '✅ Web Worker terminated', 'success');
} else {
displayResult('worker-results', '❌ No Web Worker to terminate', 'error');
}
} catch (error) {
displayResult('worker-results', `❌ Worker termination failed: ${error.message}`, 'error');
}
}
function registerServiceWorker() {
try {
if (!apiManager?.worker || !('serviceWorker' in navigator)) {
displayResult('worker-results', '❌ Service Worker not supported', 'error');
return;
}
navigator.serviceWorker.register('/sw.js')
.then(registration => {
displayResult('worker-results', '✅ Service Worker registered successfully', 'success');
workers.service = registration;
})
.catch(error => {
displayResult('worker-results', `❌ Service Worker registration failed: ${error.message}`, 'error');
});
} catch (error) {
displayResult('worker-results', `❌ Service Worker registration error: ${error.message}`, 'error');
}
}
function updateServiceWorker() {
try {
if (workers.service) {
workers.service.update().then(() => {
displayResult('worker-results', '✅ Service Worker update check completed', 'success');
});
} else {
displayResult('worker-results', '❌ No Service Worker registration found', 'error');
}
} catch (error) {
displayResult('worker-results', `❌ Service Worker update failed: ${error.message}`, 'error');
}
}
function getServiceWorkerStatus() {
try {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => {
displayResult('worker-results', `📊 Service Workers: ${registrations.length} registered`, 'success');
registrations.forEach((reg, index) => {
displayResult('worker-results', `#${index + 1}: ${reg.scope}, state: ${reg.active?.state || 'inactive'}`);
});
});
} else {
displayResult('worker-results', '❌ Service Worker not supported', 'error');
}
} catch (error) {
displayResult('worker-results', `❌ Service Worker status failed: ${error.message}`, 'error');
}
}
// Performance API Functions
function measurePerformance() {
try {
if (!apiManager?.performance) {
displayResult('performance-results', '❌ Performance API not available', 'error');
return;
}
const startTime = performance.now();
// Simulate some work
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += Math.sqrt(i);
}
const endTime = performance.now();
const duration = endTime - startTime;
displayResult('performance-results', `⚡ Performance: Operation took ${duration.toFixed(2)}ms`, 'success');
displayResult('performance-results', `📊 Result: ${sum.toFixed(2)}`);
} catch (error) {
displayResult('performance-results', `❌ Performance measurement failed: ${error.message}`, 'error');
}
}
function getPerformanceEntries() {
try {
const entries = performance.getEntriesByType('navigation');
if (entries.length > 0) {
const nav = entries[0];
displayResult('performance-results', `🚀 Navigation: ${nav.loadEventEnd - nav.navigationStart}ms total`, 'success');
displayResult('performance-results', `📡 DNS: ${nav.domainLookupEnd - nav.domainLookupStart}ms`);
displayResult('performance-results', `🔗 Connect: ${nav.connectEnd - nav.connectStart}ms`);
displayResult('performance-results', `📄 DOM: ${nav.domContentLoadedEventEnd - nav.domContentLoadedEventStart}ms`);
}
const resourceEntries = performance.getEntriesByType('resource').slice(0, 5);
displayResult('performance-results', `📚 Resources (first 5): ${resourceEntries.length} entries`);
resourceEntries.forEach(entry => {
displayResult('performance-results', `• ${entry.name.split('/').pop()}: ${entry.duration.toFixed(2)}ms`);
});
} catch (error) {
displayResult('performance-results', `❌ Performance entries failed: ${error.message}`, 'error');
}
}
function createPerformanceMark() {
try {
const markName = `api-test-mark-${Date.now()}`;
performance.mark(markName);
setTimeout(() => {
performance.mark(`${markName}-end`);
performance.measure(`${markName}-duration`, markName, `${markName}-end`);
const measure = performance.getEntriesByName(`${markName}-duration`)[0];
displayResult('performance-results', `🏷️ Performance Mark: ${measure.duration.toFixed(2)}ms`, 'success');
}, Math.random() * 1000);
displayResult('performance-results', `✅ Performance mark created: ${markName}`, 'success');
} catch (error) {
displayResult('performance-results', `❌ Performance mark failed: ${error.message}`, 'error');
}
}
function getResourceTiming() {
try {
const resources = performance.getEntriesByType('resource');
const totalResources = resources.length;
const totalTime = resources.reduce((sum, entry) => sum + entry.duration, 0);
const avgTime = totalTime / totalResources;
displayResult('performance-results', `📊 Resources: ${totalResources} total, ${avgTime.toFixed(2)}ms average`, 'success');
const slowResources = resources.filter(entry => entry.duration > 100);
if (slowResources.length > 0) {
displayResult('performance-results', `🐌 Slow resources (>100ms): ${slowResources.length}`);
slowResources.slice(0, 3).forEach(entry => {
displayResult('performance-results', `• ${entry.name.split('/').pop()}: ${entry.duration.toFixed(2)}ms`);
});
}
} catch (error) {
displayResult('performance-results', `❌ Resource timing failed: ${error.message}`, 'error');
}
}
function measureNavigationTiming() {
try {
const nav = performance.getEntriesByType('navigation')[0];
if (nav) {
const metrics = {
'DNS Lookup': nav.domainLookupEnd - nav.domainLookupStart,
'TCP Connect': nav.connectEnd - nav.connectStart,
'Request': nav.responseStart - nav.requestStart,
'Response': nav.responseEnd - nav.responseStart,
'DOM Processing': nav.domContentLoadedEventEnd - nav.responseEnd,
'Load Complete': nav.loadEventEnd - nav.loadEventStart
};
displayResult('performance-results', '🚀 Navigation Timing:', 'success');
Object.entries(metrics).forEach(([name, time]) => {
displayResult('performance-results', `• ${name}: ${time.toFixed(2)}ms`);
});
}
} catch (error) {
displayResult('performance-results', `❌ Navigation timing failed: ${error.message}`, 'error');
}
}
function clearPerformanceData() {
try {
performance.clearMarks();
performance.clearMeasures();
displayResult('performance-results', '✅ Performance data cleared', 'success');
} catch (error) {
displayResult('performance-results', `❌ Clear performance data failed: ${error.message}`, 'error');
}
}
// Comprehensive Test Functions
async function runFullAPITest() {
displayResult('comprehensive-results', '🧪 Starting comprehensive API test suite...', 'success');
const tests = [
{ name: 'API Manager', fn: () => getAPIManagerStatus() },
{ name: 'Intersection Observer', fn: () => createIntersectionObserver() },
{ name: 'Local Storage', fn: () => testLocalStorage() },
{ name: 'Performance Measurement', fn: () => measurePerformance() },
{ name: 'Network Info', fn: () => getNetworkInfo() },
{ name: 'Basic Animation', fn: () => createBasicAnimation() }
];
let passed = 0;
let failed = 0;
for (const test of tests) {
try {
await test.fn();
passed++;
displayResult('comprehensive-results', `✅ ${test.name}: PASSED`);
} catch (error) {
failed++;
displayResult('comprehensive-results', `❌ ${test.name}: FAILED - ${error.message}`, 'error');
}
// Small delay between tests
await new Promise(resolve => setTimeout(resolve, 100));
}
displayResult('comprehensive-results', `📊 Test Results: ${passed}/${tests.length} passed, ${failed} failed`, passed === tests.length ? 'success' : 'warning');
}
async function createIntegratedWorkflow() {
displayResult('comprehensive-results', '🔄 Creating integrated workflow...', 'success');
try {
// Step 1: Initialize core APIs
await initializeAPIManager();
displayResult('comprehensive-results', '1⃣ API Manager initialized');
// Step 2: Set up observers
createIntersectionObserver();
createResizeObserver();
displayResult('comprehensive-results', '2⃣ Observers configured');
// Step 3: Test storage capabilities
testLocalStorage();
testSessionStorage();
displayResult('comprehensive-results', '3⃣ Storage tested');
// Step 4: Start monitoring
monitorConnection();
displayResult('comprehensive-results', '4⃣ Monitoring started');
// Step 5: Create animations
createBasicAnimation();
displayResult('comprehensive-results', '5⃣ Animations created');
displayResult('comprehensive-results', '✅ Integrated workflow completed successfully', 'success');
} catch (error) {
displayResult('comprehensive-results', `❌ Integrated workflow failed: ${error.message}`, 'error');
}
}
async function generateAPIReport() {
displayResult('comprehensive-results', '📋 Generating comprehensive API report...', 'success');
const report = {
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
apis: {}
};
// Test API availability
const apiTests = {
'Intersection Observer': () => 'IntersectionObserver' in window,
'Resize Observer': () => 'ResizeObserver' in window,
'Mutation Observer': () => 'MutationObserver' in window,
'getUserMedia': () => navigator.mediaDevices?.getUserMedia !== undefined,
'getDisplayMedia': () => navigator.mediaDevices?.getDisplayMedia !== undefined,
'IndexedDB': () => 'indexedDB' in window,
'Cache API': () => 'caches' in window,
'Service Worker': () => 'serviceWorker' in navigator,
'Web Worker': () => 'Worker' in window,
'Web Animations': () => 'animate' in document.createElement('div'),
'Geolocation': () => 'geolocation' in navigator,
'Vibration': () => 'vibrate' in navigator,
'Network Information': () => 'connection' in navigator,
'Performance API': () => 'performance' in window,
'Permissions API': () => 'permissions' in navigator
};
Object.entries(apiTests).forEach(([name, test]) => {
try {
report.apis[name] = test();
} catch (error) {
report.apis[name] = false;
}
});
// Display report
displayResult('comprehensive-results', '📊 API Support Report:', 'success');
displayResult('comprehensive-results', JSON.stringify(report, null, 2));
const supportedCount = Object.values(report.apis).filter(Boolean).length;
const totalCount = Object.keys(report.apis).length;
displayResult('comprehensive-results', `✅ Summary: ${supportedCount}/${totalCount} APIs supported (${Math.round(supportedCount/totalCount*100)}%)`, 'success');
}
</script>