extension: Make the player page a local Ruffle demo
This commit is contained in:
parent
a11725c27c
commit
e7df6d890e
|
@ -540,7 +540,7 @@ export interface DataLoadOptions extends BaseLoadOptions {
|
||||||
/**
|
/**
|
||||||
* The data to load a movie from.
|
* The data to load a movie from.
|
||||||
*/
|
*/
|
||||||
data: Iterable<number>;
|
data: ArrayLike<number> | ArrayBufferLike;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the SWF movie to provide to ActionScript.
|
* The filename of the SWF movie to provide to ActionScript.
|
||||||
|
|
|
@ -150,7 +150,7 @@ export class RufflePlayer extends HTMLElement {
|
||||||
private contextMenuSupported = false;
|
private contextMenuSupported = false;
|
||||||
|
|
||||||
// The effective config loaded upon `.load()`.
|
// The effective config loaded upon `.load()`.
|
||||||
private loadedConfig?: URLLoadOptions | DataLoadOptions;
|
public loadedConfig?: URLLoadOptions | DataLoadOptions;
|
||||||
|
|
||||||
private swfUrl?: URL;
|
private swfUrl?: URL;
|
||||||
private instance: Ruffle | null;
|
private instance: Ruffle | null;
|
||||||
|
|
|
@ -77,6 +77,9 @@
|
||||||
"action_reload": {
|
"action_reload": {
|
||||||
"message": "Reload tab to apply changes"
|
"message": "Reload tab to apply changes"
|
||||||
},
|
},
|
||||||
|
"open_player_page": {
|
||||||
|
"message": "Open SWF Player"
|
||||||
|
},
|
||||||
"open_settings_page": {
|
"open_settings_page": {
|
||||||
"message": "Open Settings Page"
|
"message": "Open Settings Page"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,199 @@
|
||||||
|
:root {
|
||||||
|
--ruffle-blue: #37528c;
|
||||||
|
--ruffle-orange: #ffad33;
|
||||||
|
--splash-screen-background: #31497d;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-family: Lato, sans-serif;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
border: 8px dashed var(--ruffle-orange);
|
||||||
|
border-radius: 30px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-in;
|
||||||
|
margin: 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#overlay.drag {
|
||||||
|
opacity: 1;
|
||||||
|
transition-timing-function: ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
#player {
|
#player {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--ruffle-blue);
|
||||||
|
box-shadow: 0 3px 6px 5px var(--ruffle-blue);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 0 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title:hover {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title img {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-picker select,
|
||||||
|
#file-picker input,
|
||||||
|
#author {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local-file-container,
|
||||||
|
#sample-swfs-container {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local-file {
|
||||||
|
width: 0;
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local-file-label {
|
||||||
|
color: var(--ruffle-blue);
|
||||||
|
padding: 3px 10px;
|
||||||
|
margin: 5px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 50px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local-file-name {
|
||||||
|
min-width: 150px;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sample-swfs {
|
||||||
|
background-color: white;
|
||||||
|
color: var(--ruffle-blue);
|
||||||
|
border: 1px solid white;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#author-container {
|
||||||
|
font-size: small;
|
||||||
|
}
|
||||||
|
|
||||||
|
#author {
|
||||||
|
color: var(--ruffle-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background-color: var(--ruffle-blue);
|
||||||
|
margin: 15vh auto;
|
||||||
|
padding: 20px;
|
||||||
|
border: 2px solid white;
|
||||||
|
width: 300px;
|
||||||
|
height: 270px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
color: #aaa;
|
||||||
|
float: right;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#open-modal,
|
||||||
|
#reload-swf {
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#metadata {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#metadata td {
|
||||||
|
padding: 2px 1px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
color: var(--ruffle-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
#metadata tr td:nth-child(1) {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 800px) {
|
||||||
|
#local-file-container,
|
||||||
|
#sample-swfs-container {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local-file-container {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (width <= 600px) {
|
||||||
|
#local-file-static-label,
|
||||||
|
#sample-swfs-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#author-container {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav {
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,86 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Ruffle</title>
|
<title>Ruffle Player</title>
|
||||||
<link rel="icon" type="image/png" href="images/icon32.png" />
|
<link rel="icon" type="image/png" href="images/icon32.png" />
|
||||||
<link rel="stylesheet" href="css/player.css" />
|
<link rel="stylesheet" href="css/player.css" />
|
||||||
|
<link rel="stylesheet" href="css/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="main"></div>
|
<div id="nav">
|
||||||
|
<div id="title">
|
||||||
|
<a href="https://ruffle.rs/" target="_blank">
|
||||||
|
<img
|
||||||
|
src="images/logo.svg"
|
||||||
|
alt="Ruffle"
|
||||||
|
data-canonical-src="https://ruffle.rs/assets/logo.svg" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="file-picker">
|
||||||
|
<div id="local-file-container">
|
||||||
|
<span id="local-file-static-label">Local SWF:</span>
|
||||||
|
<input type="file" accept=".swf,.spl" id="local-file"
|
||||||
|
aria-describedby="local-file-static-label" />
|
||||||
|
<label for="local-file" id="local-file-label">Select File</label>
|
||||||
|
<span id="local-file-name">No file selected.</span>
|
||||||
|
</div>
|
||||||
|
<div id="sample-swfs-container">
|
||||||
|
<label for="webURL">Web URL: </label>
|
||||||
|
<input id="webURL" name="webURL" type="text" placeholder="URL of a .swf file on the web">
|
||||||
|
<button type="submit" id="webFormSubmit">Load</button>
|
||||||
|
</div>
|
||||||
|
 
|
||||||
|
<svg width="20px" id="open-modal" viewBox="0 0 416.979 416.979"><path fill="white" d="M356.004 61.156c-81.37-81.47-213.377-81.551-294.848-.182-81.47 81.371-81.552 213.379-.181 294.85 81.369 81.47 213.378 81.551 294.849.181 81.469-81.369 81.551-213.379.18-294.849zM237.6 340.786a5.821 5.821 0 0 1-5.822 5.822h-46.576a5.821 5.821 0 0 1-5.822-5.822V167.885a5.821 5.821 0 0 1 5.822-5.822h46.576a5.82 5.82 0 0 1 5.822 5.822v172.901zm-29.11-202.885c-18.618 0-33.766-15.146-33.766-33.765 0-18.617 15.147-33.766 33.766-33.766s33.766 15.148 33.766 33.766c0 18.619-15.149 33.765-33.766 33.765z"/></g></svg>
|
||||||
|
 
|
||||||
|
<svg id="reload-swf" width="20px" viewBox="0 0 489.711 489.711"><path fill="white" d="M112.156 97.111c72.3-65.4 180.5-66.4 253.8-6.7l-58.1 2.2c-7.5.3-13.3 6.5-13 14 .3 7.3 6.3 13 13.5 13h.5l89.2-3.3c7.3-.3 13-6.2 13-13.5v-1.6l-3.3-88.2c-.3-7.5-6.6-13.3-14-13-7.5.3-13.3 6.5-13 14l2.1 55.3c-36.3-29.7-81-46.9-128.8-49.3-59.2-3-116.1 17.3-160 57.1-60.4 54.7-86 137.9-66.8 217.1 1.5 6.2 7 10.3 13.1 10.3 1.1 0 2.1-.1 3.2-.4 7.2-1.8 11.7-9.1 9.9-16.3-16.8-69.6 5.6-142.7 58.7-190.7zm350.3 98.4c-1.8-7.2-9.1-11.7-16.3-9.9-7.2 1.8-11.7 9.1-9.9 16.3 16.9 69.6-5.6 142.7-58.7 190.7-37.3 33.7-84.1 50.3-130.7 50.3-44.5 0-88.9-15.1-124.7-44.9l58.8-5.3c7.4-.7 12.9-7.2 12.2-14.7s-7.2-12.9-14.7-12.2l-88.9 8c-7.4.7-12.9 7.2-12.2 14.7l8 88.9c.6 7 6.5 12.3 13.4 12.3.4 0 .8 0 1.2-.1 7.4-.7 12.9-7.2 12.2-14.7l-4.8-54.1c36.3 29.4 80.8 46.5 128.3 48.9 3.8.2 7.6.3 11.3.3 55.1 0 107.5-20.2 148.7-57.4 60.4-54.7 86-137.8 66.8-217.1z"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="main" aria-label="Select a demo or drag an SWF">
|
||||||
|
<div id="overlay" class="hidden"></div>
|
||||||
|
</div>
|
||||||
|
<div id="metadata-modal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<span class="close" id="close-modal">×</span>
|
||||||
|
<table id="metadata">
|
||||||
|
<tr>
|
||||||
|
<td>Uncompressed Length</td>
|
||||||
|
<td><span class="metadata" id="uncompressedLength">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SWF Version</td>
|
||||||
|
<td><span class="metadata" id="swfVersion">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>FP Version</td>
|
||||||
|
<td><span class="metadata" id="flashVersion">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>ActionScript 3</td>
|
||||||
|
<td><span class="metadata" id="isActionScript3">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total Frames</td>
|
||||||
|
<td><span class="metadata" id="numFrames">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Frame Rate</td>
|
||||||
|
<td><span class="metadata" id="frameRate">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SWF Width</td>
|
||||||
|
<td><span class="metadata" id="width">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SWF Height</td>
|
||||||
|
<td><span class="metadata" id="height">Loading</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>SWF Background Color</td>
|
||||||
|
<td><input class="metadata" type="color" id="backgroundColor" disabled value="#FFFFFF"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script src="dist/player.js"></script>
|
<script src="dist/player.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="version-text">Ruffle extension</div>
|
<div id="version-text">Ruffle extension</div>
|
||||||
<button id="options-button">Settings</button>
|
<button id="options-button">Settings</button>
|
||||||
|
<button id="player-button">Open SWF Player</button>
|
||||||
<button id="reload-button" disabled>Reload</button>
|
<button id="reload-button" disabled>Reload</button>
|
||||||
<script src="dist/popup.js"></script>
|
<script src="dist/popup.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -1,19 +1,230 @@
|
||||||
import * as utils from "./utils";
|
import * as utils from "./utils";
|
||||||
import { PublicAPI } from "ruffle-core";
|
import { PublicAPI } from "ruffle-core";
|
||||||
import type { Letterbox } from "ruffle-core";
|
import type {
|
||||||
|
Letterbox,
|
||||||
|
RufflePlayer,
|
||||||
|
DataLoadOptions,
|
||||||
|
URLLoadOptions,
|
||||||
|
} from "ruffle-core";
|
||||||
|
|
||||||
const api = PublicAPI.negotiate(window.RufflePlayer!, "local");
|
const api = PublicAPI.negotiate(window.RufflePlayer!, "local");
|
||||||
window.RufflePlayer = api;
|
window.RufflePlayer = api;
|
||||||
const ruffle = api.newest()!;
|
const ruffle = api.newest()!;
|
||||||
|
let player: RufflePlayer;
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", async () => {
|
const main = document.getElementById("main")!;
|
||||||
const url = new URL(window.location.href);
|
const overlay = document.getElementById("overlay")!;
|
||||||
// Hash always starts with #, gotta slice that off
|
const localFileInput = document.getElementById(
|
||||||
const swfUrl = url.hash.length > 1 ? url.hash.slice(1) : null;
|
"local-file",
|
||||||
if (!swfUrl) {
|
)! as HTMLInputElement;
|
||||||
|
const localFileName = document.getElementById("local-file-name")!;
|
||||||
|
const closeModal = document.getElementById("close-modal")!;
|
||||||
|
const openModal = document.getElementById("open-modal")!;
|
||||||
|
const reloadSwf = document.getElementById("reload-swf")!;
|
||||||
|
const metadataModal = document.getElementById("metadata-modal")!;
|
||||||
|
|
||||||
|
// Default config used by the player.
|
||||||
|
const defaultConfig = {
|
||||||
|
letterbox: "on" as Letterbox,
|
||||||
|
forceScale: true,
|
||||||
|
forceAlign: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const swfToFlashVersion: { [key: number]: string } = {
|
||||||
|
1: "1",
|
||||||
|
2: "2",
|
||||||
|
3: "3",
|
||||||
|
4: "4",
|
||||||
|
5: "5",
|
||||||
|
6: "6",
|
||||||
|
7: "7",
|
||||||
|
8: "8",
|
||||||
|
9: "9.0",
|
||||||
|
10: "10.0/10.1",
|
||||||
|
11: "10.2",
|
||||||
|
12: "10.3",
|
||||||
|
13: "11.0",
|
||||||
|
14: "11.1",
|
||||||
|
15: "11.2",
|
||||||
|
16: "11.3",
|
||||||
|
17: "11.4",
|
||||||
|
18: "11.5",
|
||||||
|
19: "11.6",
|
||||||
|
20: "11.7",
|
||||||
|
21: "11.8",
|
||||||
|
22: "11.9",
|
||||||
|
23: "12",
|
||||||
|
24: "13",
|
||||||
|
25: "14",
|
||||||
|
26: "15",
|
||||||
|
27: "16",
|
||||||
|
28: "17",
|
||||||
|
29: "18",
|
||||||
|
30: "19",
|
||||||
|
31: "20",
|
||||||
|
32: "21",
|
||||||
|
33: "22",
|
||||||
|
34: "23",
|
||||||
|
35: "24",
|
||||||
|
36: "25",
|
||||||
|
37: "26",
|
||||||
|
38: "27",
|
||||||
|
39: "28",
|
||||||
|
40: "29",
|
||||||
|
41: "30",
|
||||||
|
42: "31",
|
||||||
|
43: "32",
|
||||||
|
};
|
||||||
|
|
||||||
|
function unload() {
|
||||||
|
if (player) {
|
||||||
|
player.remove();
|
||||||
|
document.querySelectorAll("span.metadata").forEach((el) => {
|
||||||
|
el.textContent = "Loading";
|
||||||
|
});
|
||||||
|
(
|
||||||
|
document.getElementById("backgroundColor")! as HTMLInputElement
|
||||||
|
).value = "#FFFFFF";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(options: string | DataLoadOptions | URLLoadOptions) {
|
||||||
|
unload();
|
||||||
|
player = ruffle.createPlayer();
|
||||||
|
player.id = "player";
|
||||||
|
main.append(player);
|
||||||
|
player.load(options);
|
||||||
|
player.addEventListener("loadedmetadata", function () {
|
||||||
|
if (player.metadata) {
|
||||||
|
for (const [key, value] of Object.entries(player.metadata)) {
|
||||||
|
const metadataElement = document.getElementById(key);
|
||||||
|
if (metadataElement) {
|
||||||
|
switch (key) {
|
||||||
|
case "backgroundColor":
|
||||||
|
(metadataElement as HTMLInputElement).value =
|
||||||
|
value ?? "#FFFFFF";
|
||||||
|
break;
|
||||||
|
case "uncompressedLength":
|
||||||
|
metadataElement.textContent = `${value >> 10}Kb`;
|
||||||
|
break;
|
||||||
|
// @ts-expect-error This intentionally falls through to the default case
|
||||||
|
case "swfVersion":
|
||||||
|
document.getElementById(
|
||||||
|
"flashVersion",
|
||||||
|
)!.textContent = swfToFlashVersion[value] ?? null;
|
||||||
|
// falls through and executes the default case as well
|
||||||
|
default:
|
||||||
|
metadataElement.textContent = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadFile(file: File | undefined) {
|
||||||
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (file.name) {
|
||||||
|
localFileName.textContent = file.name;
|
||||||
|
}
|
||||||
|
const data = await new Response(file).arrayBuffer();
|
||||||
|
load({ data: data, swfFileName: file.name, ...defaultConfig });
|
||||||
|
history.pushState("", document.title, window.location.pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
localFileInput.addEventListener("change", (event) => {
|
||||||
|
const eventTarget = event.target as HTMLInputElement;
|
||||||
|
if (
|
||||||
|
eventTarget?.files &&
|
||||||
|
eventTarget?.files.length > 0 &&
|
||||||
|
eventTarget.files[0]
|
||||||
|
) {
|
||||||
|
loadFile(eventTarget.files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
main.addEventListener("dragenter", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
main.addEventListener("dragleave", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.remove("drag");
|
||||||
|
});
|
||||||
|
main.addEventListener("dragover", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.add("drag");
|
||||||
|
});
|
||||||
|
main.addEventListener("drop", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.remove("drag");
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
localFileInput.files = event.dataTransfer.files;
|
||||||
|
loadFile(event.dataTransfer.files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
localFileInput.addEventListener("dragleave", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.remove("drag");
|
||||||
|
});
|
||||||
|
localFileInput.addEventListener("dragover", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.add("drag");
|
||||||
|
});
|
||||||
|
localFileInput.addEventListener("drop", (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
overlay.classList.remove("drag");
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
localFileInput.files = event.dataTransfer.files;
|
||||||
|
loadFile(event.dataTransfer.files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
closeModal.addEventListener("click", () => {
|
||||||
|
metadataModal.style.display = "none";
|
||||||
|
});
|
||||||
|
|
||||||
|
openModal.addEventListener("click", () => {
|
||||||
|
metadataModal.style.display = "block";
|
||||||
|
});
|
||||||
|
|
||||||
|
reloadSwf.addEventListener("click", () => {
|
||||||
|
if (player) {
|
||||||
|
const confirmReload = confirm("Reload the current SWF?");
|
||||||
|
if (confirmReload) {
|
||||||
|
if (player.loadedConfig) {
|
||||||
|
player.load(player.loadedConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
if (
|
||||||
|
navigator.userAgent.match(/iPad/i) ||
|
||||||
|
navigator.userAgent.match(/iPhone/i)
|
||||||
|
) {
|
||||||
|
localFileInput.removeAttribute("accept");
|
||||||
|
}
|
||||||
|
overlay.classList.remove("hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
window.onclick = (event) => {
|
||||||
|
if (event.target === metadataModal) {
|
||||||
|
metadataModal.style.display = "none";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function loadSwf(swfUrl: string) {
|
||||||
try {
|
try {
|
||||||
const pathname = new URL(swfUrl).pathname;
|
const pathname = new URL(swfUrl).pathname;
|
||||||
document.title = pathname.substring(pathname.lastIndexOf("/") + 1);
|
document.title = pathname.substring(pathname.lastIndexOf("/") + 1);
|
||||||
|
@ -21,19 +232,39 @@ window.addEventListener("DOMContentLoaded", async () => {
|
||||||
// Ignore URL parsing errors.
|
// Ignore URL parsing errors.
|
||||||
}
|
}
|
||||||
|
|
||||||
const player = ruffle.createPlayer();
|
|
||||||
player.id = "player";
|
|
||||||
document.getElementById("main")!.append(player);
|
|
||||||
|
|
||||||
const options = await utils.getExplicitOptions();
|
const options = await utils.getExplicitOptions();
|
||||||
|
localFileName.textContent = document.title;
|
||||||
player.load({
|
localFileInput.value = "";
|
||||||
|
load({
|
||||||
...options,
|
...options,
|
||||||
url: swfUrl,
|
url: swfUrl,
|
||||||
base: swfUrl.substring(0, swfUrl.lastIndexOf("/") + 1),
|
base: swfUrl.substring(0, swfUrl.lastIndexOf("/") + 1),
|
||||||
// Override some default values when playing in the extension player page.
|
...defaultConfig,
|
||||||
letterbox: "on" as Letterbox,
|
|
||||||
forceAlign: true,
|
|
||||||
forceScale: true,
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("pageshow", async () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
// Hash always starts with #, gotta slice that off
|
||||||
|
const swfUrl = url.hash.length > 1 ? url.hash.slice(1) : null;
|
||||||
|
if (swfUrl) {
|
||||||
|
await loadSwf(swfUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", async () => {
|
||||||
|
const webFormSubmit = document.getElementById(
|
||||||
|
"webFormSubmit",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
if (webFormSubmit) {
|
||||||
|
webFormSubmit.addEventListener("click", function () {
|
||||||
|
const webURL = document.getElementById(
|
||||||
|
"webURL",
|
||||||
|
) as HTMLInputElement;
|
||||||
|
if ((webURL?.value || "") !== "") {
|
||||||
|
loadSwf(webURL.value);
|
||||||
|
window.location.href = "#" + webURL.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -170,6 +170,15 @@ window.addEventListener("DOMContentLoaded", () => {
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const playerButton = document.getElementById(
|
||||||
|
"player-button",
|
||||||
|
) as HTMLButtonElement;
|
||||||
|
playerButton.textContent = utils.i18n.getMessage("open_player_page");
|
||||||
|
playerButton.addEventListener("click", async () => {
|
||||||
|
await utils.openPlayerPage();
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
|
|
||||||
reloadButton = document.getElementById(
|
reloadButton = document.getElementById(
|
||||||
"reload-button",
|
"reload-button",
|
||||||
) as HTMLButtonElement;
|
) as HTMLButtonElement;
|
||||||
|
|
|
@ -63,6 +63,7 @@ export let runtime: {
|
||||||
};
|
};
|
||||||
|
|
||||||
export let openOptionsPage: () => Promise<void>;
|
export let openOptionsPage: () => Promise<void>;
|
||||||
|
export let openPlayerPage: () => Promise<void>;
|
||||||
|
|
||||||
function promisify<T>(
|
function promisify<T>(
|
||||||
func: (callback: (result: T) => void) => void,
|
func: (callback: (result: T) => void) => void,
|
||||||
|
@ -129,12 +130,20 @@ if (typeof chrome !== "undefined") {
|
||||||
promisify((cb: () => void) =>
|
promisify((cb: () => void) =>
|
||||||
chrome.tabs.create({ url: "/options.html" }, cb),
|
chrome.tabs.create({ url: "/options.html" }, cb),
|
||||||
);
|
);
|
||||||
|
openPlayerPage = () =>
|
||||||
|
promisify((_cb: () => void) =>
|
||||||
|
chrome.tabs.create({ url: "/player.html" }),
|
||||||
|
);
|
||||||
} else if (typeof browser !== "undefined") {
|
} else if (typeof browser !== "undefined") {
|
||||||
i18n = browser.i18n;
|
i18n = browser.i18n;
|
||||||
storage = browser.storage;
|
storage = browser.storage;
|
||||||
tabs = browser.tabs;
|
tabs = browser.tabs;
|
||||||
runtime = browser.runtime;
|
runtime = browser.runtime;
|
||||||
openOptionsPage = () => browser.runtime.openOptionsPage();
|
openOptionsPage = () => browser.runtime.openOptionsPage();
|
||||||
|
openPlayerPage = () =>
|
||||||
|
promisify((_cb: () => void) =>
|
||||||
|
browser.tabs.create({ url: "/player.html" }),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Extension API not found.");
|
throw new Error("Extension API not found.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue