@abreen/tada 1.11.3 → 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -64
- package/bin/tada.ts +61 -66
- package/build/build-manifest.ts +14 -3
- package/build/bundle.ts +0 -1
- package/build/config-files.ts +183 -0
- package/build/config-loader.ts +159 -0
- package/build/copy.ts +0 -83
- package/build/generate-content-assets.ts +75 -160
- package/build/globals.ts +48 -89
- package/build/log.ts +27 -18
- package/build/pagefind.ts +33 -26
- package/build/pipeline.ts +98 -79
- package/build/reachability.ts +51 -248
- package/build/serve.ts +35 -6
- package/build/site-variables.ts +20 -11
- package/build/source-model.ts +400 -0
- package/build/{watch/records.ts → source-records.ts} +111 -49
- package/build/template-globals.ts +91 -0
- package/build/templates.ts +50 -40
- package/build/test-helpers.ts +15 -0
- package/build/toc-plugin.ts +5 -1
- package/build/types.d.ts +9 -1
- package/build/util.ts +8 -0
- package/build/utils/code.ts +6 -16
- package/build/utils/content-files.ts +57 -126
- package/build/utils/final-html.ts +239 -0
- package/build/utils/markdown.ts +237 -17
- package/build/utils/paths.ts +2 -1
- package/build/utils/render.ts +108 -99
- package/build/validate-config-links.ts +91 -14
- package/build/watch/assets.ts +0 -2
- package/build/watch/build-full.ts +14 -15
- package/build/watch/build-incremental.ts +15 -8
- package/build/watch/compiler-types.d.ts +6 -1
- package/build/watch/compiler.ts +27 -15
- package/build/watch/index.ts +2 -7
- package/build/watch/planner.ts +32 -16
- package/build/watch/reload.ts +4 -0
- package/build/watch/runtime.ts +29 -45
- package/build/watch/snapshot.ts +50 -402
- package/build/watch/validation.ts +6 -3
- package/build/watch-reachability-state.ts +16 -23
- package/build/watch-reload-client.ts +11 -4
- package/init/content/index.md +1 -1
- package/init/content/labs/02/index.md +61 -0
- package/init/content/labs/02/selection_sort.py +23 -0
- package/init/content/labs/index.md +4 -2
- package/init/content/lectures/01/index.md +1 -1
- package/init/content/markdown.md +1 -1
- package/package.json +3 -4
- package/src/code/index.ts +46 -18
- package/src/code.scss +2 -1
- package/src/globals.ts +47 -0
- package/src/index.ts +1 -0
- package/src/navigate/index.ts +2 -5
- package/src/navigate/lifecycle.ts +3 -1
- package/src/navigate/runtime.ts +6 -5
- package/src/page-update/index.ts +20 -16
- package/src/search/index.ts +53 -25
- package/src/slides/index.ts +467 -0
- package/src/slides/style.scss +104 -0
- package/src/style.scss +8 -3
- package/src/timezone/index.ts +16 -20
- package/src/top/index.ts +2 -4
- package/src/trace/index.ts +91 -7
- package/src/trace/style.scss +1 -1
- package/src/util.ts +6 -2
- package/templates/_author.html +2 -2
- package/templates/_heading.html +1 -1
- package/templates/_nav.html +2 -2
- package/templates/_theme.scss +3 -3
- package/templates/_top.html +14 -14
- package/templates/default.html +8 -0
- package/types/dev.d.ts +1 -1
- package/types/site-variables.d.ts +4 -5
- package/watch/fs-commit.ts +63 -10
- package/build/apply-base-path-plugin.ts +0 -186
- package/build/content-watch.ts +0 -104
- package/build/validate-internal-links-plugin.ts +0 -207
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
parent: ../index.html
|
|
3
|
+
parentLabel: Labs
|
|
4
|
+
title: Lab 2
|
|
5
|
+
author: alex
|
|
6
|
+
description: A page demonstrating slides mode.
|
|
7
|
+
slides: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Selection sort
|
|
11
|
+
|
|
12
|
+
Selection sort is a well-known comparison-based sorting algorithm.
|
|
13
|
+
|
|
14
|
+
- Divides the array into a sorted left part and an unsorted right part
|
|
15
|
+
- Repeatedly scans left-to-right, looking for the smallest element
|
|
16
|
+
- Swaps the smallest in the right part into correct position in the left part
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<%= renderTrace('selection_sort.py') %>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Impressions
|
|
25
|
+
|
|
26
|
+
Selection sort's strength is its simplicity.
|
|
27
|
+
|
|
28
|
+
- `index_smallest()` always scans from `start` to the end
|
|
29
|
+
- It requires no additional memory (other than local variables)
|
|
30
|
+
|
|
31
|
+
However
|
|
32
|
+
|
|
33
|
+
- It has no `break` statements & can't return early
|
|
34
|
+
- No difference between best, average and worst cases
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Performance
|
|
39
|
+
|
|
40
|
+
- The outer loop always performs $n - 1$ iterations
|
|
41
|
+
- There are always $n - 1$ swaps
|
|
42
|
+
- At each value of `i`, `index_smallest()` iterates from `i + 1` to the end
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Comparisons
|
|
47
|
+
|
|
48
|
+
The innermost statement compares `nums[i]` and `nums[curr]`.
|
|
49
|
+
|
|
50
|
+
- when `i` is 0, the comparison is executed $n - 1$ times
|
|
51
|
+
- when `i` is 1, the innermost statement is executed $n - 2$ times
|
|
52
|
+
- $\dots$
|
|
53
|
+
- when `i` is $n - 3$, the innermost statement is executed two times
|
|
54
|
+
- when `i` is $n - 2$, the innermost statement is executed one time
|
|
55
|
+
|
|
56
|
+
Therefore the total number of comparisons is
|
|
57
|
+
|
|
58
|
+
$$
|
|
59
|
+
(n-1) + (n-2) + \dots + 1 = \sum_{i=1}^{n-1}i
|
|
60
|
+
$$
|
|
61
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
def swap(items, i, j):
|
|
2
|
+
temp = items[i]
|
|
3
|
+
items[i] = items[j]
|
|
4
|
+
items[j] = temp
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def index_smallest(nums, start):
|
|
8
|
+
curr = start
|
|
9
|
+
for i in range(start + 1, len(nums)):
|
|
10
|
+
if nums[i] < nums[curr]:
|
|
11
|
+
curr = i
|
|
12
|
+
|
|
13
|
+
return curr
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def selection(nums):
|
|
17
|
+
for i in range(len(nums) - 1):
|
|
18
|
+
swap(nums, i, index_smallest(nums, i))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
input1 = [4, 9, 2, 10, 19, 5, 7]
|
|
22
|
+
selection(input1)
|
|
23
|
+
print(input1)
|
|
@@ -8,6 +8,8 @@ In each one-hour lab, we'll dive deeper and write code together, exploring how
|
|
|
8
8
|
to apply the concepts we learned in lecture to solve real-world problems and
|
|
9
9
|
write full-length programs.
|
|
10
10
|
|
|
11
|
-
0. [`VowelCounter` and user input](
|
|
11
|
+
0. [`VowelCounter` and user input](00/index.html)
|
|
12
12
|
|
|
13
|
-
1. [Memory diagrams](
|
|
13
|
+
1. [Memory diagrams](01/index.html)
|
|
14
|
+
|
|
15
|
+
2. [Slides mode demo](02/index.html)
|
|
@@ -10,7 +10,7 @@ Here is a sample description of the topics covered at the first lecture.
|
|
|
10
10
|
|
|
11
11
|
The value of `vars.foobar` is <%= vars.foobar %>.
|
|
12
12
|
|
|
13
|
-
You can add any variables you want to the `site.dev.
|
|
13
|
+
You can add any variables you want to the `site.dev.yaml` and `site.prod.yaml`
|
|
14
14
|
files under the `"vars"` property and access them using Lodash template syntax
|
|
15
15
|
from Markdown files, HTML files, and source code. (Lodash template subtitution
|
|
16
16
|
only works in source code files whose extension is listed in
|
package/init/content/markdown.md
CHANGED
|
@@ -126,7 +126,7 @@ The syntax for links is unchanged from Presto. However,
|
|
|
126
126
|
- external links (links whose domain is not one of `site.internalDomains`) are
|
|
127
127
|
automatically given `target="_blank"` and special styling
|
|
128
128
|
|
|
129
|
-
See `
|
|
129
|
+
See `site.dev.yaml` and `site.prod.yaml` to change `site.basePath`
|
|
130
130
|
and `site.internalDomains`.
|
|
131
131
|
|
|
132
132
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abreen/tada",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A static site generator",
|
|
6
6
|
"license": "MIT",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"lint:sass": "bun run scripts/lint-sass.ts",
|
|
39
39
|
"typecheck": "tsc --noEmit",
|
|
40
40
|
"format": "prettier --write \"**/*.{ts,js,scss,json}\"",
|
|
41
|
+
"test:unit": "bun run scripts/test.ts unit",
|
|
41
42
|
"test:playwright": "bun run scripts/test.ts playwright",
|
|
42
43
|
"test:functional": "bun run scripts/test.ts functional",
|
|
43
44
|
"test:all": "bun run scripts/test.ts all",
|
|
@@ -79,8 +80,7 @@
|
|
|
79
80
|
"sass": "^1.99.0",
|
|
80
81
|
"sharp": "^0.34.5",
|
|
81
82
|
"shiki": "^4.0.2",
|
|
82
|
-
"string-strip-html": "^8.5.0"
|
|
83
|
-
"ws": "^8.20.0"
|
|
83
|
+
"string-strip-html": "^8.5.0"
|
|
84
84
|
},
|
|
85
85
|
"lint-staged": {
|
|
86
86
|
"*.{ts,js}": "prettier --write",
|
|
@@ -110,7 +110,6 @@
|
|
|
110
110
|
"@types/istanbul-reports": "^3.0.4",
|
|
111
111
|
"@types/lodash": "^4.17.24",
|
|
112
112
|
"@types/markdown-it-container": "^4.0.0",
|
|
113
|
-
"@types/ws": "^8.18.1",
|
|
114
113
|
"eslint": "^10.2.1",
|
|
115
114
|
"husky": "^9.1.7",
|
|
116
115
|
"istanbul-lib-coverage": "^3.2.2",
|
package/src/code/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { globals } from '../globals';
|
|
2
|
+
|
|
1
3
|
export default async function mount(
|
|
2
4
|
window: Window,
|
|
3
5
|
): Promise<void | (() => void)> {
|
|
@@ -6,7 +8,17 @@ export default async function mount(
|
|
|
6
8
|
return;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
document.
|
|
11
|
+
const codeBodyEl = document.querySelector<HTMLElement>('.code-body');
|
|
12
|
+
const scrollbarEl = document.querySelector<HTMLElement>('.code-scrollbar');
|
|
13
|
+
if (!codeBodyEl || !scrollbarEl) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const codeBody = codeBodyEl;
|
|
17
|
+
const scrollbar = scrollbarEl;
|
|
18
|
+
|
|
19
|
+
const cleanups: Array<() => void> = [];
|
|
20
|
+
|
|
21
|
+
const handleCopy = (e: ClipboardEvent) => {
|
|
10
22
|
const selection = window.getSelection();
|
|
11
23
|
if (!selection || selection.rangeCount === 0) {
|
|
12
24
|
return;
|
|
@@ -54,19 +66,23 @@ export default async function mount(
|
|
|
54
66
|
|
|
55
67
|
e.clipboardData!.setData('text/plain', lines.join('\n'));
|
|
56
68
|
e.preventDefault();
|
|
69
|
+
};
|
|
70
|
+
document.addEventListener('copy', handleCopy);
|
|
71
|
+
cleanups.push(() => {
|
|
72
|
+
document.removeEventListener('copy', handleCopy);
|
|
57
73
|
});
|
|
58
74
|
|
|
59
75
|
const downloadLink = document.querySelector<HTMLAnchorElement>(
|
|
60
76
|
'.file-header a[download]',
|
|
61
77
|
);
|
|
62
78
|
if (downloadLink && 'showSaveFilePicker' in window) {
|
|
63
|
-
|
|
79
|
+
const handleDownloadClick = async (e: MouseEvent) => {
|
|
64
80
|
e.preventDefault();
|
|
65
81
|
try {
|
|
66
82
|
const handle = await window.showSaveFilePicker!({
|
|
67
83
|
suggestedName: downloadLink.download,
|
|
68
84
|
});
|
|
69
|
-
const response = await fetch(downloadLink.href);
|
|
85
|
+
const response = await globals.fetch(downloadLink.href);
|
|
70
86
|
const writable = await handle.createWritable();
|
|
71
87
|
await writable.write(await response.blob());
|
|
72
88
|
await writable.close();
|
|
@@ -75,47 +91,59 @@ export default async function mount(
|
|
|
75
91
|
throw err;
|
|
76
92
|
}
|
|
77
93
|
}
|
|
94
|
+
};
|
|
95
|
+
downloadLink.addEventListener('click', handleDownloadClick);
|
|
96
|
+
cleanups.push(() => {
|
|
97
|
+
downloadLink.removeEventListener('click', handleDownloadClick);
|
|
78
98
|
});
|
|
79
99
|
}
|
|
80
100
|
|
|
81
|
-
const codeBody = document.querySelector<HTMLElement>('.code-body');
|
|
82
|
-
const scrollbar = document.querySelector<HTMLElement>('.code-scrollbar');
|
|
83
|
-
if (!codeBody || !scrollbar) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
101
|
const inner = scrollbar.firstElementChild as HTMLElement;
|
|
88
102
|
let syncing = false;
|
|
89
103
|
|
|
90
104
|
function updateScrollbar(): void {
|
|
91
|
-
const hasOverflow = codeBody
|
|
92
|
-
scrollbar
|
|
93
|
-
inner.style.width = codeBody
|
|
105
|
+
const hasOverflow = codeBody.scrollWidth > codeBody.clientWidth;
|
|
106
|
+
scrollbar.style.display = hasOverflow ? '' : 'none';
|
|
107
|
+
inner.style.width = codeBody.scrollWidth + 'px';
|
|
94
108
|
}
|
|
95
109
|
|
|
96
|
-
|
|
110
|
+
const handleCodeBodyScroll = () => {
|
|
97
111
|
if (syncing) {
|
|
98
112
|
return;
|
|
99
113
|
}
|
|
100
114
|
syncing = true;
|
|
101
|
-
scrollbar
|
|
115
|
+
scrollbar.scrollLeft = codeBody.scrollLeft;
|
|
102
116
|
syncing = false;
|
|
117
|
+
};
|
|
118
|
+
codeBody.addEventListener('scroll', handleCodeBodyScroll);
|
|
119
|
+
cleanups.push(() => {
|
|
120
|
+
codeBody.removeEventListener('scroll', handleCodeBodyScroll);
|
|
103
121
|
});
|
|
104
122
|
|
|
105
|
-
|
|
123
|
+
const handleScrollbarScroll = () => {
|
|
106
124
|
if (syncing) {
|
|
107
125
|
return;
|
|
108
126
|
}
|
|
109
127
|
syncing = true;
|
|
110
|
-
codeBody
|
|
128
|
+
codeBody.scrollLeft = scrollbar.scrollLeft;
|
|
111
129
|
syncing = false;
|
|
130
|
+
};
|
|
131
|
+
scrollbar.addEventListener('scroll', handleScrollbarScroll);
|
|
132
|
+
cleanups.push(() => {
|
|
133
|
+
scrollbar.removeEventListener('scroll', handleScrollbarScroll);
|
|
112
134
|
});
|
|
113
135
|
|
|
114
|
-
const resizeObserver =
|
|
136
|
+
const resizeObserver = globals.createResizeObserver(updateScrollbar);
|
|
115
137
|
resizeObserver.observe(codeBody);
|
|
116
138
|
updateScrollbar();
|
|
139
|
+
cleanups.push(() => {
|
|
140
|
+
resizeObserver.disconnect();
|
|
141
|
+
});
|
|
117
142
|
|
|
118
143
|
return () => {
|
|
119
|
-
|
|
144
|
+
cleanups
|
|
145
|
+
.splice(0)
|
|
146
|
+
.reverse()
|
|
147
|
+
.forEach(cleanup => cleanup());
|
|
120
148
|
};
|
|
121
149
|
}
|
package/src/code.scss
CHANGED
package/src/globals.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
type FetchFunction = (
|
|
2
|
+
input: RequestInfo | URL,
|
|
3
|
+
init?: RequestInit,
|
|
4
|
+
) => Promise<Response>;
|
|
5
|
+
|
|
6
|
+
type ImportModuleFunction = (specifier: string) => Promise<unknown>;
|
|
7
|
+
type LocationMutationFunction = (window: Window, value: string) => void;
|
|
8
|
+
|
|
9
|
+
export interface Globals {
|
|
10
|
+
replaceLocation: LocationMutationFunction;
|
|
11
|
+
createResizeObserver: (
|
|
12
|
+
callback: ResizeObserverCallback,
|
|
13
|
+
) => Pick<ResizeObserver, 'disconnect' | 'observe'>;
|
|
14
|
+
fetch: FetchFunction;
|
|
15
|
+
importModule: ImportModuleFunction;
|
|
16
|
+
isDocumentHidden: (document: Document) => boolean;
|
|
17
|
+
now: () => number;
|
|
18
|
+
setLocationHash: LocationMutationFunction;
|
|
19
|
+
setLocationHref: LocationMutationFunction;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const globals: Globals = {
|
|
23
|
+
replaceLocation(window, value) {
|
|
24
|
+
window.location.replace(value);
|
|
25
|
+
},
|
|
26
|
+
createResizeObserver(callback) {
|
|
27
|
+
return new ResizeObserver(callback);
|
|
28
|
+
},
|
|
29
|
+
fetch(input: RequestInfo | URL, init?: RequestInit) {
|
|
30
|
+
return fetch(input, init);
|
|
31
|
+
},
|
|
32
|
+
importModule(specifier) {
|
|
33
|
+
return import(specifier);
|
|
34
|
+
},
|
|
35
|
+
isDocumentHidden(document) {
|
|
36
|
+
return document.hidden;
|
|
37
|
+
},
|
|
38
|
+
now() {
|
|
39
|
+
return Date.now();
|
|
40
|
+
},
|
|
41
|
+
setLocationHash(window, value) {
|
|
42
|
+
window.location.hash = value;
|
|
43
|
+
},
|
|
44
|
+
setLocationHref(window, value) {
|
|
45
|
+
window.location.href = value;
|
|
46
|
+
},
|
|
47
|
+
};
|
package/src/index.ts
CHANGED
package/src/navigate/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
setCurrentPath,
|
|
13
13
|
setHistoryIndex,
|
|
14
14
|
} from './runtime';
|
|
15
|
+
import { globals } from '../globals';
|
|
15
16
|
|
|
16
17
|
function findAnchor(event: MouseEvent): HTMLAnchorElement | null {
|
|
17
18
|
const target = event.target as HTMLElement | null;
|
|
@@ -77,11 +78,7 @@ export default function mountNavigate(window: Window): () => void {
|
|
|
77
78
|
clearSearch(window.document);
|
|
78
79
|
closeHeaderDetails(window.document);
|
|
79
80
|
if (url.hash) {
|
|
80
|
-
|
|
81
|
-
// updates :target, fires hashchange (which the TOC listens for),
|
|
82
|
-
// creates a new history entry, and scrolls to the element.
|
|
83
|
-
// pushState would do none of those things.
|
|
84
|
-
window.location.hash = url.hash.slice(1);
|
|
81
|
+
globals.setLocationHash(window, url.hash);
|
|
85
82
|
}
|
|
86
83
|
return;
|
|
87
84
|
}
|
|
@@ -5,6 +5,7 @@ import mountTimeZone from '../timezone';
|
|
|
5
5
|
import mountCode from '../code';
|
|
6
6
|
import mountTrace from '../trace';
|
|
7
7
|
import mountPrint from '../print';
|
|
8
|
+
import mountSlides from '../slides';
|
|
8
9
|
import { scheduleTask } from '../util';
|
|
9
10
|
|
|
10
11
|
const PER_PAGE_COMPONENTS: Record<
|
|
@@ -17,6 +18,7 @@ const PER_PAGE_COMPONENTS: Record<
|
|
|
17
18
|
timeZone: mountTimeZone,
|
|
18
19
|
code: mountCode,
|
|
19
20
|
trace: mountTrace,
|
|
21
|
+
slides: mountSlides,
|
|
20
22
|
print: mountPrint,
|
|
21
23
|
};
|
|
22
24
|
|
|
@@ -39,7 +41,7 @@ export async function mountPerPageComponents(
|
|
|
39
41
|
}
|
|
40
42
|
resolve();
|
|
41
43
|
} catch (err) {
|
|
42
|
-
if (
|
|
44
|
+
if (__IS_DEV__) {
|
|
43
45
|
console.error(`Failed to mount ${name} component:`, String(err));
|
|
44
46
|
}
|
|
45
47
|
reject();
|
package/src/navigate/runtime.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mountPerPageComponents, teardownPerPageComponents } from './lifecycle';
|
|
2
|
+
import { globals } from '../globals';
|
|
2
3
|
|
|
3
4
|
export const NAVIGATION_EVENT = 'tada:navigation';
|
|
4
5
|
|
|
@@ -196,19 +197,19 @@ export async function navigateToUrl(
|
|
|
196
197
|
|
|
197
198
|
let response: Response;
|
|
198
199
|
try {
|
|
199
|
-
response = await fetch(url, { signal: controller.signal });
|
|
200
|
+
response = await globals.fetch(url, { signal: controller.signal });
|
|
200
201
|
} catch (err: unknown) {
|
|
201
202
|
header?.classList.remove('loading');
|
|
202
203
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
203
204
|
return;
|
|
204
205
|
}
|
|
205
|
-
window
|
|
206
|
+
globals.setLocationHref(window, url);
|
|
206
207
|
return;
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
if (!response.ok) {
|
|
210
211
|
header?.classList.remove('loading');
|
|
211
|
-
window
|
|
212
|
+
globals.setLocationHref(window, url);
|
|
212
213
|
return;
|
|
213
214
|
}
|
|
214
215
|
|
|
@@ -226,7 +227,7 @@ export async function navigateToUrl(
|
|
|
226
227
|
.querySelector('meta[name="generator"]')
|
|
227
228
|
?.getAttribute('content');
|
|
228
229
|
if (!currentGenerator || !newGenerator || newGenerator !== currentGenerator) {
|
|
229
|
-
window
|
|
230
|
+
globals.setLocationHref(window, url);
|
|
230
231
|
return;
|
|
231
232
|
}
|
|
232
233
|
|
|
@@ -246,7 +247,7 @@ export async function navigateToUrl(
|
|
|
246
247
|
|
|
247
248
|
if (typeof scrollTarget === 'string') {
|
|
248
249
|
const urlWithHash = parsed.pathname + parsed.search + '#' + scrollTarget;
|
|
249
|
-
|
|
250
|
+
globals.replaceLocation(window, urlWithHash);
|
|
250
251
|
window.history.replaceState({ navIndex: historyIndex }, '', urlWithHash);
|
|
251
252
|
} else if (typeof scrollTarget === 'number') {
|
|
252
253
|
window.scrollTo({ top: scrollTarget });
|
package/src/page-update/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type ResponseValidators,
|
|
8
8
|
} from '../validators';
|
|
9
9
|
import { NAVIGATION_EVENT, refreshCurrentPage } from '../navigate/runtime';
|
|
10
|
+
import { globals } from '../globals';
|
|
10
11
|
|
|
11
12
|
const POLL_INTERVAL_MS = 600_000;
|
|
12
13
|
|
|
@@ -96,7 +97,7 @@ export function mountPageUpdate(
|
|
|
96
97
|
|
|
97
98
|
function scheduleNextCheck() {
|
|
98
99
|
clearTimer();
|
|
99
|
-
if (document
|
|
100
|
+
if (globals.isDocumentHidden(document)) {
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
103
|
timer = window.setTimeout(() => {
|
|
@@ -107,17 +108,20 @@ export function mountPageUpdate(
|
|
|
107
108
|
async function fetchValidators(
|
|
108
109
|
path: string,
|
|
109
110
|
): Promise<ResponseValidators | null> {
|
|
110
|
-
if (
|
|
111
|
+
if (__IS_DEV__) {
|
|
111
112
|
console.log(
|
|
112
|
-
`[page-update] HEAD ${path} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
113
|
+
`[page-update] HEAD ${path} hidden=${globals.isDocumentHidden(document)} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
113
114
|
);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
const res = await fetch(path, {
|
|
117
|
+
const res = await globals.fetch(path, {
|
|
118
|
+
method: 'HEAD',
|
|
119
|
+
cache: 'no-cache',
|
|
120
|
+
});
|
|
117
121
|
|
|
118
|
-
if (
|
|
122
|
+
if (__IS_DEV__) {
|
|
119
123
|
console.log(
|
|
120
|
-
`[page-update] HEAD ${path} -> ${res.status} etag=${res.headers.get('ETag')} last-modified=${res.headers.get('Last-Modified')} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
124
|
+
`[page-update] HEAD ${path} -> ${res.status} etag=${res.headers.get('ETag')} last-modified=${res.headers.get('Last-Modified')} hidden=${globals.isDocumentHidden(document)} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
121
125
|
);
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -170,7 +174,7 @@ export function mountPageUpdate(
|
|
|
170
174
|
// best-effort
|
|
171
175
|
} finally {
|
|
172
176
|
checkInFlight = false;
|
|
173
|
-
if (rerunAfterCurrentCheck && !document
|
|
177
|
+
if (rerunAfterCurrentCheck && !globals.isDocumentHidden(document)) {
|
|
174
178
|
rerunAfterCurrentCheck = false;
|
|
175
179
|
shouldRerun = true;
|
|
176
180
|
} else {
|
|
@@ -191,20 +195,20 @@ export function mountPageUpdate(
|
|
|
191
195
|
hasBaseline = false;
|
|
192
196
|
hideToast();
|
|
193
197
|
clearTimer();
|
|
194
|
-
if (!document
|
|
198
|
+
if (!globals.isDocumentHidden(document)) {
|
|
195
199
|
void checkForUpdate();
|
|
196
200
|
}
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
function handleVisibilityChange() {
|
|
200
|
-
if (
|
|
204
|
+
if (__IS_DEV__) {
|
|
201
205
|
console.log(
|
|
202
|
-
`[page-update] visibilitychange hidden=${document
|
|
206
|
+
`[page-update] visibilitychange hidden=${globals.isDocumentHidden(document)} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
203
207
|
);
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
clearTimer();
|
|
207
|
-
if (document
|
|
211
|
+
if (globals.isDocumentHidden(document)) {
|
|
208
212
|
return;
|
|
209
213
|
}
|
|
210
214
|
|
|
@@ -212,7 +216,7 @@ export function mountPageUpdate(
|
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
function handleNavigation() {
|
|
215
|
-
if (
|
|
219
|
+
if (__IS_DEV__) {
|
|
216
220
|
console.log(
|
|
217
221
|
`[page-update] navigation path=${window.location.pathname} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
218
222
|
);
|
|
@@ -227,7 +231,7 @@ export function mountPageUpdate(
|
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
function handleWindowFocus() {
|
|
230
|
-
if (
|
|
234
|
+
if (__IS_DEV__) {
|
|
231
235
|
console.log(
|
|
232
236
|
`[page-update] window focus visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
233
237
|
);
|
|
@@ -235,7 +239,7 @@ export function mountPageUpdate(
|
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
function handleWindowBlur() {
|
|
238
|
-
if (
|
|
242
|
+
if (__IS_DEV__) {
|
|
239
243
|
console.log(
|
|
240
244
|
`[page-update] window blur visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
241
245
|
);
|
|
@@ -253,8 +257,8 @@ export function mountPageUpdate(
|
|
|
253
257
|
window.addEventListener('blur', handleWindowBlur);
|
|
254
258
|
window.addEventListener(NAVIGATION_EVENT, handleNavigation);
|
|
255
259
|
|
|
256
|
-
if (!document
|
|
257
|
-
if (
|
|
260
|
+
if (!globals.isDocumentHidden(document)) {
|
|
261
|
+
if (__IS_DEV__) {
|
|
258
262
|
console.log(
|
|
259
263
|
`[page-update] mount path=${currentPath} interval=${pollIntervalMs} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
260
264
|
);
|