mirror of
				https://github.com/Theodor-Springmann-Stiftung/musenalm.git
				synced 2025-10-30 17:55:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			185 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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()()
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   })
 | |
| })()
 | 
