1
1
const privateData = new WeakMap ( )
2
2
3
- // Functional stand in for the W3 spec "queue a task" paradigm
4
- function task ( ) : Promise < void > {
5
- return new Promise ( resolve => setTimeout ( resolve , 0 ) )
6
- }
7
-
8
3
function isWildcard ( accept : string | null ) {
9
4
return accept && ! ! accept . split ( ',' ) . find ( x => x . match ( / ^ \s * \* \/ \* / ) )
10
5
}
@@ -133,28 +128,26 @@ export default class IncludeFragmentElement extends HTMLElement {
133
128
}
134
129
)
135
130
136
- #handleData( ) : Promise < void > {
137
- if ( this . #busy) return Promise . resolve ( )
131
+ async #handleData( ) : Promise < void > {
132
+ if ( this . #busy) return
138
133
this . #busy = true
139
-
140
134
this . #observer. unobserve ( this )
141
- return this . #getData( ) . then (
142
- ( html : string ) => {
143
- const template = document . createElement ( 'template' )
144
- // eslint-disable-next-line github/no-inner-html
145
- template . innerHTML = html
146
- const fragment = document . importNode ( template . content , true )
147
- const canceled = ! this . dispatchEvent (
148
- new CustomEvent ( 'include-fragment-replace' , { cancelable : true , detail : { fragment} } )
149
- )
150
- if ( canceled ) return
151
- this . replaceWith ( fragment )
152
- this . dispatchEvent ( new CustomEvent ( 'include-fragment-replaced' ) )
153
- } ,
154
- ( ) => {
155
- this . classList . add ( 'is-error' )
156
- }
157
- )
135
+ try {
136
+ const html = await this . #getData( )
137
+
138
+ const template = document . createElement ( 'template' )
139
+ // eslint-disable-next-line github/no-inner-html
140
+ template . innerHTML = html
141
+ const fragment = document . importNode ( template . content , true )
142
+ const canceled = ! this . dispatchEvent (
143
+ new CustomEvent ( 'include-fragment-replace' , { cancelable : true , detail : { fragment} } )
144
+ )
145
+ if ( canceled ) return
146
+ this . replaceWith ( fragment )
147
+ this . dispatchEvent ( new CustomEvent ( 'include-fragment-replaced' ) )
148
+ } catch {
149
+ this . classList . add ( 'is-error' )
150
+ }
158
151
}
159
152
160
153
#getData( ) : Promise < string > {
@@ -173,47 +166,43 @@ export default class IncludeFragmentElement extends HTMLElement {
173
166
}
174
167
}
175
168
176
- #fetchDataWithEvents( ) : Promise < string > {
169
+ // Functional stand in for the W3 spec "queue a task" paradigm
170
+ async #task( eventsToDispatch : string [ ] ) : Promise < void > {
171
+ await new Promise ( resolve => setTimeout ( resolve , 0 ) )
172
+ for ( const eventType of eventsToDispatch ) {
173
+ this . dispatchEvent ( new Event ( eventType ) )
174
+ }
175
+ }
176
+
177
+ async #fetchDataWithEvents( ) : Promise < string > {
177
178
// We mimic the same event order as <img>, including the spec
178
179
// which states events must be dispatched after "queue a task".
179
180
// https://www.w3.org/TR/html52/semantics-embedded-content.html#the-img-element
180
- return task ( )
181
- . then ( ( ) => {
182
- this . dispatchEvent ( new Event ( 'loadstart' ) )
183
- return this . fetch ( this . request ( ) )
184
- } )
185
- . then ( response => {
186
- if ( response . status !== 200 ) {
187
- throw new Error ( `Failed to load resource: the server responded with a status of ${ response . status } ` )
188
- }
189
- const ct = response . headers . get ( 'Content-Type' )
190
- if ( ! isWildcard ( this . accept ) && ( ! ct || ! ct . includes ( this . accept ? this . accept : 'text/html' ) ) ) {
191
- throw new Error ( `Failed to load resource: expected ${ this . accept || 'text/html' } but was ${ ct } ` )
192
- }
193
- return response . text ( )
194
- } )
195
- . then (
196
- data => {
197
- // Dispatch `load` and `loadend` async to allow
198
- // the `load()` promise to resolve _before_ these
199
- // events are fired.
200
- task ( ) . then ( ( ) => {
201
- this . dispatchEvent ( new Event ( 'load' ) )
202
- this . dispatchEvent ( new Event ( 'loadend' ) )
203
- } )
204
- return data
205
- } ,
206
- error => {
207
- // Dispatch `error` and `loadend` async to allow
208
- // the `load()` promise to resolve _before_ these
209
- // events are fired.
210
- task ( ) . then ( ( ) => {
211
- this . dispatchEvent ( new Event ( 'error' ) )
212
- this . dispatchEvent ( new Event ( 'loadend' ) )
213
- } )
214
- throw error
215
- }
216
- )
181
+
182
+ await this . #task( [ 'loadstart' ] )
183
+ const response = await this . fetch ( this . request ( ) )
184
+ if ( response . status !== 200 ) {
185
+ throw new Error ( `Failed to load resource: the server responded with a status of ${ response . status } ` )
186
+ }
187
+ const ct = response . headers . get ( 'Content-Type' )
188
+ if ( ! isWildcard ( this . accept ) && ( ! ct || ! ct . includes ( this . accept ? this . accept : 'text/html' ) ) ) {
189
+ throw new Error ( `Failed to load resource: expected ${ this . accept || 'text/html' } but was ${ ct } ` )
190
+ }
191
+ const data = await response . text ( )
192
+
193
+ try {
194
+ // Dispatch `load` and `loadend` async to allow
195
+ // the `load()` promise to resolve _before_ these
196
+ // events are fired.
197
+ this . #task( [ 'load' , 'loadend' ] )
198
+ return data
199
+ } catch ( error ) {
200
+ // Dispatch `error` and `loadend` async to allow
201
+ // the `load()` promise to resolve _before_ these
202
+ // events are fired.
203
+ this . #task( [ 'error' , 'loadend' ] )
204
+ throw error
205
+ }
217
206
}
218
207
}
219
208
0 commit comments