@kudoai/chatgpt.js 2.6.4 → 2.6.6
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 +341 -0
- package/chatgpt.js +22 -22
- package/dist/chatgpt.min.js +7 -0
- package/docs/README.md +341 -324
- package/docs/USERGUIDE.md +1812 -1814
- package/docs/de/README.md +341 -324
- package/docs/es/README.md +341 -324
- package/docs/fr/README.md +341 -324
- package/docs/hi/README.md +342 -325
- package/docs/it/README.md +341 -324
- package/docs/ja/README.md +341 -324
- package/docs/ko/README.md +346 -329
- package/docs/ne/README.md +342 -325
- package/docs/nl/README.md +341 -324
- package/docs/pt/README.md +341 -324
- package/docs/vi/README.md +341 -324
- package/docs/zh-cn/README.md +341 -324
- package/docs/zh-tw/README.md +340 -323
- package/package.json +51 -31
- package/starters/chrome/LICENSE.md +43 -0
- package/starters/chrome/docs/README.md +17 -1
- package/starters/chrome/docs/SECURITY.md +17 -0
- package/starters/chrome/docs/de/LICENSE.md +21 -3
- package/starters/chrome/docs/de/README.md +17 -1
- package/starters/chrome/docs/es/LICENSE.md +21 -3
- package/starters/chrome/docs/es/README.md +17 -1
- package/starters/chrome/docs/fr/LICENSE.md +21 -3
- package/starters/chrome/docs/fr/README.md +17 -1
- package/starters/chrome/docs/hi/LICENSE.md +21 -3
- package/starters/chrome/docs/hi/README.md +17 -2
- package/starters/chrome/docs/hi/SECURITY.md +17 -0
- package/starters/chrome/docs/it/LICENSE.md +21 -3
- package/starters/chrome/docs/it/README.md +17 -1
- package/starters/chrome/docs/ja/LICENSE.md +21 -3
- package/starters/chrome/docs/ja/README.md +17 -2
- package/starters/chrome/docs/ko/LICENSE.md +21 -3
- package/starters/chrome/docs/ko/README.md +17 -1
- package/starters/chrome/docs/nl/LICENSE.md +20 -3
- package/starters/chrome/docs/nl/README.md +17 -1
- package/starters/chrome/docs/pt/LICENSE.md +21 -3
- package/starters/chrome/docs/pt/README.md +17 -1
- package/starters/chrome/docs/vi/LICENSE.md +21 -3
- package/starters/chrome/docs/vi/README.md +17 -1
- package/starters/chrome/docs/zh-cn/LICENSE.md +21 -3
- package/starters/chrome/docs/zh-cn/README.md +17 -2
- package/starters/chrome/docs/zh-cn/SECURITY.md +17 -0
- package/starters/chrome/docs/zh-tw/LICENSE.md +21 -3
- package/starters/chrome/docs/zh-tw/README.md +17 -1
- package/starters/chrome/extension/content.js +1 -1
- package/starters/chrome/extension/lib/chatgpt.js +6 -4
- package/starters/chrome/extension/manifest.json +1 -1
- package/starters/greasemonkey/LICENSE.md +43 -0
- package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +52 -52
- package/starters/greasemonkey/docs/SECURITY.md +17 -0
- package/starters/greasemonkey/docs/de/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/es/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/fr/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/hi/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/hi/SECURITY.md +17 -0
- package/starters/greasemonkey/docs/it/LICENSE.md +29 -0
- package/starters/greasemonkey/docs/ja/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/ko/LICENSE.md +34 -0
- package/starters/greasemonkey/docs/nl/LICENSE.md +30 -0
- package/starters/greasemonkey/docs/pt/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/vi/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/zh-cn/LICENSE.md +31 -0
- package/starters/greasemonkey/docs/zh-cn/SECURITY.md +17 -0
- package/starters/greasemonkey/docs/zh-tw/LICENSE.md +31 -0
- package/dist/chatgpt-2.6.4.min.js +0 -1
- package/docs/.nojekyll +0 -0
- package/docs/CNAME +0 -1
- package/docs/_coverpage.md +0 -16
- package/docs/_utils/LICENSE.md +0 -21
- package/docs/_utils/minify.js +0 -50
- package/docs/assets/docsify/cursors/futuristic/pointer.cur +0 -0
- package/docs/assets/docsify/favicons/favicon16.png +0 -0
- package/docs/assets/docsify/favicons/favicon320.png +0 -0
- package/docs/assets/docsify/favicons/favicon48.png +0 -0
- package/docs/assets/docsify/favicons/favicon64.png +0 -0
- package/docs/assets/docsify/fonts/eurostile-extended-black/EurostileExtendedBlack.otf +0 -0
- package/docs/assets/docsify/fonts/eurostile-extended-black/EurostileExtendedBlack.ttf +0 -0
- package/docs/assets/docsify/fonts/eurostile-extended-black/EurostileExtendedBlack.woff +0 -0
- package/docs/assets/docsify/fonts/eurostile-extended-black/EurostileExtendedBlack.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/OFL.txt +0 -93
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Bold.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-BoldItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-ExtraLight.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-ExtraLightItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Italic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Light.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-LightItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Medium.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-MediumItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Regular.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-SemiBold.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-SemiBoldItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-Thin.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/otf/IBMPlexMono-ThinItalic.otf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Bold.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-BoldItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-ExtraLight.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-ExtraLightItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Italic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Light.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-LightItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Medium.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-MediumItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Regular.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-SemiBold.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-SemiBoldItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-Thin.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/ttf/IBMPlexMono-ThinItalic.ttf +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Bold.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-BoldItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-ExtraLight.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-ExtraLightItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Italic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Light.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-LightItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Medium.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-MediumItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Regular.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-SemiBold.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-SemiBoldItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-Thin.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff/IBMPlexMono-ThinItalic.woff +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Bold.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-BoldItalic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-ExtraLight.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-ExtraLightItalic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Italic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Light.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-LightItatlic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Medium.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-MediumItalic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Regular.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-SemiBold.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-SemiBoldItalic.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-Thin.woff2 +0 -0
- package/docs/assets/docsify/fonts/ibm-plex-mono/woff2/IBMPlexMono-ThinItalic.woff2 +0 -0
- package/docs/assets/docsify/fonts/major-mono-display/MajorMonoDisplay-Regular.otf +0 -0
- package/docs/assets/docsify/fonts/major-mono-display/MajorMonoDisplay-Regular.ttf +0 -0
- package/docs/assets/docsify/fonts/major-mono-display/MajorMonoDisplay-Regular.woff +0 -0
- package/docs/assets/docsify/fonts/major-mono-display/MajorMonoDisplay-Regular.woff2 +0 -0
- package/docs/assets/docsify/fonts/major-mono-display/OFL.txt +0 -93
- package/docs/assets/docsify/fonts/polysans-neutral/PolySansNeutral.eot +0 -0
- package/docs/assets/docsify/fonts/polysans-neutral/PolySansNeutral.ttf +0 -0
- package/docs/assets/docsify/fonts/polysans-neutral/PolySansNeutral.woff +0 -0
- package/docs/assets/docsify/fonts/polysans-neutral/PolySansNeutral.woff2 +0 -0
- package/docs/assets/docsify/html/footer.html +0 -23
- package/docs/assets/docsify/js/min/back-to-top-button.min.js +0 -1
- package/docs/assets/docsify/js/min/copy-code-button.min.js +0 -1
- package/docs/assets/docsify/js/min/onload-hacks.min.js +0 -3
- package/docs/assets/docsify/js/min/starry-background.min.js +0 -1
- package/docs/assets/docsify/js/src/back-to-top-button.js +0 -64
- package/docs/assets/docsify/js/src/copy-code-button.js +0 -91
- package/docs/assets/docsify/js/src/onload-hacks.js +0 -613
- package/docs/assets/docsify/js/src/starry-background.js +0 -111
- package/docs/assets/docsify/styles/css/style.min.css +0 -1
- package/docs/assets/docsify/styles/css/style.min.css.map +0 -1
- package/docs/assets/docsify/styles/scss/style.scss +0 -510
- package/docs/assets/separators/aqua.png +0 -0
- package/docs/de/_coverpage.md +0 -12
- package/docs/es/_coverpage.md +0 -12
- package/docs/fr/_coverpage.md +0 -12
- package/docs/hi/_coverpage.md +0 -12
- package/docs/index.html +0 -91
- package/docs/it/_coverpage.md +0 -12
- package/docs/ja/_coverpage.md +0 -12
- package/docs/ko/_coverpage.md +0 -12
- package/docs/ne/_coverpage.md +0 -12
- package/docs/nl/_coverpage.md +0 -12
- package/docs/pt/_coverpage.md +0 -12
- package/docs/vi/_coverpage.md +0 -12
- package/docs/zh-cn/_coverpage.md +0 -12
- package/docs/zh-tw/_coverpage.md +0 -12
- package/starters/chrome/LICENSE +0 -21
- package/starters/greasemonkey/LICENSE +0 -21
|
@@ -1,613 +0,0 @@
|
|
|
1
|
-
/* Hack page elements on load */
|
|
2
|
-
|
|
3
|
-
const taglineWords = []; // for iObserver's scrambleText() + randomizeCase()
|
|
4
|
-
const features = [ // for iObserver's typeText() to #feature-list
|
|
5
|
-
'>> Feature-rich', '>> Object-oriented', '>> Easy-to-use',
|
|
6
|
-
'>> Lightweight (yet optimally performant)' ];
|
|
7
|
-
const visibilityMap = []; // to store flags for section visibility
|
|
8
|
-
const sectionColors = [ // for mdLoaded.then's scroll color hacks
|
|
9
|
-
'#64ffff', // Importing the Library
|
|
10
|
-
'#f9ee16', // Greasemonkey
|
|
11
|
-
'lime', // Chrome
|
|
12
|
-
'orange', // Usage
|
|
13
|
-
'#b981f9', // Made w/ chatgpt.js
|
|
14
|
-
'#f581f9', // ChatGPT Infinity tile
|
|
15
|
-
'#81f9c3' ]; // Contributors
|
|
16
|
-
const iniStarZvelocity = window.starVelocity.z,
|
|
17
|
-
warpDuration = 1600, hiWarpDuration = 1400, starResetDelay = 15;
|
|
18
|
-
|
|
19
|
-
// Define OBSERVERS
|
|
20
|
-
|
|
21
|
-
const mdLoaded = new Promise((resolve) => {
|
|
22
|
-
const mdObserver = new MutationObserver((mutationsList, observer) => {
|
|
23
|
-
if (document.querySelector('#shields')) { observer.disconnect(); resolve(); }});
|
|
24
|
-
mdObserver.observe(document.body, { childList: true, subtree: true });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const iObserver = new IntersectionObserver(entries => { entries.forEach(entry => {
|
|
28
|
-
|
|
29
|
-
// Set visibility FLAG
|
|
30
|
-
const key = entry.target.id || entry.target.className;
|
|
31
|
-
visibilityMap[key] = entry.isIntersecting;
|
|
32
|
-
|
|
33
|
-
// Handle COVER
|
|
34
|
-
if (entry.target.className === 'cover-main') {
|
|
35
|
-
if (entry.isIntersecting) {
|
|
36
|
-
|
|
37
|
-
// Reset colors
|
|
38
|
-
document.querySelector('#kudoai a').style.color = 'white';
|
|
39
|
-
window.starColor = 'white';
|
|
40
|
-
(document.querySelector('#scrollbar-style') || {}).innerText = (
|
|
41
|
-
':root { scrollbar-color: rgb(210,210,210) #1a1a1a }'
|
|
42
|
-
+ 'body::-webkit-scrollbar-thumb { background-color: white }');
|
|
43
|
-
|
|
44
|
-
// Animate KudoAI logo
|
|
45
|
-
const kudo = document.querySelector('.kudo');
|
|
46
|
-
kudo.classList.add('hover');
|
|
47
|
-
setTimeout(() => { kudo.classList.remove('hover'); }, 955);
|
|
48
|
-
|
|
49
|
-
// Scramble entire tagline + add case randomization layer
|
|
50
|
-
Array.from( // clear tagline spans to maintain grow effect
|
|
51
|
-
document.querySelectorAll('span[id^="tagline"]'))
|
|
52
|
-
.forEach(span => { span.textContent = ''; });
|
|
53
|
-
scrambleText([taglineWords[0]], document.querySelector('#tagline-pre-adj'));
|
|
54
|
-
scrambleText(taglineWords[1], document.querySelector('#tagline-adj'), 750);
|
|
55
|
-
scrambleText([taglineWords[2]], document.querySelector('#tagline-post-adj'));
|
|
56
|
-
randomizeCase(document.querySelector('#tagline-pre-adj'));
|
|
57
|
-
randomizeCase(document.querySelector('#tagline-post-adj'));
|
|
58
|
-
|
|
59
|
-
// Star boost
|
|
60
|
-
if (window.starVelocity.z <= iniStarZvelocity) { // to avoid reverse boost from scroll-ups
|
|
61
|
-
window.starVelocity.z += .024; // boost velocity
|
|
62
|
-
setTimeout(() => { // slow velocity
|
|
63
|
-
window.starVelocity.z -= .02; }, 1155);
|
|
64
|
-
setTimeout(() => { // slow velocity to original
|
|
65
|
-
window.starVelocity.z = iniStarZvelocity; }, 1355);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
} else // stop scrambling tagline adjective
|
|
69
|
-
clearTimeout(scrambleText.timeoutID);
|
|
70
|
-
|
|
71
|
-
// Handle FEATURE LIST
|
|
72
|
-
} else if (entry.target.id === 'feature-list') { // type features or clear content/timeouts
|
|
73
|
-
if (entry.isIntersecting) typeText(features, entry.target, 20);
|
|
74
|
-
else { entry.target.innerHTML = ''; clearTimeout(typeText.timeoutID); }
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
});});
|
|
78
|
-
|
|
79
|
-
const onLoadObserver = new MutationObserver(() => {
|
|
80
|
-
|
|
81
|
-
// Exit if not loaded
|
|
82
|
-
if (!document.querySelector('.cover-main blockquote p')) return;
|
|
83
|
-
|
|
84
|
-
// Activate SMOOTH SCROLL
|
|
85
|
-
smoothScroll(document, 155, 9);
|
|
86
|
-
|
|
87
|
-
// Hack HOMEPAGE
|
|
88
|
-
if (/#\/(\w{2}(-\w{2})?\/)?$/.test(location.hash)) {
|
|
89
|
-
|
|
90
|
-
// Hide SIDEBAR
|
|
91
|
-
if (!isMobileDevice()) document.body.className = 'ready close';
|
|
92
|
-
|
|
93
|
-
// Populate [taglineWords] for iObserver's scrambleText() + randomizeCase()
|
|
94
|
-
const taglineSpans = Array.from(document.querySelectorAll('span[id^="tagline"]'));
|
|
95
|
-
taglineSpans.map(span => { taglineWords.push(
|
|
96
|
-
/pre|post/.exec(span.id) ? span.textContent : span.textContent.split('|')); });
|
|
97
|
-
taglineSpans.forEach(span => { span.textContent = ''; }); // clear them out
|
|
98
|
-
|
|
99
|
-
// Observe COVER for visibility change tagline hacks
|
|
100
|
-
iObserver.observe(document.querySelector('.cover-main'));
|
|
101
|
-
|
|
102
|
-
// Add TOP GRADIENT
|
|
103
|
-
const cover = document.querySelector('.cover'),
|
|
104
|
-
topGradient = document.createElement('div');
|
|
105
|
-
topGradient.classList.add('top-gradient');
|
|
106
|
-
document.body.append(topGradient);
|
|
107
|
-
updateTGvisibility(); // since page load can be below fold
|
|
108
|
-
function updateTGvisibility() {
|
|
109
|
-
topGradient.style.display = ( // hide/show when fold is 85% at top
|
|
110
|
-
window.scrollY > 0.85 * cover.offsetHeight ? '' : 'none' ); }
|
|
111
|
-
|
|
112
|
-
mdLoaded.then(() => {
|
|
113
|
-
|
|
114
|
-
// Scroll slightly to overcome Chromium bug preventing parallax
|
|
115
|
-
if (navigator.userAgent.includes('Chrome'))
|
|
116
|
-
window.scrollBy(0, 200); setTimeout(() => window.scrollBy(0, -200), 600);
|
|
117
|
-
|
|
118
|
-
// Disable SEARCH
|
|
119
|
-
document.querySelector('.search').style.display = 'none';
|
|
120
|
-
document.querySelector('.sidebar-nav').style.paddingTop = '102px';
|
|
121
|
-
|
|
122
|
-
// Create/select FEATURE LIST
|
|
123
|
-
const featureListDiv = document.querySelector('#feature-list') || // select div
|
|
124
|
-
document.createElement('div'); // ...or create it
|
|
125
|
-
if (!featureListDiv.parentElement) { // append created div if not in DOM
|
|
126
|
-
featureListDiv.setAttribute('id', 'feature-list');
|
|
127
|
-
const introDiv = document.querySelector('#intro');
|
|
128
|
-
introDiv.parentElement.insertBefore( // insert after description
|
|
129
|
-
featureListDiv, introDiv.nextElementSibling.nextElementSibling);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ...then observe for visibility change to apply typing hack
|
|
133
|
-
iObserver.observe(featureListDiv);
|
|
134
|
-
|
|
135
|
-
// Append COPYRIGHT NOTICE footer
|
|
136
|
-
const article = document.querySelector('article'), // to insert at end of
|
|
137
|
-
copyrightFooter = document.createElement('div');
|
|
138
|
-
copyrightFooter.id = 'copyright-footer';
|
|
139
|
-
copyrightFooter.innerHTML = '<span style="font-size: 115%">Copyright © 2023–' + new Date().getFullYear()
|
|
140
|
-
+ ' <a href="https://kudoai.com" target="_blank" rel="noopener">KudoAI</a>.</span><br>'
|
|
141
|
-
+ 'Designed by <a href="https://adamlui.com" target="_blank" rel="noopener">Adam Lui</a> / '
|
|
142
|
-
+ 'Powered by <a href="https://docsify.js.org" target="_blank" rel="noopener">Docsify</a> / '
|
|
143
|
-
+ 'Hosted by <a href="https://github.com" target="_blank" rel="noopener">GitHub</a>';
|
|
144
|
-
article.append(copyrightFooter);
|
|
145
|
-
|
|
146
|
-
// Replace GitHub demo embed w/ YouTube one
|
|
147
|
-
const ghDemo = document.querySelector('a[href*="/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3140b0f8a4"]'),
|
|
148
|
-
ytDemo = document.createElement('iframe');
|
|
149
|
-
ytDemo.setAttribute('width', '855'); ytDemo.setAttribute('height', '455');
|
|
150
|
-
ytDemo.setAttribute('src', 'https://www.youtube.com/embed/yG8DtsEo0PM?rel=0');
|
|
151
|
-
ytDemo.setAttribute('allow',
|
|
152
|
-
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share');
|
|
153
|
-
ytDemo.setAttribute('allowfullscreen', '');
|
|
154
|
-
ytDemo.style.minWidth = 'fit-content'; ytDemo.style.width = '855px'; ytDemo.style.marginBottom = '30px';
|
|
155
|
-
ghDemo.parentNode.replaceChild(ytDemo, ghDemo);
|
|
156
|
-
ytDemo.parentNode.style.textAlign = 'center';
|
|
157
|
-
|
|
158
|
-
// Strip blockquote wrappers from showcase app descriptions
|
|
159
|
-
document.querySelectorAll('blockquote').forEach(blockquote => {
|
|
160
|
-
const parent = blockquote.parentNode, content = blockquote.innerHTML;
|
|
161
|
-
parent.replaceChild(document.createRange().createContextualFragment(content), blockquote);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Add FADE classes to elements
|
|
165
|
-
const fadeUpElements = [], fadeRightElements = [], fadeLeftElements = [];
|
|
166
|
-
fadeUpElements.push(...document.querySelectorAll(
|
|
167
|
-
'.cover-main img, .cover-main a,' // cover elements
|
|
168
|
-
+ 'h2, h3, p, pre, main li,' // general elements
|
|
169
|
-
+ 'div#partners-collage, #copyright-footer')); // footer elements
|
|
170
|
-
fadeUpElements.forEach((element) => { element.classList.add('content-fadeup'); });
|
|
171
|
-
fadeUpElements.push( // language selector
|
|
172
|
-
document.querySelector('#language-menu'));
|
|
173
|
-
fadeUpElements[fadeUpElements.length - 1].classList.add('menu-fadeup');
|
|
174
|
-
fadeRightElements.push(...document.querySelectorAll( // left-side showcase apps
|
|
175
|
-
`#showcase ~ h3:nth-of-type(odd):not(#contributors ~ *),
|
|
176
|
-
#showcase ~ h3 + p:nth-of-type(odd):not(#contributors ~ *`));
|
|
177
|
-
fadeRightElements.forEach((element) => { element.classList.add('content-faderight'); });
|
|
178
|
-
fadeLeftElements.push(...document.querySelectorAll( // right-side showcase apps
|
|
179
|
-
`#showcase ~ h3:nth-of-type(even):not(#contributors ~ *),
|
|
180
|
-
#showcase ~ h3 + p:nth-of-type(even):not(#contributors ~ *`));
|
|
181
|
-
fadeLeftElements.forEach((element) => { element.classList.add('content-fadeleft'); });
|
|
182
|
-
const fadeElements = [...fadeUpElements, ...fadeRightElements, ...fadeLeftElements];
|
|
183
|
-
|
|
184
|
-
// ...then observe for visibility change to update element/sidebar states
|
|
185
|
-
const sideNavItems = [...document.querySelectorAll('.sidebar-nav li')];
|
|
186
|
-
const fadeObserver = new IntersectionObserver(
|
|
187
|
-
(entries) => { entries.forEach((entry) => {
|
|
188
|
-
if (entry.isIntersecting) {
|
|
189
|
-
entry.target.classList.add('visible');
|
|
190
|
-
|
|
191
|
-
// Update sidebar w/ active class for headings
|
|
192
|
-
if (entry.target.tagName.startsWith('H')) {
|
|
193
|
-
|
|
194
|
-
// Find the nav item that matches intersecting heading
|
|
195
|
-
const headingText = entry.target.querySelector('a').textContent,
|
|
196
|
-
activeNavItem = (document.querySelector(
|
|
197
|
-
`a[title="${ headingText }"]`) || {}).parentElement;
|
|
198
|
-
|
|
199
|
-
// Add `nav-active` class to matched nav item
|
|
200
|
-
if (activeNavItem) {
|
|
201
|
-
sideNavItems.forEach(item => item.classList.remove('nav-active'));
|
|
202
|
-
activeNavItem.classList.add('nav-active');
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} else entry.target.classList.remove('visible');
|
|
206
|
-
});}, { root: null, threshold: 0.02 });
|
|
207
|
-
fadeElements.forEach((element) => { fadeObserver.observe(element); });
|
|
208
|
-
|
|
209
|
-
// Change stars shield link to repo
|
|
210
|
-
const starsShieldLink = document.querySelector('a[href$="stargazers"]'),
|
|
211
|
-
href = starsShieldLink.getAttribute('href');
|
|
212
|
-
starsShieldLink.setAttribute('href', href.replace('/stargazers', ''));
|
|
213
|
-
|
|
214
|
-
// Establish TRIGGER POINTS for scroll FX
|
|
215
|
-
const triggerElements = [], triggerPoints = [];
|
|
216
|
-
triggerElements.push(...document.querySelectorAll('h2'));
|
|
217
|
-
triggerElements.push(document.querySelector('h3#-greasemonkey'));
|
|
218
|
-
triggerElements.push(document.querySelector('h3#-chrome'));
|
|
219
|
-
triggerElements.push( // 1st showcase tile
|
|
220
|
-
document.querySelector('img[src*="chatgpt-infinity"]'));
|
|
221
|
-
triggerElements.forEach(element => {
|
|
222
|
-
const elementPos = element.getBoundingClientRect().top;
|
|
223
|
-
const vOffsetDivisor = ( // higher = lower pos
|
|
224
|
-
element.id.includes('⚡') ? 1.5 // Importing the Library section
|
|
225
|
-
: element.tagName === 'IMG' ? 0.8 // 1st showcase tile
|
|
226
|
-
: 8.8 ); // headings
|
|
227
|
-
triggerPoints.push(elementPos - window.innerHeight/vOffsetDivisor);
|
|
228
|
-
});
|
|
229
|
-
triggerPoints.sort((a, b) => a - b); // sort ascending
|
|
230
|
-
|
|
231
|
-
// Update COLORS + STAR VELOCITY on scroll
|
|
232
|
-
window.addEventListener('scroll', () => {
|
|
233
|
-
|
|
234
|
-
// Exit if still in 1st two sections
|
|
235
|
-
if (visibilityMap['cover-main'] || visibilityMap['feature-list']) return;
|
|
236
|
-
|
|
237
|
-
// Determine current section
|
|
238
|
-
let currentSection = 0;
|
|
239
|
-
while (window.scrollY > triggerPoints[currentSection] &&
|
|
240
|
-
currentSection < triggerPoints.length)
|
|
241
|
-
currentSection++;
|
|
242
|
-
|
|
243
|
-
// Color/animate logo/stars + color scrollbar if section changed
|
|
244
|
-
const sectionColor = sectionColors[currentSection - 2];
|
|
245
|
-
if (sectionColor !== window.starColor) {
|
|
246
|
-
|
|
247
|
-
// Color/animate stars
|
|
248
|
-
window.starColor = sectionColor;
|
|
249
|
-
setTimeout(() => { // schedule color reset
|
|
250
|
-
if (window.starVelocity.z <= iniStarZvelocity) {
|
|
251
|
-
window.starColor = 'white'; }}, warpDuration + starResetDelay);
|
|
252
|
-
window.starVelocity.z += .0045; // boost velocity
|
|
253
|
-
setTimeout(() => { // slow velocity
|
|
254
|
-
window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .0025);
|
|
255
|
-
}, hiWarpDuration);
|
|
256
|
-
setTimeout(() => { // slow velocity to original
|
|
257
|
-
window.starVelocity.z = Math.max(iniStarZvelocity, window.starVelocity.z - .002);
|
|
258
|
-
}, warpDuration);
|
|
259
|
-
|
|
260
|
-
// Color/animate logo
|
|
261
|
-
const kudoAIlogo = document.querySelector('#kudoai a'),
|
|
262
|
-
kudo = document.querySelector('.kudo');
|
|
263
|
-
kudoAIlogo.style.color = sectionColor;
|
|
264
|
-
kudo.classList.add('hover'); // trigger slide animation
|
|
265
|
-
setTimeout(() => { // schedule color/animation reset
|
|
266
|
-
if (window.starVelocity.z <= iniStarZvelocity) {
|
|
267
|
-
kudoAIlogo.style.color = 'white';
|
|
268
|
-
kudo.classList.remove('hover');
|
|
269
|
-
}}, warpDuration + 5);
|
|
270
|
-
|
|
271
|
-
// Color scrollbar
|
|
272
|
-
const scrollbarStyle = document.querySelector('#scrollbar-style') || // select div
|
|
273
|
-
document.createElement('style'); // ...or create it
|
|
274
|
-
if (!scrollbarStyle.parentElement) { // append created div if not in DOM
|
|
275
|
-
scrollbarStyle.setAttribute('id', 'scrollbar-style');
|
|
276
|
-
document.head.append(scrollbarStyle);
|
|
277
|
-
}
|
|
278
|
-
scrollbarStyle.innerText = (
|
|
279
|
-
`:root { scrollbar-color: ${ sectionColor } #1a1a1a }`
|
|
280
|
-
+ `body::-webkit-scrollbar-thumb { background-color: ${ sectionColor } }`);
|
|
281
|
-
setTimeout(() => { // schedule color reset
|
|
282
|
-
if (window.starVelocity.z <= iniStarZvelocity) {
|
|
283
|
-
scrollbarStyle.innerText = (
|
|
284
|
-
':root { scrollbar-color: rgb(210,210,210) #1a1a1a }'
|
|
285
|
-
+ 'body::-webkit-scrollbar-thumb { background-color: white }');
|
|
286
|
-
}}, warpDuration + 5);
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// Update LANGUAGE SELECTOR word
|
|
292
|
-
setTimeout(() => {
|
|
293
|
-
const activeLanguage = document.querySelector('.active').innerText;
|
|
294
|
-
document.getElementById('dropdown-button').innerText = activeLanguage;
|
|
295
|
-
}, 250);
|
|
296
|
-
|
|
297
|
-
// Convert OpenAI showcase icons + sidebar logo to dark-mode
|
|
298
|
-
document.querySelectorAll('picture').forEach(picture => {
|
|
299
|
-
const srcElement = picture.querySelector('source'),
|
|
300
|
-
srcSet = srcElement.getAttribute('srcset'),
|
|
301
|
-
imgElement = document.createElement('img');
|
|
302
|
-
imgElement.setAttribute('src', srcSet);
|
|
303
|
-
picture.parentNode.replaceChild(imgElement, picture);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
// Append EMAIL SIGNUP footer
|
|
307
|
-
const partnersCollage = document.getElementById('partners-collage'), // to insert after
|
|
308
|
-
emailFooter = document.createElement('div');
|
|
309
|
-
fetch('assets/docsify/html/footer.html')
|
|
310
|
-
.then(response => response.text()).then(html => {
|
|
311
|
-
emailFooter.innerHTML = html;
|
|
312
|
-
partnersCollage.insertAdjacentElement('afterend', emailFooter);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Remove readme's BACK-TO-TOP link
|
|
316
|
-
const readmeBTTlink = document.querySelector('p a[href="#"]');
|
|
317
|
-
readmeBTTlink.previousSibling.remove(); readmeBTTlink.remove();
|
|
318
|
-
|
|
319
|
-
setTimeout(() => { // Add PARALLAX
|
|
320
|
-
|
|
321
|
-
// Target TRIGGERS
|
|
322
|
-
const parallaxTriggers = [];
|
|
323
|
-
document.querySelectorAll('#main, h2:not([id="about"])').forEach(trigger => {
|
|
324
|
-
const y = trigger.getBoundingClientRect().top - window.innerHeight / 1.2;
|
|
325
|
-
const triggerElem = trigger.tagName === 'H2' ? trigger.parentElement : trigger;
|
|
326
|
-
parallaxTriggers.push({ element: triggerElem, y });
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// Add SCROLL listener
|
|
330
|
-
window.addEventListener('scroll', () => {
|
|
331
|
-
updateTGvisibility();
|
|
332
|
-
parallaxTriggers.forEach(trigger => {
|
|
333
|
-
if (window.scrollY >= trigger.y && window.scrollY < trigger.y + window.innerHeight) {
|
|
334
|
-
|
|
335
|
-
// Target previous elements to hack
|
|
336
|
-
const prevElems = [];
|
|
337
|
-
if (trigger.element.id === 'main')
|
|
338
|
-
prevElems.push(document.querySelector('.cover-main'));
|
|
339
|
-
else { // target previous 6 siblings
|
|
340
|
-
let currentElem = trigger.element.previousElementSibling;
|
|
341
|
-
for (let i = 0; i < 7; i++) {
|
|
342
|
-
if (currentElem) {
|
|
343
|
-
prevElems.push(currentElem);
|
|
344
|
-
currentElem = currentElem.previousElementSibling;
|
|
345
|
-
} else break;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Apply transparency + translate to siblings
|
|
350
|
-
prevElems.forEach(elem => {
|
|
351
|
-
const topGap = trigger.y - window.scrollY,
|
|
352
|
-
newOpacity = 1 - Math.abs(topGap) / ( window.innerHeight - 5),
|
|
353
|
-
parallaxOffset = topGap * -0.55,
|
|
354
|
-
scaleDelay = 285, // px from trigger.y to delay scaling
|
|
355
|
-
scaleFactor = topGap > -scaleDelay ? 1
|
|
356
|
-
: 1 - Math.abs(topGap + scaleDelay) / 5 / window.innerHeight;
|
|
357
|
-
try { elem.classList.remove('content-fadeup'); } catch (err) {}
|
|
358
|
-
elem.style.opacity = newOpacity;
|
|
359
|
-
elem.style.transform = `translateY(${ parallaxOffset }px) scale(${ scaleFactor })`;
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
}});});}, 100);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
// Hide SITE LANG SELECTOR from NON-HOME pages
|
|
366
|
-
} else document.querySelector('.app-nav').style.display = 'none';
|
|
367
|
-
|
|
368
|
-
// Hack LICENSE/SECURIY pages
|
|
369
|
-
if (/LICENSE|SECURITY/.test(location.hash)) {
|
|
370
|
-
|
|
371
|
-
// Hide SIDEBAR
|
|
372
|
-
if (!isMobileDevice()) document.body.className = 'ready close';
|
|
373
|
-
|
|
374
|
-
// Correct DOC LANG SELECTOR links
|
|
375
|
-
mdLoaded.then(() => {
|
|
376
|
-
const docLangSelector = document.querySelectorAll('h5 a');
|
|
377
|
-
for (const lang of docLangSelector)
|
|
378
|
-
lang.href = lang.href.replace(/(.*\/\/.*?\/)((\w{2}(-\w{2})?\/)?.*)\.md/, '$1#/$2');
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// DISCONNECT observer
|
|
383
|
-
onLoadObserver.disconnect();
|
|
384
|
-
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Define FUNCTIONS
|
|
388
|
-
|
|
389
|
-
function isMobileDevice() {
|
|
390
|
-
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); }
|
|
391
|
-
|
|
392
|
-
function validateIntArg(arg, name, defaultVal) {
|
|
393
|
-
if (arg === undefined) return defaultVal; // no validation required
|
|
394
|
-
if (!Number.isInteger(arg) && !/^\d+$/.test(arg))
|
|
395
|
-
throw new Error(name + ' must be an integer.');
|
|
396
|
-
return parseInt(arg, 10);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
function smoothScroll(target, speed, smooth) {
|
|
400
|
-
|
|
401
|
-
// Init target
|
|
402
|
-
if (target === document)
|
|
403
|
-
target = (document.scrollingElement
|
|
404
|
-
|| document.documentElement
|
|
405
|
-
|| document.body.parentNode
|
|
406
|
-
|| document.body); // cross browser support for document scrolling
|
|
407
|
-
|
|
408
|
-
// Init variables
|
|
409
|
-
let moving = false, pos = target.scrollTop;
|
|
410
|
-
const frame = target === document.body && document.documentElement
|
|
411
|
-
? document.documentElement
|
|
412
|
-
: target; // safari
|
|
413
|
-
// Add listeners
|
|
414
|
-
target.addEventListener('mousewheel', scrolled, { passive: false });
|
|
415
|
-
target.addEventListener('DOMMouseScroll', scrolled, { passive: false });
|
|
416
|
-
|
|
417
|
-
function scrolled(e) {
|
|
418
|
-
e.preventDefault(); // disable default scrolling
|
|
419
|
-
const delta = normalizeWheelDelta(e);
|
|
420
|
-
pos += -delta * speed;
|
|
421
|
-
pos = ( // limit scrolling
|
|
422
|
-
Math.max(0, Math.min(pos, target.scrollHeight - frame.clientHeight)));
|
|
423
|
-
if (!moving) update();
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function normalizeWheelDelta(e) {
|
|
427
|
-
if (e.detail) {
|
|
428
|
-
if (e.wheelDelta)
|
|
429
|
-
return e.wheelDelta/e.detail/40 * (e.detail>0 ? 1 : -1); // Opera
|
|
430
|
-
else return -e.detail/3; // Firefox
|
|
431
|
-
} else return e.wheelDelta/120; // IE/Safari/Chrome
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
function update() {
|
|
435
|
-
moving = true;
|
|
436
|
-
const delta = (pos - target.scrollTop) / smooth;
|
|
437
|
-
target.scrollTop += delta;
|
|
438
|
-
if (Math.abs(delta) > 0.5) requestFrame(update);
|
|
439
|
-
else moving = false;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const requestFrame = function() { // requestAnimationFrame cross browser
|
|
443
|
-
return (
|
|
444
|
-
window.requestAnimationFrame ||
|
|
445
|
-
window.webkitRequestAnimationFrame ||
|
|
446
|
-
window.mozRequestAnimationFrame ||
|
|
447
|
-
window.oRequestAnimationFrame ||
|
|
448
|
-
window.msRequestAnimationFrame ||
|
|
449
|
-
function(func) { window.setTimeout(func, 1000 / 50); }
|
|
450
|
-
);
|
|
451
|
-
}();
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
function scrambleText(text, destination, delayBetweenWords, textIdx = 0) {
|
|
455
|
-
|
|
456
|
-
// Validate args
|
|
457
|
-
if (typeof text === 'string') text = [text]; // array of strings to scramble
|
|
458
|
-
if (!destination?.nodeName) // DOM element to scramble to
|
|
459
|
-
throw new Error('Destination (2nd arg) must be a DOM element');
|
|
460
|
-
if (delayBetweenWords) { // ms to delay between scrambles
|
|
461
|
-
if (!Number.isInteger(delayBetweenWords) && !/^\d+$/.test(delayBetweenWords))
|
|
462
|
-
throw new Error('Delay betweeen words (3nd arg) must be an integer (ms)');
|
|
463
|
-
delayBetweenWords = parseInt(delayBetweenWords, 10);
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Scramble text
|
|
467
|
-
const textToScramble = new Scramble(destination);
|
|
468
|
-
textToScramble.setText(text[textIdx])
|
|
469
|
-
.then(() => { if (delayBetweenWords && visibilityMap['cover-main']) {
|
|
470
|
-
scrambleText.timeoutID = setTimeout(() => {
|
|
471
|
-
scrambleText(text, destination, delayBetweenWords, (textIdx + 1) % text.length); },
|
|
472
|
-
delayBetweenWords);
|
|
473
|
-
}});
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB, inflectionPt) {
|
|
477
|
-
|
|
478
|
-
// Validate args
|
|
479
|
-
if (!targetNode?.nodeName) // DOM element to randomize case of text content
|
|
480
|
-
throw new Error('Target node (1st arg) must be a DOM element');
|
|
481
|
-
iniDelay = validateIntArg( // ms to initially between case switches
|
|
482
|
-
iniDelay, 'Initial delay', 5);
|
|
483
|
-
finalDelay = validateIntArg( // ms to finally delay between case switches
|
|
484
|
-
finalDelay, 'Final delay', 1000);
|
|
485
|
-
incrementA = validateIntArg( // ms to initially increment from iniDelay to finalDelay
|
|
486
|
-
incrementA, 'Increment A', 10);
|
|
487
|
-
incrementB = validateIntArg( // ms to increment from iniDelay to finalDelay after inflection
|
|
488
|
-
incrementB, 'Increment B', 111);
|
|
489
|
-
inflectionPt = validateIntArg( // ms of iniDelay state before inflecting to Increment B
|
|
490
|
-
inflectionPt, 'Inflection point', 265);
|
|
491
|
-
|
|
492
|
-
// Randomize case
|
|
493
|
-
targetNode.textContent = targetNode.textContent.split('').map(letter => {
|
|
494
|
-
return Math.random() < 0.5 ? letter.toUpperCase() : letter.toLowerCase();
|
|
495
|
-
}).join('');
|
|
496
|
-
randomizeCase.iniDelay = randomizeCase.iniDelay || iniDelay;
|
|
497
|
-
randomizeCase.iniDelay += randomizeCase.iniDelay < inflectionPt ? incrementA : incrementB;
|
|
498
|
-
if (randomizeCase.iniDelay > finalDelay) randomizeCase.iniDelay = finalDelay; // cap at `finalDelay`
|
|
499
|
-
setTimeout(() => {
|
|
500
|
-
randomizeCase(targetNode, iniDelay, finalDelay, incrementA, incrementB, inflectionPt);
|
|
501
|
-
}, randomizeCase.iniDelay);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos, linesToScrollAt) {
|
|
505
|
-
|
|
506
|
-
// Validate args
|
|
507
|
-
if (typeof txtToType === 'string') txtToType = [txtToType]; // array of strings to type
|
|
508
|
-
if (!destination?.nodeName) // DOM element to type to
|
|
509
|
-
throw new Error('Destination must be a DOM element');
|
|
510
|
-
typeDelay = validateIntArg( // ms to delay between chars typed
|
|
511
|
-
typeDelay, 'Typing delay', 30);
|
|
512
|
-
iniTxtToType = validateIntArg( // index of txt array to start typing
|
|
513
|
-
iniTxtToType, 'Initial text array index', 0);
|
|
514
|
-
iniTxtPos = validateIntArg( // position in txt string to start typing from
|
|
515
|
-
iniTxtPos, 'Initial text string position', 3);
|
|
516
|
-
linesToScrollAt = validateIntArg( // lines reached before scrolling up
|
|
517
|
-
linesToScrollAt, 'Lines to scroll at', 5);
|
|
518
|
-
|
|
519
|
-
// Init variables
|
|
520
|
-
let typeContent = ' ',
|
|
521
|
-
iniRow = Math.max(0, iniTxtToType - linesToScrollAt);
|
|
522
|
-
|
|
523
|
-
// Type text
|
|
524
|
-
while (iniRow < iniTxtToType) typeContent += txtToType[iniRow++] + '<br /><br />';
|
|
525
|
-
destination.innerHTML = typeContent + txtToType[iniTxtToType].substring(0, iniTxtPos) + '_';
|
|
526
|
-
if (iniTxtPos++ == txtToType[iniTxtToType].length) {
|
|
527
|
-
iniTxtPos = 0; iniTxtToType++;
|
|
528
|
-
if (iniTxtToType != txtToType.length) { // if end of string reached
|
|
529
|
-
typeText.timeoutID = setTimeout(() => {
|
|
530
|
-
typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos);
|
|
531
|
-
}, 88); // pause til next string
|
|
532
|
-
}} else typeText.timeoutID = setTimeout(() => {
|
|
533
|
-
typeText(txtToType, destination, typeDelay, iniTxtToType, iniTxtPos);
|
|
534
|
-
}, typeDelay + (Math.random() * 220) - 110);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// Define SCRAMBLE class
|
|
538
|
-
|
|
539
|
-
class Scramble {
|
|
540
|
-
constructor(el) {
|
|
541
|
-
this.el = el;
|
|
542
|
-
this.chars = '!<>-_\\/[]{}—=+*^?#________';
|
|
543
|
-
this.update = this.update.bind(this);
|
|
544
|
-
}
|
|
545
|
-
setText(newText) {
|
|
546
|
-
const oldText = this.el.innerText,
|
|
547
|
-
length = Math.max(oldText.length, newText.length),
|
|
548
|
-
promise = new Promise((resolve) => this.resolve = resolve);
|
|
549
|
-
this.queue = [];
|
|
550
|
-
for (let i = 0; i < length; i++) {
|
|
551
|
-
const from = oldText[i] || '',
|
|
552
|
-
to = newText[i] || '',
|
|
553
|
-
start = Math.floor(Math.random() * 45), // speed of beginning scramble
|
|
554
|
-
end = start + Math.floor(Math.random() * 45); // speed of end scramble
|
|
555
|
-
this.queue.push({ from, to, start, end });
|
|
556
|
-
}
|
|
557
|
-
cancelAnimationFrame(this.frameRequest);
|
|
558
|
-
this.frame = 0; this.update(); return promise;
|
|
559
|
-
}
|
|
560
|
-
update() {
|
|
561
|
-
let output = '', complete = 0;
|
|
562
|
-
for (let i = 0, n = this.queue.length; i < n; i++) {
|
|
563
|
-
let { from, to, start, end, char } = this.queue[i];
|
|
564
|
-
if (this.frame >= end) { complete++; output += to; }
|
|
565
|
-
else if (this.frame >= start) {
|
|
566
|
-
if (!char || Math.random() < 0.28) {
|
|
567
|
-
char = this.randomChar();
|
|
568
|
-
this.queue[i].char = char;
|
|
569
|
-
}
|
|
570
|
-
output += `<span class="dud">${ char }</span>`;
|
|
571
|
-
} else output += from;
|
|
572
|
-
}
|
|
573
|
-
this.el.innerHTML = output;
|
|
574
|
-
if (complete === this.queue.length) this.resolve();
|
|
575
|
-
else {
|
|
576
|
-
this.frameRequest = requestAnimationFrame(this.update);
|
|
577
|
-
this.frame++;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
randomChar() {
|
|
581
|
-
return this.chars[Math.floor(Math.random() * this.chars.length)]; }
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// Run MAIN routine
|
|
585
|
-
|
|
586
|
-
// Add listeners to language selector
|
|
587
|
-
const languageMenu = document.getElementById('language-menu'),
|
|
588
|
-
languageSelector = document.getElementById('language-selector');
|
|
589
|
-
languageMenu.style.display = 'none'; // hide on page load
|
|
590
|
-
let hideTimeout; // to account for gap between button & menu
|
|
591
|
-
languageSelector.addEventListener('mouseenter', () => {
|
|
592
|
-
clearTimeout(hideTimeout); languageMenu.style.display = 'block'; });
|
|
593
|
-
languageSelector.addEventListener('mouseleave', () => {
|
|
594
|
-
hideTimeout = setTimeout(() => { languageMenu.style.display = 'none'; }, 55); });
|
|
595
|
-
languageMenu.addEventListener('mouseenter', () => {
|
|
596
|
-
clearTimeout(hideTimeout); languageMenu.style.display = 'block'; });
|
|
597
|
-
languageMenu.addEventListener('mouseleave', () => {
|
|
598
|
-
clearTimeout(hideTimeout); hideTimeout = setTimeout(() => {
|
|
599
|
-
languageMenu.style.display = 'none'; }, 55);
|
|
600
|
-
});
|
|
601
|
-
document.querySelectorAll('#language-selector a').forEach((link) => { // add listener to hide tooltips
|
|
602
|
-
link.addEventListener('mouseenter', () => { link.removeAttribute('title'); });});
|
|
603
|
-
document.querySelectorAll('.dropdown-link').forEach((link) => { // add listener to dismisss menu
|
|
604
|
-
link.addEventListener('click', () => { languageMenu.style.display = 'none'; });});
|
|
605
|
-
|
|
606
|
-
// Observe for load + re-connect on nav to new hash
|
|
607
|
-
onLoadObserver.observe(document.body, { childList: true, subtree: true });
|
|
608
|
-
let fromUnhashedURL = window.location.href.includes('#');
|
|
609
|
-
window.addEventListener('hashchange', () => {
|
|
610
|
-
if (!fromUnhashedURL) fromUnhashedURL = true;
|
|
611
|
-
else if (fromUnhashedURL)
|
|
612
|
-
onLoadObserver.observe(document.body, { childList: true, subtree: true });
|
|
613
|
-
});
|