UNPKG

@lovebowls/leagueelements

Version:

League Elements package for LoveBowls

1,030 lines (934 loc) 34.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1.0"> <title>Test LeagueElementConfig API</title> <style> body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; } .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); overflow: hidden; } .header { background: #3498db; color: white; padding: 20px; text-align: center; } .content { padding: 20px; } .controls { margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 5px; border: 1px solid #dee2e6; } .control-group { margin-bottom: 15px; padding: 10px; background: white; border-radius: 3px; border: 1px solid #e9ecef; } .control-group h3 { margin: 0 0 10px 0; color: #495057; font-size: 16px; } .control-row { display: flex; align-items: center; gap: 15px; margin-bottom: 10px; flex-wrap: wrap; } .control-row label { font-weight: bold; min-width: 120px; color: #495057; } .control-row input, .control-row select { padding: 8px 12px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px; } .control-row input[type="number"] { width: 80px; } .control-row input[type="text"] { width: 600px; } .button-group { display: flex; gap: 10px; flex-wrap: wrap; } .btn { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: bold; transition: background-color 0.2s; } .btn-primary { background: #3498db; color: white; } .btn-primary:hover { background: #2980b9; } .btn-success { background: #27ae60; color: white; } .btn-success:hover { background: #229954; } .btn-warning { background: #f39c12; color: white; } .btn-warning:hover { background: #e67e22; } .btn-danger { background: #e74c3c; color: white; } .btn-danger:hover { background: #c0392b; } .btn:disabled { background: #bdc3c7; cursor: not-allowed; } .status { margin: 15px 0; padding: 12px; border-radius: 4px; font-size: 14px; border: 1px solid; } .status.success { background: #d4edda; color: #155724; border-color: #c3e6cb; } .status.error { background: #f8d7da; color: #721c24; border-color: #f5c6cb; } .status.info { background: #d1ecf1; color: #0c5460; border-color: #bee5eb; } .status.warning { background: #fff3cd; color: #856404; border-color: #ffeaa7; } .league-container { min-height: 500px; border: 2px solid #dee2e6; border-radius: 5px; background: #fafafa; position: relative; } .league-container.loading { display: flex; align-items: center; justify-content: center; } .event-log { margin-top: 20px; padding: 15px; background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 5px; max-height: 300px; overflow-y: auto; } .event-log h3 { margin: 0 0 10px 0; color: #495057; } .event-entry { padding: 5px 0; border-bottom: 1px solid #e9ecef; font-family: monospace; font-size: 12px; } .event-entry:last-child { border-bottom: none; } .event-time { color: #6c757d; font-size: 11px; } .event-message { color: #495057; } .event-error { color: #dc3545; } .event-success { color: #28a745; } .api-info { background: #e3f2fd; border: 1px solid #bbdefb; border-radius: 4px; padding: 10px; margin-bottom: 15px; } .api-info h4 { margin: 0 0 5px 0; color: #1976d2; } .api-info p { margin: 0; font-size: 14px; color: #424242; } .api-url { font-family: monospace; background: #f5f5f5; padding: 2px 4px; border-radius: 2px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>LeagueElementConfig API Test Harness</h1> <p>Test the configuration wrapper for easy league hosting</p> </div> <div class="content"> <div class="api-info"> <h4>API Configuration</h4> <p>CDN: <span class="api-url">https://cdn.jsdelivr.net/npm/@lovebowls/leagueelements@latest/dist/browser/leagueElement.bundle.min.js</span></p> <p>Default League ID: <span class="api-url">755ab2f2-20eb-a28a-6f0f-d8fd9b4046e8</span></p> <p>API Endpoint: <span class="api-url">https://www.lovebowls.co.uk/_functions/League?id=xxx</span></p> <p id="mockStatus" style="margin-top: 10px; font-weight: bold; color: #e67e22;">Mock Mode: <span id="mockStatusText">Disabled</span></p> </div> <div class="controls"> <div class="control-group"> <h3>League Configuration</h3> <div class="control-row"> <label for="leagueId">League ID:</label> <input type="text" id="leagueId" value="755ab2f2-20eb-a28a-6f0f-d8fd9b4046e8" placeholder="Enter league ID" style="width: 420px;"> </div> <div class="control-row"> <label for="apiBaseUrl">API Base URL:</label> <input type="text" id="apiBaseUrl" value="https://www.lovebowls.co.uk/_functions" placeholder="API base URL" style="width: 420px;"> </div> <div class="control-row"> <label for="cdnUrl">CDN URL:</label> <input type="text" id="cdnUrl" value="https://cdn.jsdelivr.net/npm/@lovebowls/leagueelements@latest/dist/browser/leagueElement.bundle.min.js" placeholder="CDN URL" style="width: 420px;"> <button class="btn btn-primary" id="loadCdnBtn" type="button">Load CDN</button> </div> <div class="control-row"> <label for="mockEndpoint">Mock Endpoint:</label> <input type="checkbox" id="mockEndpoint" style="margin: 0;"> <span style="color: #666; font-size: 14px;">Use mock data instead of real API calls</span> </div> </div> <div class="control-group"> <h3>Display Settings</h3> <div class="control-row"> <label for="isMobile">Mobile Mode:</label> <select id="isMobile"> <option value="false">Desktop</option> <option value="true">Mobile</option> </select> </div> <div class="control-row"> <label for="fontScale">Font Scale:</label> <input type="number" id="fontScale" value="1.0" min="0.5" max="2.0" step="0.1"> </div> </div> <div class="control-group"> <h3>Actions</h3> <div class="button-group"> <button class="btn btn-primary" onclick="loadLeague()" id="loadBtn">Load League</button> <button class="btn btn-success" onclick="reloadLeague()" id="reloadBtn" disabled>Reload</button> <button class="btn btn-warning" onclick="updateConfig()" id="updateBtn" disabled>Update Config</button> <button class="btn btn-danger" onclick="destroyLeague()" id="destroyBtn" disabled>Destroy</button> </div> </div> </div> <div id="status" class="status info"> Ready to test LeagueElementConfig API. Enter a league ID and click "Load League". </div> <div id="leagueContainer" class="league-container"> <!-- League element will be loaded here --> </div> <div class="event-log"> <h3>Event Log</h3> <div id="eventLog"> <div class="event-entry"> <span class="event-time">[Ready]</span> <span class="event-message">Test harness initialized</span> </div> </div> </div> </div> </div> <!-- Load the league element from CDN --> <script> let leagueConfig = null; let eventLogCounter = 0; let cdnScriptLoaded = false; let cdnScriptTag = null; function loadCdnScript(url, callback) { if (cdnScriptTag) { cdnScriptTag.remove(); cdnScriptLoaded = false; } cdnScriptTag = document.createElement('script'); cdnScriptTag.src = url; cdnScriptTag.onload = () => { cdnScriptLoaded = true; logEvent(`CDN script loaded: ${url}`, 'success'); if (callback) callback(); }; cdnScriptTag.onerror = () => { logEvent(`Failed to load CDN script: ${url}`, 'error'); showStatus('Error loading CDN script. Check the URL.', 'error'); }; document.body.appendChild(cdnScriptTag); } // Mock API response data const mockApiResponse = { "status": 200, "headers": { "alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000", "charset": "utf-8", "content-length": "5761", "content-security-policy": "default-src 'self'; script-src 'nonce-20c412e9-fdfa-4619-97f8-035f41a496f6'", "content-type": "text/calendar; charset=utf-8", "date": "Tue, 08 Jul 2025 07:52:55 GMT", "glb-x-seen-by": "wMMTADooq5AJ3cFomJ/MuXOQWGce7NCZXKms1ErOpBs=", "server": "Pepyaka", "strict-transport-security": "max-age=120 ; includeSubDomains", "via": "1.1 google", "x-content-type-options": "nosniff", "x-seen-by": "GilIRCy+Ky2nI9KZaDKzWLxkNjrXdwdgtu6E0yACibU=,m0j2EEknGIVUW/liY8BLLlPVSO1QPQ7KlY+JzrfjmCLV0TBmJ+uLPQ4OZPC1VSMH,qYxvFa0bBL43z6b6TutC4QnyXr0qgTLOz1RENYVceRMs1Tx9NtWu5mkoMiVppS6xErWKkVeoX4tBqMSi/Z0s1A==,pmLOvFUH0C4tG2Y6Ckb8liSOA+nC7OTAsdOEZa3GGu4=,F8o6Y3HcNYwTAFShvBTacl8BWTwXC3fqq2Xjv80NCNxqCyWRQPaWGp5lJ3PBtJNt+YUY9RKvhYF9ED4yNc8uQH2JzErJ8ZPrQMNW10je6Sg=,XQz4BWTkaIEoz0A1TYYDxZxHSdzlstCUUJsccb2FfRg=,wLeTeVGgkrQCFpIbmiMHmgvCn+ARQDaqnr/JXmVpgjrp2JO+UBV0Ua37eHf3jJiH/K3aK33/h00jpqykUzRL/5AZpAlN4Qr1+gOMkjAKqMU=,c2FX7mUocL421H/ZDSvkz51TFMbL9q5YnmksK2i6ZbP+0LoOGLBGRHIG60ZM3dSi,3h6zdoeTDYlwgjQoBu5YkQ==", "x-wix-request-id": "1751961162.62231409533061766561" }, "body": { "league": { "_id": "755ab2f2-20eb-a28a-6f0f-d8fd9b4046e8", "name": "test", "teams": [ { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" } ], "matches": [ { "_id": "match_1751910222124_1", "homeTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-07-11T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.063Z", "updatedAt": "2025-07-07T17:43:42.063Z" }, { "_id": "match_1751910222124_2", "homeTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-07-18T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.063Z", "updatedAt": "2025-07-07T17:43:42.063Z" }, { "_id": "match_1751910222124_3", "homeTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-07-18T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.063Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, { "_id": "match_1751910222124_5", "homeTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-07-25T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.063Z", "updatedAt": "2025-07-07T17:43:42.063Z" }, { "_id": "match_1751910222124_6", "homeTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-01T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.063Z", "updatedAt": "2025-07-07T17:43:42.063Z" }, { "_id": "match_1751910222124_8", "homeTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-08T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_11", "homeTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-15T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_12", "homeTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-22T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_13", "homeTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-22T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_15", "homeTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-08-29T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_16", "homeTeam": { "_id": "Green", "name": "Green", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Purple", "name": "Purple", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-09-05T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" }, { "_id": "match_1751910222124_18", "homeTeam": { "_id": "Red", "name": "Red", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "awayTeam": { "_id": "Yellow", "name": "Yellow", "createdAt": "2025-07-07T17:33:37.269Z", "updatedAt": "2025-07-07T17:33:37.269Z" }, "date": "2025-09-12T00:00:00.000Z", "rink": null, "result": null, "createdAt": "2025-07-07T17:43:42.064Z", "updatedAt": "2025-07-07T17:43:42.064Z" } ], "settings": { "pointsForWin": 3, "pointsForDraw": 1, "pointsForLoss": 0, "promotionPositions": 0, "relegationPositions": 0, "timesTeamsPlayOther": 2, "rinkPoints": { "pointsPerRinkWin": 2, "pointsPerRinkDraw": 1, "defaultRinks": 4, "enabled": false } }, "createdAt": "2025-07-07T15:42:55.423Z", "updatedAt": "2025-07-07T15:42:55.423Z" } } }; // Global functions for the buttons window.loadLeague = async function() { const leagueId = document.getElementById('leagueId').value.trim(); const apiBaseUrl = document.getElementById('apiBaseUrl').value.trim(); const isMobile = document.getElementById('isMobile').value === 'true'; const fontScale = parseFloat(document.getElementById('fontScale').value); if (!leagueId) { showStatus('Please enter a league ID', 'error'); logEvent('Error: No league ID provided', 'error'); return; } if (!apiBaseUrl) { showStatus('Please enter an API base URL', 'error'); logEvent('Error: No API base URL provided', 'error'); return; } try { // Destroy existing config if any if (leagueConfig) { leagueConfig.destroy(); } logEvent(`Creating LeagueElementConfig with league ID: ${leagueId}`); // Create new config leagueConfig = new LeagueElementConfig({ leagueId: leagueId, container: '#leagueContainer', isMobile: isMobile, fontScale: fontScale, apiBaseUrl: apiBaseUrl, onError: (error) => { showStatus(`Error: ${error.message}`, 'error'); logEvent(`Config Error: ${error.message}`, 'error'); updateButtons(false); }, onLoad: (element, data) => { showStatus(`League loaded successfully! Can edit: ${data.canEdit}`, 'success'); logEvent(`League loaded successfully - Can edit: ${data.canEdit}`, 'success'); updateButtons(true); // Log league data summary if (data.league) { logEvent(`League: "${data.league.name}" with ${data.league.teams?.length || 0} teams, ${data.league.matches?.length || 0} matches`); } } }); // Override the _fetchLeagueData method if mock mode is enabled const useMock = document.getElementById('mockEndpoint').checked; if (useMock) { logEvent('Mock mode enabled - using mock data instead of API call'); leagueConfig._fetchLeagueData = async function() { // Simulate network delay await new Promise(resolve => setTimeout(resolve, 500)); // Return mock data return { canEdit: true, league: mockApiResponse.body.league }; }; } showStatus('Loading league data...', 'info'); if (useMock) { logEvent(`Loading mock league data for ID: ${leagueId}`); } else { logEvent(`Loading league data from ${apiBaseUrl}/League?id=${leagueId}`); } await leagueConfig.load(); } catch (error) { showStatus(`Configuration error: ${error.message}`, 'error'); logEvent(`Configuration Error: ${error.message}`, 'error'); } }; window.reloadLeague = async function() { if (leagueConfig) { showStatus('Reloading league data...', 'info'); logEvent('Reloading league data...'); await leagueConfig.reload(); } }; window.updateConfig = function() { if (!leagueConfig) { showStatus('No league config to update', 'warning'); return; } const isMobile = document.getElementById('isMobile').value === 'true'; const fontScale = parseFloat(document.getElementById('fontScale').value); logEvent(`Updating config - Mobile: ${isMobile}, Font Scale: ${fontScale}`); leagueConfig.updateConfig({ isMobile: isMobile, fontScale: fontScale }); showStatus('Configuration updated', 'success'); }; window.destroyLeague = function() { if (leagueConfig) { leagueConfig.destroy(); leagueConfig = null; showStatus('League destroyed', 'info'); logEvent('League destroyed'); updateButtons(false); } }; function showStatus(message, type) { const statusEl = document.getElementById('status'); statusEl.textContent = message; statusEl.className = `status ${type}`; } function updateButtons(enabled) { document.getElementById('reloadBtn').disabled = !enabled; document.getElementById('updateBtn').disabled = !enabled; document.getElementById('destroyBtn').disabled = !enabled; } function logEvent(message, type = 'info') { const eventLog = document.getElementById('eventLog'); const timestamp = new Date().toLocaleTimeString(); const eventClass = type === 'error' ? 'event-error' : type === 'success' ? 'event-success' : 'event-message'; const eventEntry = document.createElement('div'); eventEntry.className = 'event-entry'; eventEntry.innerHTML = ` <span class="event-time">[${timestamp}]</span> <span class="${eventClass}">${message}</span> `; eventLog.appendChild(eventEntry); eventLog.scrollTop = eventLog.scrollHeight; // Keep only last 50 events while (eventLog.children.length > 50) { eventLog.removeChild(eventLog.firstChild); } } // Set up global event listeners for league events document.addEventListener('league-config-event', (event) => { const { type, league, error, config, leagueId } = event.detail; switch (type) { case 'requestSaveLeague': logEvent(`League save requested for: ${league?.name || 'Unknown'}`); showStatus('League save requested - implement your save logic here', 'info'); break; case 'requestAdminView': logEvent(`Admin view requested for league: ${leagueId}`); showStatus('Admin view requested', 'info'); break; case 'matchClick': logEvent(`Match clicked: ${event.detail.match?.homeTeam?.name || 'Unknown'} vs ${event.detail.match?.awayTeam?.name || 'Unknown'}`); break; case 'teamSelectedForSchedule': logEvent(`Team selected for schedule: ${event.detail.teamName} (${event.detail.teamId})`); break; default: logEvent(`League event: ${type}`, 'info'); } }); // On page load, load the default CDN script window.addEventListener('DOMContentLoaded', () => { const cdnUrlInput = document.getElementById('cdnUrl'); const loadCdnBtn = document.getElementById('loadCdnBtn'); const defaultCdnUrl = cdnUrlInput.value; loadCdnScript(defaultCdnUrl, () => { logEvent('LeagueElementConfig class loaded successfully'); showStatus('Ready to test LeagueElementConfig API', 'info'); detectVersionInfo(); }); loadCdnBtn.addEventListener('click', () => { loadCdnScript(cdnUrlInput.value, () => { logEvent('LeagueElementConfig class loaded successfully'); showStatus('Ready to test LeagueElementConfig API', 'info'); detectVersionInfo(); }); }); // 1. Make the three input fields wider // 2. Add logic to disable API Base URL when Mock Endpoint is checked // --- HTML: Make input fields wider --- // In the .control-row input[type="text"] CSS, change width from 200px to 420px // <input type="text" id="leagueId" ... style="width: 420px;"> // <input type="text" id="apiBaseUrl" ... style="width: 420px;"> // <input type="text" id="cdnUrl" ... style="width: 420px;"> // --- JS: Disable API Base URL when Mock Endpoint is checked --- const apiBaseUrlInput = document.getElementById('apiBaseUrl'); const mockEndpoint = document.getElementById('mockEndpoint'); function updateApiBaseUrlDisabled() { apiBaseUrlInput.disabled = mockEndpoint.checked; } mockEndpoint.addEventListener('change', updateApiBaseUrlDisabled); // Set initial state updateApiBaseUrlDisabled(); }); // Update all functions that use LeagueElementConfig to check cdnScriptLoaded first function ensureCdnLoaded(fn) { return function(...args) { if (!cdnScriptLoaded || typeof LeagueElementConfig === 'undefined') { showStatus('CDN script not loaded yet. Please wait or reload.', 'error'); logEvent('CDN script not loaded yet.', 'error'); return; } return fn(...args); }; } window.loadLeague = ensureCdnLoaded(window.loadLeague); window.reloadLeague = ensureCdnLoaded(window.reloadLeague); window.updateConfig = ensureCdnLoaded(window.updateConfig); window.destroyLeague = ensureCdnLoaded(window.destroyLeague); // Function to detect version information from the loaded package function detectVersionInfo() { try { // Method 1: Check if there's a version property on the class if (LeagueElementConfig.version) { logEvent(`Package version: ${LeagueElementConfig.version}`, 'success'); } // Method 2: Check if there's a version on the LeagueElement class if (window.customElements && window.customElements.get('league-element')) { const LeagueElementClass = window.customElements.get('league-element'); if (LeagueElementClass && LeagueElementClass.version) { logEvent(`LeagueElement version: ${LeagueElementClass.version}`, 'success'); } } // Method 3: Check for any global version variables if (window.LeagueElementsVersion) { logEvent(`Global version: ${window.LeagueElementsVersion}`, 'success'); } // Method 4: Try to extract version from script tags or fetch the script if using @latest const scripts = document.querySelectorAll('script[src*="leagueelements"]'); scripts.forEach(script => { const src = script.src; logEvent(`Loaded script: ${src}`, 'info'); // Try to extract version from URL const versionMatch = src.match(/@(\d+\.\d+\.\d+)/); if (versionMatch) { logEvent(`Detected version from URL: ${versionMatch[1]}`, 'success'); } else { // If URL is "latest", fetch the script and extract from comment fetch(src) .then(resp => resp.text()) .then(text => { const commentMatch = text.match(/@lovebowls\/leagueelements@([0-9.]+)\/dist/); if (commentMatch) { logEvent(`Extracted version from bundle comment: ${commentMatch[1]}`, 'success'); } else { logEvent('Could not extract version from bundle comment', 'warn'); } }) .catch(err => { logEvent(`Error fetching script for version: ${err.message}`, 'error'); }); } }); // Method 5: Check for package.json or similar in the global scope if (window.__LEAGUE_ELEMENTS_VERSION__) { logEvent(`Package version (global): ${window.__LEAGUE_ELEMENTS_VERSION__}`, 'success'); } // Method 6: Try to detect from the class constructor or prototype if (LeagueElementConfig.prototype && LeagueElementConfig.prototype.constructor) { const constructorStr = LeagueElementConfig.prototype.constructor.toString(); const versionMatch = constructorStr.match(/version[:\s]*['\"`]?(\d+\.\d+\.\d+)['\"`]?/i); if (versionMatch) { logEvent(`Detected version from constructor: ${versionMatch[1]}`, 'success'); } } // Method 7: Try to detect from the CDN response headers (if available) if (window.performance && window.performance.getEntriesByType) { const resourceEntries = window.performance.getEntriesByType('resource'); const cdnEntry = resourceEntries.find(entry => entry.name.includes('leagueelements') && entry.name.includes('cdn.jsdelivr.net') ); if (cdnEntry) { logEvent(`CDN resource loaded: ${cdnEntry.name}`, 'info'); logEvent(`CDN load time: ${Math.round(cdnEntry.duration)}ms`, 'info'); } } } catch (error) { logEvent(`Version detection error: ${error.message}`, 'error'); } } // Add keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey) { switch (e.key) { case 'l': e.preventDefault(); loadLeague(); break; case 'r': e.preventDefault(); reloadLeague(); break; case 'd': e.preventDefault(); destroyLeague(); break; } } }); // Log keyboard shortcuts setTimeout(() => { logEvent('Keyboard shortcuts: Ctrl+L (Load), Ctrl+R (Reload), Ctrl+D (Destroy)'); }, 1000); // Update mock status when checkbox changes document.getElementById('mockEndpoint').addEventListener('change', (e) => { const mockStatusText = document.getElementById('mockStatusText'); if (e.target.checked) { mockStatusText.textContent = 'Enabled'; mockStatusText.style.color = '#e67e22'; logEvent('Mock endpoint enabled'); } else { mockStatusText.textContent = 'Disabled'; mockStatusText.style.color = '#27ae60'; logEvent('Mock endpoint disabled'); } }); </script> </body> </html>