109 lines
3.6 KiB
JavaScript
109 lines
3.6 KiB
JavaScript
import {Controller} from '@hotwired/stimulus'
|
|
|
|
export default class extends Controller {
|
|
|
|
static targets = ['indicator']
|
|
static classes = ['hidden']
|
|
|
|
connect() {
|
|
this.isVisible = false
|
|
this.debounceTimeout = null
|
|
|
|
// Bind event handlers to preserve context
|
|
this.boundHandleBeforeRequest = this.handleBeforeRequest.bind(this)
|
|
this.boundHandleAfterRequest = this.handleAfterRequest.bind(this)
|
|
this.boundHandleTimeout = this.handleTimeout.bind(this)
|
|
this.boundHandlePageShow = this.handlePageShow.bind(this)
|
|
this.boundHandleHistoryRestore = this.handleHistoryRestore.bind(this)
|
|
|
|
// Listen to HTMX events
|
|
document.body.addEventListener('htmx:beforeRequest', this.boundHandleBeforeRequest)
|
|
document.body.addEventListener('htmx:afterRequest', this.boundHandleAfterRequest)
|
|
document.body.addEventListener('htmx:timeout', this.boundHandleTimeout)
|
|
document.body.addEventListener('htmx:historyRestore', this.boundHandleHistoryRestore)
|
|
|
|
// Listen for browser back/forward navigation
|
|
window.addEventListener('pageshow', this.boundHandlePageShow)
|
|
}
|
|
|
|
disconnect() {
|
|
// Clean up event listeners
|
|
document.body.removeEventListener('htmx:beforeRequest', this.boundHandleBeforeRequest)
|
|
document.body.removeEventListener('htmx:afterRequest', this.boundHandleAfterRequest)
|
|
document.body.removeEventListener('htmx:timeout', this.boundHandleTimeout)
|
|
document.body.removeEventListener('htmx:historyRestore', this.boundHandleHistoryRestore)
|
|
window.removeEventListener('pageshow', this.boundHandlePageShow)
|
|
|
|
// Clear any pending timeout
|
|
if (this.debounceTimeout) {
|
|
clearTimeout(this.debounceTimeout)
|
|
}
|
|
}
|
|
|
|
handleBeforeRequest(event) {
|
|
// Don't start a new debounce if already visible
|
|
if (this.isVisible) {
|
|
return
|
|
}
|
|
|
|
// Show indicator after 200ms delay for field refreshes
|
|
this.debounceTimeout = setTimeout(() => {
|
|
this.show()
|
|
}, 200)
|
|
}
|
|
|
|
handleAfterRequest(event) {
|
|
// Clear debounce timer if request completes before 200ms
|
|
if (this.debounceTimeout) {
|
|
clearTimeout(this.debounceTimeout)
|
|
this.debounceTimeout = null
|
|
}
|
|
|
|
// Check if response contains HX-Redirect header
|
|
const xhr = event.detail.xhr
|
|
const hxRedirect = xhr.getResponseHeader('HX-Redirect')
|
|
|
|
// Keep loading indicator visible if redirecting
|
|
if (hxRedirect) {
|
|
// Ensure indicator is visible during redirect
|
|
if (!this.isVisible) {
|
|
this.show()
|
|
}
|
|
return
|
|
}
|
|
|
|
// Hide indicator if it's visible
|
|
this.hide()
|
|
}
|
|
|
|
handleTimeout(event) {
|
|
// Hide loading indicator
|
|
this.hide()
|
|
|
|
// Show user-friendly error message
|
|
alert('Die Anfrage hat zu lange gedauert. Bitte versuchen Sie es erneut. Falls das Problem weiterhin besteht, kontaktieren Sie bitte unseren Support.')
|
|
}
|
|
|
|
handlePageShow(event) {
|
|
// event.persisted is true when page is restored from bfcache (back/forward navigation)
|
|
if (event.persisted) {
|
|
this.hide()
|
|
}
|
|
}
|
|
|
|
handleHistoryRestore(event) {
|
|
// HTMX history restore - hide loading indicator
|
|
this.hide()
|
|
}
|
|
|
|
show() {
|
|
this.isVisible = true
|
|
this.indicatorTarget.classList.remove(this.hiddenClass)
|
|
}
|
|
|
|
hide() {
|
|
this.isVisible = false
|
|
this.indicatorTarget.classList.add(this.hiddenClass)
|
|
}
|
|
}
|