Skip to content

Commit b8d9b90

Browse files
Update downloads content without full page reload (#1312)
Co-authored-by: Shivam Mathur <[email protected]>
1 parent 0a43db5 commit b8d9b90

File tree

1 file changed

+69
-7
lines changed

1 file changed

+69
-7
lines changed

downloads.php

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,7 @@ function option(string $value, string $desc, $attributes = []): string
194194
<?= array_key_exists('source', $options) && $options['source'] === 'Y' ? 'checked' : '' ?>/>
195195
</label>
196196

197-
<noscript>
198197
<button type="submit" class="button">Update Instructions</button>
199-
</noscript>
200198
</form>
201199

202200
<div class="tip">
@@ -254,13 +252,77 @@ function option(string $value, string $desc, $attributes = []): string
254252
<?php endif; ?>
255253

256254
<script>
257-
window.onload = function () {
258-
let form = document.getElementById("instructions-form")
255+
let currentController = null;
256+
257+
function loadInstructions(url) {
258+
const form = document.querySelector('#instructions-form')
259+
const instructions = document.getElementById('instructions')
260+
261+
if (currentController) {
262+
currentController.abort()
263+
}
264+
currentController = new AbortController()
265+
266+
fetch(url, {signal: currentController.signal})
267+
.then(response => {
268+
if (!response.ok) {
269+
instructions.innerHTML = `<p class="error">Error ${response.status}: Unable to load data.</p>`
270+
throw new Error(`HTTP ${response.status} ${response.statusText}`)
271+
}
272+
return response.text()
273+
})
274+
.then(html => {
275+
const parser = new DOMParser();
276+
const doc = parser.parseFromString(html, 'text/html')
277+
278+
const newForm = doc.querySelector('#instructions-form')
279+
const newInstructions = doc.querySelector('#instructions')
280+
281+
if (newForm && form) form.innerHTML = newForm.innerHTML
282+
if (newInstructions && instructions) instructions.innerHTML = newInstructions.innerHTML
283+
284+
removeUpdateInstructionsButton()
285+
286+
if (window.Prism && typeof Prism.highlightAll === 'function') {
287+
Prism.highlightAll()
288+
}
289+
})
290+
.catch(err => {
291+
if (err.name === 'AbortError') return;
292+
console.error('Request failed:', err)
293+
if (!instructions.querySelector('.error')) {
294+
instructions.innerHTML = `<p class="error">An unexpected error occurred.</p>`
295+
}
296+
});
297+
}
259298

260-
form.addEventListener('change', function () {
261-
form.submit();
262-
});
299+
function removeUpdateInstructionsButton() {
300+
const btn = document.querySelector('#instructions-form button[type="submit"]')
301+
if (btn && window.fetch && window.AbortController) {
302+
btn.remove()
303+
}
263304
}
305+
306+
document.addEventListener('DOMContentLoaded', function () {
307+
removeUpdateInstructionsButton()
308+
})
309+
310+
document.addEventListener('change', function (e) {
311+
if (e.target.closest('#instructions-form')) {
312+
const form = e.target.closest('#instructions-form')
313+
const params = new URLSearchParams(new FormData(form)).toString()
314+
const newUrl = form.action.split('?')[0] + '?' + params
315+
316+
history.pushState({url: newUrl}, '', newUrl)
317+
loadInstructions(newUrl)
318+
}
319+
})
320+
321+
window.addEventListener('popstate', function (e) {
322+
if (e.state && e.state.url) {
323+
loadInstructions(e.state.url)
324+
}
325+
})
264326
</script>
265327

266328
<?php

0 commit comments

Comments
 (0)