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.
Files changed (61) hide show
  1. package/README.md +4 -0
  2. package/package.json +6 -6
  3. package/src/pages/search.json.ts +6 -9
  4. package/.npmrc +0 -2
  5. package/public/css/main.css +0 -1189
  6. package/public/css/vars.css +0 -89
  7. package/public/icons/android-chrome-192x192.png +0 -0
  8. package/public/icons/android-chrome-512x512.png +0 -0
  9. package/public/icons/apple-touch-icon.png +0 -0
  10. package/public/icons/favicon-16x16.png +0 -0
  11. package/public/icons/favicon-32x32.png +0 -0
  12. package/public/icons/favicon.ico +0 -0
  13. package/public/js/main.js +0 -66
  14. package/public/js/modules/animation.js +0 -69
  15. package/public/js/modules/click-blocks.js +0 -42
  16. package/public/js/modules/code-blocks.js +0 -59
  17. package/public/js/modules/detail-tabs.js +0 -194
  18. package/public/js/modules/events.js +0 -19
  19. package/public/js/modules/external-links.js +0 -20
  20. package/public/js/modules/figures.js +0 -28
  21. package/public/js/modules/focus.js +0 -76
  22. package/public/js/modules/headers.js +0 -21
  23. package/public/js/modules/input-type.js +0 -53
  24. package/public/js/modules/nav-mobile.js +0 -159
  25. package/public/js/modules/nav-sticky.js +0 -56
  26. package/public/js/modules/query.js +0 -41
  27. package/public/js/modules/resizing.js +0 -43
  28. package/public/js/modules/search-dialog.js +0 -69
  29. package/public/js/modules/share.js +0 -31
  30. package/public/js/modules/string.js +0 -77
  31. package/public/js/modules/toc.js +0 -82
  32. package/public/js/modules/youtube.js +0 -44
  33. package/public/js/search.js +0 -615
  34. package/src/themes/accelerator/components/ArticleList.astro +0 -90
  35. package/src/themes/accelerator/components/Authors.astro +0 -65
  36. package/src/themes/accelerator/components/AuthorsMini.astro +0 -41
  37. package/src/themes/accelerator/components/Breadcrumbs.astro +0 -53
  38. package/src/themes/accelerator/components/Copyright.astro +0 -28
  39. package/src/themes/accelerator/components/Footer.astro +0 -37
  40. package/src/themes/accelerator/components/FooterItem.astro +0 -31
  41. package/src/themes/accelerator/components/Header.astro +0 -46
  42. package/src/themes/accelerator/components/HtmlHead.astro +0 -60
  43. package/src/themes/accelerator/components/Navigation.astro +0 -34
  44. package/src/themes/accelerator/components/NavigationBar.astro +0 -33
  45. package/src/themes/accelerator/components/NavigationItem.astro +0 -40
  46. package/src/themes/accelerator/components/PagingLinks.astro +0 -36
  47. package/src/themes/accelerator/components/RecentlyUpdated.astro +0 -38
  48. package/src/themes/accelerator/components/Related.astro +0 -87
  49. package/src/themes/accelerator/components/SkipLinks.astro +0 -29
  50. package/src/themes/accelerator/components/TableOfContents.astro +0 -46
  51. package/src/themes/accelerator/components/Taxonomy.astro +0 -53
  52. package/src/themes/accelerator/layouts/Author.astro +0 -27
  53. package/src/themes/accelerator/layouts/Default.astro +0 -83
  54. package/src/themes/accelerator/layouts/Redirect.astro +0 -29
  55. package/src/themes/accelerator/layouts/Search.astro +0 -48
  56. package/src/themes/accelerator/utilities/Languages.ts +0 -21
  57. package/src/themes/accelerator/utilities/custom-markdown.mjs +0 -142
  58. package/src/themes/accelerator/utilities/default-layout.mjs +0 -7
  59. package/src/themes/accelerator/utilities/img.mjs +0 -142
  60. package/src/themes/accelerator/utilities/language.json +0 -117
  61. package/src/themes/accelerator/utilities/stats.mjs +0 -44
