Files
lenz-web/views/public/js/loading-states.js
Simon Martens e19fd47c17 Init
2025-03-05 16:41:39 +01:00

185 lines
5.4 KiB
JavaScript

;(function() {
const loadingStatesUndoQueue = []
function loadingStateContainer(target) {
return htmx.closest(target, '[data-loading-states]') || document.body
}
function mayProcessUndoCallback(target, callback) {
if (document.body.contains(target)) {
callback()
}
}
function mayProcessLoadingStateByPath(elt, requestPath) {
const pathElt = htmx.closest(elt, '[data-loading-path]')
if (!pathElt) {
return true
}
return pathElt.getAttribute('data-loading-path') === requestPath
}
function queueLoadingState(sourceElt, targetElt, doCallback, undoCallback) {
const delayElt = htmx.closest(sourceElt, '[data-loading-delay]')
if (delayElt) {
const delayInMilliseconds =
delayElt.getAttribute('data-loading-delay') || 200
const timeout = setTimeout(function() {
doCallback()
loadingStatesUndoQueue.push(function() {
mayProcessUndoCallback(targetElt, undoCallback)
})
}, delayInMilliseconds)
loadingStatesUndoQueue.push(function() {
mayProcessUndoCallback(targetElt, function() { clearTimeout(timeout) })
})
} else {
doCallback()
loadingStatesUndoQueue.push(function() {
mayProcessUndoCallback(targetElt, undoCallback)
})
}
}
function getLoadingStateElts(loadingScope, type, path) {
return Array.from(htmx.findAll(loadingScope, '[' + type + ']')).filter(
function(elt) { return mayProcessLoadingStateByPath(elt, path) }
)
}
function getLoadingTarget(elt) {
if (elt.getAttribute('data-loading-target')) {
return Array.from(
htmx.findAll(elt.getAttribute('data-loading-target'))
)
}
return [elt]
}
htmx.defineExtension('loading-states', {
onEvent: function(name, evt) {
if (name === 'htmx:beforeRequest') {
const container = loadingStateContainer(evt.target)
const loadingStateTypes = [
'data-loading',
'data-loading-class',
'data-loading-class-remove',
'data-loading-disable',
'data-loading-aria-busy'
]
const loadingStateEltsByType = {}
loadingStateTypes.forEach(function(type) {
loadingStateEltsByType[type] = getLoadingStateElts(
container,
type,
evt.detail.pathInfo.requestPath
)
})
loadingStateEltsByType['data-loading'].forEach(function(sourceElt) {
getLoadingTarget(sourceElt).forEach(function(targetElt) {
queueLoadingState(
sourceElt,
targetElt,
function() {
targetElt.style.display =
sourceElt.getAttribute('data-loading') ||
'inline-block'
},
function() { targetElt.style.display = 'none' }
)
})
})
loadingStateEltsByType['data-loading-class'].forEach(
function(sourceElt) {
const classNames = sourceElt
.getAttribute('data-loading-class')
.split(' ')
getLoadingTarget(sourceElt).forEach(function(targetElt) {
queueLoadingState(
sourceElt,
targetElt,
function() {
classNames.forEach(function(className) {
targetElt.classList.add(className)
})
},
function() {
classNames.forEach(function(className) {
targetElt.classList.remove(className)
})
}
)
})
}
)
loadingStateEltsByType['data-loading-class-remove'].forEach(
function(sourceElt) {
const classNames = sourceElt
.getAttribute('data-loading-class-remove')
.split(' ')
getLoadingTarget(sourceElt).forEach(function(targetElt) {
queueLoadingState(
sourceElt,
targetElt,
function() {
classNames.forEach(function(className) {
targetElt.classList.remove(className)
})
},
function() {
classNames.forEach(function(className) {
targetElt.classList.add(className)
})
}
)
})
}
)
loadingStateEltsByType['data-loading-disable'].forEach(
function(sourceElt) {
getLoadingTarget(sourceElt).forEach(function(targetElt) {
queueLoadingState(
sourceElt,
targetElt,
function() { targetElt.disabled = true },
function() { targetElt.disabled = false }
)
})
}
)
loadingStateEltsByType['data-loading-aria-busy'].forEach(
function(sourceElt) {
getLoadingTarget(sourceElt).forEach(function(targetElt) {
queueLoadingState(
sourceElt,
targetElt,
function() { targetElt.setAttribute('aria-busy', 'true') },
function() { targetElt.removeAttribute('aria-busy') }
)
})
}
)
}
if (name === 'htmx:beforeOnLoad') {
while (loadingStatesUndoQueue.length > 0) {
loadingStatesUndoQueue.shift()()
}
}
}
})
})()