diff options
Diffstat (limited to 'misc/dist/html')
-rw-r--r-- | misc/dist/html/editor.html | 20 | ||||
-rw-r--r-- | misc/dist/html/manifest.json | 18 | ||||
-rw-r--r-- | misc/dist/html/offline.html | 42 | ||||
-rw-r--r-- | misc/dist/html/service-worker.js | 84 |
4 files changed, 162 insertions, 2 deletions
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index 535721f418..3bf87f3506 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -2,8 +2,18 @@ <html xmlns='http://www.w3.org/1999/xhtml' lang='' xml:lang=''> <head> <meta charset='utf-8' /> - <meta name='viewport' content='width=device-width, user-scalable=no' /> + <meta name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no' /> + <meta name="mobile-web-app-capable" content="yes" /> + <meta name="apple-mobile-web-app-capable" content="yes" /> + <meta name="application-name" content="Godot" /> + <meta name="apple-mobile-web-app-title" content="Godot" /> + <meta name="theme-color" content="#478cbf" /> + <meta name="msapplication-navbutton-color" content="#478cbf" /> + <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> + <meta name="msapplication-starturl" content="/latest" /> <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' /> + <link rel="apple-touch-icon" type="image/png" href="favicon.png" /> + <link rel="manifest" href="manifest.json" /> <title>Godot Engine Web Editor (@GODOT_VERSION@)</title> <style> *:focus { @@ -250,7 +260,13 @@ <div id='status-notice' class='godot' style='display: none;'></div> </div> </div> - + <script> + window.addEventListener("load", () => { + if ("serviceWorker" in navigator) { + navigator.serviceWorker.register("service.worker.js"); + } + }); + </script> <script src='godot.tools.js'></script> <script>//<![CDATA[ diff --git a/misc/dist/html/manifest.json b/misc/dist/html/manifest.json new file mode 100644 index 0000000000..6e0053c23c --- /dev/null +++ b/misc/dist/html/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Godot Engine", + "short_name": "Godot", + "description": "Multi-platform 2D and 3D game engine with a feature-rich editor", + "lang": "en", + "start_url": "/godot.tools.html", + "display": "standalone", + "orientation": "landscape", + "theme_color": "#478cbf", + "icons": [ + { + "src": "favicon.png", + "sizes": "256x256", + "type": "image/png" + } + ], + "background_color": "#333b4f" +} diff --git a/misc/dist/html/offline.html b/misc/dist/html/offline.html new file mode 100644 index 0000000000..000c21b4d3 --- /dev/null +++ b/misc/dist/html/offline.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <title>You are offline</title> + <style> + html { + background-color: #333b4f; + color: #e0e0e0; + } + + body { + font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + margin: 2rem; + } + + p { + margin-block: 1rem; + } + + button { + display: block; + padding: 1rem 2rem; + margin: 3rem auto 0; + } + </style> +</head> +<body> + <h1>You are offline</h1> + <p>This application requires an Internet connection to run for the first time.</p> + <p>Press the button below to try reloading:</p> + <button type="button">Reload</button> + + <script> + document.querySelector("button").addEventListener("click", () => { + window.location.reload(); + }); + </script> +</body> +</html> diff --git a/misc/dist/html/service-worker.js b/misc/dist/html/service-worker.js new file mode 100644 index 0000000000..d4eaed2b17 --- /dev/null +++ b/misc/dist/html/service-worker.js @@ -0,0 +1,84 @@ +// This service worker is required to expose an exported Godot project as a +// Progressive Web App. It provides an offline fallback page telling the user +// that they need an Internet conneciton to run the project if desired. +// Incrementing CACHE_VERSION will kick off the install event and force +// previously cached resources to be updated from the network. +const CACHE_VERSION = "@GODOT_VERSION@"; +const CACHE_NAME = "@GODOT_NAME@-cache"; +const OFFLINE_URL = "offline.html"; +// Files that will be cached on load. +const CACHED_FILES = [ + "godot.tools.html", + "offline.html", + "godot.tools.js", + "godot.tools.worker.js", + "godot.tools.audio.worklet.js", + "logo.svg", + "favicon.png", +]; + +// Files that we might not want the user to preload, and will only be cached on first load. +const CACHABLE_FILES = [ + "godot.tools.wasm", +]; +const FULL_CACHE = CACHED_FILES.concat(CACHABLE_FILES); + +self.addEventListener("install", (event) => { + event.waitUntil(async function () { + const cache = await caches.open(CACHE_NAME); + // Clear old cache (including optionals). + await Promise.all(FULL_CACHE.map(path => cache.delete(path))); + // Insert new one. + const done = await cache.addAll(CACHED_FILES); + return done; + }()); +}); + +self.addEventListener("activate", (event) => { + event.waitUntil(async function () { + if ("navigationPreload" in self.registration) { + await self.registration.navigationPreload.enable(); + } + }()); + // Tell the active service worker to take control of the page immediately. + self.clients.claim(); +}); + +self.addEventListener("fetch", (event) => { + const isNavigate = event.request.mode === "navigate"; + const url = event.request.url || ""; + const referrer = event.request.referrer || ""; + const base = referrer.slice(0, referrer.lastIndexOf("/") + 1); + const local = url.startsWith(base) ? url.replace(base, "") : ""; + const isCachable = FULL_CACHE.some(v => v === local) || (base === referrer && base.endsWith(CACHED_FILES[0])); + if (isNavigate || isCachable) { + event.respondWith(async function () { + try { + // Use the preloaded response, if it's there + let request = event.request.clone(); + let response = await event.preloadResponse; + if (!response) { + // Or, go over network. + response = await fetch(event.request); + } + if (isCachable) { + // Update the cache + const cache = await caches.open(CACHE_NAME); + cache.put(request, response.clone()); + } + return response; + } catch (error) { + const cache = await caches.open(CACHE_NAME); + if (event.request.mode === "navigate") { + // Check if we have full cache. + const cached = await Promise.all(FULL_CACHE.map(name => cache.match(name))); + const missing = cached.some(v => v === undefined); + const cachedResponse = missing ? await caches.match(OFFLINE_URL) : await caches.match(CACHED_FILES[0]); + return cachedResponse; + } + const cachedResponse = await caches.match(event.request); + return cachedResponse; + } + }()); + } +}); |