mirror of
https://github.com/rwv/chinese-dos-games-web.git
synced 2024-11-25 16:53:07 +08:00
separate data and website
This commit is contained in:
parent
fd45c1a218
commit
41143b9887
7
.gitignore
vendored
7
.gitignore
vendored
@ -102,3 +102,10 @@ venv.bak/
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# data package/scripts generated by Emscripten
|
||||
scripts.json
|
||||
static/gamedata/
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
[submodule "static/games"]
|
||||
path = static/games
|
||||
url = https://github.com/rwv/chinese-dos-games.git
|
||||
branch = master
|
31
app.py
Normal file
31
app.py
Normal file
@ -0,0 +1,31 @@
|
||||
from flask import Flask
|
||||
from flask import render_template, redirect, url_for
|
||||
|
||||
from game_infos import game_infos
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html', games=game_infos['games'])
|
||||
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
return render_template('about.html', games=game_infos['games'])
|
||||
|
||||
|
||||
@app.route('/games/<identifier>/')
|
||||
def game(identifier):
|
||||
game_info = game_infos["games"][identifier]
|
||||
return render_template('game.html', game_info=game_info)
|
||||
|
||||
|
||||
@app.route('/games/<identifier>/logo/emularity_color_small.png')
|
||||
def emularity_logo(identifier):
|
||||
return redirect(url_for('static', filename='emularity/emularity_color_small.png'), code=301)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
9
game_infos.py
Normal file
9
game_infos.py
Normal file
@ -0,0 +1,9 @@
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
|
||||
root = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
|
||||
|
||||
with open(os.path.join(root, 'static', 'games', 'games.json'), encoding='utf8') as f:
|
||||
content = f.read()
|
||||
game_infos = json.loads(content)
|
155
static/css/main.css
Normal file
155
static/css/main.css
Normal file
@ -0,0 +1,155 @@
|
||||
.emscripten {
|
||||
padding-right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.emscripten {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
|
||||
canvas.emscripten {
|
||||
border: 0px none;
|
||||
background-color: black;
|
||||
width: 100%;
|
||||
image-rendering: auto !important;
|
||||
}
|
||||
|
||||
#emscripten_logo {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: 0;
|
||||
margin-top: 20px;
|
||||
margin-left: 20px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
-webkit-animation: rotation .8s linear infinite;
|
||||
-moz-animation: rotation .8s linear infinite;
|
||||
-o-animation: rotation .8s linear infinite;
|
||||
animation: rotation 0.8s linear infinite;
|
||||
|
||||
border-left: 5px solid rgb(235, 235, 235);
|
||||
border-right: 5px solid rgb(235, 235, 235);
|
||||
border-bottom: 5px solid rgb(235, 235, 235);
|
||||
border-top: 5px solid rgb(120, 120, 120);
|
||||
|
||||
border-radius: 100%;
|
||||
background-color: rgb(189, 215, 46);
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotation {
|
||||
from {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes rotation {
|
||||
from {
|
||||
-moz-transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
-moz-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-o-keyframes rotation {
|
||||
from {
|
||||
-o-transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
-o-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#status {
|
||||
/*display: inline-block;*/
|
||||
vertical-align: top;
|
||||
font-weight: bold;
|
||||
color: rgb(120, 120, 120);
|
||||
|
||||
}
|
||||
|
||||
#progress {
|
||||
height: 20px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.current_save {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.index-card-title-left {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.index-card-title-right {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.grid-item--width2 {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.html-fullscreen {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.exit_fullscreen {
|
||||
position: fixed;
|
||||
right: 1rem;
|
||||
bottom: 1rem;
|
||||
opacity: 0.1;
|
||||
z-index: 3000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.exit_fullscreen_show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.exit_fullscreen_show:hover {
|
||||
opacity: 1;
|
||||
}
|
14
static/emularity/browserfs.min.js
vendored
Normal file
14
static/emularity/browserfs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/emularity/browserfs.min.js.map
Normal file
1
static/emularity/browserfs.min.js.map
Normal file
File diff suppressed because one or more lines are too long
28
static/emularity/dosbox/dosbox-sync.js
Normal file
28
static/emularity/dosbox/dosbox-sync.js
Normal file
File diff suppressed because one or more lines are too long
BIN
static/emularity/dosbox/dosbox-sync.mem
Normal file
BIN
static/emularity/dosbox/dosbox-sync.mem
Normal file
Binary file not shown.
BIN
static/emularity/emularity_color_small.png
Normal file
BIN
static/emularity/emularity_color_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
960
static/emularity/es6-promise.js
Normal file
960
static/emularity/es6-promise.js
Normal file
@ -0,0 +1,960 @@
|
||||
/*!
|
||||
* @overview es6-promise - a tiny implementation of Promises/A+.
|
||||
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
|
||||
* @license Licensed under MIT license
|
||||
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
|
||||
* @version 2.0.0
|
||||
*/
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function $$utils$$objectOrFunction(x) {
|
||||
return typeof x === 'function' || (typeof x === 'object' && x !== null);
|
||||
}
|
||||
|
||||
function $$utils$$isFunction(x) {
|
||||
return typeof x === 'function';
|
||||
}
|
||||
|
||||
function $$utils$$isMaybeThenable(x) {
|
||||
return typeof x === 'object' && x !== null;
|
||||
}
|
||||
|
||||
var $$utils$$_isArray;
|
||||
|
||||
if (!Array.isArray) {
|
||||
$$utils$$_isArray = function (x) {
|
||||
return Object.prototype.toString.call(x) === '[object Array]';
|
||||
};
|
||||
} else {
|
||||
$$utils$$_isArray = Array.isArray;
|
||||
}
|
||||
|
||||
var $$utils$$isArray = $$utils$$_isArray;
|
||||
var $$utils$$now = Date.now || function() { return new Date().getTime(); };
|
||||
function $$utils$$F() { }
|
||||
|
||||
var $$utils$$o_create = (Object.create || function (o) {
|
||||
if (arguments.length > 1) {
|
||||
throw new Error('Second argument not supported');
|
||||
}
|
||||
if (typeof o !== 'object') {
|
||||
throw new TypeError('Argument must be an object');
|
||||
}
|
||||
$$utils$$F.prototype = o;
|
||||
return new $$utils$$F();
|
||||
});
|
||||
|
||||
var $$asap$$len = 0;
|
||||
|
||||
var $$asap$$default = function asap(callback, arg) {
|
||||
$$asap$$queue[$$asap$$len] = callback;
|
||||
$$asap$$queue[$$asap$$len + 1] = arg;
|
||||
$$asap$$len += 2;
|
||||
if ($$asap$$len === 2) {
|
||||
// If len is 1, that means that we need to schedule an async flush.
|
||||
// If additional callbacks are queued before the queue is flushed, they
|
||||
// will be processed by this flush that we are scheduling.
|
||||
$$asap$$scheduleFlush();
|
||||
}
|
||||
};
|
||||
|
||||
var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {};
|
||||
var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver;
|
||||
|
||||
// test for web worker but not in IE10
|
||||
var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
|
||||
typeof importScripts !== 'undefined' &&
|
||||
typeof MessageChannel !== 'undefined';
|
||||
|
||||
// node
|
||||
function $$asap$$useNextTick() {
|
||||
return function() {
|
||||
process.nextTick($$asap$$flush);
|
||||
};
|
||||
}
|
||||
|
||||
function $$asap$$useMutationObserver() {
|
||||
var iterations = 0;
|
||||
var observer = new $$asap$$BrowserMutationObserver($$asap$$flush);
|
||||
var node = document.createTextNode('');
|
||||
observer.observe(node, { characterData: true });
|
||||
|
||||
return function() {
|
||||
node.data = (iterations = ++iterations % 2);
|
||||
};
|
||||
}
|
||||
|
||||
// web worker
|
||||
function $$asap$$useMessageChannel() {
|
||||
var channel = new MessageChannel();
|
||||
channel.port1.onmessage = $$asap$$flush;
|
||||
return function () {
|
||||
channel.port2.postMessage(0);
|
||||
};
|
||||
}
|
||||
|
||||
function $$asap$$useSetTimeout() {
|
||||
return function() {
|
||||
setTimeout($$asap$$flush, 1);
|
||||
};
|
||||
}
|
||||
|
||||
var $$asap$$queue = new Array(1000);
|
||||
|
||||
function $$asap$$flush() {
|
||||
for (var i = 0; i < $$asap$$len; i+=2) {
|
||||
var callback = $$asap$$queue[i];
|
||||
var arg = $$asap$$queue[i+1];
|
||||
|
||||
callback(arg);
|
||||
|
||||
$$asap$$queue[i] = undefined;
|
||||
$$asap$$queue[i+1] = undefined;
|
||||
}
|
||||
|
||||
$$asap$$len = 0;
|
||||
}
|
||||
|
||||
var $$asap$$scheduleFlush;
|
||||
|
||||
// Decide what async method to use to triggering processing of queued callbacks:
|
||||
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
|
||||
$$asap$$scheduleFlush = $$asap$$useNextTick();
|
||||
} else if ($$asap$$BrowserMutationObserver) {
|
||||
$$asap$$scheduleFlush = $$asap$$useMutationObserver();
|
||||
} else if ($$asap$$isWorker) {
|
||||
$$asap$$scheduleFlush = $$asap$$useMessageChannel();
|
||||
} else {
|
||||
$$asap$$scheduleFlush = $$asap$$useSetTimeout();
|
||||
}
|
||||
|
||||
function $$$internal$$noop() {}
|
||||
var $$$internal$$PENDING = void 0;
|
||||
var $$$internal$$FULFILLED = 1;
|
||||
var $$$internal$$REJECTED = 2;
|
||||
var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject();
|
||||
|
||||
function $$$internal$$selfFullfillment() {
|
||||
return new TypeError("You cannot resolve a promise with itself");
|
||||
}
|
||||
|
||||
function $$$internal$$cannotReturnOwn() {
|
||||
return new TypeError('A promises callback cannot return that same promise.')
|
||||
}
|
||||
|
||||
function $$$internal$$getThen(promise) {
|
||||
try {
|
||||
return promise.then;
|
||||
} catch(error) {
|
||||
$$$internal$$GET_THEN_ERROR.error = error;
|
||||
return $$$internal$$GET_THEN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
|
||||
try {
|
||||
then.call(value, fulfillmentHandler, rejectionHandler);
|
||||
} catch(e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$handleForeignThenable(promise, thenable, then) {
|
||||
$$asap$$default(function(promise) {
|
||||
var sealed = false;
|
||||
var error = $$$internal$$tryThen(then, thenable, function(value) {
|
||||
if (sealed) { return; }
|
||||
sealed = true;
|
||||
if (thenable !== value) {
|
||||
$$$internal$$resolve(promise, value);
|
||||
} else {
|
||||
$$$internal$$fulfill(promise, value);
|
||||
}
|
||||
}, function(reason) {
|
||||
if (sealed) { return; }
|
||||
sealed = true;
|
||||
|
||||
$$$internal$$reject(promise, reason);
|
||||
}, 'Settle: ' + (promise._label || ' unknown promise'));
|
||||
|
||||
if (!sealed && error) {
|
||||
sealed = true;
|
||||
$$$internal$$reject(promise, error);
|
||||
}
|
||||
}, promise);
|
||||
}
|
||||
|
||||
function $$$internal$$handleOwnThenable(promise, thenable) {
|
||||
if (thenable._state === $$$internal$$FULFILLED) {
|
||||
$$$internal$$fulfill(promise, thenable._result);
|
||||
} else if (promise._state === $$$internal$$REJECTED) {
|
||||
$$$internal$$reject(promise, thenable._result);
|
||||
} else {
|
||||
$$$internal$$subscribe(thenable, undefined, function(value) {
|
||||
$$$internal$$resolve(promise, value);
|
||||
}, function(reason) {
|
||||
$$$internal$$reject(promise, reason);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$handleMaybeThenable(promise, maybeThenable) {
|
||||
if (maybeThenable.constructor === promise.constructor) {
|
||||
$$$internal$$handleOwnThenable(promise, maybeThenable);
|
||||
} else {
|
||||
var then = $$$internal$$getThen(maybeThenable);
|
||||
|
||||
if (then === $$$internal$$GET_THEN_ERROR) {
|
||||
$$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error);
|
||||
} else if (then === undefined) {
|
||||
$$$internal$$fulfill(promise, maybeThenable);
|
||||
} else if ($$utils$$isFunction(then)) {
|
||||
$$$internal$$handleForeignThenable(promise, maybeThenable, then);
|
||||
} else {
|
||||
$$$internal$$fulfill(promise, maybeThenable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$resolve(promise, value) {
|
||||
if (promise === value) {
|
||||
$$$internal$$reject(promise, $$$internal$$selfFullfillment());
|
||||
} else if ($$utils$$objectOrFunction(value)) {
|
||||
$$$internal$$handleMaybeThenable(promise, value);
|
||||
} else {
|
||||
$$$internal$$fulfill(promise, value);
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$publishRejection(promise) {
|
||||
if (promise._onerror) {
|
||||
promise._onerror(promise._result);
|
||||
}
|
||||
|
||||
$$$internal$$publish(promise);
|
||||
}
|
||||
|
||||
function $$$internal$$fulfill(promise, value) {
|
||||
if (promise._state !== $$$internal$$PENDING) { return; }
|
||||
|
||||
promise._result = value;
|
||||
promise._state = $$$internal$$FULFILLED;
|
||||
|
||||
if (promise._subscribers.length === 0) {
|
||||
} else {
|
||||
$$asap$$default($$$internal$$publish, promise);
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$reject(promise, reason) {
|
||||
if (promise._state !== $$$internal$$PENDING) { return; }
|
||||
promise._state = $$$internal$$REJECTED;
|
||||
promise._result = reason;
|
||||
|
||||
$$asap$$default($$$internal$$publishRejection, promise);
|
||||
}
|
||||
|
||||
function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
|
||||
var subscribers = parent._subscribers;
|
||||
var length = subscribers.length;
|
||||
|
||||
parent._onerror = null;
|
||||
|
||||
subscribers[length] = child;
|
||||
subscribers[length + $$$internal$$FULFILLED] = onFulfillment;
|
||||
subscribers[length + $$$internal$$REJECTED] = onRejection;
|
||||
|
||||
if (length === 0 && parent._state) {
|
||||
$$asap$$default($$$internal$$publish, parent);
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$publish(promise) {
|
||||
var subscribers = promise._subscribers;
|
||||
var settled = promise._state;
|
||||
|
||||
if (subscribers.length === 0) { return; }
|
||||
|
||||
var child, callback, detail = promise._result;
|
||||
|
||||
for (var i = 0; i < subscribers.length; i += 3) {
|
||||
child = subscribers[i];
|
||||
callback = subscribers[i + settled];
|
||||
|
||||
if (child) {
|
||||
$$$internal$$invokeCallback(settled, child, callback, detail);
|
||||
} else {
|
||||
callback(detail);
|
||||
}
|
||||
}
|
||||
|
||||
promise._subscribers.length = 0;
|
||||
}
|
||||
|
||||
function $$$internal$$ErrorObject() {
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject();
|
||||
|
||||
function $$$internal$$tryCatch(callback, detail) {
|
||||
try {
|
||||
return callback(detail);
|
||||
} catch(e) {
|
||||
$$$internal$$TRY_CATCH_ERROR.error = e;
|
||||
return $$$internal$$TRY_CATCH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$invokeCallback(settled, promise, callback, detail) {
|
||||
var hasCallback = $$utils$$isFunction(callback),
|
||||
value, error, succeeded, failed;
|
||||
|
||||
if (hasCallback) {
|
||||
value = $$$internal$$tryCatch(callback, detail);
|
||||
|
||||
if (value === $$$internal$$TRY_CATCH_ERROR) {
|
||||
failed = true;
|
||||
error = value.error;
|
||||
value = null;
|
||||
} else {
|
||||
succeeded = true;
|
||||
}
|
||||
|
||||
if (promise === value) {
|
||||
$$$internal$$reject(promise, $$$internal$$cannotReturnOwn());
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
value = detail;
|
||||
succeeded = true;
|
||||
}
|
||||
|
||||
if (promise._state !== $$$internal$$PENDING) {
|
||||
// noop
|
||||
} else if (hasCallback && succeeded) {
|
||||
$$$internal$$resolve(promise, value);
|
||||
} else if (failed) {
|
||||
$$$internal$$reject(promise, error);
|
||||
} else if (settled === $$$internal$$FULFILLED) {
|
||||
$$$internal$$fulfill(promise, value);
|
||||
} else if (settled === $$$internal$$REJECTED) {
|
||||
$$$internal$$reject(promise, value);
|
||||
}
|
||||
}
|
||||
|
||||
function $$$internal$$initializePromise(promise, resolver) {
|
||||
try {
|
||||
resolver(function resolvePromise(value){
|
||||
$$$internal$$resolve(promise, value);
|
||||
}, function rejectPromise(reason) {
|
||||
$$$internal$$reject(promise, reason);
|
||||
});
|
||||
} catch(e) {
|
||||
$$$internal$$reject(promise, e);
|
||||
}
|
||||
}
|
||||
|
||||
function $$$enumerator$$makeSettledResult(state, position, value) {
|
||||
if (state === $$$internal$$FULFILLED) {
|
||||
return {
|
||||
state: 'fulfilled',
|
||||
value: value
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
state: 'rejected',
|
||||
reason: value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
|
||||
this._instanceConstructor = Constructor;
|
||||
this.promise = new Constructor($$$internal$$noop, label);
|
||||
this._abortOnReject = abortOnReject;
|
||||
|
||||
if (this._validateInput(input)) {
|
||||
this._input = input;
|
||||
this.length = input.length;
|
||||
this._remaining = input.length;
|
||||
|
||||
this._init();
|
||||
|
||||
if (this.length === 0) {
|
||||
$$$internal$$fulfill(this.promise, this._result);
|
||||
} else {
|
||||
this.length = this.length || 0;
|
||||
this._enumerate();
|
||||
if (this._remaining === 0) {
|
||||
$$$internal$$fulfill(this.promise, this._result);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$$$internal$$reject(this.promise, this._validationError());
|
||||
}
|
||||
}
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._validateInput = function(input) {
|
||||
return $$utils$$isArray(input);
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._validationError = function() {
|
||||
return new Error('Array Methods must be provided an Array');
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._init = function() {
|
||||
this._result = new Array(this.length);
|
||||
};
|
||||
|
||||
var $$$enumerator$$default = $$$enumerator$$Enumerator;
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._enumerate = function() {
|
||||
var length = this.length;
|
||||
var promise = this.promise;
|
||||
var input = this._input;
|
||||
|
||||
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
|
||||
this._eachEntry(input[i], i);
|
||||
}
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
|
||||
var c = this._instanceConstructor;
|
||||
if ($$utils$$isMaybeThenable(entry)) {
|
||||
if (entry.constructor === c && entry._state !== $$$internal$$PENDING) {
|
||||
entry._onerror = null;
|
||||
this._settledAt(entry._state, i, entry._result);
|
||||
} else {
|
||||
this._willSettleAt(c.resolve(entry), i);
|
||||
}
|
||||
} else {
|
||||
this._remaining--;
|
||||
this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry);
|
||||
}
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
|
||||
var promise = this.promise;
|
||||
|
||||
if (promise._state === $$$internal$$PENDING) {
|
||||
this._remaining--;
|
||||
|
||||
if (this._abortOnReject && state === $$$internal$$REJECTED) {
|
||||
$$$internal$$reject(promise, value);
|
||||
} else {
|
||||
this._result[i] = this._makeResult(state, i, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._remaining === 0) {
|
||||
$$$internal$$fulfill(promise, this._result);
|
||||
}
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
$$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
|
||||
var enumerator = this;
|
||||
|
||||
$$$internal$$subscribe(promise, undefined, function(value) {
|
||||
enumerator._settledAt($$$internal$$FULFILLED, i, value);
|
||||
}, function(reason) {
|
||||
enumerator._settledAt($$$internal$$REJECTED, i, reason);
|
||||
});
|
||||
};
|
||||
|
||||
var $$promise$all$$default = function all(entries, label) {
|
||||
return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
|
||||
};
|
||||
|
||||
var $$promise$race$$default = function race(entries, label) {
|
||||
/*jshint validthis:true */
|
||||
var Constructor = this;
|
||||
|
||||
var promise = new Constructor($$$internal$$noop, label);
|
||||
|
||||
if (!$$utils$$isArray(entries)) {
|
||||
$$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
|
||||
return promise;
|
||||
}
|
||||
|
||||
var length = entries.length;
|
||||
|
||||
function onFulfillment(value) {
|
||||
$$$internal$$resolve(promise, value);
|
||||
}
|
||||
|
||||
function onRejection(reason) {
|
||||
$$$internal$$reject(promise, reason);
|
||||
}
|
||||
|
||||
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
|
||||
$$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
var $$promise$resolve$$default = function resolve(object, label) {
|
||||
/*jshint validthis:true */
|
||||
var Constructor = this;
|
||||
|
||||
if (object && typeof object === 'object' && object.constructor === Constructor) {
|
||||
return object;
|
||||
}
|
||||
|
||||
var promise = new Constructor($$$internal$$noop, label);
|
||||
$$$internal$$resolve(promise, object);
|
||||
return promise;
|
||||
};
|
||||
|
||||
var $$promise$reject$$default = function reject(reason, label) {
|
||||
/*jshint validthis:true */
|
||||
var Constructor = this;
|
||||
var promise = new Constructor($$$internal$$noop, label);
|
||||
$$$internal$$reject(promise, reason);
|
||||
return promise;
|
||||
};
|
||||
|
||||
var $$es6$promise$promise$$counter = 0;
|
||||
|
||||
function $$es6$promise$promise$$needsResolver() {
|
||||
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
||||
}
|
||||
|
||||
function $$es6$promise$promise$$needsNew() {
|
||||
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
||||
}
|
||||
|
||||
var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise;
|
||||
|
||||
/**
|
||||
Promise objects represent the eventual result of an asynchronous operation. The
|
||||
primary way of interacting with a promise is through its `then` method, which
|
||||
registers callbacks to receive either a promise’s eventual value or the reason
|
||||
why the promise cannot be fulfilled.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
||||
- `thenable` is an object or function that defines a `then` method.
|
||||
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
||||
- `exception` is a value that is thrown using the throw statement.
|
||||
- `reason` is a value that indicates why a promise was rejected.
|
||||
- `settled` the final resting state of a promise, fulfilled or rejected.
|
||||
|
||||
A promise can be in one of three states: pending, fulfilled, or rejected.
|
||||
|
||||
Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
||||
state. Promises that are rejected have a rejection reason and are in the
|
||||
rejected state. A fulfillment value is never a thenable.
|
||||
|
||||
Promises can also be said to *resolve* a value. If this value is also a
|
||||
promise, then the original promise's settled state will match the value's
|
||||
settled state. So a promise that *resolves* a promise that rejects will
|
||||
itself reject, and a promise that *resolves* a promise that fulfills will
|
||||
itself fulfill.
|
||||
|
||||
|
||||
Basic Usage:
|
||||
------------
|
||||
|
||||
```js
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
// on success
|
||||
resolve(value);
|
||||
|
||||
// on failure
|
||||
reject(reason);
|
||||
});
|
||||
|
||||
promise.then(function(value) {
|
||||
// on fulfillment
|
||||
}, function(reason) {
|
||||
// on rejection
|
||||
});
|
||||
```
|
||||
|
||||
Advanced Usage:
|
||||
---------------
|
||||
|
||||
Promises shine when abstracting away asynchronous interactions such as
|
||||
`XMLHttpRequest`s.
|
||||
|
||||
```js
|
||||
function getJSON(url) {
|
||||
return new Promise(function(resolve, reject){
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', url);
|
||||
xhr.onreadystatechange = handler;
|
||||
xhr.responseType = 'json';
|
||||
xhr.setRequestHeader('Accept', 'application/json');
|
||||
xhr.send();
|
||||
|
||||
function handler() {
|
||||
if (this.readyState === this.DONE) {
|
||||
if (this.status === 200) {
|
||||
resolve(this.response);
|
||||
} else {
|
||||
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getJSON('/posts.json').then(function(json) {
|
||||
// on fulfillment
|
||||
}, function(reason) {
|
||||
// on rejection
|
||||
});
|
||||
```
|
||||
|
||||
Unlike callbacks, promises are great composable primitives.
|
||||
|
||||
```js
|
||||
Promise.all([
|
||||
getJSON('/posts'),
|
||||
getJSON('/comments')
|
||||
]).then(function(values){
|
||||
values[0] // => postsJSON
|
||||
values[1] // => commentsJSON
|
||||
|
||||
return values;
|
||||
});
|
||||
```
|
||||
|
||||
@class Promise
|
||||
@param {function} resolver
|
||||
Useful for tooling.
|
||||
@constructor
|
||||
*/
|
||||
function $$es6$promise$promise$$Promise(resolver) {
|
||||
this._id = $$es6$promise$promise$$counter++;
|
||||
this._state = undefined;
|
||||
this._result = undefined;
|
||||
this._subscribers = [];
|
||||
|
||||
if ($$$internal$$noop !== resolver) {
|
||||
if (!$$utils$$isFunction(resolver)) {
|
||||
$$es6$promise$promise$$needsResolver();
|
||||
}
|
||||
|
||||
if (!(this instanceof $$es6$promise$promise$$Promise)) {
|
||||
$$es6$promise$promise$$needsNew();
|
||||
}
|
||||
|
||||
$$$internal$$initializePromise(this, resolver);
|
||||
}
|
||||
}
|
||||
|
||||
$$es6$promise$promise$$Promise.all = $$promise$all$$default;
|
||||
$$es6$promise$promise$$Promise.race = $$promise$race$$default;
|
||||
$$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default;
|
||||
$$es6$promise$promise$$Promise.reject = $$promise$reject$$default;
|
||||
|
||||
$$es6$promise$promise$$Promise.prototype = {
|
||||
constructor: $$es6$promise$promise$$Promise,
|
||||
|
||||
/**
|
||||
The primary way of interacting with a promise is through its `then` method,
|
||||
which registers callbacks to receive either a promise's eventual value or the
|
||||
reason why the promise cannot be fulfilled.
|
||||
|
||||
```js
|
||||
findUser().then(function(user){
|
||||
// user is available
|
||||
}, function(reason){
|
||||
// user is unavailable, and you are given the reason why
|
||||
});
|
||||
```
|
||||
|
||||
Chaining
|
||||
--------
|
||||
|
||||
The return value of `then` is itself a promise. This second, 'downstream'
|
||||
promise is resolved with the return value of the first promise's fulfillment
|
||||
or rejection handler, or rejected if the handler throws an exception.
|
||||
|
||||
```js
|
||||
findUser().then(function (user) {
|
||||
return user.name;
|
||||
}, function (reason) {
|
||||
return 'default name';
|
||||
}).then(function (userName) {
|
||||
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
||||
// will be `'default name'`
|
||||
});
|
||||
|
||||
findUser().then(function (user) {
|
||||
throw new Error('Found user, but still unhappy');
|
||||
}, function (reason) {
|
||||
throw new Error('`findUser` rejected and we're unhappy');
|
||||
}).then(function (value) {
|
||||
// never reached
|
||||
}, function (reason) {
|
||||
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
||||
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
|
||||
});
|
||||
```
|
||||
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
||||
|
||||
```js
|
||||
findUser().then(function (user) {
|
||||
throw new PedagogicalException('Upstream error');
|
||||
}).then(function (value) {
|
||||
// never reached
|
||||
}).then(function (value) {
|
||||
// never reached
|
||||
}, function (reason) {
|
||||
// The `PedgagocialException` is propagated all the way down to here
|
||||
});
|
||||
```
|
||||
|
||||
Assimilation
|
||||
------------
|
||||
|
||||
Sometimes the value you want to propagate to a downstream promise can only be
|
||||
retrieved asynchronously. This can be achieved by returning a promise in the
|
||||
fulfillment or rejection handler. The downstream promise will then be pending
|
||||
until the returned promise is settled. This is called *assimilation*.
|
||||
|
||||
```js
|
||||
findUser().then(function (user) {
|
||||
return findCommentsByAuthor(user);
|
||||
}).then(function (comments) {
|
||||
// The user's comments are now available
|
||||
});
|
||||
```
|
||||
|
||||
If the assimliated promise rejects, then the downstream promise will also reject.
|
||||
|
||||
```js
|
||||
findUser().then(function (user) {
|
||||
return findCommentsByAuthor(user);
|
||||
}).then(function (comments) {
|
||||
// If `findCommentsByAuthor` fulfills, we'll have the value here
|
||||
}, function (reason) {
|
||||
// If `findCommentsByAuthor` rejects, we'll have the reason here
|
||||
});
|
||||
```
|
||||
|
||||
Simple Example
|
||||
--------------
|
||||
|
||||
Synchronous Example
|
||||
|
||||
```javascript
|
||||
var result;
|
||||
|
||||
try {
|
||||
result = findResult();
|
||||
// success
|
||||
} catch(reason) {
|
||||
// failure
|
||||
}
|
||||
```
|
||||
|
||||
Errback Example
|
||||
|
||||
```js
|
||||
findResult(function(result, err){
|
||||
if (err) {
|
||||
// failure
|
||||
} else {
|
||||
// success
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Promise Example;
|
||||
|
||||
```javascript
|
||||
findResult().then(function(result){
|
||||
// success
|
||||
}, function(reason){
|
||||
// failure
|
||||
});
|
||||
```
|
||||
|
||||
Advanced Example
|
||||
--------------
|
||||
|
||||
Synchronous Example
|
||||
|
||||
```javascript
|
||||
var author, books;
|
||||
|
||||
try {
|
||||
author = findAuthor();
|
||||
books = findBooksByAuthor(author);
|
||||
// success
|
||||
} catch(reason) {
|
||||
// failure
|
||||
}
|
||||
```
|
||||
|
||||
Errback Example
|
||||
|
||||
```js
|
||||
|
||||
function foundBooks(books) {
|
||||
|
||||
}
|
||||
|
||||
function failure(reason) {
|
||||
|
||||
}
|
||||
|
||||
findAuthor(function(author, err){
|
||||
if (err) {
|
||||
failure(err);
|
||||
// failure
|
||||
} else {
|
||||
try {
|
||||
findBoooksByAuthor(author, function(books, err) {
|
||||
if (err) {
|
||||
failure(err);
|
||||
} else {
|
||||
try {
|
||||
foundBooks(books);
|
||||
} catch(reason) {
|
||||
failure(reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch(error) {
|
||||
failure(err);
|
||||
}
|
||||
// success
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Promise Example;
|
||||
|
||||
```javascript
|
||||
findAuthor().
|
||||
then(findBooksByAuthor).
|
||||
then(function(books){
|
||||
// found books
|
||||
}).catch(function(reason){
|
||||
// something went wrong
|
||||
});
|
||||
```
|
||||
|
||||
@method then
|
||||
@param {Function} onFulfilled
|
||||
@param {Function} onRejected
|
||||
Useful for tooling.
|
||||
@return {Promise}
|
||||
*/
|
||||
then: function(onFulfillment, onRejection) {
|
||||
var parent = this;
|
||||
var state = parent._state;
|
||||
|
||||
if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var child = new this.constructor($$$internal$$noop);
|
||||
var result = parent._result;
|
||||
|
||||
if (state) {
|
||||
var callback = arguments[state - 1];
|
||||
$$asap$$default(function(){
|
||||
$$$internal$$invokeCallback(state, child, callback, result);
|
||||
});
|
||||
} else {
|
||||
$$$internal$$subscribe(parent, child, onFulfillment, onRejection);
|
||||
}
|
||||
|
||||
return child;
|
||||
},
|
||||
|
||||
/**
|
||||
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
|
||||
as the catch block of a try/catch statement.
|
||||
|
||||
```js
|
||||
function findAuthor(){
|
||||
throw new Error('couldn't find that author');
|
||||
}
|
||||
|
||||
// synchronous
|
||||
try {
|
||||
findAuthor();
|
||||
} catch(reason) {
|
||||
// something went wrong
|
||||
}
|
||||
|
||||
// async with promises
|
||||
findAuthor().catch(function(reason){
|
||||
// something went wrong
|
||||
});
|
||||
```
|
||||
|
||||
@method catch
|
||||
@param {Function} onRejection
|
||||
Useful for tooling.
|
||||
@return {Promise}
|
||||
*/
|
||||
'catch': function(onRejection) {
|
||||
return this.then(null, onRejection);
|
||||
}
|
||||
};
|
||||
|
||||
var $$es6$promise$polyfill$$default = function polyfill() {
|
||||
var local;
|
||||
|
||||
if (typeof global !== 'undefined') {
|
||||
local = global;
|
||||
} else if (typeof window !== 'undefined' && window.document) {
|
||||
local = window;
|
||||
} else {
|
||||
local = self;
|
||||
}
|
||||
|
||||
var es6PromiseSupport =
|
||||
"Promise" in local &&
|
||||
// Some of these methods are missing from
|
||||
// Firefox/Chrome experimental implementations
|
||||
"resolve" in local.Promise &&
|
||||
"reject" in local.Promise &&
|
||||
"all" in local.Promise &&
|
||||
"race" in local.Promise &&
|
||||
// Older version of the spec had a resolver object
|
||||
// as the arg rather than a function
|
||||
(function() {
|
||||
var resolve;
|
||||
new local.Promise(function(r) { resolve = r; });
|
||||
return $$utils$$isFunction(resolve);
|
||||
}());
|
||||
|
||||
if (!es6PromiseSupport) {
|
||||
local.Promise = $$es6$promise$promise$$default;
|
||||
}
|
||||
};
|
||||
|
||||
var es6$promise$umd$$ES6Promise = {
|
||||
'Promise': $$es6$promise$promise$$default,
|
||||
'polyfill': $$es6$promise$polyfill$$default
|
||||
};
|
||||
|
||||
/* global define:true module:true window: true */
|
||||
if (typeof define === 'function' && define['amd']) {
|
||||
define(function() { return es6$promise$umd$$ES6Promise; });
|
||||
} else if (typeof module !== 'undefined' && module['exports']) {
|
||||
module['exports'] = es6$promise$umd$$ES6Promise;
|
||||
} else if (typeof this !== 'undefined') {
|
||||
this['ES6Promise'] = es6$promise$umd$$ES6Promise;
|
||||
}
|
||||
}).call(this);
|
1817
static/emularity/loader.js
Normal file
1817
static/emularity/loader.js
Normal file
File diff suppressed because it is too large
Load Diff
1
static/games
Submodule
1
static/games
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d781c7ac19e80197032bb26d77de0e1018a62772
|
12
static/js/game.js
Normal file
12
static/js/game.js
Normal file
@ -0,0 +1,12 @@
|
||||
function htmlFullscreen() {
|
||||
var gameCanvas = document.getElementById('canvas');
|
||||
var exitButton = document.getElementById('exit_button')
|
||||
if (gameCanvas.classList.contains('html-fullscreen')) {
|
||||
gameCanvas.classList.remove('html-fullscreen');
|
||||
exitButton.classList.remove('exit_fullscreen_show');
|
||||
}
|
||||
else {
|
||||
gameCanvas.classList.add('html-fullscreen');
|
||||
exitButton.classList.add('exit_fullscreen_show');
|
||||
}
|
||||
}
|
37
templates/about.html
Normal file
37
templates/about.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block title %}关于{% endblock %}
|
||||
{% block main %}
|
||||
<div class="container mt-3">
|
||||
<h2>中文 DOS 游戏 🎮</h2>
|
||||
<h3>项目地址</h3>
|
||||
<p><a href="https://github.com/rwv/chinese-dos-games">https://github.com/rwv/chinese-dos-games</a></p>
|
||||
|
||||
<h3>游戏列表</h3>
|
||||
<p>
|
||||
{% if games %}
|
||||
<ul>
|
||||
{% for key, game_info in games.items() %}
|
||||
<li>
|
||||
<a href="{{ url_for('game', identifier=game_info['identifier']) }}">{{ game_info['name']['zh-Hans'] }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<h3>感谢</h3>
|
||||
<p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/dreamlayers/em-dosbox" target="_blank">dreamlayers/em-dosbox: An Emscripten
|
||||
port of DOSBox</a></li>
|
||||
<li><a href="https://github.com/db48x/emularity" target="_blank">db48x/emularity: easily embed emulators</a></li>
|
||||
|
||||
</ul>
|
||||
</p>
|
||||
<h3>许可</h3>
|
||||
<p><a href="https://www.gnu.org/licenses/gpl-3.0.html">The GNU General Public License v3.0</a></p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
55
templates/base.html
Normal file
55
templates/base.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hans">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/es6-promise.js') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/browserfs.min.js') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/loader.js') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/dosbox/dosbox-sync.js') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/dosbox/dosbox-sync.mem') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='emularity/emularity_color_small.png') }}">
|
||||
<link rel="prefetch" href="{{ url_for('static', filename='js/game.js') }}">
|
||||
<link href="{{ url_for('static', filename='css/main.css') }}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
|
||||
integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
|
||||
crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar sticky-top navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="{{ url_for('index') }}">🎮</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup"
|
||||
aria-controls="navbarNavAltMarkup"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav">
|
||||
<a class="nav-item nav-link" href="{{ url_for('index') }}">首页</a>
|
||||
<a class="nav-item nav-link" href="{{ url_for('about') }}">关于</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{% block main %}{% endblock %}
|
||||
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
|
||||
integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
|
||||
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
{% block footer %}{% endblock %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
90
templates/game.html
Normal file
90
templates/game.html
Normal file
@ -0,0 +1,90 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block title %}{{ game_info["name"]["zh-Hans"] }}{% endblock %}
|
||||
{% block main %}
|
||||
<div class="container mt-3">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<div class="card mb-3">
|
||||
<div id="screen_container">
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<h5 class="card-title game-title">{{ game_info["name"]["zh-Hans"] }}</h5>
|
||||
<div id='controls'>
|
||||
<span><input class="btn btn-light" type="button" value="网页全屏"
|
||||
onclick="htmlFullscreen();"></span>
|
||||
<span><input class="btn btn-light" type="button" value="全屏游戏"
|
||||
onclick="emulator.requestFullScreen();"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
{% if game_info.keymaps %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">操作</h5>
|
||||
{% for k,v in game_info.keymaps.items() %}
|
||||
<kbd>{{ k }}</kbd> {{ v }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if game_info.cheats %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">作弊</h5>
|
||||
{% for k,v in game_info.cheats.items() %}
|
||||
<code>{{ k }}</code> {{ v }}<br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if game_info.links %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">链接</h5>
|
||||
{% for k,v in game_info.links.items() %}
|
||||
<a href="{{ v }}" class="card-link" target="_blank">{{ k }}</a><br>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="exit_fullscreen" id="exit_button">
|
||||
<input class="btn btn-light" type="button" value="退出" onclick="htmlFullscreen();">
|
||||
</div>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='emularity/es6-promise.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='emularity/browserfs.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ url_for('static', filename='emularity/loader.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
var emulator = new Emulator(document.querySelector("#canvas"),
|
||||
null,
|
||||
new DosBoxLoader(DosBoxLoader.emulatorJS("{{ url_for('static', filename='emularity/dosbox/dosbox-sync.js') }}"),
|
||||
DosBoxLoader.locateAdditionalEmulatorJS(locateAdditionalFiles),
|
||||
DosBoxLoader.nativeResolution(640, 480),
|
||||
DosBoxLoader.mountZip("c",
|
||||
DosBoxLoader.fetchFile("Game File",
|
||||
"{{ url_for('static', filename="games/bin/{}.zip".format(game_info["identifier"])) }}")),
|
||||
DosBoxLoader.startExe("{{ game_info["executable"] }}")))
|
||||
emulator.start({waitAfterDownloading: true});
|
||||
|
||||
function locateAdditionalFiles(filename) {
|
||||
if (filename === "dosbox.html.mem") {
|
||||
return "{{ url_for('static', filename='emularity/dosbox/dosbox-sync.mem') }}";
|
||||
}
|
||||
else {
|
||||
return "{{ url_for('static', filename='emularity/dosbox/dosbox-sync.mem') }}" + filename;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/game.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
40
templates/index.html
Normal file
40
templates/index.html
Normal file
@ -0,0 +1,40 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block title %}首页{% endblock %}
|
||||
{% block main %}
|
||||
<div class="container mt-3 grid">
|
||||
{% if games %}
|
||||
{% for key, game_info in games.items() %}
|
||||
<div class="card grid-item mb-3 mr-3">
|
||||
<a href="{{ url_for('game', identifier=game_info.identifier) }}">
|
||||
<img class="card-img-top"
|
||||
src="{{ url_for('static', filename='games/img/{}/{}'.format(game_info.identifier, game_info.coverFilename)) }}"
|
||||
alt="{{ game_info['name']['zh-Hans'] }}">
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ game_info['name']['zh-Hans'] }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="grid">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.imagesloaded/3.1.8/imagesloaded.pkgd.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/masonry/3.3.1/masonry.pkgd.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
var $container = $(".grid");
|
||||
$container.masonry();
|
||||
|
||||
$container.imagesLoaded()
|
||||
.progress(function (instance, image) {
|
||||
$container.masonry();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user