Initial commit

This commit is contained in:
Ben Garrett 2019-01-13 16:48:35 +11:00
commit ad15f11810
20 changed files with 3835 additions and 0 deletions

52
.eslintrc.js Normal file
View File

@ -0,0 +1,52 @@
module.exports = {
"env": {
"es6": true,
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2017,
"impliedStrict": true,
},
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"linebreak-style": [
"off"
],
"no-console": 0,
"no-fallthrough": ["error", { "commentPattern": "break[\\s\\w]*omitted" }],
"no-unused-vars": ["error", { "vars": "local" }],
"quotes": [
"error",
"backtick",
],
"semi": [
"error",
"never",
],
"strict": ["error", "global"],
},
"globals": {
"DoseeLoader": true,
"Emulator": true,
"metaContent": true,
"storageAvailable": true,
"BuildEcma48": true,
"buildLinksToCSS": true,
"changeTextScanlines": true,
"changeTextEffect": true,
"checkArg": true,
"checkErr": true,
"checkRange": true,
"displayErr": true,
"findControlSequences": true,
"findEngine": true,
"Font": true,
"Guess": true,
"humaniseFS": true,
"Palette": true,
"ParseToChildren": true,
"runSpinLoader": true,
"Transcode": true,
}
};

BIN
disk_drives/g_drive.zip Normal file

Binary file not shown.

BIN
disk_drives/s_drive.zip Normal file

Binary file not shown.

BIN
disk_drives/u_drive.zip Normal file

Binary file not shown.

160
dosee-functions.js Normal file
View File

@ -0,0 +1,160 @@
/*
* /javascripts/dosee-functions.js
*
* DOSee user interface functions
*/
/* global saveAs screenfull */
/* eslint-env es6 */
/* eslint quotes: ['error', 'backtick'] */
/* eslint indent: ["error", 4, { "SwitchCase": 1 } ] */
/* eslint no-console: ["error", { allow: ["log", "error", "warn"] }] */
'use strict'
// Returns the content data stored in HTML <meta> tags
function metaContent(name) {
const elm = document.getElementsByName(name)
if (elm[0] === undefined) return null
else return elm[0].getAttribute(`content`)
}
// Test the local storage availability for the browser
// Source: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
function storageAvailable(type) {
const test = function (t) {
try {
const storage = window[t],
x = `__storage_test__`
storage.setItem(x, `test data`)
storage.removeItem(x)
return true
} catch (e) {
return false
}
}
switch (type) {
case `local`: case `session`:
return test(`${type}Storage`)
default: return false
}
}
(function () {
// 'Options' tab interactions
// Restore existing and save new interactions that are kept after the browser is closed
if (storageAvailable(`local`)) {
// Reveal Options tab
const dto = document.getElementById(`doseeOptionsTab`)
dto.classList.remove(`hide-true`)
dto.classList.add(`hide-false`)
// Automatically start DOS emulation
const asb = document.getElementById(`doseeAutoRun`)
asb.addEventListener(`click`, function () {
const chk = asb.checked
localStorage.setItem(`doseeAutostart`, chk) // boolean value
})
const d = localStorage.getItem(`doseeAutostart`)
if (d === `true`) asb.checked = true
// For sharper DOS ASCII/ANSI text
const nab = document.getElementById(`doseeAspect`)
const e = localStorage.getItem(`doseeAspect`)
nab.addEventListener(`click`, function () {
var dosaspect = nab.checked
localStorage.setItem(`doseeAspect`, !dosaspect) // boolean value
})
if (e === `false`) nab.checked = true
// Scaler engine
const sOpt = document.querySelectorAll(`input[name=dosscale]`)
let i = sOpt.length
while (i--)
sOpt[i].addEventListener(`change`, function () {
localStorage.setItem(`doseeScaler`, this.value)
}, 0)
}
// Session storage interactions that get deleted when the browser tab is closed
if (storageAvailable(`session`)) {
const setTab = function (ac) {
if (ac === null) return
sessionStorage.setItem(`doseeTab`, `${ac}`)
}
const tab = document.getElementById(`doseeTabs`)
const tabs = tab.getElementsByClassName(`tabtoggle`)
// tab event listeners
if (tabs != null && tabs.length >= 0) {
let i = tabs.length
while (i--) {
tabs[i].addEventListener(`click`, function () {
setTab(this.firstChild.getAttribute(`aria-controls`))
}, 0)
}
}
// restore most recently used tab
const savedTab = sessionStorage.getItem(`doseeTab`)
if (savedTab !== null) {
const dt = document.getElementById(`doseeTabs`)
const dtc = document.getElementById(`doseeTabContent`)
const ts = document.getElementById(`${savedTab}Tab`)
const tb = document.getElementById(savedTab)
if (dt !== null && dtc !== null && ts !== null && tb !== null) {
dt.getElementsByClassName(`active`)[0].classList.remove(`active`)
dtc.getElementsByClassName(`active`)[0].classList.remove(`active`)
ts.classList.add(`active`)
tb.classList.add(`active`)
}
}
}
// Full screen button
{
let elem = document.getElementById(`doseeCanvas`)
if (screenfull.enabled) {
const fsb = document.getElementById(`doseeFullScreen`)
fsb.classList.remove(`hide-true`)
fsb.classList.add(`hide-false-inline`)
const chrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)
if (chrome) elem = document.getElementById(`doseeContainer`)
}
document.getElementById(`doseeFullScreen`).addEventListener(`click`, function () {
if (screenfull.enabled) screenfull.request(elem)
})
}
// Screenshot button & screenshot + upload button
try {
const fss = !!new Blob()
if (typeof fss !== `undefined`) {
const ssb = document.getElementById(`doseeCaptureScreen`)
// dosee screenshot button
ssb.classList.remove(`hide-true`)
ssb.classList.add(`hide-false-inline`)
ssb.addEventListener(`click`, function () {
const canvas = document.getElementById(`doseeCanvas`)
const filename = metaContent(`dosee:capname`)
canvas.toBlob(function (blob) {
saveAs(blob, filename)
const click = ssb.childNodes[0].childNodes[0].classList
click.add(`brand-success`)
setTimeout(function () { click.remove(`brand-success`) }, 750)
})
})
}
} catch (err) {
console.error(err)
}
// Keyboard navigation is disabled
{
const tki = document.getElementsByClassName(`touchKeyboardIcons`)
if (typeof tki[0] !== `undefined`) {
tki[0].style.cssText = `display: none`
}
}
// Reboot button
document.getElementById(`doseereboot`).addEventListener(`click`, function () {
location.reload(true)
})
})()

74
dosee-init.js Normal file
View File

