Fork i18n + search + filtering- v0.2
at main 184 lines 5.6 kB view raw
1;(function() { 2 const loadingStatesUndoQueue = [] 3 4 function loadingStateContainer(target) { 5 return htmx.closest(target, '[data-loading-states]') || document.body 6 } 7 8 function mayProcessUndoCallback(target, callback) { 9 if (document.body.contains(target)) { 10 callback() 11 } 12 } 13 14 function mayProcessLoadingStateByPath(elt, requestPath) { 15 const pathElt = htmx.closest(elt, '[data-loading-path]') 16 if (!pathElt) { 17 return true 18 } 19 20 return pathElt.getAttribute('data-loading-path') === requestPath 21 } 22 23 function queueLoadingState(sourceElt, targetElt, doCallback, undoCallback) { 24 const delayElt = htmx.closest(sourceElt, '[data-loading-delay]') 25 if (delayElt) { 26 const delayInMilliseconds = 27 delayElt.getAttribute('data-loading-delay') || 200 28 const timeout = setTimeout(function() { 29 doCallback() 30 31 loadingStatesUndoQueue.push(function() { 32 mayProcessUndoCallback(targetElt, undoCallback) 33 }) 34 }, delayInMilliseconds) 35 36 loadingStatesUndoQueue.push(function() { 37 mayProcessUndoCallback(targetElt, function() { clearTimeout(timeout) }) 38 }) 39 } else { 40 doCallback() 41 loadingStatesUndoQueue.push(function() { 42 mayProcessUndoCallback(targetElt, undoCallback) 43 }) 44 } 45 } 46 47 function getLoadingStateElts(loadingScope, type, path) { 48 return Array.from(htmx.findAll(loadingScope, '[' + type + ']')).filter( 49 function(elt) { return mayProcessLoadingStateByPath(elt, path) } 50 ) 51 } 52 53 function getLoadingTarget(elt) { 54 if (elt.getAttribute('data-loading-target')) { 55 return Array.from( 56 htmx.findAll(elt.getAttribute('data-loading-target')) 57 ) 58 } 59 return [elt] 60 } 61 62 htmx.defineExtension('loading-states', { 63 onEvent: function(name, evt) { 64 if (name === 'htmx:beforeRequest') { 65 const container = loadingStateContainer(evt.target) 66 67 const loadingStateTypes = [ 68 'data-loading', 69 'data-loading-class', 70 'data-loading-class-remove', 71 'data-loading-disable', 72 'data-loading-aria-busy' 73 ] 74 75 const loadingStateEltsByType = {} 76 77 loadingStateTypes.forEach(function(type) { 78 loadingStateEltsByType[type] = getLoadingStateElts( 79 container, 80 type, 81 evt.detail.pathInfo.requestPath 82 ) 83 }) 84 85 loadingStateEltsByType['data-loading'].forEach(function(sourceElt) { 86 getLoadingTarget(sourceElt).forEach(function(targetElt) { 87 queueLoadingState( 88 sourceElt, 89 targetElt, 90 function() { 91 targetElt.style.display = 92 sourceElt.getAttribute('data-loading') || 93 'inline-block' 94 }, 95 function() { targetElt.style.display = 'none' } 96 ) 97 }) 98 }) 99 100 loadingStateEltsByType['data-loading-class'].forEach( 101 function(sourceElt) { 102 const classNames = sourceElt 103 .getAttribute('data-loading-class') 104 .split(' ') 105 106 getLoadingTarget(sourceElt).forEach(function(targetElt) { 107 queueLoadingState( 108 sourceElt, 109 targetElt, 110 function() { 111 classNames.forEach(function(className) { 112 targetElt.classList.add(className) 113 }) 114 }, 115 function() { 116 classNames.forEach(function(className) { 117 targetElt.classList.remove(className) 118 }) 119 } 120 ) 121 }) 122 } 123 ) 124 125 loadingStateEltsByType['data-loading-class-remove'].forEach( 126 function(sourceElt) { 127 const classNames = sourceElt 128 .getAttribute('data-loading-class-remove') 129 .split(' ') 130 131 getLoadingTarget(sourceElt).forEach(function(targetElt) { 132 queueLoadingState( 133 sourceElt, 134 targetElt, 135 function() { 136 classNames.forEach(function(className) { 137 targetElt.classList.remove(className) 138 }) 139 }, 140 function() { 141 classNames.forEach(function(className) { 142 targetElt.classList.add(className) 143 }) 144 } 145 ) 146 }) 147 } 148 ) 149 150 loadingStateEltsByType['data-loading-disable'].forEach( 151 function(sourceElt) { 152 getLoadingTarget(sourceElt).forEach(function(targetElt) { 153 queueLoadingState( 154 sourceElt, 155 targetElt, 156 function() { targetElt.disabled = true }, 157 function() { targetElt.disabled = false } 158 ) 159 }) 160 } 161 ) 162 163 loadingStateEltsByType['data-loading-aria-busy'].forEach( 164 function(sourceElt) { 165 getLoadingTarget(sourceElt).forEach(function(targetElt) { 166 queueLoadingState( 167 sourceElt, 168 targetElt, 169 function() { targetElt.setAttribute('aria-busy', 'true') }, 170 function() { targetElt.removeAttribute('aria-busy') } 171 ) 172 }) 173 } 174 ) 175 } 176 177 if (name === 'htmx:beforeOnLoad') { 178 while (loadingStatesUndoQueue.length > 0) { 179 loadingStatesUndoQueue.shift()() 180 } 181 } 182 } 183 }) 184})()