@@ -1,21 +0,0 @@
1
- import { qsa } from './query.js';
2
-
3
- /**
4
- * Enables copy on code blocks (<pre><code>...)
5
- */
6
- function enhanceHeaders() {
7
-
8
- // Make code blocks focusable, so they can be keyboard scrolled
9
- qsa('h2[id], h3[id], h4[id], h5[id], h6[id]').forEach((elem) => {
10
- const linkContainer = document.createElement('a');
11
- linkContainer.href = `#${elem.id}`;
12
- linkContainer.className = 'bookmark-link';
13
- linkContainer.innerHTML = 'Bookmark'
14
- console.log(elem, typeof elem);
15
- elem.appendChild(linkContainer);
16
- });
17
-
18
-
19
- }
20
-
21
- export { enhanceHeaders }
@@ -1,53 +0,0 @@
1
- // @ts-check
2
-
3
- let inputType = 'unknown';
4
-
5
- /**
6
- * Sets the user input mode as a class
7
- */
8
- function monitorInputType() {
9
- window.addEventListener('keydown', event => {
10
- const eventType = 'input-keyboard';
11
- processInput(eventType);
12
- });
13
-
14
- window.addEventListener('mousemove', event => {
15
- const eventType = 'input-mouse';
16
- processInput(eventType);
17
- });
18
-
19
- window.addEventListener('touchstart', event => {
20
- const eventType = 'input-touch';
21
- processInput(eventType);
22
- });
23
- }
24
-
25
- /**
26
- * Processes the keyboard, mouse, or touch event
27
- * @param {string} eventType
28
- */
29
- function processInput(eventType) {
30
- if (inputType !== eventType) {
31
- removeClass(inputType);
32
- inputType = eventType;
33
- addClass(inputType);
34
- }
35
- }
36
-
37
- /**
38
- * Removes an input type class from the body
39
- * @param {string} inputType
40
- */
41
- function removeClass(inputType) {
42
- document.body.classList.remove(inputType);
43
- }
44
-
45
- /**
46
- * Adds an input type class to the body
47
- * @param {string} inputType
48
- */
49
- function addClass(inputType) {
50
- document.body.classList.add(inputType);
51
- }
52
-
53
- export { monitorInputType };
@@ -1,159 +0,0 @@
1
- // @ts-check
2
-
3
- import { qs, qsa } from './query.js';
4
- import { getFocusableElement, trapFocusForward, trapReverseFocus } from './focus.js';
5
-
6
- /**
7
- * Provides an overlay with the navigation for mobile users.
8
- *
9
- * Example: You have site navigation on the page, but demote it (closer to the footer) on mobile to avoid
10
- * the content being pushed below the fold. You provide an icon that bookmarks to the
11
- * navigation.
12
- *
13
- * The mobile navigation intercepts the bookmark link and opens the navigation in a modal
14
- * overlay, trapping keyboard focus until the overlay is closed.
15
- *
16
- * @param {string} resizedEventName
17
- */
18
- function addMobileNav(resizedEventName) {
19
- const icons = qsa('[data-navigationid]');
20
- for (let icon of icons) {
21
- addMobileNavigation(icon, resizedEventName);
22
- }
23
-
24
- const details = qsa('[data-openon]');
25
- for (let detail of details) {
26
- const minWidth = parseInt(detail.dataset.openon, 10);
27
- const width = window.innerWidth;
28
- if (width > minWidth) {
29
- detail.setAttribute('open', 'open');
30
- }
31
- }
32
- }
33
-
34
- /**
35
- * @param {HTMLElement} icon
36
- * @param {string} resizedEventName
37
- */
38
- function addMobileNavigation(icon, resizedEventName) {
39
- const navigationSelector = icon.dataset.navigationid || '';
40
- const iconType = icon.firstElementChild && icon.firstElementChild.tagName == 'svg'
41
- ? 'svg'
42
- : 'element';
43
-
44
- const originalIcon = icon.innerHTML;
45
- const overlay = document.createElement('div');
46
- const dataOpen = 'data-open';
47
-
48
- icon.setAttribute('aria-expanded', 'false');
49
- icon.setAttribute('aria-controls', navigationSelector);
50
-
51
- // Focus trap (forwards the tab / shift-tab back to the menu)
52
- icon.addEventListener('keydown', function(e) {
53
- if (icon.getAttribute(dataOpen) === dataOpen) {
54
- var focusElements = getFocusableElement(overlay);
55
- trapFocusForward(e, focusElements.first);
56
- trapReverseFocus(e, focusElements.last);
57
- }
58
- });
59
-
60
- // Close menu on escape-key press
61
- document.addEventListener('keydown', function(e) {
62
- if (icon.getAttribute(dataOpen) === dataOpen) {
63
- if (e.key === 'Escape') {
64
- closeMobileMenu();
65
- }
66
- }
67
- });
68
-
69
- // Opens and closes menu
70
- function handleIconInteraction() {
71
- if (icon.dataset.open == dataOpen) {
72
- closeMobileMenu();
73
- } else {
74
- openMobileMenu();
75
- }
76
- }
77
-
78
- function openMobileMenu(){
79
- const w1 = document.body.getBoundingClientRect().width;
80
- document.body.style.overflow = 'hidden';
81
- const w2 = document.body.getBoundingClientRect().width;
82
- document.documentElement.style.color = 'red';
83
- document.documentElement.style.paddingInlineEnd = (w2 - w1) + 'px';
84
-
85
- console.log(w1, w2, w1 - w2);
86
- const menuElement = qs('#' + navigationSelector);
87
-
88
- overlay.innerHTML = menuElement.outerHTML;
89
- overlay.className = 'overlay overlay-menu';
90
- overlay.style.display = 'block';
91
- menuElement.style.display = 'none';
92
-
93
- qsa('[id]', overlay).forEach((elem) => {
94
- elem.id = 'overlay__' + elem.id
95
- });
96
-
97
- // Modal Accessibility
98
- const title = menuElement.getAttribute('aria-label') ?? '';
99
- overlay.setAttribute('role', 'dialog');
100
- overlay.setAttribute('aria-modal', 'true');
101
- overlay.setAttribute('aria-label', title);
102
-
103
- // Trap Focus to Visible Overlay
104
- const focusElements = getFocusableElement(overlay);
105
-
106
- focusElements.first.addEventListener('keydown', function(e) {
107
- trapReverseFocus(e, icon);
108
- })
109
- focusElements.last.addEventListener('keydown', function(e) {
110
- trapFocusForward(e, icon);
111
- });
112
-
113
- if (iconType === 'svg') {
114
- icon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg"
115
- width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5"
116
- fill="none" stroke-linecap="round" stroke-linejoin="round">
117
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
118
- <line x1="18" y1="6" x2="6" y2="18" />
119
- <line x1="6" y1="6" x2="18" y2="18" />
120
- </svg>`;
121
- }
122
-
123
- document.body.appendChild(overlay);
124
- icon.setAttribute(dataOpen, dataOpen);
125
- icon.setAttribute('aria-expanded', 'true');
126
- focusElements.first.focus();
127
- }
128
-
129
- function closeMobileMenu() {
130
- const menuElement = qs('#' + navigationSelector);
131
- menuElement.style.display = '';
132
- document.body.style.overflow = 'auto';
133
- document.documentElement.style.paddingInlineEnd = '0';
134
-
135
- if (icon.getAttribute(dataOpen) === dataOpen) {
136
- overlay.innerHTML = '';
137
- overlay.style.display = 'none';
138
- document.body.removeChild(overlay);
139
- }
140
-
141
- icon.innerHTML = originalIcon;
142
- icon.removeAttribute(dataOpen);
143
- icon.setAttribute('aria-expanded', 'false');
144
- }
145
-
146
- icon.addEventListener('click', function (e) {
147
- e.preventDefault();
148
- handleIconInteraction();
149
- return false;
150
- });
151
-
152
- document.addEventListener(resizedEventName, function (/** @type {any} */e) {
153
- if (e.detail.change.width > 0) {
154
- closeMobileMenu();
155
- }
156
- })
157
- }
158
-
159
- export { addMobileNav };
@@ -1,56 +0,0 @@
1
- // @ts-check
2
-
3
- import { qs } from './query.js';
4
-
5
- /**
6
- * Makes an existing navigation element sticky
7
- *
8
- * Example: If the existing navigation is not as tall as the content, the
9
- * navigation will stick to the top, allowing the user to see it as
10
- * they scroll through the article
11
- *
12
- * @param {string} headerSelector
13
- * @param {string} navigationSelector
14
- * @param {string} navigationListSelector
15
- * @param {string} resizedEventName
16
- */
17
- function addStickyNavigation(headerSelector, navigationSelector, navigationListSelector, resizedEventName) {
18
- function setNavigationMode() {
19
- const header = qs(headerSelector);
20
- const navigation = qs(navigationSelector);
21
- const navigationList = qs(navigationListSelector);
22
-
23
- const buffer = 50;
24
- const className = 'sticky';
25
-
26
- const dimensions = {
27
- browserHeight: window.innerHeight,
28
- browserWidth: window.innerWidth,
29
- headerHeight: header.clientHeight,
30
- navigationHeight: navigationList.clientHeight
31
- };
32
-
33
- // Only enable sticky mode if the menu will fit vertically
34
- // && where the browser is more than 860px wide
35
- if (dimensions.navigationHeight < ((dimensions.browserHeight - Math.max(dimensions.headerHeight, site_features.stickyNav.top)) - buffer)
36
- && dimensions.browserWidth > 860) {
37
- console.log('Navigation: Sticky Mode');
38
- navigation.classList.add(className);
39
- const top = site_features.stickyNav.top ?? 220;
40
- navigation.style.top = top + 'px';
41
- } else {
42
- console.log('Navigation: Fixed Mode');
43
- navigation.classList.remove(className);
44
- }
45
- }
46
-
47
- setNavigationMode();
48
-
49
- document.addEventListener(resizedEventName, function(e) {
50
- if (e.detail && e.detail.change && e.detail.change.height != 0) {
51
- setNavigationMode();
52
- }
53
- });
54
- }
55
-
56
- export { addStickyNavigation };
@@ -1,41 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- *
5
- * @param {string} query
6
- * @param {HTMLElement} [container]
7
- * @returns {HTMLElement}
8
- */
9
- function qs(query, container) {
10
- const target = (container)
11
- ? container
12
- : document;
13
-
14
- /** @type {any} */
15
- const result = target.querySelector(query);
16
-
17
- if (result) {
18
- return result;
19
- }
20
-
21
- throw new Error(`No element ${query}`);
22
- }
23
-
24
- /**
25
- * Utility for query selector all
26
- *
27
- * @param {string} query
28
- * @param {HTMLElement | null} [container]
29
- * @returns {NodeListOf<any>}
30
- */
31
- function qsa(query, container) {
32
- const target = (container)
33
- ? container
34
- : document;
35
-
36
- /** @type {NodeListOf<HTMLElement>} */
37
- const result = target.querySelectorAll(query);
38
- return result;
39
- }
40
-
41
- export { qs, qsa };
@@ -1,43 +0,0 @@
1
- // @ts-check
2
-
3
- import { raiseEvent } from './events.js';
4
-
5
- var resizeEventName = 'resize';
6
- var resizedEventName = 'resized';
7
-
8
- var width = window.innerWidth;
9
- var height = window.innerHeight;
10
-
11
- /**
12
- * Adds a de-bounced "resized" event, so you can listen to:
13
- * document.addEventListener('resized', <handler>);
14
- *
15
- * @returns {string}
16
- */
17
- function addResizedEvent() {
18
- let debounce = null;
19
-
20
- function resizeEnd(e) {
21
- window.clearTimeout(debounce);
22
- debounce = window.setTimeout(raiseResizeEvent, 500);
23
- }
24
-
25
- function raiseResizeEvent() {
26
- const change = {
27
- width: window.innerWidth - width,
28
- height: window.innerHeight - height
29
- };
30
-
31
- width = window.innerWidth;
32
- height = window.innerHeight;
33
-
34
-
35
- raiseEvent(resizedEventName, { change: change });
36
- }
37
-
38
- window.addEventListener(resizeEventName, resizeEnd);
39
-
40
- return resizedEventName;
41
- }
42
-
43
- export { addResizedEvent };
@@ -1,69 +0,0 @@
1
- // @ts-check
2
-
3
- function enhanceSearchIcon() {
4
- if (document.querySelector('#site-search-query') == null) {
5
- const icon = document.querySelector('a.search-icon');
6
-
7
- if (icon != null) {
8
- fetch(icon.href)
9
- .then(response => response.text())
10
- .then(html => {
11
- const parser = new DOMParser();
12
- const doc = parser.parseFromString(html, 'text/html');
13
- const form = doc.querySelector('#site-search');
14
- const input = form.querySelector('#site-search-query');
15
- const results = doc.querySelector('#site-search-results');
16
- icon.setAttribute('aria-expanded', 'false');
17
-
18
- input?.setAttribute('autofocus', 'autofocus');
19
-
20
- const close = document.createElement('button');
21
- close.id = 'site-search-close';
22
- close.value = 'cancel';
23
- close.formMethod = 'dialog';
24
- close.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round">
25
- <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
26
- <line x1="18" y1="6" x2="6" y2="18"></line>
27
- <line x1="6" y1="6" x2="18" y2="18"></line>
28
- </svg>`;
29
-
30
- const script = doc.querySelector('script[src*="/search.js"]');
31
- const scr = document.createElement('script');
32
- for (let att, i = 0, atts = script.attributes, n = atts.length; i < n; i++){
33
- att = atts[i];
34
- scr.setAttribute(att.nodeName, att.nodeValue ?? '');
35
- }
36
-
37
- const dialog = document.createElement('dialog');
38
- dialog.className = 'search-dialog';
39
- dialog.append(close, form, results);
40
-
41
- document.body.appendChild(dialog);
42
- document.body.appendChild(scr);
43
-
44
- function openSearch(e) {
45
- e.preventDefault();
46
- dialog.showModal();
47
- icon.setAttribute('aria-expanded', 'true');
48
- return false;
49
- }
50
-
51
- // Open search on CTRL + SPACE
52
- window.onkeydown = function(e) {
53
- if (e.ctrlKey && e.key == ' ') {
54
- return openSearch(e);
55
- }
56
- };
57
-
58
- // Open search on click
59
- icon.addEventListener('click', openSearch);
60
-
61
- // Close dialog
62
- close.addEventListener('click', () => dialog.close());
63
- dialog.addEventListener('close', () => icon.setAttribute('aria-expanded', 'false'));
64
- });
65
- }
66
- }
67
- }
68
-
69
- export { enhanceSearchIcon };
@@ -1,31 +0,0 @@
1
- import { qs, qsa } from './query.js';
2
-
3
- function handleClick() {
4
-
5
- const title = this.dataset.sharetitle ?? qs('meta[property="og:title"]').content;
6
- const text = this.dataset.sharetext ?? qs('meta[property="og:description"]').content;
7
- const url = this.dataset.shareurl ?? document.location;
8
-
9
- const share = {
10
- title: title,
11
- text: text,
12
- url: url
13
- };
14
-
15
- if (navigator.share) {
16
- navigator.share(share);
17
- }
18
- }
19
-
20
- function enableSharing() {
21
- const canShare = !!navigator.share;
22
- qsa('[data-share]').forEach((elem) => {
23
- if (canShare) {
24
- elem.addEventListener('click', handleClick);
25
- } else {
26
- elem.style.display = 'none';
27
- }
28
- });
29
- }
30
-
31
- export { enableSharing }
@@ -1,77 +0,0 @@
1
- // @ts-check
2
-
3
- /**
4
- * Looks for a search within a string
5
- *
6
- * @param {string} string
7
- * @param {string} search
8
- * @returns
9
- */
10
- function contains(string, search) {
11
- return string.indexOf(search) > -1;
12
- }
13
-
14
- /**
15
- * Looks for a search within a string
16
- *
17
- * @param {string} string
18
- * @param {string} search
19
- * @returns
20
- */
21
- function containsWord(string, search) {
22
- return string.split(' ').indexOf(search) > -1;
23
- }
24
-
25
- /**
26
- *
27
- * @param {string} string
28
- * @param {string[]} terms
29
- * @returns
30
- */
31
- function highlight(string, terms) {
32
- terms.forEach(term => {
33
- const regEx = new RegExp(term, "ig");
34
- const matches = string.match(regEx);
35
- if (matches) {
36
- string = string.replace(regEx, `<mark>${matches[0]}</mark>`)
37
- }
38
- });
39
- return string;
40
- }
41
-
42
- /**
43
- * Simplifies a string to plain lower case, removing diacritic characters and hyphens
44
- * This means a search for "co-op" will be found in "COOP" and "Café" will be found in "cafe"
45
- * @param {string} string
46
- * @returns {string}
47
- */
48
- function sanitise(string) {
49
- // @ts-ignore
50
- if (String.prototype.normalize) {
51
- // Reduces diacritic characters to plain characters
52
- string.trim().normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().replace(/-/g, '');
53
- }
54
-
55
- // Some browsers can't normalise strings
56
- return string.trim().toLowerCase().replace(/-/g, '');
57
- }
58
-
59
- /**
60
- * Sets a minimum length for a search
61
- * @param {string} string
62
- * @returns
63
- */
64
- function isLongEnough(string) {
65
- return string.length > 1;
66
- }
67
-
68
- /**
69
- *
70
- * @param {string} string
71
- * @returns {string[]}
72
- */
73
- function explode(string) {
74
- return string.split(' ').filter(isLongEnough).map(sanitise);
75
- }
76
-
77
- export { contains, containsWord, sanitise, explode, highlight };
@@ -1,82 +0,0 @@
1
- // @ts-check
2
-
3
- import { qsa } from './query.js';
4
-
5
- let links = [];
6
- let current = '';
7
- const headings = [];
8
- const highlightClass = 'highlight';
9
-
10
- /**
11
- * Makes an entire block clickable based on a data-attribute, usually "data-destination"
12
- *
13
- * Example: You have a list of blog posts, including featured images. If you make the title
14
- * clickable, clicks on the image won't open the blog. Adding links to the images means
15
- * keyboard users have to tab twice as much to get through the list.
16
- *
17
- * Use clickable blocks to allow keyboard users to tab through the real links, but still
18
- * capture clicks elsewhere on the block.
19
- *
20
- */
21
- function highlightCurrentHeading(tocSelector) {
22
- links = qsa(tocSelector);
23
-
24
- links.forEach((link) => {
25
- const bookmarkLink = getBookmarkLink(link.href);
26
- if (bookmarkLink) {
27
- headings.push(document.getElementById(bookmarkLink));
28
- }
29
- });
30
-
31
- recheck();
32
- }
33
-
34
- function getBookmarkLink(link) {
35
- const linkParts = link.split('#');
36
- if (linkParts.length === 2) {
37
- return linkParts[1];
38
- }
39
-
40
- return '';
41
- }
42
-
43
- function highlight(id) {
44
- links.forEach((link) => {
45
- link.classList.remove(highlightClass);
46
-
47
- const bookmarkLink = getBookmarkLink(link.href);
48
- if (bookmarkLink === id) {
49
- link.classList.add(highlightClass);
50
- }
51
- });
52
- }
53
-
54
- function recheck() {
55
- const docTop = Math.floor(document.documentElement.scrollTop);
56
- const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
57
-
58
- const validItems = [];
59
-
60
- headings.forEach((elem) => {
61
-
62
- const hasPassed = (elem.offsetTop < docTop);
63
- const inView = (elem.offsetTop > docTop) && (elem.offsetTop < (docTop + vh));
64
- const isValid = (docTop + vh) - elem.offsetTop > (vh / 1.5);
65
-
66
- if (isValid) {
67
- validItems.push(elem);
68
- }
69
- });
70
-
71
- const item = validItems.pop();
72
-
73
- if (item && item.id !== current) {
74
- console.log('Reading', item.id);
75
- current = item.id;
76
- highlight(item.id);
77
- }
78
-
79
- window.setTimeout(recheck, 1000);
80
- }
81
-
82
- export { highlightCurrentHeading };
@@ -1,44 +0,0 @@
1
- // @ts-check
2
-
3
- import { qsa } from './query.js';
4
-
5
- function enhanceYoutubeLinks() {
6
- const videos = qsa('a[href^="https://www.youtube.com/watch?v="]');
7
-
8
- for (var video of videos) {
9
- if (video.parentNode.childNodes.length > 1) {
10
- // Don't turn video into embed if it's part of a longer paragraph, for example.
11
- continue;
12
- }
13
-
14
- const id = new URL(video.href).searchParams.get('v');
15
- video.setAttribute('data-youtube', id);
16
- video.classList.add('init');
17
- video.setAttribute('role', 'button');
18
-
19
- video.innerHTML = `<div class="yt-video">
20
- <div class="play-icon" style="background-image: url(https://img.youtube.com/vi/${id}/0.jpg)">▶</div>
21
- <div class="title">${video.textContent}</div>
22
- </div>`;
23
- }
24
-
25
- function clickHandler (event) {
26
- var link = event.target.closest('[data-youtube]');
27
-
28
- if (!link) {
29
- return;
30
- }
31
-
32
- event.preventDefault();
33
- var id = link.getAttribute('data-youtube');
34
-
35
- var player = document.createElement('div');
36
- player.innerHTML = `<iframe class="yt-iframe" width="560" height="315" src="https://www.youtube-nocookie.com/embed/${id}?autoplay=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
37
-
38
- link.replaceWith(player);
39
- }
40
-
41
- document.addEventListener('click', clickHandler);
42
- }
43
-
44
- export { enhanceYoutubeLinks }