| ;(function () { | |
| let 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', | |
| ] | |
| let 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()() | |
| } | |
| } | |
| }, | |
| }) | |
| })() | |