template.html.in 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <!DOCTYPE html>
  2. <html lang="en-us">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  6. <title>SuperTux @SUPERTUX_VERSION_STRING@</title>
  7. <style>
  8. body {
  9. font-family: arial;
  10. margin: 0;
  11. padding: none;
  12. background-color: black;
  13. }
  14. .emscripten {
  15. padding-right: 0;
  16. margin-left: auto;
  17. margin-right: auto;
  18. display: block
  19. }
  20. canvas.emscripten {
  21. border: 0 none;
  22. background-color: #0000;
  23. }
  24. .spinner {
  25. height: 30px;
  26. width: 30px;
  27. margin: 0;
  28. margin-top: 20px;
  29. margin-left: 20px;
  30. display: inline-block;
  31. vertical-align: top;
  32. -webkit-animation: rotation .8s linear infinite;
  33. -moz-animation: rotation .8s linear infinite;
  34. -o-animation: rotation .8s linear infinite;
  35. animation: rotation .8s linear infinite;
  36. border-left: 5px solid #ebebeb;
  37. border-right: 5px solid #ebebeb;
  38. border-bottom: 5px solid #ebebeb;
  39. border-top: 5px solid #78787800;
  40. border-radius: 100%;
  41. }
  42. @-webkit-keyframes rotation {
  43. from {
  44. -webkit-transform: rotate(0)
  45. }
  46. to {
  47. -webkit-transform: rotate(360deg)
  48. }
  49. }
  50. @-moz-keyframes rotation {
  51. from {
  52. -moz-transform: rotate(0)
  53. }
  54. to {
  55. -moz-transform: rotate(360deg)
  56. }
  57. }
  58. @-o-keyframes rotation {
  59. from {
  60. -o-transform: rotate(0)
  61. }
  62. to {
  63. -o-transform: rotate(360deg)
  64. }
  65. }
  66. @keyframes rotation {
  67. from {
  68. transform: rotate(0)
  69. }
  70. to {
  71. transform: rotate(360deg)
  72. }
  73. }
  74. #status {
  75. display: inline-block;
  76. vertical-align: top;
  77. margin-top: 30px;
  78. margin-left: 20px;
  79. margin-bottom: 30px;
  80. margin-right: 20px;
  81. font-weight: 700;
  82. color: #d7d7d7;
  83. }
  84. #progress {
  85. height: 6px;
  86. width: 200px;
  87. border: none;
  88. border-radius: 3px;
  89. background: #787878;
  90. margin-left: 20px;
  91. }
  92. progress::-moz-progress-bar {
  93. border-radius: 3px;
  94. background: white;
  95. }
  96. #output {
  97. width: 100%;
  98. height: 200px;
  99. margin: 0 auto;
  100. margin-top: 10px;
  101. border: 0;
  102. padding-left: 0;
  103. padding-right: 0;
  104. display: block;
  105. background-color: #0000;
  106. color: #fff;
  107. font-family: 'Lucida Console', Monaco, monospace;
  108. outline: 0;
  109. overflow: scroll;
  110. }
  111. #overlay {
  112. position: fixed;
  113. left: 0;
  114. top: 0;
  115. height: 100%;
  116. width: 100%;
  117. background-color: #000d;
  118. z-index: 10;
  119. background-image: linear-gradient(to bottom, #000a, #000a), url('supertux2.png'), url('supertux2_bkg.png');
  120. background-position: 0 0, 50% calc(50% - 100px);
  121. background-repeat: repeat, no-repeat;
  122. animation: movebkg 10s linear infinite;
  123. }
  124. .center_stuff {
  125. display: flex;
  126. align-items: center;
  127. justify-content: center;
  128. }
  129. .bottom_stuff {
  130. text-align: center;
  131. color: #fff7;
  132. position: absolute;
  133. bottom: 0;
  134. width: 100%;
  135. padding: 15px;
  136. }
  137. .bottom_stuff a {
  138. color: #8cf;
  139. font-weight: bold;
  140. }
  141. @keyframes movebkg {
  142. from {
  143. background-position: 0 0, 50% calc(50% - 100px);
  144. }
  145. to {
  146. background-position: -256px 0, 50% calc(50% - 100px);
  147. }
  148. }
  149. </style>
  150. </head>
  151. <body>
  152. <div id="overlay" class="center_stuff">
  153. <center>
  154. <div class="spinner" id="spinner"></div>
  155. <div class="emscripten" id="status">Downloading...</div>
  156. <br/>
  157. <div class="emscripten"><progress hidden id="progress" max="100" value="0"></progress></div>
  158. </center>
  159. <div class="bottom_stuff">
  160. <p>If the game is unplayably slow, try downloading the desktop version for your platform at <a href="https://www.supertux.org/download.html" target="_blank">supertux.org</a></p>
  161. <p id="progress_desc"></p>
  162. </div>
  163. </div>
  164. <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex="0"></canvas>
  165. <p id="output"></p>
  166. <input type="file" id="file_upload" multiple="multiple" style="display:none">
  167. <script>
  168. if ("@CMAKE_BUILD_TYPE@" == "Release") {
  169. document.getElementById("output").style.display = "none";
  170. }
  171. var statusElement = document.getElementById("status"),
  172. progressElement = document.getElementById("progress"),
  173. progressDescElement = document.getElementById("progress_desc"),
  174. overlayElement = document.getElementById("overlay"),
  175. spinnerElement = document.getElementById("spinner");
  176. var lastUpdate = Date.now() / 1000;
  177. var lastStep = 0;
  178. function getExp(num) {
  179. if (num > 1e12) {
  180. return (num / 1e12).toFixed(3) + "T";
  181. } else if (num > 1e9) {
  182. return (num / 1e9).toFixed(3) + "G";
  183. } else if (num > 1e6) {
  184. return (num / 1e6).toFixed(3) + "M";
  185. } else if (num > 1e3) {
  186. return (num / 1e3).toFixed(3) + "K";
  187. } else {
  188. return num.toFixed();
  189. }
  190. }
  191. var Module = {
  192. preRun: [],
  193. postRun: [],
  194. print: function () {
  195. var e = document.getElementById("output");
  196. if (e)
  197. e.innerHTML = "";
  198. return function (t) {
  199. if (arguments.length > 1)
  200. t = Array.prototype.slice.call(arguments).join(" ");
  201. t = Array.prototype.slice.call(arguments).join(" ");
  202. console.log(t);
  203. if (e) {
  204. e.innerHTML += t + "<br/>";
  205. e.scrollTop = e.scrollHeight;
  206. }
  207. }
  208. }(),
  209. printErr: function () {
  210. var e = document.getElementById("output");
  211. if (e)
  212. e.innerHTML = "";
  213. return function (t) {
  214. if (arguments.length > 1)
  215. t = Array.prototype.slice.call(arguments).join(" ");
  216. console.error(t);
  217. if (e) {
  218. e.innerHTML += "<span style='color:red;'>" + t + "</span><br/>";
  219. e.scrollTop = e.scrollHeight;
  220. }
  221. }
  222. }(),
  223. canvas: function () {
  224. var c = document.getElementById("canvas");
  225. c.addEventListener("webglcontextlost", (function (e) {
  226. alert("WebGL context lost. You will need to reload the page.");
  227. e.preventDefault();
  228. }), !1);
  229. // Fixed a bug where an iframe containing SuperTUx (e. g. Newgrounds)
  230. // would lose focus if the user clicks outside of the iframe and cannot
  231. // get focus back when user clicks inside the iframe, thus preventing
  232. // any keyboard input from being received by SuperTux.
  233. // If you want to try: Disable the three lines below, compile, upload on
  234. // Newgrounds, wait for the game to load, click outside the game, click
  235. // back inside the game, then try to press buttons (e. g. arrows), it'll
  236. // behave as if focus was outside the iframe (e. g. pressing down will scroll
  237. // the page instead of navigating the menus/worldmap/ducking/whatever)
  238. c.addEventListener("click", function(e) {
  239. c.focus();
  240. });
  241. return c;
  242. }(),
  243. setStatus: function (e) {
  244. overlayElement.style.display = e ? "flex" : "none";
  245. if (Module.setStatus.last || (Module.setStatus.last = { time: Date.now(), text: "" }), e !== Module.setStatus.last.text)
  246. {
  247. var t = e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),
  248. n = Date.now();
  249. if (!(t && n - Module.setStatus.last.time < 30))
  250. {
  251. Module.setStatus.last.time = n;
  252. Module.setStatus.last.text = e;
  253. if (t)
  254. {
  255. e = t[1];
  256. progressElement.value = 100 * parseInt(t[2]);
  257. progressElement.max = 100 * parseInt(t[4]);
  258. progressElement.hidden = false;
  259. var update = Date.now() / 1000
  260. progressDescElement.innerText = e.match(/[Dd]ownload/)
  261. ? getExp(parseInt(t[2])) + "b / " + getExp(parseInt(t[4])) + "b (" + getExp((parseInt(t[2]) - lastStep) / (update - lastUpdate)) + "b/s)"
  262. : t[2] + " of " + t[4] + " assets loaded";
  263. lastUpdate = Date.now() / 1000;
  264. lastStep = parseInt(t[2]);
  265. spinnerElement.hidden = false;
  266. }
  267. else
  268. {
  269. progressElement.value = null;
  270. progressElement.max = null;
  271. progressElement.hidden = true;
  272. progressDescElement.innerText = "";
  273. if (!e)
  274. spinnerElement.style.display = "none";
  275. }
  276. statusElement.innerHTML = e;
  277. }
  278. }
  279. },
  280. totalDependencies: 0,
  281. monitorRunDependencies: function (e) {
  282. this.totalDependencies = Math.max(this.totalDependencies, e);
  283. Module.setStatus(e ? "Preparing... (" + (this.totalDependencies - e) + "/" + this.totalDependencies + ")" : "All downloads complete.")
  284. }
  285. };
  286. Module.setStatus("Downloading...");
  287. window.onerror = function (e) {
  288. Module.setStatus("Oops!<br><br>An error occured and SuperTux crashed.<br><br><pre>" + e + "</pre>");
  289. spinnerElement.style.display = "none";
  290. Module.setStatus = function (e) {
  291. if (e)
  292. Module.printErr("[post-exception status] " + e)
  293. }
  294. }
  295. var autofit = true;
  296. var setResolution = null;
  297. function tryResize() {
  298. if (!autofit)
  299. return;
  300. if (!setResolution)
  301. setResolution = Module.cwrap('set_resolution', 'void', ['number']);
  302. setResolution(window.innerWidth, window.innerHeight);
  303. }
  304. window.supertux_setAutofit = function(newAutofit) {
  305. autofit = newAutofit;
  306. document.body.style.overflow = (autofit || ("@CMAKE_BUILD_TYPE@" == "Release")) ? "hidden" : "initial";
  307. tryResize();
  308. }
  309. // FIXME: Hardcoded
  310. const root = "/home/web_user/.local/share/supertux2/";
  311. window.supertux_loadFiles = function() {
  312. for (var key of Object.keys(localStorage)) {
  313. if (key !== "config" && !key.match("^profile[0-9]+/"))
  314. continue;
  315. if (key.indexOf("/") !== -1) {
  316. try {
  317. FS.mkdir(root + key.substr(0, key.indexOf("/")));
  318. } catch {
  319. // Folder probably already exists
  320. }
  321. }
  322. FS.writeFile(root + key, localStorage.getItem(key));
  323. }
  324. }
  325. window.supertux_saveFiles = function() {
  326. function save(file) {
  327. try {
  328. localStorage.setItem(file, FS.readFile(root + file, { encoding: "utf8" }));
  329. return true;
  330. } catch(e) {
  331. console.error(e);
  332. console.error("ERROR: Couldn't save file '" + file + "'");
  333. return false;
  334. }
  335. }
  336. save("config");
  337. var data_folder = FS.lookupPath(root);
  338. for (var folder_name in data_folder.node.contents) {
  339. if (!folder_name.match("^profile[0-9]+$"))
  340. continue;
  341. for (var file_name in data_folder.node.contents[folder_name].contents) {
  342. save(folder_name + "/" + file_name);
  343. }
  344. }
  345. }
  346. window.supertux_download = function(path) {
  347. try {
  348. var downloadBlob = function(data, fileName, mimeType) {
  349. var blob, url;
  350. blob = new Blob([data], {
  351. type: mimeType
  352. });
  353. url = window.URL.createObjectURL(blob);
  354. var a;
  355. a = document.createElement('a');
  356. a.href = url;
  357. a.download = fileName;
  358. document.body.appendChild(a);
  359. a.style = 'display: none';
  360. a.click();
  361. a.remove()
  362. setTimeout(function() {
  363. return window.URL.revokeObjectURL(url);
  364. }, 1000);
  365. };
  366. var stat = FS.stat(path);
  367. var size = stat.size;
  368. var file = FS.open(path, 'r');
  369. var buf = new Uint8Array(size);
  370. FS.read(file, buf, 0, size, 0);
  371. FS.close(file);
  372. downloadBlob(buf, path.substr(path.lastIndexOf('/') + 1), 'application/octet-stream');
  373. return true;
  374. } catch(e) {
  375. console.error(e);
  376. return false;
  377. }
  378. }
  379. const file_upload = document.getElementById("file_upload");
  380. var base_path = '/';
  381. window.supertux_upload = function(base) {
  382. base_path = base;
  383. // Remove one (or multiple) leading slashes
  384. while (base_path.startsWith("/"))
  385. base_path = base_path.substr(1);
  386. // Add ending slash if missing
  387. if (!base_path.endsWith("/"))
  388. base_path += "/";
  389. // Remove duplicate slashes
  390. base_path = base_path.replaceAll(/\/+/g, "/");
  391. file_upload.click();
  392. }
  393. file_upload.addEventListener('change', () => {
  394. for (var file of file_upload.files) {
  395. var fr = new FileReader();
  396. fr.filename = file.name;
  397. fr.onload = function(e) {
  398. var data = new Uint8Array(e.target.result);
  399. // Create all dirs if necessary
  400. var index = 0;
  401. while (base_path.indexOf("/", index) != -1) {
  402. index = base_path.indexOf("/", index);
  403. var subfolder = base_path.substr(0, index);
  404. if (!FS.analyzePath(root + subfolder).exists)
  405. FS.mkdir(root + subfolder);
  406. index += 1;
  407. }
  408. var em_file = FS.open(root + base_path + e.target.filename, "w");
  409. FS.write(em_file, data, 0, data.length, 0);
  410. FS.close(em_file);
  411. };
  412. fr.readAsArrayBuffer(file);
  413. }
  414. });
  415. window.onresize = tryResize;
  416. window.onunload = () => {
  417. Module.ccall("save_config", "void", [], []);
  418. supertux_saveFiles();
  419. };
  420. </script>
  421. <script async src="supertux2.js"></script>
  422. </body>
  423. </html>