forked from
smokesignal.events/smokesignal
Fork i18n + search + filtering- v0.2
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})()