mirror of
https://github.com/EmulatorJS/EmulatorJS.git
synced 2026-02-06 11:17:36 +00:00
- Changed private methods (#addFileToDB and #getObjectStore) in EJS_STORAGE class to public methods (addFileToDB and getObjectStore) for better accessibility. - Updated index.html to include language and charset attributes for improved HTML5 compliance and accessibility.
429 lines
16 KiB
HTML
429 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>EmulatorJS</title>
|
|
<link rel="icon" href="docs/favicon.ico" sizes="16x16 32x32 48x48 64x64" type="image/vnd.microsoft.icon">
|
|
<meta name="viewport" content="width = device-width, initial-scale = 1">
|
|
<style>
|
|
body, html {
|
|
height: 100%;
|
|
background-color: black;
|
|
color: white;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
body, #box, #top {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-direction: column;
|
|
}
|
|
|
|
#box {
|
|
color: #aaa;
|
|
height: 20em;
|
|
width: 30em;
|
|
max-width: 80%;
|
|
max-height: 80%;
|
|
background-color: #333;
|
|
border-radius: 0.4em;
|
|
border: 2px solid #555;
|
|
position: relative;
|
|
flex-direction: column;
|
|
transition-duration: 0.2s;
|
|
overflow: hidden;
|
|
font-family: monospace;
|
|
font-weight: bold;
|
|
font-size: 20px;
|
|
margin: 5px;
|
|
text-align: center;
|
|
padding: 10px;
|
|
}
|
|
|
|
#box:hover, #box[drag] {
|
|
border-color: #1AAFFF;
|
|
color: #ddd
|
|
}
|
|
|
|
#advanced {
|
|
color: #aaa;
|
|
text-align: left;
|
|
width: 30em;
|
|
max-width: 80%;
|
|
background-color: #333;
|
|
border-radius: 0.4em;
|
|
border: 2px solid #555;
|
|
position: relative;
|
|
flex-direction: column;
|
|
transition-duration: 0.2s;
|
|
overflow: hidden;
|
|
font-family: monospace;
|
|
font-weight: bold;
|
|
font-size: 20px;
|
|
margin: 5px;
|
|
padding: 10px;
|
|
}
|
|
|
|
#advancedOptionsBox {
|
|
margin-top: 10px;
|
|
font-size: 14px;
|
|
margin-left: 20px;
|
|
}
|
|
|
|
.advancedOptionsBoxRow {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
#input {
|
|
cursor: pointer;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
opacity: 0;
|
|
}
|
|
|
|
#display {
|
|
width: 100%;
|
|
height: 100%
|
|
}
|
|
|
|
select, button {
|
|
padding: 0.6em 0.4em;
|
|
margin: 0.5em;
|
|
width: 15em;
|
|
max-width: 100%;
|
|
font-family: monospace;
|
|
font-weight: bold;
|
|
font-size: 16px;
|
|
background-color: #444;
|
|
color: #aaa;
|
|
border-radius: 0.4em;
|
|
border: 1px solid #555;
|
|
cursor: pointer;
|
|
transition-duration: 0.2s
|
|
}
|
|
|
|
select:hover, button:hover {
|
|
background-color: #666;
|
|
color: #ddd
|
|
}
|
|
|
|
.logo {
|
|
width: 130px;
|
|
height: 130px;
|
|
filter: drop-shadow(0 0 8px white);
|
|
}
|
|
|
|
#top {
|
|
margin: 5px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div id="top">
|
|
<h1>EmulatorJS Demo</h1>
|
|
<img src="docs/Logo-light.png" alt="Logo" class="logo">
|
|
<br>
|
|
</div>
|
|
<div id="box">
|
|
<input type="file" id ="input" title="Upload" />
|
|
Drag ROM file or click here
|
|
</div>
|
|
<div id="advanced">
|
|
<div id="advancedToggleBox">
|
|
<input type="checkbox" id="advancedToggle" />
|
|
<label for="advancedToggle"> Show Advanced Options</label>
|
|
</div>
|
|
<div id="advancedOptionsBox">
|
|
<div class="advancedOptionsBoxRow">
|
|
<input type="file" id ="inputAdvanced" title="BIOS" />
|
|
<label for="inputAdvanced"> Upload BIOS file (if required)</label>
|
|
</div>
|
|
<div class="advancedOptionsBoxRow">
|
|
<input type="checkbox" id="debugToggle" />
|
|
<label for="debugToggle"> Enable Debug Mode</label>
|
|
</div>
|
|
<div id="advancedOptionsBoxThreads" class="advancedOptionsBoxRow">
|
|
<input type="checkbox" id="threadsToggle" />
|
|
<label for="threadsToggle"> Enable Threads</label>
|
|
</div>
|
|
<div class="advancedOptionsBoxRow">
|
|
<span>Browser mode: </span>
|
|
<input type="radio" id="browserModeAuto" name="browserMode" value="auto">
|
|
<label for="browserModeAuto"> Auto </label>
|
|
<input type="radio" id="browserModeDesktop" name="browserMode" value="desktop">
|
|
<label for="browserModeDesktop"> Desktop </label>
|
|
<input type="radio" id="browserModeMobile" name="browserMode" value="mobile">
|
|
<label for="browserModeMobile"> Mobile </label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let enableDebug = false;
|
|
let enableThreads = false;
|
|
let browserMode;
|
|
|
|
const biosFileInput = document.getElementById("inputAdvanced");
|
|
|
|
const advancedToggle = document.getElementById("advancedToggle");
|
|
const advanced = document.getElementById("advanced");
|
|
const advancedOptionsBox = document.getElementById("advancedOptionsBox");
|
|
advancedOptionsBox.style.display = "none";
|
|
advancedToggle.addEventListener("change", (event) => {
|
|
if (event.target.checked) {
|
|
advancedOptionsBox.style.display = "block";
|
|
} else {
|
|
advancedOptionsBox.style.display = "none";
|
|
}
|
|
});
|
|
|
|
const queryString = window.location.search;
|
|
const urlParams = new URLSearchParams(queryString);
|
|
const debugToggle = document.getElementById("debugToggle");
|
|
debugToggle.addEventListener("change", (event) => {
|
|
enableDebug = event.target.checked;
|
|
console.log(`Debug is ${enableDebug ? "enabled" : "disabled"}`);
|
|
});
|
|
const threadsToggleAvailable = document.getElementById("advancedOptionsBoxThreads");
|
|
const threadsToggle = document.getElementById("threadsToggle");
|
|
threadsToggle.addEventListener("change", (event) => {
|
|
enableThreads = event.target.checked;
|
|
console.log(`Threads are ${enableThreads ? "enabled" : "disabled"}`);
|
|
});
|
|
if (parseInt(urlParams.get("debug")) === 1 || urlParams.get("debug") === "true") {
|
|
enableDebug = true;
|
|
debugToggle.checked = true;
|
|
console.log("Debug is enabled");
|
|
} else {
|
|
debugToggle.checked = false;
|
|
console.log("Debug is disabled");
|
|
}
|
|
|
|
if (window.SharedArrayBuffer) {
|
|
threadsToggleAvailable.style.display = "block";
|
|
if (parseInt(urlParams.get("threads")) === 1 || urlParams.get("threads") === "true") {
|
|
enableThreads = true;
|
|
threadsToggle.checked = true;
|
|
console.log("Threads are enabled");
|
|
} else {
|
|
threadsToggle.checked = false;
|
|
console.log("Threads are disabled");
|
|
}
|
|
} else {
|
|
threadsToggleAvailable.style.display = "none";
|
|
console.warn("Threads are disabled as SharedArrayBuffer is not available. Threads requires two headers to be set when sending you html page. See https://stackoverflow.com/a/68630724");
|
|
}
|
|
|
|
const browserModeAuto = document.getElementById("browserModeAuto");
|
|
browserModeAuto.addEventListener("change", (event) => {
|
|
if (event.target.checked) {
|
|
browserMode = undefined;
|
|
console.log("Browser mode set to auto");
|
|
}
|
|
});
|
|
const browserModeDesktop = document.getElementById("browserModeDesktop");
|
|
browserModeDesktop.addEventListener("change", (event) => {
|
|
if (event.target.checked) {
|
|
browserMode = "desktop";
|
|
console.log("Browser mode set to desktop");
|
|
}
|
|
});
|
|
const browserModeMobile = document.getElementById("browserModeMobile");
|
|
browserModeMobile.addEventListener("change", (event) => {
|
|
if (event.target.checked) {
|
|
browserMode = "mobile";
|
|
console.log("Browser mode set to mobile");
|
|
}
|
|
});
|
|
if (urlParams.get("browserMode")) {
|
|
browserMode = urlParams.get("browserMode");
|
|
switch (browserMode) {
|
|
case 1:
|
|
case "1":
|
|
case "mobile":
|
|
browserModeMobile.checked = true;
|
|
break;
|
|
case 2:
|
|
case "2":
|
|
case "desktop":
|
|
browserModeDesktop.checked = true;
|
|
break;
|
|
default:
|
|
browserModeAuto.checked = true;
|
|
break;
|
|
}
|
|
} else {
|
|
browserModeAuto.checked = true;
|
|
}
|
|
|
|
if (urlParams.get("rom")) {
|
|
console.log(`Loading ROM from URL: roms/${urlParams.get("rom")}`);
|
|
run(false, urlParams.get("rom"));
|
|
}
|
|
|
|
async function run(upload, file) {
|
|
const url = upload ? input.files[0] : `roms/${file}`;
|
|
const parts = upload ? input.files[0].name.split(".") : file.split(".");
|
|
|
|
const biosUrl = biosFileInput.files.length > 0 ? biosFileInput.files[0] : "";
|
|
|
|
const core = await (async (ext) => {
|
|
if (["fds", "nes", "unif", "unf"].includes(ext))
|
|
return "nes"
|
|
|
|
if (["smc", "fig", "sfc", "gd3", "gd7", "dx2", "bsx", "swc"].includes(ext))
|
|
return "snes"
|
|
|
|
if (["z64", "n64"].includes(ext))
|
|
return "n64"
|
|
|
|
if (["pce"].includes(ext))
|
|
return "pce"
|
|
|
|
if (["ngp", "ngc"].includes(ext))
|
|
return "ngp"
|
|
|
|
if (["ws", "wsc"].includes(ext))
|
|
return "ws"
|
|
|
|
if (["col", "cv"].includes(ext))
|
|
return "coleco"
|
|
|
|
if (["d64"].includes(ext))
|
|
return "vice_x64sc"
|
|
|
|
if (["md", "sg", "smd", "gen"].includes(ext))
|
|
return "segaMD"
|
|
|
|
if (["nds", "gba", "gb", "z64", "n64"].includes(ext))
|
|
return ext
|
|
|
|
return await new Promise(resolve => {
|
|
var coreValues = {
|
|
"Nintendo 64": "n64",
|
|
"Nintendo Game Boy": "gb",
|
|
"Nintendo Game Boy Advance": "gba",
|
|
"Nintendo DS": "nds",
|
|
"Nintendo Entertainment System": "nes",
|
|
"Super Nintendo Entertainment System": "snes",
|
|
"PlayStation": "psx",
|
|
"Virtual Boy": "vb",
|
|
"Sega Mega Drive": "segaMD",
|
|
"Sega Master System": "segaMS",
|
|
"Sega CD": "segaCD",
|
|
"Atari Lynx": "lynx",
|
|
"Sega 32X": "sega32x",
|
|
"Atari Jaguar": "jaguar",
|
|
"Sega Game Gear": "segaGG",
|
|
"Sega Saturn": "segaSaturn",
|
|
"Atari 7800": "atari7800",
|
|
"Atari 2600": "atari2600",
|
|
"Arcade": "arcade",
|
|
"NEC TurboGrafx-16/SuperGrafx/PC Engine": "pce",
|
|
"NEC PC-FX": "pcfx",
|
|
"SNK NeoGeo Pocket (Color)": "ngp",
|
|
"Bandai WonderSwan (Color)": "ws",
|
|
"ColecoVision": "coleco",
|
|
"Commodore 64": "vice_x64sc",
|
|
"Commodore 128": "vice_x128",
|
|
"Commodore VIC20": "vice_xvic",
|
|
"Commodore Plus/4": "vice_xplus4",
|
|
"Commodore PET": "vice_xpet",
|
|
"Amiga": "puae"
|
|
}
|
|
|
|
if (enableThreads) {
|
|
coreValues["DOSBOX-PURE"] = "dosbox_pure";
|
|
coreValues["PlayStation Portable"] = "ppsspp";
|
|
}
|
|
|
|
for (let core in coreValues) {
|
|
if (core.toLowerCase() === ext) {
|
|
resolve(core)
|
|
}
|
|
}
|
|
|
|
const cores = Object.keys(coreValues).sort().reduce(
|
|
(obj, key) => {
|
|
obj[key] = coreValues[key];
|
|
return obj;
|
|
},
|
|
{}
|
|
);
|
|
|
|
const button = document.createElement("button")
|
|
const select = document.createElement("select")
|
|
|
|
for (const type in cores) {
|
|
const option = document.createElement("option")
|
|
|
|
option.value = cores[type]
|
|
option.textContent = type
|
|
select.appendChild(option)
|
|
}
|
|
|
|
button.onclick = () => resolve(select[select.selectedIndex].value)
|
|
button.textContent = "Load game"
|
|
box.innerHTML = ""
|
|
|
|
box.appendChild(select)
|
|
box.appendChild(button)
|
|
})
|
|
})(parts.pop())
|
|
|
|
const div = document.createElement("div")
|
|
const sub = document.createElement("div")
|
|
const script = document.createElement("script")
|
|
|
|
sub.id = "game"
|
|
div.id = "display"
|
|
|
|
const top = document.getElementById("top");
|
|
top.remove();
|
|
box.remove();
|
|
div.appendChild(sub);
|
|
advanced.remove();
|
|
document.body.appendChild(div)
|
|
|
|
window.EJS_player = "#game";
|
|
window.EJS_gameName = parts.shift();
|
|
window.EJS_biosUrl = biosUrl;
|
|
window.EJS_gameUrl = url;
|
|
// window.EJS_gameUrl = "smb.zip";
|
|
window.EJS_core = core;
|
|
window.EJS_pathtodata = "data/";
|
|
window.EJS_startOnLoaded = true;
|
|
window.EJS_DEBUG_XX = enableDebug;
|
|
window.EJS_threads = enableThreads;
|
|
if (browserMode) {
|
|
window.EJS_browserMode = browserMode;
|
|
}
|
|
window.EJS_cacheConfig = {
|
|
enabled: true,
|
|
cacheMaxSizeMB: 4096,
|
|
cacheMaxAgeMins: 7200
|
|
};
|
|
|
|
script.src = "data/loader.js";
|
|
document.body.appendChild(script);
|
|
}
|
|
|
|
input.onchange = async () => {
|
|
run(true);
|
|
}
|
|
|
|
box.ondragover = () => box.setAttribute("drag", true);
|
|
box.ondragleave = () => box.removeAttribute("drag");
|
|
</script>
|
|
</body>
|
|
</html>
|