@abreen/tada 1.15.9 → 1.15.10
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/package.json +1 -1
- package/src/navigate/eligible.ts +8 -1
- package/src/page-update/index.ts +5 -1
- package/src/search/index.ts +105 -66
- package/src/top/index.ts +3 -2
package/package.json
CHANGED
package/src/navigate/eligible.ts
CHANGED
|
@@ -45,7 +45,14 @@ export function isEligibleLink(
|
|
|
45
45
|
return false;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const normalizedBasePath = basePath.endsWith('/')
|
|
49
|
+
? basePath.slice(0, -1) || '/'
|
|
50
|
+
: basePath;
|
|
51
|
+
if (
|
|
52
|
+
normalizedBasePath !== '/' &&
|
|
53
|
+
url.pathname !== normalizedBasePath &&
|
|
54
|
+
!url.pathname.startsWith(`${normalizedBasePath}/`)
|
|
55
|
+
) {
|
|
49
56
|
return false;
|
|
50
57
|
}
|
|
51
58
|
|
package/src/page-update/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { NAVIGATION_EVENT, refreshCurrentPage } from '../navigate/runtime';
|
|
|
10
10
|
import { globals } from '../globals';
|
|
11
11
|
|
|
12
12
|
const POLL_INTERVAL_MS = 600_000;
|
|
13
|
+
export const PAGE_UPDATE_REFRESH_EVENT = 'tada:page-update-refresh';
|
|
13
14
|
|
|
14
15
|
interface PageUpdateOptions {
|
|
15
16
|
pollIntervalMs?: number;
|
|
@@ -247,7 +248,10 @@ export function mountPageUpdate(
|
|
|
247
248
|
}
|
|
248
249
|
|
|
249
250
|
function handleReloadClick() {
|
|
250
|
-
void refreshPage(window)
|
|
251
|
+
void refreshPage(window).then(() => {
|
|
252
|
+
const EventCtor = (window as unknown as { Event: typeof Event }).Event;
|
|
253
|
+
window.dispatchEvent(new EventCtor(PAGE_UPDATE_REFRESH_EVENT));
|
|
254
|
+
});
|
|
251
255
|
}
|
|
252
256
|
|
|
253
257
|
reloadButton.addEventListener('click', handleReloadClick);
|
package/src/search/index.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { getElement, applyBasePath } from '../util';
|
|
2
2
|
import { getPdfPageNumber, groupPdfResults } from './pdf-utils';
|
|
3
3
|
import type { Result } from './pdf-utils';
|
|
4
|
-
import {
|
|
5
|
-
getResponseValidators,
|
|
6
|
-
hasResponseValidatorsChanged,
|
|
7
|
-
type ResponseValidators,
|
|
8
|
-
} from '../validators';
|
|
4
|
+
import { PAGE_UPDATE_REFRESH_EVENT } from '../page-update';
|
|
9
5
|
import { globals } from '../globals';
|
|
10
6
|
|
|
11
|
-
const MAX_RESULTS = 24;
|
|
12
|
-
|
|
13
7
|
interface PagefindSubResult {
|
|
14
8
|
title?: string;
|
|
15
9
|
url: string;
|
|
@@ -34,7 +28,9 @@ interface PagefindSearchResult {
|
|
|
34
28
|
}
|
|
35
29
|
|
|
36
30
|
interface Pagefind {
|
|
31
|
+
destroy(): Promise<void>;
|
|
37
32
|
init(): Promise<void>;
|
|
33
|
+
options(options: { basePath: string }): Promise<void>;
|
|
38
34
|
search(query: string): Promise<{ results: PagefindSearchResult[] }>;
|
|
39
35
|
}
|
|
40
36
|
|
|
@@ -61,8 +57,7 @@ async function doSearch(query: string, window: Window): Promise<SearchState> {
|
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
const search = await pagefind.search(query);
|
|
64
|
-
const
|
|
65
|
-
const data = await Promise.all(slice.map(r => r.data()));
|
|
60
|
+
const data = await Promise.all(search.results.map(r => r.data()));
|
|
66
61
|
|
|
67
62
|
const titlePostfix = __SITE_TITLE_POSTFIX__;
|
|
68
63
|
const results: Result[] = data.map((d: PagefindResult) => {
|
|
@@ -139,9 +134,9 @@ function render(
|
|
|
139
134
|
ol.tabIndex = -1;
|
|
140
135
|
ol.setAttribute('aria-label', 'Search results');
|
|
141
136
|
|
|
142
|
-
const totalVisible =
|
|
137
|
+
const totalVisible = state.results.length;
|
|
143
138
|
|
|
144
|
-
state.results.
|
|
139
|
+
state.results.forEach((result, i) => {
|
|
145
140
|
const a = doc.createElement('a');
|
|
146
141
|
a.id = `result-${i}`;
|
|
147
142
|
a.className = 'result';
|
|
@@ -175,7 +170,7 @@ function render(
|
|
|
175
170
|
li.setAttribute('aria-labelledby', `title-${i}`);
|
|
176
171
|
li.appendChild(a);
|
|
177
172
|
|
|
178
|
-
const subsToShow = result.subResults
|
|
173
|
+
const subsToShow = result.subResults;
|
|
179
174
|
if (subsToShow.length > 0) {
|
|
180
175
|
const subList = doc.createElement('ul');
|
|
181
176
|
subList.className = 'sub-results';
|
|
@@ -250,10 +245,8 @@ function render(
|
|
|
250
245
|
countSpan.textContent = 'No results';
|
|
251
246
|
} else if (n === 1) {
|
|
252
247
|
countSpan.textContent = 'One result';
|
|
253
|
-
} else if (n <= MAX_RESULTS) {
|
|
254
|
-
countSpan.textContent = `${n} results`;
|
|
255
248
|
} else {
|
|
256
|
-
countSpan.textContent =
|
|
249
|
+
countSpan.textContent = `${n} results`;
|
|
257
250
|
}
|
|
258
251
|
}
|
|
259
252
|
|
|
@@ -286,64 +279,56 @@ export default (window: Window) => {
|
|
|
286
279
|
// Unhide (hidden via inline style in template to prevent FOUC)
|
|
287
280
|
resultsDiv.style.display = '';
|
|
288
281
|
|
|
289
|
-
let
|
|
290
|
-
let
|
|
291
|
-
let indexCheckInFlight = false;
|
|
292
|
-
|
|
293
|
-
async function loadPagefind() {
|
|
294
|
-
if (pagefind) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
pagefind = (await globals.importModule(
|
|
299
|
-
applyBasePath('/pagefind/pagefind.js'),
|
|
300
|
-
)) as Pagefind;
|
|
301
|
-
|
|
302
|
-
await pagefind.init();
|
|
282
|
+
let pagefindLoadPromise: Promise<boolean> | null = null;
|
|
283
|
+
let pagefindLoadGeneration = 0;
|
|
303
284
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if (res.ok) {
|
|
310
|
-
entryValidators = getResponseValidators(res);
|
|
285
|
+
function pagefindModulePath(generation: number) {
|
|
286
|
+
const path = applyBasePath('/pagefind/pagefind.js');
|
|
287
|
+
if (generation === 0) {
|
|
288
|
+
return path;
|
|
311
289
|
}
|
|
290
|
+
return `${path}?tada-pagefind-refresh=${generation}`;
|
|
312
291
|
}
|
|
313
292
|
|
|
314
|
-
async function
|
|
315
|
-
if (
|
|
316
|
-
return;
|
|
293
|
+
async function loadPagefind(): Promise<boolean> {
|
|
294
|
+
if (pagefind) {
|
|
295
|
+
return true;
|
|
317
296
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (
|
|
326
|
-
return;
|
|
297
|
+
|
|
298
|
+
const generation = pagefindLoadGeneration;
|
|
299
|
+
pagefindLoadPromise ??= (async () => {
|
|
300
|
+
const loadedPagefind = (await globals.importModule(
|
|
301
|
+
pagefindModulePath(generation),
|
|
302
|
+
)) as Pagefind;
|
|
303
|
+
|
|
304
|
+
if (generation !== pagefindLoadGeneration) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
if (generation > 0) {
|
|
308
|
+
await loadedPagefind.options({ basePath: applyBasePath('/pagefind/') });
|
|
327
309
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
invalidateUpdates();
|
|
331
|
-
pagefind = null;
|
|
332
|
-
await loadPagefind();
|
|
333
|
-
const updateId = ++latestUpdateId;
|
|
334
|
-
await update(updateId);
|
|
310
|
+
if (generation !== pagefindLoadGeneration) {
|
|
311
|
+
return false;
|
|
335
312
|
}
|
|
336
|
-
|
|
337
|
-
|
|
313
|
+
await loadedPagefind.init();
|
|
314
|
+
if (generation !== pagefindLoadGeneration) {
|
|
315
|
+
await loadedPagefind.destroy();
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
pagefind = loadedPagefind;
|
|
319
|
+
return true;
|
|
320
|
+
})();
|
|
321
|
+
|
|
322
|
+
const promise = pagefindLoadPromise;
|
|
323
|
+
try {
|
|
324
|
+
return await promise;
|
|
338
325
|
} finally {
|
|
339
|
-
|
|
326
|
+
if (pagefindLoadPromise === promise) {
|
|
327
|
+
pagefindLoadPromise = null;
|
|
328
|
+
}
|
|
340
329
|
}
|
|
341
330
|
}
|
|
342
331
|
|
|
343
|
-
loadPagefind().catch(err => {
|
|
344
|
-
console.log(`failed to load Pagefind: ${err}`);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
332
|
const state: State = {
|
|
348
333
|
value: '',
|
|
349
334
|
showResults: false,
|
|
@@ -362,10 +347,11 @@ export default (window: Window) => {
|
|
|
362
347
|
if (updateId !== latestUpdateId) {
|
|
363
348
|
return;
|
|
364
349
|
}
|
|
365
|
-
if (nextState) {
|
|
366
|
-
|
|
367
|
-
state.totalResults = nextState.totalResults;
|
|
350
|
+
if (!nextState) {
|
|
351
|
+
return;
|
|
368
352
|
}
|
|
353
|
+
state.results = nextState.results;
|
|
354
|
+
state.totalResults = nextState.totalResults;
|
|
369
355
|
if (!state.showResults) {
|
|
370
356
|
return;
|
|
371
357
|
}
|
|
@@ -381,6 +367,55 @@ export default (window: Window) => {
|
|
|
381
367
|
latestUpdateId += 1;
|
|
382
368
|
}
|
|
383
369
|
|
|
370
|
+
function loadPagefindAndUpdate() {
|
|
371
|
+
loadPagefind()
|
|
372
|
+
.then(loadedCurrentPagefind => {
|
|
373
|
+
if (loadedCurrentPagefind && state.showResults) {
|
|
374
|
+
queueUpdate();
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
.catch(err => {
|
|
378
|
+
console.log(`failed to load Pagefind: ${err}`);
|
|
379
|
+
if (state.showResults) {
|
|
380
|
+
render(input!, resultsContainer, state, false);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function invalidatePagefind() {
|
|
386
|
+
pagefindLoadGeneration += 1;
|
|
387
|
+
pagefind = null;
|
|
388
|
+
pagefindLoadPromise = null;
|
|
389
|
+
invalidateUpdates();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function reloadPagefindAfterPageUpdateRefresh() {
|
|
393
|
+
const stalePagefind = pagefind;
|
|
394
|
+
invalidatePagefind();
|
|
395
|
+
if (state.showResults) {
|
|
396
|
+
render(input!, resultsContainer, state, true);
|
|
397
|
+
}
|
|
398
|
+
if (stalePagefind) {
|
|
399
|
+
try {
|
|
400
|
+
await stalePagefind.destroy();
|
|
401
|
+
} catch (err) {
|
|
402
|
+
console.log(`failed to destroy Pagefind: ${err}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
loadPagefindAndUpdate();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function handlePageUpdateRefresh() {
|
|
409
|
+
reloadPagefindAfterPageUpdateRefresh().catch(err => {
|
|
410
|
+
console.log(`failed to reload Pagefind: ${err}`);
|
|
411
|
+
if (state.showResults) {
|
|
412
|
+
render(input!, resultsContainer, state, false);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
loadPagefindAndUpdate();
|
|
418
|
+
|
|
384
419
|
function hide() {
|
|
385
420
|
if (!state.showResults) {
|
|
386
421
|
return;
|
|
@@ -417,7 +452,6 @@ export default (window: Window) => {
|
|
|
417
452
|
if (previous && !resultsContainer.contains(previous)) {
|
|
418
453
|
previousFocus = previous;
|
|
419
454
|
}
|
|
420
|
-
checkForIndexUpdate().catch(() => {});
|
|
421
455
|
if (!state.showResults) {
|
|
422
456
|
state.showResults = true;
|
|
423
457
|
queueUpdate();
|
|
@@ -563,8 +597,13 @@ export default (window: Window) => {
|
|
|
563
597
|
window.addEventListener('pointerdown', handleWindowPointerDown);
|
|
564
598
|
window.addEventListener('pointermove', handleWindowPointerMove);
|
|
565
599
|
window.addEventListener('keydown', handleWindowKeyDown);
|
|
600
|
+
window.addEventListener(PAGE_UPDATE_REFRESH_EVENT, handlePageUpdateRefresh);
|
|
566
601
|
|
|
567
602
|
return () => {
|
|
603
|
+
window.removeEventListener(
|
|
604
|
+
PAGE_UPDATE_REFRESH_EVENT,
|
|
605
|
+
handlePageUpdateRefresh,
|
|
606
|
+
);
|
|
568
607
|
window.removeEventListener('keydown', handleWindowKeyDown);
|
|
569
608
|
window.removeEventListener('pointermove', handleWindowPointerMove);
|
|
570
609
|
window.removeEventListener('pointerdown', handleWindowPointerDown);
|
package/src/top/index.ts
CHANGED
|
@@ -30,11 +30,12 @@ export default (window: Window) => {
|
|
|
30
30
|
link.onclick = e => {
|
|
31
31
|
e.preventDefault();
|
|
32
32
|
const cleanUrl = window.location.pathname + window.location.search;
|
|
33
|
+
const historyState = window.history.state;
|
|
33
34
|
if (window.location.hash) {
|
|
34
35
|
globals.setLocationHash(window, '');
|
|
35
|
-
window.history.replaceState(
|
|
36
|
+
window.history.replaceState(historyState, '', cleanUrl);
|
|
36
37
|
} else {
|
|
37
|
-
window.history.replaceState(
|
|
38
|
+
window.history.replaceState(historyState, '', cleanUrl);
|
|
38
39
|
}
|
|
39
40
|
window.scrollTo({ top: 0 });
|
|
40
41
|
const toc = window.document.querySelector('nav.toc') as HTMLElement | null;
|