@ -0,0 +1,74 @@
/*
* dosee-loader.js
* DOSee initialisator
*/
{
`use strict`
const paths = new Map()
.set(`ddg`, `disk_drives/g_drive.zip`)
.set(`dds`, `disk_drives/s_drive.zip`)
.set(`ddu`, `disk_drives/u_drive.zip`)
.set(`core`, `emulator/dosee-core.js`)
.set(`mem`, `emulator/dosee-core.mem`)
// Load GUS (Gravis UltraSound) drivers
const gusDriver = function (q) {
if (q !== `true`) return null
return DoseeLoader.mountZip(`g`, DoseeLoader.fetchFile(`gravis ultrasound drivers`, `${paths.get(`ddg`)}`))
}
// Load the Emscripten static memory initialization code external file
// https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html#code-size
const locateFiles = function (filename) {
console.log(`filename: ${filename}`)
if (filename === `dosbox.html.mem`) return `${paths.get(`mem`)}`
return `libs/${filename}`
}
// Initialise the resolution of the DOS program - width, height
const nr = function () {
const arr = cfg.res.split(`,`)
if (arr.length < 1) return [640, 480]
return [parseInt(arr[0]), parseInt(arr[1])]
}
// Load additional DOS tools and utilities
const utils = function (q) {
if (q !== `true`) return null
return DoseeLoader.mountZip(`u`, DoseeLoader.fetchFile(`dos utilities`, `${paths.get(`ddu`)}`))
}
// Load configurations obtained from <meta name="dosee:"> HTML tags
const cfg = {
start: false,
exe: metaContent(`dosee:startexe`),
filename: metaContent(`dosee:filename`),
gus: metaContent(`dosee:gusaudio`),
path: metaContent(`dosee:gamefilepath`),
res: metaContent(`dosee:resolution`),
utils: metaContent(`dosee:utils`),
}
// Start DOSee automatically?
if (storageAvailable(`local`) && localStorage.getItem(`doseeAutostart`) === `true`) { cfg.start = true }
if (cfg.start === true) console.log(`DOSee will launch automatically`)
// Initialise DOSee
// Note order of these DoseeLoader values are important and swapping them could cause failures
// dosee-core.js is the compiled Emscripten edition of DOSBox and should not be minified
const init = new DoseeLoader(
DoseeLoader.emulatorJS(`${paths.get(`core`)}`),
DoseeLoader.locateAdditionalEmulatorJS(locateFiles),
DoseeLoader.nativeResolution(nr()[0], nr()[1]),
DoseeLoader.mountZip(`c`, DoseeLoader.fetchFile(`\'${cfg.filename}\'`, `${cfg.path}`)),
DoseeLoader.mountZip(`s`, DoseeLoader.fetchFile(`DOSee configurations`, `${paths.get(`dds`)}`)),
gusDriver(cfg.gus),
utils(cfg.utils),
DoseeLoader.startExe(cfg.exe)
)
// Start DOSee!
const emulator = new Emulator(document.querySelector(`#doseeCanvas`), null, init)
emulator.start({ waitAfterDownloading: !cfg.start })
}

979
dosee-loader.js Normal file
View File

