Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 54caf8e

Browse files
authored
Merge pull request #66 from github/preload-bug
Fix bug where calling load() on lazy element breaks the loading
2 parents 5785cf3 + 2d22690 commit 54caf8e

File tree

2 files changed

+46
-42
lines changed

2 files changed

+46
-42
lines changed

src/index.ts

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const privateData = new WeakMap()
33
const observer = new IntersectionObserver(entries => {
44
for(const entry of entries) {
55
if (entry.isIntersecting) {
6-
const {target} = entry
6+
const {target} = entry
77
observer.unobserve(target)
88
if (!(target instanceof IncludeFragmentElement)) return
99
if (target.loading === 'lazy') {
@@ -52,7 +52,7 @@ function getData(el: IncludeFragmentElement) {
5252
return data.data
5353
} else {
5454
if (src) {
55-
data = el.load()
55+
data = fetchDataWithEvents(el)
5656
} else {
5757
data = Promise.reject(new Error('missing src'))
5858
}
@@ -61,6 +61,46 @@ function getData(el: IncludeFragmentElement) {
6161
}
6262
}
6363

64+
function fetchDataWithEvents(el: IncludeFragmentElement) {
65+
// We mimic the same event order as <img>, including the spec
66+
// which states events must be dispatched after "queue a task".
67+
// https://www.w3.org/TR/html52/semantics-embedded-content.html#the-img-element
68+
return task()
69+
.then(() => {
70+
el.dispatchEvent(new Event('loadstart'))
71+
return el.fetch(el.request())
72+
})
73+
.then(response => {
74+
if (response.status !== 200) {
75+
throw new Error(`Failed to load resource: the server responded with a status of ${response.status}`)
76+
}
77+
const ct = response.headers.get('Content-Type')
78+
if (!isWildcard(el.accept) && (!ct || !ct.includes(el.accept ? el.accept : 'text/html'))) {
79+
throw new Error(`Failed to load resource: expected ${el.accept || 'text/html'} but was ${ct}`)
80+
}
81+
return response.text()
82+
})
83+
.then(data => {
84+
// Dispatch `load` and `loadend` async to allow
85+
// the `load()` promise to resolve _before_ these
86+
// events are fired.
87+
task().then(() => {
88+
el.dispatchEvent(new Event('load'))
89+
el.dispatchEvent(new Event('loadend'))
90+
})
91+
return data
92+
}, error => {
93+
// Dispatch `error` and `loadend` async to allow
94+
// the `load()` promise to resolve _before_ these
95+
// events are fired.
96+
task().then(() => {
97+
el.dispatchEvent(new Event('error'))
98+
el.dispatchEvent(new Event('loadend'))
99+
})
100+
throw error
101+
})
102+
}
103+
64104
function isWildcard(accept: string | null) {
65105
return accept && !!accept.split(',').find(x => x.match(/^\s*\*\/\*/))
66106
}
@@ -146,44 +186,7 @@ export default class IncludeFragmentElement extends HTMLElement {
146186
}
147187

148188
load(): Promise<string> {
149-
observer.unobserve(this)
150-
// We mimic the same event order as <img>, including the spec
151-
// which states events must be dispatched after "queue a task".
152-
// https://www.w3.org/TR/html52/semantics-embedded-content.html#the-img-element
153-
return task()
154-
.then(() => {
155-
this.dispatchEvent(new Event('loadstart'))
156-
return this.fetch(this.request())
157-
})
158-
.then(response => {
159-
if (response.status !== 200) {
160-
throw new Error(`Failed to load resource: the server responded with a status of ${response.status}`)
161-
}
162-
const ct = response.headers.get('Content-Type')
163-
if (!isWildcard(this.accept) && (!ct || !ct.includes(this.accept ? this.accept : 'text/html'))) {
164-
throw new Error(`Failed to load resource: expected ${this.accept || 'text/html'} but was ${ct}`)
165-
}
166-
return response.text()
167-
})
168-
.then(data => {
169-
// Dispatch `load` and `loadend` async to allow
170-
// the `load()` promise to resolve _before_ these
171-
// events are fired.
172-
task().then(() => {
173-
this.dispatchEvent(new Event('load'))
174-
this.dispatchEvent(new Event('loadend'))
175-
})
176-
return data
177-
}, error => {
178-
// Dispatch `error` and `loadend` async to allow
179-
// the `load()` promise to resolve _before_ these
180-
// events are fired.
181-
task().then(() => {
182-
this.dispatchEvent(new Event('error'))
183-
this.dispatchEvent(new Event('loadend'))
184-
})
185-
throw error
186-
})
189+
return getData(this)
187190
}
188191

189192
fetch(request: RequestInfo): Promise<Response> {

test/test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,6 @@ suite('include-fragment-element', function() {
485485
const div = document.createElement('div')
486486
div.innerHTML = '<include-fragment loading="lazy" src="/hello">loading</include-fragment>'
487487
document.body.appendChild(div)
488-
489488
return when(div.firstChild, 'include-fragment-replaced').then(() => {
490489
assert.equal(document.querySelector('include-fragment'), null)
491490
assert.equal(document.querySelector('#replaced').textContent, 'hello')
@@ -582,9 +581,11 @@ suite('include-fragment-element', function() {
582581
}, 0)
583582

584583
return load
585-
.then(() => when(div.firstChild, 'loadend'))
584+
.then(() => when(div.firstChild, 'include-fragment-replaced'))
586585
.then(() => {
587586
assert.equal(count, 1, "Load occured too many times")
587+
assert.equal(document.querySelector('include-fragment'), null)
588+
assert.equal(document.querySelector('#replaced').textContent, 'hello')
588589
})
589590
})
590591
})

0 commit comments

Comments
 (0)