-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
287 lines (266 loc) · 19.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
<!DOCTYPE html>
<html lang="en">
<head> <!-- This is the default landing page for speakworldlanguages.app -->
<script> var thisIsTheParentWhichContainsAllIFramedLessons = "yes"; /*See js_for_all_iframed_lesson_htmls*/ </script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable = no"> <!-- For mobile device screens to display things properly. As of 2022 Safari ignores this. -->
<title>SPEAK WORLD LANGUAGES: Play games with voice commands as you acquire a new language</title>
<meta name="description" content="Talk to the app! Play speech controlled games! Listen and use what you learn immediately!">
<meta name="author" content="Manheart Earthman">
<!-- https://pedro.agency/digital-marketing/how-to-stop-google-ignoring-your-meta-descriptions/ --> <!-- https://ahrefs.com/blog/meta-robots/ -->
<script src="/js_reusables/js_for_online_and_offline_modes.js">/* Before trying to load a new lesson or attempting to cache files we can check if internet is ON and working */</script>
<!-- <link rel="alternate" hreflang="ja" href="https://???hanaserutoiiy.one" "//???syabererutoiiy.one"> -->
<!-- <link rel="alternate" hreflang="ko" href="https://???"> -->
<!-- <link rel="alternate" hreflang="zh" href="https://???"> -->
<!-- <link rel="alternate" hreflang="ms" href="https://???"> -->
<!-- <link rel="alternate" hreflang="tr" href="https://???"> -->
<!-- <link rel="alternate" hreflang="ar" href="https://???"> -->
<!-- <link rel="alternate" hreflang="en" href="https://speakworldlanguages.app"> -->
<link rel="icon" type="image/png" href="/user_interface/html_icon/animated_globe_icon_39.png" id="icon" sizes="32x32"> <!-- This appears next to the title in the browser's TABS and plays as an animation. See js_for_icon_and_title_animation.js -->
<link rel="stylesheet" href="/css_reusables/css_for_every_single_html.css">
<link rel="stylesheet" href="/css_reusables/css_for_the_container_parent_html.css">
<link rel="stylesheet" href="/css_reusables/css_for_sliding_navigation_menu.css">
<link rel="stylesheet" href="/css_reusables/css_for_preloader_and_orbiting_circles.css"><!-- Contains globe preloader hide-reveal classes -->
<link rel="stylesheet" href="/css_reusables/css_for_info_boxes_in_parent.css"><!-- Visual style of save/load info boxes -->
<script src="/third_party_js/annyang-modified-for-swl.js">/*Speech Recognition library by Tal Ater - Github: TalAter*/</script>
<script src="/third_party_js/ua-parser.min.js">/*JS library for getting the browser and OS names by Faisal Salman - Github: faisalman*/</script>
<script src="/third_party_js/howler.min.js">/*An audio handler - Github: goldfire*/</script>
<!-- <script src="/third_party_js/localforage.min.js">/*IN THE FUTURE: Use indexedDB; store large blobs like recorded audio or pass data to the service worker*/</script> -->
<script defer src="/js_reusables/js_for_every_single_html.js">/*LET userInterfaceLanguage DEPEND ON DOMAIN NAME, fetch headers, fonts, resetWebp, canVibrate, defaultCursor*/</script>
<script defer src="/js_reusables/js_for_the_parent_all_browsers_all_devices.js">/*Memory card, LOAD-SAVE: openfirstlesson, load last studied language codes...*/</script>
<script defer src="/js_reusables/js_for_different_browsers_and_devices.js">/*UA-parser, deviceDetector, Microphone permissions, Whitelisted browsers*/</script>
<script defer src="/js_reusables/js_for_navigation_handling.js">/*Handle visibilitychange: what happens when user leaves the app*/</script>
<script defer src="/js_reusables/js_for_redirection_to_the_proper_domain.js">/*MAKE SURE THIS IS LISTED AFTER js_for_every_single_html » Check if UI language and browser language match, protection against unauthorized embedding*/</script>
<script defer src="/js_reusables/js_for_handling_fullscreen_mode.js">/*Handle right-clicks, double-clicks..., Be careful with iPhone not allowing fullscreen*/</script>
<script defer src="/js_reusables/js_for_hover_simulation_and_scrollglobe.js">/*Hover simulation for touch devices and rotatable globe with unique drag scrolling*/</script>
<script defer src="/js_reusables/js_for_icon_and_title_animation.js">/*A rotating globe next to the title that appears in the browser-tab*/</script>
<script defer src="/js_reusables/js_for_the_sliding_navigation_menu.js">/*NAVIGATION INSIDE THE APP, PAUSING-UNPAUSING THE APP*/</script>
<script defer src="/js_reusables/js_for_info_boxes_in_parent.js">/*[Your progress will be saved] box and [Your progress has been loaded] box*/</script>
<script defer src="/js_for_cache_handling/0_parent_initial_load_and_111.js">/*Get the files in advance to minimize waiting time - The latter caching will be handled from within each iframed html*/</script>
<!-- <script defer src="/pwa/js_for_pwa.js">/*IN THE FUTURE: Progressive Web App - Handle installation*/</script> -->
<!-- -->
<!-- Firebase -->
<script defer async type="module" src="/pwa/firebase.js"></script>
<!-- -->
<!-- SOLVED: THERE USED TO BE A CONFLICT between eruda and the canvas element, probably because they both used "ctx" as the variable name -->
<!-- Uncomment the following to be able to use the browser console on mobile devices. CAUTION: iframes must use parent.console.log -->
<!-- <script src="/third_party_js/eruda.js"></script> -->
<!-- <script>eruda.init();</script> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script>
window.addEventListener("load",startTracking,{once:true});
function startTracking() {
// Get the array ready
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-8FWCR3LS62');
setTimeout(function () {
const delayedScript = document.createElement("script"); delayedScript.async = true; delayedScript.src = "https://www.googletagmanager.com/gtag/js?id=G-8FWCR3LS62"; document.body.appendChild(delayedScript);
},3000);
}
</script>
<!-- PWA -->
<!-- Idea: We could have manifest_iOS.json and manifest_default.json and set href when DOMContentLoaded happens -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="Speak World Languages">
<meta name="apple-mobile-web-app-status-bar-style" content="#4d606f">
<link rel="apple-touch-icon" href="/pwa/homescreen_icon/icon_for_pwa_en.png">
<link rel="manifest" href="/pwa/manifest_en.json">
<script>
if ("serviceWorker" in navigator) { window.addEventListener("DOMContentLoaded",()=>{ navigator.serviceWorker.register("service-worker.js"); },{once:true}); } // Forgot what this means: Takes too long compared to window load (almost a second)
</script>
<!-- Inline style is for the pre-preloader dialog modal box only -->
<style>
dialog{ position: fixed; z-index: 12000; left:50%;top:50%;transform:translate(-50%,-50%);
background-image: linear-gradient(#a6bac8,#d2dde6); border-radius:8px; border: 0px; padding: 20px 23px 30px 23px;
font-family: "SF Pro","Helvetica","Roboto","Segoe UI Light","Segoe UI",sans-serif; font-size:1.2rem; color:white; text-align:center;}
dialog div {background-color: rgba(88,103,121,0.5); padding: 5px; border-radius: 8px; cursor: pointer; min-width:8ch; display: inline-block;}
dialog div:hover{background-color: rgba(66,80,94,0.75);}
dialog::backdrop{background-image: linear-gradient(rgba(25,42,60,0.8),rgba(60,80,103,0.8));}
@media (orientation: landscape) { dialog{min-width: 38ch; max-width: 45ch;} }
@media (orientation: portrait) { dialog{min-width: 80vmin; max-width: 90vmin;} }
</style>
</head>
<body>
<!-- Pre-preloader -->
<dialog data-nosnippet style="line-height:3.0ch; white-space: normal;">
<span style="white-space:nowrap;">Looks like it's taking</span> <span style="white-space:nowrap;">a bit long to load…</span>
<p style="line-height:1ch;"> </p>
<span style="white-space:nowrap;">Check your connection</span> <span style="white-space:nowrap;">to see if</span>
<span style="white-space:nowrap;">you should wait</span> <span style="white-space:nowrap;">or try restarting the app</span>
<p style="line-height:2ch;"> </p>
<div style="outline:none;" onclick="this.parentNode.close();">Wait</div>
<div style="outline:none;" onclick="itIsAlreadyCertainThatUserWantsToReload = true; location.reload();">Restart</div>
</dialog>
<script>
// Code for pre-preloader
var itIsAlreadyCertainThatUserWantsToReload = false; // In this case we want to skip the "Are you sure" prompt caused by beforeunload in js_for_the_parent_all_browsers_all_devices,,, Must always be false except the info box case in in js_for_info_boxes_in_parent and the dialog element here where user obviously sure as he/himself or she/herself makes the choice
let auditTheVeryFirstLoadTimeout;
document.addEventListener('readystatechange', (event) => {
if (event.target.readyState === 'interactive') { auditTheVeryFirstLoadTimeout = setTimeout(function () { document.getElementsByTagName('dialog')[0].showModal(); }, 8000); } // 8s should be good » Lesson reload box (not this dialog) appears if load still hasn't happened in 14s~20s,,, js_for_the_parent_all_browsers_all_devices AND js_for_info_boxes_in_parent
else if (event.target.readyState === 'complete') { clearTimeout(auditTheVeryFirstLoadTimeout); document.getElementsByTagName('dialog')[0].close(); }
});
</script>
<!-- Preloader with beautiful globe -->
<div id="idOfThePreloadHandlingDiv" style="position: fixed; top:0; left:0; bottom:0; right:0; background-color: white; display: flex; justify-content: center; align-items: center; z-index: 9999;">
<!-- The initial style is left inline as a safe measure against slow network etc. -->
<img id="globeFrameZeroImgID" src="/user_interface/images/preload_globe_100x150_frame0.webp" alt="Loading..." draggable="false">
<!-- The hiding and showing of this div is manipulated via script. See inline script below -->
</div>
<!-- Preloader with nice green and blue circles -->
<div id="orbitingCirclesDivID" class="orbitingCirclesTopContainer" style="display:none;">
<div class="loadingio-spinner-interwind-f4cl6mjzf0h"><div class="ldio-d52i6xebzgm">
<div><div><div><div></div></div></div><div><div><div></div></div></div></div>
</div></div>
</div>
<!-- When asking for permission about microphone -->
<div id="allowMicrophoneDivID" class="youMustAllowMicrophone">
<img src="/user_interface/images/microphone.webp" style="width:50px;" alt="Please allow microphone" draggable="false">
<p data-nosnippet>?</p>
<!-- VERY IMPORTANT: p element must be the second child in the div so that it can be selected with children[1],,, See js_for_different_browsers_and_devices -->
<!-- In Safari there will be another P element injected here,,, See js_for_different_browsers_and_devices -->
</div>
<!-- THE MAIN MENU -->
<main> <!-- See css_for_the_container_parent_html.css & js_for_the_parent_all_browsers_all_devices.js-->
<header> <!-- Font setting is in js_for_every_single_html -->
<p>Choose the language <span style="white-space:nowrap;">you want to learn</span></p>
</header>
<article>
<div id="layerA1_ID">
<div id="layerA2_ID">
<!-- See js_for_the_parent_all_browsers_all_devices.js and find mouseDownMenuButtonF touchEndMenuButtonF -->
<!-- Observe what names and ids do -->
<!-- If more than one dialect|accent is available, better if we prompt and ask which one user wants to hear -->
<button name="ja" id="">Hito Language (Japanese)</button>
<button name="ko" id="">Saram Language (Korean)</button> <!-- Saram Language (Korean) -->
<!-- As of 2023 putonghua dialect chosen automatically -->
<button name="zh" id="" style="opacity:0.55; pointer-events:none;">Chinese (coming soon)</button> <!-- Renmen Language (Chinese) -->
<!-- As of 2023 istanbul dialect chosen automatically -->
<button name="tr" id="" style="opacity:0.55; pointer-events:none;">Turkish (coming soon)</button> <!-- Kishi Language (Turkish) -->
<!-- <button name="ar" id="">Annaas Language (Arabic)</button> -->
<!-- Leute Language (German) -->
<!-- <button name="de" id="" style="opacity:0.55; pointer-events:none;">German (coming soon)</button> -->
<!-- <button name="fr" id="">Gens Language (French)</button> -->
<!-- <button name="en" id="">Eastern or Western English</button> -->
<!-- WHEN NEW BUTTONS ARE ADDED -->
<!-- MUST UPDATE function startTeaching(usersChoice) in js_for_the_parent_all_browsers_all_devices -->
<!-- Also check letUserChooseAnAccentOrDialect -->
</div>
</div>
<div id="layerB1_ID">
<div id="layerB2_ID">
<img src="/user_interface/images/arrow_left.webp" alt="Rotate left" draggable="false">
<canvas width="250" height="250">Loading...</canvas>
<img src="/user_interface/images/arrow_right.webp" alt="Rotate right" draggable="false">
</div>
</div>
</article>
<footer><p>A project by <span style="white-space:nowrap;">Manheart Earthman</span></p>
<!-- Understanding the world is good -->
<!-- Reunion of humankind is good -->
</footer>
</main>
<!-- LESSONS WILL BE DISPLAYED ONE BY ONE THROUGH THIS IFRAME -->
<iframe src="" allowfullscreen></iframe>
<!-- allowfullscreen is needed to be able to call requestFullscreen on the iframe, even though, as of Oct 2022 such a call never happens. See js_for_handling_fullscreen_mode -->
<!-- MAKE THE APP LOAD slightly FASTER BY ASSIGNING src OF THE IMAGE FILES AFTER window load -->
<script>
var preloadHandlingDiv; // REMEMBER: This will be called from bread.js, water.js etc
window.addEventListener("load",handleLoad,{once:true});
function handleLoad() {
const preloadGlobeImg = document.getElementById('globeFrameZeroImgID');
preloadGlobeImg.src = "/user_interface/images/preload_globe_100x150.webp"; // Switch from the 16KB single frame webp to the animated one 449KB one. Which will probably be ready until user chooses a language to learn.
preloadHandlingDiv = document.getElementById('idOfThePreloadHandlingDiv');
preloadHandlingDiv.classList.add("addThisClassToHideThePreloader"); // See css_for_the_container_parent_html
//---
const frame = document.getElementsByTagName('IFRAME')[0];
frame.src = "/user_interface/blank.html"; // it is only 1 kb -> REMEMBER: ayFreym.addEventListener('load',...) in js_for_the_parent_all_browsers_all_devices
//---
const main = document.getElementsByTagName('MAIN')[0];
const header = document.getElementsByTagName('HEADER')[0];
const article = document.getElementsByTagName('ARTICLE')[0];
const a1 = document.getElementById('layerA1_ID');
const a2 = document.getElementById('layerA2_ID');
const b1 = document.getElementById('layerB1_ID');
const b2 = document.getElementById('layerB2_ID');
const canvas = document.getElementsByTagName('CANVAS')[0];
const buttons = document.getElementsByTagName('BUTTON');
const footer = document.getElementsByTagName('FOOTER')[0];
// Handle styles depending on user's device
if (deviceDetector.device == "desktop") {
main.classList.add("mainDesktop");
header.classList.add("headerDesktop");
article.classList.add("articleDesktop");
a1.classList.add("layerA1_desktop");
a2.classList.add("layerA2_desktop");
b1.classList.add("layerB1_desktop");
b2.classList.add("layerB2_desktop");
canvas.classList.add("canvasDesktop");
let i; for (i = 0; i < buttons.length; i++) { buttons[i].classList.add("buttonDesktop"); }
footer.classList.add("footerDesktop");
}
else {
main.classList.add("mainPhoneOrTablet");
header.classList.add("headerPhoneOrTablet");
article.classList.add("articlePhoneOrTablet");
a1.classList.add("layerA1_mobile");
a2.classList.add("layerA2_mobile");
b1.classList.add("layerB1_mobile");
b2.classList.add("layerB2_mobile");
canvas.classList.add("canvasPhoneOrTablet");
let i; for (i = 0; i < buttons.length; i++) { buttons[i].classList.add("buttonMobile"); }
footer.classList.add("footerPhoneOrTablet"); // See css_for_the_container_parent_html
if (!isApple) { // Android
topContainerDivOfTheSlidingNavMenuForMobiles.appendChild(footer);
footer.style.position = "absolute";
footer.style.bottom = "0px";
footer.style.color = "rgba(136,166,158,0.6)";
footer.style.backgroundColor = "white";
}
}
}
</script>
<!-- WHAT TO DISPLAY DURING APP MAINTENANCE :: UNCOMMENT WHEN NECESSARY -->
<!--
<div data-nosnippet id="removeThisID" onmouseup="adminAccess()" style="position: fixed; z-index:50000; width:100vw; width:100dvw; height:100%; height:100dvh; background-color:white; display:flex; align-items:center; justify-content:center; flex-direction: column;">
<img data-nosnippet src="/user_interface/images/maintenance.png" alt="...">
<p data-nosnippet style="color:#040a17;">Sorry, we are performing app maintenance<br>Please check back later</p>
</div>
<script>let secretCounter=0; function adminAccess() { secretCounter++; if (secretCounter>4) { document.body.removeChild(document.getElementById('removeThisID')); } }</script>
-->
<!-- END OF WHAT TO DISPLAY DURING APP MAINTENANCE -->
<!-- SECRET WAY TO ACCESS CONSOLE ON MOBILES -->
<script>
let secretCounterIsAt=0; let counterResetInterval=null; const consoleActivatorScript = document.createElement("script");
if ('ontouchstart' in window) {
document.body.addEventListener("touchstart",handleActivationOfEruda);
counterResetInterval=setInterval(function () { secretCounterIsAt=0; }, 4444);
}
function handleActivationOfEruda(event) {
if (event.touches.length > 3 ) {
secretCounterIsAt++;
// -
if (secretCounterIsAt>4) {
document.body.removeEventListener("touchstart",handleActivationOfEruda);
clearInterval(counterResetInterval);
alert("Activating console");
setTimeout(function () {
alert("Getting eruda");
consoleActivatorScript.src = "/third_party_js/eruda.js";
document.body.appendChild(consoleActivatorScript);
let erudaLoadCheckInterval = setInterval(function () {
try {
eruda.init();
alert("eruda initialized"); // Why is it that this never fires on mobile, even though it fires on desktop?
clearInterval(erudaLoadCheckInterval);
} catch (e) { }
}, 1000);
}, 100);
}
}
}
</script>
<!-- END OF SECRET WAY TO ACCESS CONSOLE ON MOBILES -->
</body>
</html>