@ -0,0 +1,979 @@
/*
* /javascripts/dosee-loader.js
*
* DOSee emulator
*
* Fork of https://github.com/db48x/emularity/blob/master/loader.js
* Last commit synced to: Feb 15, 2018
*
* Major differences:
* Requires ES6 compatible browser
* Only DOS emulation
* No local save game states
* No Web Assembly builds [todo]
*/
/* global storageAvailable Module BrowserFS ES6Promise FS Promise */
/* eslint-env es6 */
/* eslint quotes: ['error', 'backtick'] */
/* eslint indent: ["error", 4, { "SwitchCase": 1 } ] */
/* eslint no-console: ["error", { allow: ["log","warn", "error"] }] */
/* eslint no-global-assign: ["error", {"exceptions": ["Module"]}] */
Module = null;
(function (Promise) {
`use strict`
const doseeVersion = `1.8p`
// DOSBox requires a valid IndexedDB
// See: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
if (window.indexedDB) {
document.getElementById(`doseeCrashed`).style.display = `none`
}
// Common API functions
// DOSee is based off The Emularity which supports multiple emulators.
// The BaseLoader naming convention was used to highlight the shared functions.
function DoseeAPI() {
return Array.prototype.reduce.call(arguments, extend)
}
// HTML <canvas> element used to display the emulation
DoseeAPI.canvas = function (id) {
const elem = id instanceof Element ? id : document.getElementById(id)
return { canvas: elem }
}
DoseeAPI.emulatorJS = function (url) {
return { emulatorJS: url }
}
DoseeAPI.locateAdditionalEmulatorJS = function (func) {
return { locateAdditionalJS: func }
}
DoseeAPI.nativeResolution = function (width, height) {
if (typeof width !== `number` || typeof height !== `number`)
throw new Error(`Width and height must be numbers`)
return {
nativeResolution: {
width: Math.floor(width),
height: Math.floor(height),
}
}
}
DoseeAPI.aspectRatio = function (ratio) {
if (typeof ratio !== `number`)
throw new Error(`Aspect ratio must be a number`)
return { aspectRatio: ratio }
}
DoseeAPI.mountZip = function (drive, file) {
return {
files: [{
drive: drive,
mountpoint: `/${drive}`,
file: file,
}]
}
}
DoseeAPI.mountFile = function (filename, file) {
return {
files: [{
mountpoint: filename,
file: file,
}]
}
}
DoseeAPI.fetchFile = function (title, url) {
return {
title: title,
url: url,
}
}
DoseeAPI.fetchOptionalFile = function (title, url) {
return {
title: title,
url: url,
optional: true,
}
}
DoseeAPI.localFile = function (title, data) {
return {
title: title,
data: data,
}
}
function DoseeLoader() {
const config = Array.prototype.reduce.call(arguments, extend)
config.emulator_arguments = build_dosbox_arguments(config.emulatorStart, config.files, config.emulatorCPU)
return config
}
Object.setPrototypeOf(DoseeLoader, DoseeAPI)
DoseeLoader.startExe = function (path) {
return { emulatorStart: path }
}
const build_dosbox_arguments = function (emulator_start, files) {
console.log(`Initialisation of DOSee ` + doseeVersion)
let verbose = `with the following configuration:`
// get guest program path
const path = emulator_start.split(/\\|\//) // I have LTS already
// get guest program file name
let prog = path.pop()
// dosbox command line arguments
const args = []
// parse URL query string
if (`URLSearchParams` in window == false) {
console.log(`DOSee needs the URLSearchParams interface to read URL query string values`)
return args
}
const urlParams = new URLSearchParams(window.location.href)
// graphic engine scalers (https://www.dosbox.com/wiki/Scaler)
let scaler = null
if (storageAvailable(`local`)) scaler = localStorage.getItem(`doseeScaler`) // look for saved option
if (scaler === null) scaler = `none`
switch (scaler) {
case `advinterp3x`:
verbose += ` Advanced interpolation engine (advinterp3x).`
args.push(`-conf`, `/dos/s/engine-advinterp3x.con`)
document.getElementById(`dosscale5`).checked = true
break
case `hq3x`:
verbose += ` High Quality 3 magnification (hq3x).`
args.push(`-conf`, `/dos/s/engine-hq3x.con`)
document.getElementById(`dosscale4`).checked = true
break
case `rgb3x`:
verbose += ` RGB engine (rgb3x).`
args.push(`-conf`, `/dos/s/engine-rgb3x.con`)
document.getElementById(`dosscale3`).checked = true
break
case `super2xsai`:
verbose += ` Super scale and interpolation engine (super2xsai).`
args.push(`-conf`, `/dos/s/engine-super2xsai.con`)
document.getElementById(`dosscale1`).checked = true
break
case `tv3x`:
verbose += ` TV 3x scale engine (tv3x).`
args.push(`-conf`, `/dos/s/engine-tv3x.con`)
document.getElementById(`dosscale2`).checked = true
break
default: document.getElementById(`dosscale0`).checked = true
break
}
// impose aspect ratio correction
let aspect = null
if (storageAvailable(`local`)) aspect = localStorage.getItem(`doseeAspect`) // look for saved option
if (aspect === null) aspect = `true`
if (aspect !== `false`) {
verbose += ` With aspect correction.`
args.push(`-conf`, `/dos/s/render.con`) // aspect=true
} else {
document.getElementById(`doseeAspect`).checked = true
verbose += ` No aspect correction.`
}
// emulation cpu speed
const cpuspeed = urlParams.get(`dosspeed`)
switch (cpuspeed) {
case `8086`:
verbose += ` 8086 real mode CPU.`
args.push(`-conf`, `/dos/s/cpu-8086.con`)
document.getElementById(`dosspeed4`).checked = true
break
case `386`:
verbose += ` 386 protect mode CPU.`
args.push(`-conf`, `/dos/s/cpu-386.con`)
document.getElementById(`dosspeed3`).checked = true
break
case `486`: case `max`:
verbose += ` Unlocked CPU speed.`
args.push(`-conf`, `/dos/s/cpu-max.con`)
document.getElementById(`dosspeed2`).checked = true
break
default:
verbose += ` Automatic CPU speed.`
args.push(`-conf`, `/dos/s/cpu-auto.con`)
document.getElementById(`dosspeed1`).checked = true
break
}
// emulation sound cards
const sound = urlParams.get(`dosaudio`)
switch (sound) {
case `none`:
verbose += ` No audio.`
args.push(`-conf`, `/dos/s/noaudio.con`)
document.getElementById(`dosaudio5`).checked = true
break
case `sb1`:
verbose += ` Sound Blaster 1.0 audio.`
args.push(`-conf`, `/dos/s/sb1.con`)
document.getElementById(`dosaudio3`).checked = true
break
case `gus`:
verbose += ` Gravis Ultrasound audio.`
args.push(`-conf`, `/dos/g/gus.con`)
document.getElementById(`dosaudio1`).checked = true
break
case `covox`:
verbose += ` Covox Speech Accelerator audio.`
args.push(`-conf`, `/dos/s/covox.con`)
document.getElementById(`dosaudio4`).checked = true
break
default:
verbose += ` Sound Blaster 16 audio.`
args.push(`-conf`, `/dos/s/sb16.con`)
document.getElementById(`dosaudio2`).checked = true
break
}
// emulation graphics or machine type
const machine = urlParams.get(`dosmachine`)
switch (machine) {
case `svga`:
verbose += ` SVGA s3 graphics.`
args.push(`-conf`, `/dos/s/svga.con`)
document.getElementById(`dosmachine1`).checked = true
document.getElementById(`svgaEffectsMsg`).style.display = `none`
break
case `cga`:
verbose += ` CGA graphics.`
args.push(`-conf`, `/dos/s/cga.con`)
document.getElementById(`dosmachine5`).checked = true
break
case `ega`:
verbose += ` EGA graphics.`
args.push(`-conf`, `/dos/s/ega.con`)
document.getElementById(`dosmachine3`).checked = true
break
case `herc`:
verbose += ` Hercules graphics.`
args.push(`-conf`, `/dos/s/herc.con`)
document.getElementById(`dosmachine6`).checked = true
break
case `tandy`:
verbose += ` Tandy graphics.`
args.push(`-conf`, `/dos/s/tandy.con`)
document.getElementById(`dosmachine4`).checked = true
break
case `et3000`:
verbose += ` SVGA ET3000 graphics.`
args.push(`-conf`, `/dos/s/et3000.con`)
document.getElementById(`dosmachine1`).checked = true
break
case `et4000`:
verbose += ` SVGA ET4000 graphics.`
args.push(`-conf`, `/dos/s/et4000.con`)
break
case `paradise`:
verbose += ` Paradise PVGA1A graphics.`
args.push(`-conf`, `/dos/s/paradise.con`)
break
case `nolfb`:
verbose += ` SVGA s3 graphics with no-line frame buffer hack.`
args.push(`-conf`, `/dos/s/nolfb.con`)
break
case `oldvbe`:
verbose += ` VESA 1.3 graphics.`
args.push(`-conf`, `/dos/s/oldvbe.con`)
break
default:
verbose += ` VGA graphics.`
args.push(`-conf`, `/dos/s/vgaonly.con`)
document.getElementById(`dosmachine2`).checked = true
break
}
// dosbox memory managers
const ems = urlParams.get(`dosems`)
if (ems === `false`) {
verbose += ` ✗ Expanded (EMS) memory.`
args.push(`-conf`, `/dos/s/noems.con`)
}
const umb = urlParams.get(`dosumb`)
if (umb === `false`) {
verbose += ` ✗ Upper Memory Block (UMB) access.`
args.push(`-conf`, `/dos/s/noumb.con`)
}
const xms = urlParams.get(`dosxms`)
if (xms === `false`) {
verbose += ` ✗ Extended (XMS) memory.`
args.push(`-conf`, `/dos/s/noxms.con`)
}
// dosbox mount points (dos drive letters)
for (const i in files) {
if (`drive` in files[i]) {
args.push(`-c`, `mount ${files[i].drive} /dos${files[i].mountpoint}`)
}
}
// dosbox default drive letter
args.push(`-c`, /^[a-zA-Z]:$/.test(path[0]) ? path.shift() : `C:`)
// load drivers not natively supplied by DOSBox and after emulated drives are mounted
// paths to drivers has been set in the sb1.con under [autoexec]
if (sound === `sb1`) {
args.push(`-c`, `SBFMDRV.COM`)
args.push(`-c`, `SOUND.COM`)
}
// dos utilities with PATH setup
const dosutilities = urlParams.get(`dosutils`)
if (dosutilities === `true`) {
args.push(`-conf`, `/dos/s/utils.con`)
}
// some programs don't run correctly unless their root directory is active
if (path && path.length) {
let pathStr = path.toString()
pathStr = pathStr.replace(`,`, `\\`)
console.log(`Execute path ${pathStr}`)
args.push(`-c`, `CD ${pathStr}`)
}
// automatically run the guest program
const skiprun = urlParams.get(`dosautorun`)
if (skiprun !== `false`) {
prog = prog.replace(` :`, ` /`) // hack to implement program options
verbose = `Will execute \`${prog}\` ${verbose}`
args.push(`-c`, prog)
// partial ansi escape code generator for coloured text
const ansi = function (code, str) {
let c = String.fromCharCode(27, 91, 48, 109) // esc[0m
switch (code) {
case `bold`: c = String.fromCharCode(27, 91, 49, 109); break // esc[1m
case `blue`: c = String.fromCharCode(27, 91, 51, 52, 109); break // esc[34m
case `white`: c = String.fromCharCode(27, 91, 51, 55, 109); break // esc[37m
}
if (str === undefined) return c
return `${c}${str}`
}
// test to display after guest program is complete
if (urlParams.get(`name`) !== `waitingapproval`) {
const finCmd = `@echo ${prog} has finished. -${ansi(`bold`)}${ansi(`blue`, `d`)}${ansi(`white`, `e`)}\
${ansi(`blue`, `f`)}${ansi(`white`, `acto`)}${ansi(`blue`, `2`)}${ansi(`white`, `.net`)}${ansi()}-`
args.push(`-c`, finCmd)
}
}
console.log(verbose)
return args
}
/**
* Emulator
*/
function Emulator(canvas, callbacks, loadFiles) {
if (typeof callbacks !== `object`) {
callbacks = {
before_emulator: null,
before_run: callbacks,
}
}
let has_started = false
const defaultSplashColors = {
foreground: `white`,
background: `black`,
failure: `red`,
success: `green`,
}
const splash = {
loading_text: ``,
spinning: true,
finished_loading: false,
colors: defaultSplashColors,
table: null,
splashimg: new Image(),
}
let cssResolution, scale, aspectRatio
// right off the bat we set the canvas's inner dimensions to
// whatever it's current css dimensions are this isn't likely to be
// the same size that dosbox will set it to, but it avoids
// the case where the size was left at the default 300x150
if (!canvas.hasAttribute(`width`)) {
const style = getComputedStyle(canvas)
canvas.width = parseInt(style.width, 10)
canvas.height = parseInt(style.height, 10)
}
this.setSplashImage = function (_splashimg) {
if (_splashimg) {
if (_splashimg instanceof Image) {
if (splash.splashimg.parentNode) {
splash.splashimg.src = _splashimg.src
} else {
splash.splashimg = _splashimg
}
} else {
splash.splashimg.src = _splashimg
}
}
return this
}
this.setCallbacks = function (_callbacks) {
if (typeof _callbacks !== `object`) {
callbacks = {
before_emulator: null,
before_run: _callbacks,
}
} else {
callbacks = _callbacks
}
return this
}
this.setSplashColors = function (colors) {
splash.colors = colors
return this
}
this.setLoad = function (loadFunc) {
loadFiles = loadFunc
return this
}
const start = function (options) {
if (has_started) return false
has_started = true
if (typeof options !== `object`) {
options = { waitAfterDownloading: false }
}
let k, c, game_data
setupSplash(canvas, splash)
drawsplash()
let loading
if (typeof loadFiles === `function`) {
loading = loadFiles(fetch_file, splash)
} else {
loading = Promise.resolve(loadFiles)
}
loading.then(loadHardDrive)
.then(loadBranding, errBranding)
.then(loadDosWarp, errDosWarp)
// hide long load time messages once emulator has loaded
{
const sdlm = document.getElementById(`doseeSlowLoad`)
if (sdlm !== `undefined`) {
sdlm.style.display = `none`
}
}
return this
function loadHardDrive(_game_data) {
return new Promise(function (resolve, reject) {
const deltaFS = new BrowserFS.FileSystem.InMemory()
finish()
function finish() {
game_data = _game_data
// Any file system writes to MountableFileSystem will be written to the
// deltaFS, letting us mount read-only zip files into the MountableFileSystem
// while being able to 'write' to them.
game_data.fs = new BrowserFS.FileSystem.OverlayFS(deltaFS,
new BrowserFS.FileSystem.MountableFileSystem())
game_data.fs.initialize(function () {
const Buffer = BrowserFS.BFSRequire(`buffer`).Buffer
function fetch(file) {
if (`data` in file && file.data !== null && typeof file.data !== `undefined`) {
return Promise.resolve(file.data)
}
return fetch_file(file.title, file.url, `arraybuffer`, file.optional)
}
function mountAt(drive) {
return function (data) {
if (data !== null) {
drive = drive.toLowerCase()
const mountpoint = `/${drive}`
// Mount into RO MFS.
game_data.fs.getOverlayedFileSystems().readable.mount(mountpoint, BFSOpenZip(new Buffer(data)))
}
}
}
Promise.all(game_data.files
.map(function (f) {
if (f && f.file) {
if (f.drive) return fetch(f.file).then(mountAt(f.drive))
}
return null
})).then(resolve, reject)
})
}
})
}
function loadBranding() {
if (!game_data || splash.failed_loading) return null
if (options.waitAfterDownloading) {
return new Promise(function (resolve) {
splash.setTitle(`✔ Click here to run`)
splash.spinning = false
// stashes these event listeners so that we can remove them after
window.addEventListener(`keydown`, k = keyevent(resolve))
canvas.addEventListener(`click`, c = resolve)
splash.splashElt.addEventListener(`click`, c)
})
}
return Promise.resolve()
}
function loadDosWarp() {
if (!game_data || splash.failed_loading) return
splash.spinning = true
window.removeEventListener(`keypress`, k)
canvas.removeEventListener(`click`, c)
splash.splashElt.removeEventListener(`click`, c)
// Don't let arrow, pg up/down, home, end affect page position
blockSomeKeys()
setupFullScreen()
disableRightClickContextMenu(canvas)
// Emscripten doesn't use the proper prefixed functions for fullscreen requests,
// so let's map the prefixed versions to the correct function.
canvas.requestPointerLock = getpointerlockenabler()
moveConfigToRoot(game_data.fs)
Module = init_module(
game_data.emulator_arguments,
game_data.fs,
game_data.locateAdditionalJS,
game_data.nativeResolution,
game_data.aspectRatio)
if (callbacks && callbacks.before_emulator) {
try {
callbacks.before_emulator()
} catch (x) {
console.log(x)
}
}
if (game_data.emulatorJS) {
// enable the operator screenshot and upload button plus jump to the emulation canvas
{
const oscb = document.getElementById(`doseeCaptureUpload`)
if (oscb !== null) {
oscb.disabled = false
}
window.location.href = `#emulator`
}
splash.setTitle(`Warping to DOS`)
attach_script(game_data.emulatorJS)
} else {
splash.setTitle(`Non-system disk or disk error`)
}
}
function errBranding() {
if (splash.failed_loading) return null
splash.setTitle(`The emulator broke ${String.fromCharCode(9785)}`) // frown face
splash.failed_loading = true
}
function errDosWarp() {
if (splash.failed_loading) return
splash.setTitle(`Invalid media, track 0 bad or unusable`)
splash.failed_loading = true
}
}
this.start = start
const init_module = function (args, fs, locateAdditionalJS, nativeResolution, aspectRatio) {
return {
arguments: args,
screenIsReadOnly: true,
print: function (text) {
// feedback from DOSBox
console.log(text)
},
canvas: canvas,
noInitialRun: false,
locateFile: locateAdditionalJS,
preInit: function () {
splash.setTitle(`Loading program into the file system`)
// Re-initialize BFS to just use the writeable in-memory storage.
BrowserFS.initialize(fs)
const BFS = new BrowserFS.EmscriptenFS()
// Mount the file system into Emscripten.
FS.mkdir(`/dos`)
FS.mount(BFS, { root: `/` }, `/dos`)
splash.finished_loading = true
splash.hide()
setTimeout(function () {
resizeCanvas(canvas,
scale = scale || scale,
cssResolution = nativeResolution || cssResolution,
aspectRatio = aspectRatio || aspectRatio)
})
if (callbacks && callbacks.before_run) {
window.setTimeout(function () {
callbacks.before_run()
}, 0)
}
}
}
}
const formatSize = function (event) {
if (event.lengthComputable)
return `(${(event.total ? (event.loaded / event.total * 100).toFixed(0) : `100`)}% \
${formatBytes(event.loaded)} of ${formatBytes(event.total)})`
return `(${formatBytes(event.loaded)})`
}
const formatBytes = function (bytes, base10) {
if (bytes === 0) return `0 B`
const unit = base10 ? 1000 : 1024,
units = base10 ? [`B`, `kB`, `MB`, `GB`, `TB`, `PB`, `EB`, `ZB`, `YB`] : [`B`, `KiB`, `MiB`, `GiB`, `TiB`, `PiB`, `EiB`, `ZiB`, `YiB`],
exp = parseInt((Math.log(bytes) / Math.log(unit))),
size = bytes / Math.pow(unit, exp)
return `${size.toFixed(1)} ${units[exp]}`
}
const fetch_file = function (title, url, rt, optional) {
const row = addRow(splash.table)
const titleCell = row[0],
statusCell = row[1]
titleCell.textContent = title
return new Promise(function (resolve, reject) {
const xhr = new XMLHttpRequest()
xhr.open(`GET`, url, true)
xhr.responseType = rt || `arraybuffer`
xhr.onprogress = function (e) {
titleCell.textContent = `${title} ${formatSize(e)}`
}
xhr.onload = function () {
if (xhr.status === 200 || xhr.status === 0) {
success()
resolve(xhr.response)
} else if (optional) {
success()
resolve(null)
} else {
failure()
reject()
}
}
xhr.onerror = function () {
if (optional) {
success()
resolve(null)
} else {
failure()
reject()
}
}
function success() {
statusCell.textContent = ``
statusCell.style.color = splash.getColor(`success`)
titleCell.textContent = title
titleCell.style.fontWeight = `bold`
titleCell.parentNode.style.backgroundColor = splash.getColor(`foreground`)
titleCell.parentNode.style.color = splash.getColor(`background`)
}
function failure() {
statusCell.textContent = ``
statusCell.style.color = splash.getColor(`failure`)
titleCell.textContent = title
titleCell.style.fontWeight = `bold`
titleCell.parentNode.style.backgroundColor = splash.getColor(`foreground`)
titleCell.parentNode.style.color = splash.getColor(`failure`)
}
xhr.send()
})
}
function keyevent(resolve) {
return function (e) {
if ((e.keycode || e.which) == 32) {
e.preventDefault()
resolve()
}
}
}
const resizeCanvas = function (canvas, scale, resolution) {
if (scale && resolution) {
// optimizeSpeed is the standardized value. different
// browsers support different values they will all ignore
// values that they don't understand.
canvas.style.imageRendering = `-moz-crisp-edges`
canvas.style.imageRendering = `-o-crisp-edges`
canvas.style.imageRendering = `-webkit-optimize-contrast`
canvas.style.imageRendering = `optimize-contrast`
canvas.style.imageRendering = `crisp-edges`
canvas.style.imageRendering = `pixelated`
canvas.style.imageRendering = `optimizeSpeed`
canvas.style.width = `${resolution.width * scale}px`
canvas.style.height = `${resolution.height * scale}px`
canvas.width = resolution.width
canvas.height = resolution.height
}
}
function setupSplash(canvas, splash) {
splash.splashElt = document.getElementById(`doseeSplashScreen`)
if (!splash.splashElt) {
splash.splashElt = document.createElement(`div`)
splash.splashElt.setAttribute(`id`, `doseeSplashScreen`)
splash.splashElt.style.position = `absolute`
splash.splashElt.style.top = `${canvas.offsetTop}px`
splash.splashElt.style.left = `${canvas.offsetLeft}px`
splash.splashElt.style.width = `${canvas.offsetWidth}px`
splash.splashElt.style.color = splash.getColor(`foreground`)
splash.splashElt.style.backgroundColor = splash.getColor(`background`)
canvas.parentElement.appendChild(splash.splashElt)
}
splash.splashimg.setAttribute(`id`, `doseeSplashImg`)
splash.splashimg.style.display = `block`
splash.splashimg.style.marginLeft = `auto`
splash.splashimg.style.marginRight = `auto`
splash.splashElt.appendChild(splash.splashimg)
splash.titleElt = document.createElement(`span`)
splash.titleElt.setAttribute(`id`, `doseeSplashTitle`)
splash.titleElt.style.display = `block`
splash.titleElt.style.width = `100%`
splash.titleElt.style.marginTop = `1em`
splash.titleElt.style.marginBottom = `1em`
splash.titleElt.style.textAlign = `center`
splash.titleElt.style.font = `24px sans-serif`
splash.titleElt.textContent = ``
splash.splashElt.appendChild(splash.titleElt)
let table = document.getElementById(`doseeProgressIndicator`)
if (!table) {
table = document.createElement(`table`)
table.setAttribute(`id`, `doseeProgressIndicator`)
table.style.width = `50%`
table.style.color = splash.getColor(`foreground`)
table.style.backgroundColor = splash.getColor(`background`)
table.style.marginLeft = `auto`
table.style.marginRight = `auto`
table.style.borderCollapse = `separate`
table.style.borderSpacing = `2px`
splash.splashElt.appendChild(table)
}
splash.table = table
}
splash.setTitle = function (title) {
splash.titleElt.textContent = title
}
splash.hide = function () {
splash.splashElt.style.display = `none`
}
splash.getColor = function (name) {
return name in splash.colors ? splash.colors[name] : defaultSplashColors[name]
}
const addRow = function (table) {
const row = table.insertRow(-1)
row.style.textAlign = `center`
const cell = row.insertCell(-1)
cell.style.position = `relative`
const titleCell = document.createElement(`span`)
titleCell.textContent = ``
titleCell.style.verticalAlign = `center`
titleCell.style.minHeight = `24px`
cell.appendChild(titleCell)
const statusCell = document.createElement(`span`)
statusCell.style.position = `absolute`
statusCell.style.left = `0`
statusCell.style.paddingLeft = `0.5em`
cell.appendChild(statusCell)
return [titleCell, statusCell]
}
const drawsplash = function () {
canvas.setAttribute(`moz-opaque`, ``)
if (!splash.splashimg.src) {
splash.splashimg.src = `images/floppy_disk_icon-180x180.png`
}
}
function attach_script(js_url) {
if (js_url) {
const head = document.getElementsByTagName(`head`)[0]
const newScript = document.createElement(`script`)
newScript.type = `text/javascript`
newScript.src = js_url
head.appendChild(newScript)
}
}
function getpointerlockenabler() {
return canvas.requestPointerLock || canvas.mozRequestPointerLock || canvas.webkitRequestPointerLock
}
function getfullscreenenabler() {
return canvas.webkitRequestFullScreen || canvas.mozRequestFullScreen || canvas.requestFullScreen
}
this.isfullscreensupported = function () {
return !!(getfullscreenenabler())
}
function setupFullScreen() {
const fullScreenChangeHandler = function () {
if (!(document.mozFullScreenElement || document.fullScreenElement)) {
resizeCanvas(canvas, scale, cssResolution, aspectRatio)
}
}
if (`onfullscreenchange` in document) {
document.addEventListener(`fullscreenchange`, fullScreenChangeHandler)
} else if (`onmozfullscreenchange` in document) {
document.addEventListener(`mozfullscreenchange`, fullScreenChangeHandler)
} else if (`onwebkitfullscreenchange` in document) {
document.addEventListener(`webkitfullscreenchange`, fullScreenChangeHandler)
}
}
this.requestFullScreen = function () {
Module.requestFullScreen(1, 0)
}
/**
* Prevents page navigation keys such as page up/page down from
* moving the page while the user is playing.
*/
function blockSomeKeys() {
function keypress(e) {
if (e.which >= 33 && e.which <= 40) {
e.preventDefault()
return false
}
return true
}
window.onkeydown = keypress
}
/**
* Disables the right click menu for the given element.
*/
function disableRightClickContextMenu(element) {
element.addEventListener(`contextmenu`,
function (e) {
if (e.button == 2) {
// Block right-click menu thru preventing default action.
e.preventDefault()
}
})
}
}
/**
* misc
*/
function BFSOpenZip(loadedData) {
return new BrowserFS.FileSystem.ZipFS(loadedData)
}
// This is such a hack. We're not calling the BrowserFS api
// 'correctly', so we have to synthesize these flags ourselves
const flag_r = {
isReadable: function () { return true },
isWriteable: function () { return false },
isTruncating: function () { return false },
isAppendable: function () { return false },
isSynchronous: function () { return false },
isExclusive: function () { return false },
pathExistsAction: function () { return 0 },
pathNotExistsAction: function () { return 1 },
}
const flag_w = {
isReadable: function () { return false },
isWriteable: function () { return true },
isTruncating: function () { return false },
isAppendable: function () { return false },
isSynchronous: function () { return false },
isExclusive: function () { return false },
pathExistsAction: function () { return 0 },
pathNotExistsAction: function () { return 3 },
}
/**
* Searches for dosbox.conf, and moves it to '/dosbox.conf'
so dosbox uses it.
*/
function moveConfigToRoot(fs) {
let dosboxConfPath = null
// Recursively search for dosbox.conf.
function searchDirectory(dirPath) {
fs.readdirSync(dirPath).forEach(function (item) {
if (dosboxConfPath) return
// Avoid infinite recursion by ignoring these entries, which exist at
// the root.
if (item === `.` || item === `..`) return
// Append `/` between dirPath and the item's name... unless dirPath
// already ends in it (which always occurs if dirPath is the root, `/`).
const itemPath = dirPath + (dirPath[dirPath.length - 1] !== `/` ? `/` : ``) + item, itemStat = fs.statSync(itemPath)
if (itemStat.isDirectory(itemStat.mode)) {
searchDirectory(itemPath)
} else if (item === `dosbox.conf`) {
dosboxConfPath = itemPath
}
})
}
searchDirectory(`/`)
if (dosboxConfPath !== null) {
fs.writeFileSync(`/dosbox.conf`, fs.readFileSync(dosboxConfPath, null, flag_r), null, flag_w, 0x1a4)
}
}
function extend(a, b) {
if (a === null) return b
if (b === null) return a
const ta = typeof a,
tb = typeof b
if (ta !== tb) {
if (ta === `undefined`) return b
if (tb === `undefined`) return a
throw new Error(`Cannot extend an ${ta} with an ${tb}`)
}
if (Array.isArray(a)) return a.concat(b)
if (ta === `object`) {
Object.keys(b).forEach(function (k) { a[k] = extend(a[k], b[k]) })
return a
}
return b
}
document.getElementById(`doseeVersion`).innerHTML = ` version ${doseeVersion}`
window.DoseeLoader = DoseeLoader
window.Emulator = Emulator
})(typeof Promise === `undefined` ? ES6Promise.Promise : Promise)

BIN
dragglex_loader.zip Normal file

Binary file not shown.

28
emulator/dosee-core.js Normal file

File diff suppressed because one or more lines are too long

BIN
emulator/dosee-core.mem Normal file

Binary file not shown.

24
fetch-libs.sh Normal file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
BFS="https://github.com/jvilk/BrowserFS/releases/download/v1.4.3/browserfs.min.js"
ZFS="https://github.com/jvilk/browserfs-zipfs-extras/releases/download/v1.0.1/browserfs-zipfs-extras.js"
MAP="https://github.com/jvilk/browserfs-zipfs-extras/releases/download/v1.0.1/browserfs-zipfs-extras.js.map"
FULL="https://raw.githubusercontent.com/sindresorhus/screenfull.js/gh-pages/dist/screenfull.min.js"
SAVE="https://raw.githubusercontent.com/eligrey/FileSaver.js/master/src/FileSaver.js"
CTB="https://raw.githubusercontent.com/eligrey/canvas-toBlob.js/master/canvas-toBlob.js"
echo "Fetching BrowserFS"
wget -nc -O libs/browserfs.min.js $BFS
echo "Fetching BrowserFS ZipFS"
wget -nc -O libs/browserfs-zipfs-extras.js $ZFS
wget -nc -O libs/browserfs-zipfs-extras.js.map $MAP
echo "Fetching screenfull"
wget -nc -O libs/screenfull.min.js $FULL
echo "Fetching FileSaver (needs to be minified)"
wget -nc -O libs/FileSaver.min.js $SAVE
echo "Fetching canvas-toBlob (needs to be minified)"
wget -nc -O libs/canvas-toBlob.min.js $CTB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

231
index.html Normal file
View File

@ -0,0 +1,231 @@
<!doctype html>
<html lang="en">
<!--
Archive.org
DOSBox version 8fedaa0 built with Emscripten 1.37.3 04255b4
Copyright 2002-2015 DOSBox Team, published under GNU GPL.
CONFIG: Generating default configuration.
Writing it to /home/web_user/.dosbox/dosbox-SVN.conf
CONFIG:Loading primary settings from config file /home/web_user/.dosbox/dosbox-SVN.conf
SDL:Current window pixel format: SDL_PIXELFORMAT_RGB888
MIDI: Opened device:none
DOSBox has switched to max cycles, because of the setting: cycles=auto.
If the game runs too fast, try a fixed cycles amount in DOSBox's options.
Emulation aborted due to nested emulation timeout.
Local:
DOSBox version 30e85e1M built with Emscripten 1.37.0 6dc4ac5
Copyright 2002-2015 DOSBox Team, published under GNU GPL.
CONFIG:Loading primary settings from config file /dos/s/render.con
CONFIG:Loading additional settings from config file /dos/s/cpu-auto.con
CONFIG:Loading additional settings from config file /dos/s/sb16.con
CONFIG:Loading additional settings from config file /dos/s/vgaonly.con
SDL:Current window pixel format: SDL_PIXELFORMAT_RGB888
MIDI: Opened device:none
-->
<head>
<meta charset="utf-8">
<title>DOSee running example</title>
<meta name="description" content="DOSee">
<meta name="author" content="Ben Garrett">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- DOSee initialisation options -->
<meta name="dosee:capname" content="b12599c.png">
<meta name="dosee:filename" content="dragglex_loader.zip">
<meta name="dosee:gamefilepath" content="dragglex_loader.zip">
<meta name="dosee:gusaudio" content="false">
<meta name="dosee:resolution" content="640, 480">
<meta name="dosee:startexe" content="DRAGGLEX.EXE">
<meta name="dosee:utils" content="false">
<!--- Preloading content to for page load performance improvement -->
<!-- https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content -->
<!-- <link rel="preload" href="emulator/dosee-core.js" as="script">
<link rel="preload" href="emulator/dosee-core.mem" as="fetch" type="application/octet-stream">
<link rel="preload" href="disk_drives/s_drive.zip" as="fetch" type="application/zip">
<link rel="preload" href="libs/browserfs.min.js" as="script">
<link rel="preload" href="libs/browserfs-zipfs-extras.js" as="script">
<link rel="preload" href="dosee-loader.js" as="script">
<link rel="preload" href="libs/screenfull.min.js" as="script">
<link rel="preload" href="dosee-functions.js" as="script">
<link rel="preload" href="libs/FileSaver.min.js" as="script">
<link rel="preload" href="libs/canvas-toBlob.min.js" as="script"> -->
<!-- Javascripts -->
<script src="index.js" defer></script>
<!-- "minimal, responsive, style-agnostic CSS framework" https://minicss.org/docs -->
<link rel="stylesheet" href="libs/mini.min.css">
</head>
<body>
<p>DOSee</p>
<hr>
<div class="container">
<div class="row">
<div class="col-sm">Emulating ... Something</div>
</div>
</div>
<div id="doseeCrashed">Oops!</div>
<p id="doseeSlowLoad">
<small class="text-warning"> If the emulation is taking too long to load,
<a href="#XMLFormat(dosee.url)#">you can turn it off</a>.</small>
</p>
<canvas id="doseeCanvas" class="rounded" style="width:640px; height: 480px; background-color: #000"></canvas>
<header id="doseeTabs">
<a href="#" id="hwButton" class="button tabtoggle">Hardware</a>
<a href="#" id="optButton" class="button tabtoggle">Options</a>
<a href="#" class="button tabtoggle">Help</a>
<a href="#" class="button" id="doseeFullScreen">Fullscreen</a>
<a href="#" class="button" id="doseeCaptureScreen">Capture</a>
<a href="#" class="button" id="doseereboot">Reboot</a>
</header>
<form id="hardware">
<fieldset>
<legend>CPU Speed</legend>
<label for="dosspeed2">
<input type="radio" name="dosspeed" id="dosspeed2" value="max"> maximum (80486)
</label>
<label for="dosspeed3">
<input type="radio" name="dosspeed" id="dosspeed3" value="386"> medium (80386)
</label>
<label for="dosspeed4">
<input type="radio" name="dosspeed" id="dosspeed4" value="8086"> slow (8086)
</label>
<label for="dosspeed1">
<input type="radio" name="dosspeed" id="dosspeed1" value="auto">
<u>automatic</u>
</label>
</fieldset>
<fieldset>
<legend>Graphics</legend>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine1" value="svga"> SuperVGA
</label>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine2" value="vga">
<u>VGA</u>
</label>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine3" value="ega"> EGA
</label>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine4" value="tandy"> Tandy
</label>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine5" value="cga"> CGA
</label>
<label class="radio-inline">
<input type="radio" name="dosmachine" id="dosmachine6" value="herc"> Hercules
</label>
</fieldset>
<fieldset>
<legend>Audio</legend>
<label class="radio-inline">
<input type="radio" name="dosaudio" id="dosaudio1" value="gus"> Gravis Ultrasound
</label>
<label class="radio-inline">
<input type="radio" name="dosaudio" id="dosaudio4" value="covox"> Covox
<small>also Disney Sound Source/DA Converter</small>
</label>
<label class="radio-inline">
<input type="radio" name="dosaudio" id="dosaudio2" value="sb16">
<u>Sound Blaster 16</u>
</label>
<label class="radio-inline">
<input type="radio" name="dosaudio" id="dosaudio3" value="sb1"> Sound Blaster 1.0
</label>
<label class="radio-inline">
<input type="radio" name="dosaudio" id="dosaudio5" value="none"> none
</label>
</fieldset>
<input type="submit" class="small primary" value="Apply changes">
</form>
<form id="options">
<p>Changes will not be applied until this browser tab has been refreshed</p>
<hr>
<div class="checkbox">
<label>
<input type="checkbox" id="doseeAutoRun"> Automatically start DOS emulation
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="doseeAspect"> Disable aspect correction
<small class="text-muted">For sharper DOS ASCII/ANSI text</small>
</label>
</div>
<hr>
<div class="form-group">
<label for="inputEmail3" class="col-sm-12 control-label">SuperVGA real-time graphic effect
<br>
<small class="text-danger" id="svgaEffectsMsg">Only works when Hardware 🡒 Graphics = SuperVGA</small>
</label>
<div class="col-sm-12">
<div class="radio">
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale0" value="none"> None
</label>
<br>
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale5" value="advinterp3x"> Advanced interpolation
<small class="text-muted">advinterp3x</small>
</label>
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale4" value="hq3x"> High Quality 3 magnification
<small class="text-muted">hq3x</small>
</label>
<br>
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale3" value="rgb3x"> RGB
<small class="text-muted">rgb3x</small>
</label>
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale1" value="super2xsai"> Super scale and interpolation
<small class="text-muted">super2xsai</small>
</label>
<label class="radio-inline">
<input type="radio" name="dosscale" id="dosscale2" value="tv3x"> Television
<small class="text-muted">tv3x</small>
</label>
</div>
</div>
</div>
<div id="helpBlock" class="help-block">
<p>
<i class="fal fa-info-circle"></i>
<a href="https://www.dosbox.com/wiki/Scaler">Graphic effect comparisons</a>
</p>
</div>
</form>
<footer>© 2018 - Ben Garrett |
<a href="">GitHub Repo</a>
<p>
<small>DOSee
<span id="doseeVersion"></span>, built on The Emularity, EM-DOSBox and DOSBox. Capture screenshot and save function built on
<a href="https://github.com/eligrey/canvas-toBlob.js">canvas-toBlob.js</a>.</small>
</p>
</footer>
<!-- these javascripts are placed at end of the page for a better user load page experience -->
<!-- they need to be loaded in this sequence and will not work with async or deferred loading -->
<!-- dosee loader -->
<script src="dosee-loader.js"></script>
<!-- browserfs -->
<script src="libs/browserfs.min.js"></script>
<!-- browserfs zipfs -->
<script src="libs/browserfs-zipfs-extras.js"></script>
<!-- screenfull -->
<script src="libs/screenfull.min.js"></script>
<!-- dosee functions -->
<script src="dosee-functions.js"></script>
<!-- dosee initialisation -->
<script src="dosee-init.js"></script>
</body>
</html>

26
index.js Normal file
View File

@ -0,0 +1,26 @@
`use strict`
{
(function () {
const hw = document.getElementById(`hardware`)
const opt = document.getElementById(`options`)
const hwBut = document.getElementById(`hwButton`)
const optBut = document.getElementById(`optButton`)
console.info(`index.js v1.0 loaded`)
// document.getElementById(`hardware`)
hwBut.onclick = function () {
resetMenu()
hw.style.display = "block"
}
optBut.onclick = function () {
resetMenu()
opt.style.display = "block"
}
resetMenu = function () {
hw.style.display = "none"
opt.style.display = "none"
}
})()
}

182
libs/FileSaver.min.js vendored Normal file
View File

@ -0,0 +1,182 @@
/* FileSaver.js
* A saveAs() FileSaver implementation.
* 1.3.8
* 2018-03-22 14:03:47
*
* By Eli Grey, https://eligrey.com
* License: MIT
* See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/
/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/src/FileSaver.js */
export var saveAs = saveAs || (function(view) {
"use strict";
// IE <10 is explicitly unsupported
if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
return;
}
var
doc = view.document
// only get URL when necessary in case Blob.js hasn't overridden it yet
, get_URL = function() {
return view.URL || view.webkitURL || view;
}
, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
, can_use_save_link = "download" in save_link
, click = function(node) {
var event = new MouseEvent("click");
node.dispatchEvent(event);
}
, is_safari = /constructor/i.test(view.HTMLElement) || view.safari
, is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
, setImmediate = view.setImmediate || view.setTimeout
, throw_outside = function(ex) {
setImmediate(function() {
throw ex;
}, 0);
}
, force_saveable_type = "application/octet-stream"
// the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
, arbitrary_revoke_timeout = 1000 * 40 // in ms
, revoke = function(file) {
var revoker = function() {
if (typeof file === "string") { // file is an object URL
get_URL().revokeObjectURL(file);
} else { // file is a File
file.remove();
}
};
setTimeout(revoker, arbitrary_revoke_timeout);
}
, dispatch = function(filesaver, event_types, event) {
event_types = [].concat(event_types);
var i = event_types.length;
while (i--) {
var listener = filesaver["on" + event_types[i]];
if (typeof listener === "function") {
try {
listener.call(filesaver, event || filesaver);
} catch (ex) {
throw_outside(ex);
}
}
}
}
, auto_bom = function(blob) {
// prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
}
return blob;
}
, FileSaver = function(blob, name, no_auto_bom) {
if (!no_auto_bom) {
blob = auto_bom(blob);
}
// First try a.download, then web filesystem, then object URLs
var
filesaver = this
, type = blob.type
, force = type === force_saveable_type
, object_url
, dispatch_all = function() {
dispatch(filesaver, "writestart progress write writeend".split(" "));
}
// on any filesys errors revert to saving with object URLs
, fs_error = function() {
if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
// Safari doesn't allow downloading of blob urls
var reader = new FileReader();
reader.onloadend = function() {
var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
var popup = view.open(url, '_blank');
if(!popup) view.location.href = url;
url=undefined; // release reference before dispatching
filesaver.readyState = filesaver.DONE;
dispatch_all();
};
reader.readAsDataURL(blob);
filesaver.readyState = filesaver.INIT;
return;
}
// don't create more object URLs than needed
if (!object_url) {
object_url = get_URL().createObjectURL(blob);
}
if (force) {
view.location.href = object_url;
} else {
var opened = view.open(object_url, "_blank");
if (!opened) {
// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
view.location.href = object_url;
}
}
filesaver.readyState = filesaver.DONE;
dispatch_all();
revoke(object_url);
}
;
filesaver.readyState = filesaver.INIT;
if (can_use_save_link) {
object_url = get_URL().createObjectURL(blob);
setImmediate(function() {
save_link.href = object_url;
save_link.download = name;
click(save_link);
dispatch_all();
revoke(object_url);
filesaver.readyState = filesaver.DONE;
}, 0);
return;
}
fs_error();
}
, FS_proto = FileSaver.prototype
, saveAs = function(blob, name, no_auto_bom) {
return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
}
;
// IE 10+ (native saveAs)
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
return function(blob, name, no_auto_bom) {
name = name || blob.name || "download";
if (!no_auto_bom) {
blob = auto_bom(blob);
}
return navigator.msSaveOrOpenBlob(blob, name);
};
}
// todo: detect chrome extensions & packaged apps
//save_link.target = "_blank";
FS_proto.abort = function(){};
FS_proto.readyState = FS_proto.INIT = 0;
FS_proto.WRITING = 1;
FS_proto.DONE = 2;
FS_proto.error =
FS_proto.onwritestart =
FS_proto.onprogress =
FS_proto.onwrite =
FS_proto.onabort =
FS_proto.onerror =
FS_proto.onwriteend =
null;
return saveAs;
}(
typeof self !== "undefined" && self
|| typeof window !== "undefined" && window
|| this
));

