@lovebowls/leagueelements
Version:
League Elements package for LoveBowls
1,030 lines (934 loc) • 34.9 kB
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>