Skip to content

Commit

Permalink
Merge pull request #6662 from squidfunk/fix/instant-loading-bugs
Browse files Browse the repository at this point in the history
Fixed instant navigation bugs
  • Loading branch information
squidfunk committed Jan 24, 2024
2 parents be95f49 + 95ad78a commit 943e978
Show file tree
Hide file tree
Showing 12 changed files with 445 additions and 397 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion material/overrides/main.html
Expand Up @@ -23,5 +23,5 @@
{% endblock %}
{% block scripts %}
{{ super() }}
<script src="{{ 'assets/javascripts/custom.526c59dc.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/custom.129bd6ad.min.js' | url }}"></script>
{% endblock %}
29 changes: 0 additions & 29 deletions material/templates/assets/javascripts/bundle.a963951d.min.js

This file was deleted.

29 changes: 29 additions & 0 deletions material/templates/assets/javascripts/bundle.c18c5fb9.min.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion material/templates/base.html
Expand Up @@ -249,7 +249,7 @@
</script>
{% endblock %}
{% block scripts %}
<script src="{{ 'assets/javascripts/bundle.a963951d.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.c18c5fb9.min.js' | url }}"></script>
{% for script in config.extra_javascript %}
{{ script | script_tag }}
{% endfor %}
Expand Down
53 changes: 43 additions & 10 deletions src/templates/assets/javascripts/browser/request/index.ts
Expand Up @@ -46,59 +46,72 @@ interface Options {
/**
* Fetch the given URL
*
* If the request fails (e.g. when dispatched from `file://` locations), the
* observable will complete without emitting a value.
* This function returns an observable that emits the response as a blob and
* completes, or emits an error if the request failed. The caller can cancel
* the request by unsubscribing at any time, which will automatically abort
* the inflight request and complete the observable.
*
* Note that we use `XMLHTTPRequest` not because we're nostalgic, but because
* it's the only way to get progress events for downloads and also allow for
* cancellation of requests, as the official Fetch API does not support this
* yet, even though we're already in 2024.
*
* @param url - Request URL
* @param options - Options
*
* @returns Response observable
* @returns Data observable
*/
export function request(
url: URL | string, options?: Options
): Observable<Blob> {
return new Observable<Blob>(observer => {
const req = new XMLHttpRequest()
req.open("GET", `${url}`)
req.open("GET", `${url}`)
req.responseType = "blob"

// Handle response
req.addEventListener("load", () => {
if (req.status >= 200 && req.status < 300) {
observer.next(req.response)
observer.complete()

// Every response that is not in the 2xx range is considered an error
} else {
observer.error(new Error(req.statusText))
}
})

// Handle network errors
req.addEventListener("error", () => {
observer.error(new Error("Network Error"))
observer.error(new Error("Network error"))
})

// Handle aborted requests
req.addEventListener("abort", () => {
observer.error(new Error("Request aborted"))
observer.complete()
})

// Handle download progress
if (typeof options?.progress$ !== "undefined") {
req.addEventListener("progress", event => {
if (event.lengthComputable) {
options.progress$!.next((event.loaded / event.total) * 100)
} else { // https://bugs.chromium.org/p/chromium/issues/detail?id=463622
const totalFromHeader = Number(req.getResponseHeader("Content-Length")) || 0
options.progress$!.next((event.loaded / totalFromHeader) * 100)

// Hack: Chromium doesn't report the total number of bytes if content
// is compressed, so we need this fallback - see https://t.ly/ZXofI
} else {
const length = req.getResponseHeader("Content-Length") ?? 0
options.progress$!.next((event.loaded / +length) * 100)
}
})

// Immediately set progress to 5% to indicate that we're loading
options.progress$.next(5)
}

// Send request
// Send request and automatically abort request upon unsubscription
req.send()
return () => req.abort()
})
}

Expand All @@ -125,6 +138,26 @@ export function requestJSON<T>(
)
}

/**
* Fetch HTML from the given URL
*
* @param url - Request URL
* @param options - Options
*
* @returns Data observable
*/
export function requestHTML(
url: URL | string, options?: Options
): Observable<Document> {
const dom = new DOMParser()
return request(url, options)
.pipe(
switchMap(res => res.text()),
map(res => dom.parseFromString(res, "text/html")),
shareReplay(1)
)
}

/**
* Fetch XML from the given URL
*
Expand Down

0 comments on commit 943e978

Please sign in to comment.