Having the dropdowns in one spot and the options for each of them in another spot is just weird and unnecessary
466 lines
14 KiB
HTML
466 lines
14 KiB
HTML
<!--
|
|
Copyright (c) 2020 Thomas Weber
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
-->
|
|
|
|
<!DOCTYPE html>
|
|
<html>
|
|
|
|
<head>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
|
background-color: #eee;
|
|
}
|
|
h1, h2, h3, h4, h5, h6 {
|
|
font-weight: 400;
|
|
}
|
|
h1 {
|
|
font-size: 2em;
|
|
}
|
|
h2 {
|
|
font-size: 1.5em;
|
|
margin: 0.5em 0 1em 0;
|
|
}
|
|
body.loaded .show-loading {
|
|
display: none;
|
|
}
|
|
body:not(.loaded) .hide-loading {
|
|
display: none !important;
|
|
}
|
|
.card {
|
|
max-width: 500px;
|
|
margin: auto;
|
|
border-radius: 0.3em;
|
|
background-color: #fff;
|
|
padding: 1em;
|
|
margin-top: 1em;
|
|
margin-bottom: 1.2em;
|
|
box-shadow: 0 0 0.5em 0.1em rgba(0, 0, 0, 0.4);
|
|
}
|
|
.center {
|
|
text-align: center;
|
|
}
|
|
|
|
textarea {
|
|
width: 100%;
|
|
height: 120px;
|
|
box-sizing: border-box;
|
|
resize: none;
|
|
}
|
|
|
|
#progress-container {
|
|
margin: auto;
|
|
position: relative;
|
|
width: 250px;
|
|
height: 7px;
|
|
border: 1px solid currentColor;
|
|
}
|
|
#progress-bar {
|
|
position: absolute;
|
|
background-color: currentColor;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
}
|
|
body:not(.running) #progress-container {
|
|
display: none;
|
|
}
|
|
#status, #download {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 40px;
|
|
text-align: center;
|
|
}
|
|
#status-text {
|
|
font-style: italic;
|
|
}
|
|
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
body {
|
|
background: #111;
|
|
color: #ddd;
|
|
}
|
|
a {
|
|
color: #4af;
|
|
}
|
|
.card {
|
|
background-color: rgb(29, 29, 29);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<section class="card">
|
|
<h1>The new packager</h1>
|
|
|
|
<p>This is the new packager for forkphorus & TurboWarp. p3 is a temporary name until something better can be thought of.</p>
|
|
</section>
|
|
|
|
<section class="show-loading card center">
|
|
<i>Loading...</i>
|
|
</section>
|
|
|
|
<section class="hide-loading card">
|
|
<h2>Select project</h2>
|
|
|
|
<div>
|
|
<label>
|
|
<input name="project.source" type="radio" value="id" checked>
|
|
Project ID
|
|
</label>
|
|
<label>
|
|
<input name="project.source" type="radio" value="file">
|
|
Project File
|
|
</label>
|
|
</div>
|
|
|
|
<div if="O.project.source === 'id'" class="fold">
|
|
<label>
|
|
Project ID or URL:
|
|
<input name="project.id" type="text">
|
|
</label>
|
|
</div>
|
|
|
|
<div if="O.project.source === 'file'" class="fold">
|
|
<label>
|
|
Project File:
|
|
<input name="project.file" type="file" accept=".sb,.sb2,.sb3">
|
|
</label>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
<section class="hide-loading card">
|
|
<h2>Runtime</h2>
|
|
|
|
<div>
|
|
<label>
|
|
Runtime
|
|
<select name="runtime.name">
|
|
<option value="turbowarp">TurboWarp</option>
|
|
<option value="forkphorus">forkphorus</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<div if="O.runtime.name === 'turbowarp'" class="fold">
|
|
<h2>TurboWarp options</h2>
|
|
|
|
<p>TurboWarp currently does not support any options.</p>
|
|
</div>
|
|
|
|
<div if="O.runtime.name === 'forkphorus'" class="fold">
|
|
<h2>forkphorus options</h2>
|
|
|
|
<div>
|
|
<label>
|
|
Turbo Mode
|
|
<input name="forkphorus.playerOptions.turbo" type="checkbox">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Show Controls
|
|
<input name="forkphorus.showControls" type="checkbox">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Username
|
|
<input name="forkphorus.playerOptions.username" type="text">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Autoplay
|
|
<select name="forkphorus.playerOptions.autoplayPolicy">
|
|
<option value="always" selected>Always</option>
|
|
<option value="never">Never</option>
|
|
<option value="if-audio-playable">If audio can be played</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Framerate
|
|
<input name="forkphorus.playerOptions.framerate" value="30" type="number">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Loading Screen Text
|
|
<input name="forkphorus.loadingScreenText" value="forkphorus">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Cloud Variables
|
|
<select name="forkphorus.playerOptions.cloudVariables">
|
|
<option value="off">Off</option>
|
|
<option value="ws" disabled>Connect to forkphorus clouddata server</option>
|
|
<option value="localStorage" selected>Store locally</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
Sprite Fencing
|
|
<input name="forkphorus.playerOptions.spriteFencing" type="checkbox">
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="hide-loading card">
|
|
<h2>Environment</h2>
|
|
|
|
<div>
|
|
<label>
|
|
Environment
|
|
<select name="environment.name">
|
|
<option value="html">Plain HTML (Standalone)</option>
|
|
<option value="zip">Zip</option>
|
|
<option value="nwjs-win64">NW.js (Windows x64)</option>
|
|
<option value="nwjs-mac">NW.js (Mac)</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<div if="O.environment.name === 'html'" class="fold">
|
|
<h2>Plain HTML Options</h2>
|
|
<p>No options.</p>
|
|
</div>
|
|
|
|
<div if="O.environment.name === 'zip'" class="fold">
|
|
<h2>Zip Options</h2>
|
|
<p>No options.</p>
|
|
</div>
|
|
|
|
<div if="O.environment.name.startsWith('nw')" class="fold">
|
|
<h2>NW.js Options</h2>
|
|
|
|
<div>
|
|
<label>
|
|
Icon
|
|
<input name="nwjs.icon" type="file" accept=".png">
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label>
|
|
package.json
|
|
<br>
|
|
<textarea name="nwjs.manifest">{
|
|
"name": "Name of the project",
|
|
"main": "project.html",
|
|
"window": {
|
|
"title": "The title of the window",
|
|
"width": 480,
|
|
"height": 360,
|
|
"resizable": true,
|
|
"icon": "icon.png"
|
|
}
|
|
}</textarea>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="hide-loading card">
|
|
<button id="package">Package</button>
|
|
</section>
|
|
|
|
<section id="download" if="O.showDownload" class="hide-loading card">
|
|
<!-- Download links will be inserted here -->
|
|
</section>
|
|
|
|
<section id="status" if="!O.showDownload" class="hide-loading card">
|
|
<div>
|
|
<div id="progress-container">
|
|
<div id="progress-bar"></div>
|
|
</div>
|
|
<div id="status-text">Status updates will appear here.</div>
|
|
</div>
|
|
</section>
|
|
|
|
<script src="lib/jszip.min.js"></script>
|
|
<script src="lib/icns.js"></script>
|
|
<script src="conditionals.js"></script>
|
|
<script src="downloader.js"></script>
|
|
<script src="parseoptions.js"></script>
|
|
<script src="packager.js"></script>
|
|
|
|
<script>
|
|
(function() {
|
|
document.body.classList.add('loaded');
|
|
|
|
O.onchange = () => {
|
|
Conditionals.update();
|
|
};
|
|
Conditionals.setup();
|
|
|
|
let totalAssets = 0;
|
|
let finishedAssets = 0;
|
|
|
|
const progressTarget = new EventTarget();
|
|
progressTarget.addEventListener('data-progress', (e) => {
|
|
totalAssets = 0;
|
|
finishedAssets = 0;
|
|
setProgress('Loading project data', e.detail);
|
|
});
|
|
progressTarget.addEventListener('asset-fetch', (e) => {
|
|
totalAssets++;
|
|
setProgress('Loading assets', finishedAssets / totalAssets);
|
|
});
|
|
progressTarget.addEventListener('asset-fetched', (e) => {
|
|
finishedAssets++;
|
|
setProgress('Loading assets', finishedAssets / totalAssets);
|
|
});
|
|
progressTarget.addEventListener('nwjs-progress', (e) => setProgress('Loading NW.js', e.detail));
|
|
|
|
const statusText = document.querySelector('#status-text');
|
|
statusText.initialText = statusText.textContent;
|
|
const downloadContainer = document.querySelector('#download');
|
|
const progressBar = document.querySelector('#progress-bar');
|
|
|
|
const loadProject = async () => {
|
|
if (O.project.source === 'file') {
|
|
if (!O.project.file) {
|
|
throw new Error('No file selected');
|
|
}
|
|
// File is a Blob
|
|
return new Packager.Project(O.project.file, await SBDownloader.identifyProjectType(O.project.file));
|
|
} else if (O.project.source === 'id') {
|
|
const match = O.project.id.match(/\d+/);
|
|
if (!match) {
|
|
throw new Error('Invalid project ID');
|
|
}
|
|
const project = await SBDownloader.download(match[0], {
|
|
progressTarget
|
|
});
|
|
return new Packager.Project(await project.asBlob(), project.type);
|
|
}
|
|
throw new Error('unknown project source');
|
|
};
|
|
|
|
const getRuntime = async (projectType) => {
|
|
switch (O.runtime.name) {
|
|
case 'turbowarp': return new Packager.runtimes.TurboWarp();
|
|
case 'forkphorus': return new Packager.runtimes.Forkphorus({
|
|
playerOptions: {
|
|
...O.forkphorus.playerOptions,
|
|
fullscreenMode: 'window',
|
|
fullscreenPadding: 0,
|
|
},
|
|
controlsOptions: O.forkphorus.showControls ? { enableFullscreen: false } : null,
|
|
loadingScreenText: O.forkphorus.loadingScreenText,
|
|
projectType: projectType,
|
|
});
|
|
}
|
|
throw new Error('unknown environment');
|
|
};
|
|
|
|
const getDefaultIcon = () => fetch('default-icon.png')
|
|
.then((r) => r.blob());
|
|
|
|
const getEnvironment = async () => {
|
|
switch (O.environment.name) {
|
|
case 'html': return new Packager.environments.HTML();
|
|
case 'zip': return new Packager.environments.Zip();
|
|
case 'nwjs-win64':
|
|
case 'nwjs-mac':
|
|
return new Packager.environments.NWjs({
|
|
icon: O.nwjs.icon || await getDefaultIcon(),
|
|
manifest: O.nwjs.manifest,
|
|
platform: O.environment.name.substr('nwjs-'.length),
|
|
});
|
|
}
|
|
throw new Error('unknown environment');
|
|
};
|
|
|
|
const addDownloadLink = (blob, fileName) => {
|
|
O.showDownload = true;
|
|
const link = document.createElement('a');
|
|
const size = blob.size / 1024 / 1024;
|
|
link.href = URL.createObjectURL(blob);
|
|
link.textContent = `Download ${fileName} (${size.toFixed(2)} MiB)`;
|
|
link.download = fileName;
|
|
downloadContainer.appendChild(link);
|
|
link.click();
|
|
Conditionals.update();
|
|
};
|
|
|
|
const resetDownloads = () => {
|
|
O.showDownload = false;
|
|
let link = downloadContainer.firstChild;
|
|
while (link) {
|
|
if (link.href) {
|
|
URL.revokeObjectURL(link.href);
|
|
}
|
|
downloadContainer.removeChild(link);
|
|
link = downloadContainer.firstChild;
|
|
}
|
|
Conditionals.update();
|
|
};
|
|
|
|
const setProgress = (status, progress) => {
|
|
if (status !== setProgress.lastStatus) {
|
|
statusText.textContent = status;
|
|
}
|
|
progressBar.style.width = `${progress * 100}%`;
|
|
};
|
|
setProgress.lastStatus = statusText.initialText;
|
|
|
|
const resetProgress = () => {
|
|
setProgress(statusText.initialText, 0);
|
|
};
|
|
|
|
document.getElementById('package').addEventListener('click', async function() {
|
|
try {
|
|
document.body.classList.add('running');
|
|
resetDownloads();
|
|
setProgress('Loading', 0);
|
|
const runtime = await getRuntime();
|
|
const environment = await getEnvironment();
|
|
const projectData = await loadProject();
|
|
environment.setRuntime(runtime);
|
|
environment.setProgressTarget(progressTarget);
|
|
environment.setProjectData(projectData);
|
|
const result = await environment.package();
|
|
if (!(result.data instanceof Blob)) {
|
|
result.data = new Blob([result.data]);
|
|
}
|
|
addDownloadLink(result.data, result.filename);
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert(e);
|
|
} finally {
|
|
document.body.classList.remove('running');
|
|
resetProgress();
|
|
}
|
|
});
|
|
}());
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|