import {Controller} from '@hotwired/stimulus' export default class extends Controller { static targets = ['indicator'] static classes = ['hidden'] static values = { visible: { type: Boolean, default: false } } connect() { 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() { // Don't start a new debounce if already visible if (true === this.visibleValue) { return } // Show indicator after 200ms delay for field refreshes this.debounceTimeout = setTimeout(() => { this.show() }, 200) } handleAfterRequest() { // Clear debounce timer if request completes before 200ms if (this.debounceTimeout) { clearTimeout(this.debounceTimeout) this.debounceTimeout = null } this.hide() } handleTimeout() { // 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 (true === event.persisted) { this.hide() } } handleHistoryRestore() { // HTMX history restore - hide loading indicator this.hide() } show() { this.visibleValue = true this.indicatorTarget.classList.remove(this.hiddenClass) } hide() { this.visibleValue = false this.indicatorTarget.classList.add(this.hiddenClass) } }