-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
208 lines (170 loc) · 8.79 KB
/
index.html
File metadata and controls
208 lines (170 loc) · 8.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Rotating URL Display</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background-color: #000;
}
/* Define a common class for both iframes */
.content-frame {
border: none;
width: 100%;
height: 100%;
position: absolute; /* Needed for stacking */
top: 0;
left: 0;
opacity: 0; /* Hidden by default */
transition: opacity 0.5s ease-in-out; /* Smooth fade transition */
}
/* Only the active frame is fully visible */
.active {
opacity: 1;
z-index: 10;
}
</style>
</head>
<body>
<!-- Two identically sized iframes for swapping content -->
<!-- frameA will start as active -->
<iframe id="frameA" src="about:blank" class="content-frame active"></iframe>
<!-- frameB will start as the preloader (hidden) -->
<iframe id="frameB" src="about:blank" class="content-frame"></iframe>
<script>
// Array of URLs to rotate, now including a 'type' to distinguish pre-loadable pages
const urlsToRotate = [
{ url: "https://www.leddepartureboard.com/singleboard/SRC/to/IMW?hideClock=false&hideMenu=true&showStationName=true", duration: 8000, type: 'live' },
{ url: "https://donostio.github.io/EvieWeather/", duration: 5000, type: 'status' }, // Pre-loadable (Weather)
{ url: "https://donostio.github.io/DLstatus/", duration: 5000, type: 'status' }, // Pre-loadable (Tube Status)
{ url: "https://www.leddepartureboard.com/singleboard/STE/to/WIM?hideClock=false&hideMenu=true&showStationName=true", duration: 8000, type: 'live' }
];
const initialDelay = 2000; // 2 seconds before the first URL from the list is loaded
const fallbackTimeout = 7000; // Fallback timeout for 'live' pages that don't load quickly
// currentUrlIndex now ALWAYS points to the page that is ABOUT TO BE DISPLAYED
let currentUrlIndex = 0;
let rotationTimer;
let loadTimeout;
const frameA = document.getElementById('frameA');
const frameB = document.getElementById('frameB');
// Initialize frames. We use the 'active' class to track visibility.
let activeFrame = frameA;
let preloaderFrame = frameB;
/**
* Loads a URL into the preloader frame, but only if it's a 'status' page.
* @param {number} indexToLoad - The index of the URL in urlsToRotate to load next.
*/
function preloadFrame(indexToLoad) {
const itemToLoad = urlsToRotate[indexToLoad];
// Only pre-load the GitHub Pages status screens
if (itemToLoad.type === 'status') {
preloaderFrame.src = itemToLoad.url;
console.log(`Pre-loading URL ${indexToLoad} (${itemToLoad.url}) in the background.`);
} else {
// Clear the preloader if the next item is a live board (since it loads into the active frame next)
preloaderFrame.src = 'about:blank';
}
}
/**
* Schedules the next display swap (performRotation) and starts pre-loading the page *after* that.
* This function is called immediately after a page becomes visible.
* @param {number} duration - The amount of time (ms) to display the current page.
*/
function scheduleNextRotation(duration) {
clearTimeout(rotationTimer);
// 1. Advance the index to the NEXT page to be displayed in the future.
currentUrlIndex = (currentUrlIndex + 1) % urlsToRotate.length;
// 2. Preload the page at the newly advanced index (this is the page that will display next).
preloadFrame(currentUrlIndex);
// 3. Set the timer for the actual rotation event
rotationTimer = setTimeout(performRotation, duration);
}
/**
* Handles the actual swap of frames and subsequent loading/pre-loading.
* currentUrlIndex points to the item we are about to display.
*/
function performRotation() {
clearTimeout(loadTimeout);
const nextItem = urlsToRotate[currentUrlIndex];
if (nextItem.type === 'live') {
// --- LIVE BOARD LOGIC (Must load now, no pre-loading possible) ---
console.log(`Loading Live URL: ${nextItem.url} for ${nextItem.duration / 1000}s. Index: ${currentUrlIndex}`);
// Load into the current active frame
activeFrame.src = nextItem.url;
// --- FIX: Add a guard flag to prevent the race condition ---
let rotationInitiated = false;
const finalizeRotation = () => {
// If rotation was already initiated by the other event (onload or timeout), exit.
if (rotationInitiated) return;
rotationInitiated = true;
clearTimeout(loadTimeout); // Clear the timeout
activeFrame.onload = null; // Clear the onload handler
// Ensure the frame is visible
activeFrame.classList.add('active');
scheduleNextRotation(nextItem.duration);
};
activeFrame.onload = finalizeRotation;
// Fallback timeout for live boards
loadTimeout = setTimeout(() => {
// Check the guard flag before calling finalizeRotation
if (!rotationInitiated) {
console.warn(`Live board load timeout reached for ${nextItem.url}. Forcing display.`);
finalizeRotation();
}
}, fallbackTimeout);
} else {
// --- STATUS BOARD LOGIC (Pre-loaded, ready for instant swap) ---
// 1. Perform the swap: Hide the current active, show the pre-loaded
activeFrame.classList.remove('active');
preloaderFrame.classList.add('active');
console.log(`Instantly displaying pre-loaded Status URL: ${nextItem.url}. Index: ${currentUrlIndex}`);
// 2. Update frame roles for the next cycle
const tempFrame = activeFrame;
activeFrame = preloaderFrame;
preloaderFrame = tempFrame;
// 3. Schedule the next rotation (which advances the index and pre-loads the *following* page)
// FIX: Increased delay from 200ms to 550ms. The CSS opacity transition is 0.5s (500ms).
// This delay ensures the frame that just became the 'preloaderFrame' is completely
// transparent before we set its src to the next pre-load URL (Tube Status), eliminating flicker.
const transitionDuration = 750;
setTimeout(() => {
scheduleNextRotation(nextItem.duration);
}, transitionDuration);
}
}
// Listen for messages from the iframed pages.
window.addEventListener('message', (event) => {
if (event.data && event.data.type === 'page-ready') {
// Find the frame that sent the message
let frameThatSentMessage = null;
if (event.source === frameA.contentWindow) {
frameThatSentMessage = frameA;
} else if (event.source === frameB.contentWindow) {
frameThatSentMessage = frameB;
}
if (frameThatSentMessage) {
// Check if the signal came from the frame currently acting as the preloader
if (frameThatSentMessage === preloaderFrame) {
console.log(`Preloader frame confirmed ready for swap: ${preloaderFrame.src}`);
} else if (frameThatSentMessage === activeFrame) {
console.warn(`Ready signal arrived late from active frame: ${activeFrame.src}.`);
}
}
}
});
/**
* Initial function to start the rotation process.
*/
function initRotation() {
// currentUrlIndex is 0. Call performRotation to load the first item.
performRotation();
}
// Start the process after the initial delay
setTimeout(initRotation, initialDelay);
</script>
</body>
</html>