@abreen/tada 1.15.3 → 1.15.5
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/hash-target.ts +29 -0
- package/src/index.ts +2 -5
- package/src/navigate/index.ts +8 -7
- package/src/slides/index.ts +8 -2
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* markdown-it-anchor's slugifier uses encodeURIComponent() so generated
|
|
3
|
+
* heading IDs can safely be used as URL hashes.
|
|
4
|
+
*
|
|
5
|
+
* Tada also allows raw HTML, so an author can create a decoded ID like
|
|
6
|
+
* <h2 id="hello world">Hello</h2>. A link to that target becomes
|
|
7
|
+
* #hello%20world, and getElementById('hello%20world') would not find it.
|
|
8
|
+
*/
|
|
9
|
+
export function getHashTarget(
|
|
10
|
+
document: Document,
|
|
11
|
+
hash: string,
|
|
12
|
+
): HTMLElement | null {
|
|
13
|
+
const id = hash.slice(1);
|
|
14
|
+
if (!id) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const rawTarget = document.getElementById(id);
|
|
19
|
+
if (rawTarget) {
|
|
20
|
+
return rawTarget;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const decodedId = decodeURIComponent(id);
|
|
25
|
+
return decodedId === id ? null : document.getElementById(decodedId);
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import mountTop from './top';
|
|
|
21
21
|
import mountNavigate from './navigate';
|
|
22
22
|
import mountPageUpdate from './page-update';
|
|
23
23
|
import { mountPerPageComponents } from './navigate/lifecycle';
|
|
24
|
+
import { getHashTarget } from './hash-target';
|
|
24
25
|
|
|
25
26
|
import { scheduleTask, formatDuration } from './util';
|
|
26
27
|
|
|
@@ -68,11 +69,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
68
69
|
// finished mutating the DOM. On a fresh cold load the browser already
|
|
69
70
|
// scrolled, so this is a harmless re-align.
|
|
70
71
|
if (window.location.hash) {
|
|
71
|
-
|
|
72
|
-
const el = window.document.getElementById(id);
|
|
73
|
-
if (el) {
|
|
74
|
-
el.scrollIntoView();
|
|
75
|
-
}
|
|
72
|
+
getHashTarget(window.document, window.location.hash)?.scrollIntoView();
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
for (const [name, reason] of Object.entries(failed)) {
|
package/src/navigate/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
setHistoryIndex,
|
|
14
14
|
} from './runtime';
|
|
15
15
|
import { globals } from '../globals';
|
|
16
|
+
import { getHashTarget } from '../hash-target';
|
|
16
17
|
|
|
17
18
|
function findAnchor(event: MouseEvent): HTMLAnchorElement | null {
|
|
18
19
|
const target = event.target as HTMLElement | null;
|
|
@@ -78,7 +79,11 @@ export default function mountNavigate(window: Window): () => void {
|
|
|
78
79
|
clearSearch(window.document);
|
|
79
80
|
closeHeaderDetails(window.document);
|
|
80
81
|
if (url.hash) {
|
|
81
|
-
|
|
82
|
+
if (url.hash === window.location.hash) {
|
|
83
|
+
getHashTarget(window.document, url.hash)?.scrollIntoView();
|
|
84
|
+
} else {
|
|
85
|
+
globals.setLocationHash(window, url.hash);
|
|
86
|
+
}
|
|
82
87
|
}
|
|
83
88
|
return;
|
|
84
89
|
}
|
|
@@ -112,12 +117,8 @@ export default function mountNavigate(window: Window): () => void {
|
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
// Same page, different hash: fall back to the fragment target
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const el = window.document.getElementById(hash);
|
|
118
|
-
if (el) {
|
|
119
|
-
el.scrollIntoView();
|
|
120
|
-
}
|
|
120
|
+
if (window.location.hash) {
|
|
121
|
+
getHashTarget(window.document, window.location.hash)?.scrollIntoView();
|
|
121
122
|
} else {
|
|
122
123
|
window.scrollTo({ top: 0 });
|
|
123
124
|
}
|
package/src/slides/index.ts
CHANGED
|
@@ -144,6 +144,7 @@ export default function mountSlides(window: Window): void | (() => void) {
|
|
|
144
144
|
let isAnnotating = false;
|
|
145
145
|
let isShiftPressed = false;
|
|
146
146
|
let isErasing = false;
|
|
147
|
+
let isDrivingTrace = false;
|
|
147
148
|
let activeAnnotation: {
|
|
148
149
|
slide: HTMLElement;
|
|
149
150
|
previousX: number;
|
|
@@ -374,7 +375,12 @@ export default function mountSlides(window: Window): void | (() => void) {
|
|
|
374
375
|
continue;
|
|
375
376
|
}
|
|
376
377
|
|
|
377
|
-
|
|
378
|
+
isDrivingTrace = true;
|
|
379
|
+
try {
|
|
380
|
+
button.click();
|
|
381
|
+
} finally {
|
|
382
|
+
isDrivingTrace = false;
|
|
383
|
+
}
|
|
378
384
|
return true;
|
|
379
385
|
}
|
|
380
386
|
|
|
@@ -863,7 +869,7 @@ export default function mountSlides(window: Window): void | (() => void) {
|
|
|
863
869
|
}
|
|
864
870
|
|
|
865
871
|
function handleAnnotationClick(event: MouseEvent): void {
|
|
866
|
-
if (!isPresenting || !isAnnotating) {
|
|
872
|
+
if (!isPresenting || !isAnnotating || isDrivingTrace) {
|
|
867
873
|
return;
|
|
868
874
|
}
|
|
869
875
|
|