File diff suppressed because it is too large Load Diff

14
libs/browserfs.min.js vendored Normal file

File diff suppressed because one or more lines are too long

125
libs/canvas-toBlob.min.js vendored Normal file
View File

@ -0,0 +1,125 @@
/* canvas-toBlob.js
* A canvas.toBlob() implementation.
* 2016-05-26
*
* By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
* License: MIT
* See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md
*/
/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
(function(view) {
"use strict";
var
Uint8Array = view.Uint8Array
, HTMLCanvasElement = view.HTMLCanvasElement
, canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype
, is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
, to_data_url = "toDataURL"
, base64_ranks
, decode_base64 = function(base64) {
var
len = base64.length
, buffer = new Uint8Array(len / 4 * 3 | 0)
, i = 0
, outptr = 0
, last = [0, 0]
, state = 0
, save = 0
, rank
, code
, undef
;
while (len--) {
code = base64.charCodeAt(i++);
rank = base64_ranks[code-43];
if (rank !== 255 && rank !== undef) {
last[1] = last[0];
last[0] = code;
save = (save << 6) | rank;
state++;
if (state === 4) {
buffer[outptr++] = save >>> 16;
if (last[1] !== 61 /* padding character */) {
buffer[outptr++] = save >>> 8;
}
if (last[0] !== 61 /* padding character */) {
buffer[outptr++] = save;
}
state = 0;
}
}
}
// 2/3 chance there's going to be some null bytes at the end, but that
// doesn't really matter with most image formats.
// If it somehow matters for you, truncate the buffer up outptr.
return buffer;
}
;
if (Uint8Array) {
base64_ranks = new Uint8Array([
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
]);
}
if (HTMLCanvasElement && (!canvas_proto.toBlob || !canvas_proto.toBlobHD)) {
if (!canvas_proto.toBlob)
canvas_proto.toBlob = function(callback, type /*, ...args*/) {
if (!type) {
type = "image/png";
} if (this.mozGetAsFile) {
callback(this.mozGetAsFile("canvas", type));
return;
} if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) {
callback(this.msToBlob());
return;
}
var
args = Array.prototype.slice.call(arguments, 1)
, dataURI = this[to_data_url].apply(this, args)
, header_end = dataURI.indexOf(",")
, data = dataURI.substring(header_end + 1)
, is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
, blob
;
if (Blob.fake) {
// no reason to decode a data: URI that's just going to become a data URI again
blob = new Blob
if (is_base64) {
blob.encoding = "base64";
} else {
blob.encoding = "URI";
}
blob.data = data;
blob.size = data.length;
} else if (Uint8Array) {
if (is_base64) {
blob = new Blob([decode_base64(data)], {type: type});
} else {
blob = new Blob([decodeURIComponent(data)], {type: type});
}
}
callback(blob);
};
if (!canvas_proto.toBlobHD && canvas_proto.toDataURLHD) {
canvas_proto.toBlobHD = function() {
to_data_url = "toDataURLHD";
var blob = this.toBlob();
to_data_url = "toDataURL";
return blob;
}
} else {
canvas_proto.toBlobHD = canvas_proto.toBlob;
}
}
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

1
libs/mini.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
libs/screenfull.min.js vendored Normal file
View File

@ -0,0 +1,7 @@
/*!
* screenfull
* v3.3.2 - 2017-10-27
* (c) Sindre Sorhus; MIT License
*/
!function(){"use strict";var a="undefined"!=typeof window&&void 0!==window.document?window.document:{},b="undefined"!=typeof module&&module.exports,c="undefined"!=typeof Element&&"ALLOW_KEYBOARD_INPUT"in Element,d=function(){for(var b,c=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],d=0,e=c.length,f={};d<e;d++)if((b=c[d])&&b[1]in a){for(d=0;d<b.length;d++)f[c[0][d]]=b[d];return f}return!1}(),e={change:d.fullscreenchange,error:d.fullscreenerror},f={request:function(b){var e=d.requestFullscreen;b=b||a.documentElement,/ Version\/5\.1(?:\.\d+)? Safari\//.test(navigator.userAgent)?b[e]():b[e](c&&Element.ALLOW_KEYBOARD_INPUT)},exit:function(){a[d.exitFullscreen]()},toggle:function(a){this.isFullscreen?this.exit():this.request(a)},onchange:function(a){this.on("change",a)},onerror:function(a){this.on("error",a)},on:function(b,c){var d=e[b];d&&a.addEventListener(d,c,!1)},off:function(b,c){var d=e[b];d&&a.removeEventListener(d,c,!1)},raw:d};if(!d)return void(b?module.exports=!1:window.screenfull=!1);Object.defineProperties(f,{isFullscreen:{get:function(){return Boolean(a[d.fullscreenElement])}},element:{enumerable:!0,get:function(){return a[d.fullscreenElement]}},enabled:{enumerable:!0,get:function(){return Boolean(a[d.fullscreenEnabled])}}}),b?module.exports=f:window.screenfull=f}();