astro-accelerator 4.0.0 → 4.0.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 +4 -0
- package/package.json +6 -6
- package/src/pages/search.json.ts +6 -9
- package/.npmrc +0 -2
- package/public/css/main.css +0 -1189
- package/public/css/vars.css +0 -89
- package/public/icons/android-chrome-192x192.png +0 -0
- package/public/icons/android-chrome-512x512.png +0 -0
- package/public/icons/apple-touch-icon.png +0 -0
- package/public/icons/favicon-16x16.png +0 -0
- package/public/icons/favicon-32x32.png +0 -0
- package/public/icons/favicon.ico +0 -0
- package/public/js/main.js +0 -66
- package/public/js/modules/animation.js +0 -69
- package/public/js/modules/click-blocks.js +0 -42
- package/public/js/modules/code-blocks.js +0 -59
- package/public/js/modules/detail-tabs.js +0 -194
- package/public/js/modules/events.js +0 -19
- package/public/js/modules/external-links.js +0 -20
- package/public/js/modules/figures.js +0 -28
- package/public/js/modules/focus.js +0 -76
- package/public/js/modules/headers.js +0 -21
- package/public/js/modules/input-type.js +0 -53
- package/public/js/modules/nav-mobile.js +0 -159
- package/public/js/modules/nav-sticky.js +0 -56
- package/public/js/modules/query.js +0 -41
- package/public/js/modules/resizing.js +0 -43
- package/public/js/modules/search-dialog.js +0 -69
- package/public/js/modules/share.js +0 -31
- package/public/js/modules/string.js +0 -77
- package/public/js/modules/toc.js +0 -82
- package/public/js/modules/youtube.js +0 -44
- package/public/js/search.js +0 -615
- package/src/themes/accelerator/components/ArticleList.astro +0 -90
- package/src/themes/accelerator/components/Authors.astro +0 -65
- package/src/themes/accelerator/components/AuthorsMini.astro +0 -41
- package/src/themes/accelerator/components/Breadcrumbs.astro +0 -53
- package/src/themes/accelerator/components/Copyright.astro +0 -28
- package/src/themes/accelerator/components/Footer.astro +0 -37
- package/src/themes/accelerator/components/FooterItem.astro +0 -31
- package/src/themes/accelerator/components/Header.astro +0 -46
- package/src/themes/accelerator/components/HtmlHead.astro +0 -60
- package/src/themes/accelerator/components/Navigation.astro +0 -34
- package/src/themes/accelerator/components/NavigationBar.astro +0 -33
- package/src/themes/accelerator/components/NavigationItem.astro +0 -40
- package/src/themes/accelerator/components/PagingLinks.astro +0 -36
- package/src/themes/accelerator/components/RecentlyUpdated.astro +0 -38
- package/src/themes/accelerator/components/Related.astro +0 -87
- package/src/themes/accelerator/components/SkipLinks.astro +0 -29
- package/src/themes/accelerator/components/TableOfContents.astro +0 -46
- package/src/themes/accelerator/components/Taxonomy.astro +0 -53
- package/src/themes/accelerator/layouts/Author.astro +0 -27
- package/src/themes/accelerator/layouts/Default.astro +0 -83
- package/src/themes/accelerator/layouts/Redirect.astro +0 -29
- package/src/themes/accelerator/layouts/Search.astro +0 -48
- package/src/themes/accelerator/utilities/Languages.ts +0 -21
- package/src/themes/accelerator/utilities/custom-markdown.mjs +0 -142
- package/src/themes/accelerator/utilities/default-layout.mjs +0 -7
- package/src/themes/accelerator/utilities/img.mjs +0 -142
- package/src/themes/accelerator/utilities/language.json +0 -117
- package/src/themes/accelerator/utilities/stats.mjs +0 -44
package/public/css/vars.css
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/* Recommended Tools
|
|
2
|
-
Check accessibility for colour combinations
|
|
3
|
-
https://toolness.github.io/accessible-color-matrix/
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
:root {
|
|
7
|
-
--fore: #333;
|
|
8
|
-
--fore-headings: #225;
|
|
9
|
-
--aft: #FBFBFC;
|
|
10
|
-
|
|
11
|
-
--fore-link: #2d4295;
|
|
12
|
-
--fore-link-alt: #4D71FF;
|
|
13
|
-
--aft-link-alt: #F3F5FF;
|
|
14
|
-
|
|
15
|
-
--fore-head: #333;
|
|
16
|
-
--aft-head: #E6E8F1;
|
|
17
|
-
|
|
18
|
-
--fore-breadcrumb: #333;
|
|
19
|
-
--aft-breadcrumb: #F3F5FF;
|
|
20
|
-
|
|
21
|
-
--link-head: #2d4295;
|
|
22
|
-
--link-alt-head: #2a4dd8;
|
|
23
|
-
|
|
24
|
-
--fore-block: #333;
|
|
25
|
-
--aft-block: #F3F5FF;
|
|
26
|
-
--icon-block: #4D71FF;
|
|
27
|
-
|
|
28
|
-
--fore-table-head: #FDFDFE;
|
|
29
|
-
--aft-table-head: #2F3141;
|
|
30
|
-
--fore-table-row-odd: #333;
|
|
31
|
-
--aft-table-row-odd: #FDFDFE;
|
|
32
|
-
--fore-table-row-even: #333;
|
|
33
|
-
--aft-table-row-even: #F3F5FF;
|
|
34
|
-
|
|
35
|
-
--heading-font: Georgia, 'Times New Roman', Times, serif;
|
|
36
|
-
--content-font: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
37
|
-
--code-font: Consolas, 'Courier New', Courier, monospace;
|
|
38
|
-
--unicode-font: "Segoe UI Symbol", "Arial Unicode MS", sans-serif;
|
|
39
|
-
|
|
40
|
-
--block-gap: 2rem;
|
|
41
|
-
--block-radius: 0.3rem;
|
|
42
|
-
|
|
43
|
-
--marker-size: 1.2rem;
|
|
44
|
-
--paragraph-margin: 1.2rem;
|
|
45
|
-
|
|
46
|
-
--box-shadow: 0 12px 24px -12px rgb(0 0 0 / 80%);
|
|
47
|
-
--box-shadow-slight: 0 6px 12px -6px rgb(0 0 0 / 40%);
|
|
48
|
-
|
|
49
|
-
--content-width: 78vw;
|
|
50
|
-
--navigation-width: 260px;
|
|
51
|
-
--grid-gap: 1rem;
|
|
52
|
-
--grid-max-width: 60rem;
|
|
53
|
-
--grid-width: 90vw;
|
|
54
|
-
|
|
55
|
-
/* Calculate the mobile width by removing l/r columns and grid gap */
|
|
56
|
-
--content-width-mobile: calc(100vw - (1rem * 2));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@media (prefers-color-scheme: dark) {
|
|
60
|
-
:root {
|
|
61
|
-
--fore: #CCC;
|
|
62
|
-
--fore-headings: #CCE;
|
|
63
|
-
--aft: #333;
|
|
64
|
-
|
|
65
|
-
--fore-link: #abb9ef;
|
|
66
|
-
--fore-link-alt: #abb9ef;
|
|
67
|
-
--aft-link-alt: #232323;
|
|
68
|
-
|
|
69
|
-
--fore-head: #CCC;
|
|
70
|
-
--aft-head: #222;
|
|
71
|
-
|
|
72
|
-
--fore-breadcrumb: #CCC;
|
|
73
|
-
--aft-breadcrumb: #2C2C2C;
|
|
74
|
-
|
|
75
|
-
--link-head: #abb9ef;
|
|
76
|
-
--link-alt-head: #6580ed;
|
|
77
|
-
|
|
78
|
-
--fore-block: #CCC;
|
|
79
|
-
--aft-block: #111;
|
|
80
|
-
--icon-block: #abb9ef;
|
|
81
|
-
|
|
82
|
-
--fore-table-head: #CCC;
|
|
83
|
-
--aft-table-head: #222;
|
|
84
|
-
--fore-table-row-odd: #CCC;
|
|
85
|
-
--aft-table-row-odd: #333;
|
|
86
|
-
--fore-table-row-even: #CCC;
|
|
87
|
-
--aft-table-row-even: #444;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/public/icons/favicon.ico
DELETED
|
Binary file
|
package/public/js/main.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import { addIntersectionObserver, addListImageIntersectionObserver } from './modules/animation.js';
|
|
3
|
-
import { addResizedEvent } from './modules/resizing.js';
|
|
4
|
-
import { addStickyNavigation } from './modules/nav-sticky.js';
|
|
5
|
-
import { addMobileNav } from './modules/nav-mobile.js';
|
|
6
|
-
import { setClickableBlocks } from './modules/click-blocks.js';
|
|
7
|
-
import { setExternalLinkAttributes } from './modules/external-links.js';
|
|
8
|
-
import { monitorInputType } from './modules/input-type.js';
|
|
9
|
-
import { enableSharing } from './modules/share.js';
|
|
10
|
-
import { highlightCurrentHeading } from './modules/toc.js';
|
|
11
|
-
|
|
12
|
-
const resizedEventName = addResizedEvent();
|
|
13
|
-
|
|
14
|
-
setClickableBlocks();
|
|
15
|
-
setExternalLinkAttributes();
|
|
16
|
-
addStickyNavigation('.site-header', '#site-nav', '#site-nav > ul', resizedEventName);
|
|
17
|
-
addMobileNav(resizedEventName);
|
|
18
|
-
addIntersectionObserver('.anim-show-parent img, .anim-show-parent .list-item');
|
|
19
|
-
addListImageIntersectionObserver('.post-list img');
|
|
20
|
-
monitorInputType();
|
|
21
|
-
enableSharing();
|
|
22
|
-
highlightCurrentHeading('.page-toc a');
|
|
23
|
-
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
const f = site_features ?? {};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
* @param {string[]} settings
|
|
30
|
-
* @param {string} option
|
|
31
|
-
* @returns
|
|
32
|
-
*/
|
|
33
|
-
function enabled(settings, option) {
|
|
34
|
-
return settings
|
|
35
|
-
&& settings.includes(option);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (enabled(f.details, 'tabs')) {
|
|
39
|
-
const tabs = await import('./modules/detail-tabs.js');
|
|
40
|
-
tabs.enhanceDetailGroups();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (enabled(f.youTubeLinks, 'embed')) {
|
|
44
|
-
const youTube = await import('./modules/youtube.js');
|
|
45
|
-
youTube.enhanceYoutubeLinks();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (enabled(f.codeBlocks, 'copy')) {
|
|
49
|
-
const codeBlocks = await import('./modules/code-blocks.js');
|
|
50
|
-
codeBlocks.enhanceCodeBlocks();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (enabled(f.figures, 'enlarge')) {
|
|
54
|
-
const figures = await import('./modules/figures.js');
|
|
55
|
-
figures.enhanceFigures();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (enabled(f.headers, 'link')) {
|
|
59
|
-
const headers = await import('./modules/headers.js');
|
|
60
|
-
headers.enhanceHeaders();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (enabled(f.search, 'dialog')) {
|
|
64
|
-
const searchDialog = await import ('./modules/search-dialog.js');
|
|
65
|
-
searchDialog.enhanceSearchIcon();
|
|
66
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { qsa } from './query.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Assists animation by setting "--shown" CSS property
|
|
7
|
-
*
|
|
8
|
-
* When an item is visible in the viewport, it will have --shown: 1
|
|
9
|
-
* Otherwise it will be --shown: 0
|
|
10
|
-
* This allows CSS transitions and calculated properties to animate elements
|
|
11
|
-
*
|
|
12
|
-
* Example
|
|
13
|
-
* transition: all 0.2s ease-in;
|
|
14
|
-
* scale: calc(0.75 + (var(--shown, 1) * 0.25));
|
|
15
|
-
*
|
|
16
|
-
* @param {string} listItemQuery
|
|
17
|
-
*/
|
|
18
|
-
function addIntersectionObserver(listItemQuery) {
|
|
19
|
-
function handleIntersection(entries, observer) {
|
|
20
|
-
for (let entry of entries) {
|
|
21
|
-
const value = entry.isIntersecting ? 1 : 0;
|
|
22
|
-
entry.target.style.setProperty('--shown', value);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const options = {
|
|
27
|
-
root: null,
|
|
28
|
-
rootMargin: '0px',
|
|
29
|
-
threshold: 0
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const observer = new IntersectionObserver(handleIntersection, options)
|
|
33
|
-
|
|
34
|
-
qsa(listItemQuery).forEach((elem) => observer.observe(elem));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Assists animation by setting "--shown" CSS property
|
|
39
|
-
*
|
|
40
|
-
* When an item is visible in the viewport, it will have --shown: 1
|
|
41
|
-
* Otherwise it will be --shown: 0
|
|
42
|
-
* This allows CSS transitions and calculated properties to animate elements
|
|
43
|
-
*
|
|
44
|
-
* Example
|
|
45
|
-
* transition: all 0.2s ease-in;
|
|
46
|
-
* scale: calc(0.75 + (var(--shown, 1) * 0.25));
|
|
47
|
-
*
|
|
48
|
-
* @param {string} imgItemQuery
|
|
49
|
-
*/
|
|
50
|
-
function addListImageIntersectionObserver(imgItemQuery) {
|
|
51
|
-
function handleIntersection(entries, observer) {
|
|
52
|
-
for (let entry of entries) {
|
|
53
|
-
const value = entry.isIntersecting ? 1 : 0;
|
|
54
|
-
entry.target.style.setProperty('--imgshown', value);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const options = {
|
|
59
|
-
root: null,
|
|
60
|
-
rootMargin: '0px',
|
|
61
|
-
threshold: 0.5
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const observer = new IntersectionObserver(handleIntersection, options)
|
|
65
|
-
|
|
66
|
-
qsa(imgItemQuery).forEach((elem) => observer.observe(elem));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export { addIntersectionObserver, addListImageIntersectionObserver };
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { qsa } from './query.js';
|
|
4
|
-
|
|
5
|
-
const dataAttributeName = 'data-destination';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Makes an entire block clickable based on a data-attribute, usually "data-destination"
|
|
9
|
-
*
|
|
10
|
-
* Example: You have a list of blog posts, including featured images. If you make the title
|
|
11
|
-
* clickable, clicks on the image won't open the blog. Adding links to the images means
|
|
12
|
-
* keyboard users have to tab twice as much to get through the list.
|
|
13
|
-
*
|
|
14
|
-
* Use clickable blocks to allow keyboard users to tab through the real links, but still
|
|
15
|
-
* capture clicks elsewhere on the block.
|
|
16
|
-
*
|
|
17
|
-
*/
|
|
18
|
-
function setClickableBlocks() {
|
|
19
|
-
qsa('[' + dataAttributeName + ']').forEach((listItem) => {
|
|
20
|
-
listItem.style.cursor = 'pointer';
|
|
21
|
-
listItem.addEventListener('click', handleClick);
|
|
22
|
-
listItem.addEventListener('touch', handleClick);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Handles the block-level clicks
|
|
28
|
-
*
|
|
29
|
-
* @param {Event} e
|
|
30
|
-
* @returns
|
|
31
|
-
*/
|
|
32
|
-
function handleClick(e) {
|
|
33
|
-
const location = this.getAttribute(dataAttributeName);
|
|
34
|
-
|
|
35
|
-
if (location) {
|
|
36
|
-
e.preventDefault();
|
|
37
|
-
document.location = location;
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export { setClickableBlocks };
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { qs, qsa } from './query.js';
|
|
2
|
-
|
|
3
|
-
const activeClass = "copy-button";
|
|
4
|
-
|
|
5
|
-
const clipboard = `<svg xmlns="http://www.w3.org/2000/svg" title="Copy" width="30" height="30" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
6
|
-
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
7
|
-
<path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" />
|
|
8
|
-
<rect x="9" y="3" width="6" height="4" rx="2" />
|
|
9
|
-
</svg>`;
|
|
10
|
-
|
|
11
|
-
const clipboardDone = `<svg xmlns="http://www.w3.org/2000/svg" title="Copied" width="30" height="30" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
12
|
-
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
13
|
-
<path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" />
|
|
14
|
-
<rect x="9" y="3" width="6" height="4" rx="2" />
|
|
15
|
-
<path d="M9 14l2 2l4 -4" />
|
|
16
|
-
</svg>`;
|
|
17
|
-
|
|
18
|
-
const clipboardError = `<svg xmlns="http://www.w3.org/2000/svg" title="Cannot copy" width="30" height="30" viewBox="0 0 24 24" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
19
|
-
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
|
20
|
-
<path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" />
|
|
21
|
-
<rect x="9" y="3" width="6" height="4" rx="2" />
|
|
22
|
-
<path d="M10 12l4 4m0 -4l-4 4" />
|
|
23
|
-
</svg>`
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Enables copy on code blocks (<pre><code>...)
|
|
27
|
-
*/
|
|
28
|
-
function enhanceCodeBlocks() {
|
|
29
|
-
|
|
30
|
-
// Make code blocks focusable, so they can be keyboard scrolled
|
|
31
|
-
qsa('pre.astro-code').forEach((elem) => elem.setAttribute('tabindex', '0'));
|
|
32
|
-
|
|
33
|
-
qsa(`pre:not(.${activeClass})`).forEach(node => {
|
|
34
|
-
const copy = document.createElement('button');
|
|
35
|
-
copy.classList.add(activeClass);
|
|
36
|
-
copy.innerHTML = clipboard;
|
|
37
|
-
copy.title = 'Copy';
|
|
38
|
-
|
|
39
|
-
const copyContainer = document.createElement('div');
|
|
40
|
-
copyContainer.className = 'copy-container';
|
|
41
|
-
copyContainer.appendChild(copy);
|
|
42
|
-
|
|
43
|
-
node.insertAdjacentElement('beforebegin', copyContainer);
|
|
44
|
-
copy.addEventListener('click', async () => {
|
|
45
|
-
if (navigator.clipboard) {
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
const text = qs('code', node).innerText;
|
|
48
|
-
await navigator.clipboard.writeText(text);
|
|
49
|
-
copy.innerHTML = clipboardDone;
|
|
50
|
-
} else {
|
|
51
|
-
copy.innerHTML = clipboardError;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
setTimeout(() => copy.innerHTML = clipboard, 2000);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export { enhanceCodeBlocks }
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { qs, qsa } from './query.js';
|
|
2
|
-
|
|
3
|
-
function unique(value, index, array) {
|
|
4
|
-
return array.indexOf(value) === index;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Converts <detail data-group="id"> into tabs
|
|
9
|
-
*/
|
|
10
|
-
function enhanceDetailGroups() {
|
|
11
|
-
const details = qsa('details[data-group]');
|
|
12
|
-
const groups = [];
|
|
13
|
-
|
|
14
|
-
details.forEach(d => d.dataset && d.dataset.group && groups.push(d.dataset.group));
|
|
15
|
-
let uniqueGroups = groups.filter(unique);
|
|
16
|
-
|
|
17
|
-
uniqueGroups.forEach(g => {
|
|
18
|
-
const participants = qsa(`details[data-group='${ g }']`);
|
|
19
|
-
if (participants.length === 0) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const tablist = document.createElement('div');
|
|
24
|
-
tablist.role = 'tablist';
|
|
25
|
-
tablist.className = 'tab-list';
|
|
26
|
-
participants[0].parentNode.insertBefore(tablist, participants[0]);
|
|
27
|
-
|
|
28
|
-
participants.forEach((p, i) => {
|
|
29
|
-
|
|
30
|
-
const heading = qs('summary', p);
|
|
31
|
-
|
|
32
|
-
// Create the tab panel
|
|
33
|
-
|
|
34
|
-
const tabPanel = document.createElement('div');
|
|
35
|
-
tabPanel.setAttribute('tabindex', '0');
|
|
36
|
-
tabPanel.setAttribute('role', 'tabpanel');
|
|
37
|
-
tabPanel.setAttribute('aria-labelledby', `aatb_${ g }_${ i }`);
|
|
38
|
-
tabPanel.id = `aatb_panel_${ g }_${ i }`;
|
|
39
|
-
|
|
40
|
-
const content = document.createElement('div');
|
|
41
|
-
content.innerHTML = p.innerHTML;
|
|
42
|
-
const contentSummary = qs('summary', content);
|
|
43
|
-
content.removeChild(contentSummary);
|
|
44
|
-
|
|
45
|
-
tabPanel.appendChild(content);
|
|
46
|
-
|
|
47
|
-
participants[0].parentNode.insertBefore(tabPanel, participants[0]);
|
|
48
|
-
|
|
49
|
-
// Create the tab control
|
|
50
|
-
|
|
51
|
-
const tabButton = document.createElement('button');
|
|
52
|
-
tabButton.id = `aatb_${ g }_${ i }`;
|
|
53
|
-
tabButton.type = 'button';
|
|
54
|
-
tabButton.setAttribute('role', 'tab');
|
|
55
|
-
tabButton.setAttribute('aria-selected', i == 0 ? 'true' : 'false');
|
|
56
|
-
tabButton.setAttribute('aria-controls', tabPanel.id);
|
|
57
|
-
|
|
58
|
-
const tabHeading = document.createElement('span');
|
|
59
|
-
tabHeading.className = 'focus';
|
|
60
|
-
tabHeading.innerText = heading.innerText;
|
|
61
|
-
|
|
62
|
-
tabButton.appendChild(tabHeading);
|
|
63
|
-
tablist.appendChild(tabButton);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
new TabsManual(tablist);
|
|
67
|
-
|
|
68
|
-
participants.forEach((p, i) => {
|
|
69
|
-
p.parentNode.removeChild(p);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// remove details elements
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
class TabsManual {
|
|
78
|
-
constructor(groupNode) {
|
|
79
|
-
this.tablistNode = groupNode;
|
|
80
|
-
|
|
81
|
-
this.tabs = [];
|
|
82
|
-
|
|
83
|
-
this.firstTab = null;
|
|
84
|
-
this.lastTab = null;
|
|
85
|
-
|
|
86
|
-
this.tabs = Array.from(this.tablistNode.querySelectorAll('[role=tab]'));
|
|
87
|
-
this.tabpanels = [];
|
|
88
|
-
|
|
89
|
-
for (var i = 0; i < this.tabs.length; i += 1) {
|
|
90
|
-
var tab = this.tabs[i];
|
|
91
|
-
var tabpanel = document.getElementById(tab.getAttribute('aria-controls'));
|
|
92
|
-
|
|
93
|
-
tab.tabIndex = -1;
|
|
94
|
-
tab.setAttribute('aria-selected', 'false');
|
|
95
|
-
this.tabpanels.push(tabpanel);
|
|
96
|
-
|
|
97
|
-
tab.addEventListener('keydown', this.onKeydown.bind(this));
|
|
98
|
-
tab.addEventListener('click', this.onClick.bind(this));
|
|
99
|
-
|
|
100
|
-
if (!this.firstTab) {
|
|
101
|
-
this.firstTab = tab;
|
|
102
|
-
}
|
|
103
|
-
this.lastTab = tab;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
this.setSelectedTab(this.firstTab);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
setSelectedTab(currentTab) {
|
|
110
|
-
for (var i = 0; i < this.tabs.length; i += 1) {
|
|
111
|
-
var tab = this.tabs[i];
|
|
112
|
-
if (currentTab === tab) {
|
|
113
|
-
tab.setAttribute('aria-selected', 'true');
|
|
114
|
-
tab.removeAttribute('tabindex');
|
|
115
|
-
this.tabpanels[i].classList.remove('is-hidden');
|
|
116
|
-
} else {
|
|
117
|
-
tab.setAttribute('aria-selected', 'false');
|
|
118
|
-
tab.tabIndex = -1;
|
|
119
|
-
this.tabpanels[i].classList.add('is-hidden');
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
moveFocusToTab(currentTab) {
|
|
125
|
-
currentTab.focus();
|
|
126
|
-
this.setSelectedTab(currentTab);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
moveFocusToPreviousTab(currentTab) {
|
|
130
|
-
var index;
|
|
131
|
-
|
|
132
|
-
if (currentTab === this.firstTab) {
|
|
133
|
-
this.moveFocusToTab(this.lastTab);
|
|
134
|
-
} else {
|
|
135
|
-
index = this.tabs.indexOf(currentTab);
|
|
136
|
-
this.moveFocusToTab(this.tabs[index - 1]);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
moveFocusToNextTab(currentTab) {
|
|
141
|
-
var index;
|
|
142
|
-
|
|
143
|
-
if (currentTab === this.lastTab) {
|
|
144
|
-
this.moveFocusToTab(this.firstTab);
|
|
145
|
-
} else {
|
|
146
|
-
index = this.tabs.indexOf(currentTab);
|
|
147
|
-
this.moveFocusToTab(this.tabs[index + 1]);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* EVENT HANDLERS */
|
|
152
|
-
|
|
153
|
-
onKeydown(event) {
|
|
154
|
-
var tgt = event.currentTarget,
|
|
155
|
-
flag = false;
|
|
156
|
-
|
|
157
|
-
switch (event.key) {
|
|
158
|
-
case 'ArrowLeft':
|
|
159
|
-
this.moveFocusToPreviousTab(tgt);
|
|
160
|
-
flag = true;
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case 'ArrowRight':
|
|
164
|
-
this.moveFocusToNextTab(tgt);
|
|
165
|
-
flag = true;
|
|
166
|
-
break;
|
|
167
|
-
|
|
168
|
-
case 'Home':
|
|
169
|
-
this.moveFocusToTab(this.firstTab);
|
|
170
|
-
flag = true;
|
|
171
|
-
break;
|
|
172
|
-
|
|
173
|
-
case 'End':
|
|
174
|
-
this.moveFocusToTab(this.lastTab);
|
|
175
|
-
flag = true;
|
|
176
|
-
break;
|
|
177
|
-
|
|
178
|
-
default:
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (flag) {
|
|
183
|
-
event.stopPropagation();
|
|
184
|
-
event.preventDefault();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
onClick(event) {
|
|
189
|
-
this.setSelectedTab(event.currentTarget);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
export { enhanceDetailGroups }
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
*
|
|
5
|
-
* @param {string} name
|
|
6
|
-
* @param {{[key: string]: any}} detail
|
|
7
|
-
* @param {Document | HTMLElement} [target]
|
|
8
|
-
*/
|
|
9
|
-
function raiseEvent(name, detail, target) {
|
|
10
|
-
if (!target) {
|
|
11
|
-
target = document;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const event = new CustomEvent(name, { detail: detail});
|
|
15
|
-
document.dispatchEvent(event);
|
|
16
|
-
console.log('Event Raised', name, detail);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { raiseEvent };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { qsa } from './query.js';
|
|
2
|
-
|
|
3
|
-
function setExternalLinkAttributes() {
|
|
4
|
-
// Open external links in a new tab
|
|
5
|
-
qsa('a[href^=http]').forEach((link) => {
|
|
6
|
-
// Open external links in a new tab
|
|
7
|
-
const destination = new URL(link.href);
|
|
8
|
-
if (destination.hostname != window.location.hostname) {
|
|
9
|
-
if (!link.target) {
|
|
10
|
-
link.setAttribute('target', '_blank');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (!link.rel) {
|
|
14
|
-
link.setAttribute('rel', 'noopener');
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export { setExternalLinkAttributes }
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { qs, qsa } from './query.js';
|
|
2
|
-
|
|
3
|
-
const activeClass = 'magnify-icon';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Enables opening image in new tab
|
|
7
|
-
*/
|
|
8
|
-
function enhanceFigures() {
|
|
9
|
-
qsa(`figure > p > img`).forEach(node => {
|
|
10
|
-
const src = node.src;
|
|
11
|
-
|
|
12
|
-
const magnify = document.createElement('button');
|
|
13
|
-
magnify.classList.add(activeClass);
|
|
14
|
-
magnify.title = 'Enlarge';
|
|
15
|
-
|
|
16
|
-
const magnifyContainer = document.createElement('div');
|
|
17
|
-
magnifyContainer.className = 'magnify-container';
|
|
18
|
-
magnifyContainer.appendChild(magnify);
|
|
19
|
-
|
|
20
|
-
node.insertAdjacentElement('beforebegin', magnifyContainer);
|
|
21
|
-
|
|
22
|
-
magnify.addEventListener('click', async () => {
|
|
23
|
-
window.open(src);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { enhanceFigures }
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { qsa } from './query.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Gets first, last, and all focusable elements in the target
|
|
7
|
-
*
|
|
8
|
-
* For the supplied element, finds all the elements that can receive keyboard focus.
|
|
9
|
-
*
|
|
10
|
-
* Examples: a, button, input, textarea, select, and other valid interactive items
|
|
11
|
-
* that haven't been disabled or hidden.
|
|
12
|
-
*
|
|
13
|
-
* @param {HTMLElement} target element
|
|
14
|
-
* @returns {{first: HTMLElement, last: HTMLElement, all: HTMLElement[]}}
|
|
15
|
-
*/
|
|
16
|
-
function getFocusableElement(target) {
|
|
17
|
-
const focusElements = Array.from(
|
|
18
|
-
qsa('a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])', target)
|
|
19
|
-
).filter(function(el) {
|
|
20
|
-
return !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
first: focusElements[0],
|
|
25
|
-
last: focusElements[focusElements.length -1],
|
|
26
|
-
all: focusElements
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Mechanism to trap focus
|
|
32
|
-
*
|
|
33
|
-
* @param {KeyboardEvent} event
|
|
34
|
-
* @param {HTMLElement} focusItem
|
|
35
|
-
* @returns
|
|
36
|
-
*/
|
|
37
|
-
function trapFocus(event, focusItem) {
|
|
38
|
-
switch (event.code.toLowerCase()) {
|
|
39
|
-
case 'tab':
|
|
40
|
-
event.preventDefault();
|
|
41
|
-
focusItem.focus();
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Mechanism to trap focus (TAB)
|
|
48
|
-
*
|
|
49
|
-
* @param {KeyboardEvent} event
|
|
50
|
-
* @param {HTMLElement} focusItem
|
|
51
|
-
* @returns
|
|
52
|
-
*/
|
|
53
|
-
function trapFocusForward(event, focusItem) {
|
|
54
|
-
if (event.shiftKey) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
trapFocus(event, focusItem);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Mechanism to trap tab (SHIFT + TAB)
|
|
63
|
-
*
|
|
64
|
-
* @param {KeyboardEvent} event
|
|
65
|
-
* @param {HTMLElement} focusItem
|
|
66
|
-
* @returns
|
|
67
|
-
*/
|
|
68
|
-
function trapReverseFocus(event, focusItem) {
|
|
69
|
-
if (!event.shiftKey) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
trapFocus(event, focusItem);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export { getFocusableElement, trapFocusForward, trapReverseFocus };
|