Commit preliminary 0.00a emulator files for Processor and Control Console cloned from retro-205.
3422
emulator/B220Processor.js
Normal file
10
index.html
@@ -31,11 +31,11 @@
|
||||
<h2>Main Links</h2>
|
||||
|
||||
<ul>
|
||||
<!--
|
||||
<li><a href="./webUI/D220.html">220 Emulator Home Page</a>
|
||||
<li><a href="./webUI/B220.html">220 Emulator Home Page</a>
|
||||
<br>The home page from which you can start the emulator and open the control panels.
|
||||
|
||||
<li><a href="./webSite/HelpMenu.html">Help & Getting Started</a>
|
||||
<!--
|
||||
<li><a href="./webSite/HelpMenu.html">Help & Getting Started</a>
|
||||
<br>A menu of information resources to assist you in setting up and operating the emulator.
|
||||
-->
|
||||
|
||||
@@ -66,10 +66,10 @@
|
||||
|
||||
<p>
|
||||
<div id=footerDiv>
|
||||
Copyright (c) 2016, Paul Kimpel • Licensed under the <a href="LICENSE.txt">MIT License</a>
|
||||
Copyright (c) 2017, Paul Kimpel • Licensed under the <a href="LICENSE.txt">MIT License</a>
|
||||
</div>
|
||||
<div id=lastModDiv>Revised
|
||||
2016-12-17
|
||||
2016-12-25
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
75
webUI/B220.css
Normal file
@@ -0,0 +1,75 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220.css
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator home page style sheet.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 D205.css.
|
||||
***********************************************************************/
|
||||
|
||||
BODY {
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 10pt;
|
||||
background-color: white;
|
||||
color: black;
|
||||
height: 100%;
|
||||
margin: 4px;
|
||||
padding: 4px}
|
||||
|
||||
H1 {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
font-size: 14pt;
|
||||
font-weight: bold}
|
||||
|
||||
#VersionDiv {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
text-align: right}
|
||||
#StatusMsg {
|
||||
text-align: center;
|
||||
font-size: 85%;
|
||||
color: blue}
|
||||
#InfoTable {
|
||||
margin-top: 0;
|
||||
width: 100%}
|
||||
#CenteredBody {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 15%;
|
||||
bottom: 25%;
|
||||
left: 0;
|
||||
right: 0}
|
||||
#B220Image {
|
||||
box-shadow: 12px 12px 12px gray;
|
||||
height: 80%}
|
||||
#StartUpBtn,
|
||||
#ConfigureBtn {
|
||||
margin-top: 2em;
|
||||
background-color: #246;
|
||||
color: white;
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-weight: normal;
|
||||
font-size: 12pt;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 0.5em;
|
||||
border-radius: 16px;
|
||||
border: 2px solid #999}
|
||||
#StartUpBtn[disabled],
|
||||
#ConfigureBtn[disabled] {
|
||||
background-color: #468;
|
||||
color: #999;
|
||||
border-color: #666}
|
||||
#PageFooter {
|
||||
margin-top: 2em;
|
||||
margin-left: calc(50% - 3in);
|
||||
margin-right: calc(50% - 3in);
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
text-align: center}
|
||||
85
webUI/B220.html
Normal file
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html manifest="D205Manifest.appcache">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>retro-220 Emulator</title>
|
||||
<!--
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220.html
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator home page.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 D205.html.
|
||||
***********************************************************************/
|
||||
-->
|
||||
<meta name="Author" content="Paul Kimpel">
|
||||
<meta http-equiv="Content-Script-Type" content="text/javascript">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
|
||||
<link id=homeStyleSheet rel=stylesheet type="text/css" href="B220.css">
|
||||
|
||||
<script src="./B220PanelUtil.js"></script> <!-- must be first -->
|
||||
<script src="./B220Util.js"></script>
|
||||
<script src="./B220SetCallback.js"></script>
|
||||
<script src="./B220SystemConfig.js"></script>
|
||||
|
||||
<script src="../emulator/B220Processor.js"></script>
|
||||
|
||||
<script src="./B220ControlConsole.js"></script>
|
||||
|
||||
<!--
|
||||
<script src="./B220ConsoleOutput.js"></script>
|
||||
<script src="./B220ConsoleInput.js"></script>
|
||||
|
||||
<script src="./B220CardatronInput.js"></script>
|
||||
<script src="./B220CardatronOutput.js"></script>
|
||||
<script src="./B220CardatronControl.js"></script>
|
||||
|
||||
<script src="./B220DataFile.js"></script>
|
||||
<script src="./B220MagTapeDrive.js"></script>
|
||||
<script src="./B220MagTapeControl.js"></script>
|
||||
-->
|
||||
|
||||
<script src="./B220.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id=VersionDiv>
|
||||
<img id=Retro220Logo src="./resources/retro-220-Logo.png" alt="retro-220 Logo">
|
||||
<div id=EmulatorVersion></div>
|
||||
</div>
|
||||
<h1>Burroughs 220 Emulator</h1>
|
||||
<hr>
|
||||
<table id=InfoTable>
|
||||
<tr>
|
||||
<td><a href="https://github.com/pkimpel/retro-220/" target="_blank">
|
||||
Open-Source Project</a>
|
||||
<td id=StatusMsg>
|
||||
<td class=rj><a href="http://datatron.blogspot.com/" target="_blank">
|
||||
Burroughs 205 & 220 Blog</a>
|
||||
</table>
|
||||
|
||||
<div id=CenteredBody>
|
||||
<img id=B220Image src="./resources/B220-Site.jpg"
|
||||
alt="Burroughs 220 System, ca. 1960">
|
||||
<br>
|
||||
<button id=StartUpBtn>
|
||||
Start the Emulator
|
||||
</button>
|
||||
|
||||
<button id=ConfigureBtn>
|
||||
Configure System
|
||||
</button>
|
||||
|
||||
<div id=PageFooter>
|
||||
<i>(Caution: Closing this window, minimizing it, or placing the page on a non-active tab may cause the emulator to run very slowly)</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
175
webUI/B220.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator top page routines.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205/D205.js.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
window.addEventListener("load", function() {
|
||||
var config = new B220SystemConfig();// system configuration object
|
||||
var devices = {}; // hash of I/O devices for the Processor
|
||||
var processor; // the Processor object
|
||||
var statusMsgTimer = 0; // status message timer control cookie
|
||||
|
||||
/**************************************/
|
||||
function systemShutDown() {
|
||||
/* Powers down the Processor and shuts down all of the panels and I/O devices */
|
||||
var e;
|
||||
|
||||
processor.powerDown();
|
||||
for (e in devices) {
|
||||
if (devices[e]) {
|
||||
devices[e].shutDown();
|
||||
devices[e] = null;
|
||||
}
|
||||
}
|
||||
|
||||
processor = null;
|
||||
document.getElementById("StartUpBtn").disabled = false;
|
||||
document.getElementById("StartUpBtn").focus();
|
||||
document.getElementById("ConfigureBtn").disabled = false;
|
||||
config.flush();
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function systemStartup(ev) {
|
||||
/* Establishes the system components */
|
||||
var u;
|
||||
var x;
|
||||
|
||||
ev.target.disabled = true;
|
||||
document.getElementById("ConfigureBtn").disabled = true;
|
||||
|
||||
processor = new B220Processor(config, devices);
|
||||
|
||||
/********************
|
||||
if (config.getNode("Cardatron.hasCardatron")) {
|
||||
devices.CardatronControl = new B220CardatronControl(processor);
|
||||
} else {
|
||||
devices.CardatronControl = null;
|
||||
}
|
||||
|
||||
if (config.getNode("MagTape.hasMagTape")) {
|
||||
devices.MagTapeControl = new B220MagTapeControl(processor);
|
||||
} else {
|
||||
devices.MagTapeControl = null;
|
||||
}
|
||||
********************/
|
||||
|
||||
// Control Console must be instantiated last
|
||||
devices.ControlConsole = new B220ControlConsole(processor, systemShutDown);
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function configureSystem(ev) {
|
||||
/* Opens the system configuration UI */
|
||||
|
||||
config.openConfigUI();
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function clearStatusMsg(inSeconds) {
|
||||
/* Delays for "inSeconds" seconds, then clears the StatusMsg element */
|
||||
|
||||
if (statusMsgTimer) {
|
||||
clearTimeout(statusMsgTimer);
|
||||
}
|
||||
|
||||
statusMsgTimer = setTimeout(function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "";
|
||||
statusMsgTimer = 0;
|
||||
}, inSeconds*1000);
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function openDiagPanel(ev) {
|
||||
/* Opens the emulator's diagnostic panel in a new sub-window */
|
||||
var win;
|
||||
|
||||
win = window.open("B220DiagMonitor.html", "DiagPanel",
|
||||
"location=no,scrollbars=no,resizable,width=300,height=500,top=0,left=0");
|
||||
win.global = window; // give it access to our globals.
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function checkBrowser() {
|
||||
/* Checks whether this browser can support the necessary stuff */
|
||||
var missing = "";
|
||||
|
||||
if (!window.ArrayBuffer) {missing += ", ArrayBuffer"}
|
||||
if (!window.DataView) {missing += ", DataView"}
|
||||
if (!window.Blob) {missing += ", Blob"}
|
||||
if (!window.File) {missing += ", File"}
|
||||
if (!window.FileReader) {missing += ", FileReader"}
|
||||
if (!window.FileList) {missing += ", FileList"}
|
||||
if (!window.JSON) {missing += ", JSON"}
|
||||
if (!window.localStorage) {missing += ", LocalStorage"}
|
||||
if (!window.indexedDB) {missing += ", IndexedDB"}
|
||||
if (!window.postMessage) {missing += ", window.postMessage"}
|
||||
if (!(window.performance && "now" in performance)) {missing += ", performance.now"}
|
||||
if (!window.Promise) {missing += ", Promise"}
|
||||
|
||||
if (missing.length == 0) {
|
||||
return true;
|
||||
} else {
|
||||
alert("The emulator cannot run...\n" +
|
||||
"your browser does not support the following features:\n\n" +
|
||||
missing.substring(2));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***** window.onload() outer block *****/
|
||||
|
||||
document.getElementById("StartUpBtn").disabled = true;
|
||||
document.getElementById("EmulatorVersion").textContent = B220Processor.version;
|
||||
if (checkBrowser()) {
|
||||
document.getElementById("Retro220Logo").addEventListener("dblclick", openDiagPanel);
|
||||
document.getElementById("StartUpBtn").disabled = false;
|
||||
document.getElementById("StartUpBtn").addEventListener("click", systemStartup);
|
||||
document.getElementById("StartUpBtn").focus();
|
||||
document.getElementById("ConfigureBtn").disabled = false;
|
||||
document.getElementById("ConfigureBtn").addEventListener("click", configureSystem);
|
||||
|
||||
window.applicationCache.addEventListener("checking", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Checking for emulator update...";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("noupdate", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Emulator version is current.";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("obsolete", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Emulator off-line installation has been disabled.";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("downloading", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Initiating download for emulator update...";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("progress", function(ev) {
|
||||
var text = (ev.loaded && ev.total ? ev.loaded.toString() + "/" + ev.total.toString() : "Unknown number of");
|
||||
document.getElementById("StatusMsg").textContent = text + " resources downloaded thus far...";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("updateready", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Emulator update completed. Reload this page to activate the new version.";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("cached", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Emulator is now installed for off-line use.";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
window.applicationCache.addEventListener("error", function(ev) {
|
||||
document.getElementById("StatusMsg").textContent = "Browser reported error during emulator version check.";
|
||||
clearStatusMsg(15);
|
||||
});
|
||||
}
|
||||
});
|
||||
553
webUI/B220Common.css
Normal file
@@ -0,0 +1,553 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220Common.css
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator common style sheet.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, split from retro-205/D205Common.css
|
||||
***********************************************************************/
|
||||
|
||||
@font-face {
|
||||
font-family: "DejaVuSansMonoBookWeb";
|
||||
src: url("./resources/DejaVuSansMono-webfont.woff") format("woff"),
|
||||
url("./resources/DejaVuSansMono-webfont.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "DejaVuSansWeb";
|
||||
src: url("./resources/DejaVuSans-webfont.woff") format("woff"),
|
||||
url("./resources/DejaVuSans-webfont.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "DejaVuSansWeb";
|
||||
src: url("./resources/DejaVuSans-Bold-webfont.woff") format("woff"),
|
||||
url("./resources/DejaVuSans-Bold-webfont.ttf") format("truetype");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
HTML {
|
||||
height: 100%}
|
||||
|
||||
BODY {
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 10pt;
|
||||
background-color: white;
|
||||
color: black;
|
||||
margin: 4px;
|
||||
padding: 4px}
|
||||
|
||||
BODY.panelBody {
|
||||
position: relative;
|
||||
font-size: 8pt;
|
||||
margin: 0;
|
||||
padding: 0}
|
||||
|
||||
BODY.deviceBody {
|
||||
font-size: 7pt;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #246;
|
||||
color: white}
|
||||
|
||||
H1 {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
font-size: 14pt;
|
||||
font-weight: bold}
|
||||
|
||||
IFRAME.paper {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace;
|
||||
font-size: 8pt;
|
||||
line-height: 120%;
|
||||
color: black;
|
||||
background-color: white}
|
||||
|
||||
PRE {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace}
|
||||
PRE.paper {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 8pt;
|
||||
line-height: 120%}
|
||||
|
||||
INPUT[type=text] {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace;
|
||||
font-size: 8pt}
|
||||
|
||||
DIV.paper {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace;
|
||||
white-space: pre;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: 8pt;
|
||||
line-height: 120%}
|
||||
DIV.topOfForm {
|
||||
page-break-before: always;
|
||||
margin-top: 1px;
|
||||
padding-top: 1px;
|
||||
border-top: 1px dashed black}
|
||||
|
||||
DIV.caption {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
line-height: 100%;
|
||||
text-align: center}
|
||||
|
||||
DIV.lampBox {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 30px;
|
||||
border-top: 1px solid #999;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #666;
|
||||
border-bottom: 1px solid #666;
|
||||
background-color: black}
|
||||
|
||||
DIV.lampButton {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 6px;
|
||||
bottom: 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #CCC;
|
||||
font-size: 6px;
|
||||
line-height: 6px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: black;
|
||||
background-color: white}
|
||||
|
||||
DIV.neonLamp {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
/* border: 2px solid #999; */
|
||||
background-image: radial-gradient(circle, #999, #333)}
|
||||
DIV.neonLit1 {
|
||||
background-image: radial-gradient(circle, #A85, #444)}
|
||||
DIV.neonLit2 {
|
||||
background-image: radial-gradient(circle, #B84, #555)}
|
||||
DIV.neonLit3 {
|
||||
background-image: radial-gradient(circle, #C83, #666)}
|
||||
DIV.neonLit4 {
|
||||
background-image: radial-gradient(circle, #D82, #777)}
|
||||
DIV.neonLit5 {
|
||||
background-image: radial-gradient(circle, #E91, #888)}
|
||||
DIV.neonLit {
|
||||
background-image: radial-gradient(circle, #F93, #F93, #999)}
|
||||
|
||||
DIV.neonLampTopCaption {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
top: -13px;
|
||||
left: -8px;
|
||||
line-height: 100%;
|
||||
font-size: 6px;
|
||||
text-align: center}
|
||||
DIV.neonLampBottomCaption {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
bottom: -10px;
|
||||
left: -8px;
|
||||
font-size: 6px;
|
||||
text-align: center}
|
||||
|
||||
DIV.lampCollar {
|
||||
border: 2px solid #DDD}
|
||||
|
||||
DIV.whiteLamp {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
background-image: radial-gradient(circle, #999, #333)}
|
||||
DIV.whiteLit1 {
|
||||
background-image: radial-gradient(circle, #AAA, #999, #444)}
|
||||
DIV.whiteLit2 {
|
||||
background-image: radial-gradient(circle, #BBB, #AAA, #555)}
|
||||
DIV.whiteLit3 {
|
||||
background-image: radial-gradient(circle, #CCC, #BBB, #666)}
|
||||
DIV.whiteLit4 {
|
||||
background-image: radial-gradient(circle, #DDD, #CCC, #777)}
|
||||
DIV.whiteLit5 {
|
||||
background-image: radial-gradient(circle, #EEE, #DDD, #888)}
|
||||
DIV.whiteLit {
|
||||
background-image: radial-gradient(circle, #FFF, #EEE, #999)}
|
||||
|
||||
DIV.redLamp {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
background-image: radial-gradient(circle, #900, #300)}
|
||||
DIV.redLit1 {
|
||||
background-image: radial-gradient(circle, #A00, #900, #400)}
|
||||
DIV.redLit2 {
|
||||
background-image: radial-gradient(circle, #B00, #A00, #500)}
|
||||
DIV.redLit3 {
|
||||
background-image: radial-gradient(circle, #C00, #B00, #600)}
|
||||
DIV.redLit4 {
|
||||
background-image: radial-gradient(circle, #D00, #C00, #700)}
|
||||
DIV.redLit5 {
|
||||
background-image: radial-gradient(circle, #E00, #D00, #800)}
|
||||
DIV.redLit {
|
||||
background-image: radial-gradient(circle, #F00, #E00, #900)}
|
||||
|
||||
DIV.orangeLamp {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
background-image: radial-gradient(circle, #960, #330)}
|
||||
DIV.orangeLit1 {
|
||||
background-image: radial-gradient(circle, #A63, #963, #430)}
|
||||
DIV.orangeLit2 {
|
||||
background-image: radial-gradient(circle, #B73, #A73, #540)}
|
||||
DIV.orangeLit3 {
|
||||
background-image: radial-gradient(circle, #C73, #B73, #640)}
|
||||
DIV.orangeLit4 {
|
||||
background-image: radial-gradient(circle, #D83, #C83, #750)}
|
||||
DIV.orangeLit5 {
|
||||
background-image: radial-gradient(circle, #E83, #D83, #850)}
|
||||
DIV.orangeLit {
|
||||
background-image: radial-gradient(circle, #F93, #E93, #960)}
|
||||
|
||||
DIV.greenLamp {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 4px;
|
||||
border-radius: 50%;
|
||||
background-image: radial-gradient(circle, #090, #030)}
|
||||
DIV.greenLit1 {
|
||||
background-image: radial-gradient(circle, #0A0, #090, #040)}
|
||||
DIV.greenLit2 {
|
||||
background-image: radial-gradient(circle, #0B0, #0A0, #050)}
|
||||
DIV.greenLit3 {
|
||||
background-image: radial-gradient(circle, #0C0, #0B0, #060)}
|
||||
DIV.greenLit4 {
|
||||
background-image: radial-gradient(circle, #0D0, #0C0, #070)}
|
||||
DIV.greenLit5 {
|
||||
background-image: radial-gradient(circle, #0E0, #0D0, #080)}
|
||||
DIV.greenLit {
|
||||
background-image: radial-gradient(circle, #0F0, #0E0, #090)}
|
||||
|
||||
DIV.coloredLampTopCaption {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
top: -13px;
|
||||
left: -28px;
|
||||
line-height: 100%;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
DIV.coloredLampBottomCaption {
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
bottom: -15px;
|
||||
left: -28px;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
|
||||
DIV.toggleSwitchTopCaption {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
top: -13px;
|
||||
left: -20px;
|
||||
line-height: 100%;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
DIV.toggleSwitchBottomCaption {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
bottom: -15px;
|
||||
left: -20px;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
|
||||
DIV.blackControlKnobTopCaption {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
top: -13px;
|
||||
left: -20px;
|
||||
line-height: 100%;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
DIV.blackControlKnobBottomCaption {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
bottom: -15px;
|
||||
left: -20px;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
text-align: center}
|
||||
|
||||
DIV.panelSurface {
|
||||
position: relative;
|
||||
background-color: #D8C5BC; /* putty #EDEAE8; */
|
||||
color: black}
|
||||
|
||||
DIV.panelRegister {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
background-color: black;
|
||||
border-radius: 4px;
|
||||
border-top: 3px solid #666;
|
||||
border-left: 3px solid #666;
|
||||
border-right: 3px solid #333;
|
||||
border-bottom: 3px solid #333;
|
||||
box-shadow: 3px 3px 2px #999;
|
||||
font-size: 6px}
|
||||
|
||||
DIV.panelDiv {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
background-color: black;
|
||||
border-radius: 4px;
|
||||
border-top: 3px solid #666;
|
||||
border-left: 3px solid #666;
|
||||
border-right: 3px solid #333;
|
||||
border-bottom: 3px solid #333;
|
||||
box-shadow: 3px 3px 2px #999;
|
||||
font-size: 6px}
|
||||
|
||||
DIV.panelCaption {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
height: 5px;
|
||||
font-size: 5pt;
|
||||
border-left: 1px solid white;
|
||||
border-right: 1px solid white;
|
||||
border-top: 1px solid white}
|
||||
|
||||
DIV.boxCaption {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
top: -12px;
|
||||
left: -3px;
|
||||
font-size: 8px;
|
||||
text-align: center}
|
||||
|
||||
SPAN.panelSpan {
|
||||
position: relative;
|
||||
top: -1em;
|
||||
font-size: 5pt;
|
||||
font-weight: bold;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
background-color: #246}
|
||||
|
||||
DIV.panelRegCaption {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
line-height: 18px;
|
||||
border-top: 1px solid #999;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #666;
|
||||
border-bottom: 1px solid #666;
|
||||
color: white;
|
||||
background-color: black}
|
||||
|
||||
SPAN.panelRegSpan {
|
||||
font-size: 18px;
|
||||
vertical-align: middle}
|
||||
|
||||
DIV.panelRegSpacer {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
text-align: center;
|
||||
font-size: 18pt;
|
||||
font-weight: bold;
|
||||
border-top: 1px solid #999;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #666;
|
||||
border-bottom: 1px solid #666;
|
||||
color: white;
|
||||
background-color: black}
|
||||
|
||||
DIV.panelRegClearBar {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
top: 24px;
|
||||
height: calc(100% - 48px);
|
||||
border-top: 1px solid #999;
|
||||
border-left: 1px solid #999;
|
||||
border-right: 1px solid #666;
|
||||
border-bottom: 1px solid #666;
|
||||
color: black;
|
||||
background-color: white}
|
||||
|
||||
DIV.greenButton1 {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #090, #0F0);
|
||||
border-radius: 50%;
|
||||
border: 10px solid #CCC}
|
||||
DIV.redButton1 {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #C00, #F00);
|
||||
border-radius: 50%;
|
||||
border: 10px solid #CCC}
|
||||
DIV.redButton2 {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #C00, #F00);
|
||||
border-radius: 50%;
|
||||
border: 6px solid #CCC}
|
||||
DIV.redButton3 {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #C00, #F00);
|
||||
border-radius: 50%;
|
||||
border: 2px solid #CCC}
|
||||
DIV.blackButton1 {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #000, #333);
|
||||
border-radius: 50%;
|
||||
border: 10px solid #CCC}
|
||||
DIV.blackButton3 {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 4px;
|
||||
background-image: radial-gradient(circle, #000, #333);
|
||||
border-radius: 50%;
|
||||
border: 2px solid #CCC}
|
||||
|
||||
CANVAS.blackControlKnob1 {
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
font-size: 4px}
|
||||
|
||||
BUTTON {
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 8pt;
|
||||
font-weight: normal;
|
||||
line-height: 120%;
|
||||
width: 60px;
|
||||
height: 40px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border: 1px solid #DDD;
|
||||
border-radius: 4px}
|
||||
|
||||
BUTTON.panelLabel {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 18px;
|
||||
color: white;
|
||||
background-color: black;
|
||||
border-radius: 4px;
|
||||
border: 2px solid white;
|
||||
line-height: 5px;
|
||||
font-size: 5px;
|
||||
font-weight: normal}
|
||||
|
||||
BUTTON.large {
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 8pt;
|
||||
font-weight: normal;
|
||||
line-height: 120%;
|
||||
width: 60px;
|
||||
height: 40px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border: 1px solid #DDD;
|
||||
border-radius: 4px}
|
||||
|
||||
BUTTON.greenButton {
|
||||
background-image: radial-gradient(circle, #030, #060);
|
||||
color: white}
|
||||
|
||||
BUTTON.redButton {
|
||||
background-image: radial-gradient(circle, #600, #900);
|
||||
color: white}
|
||||
|
||||
BUTTON.blackButton {
|
||||
background-color: black;
|
||||
color: #999}
|
||||
|
||||
BUTTON.blackLit {
|
||||
color: white}
|
||||
|
||||
BUTTON.greenLit {
|
||||
color: black;
|
||||
background-image: radial-gradient(circle, #0F0, #0F0, #0C0)}
|
||||
|
||||
BUTTON.redLit {
|
||||
color: black;
|
||||
background-image: radial-gradient(circle, #F00, #F00, #C00)}
|
||||
|
||||
BUTTON.blackBorder {
|
||||
border: 1px solid black}
|
||||
|
||||
BUTTON.silverBorder {
|
||||
border: 1px solid #DDD}
|
||||
|
||||
.annunciator {
|
||||
visibility: hidden;
|
||||
white-space: nowrap;
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 7pt;
|
||||
line-height: 100%}
|
||||
.annunciatorLit {
|
||||
visibility: visible}
|
||||
|
||||
.bold {
|
||||
font-weight: bold}
|
||||
.center {
|
||||
text-align: center}
|
||||
.rj {
|
||||
text-align: right}
|
||||
.data {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace;
|
||||
text-align: left}
|
||||
.number {
|
||||
font-family: DejaVuSansMonoBookWeb, monospace;
|
||||
text-align: right}
|
||||
330
webUI/B220ControlConsole.css
Normal file
@@ -0,0 +1,330 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220ControlConsole.css
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator Control Console style sheet.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from D205SupervisoryPanel.css
|
||||
***********************************************************************/
|
||||
|
||||
#BurroughsMeatball {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 6px;
|
||||
height: 36px}
|
||||
|
||||
#BurroughsLogo {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 6px;
|
||||
height: 36px}
|
||||
|
||||
#B220Logo {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 12px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
font-family: Verdana, Arial, Helvetica, DejaVuSansWeb, san-serif;
|
||||
font-size: 36px;
|
||||
font-weight: bold}
|
||||
|
||||
#IntervalTimer {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: calc(50% - 42px);
|
||||
width: 84px;
|
||||
height: 18px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 18px;
|
||||
border-top: 3px solid #666;
|
||||
border-left: 3px solid #666;
|
||||
border-right: 3px solid #333;
|
||||
border-bottom: 3px solid #333;
|
||||
box-shadow: 3px 3px 2px #999;
|
||||
color: white;
|
||||
background-color: black}
|
||||
|
||||
#IntervalTimerResetBtn {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: calc(50% - 82px)}
|
||||
|
||||
#PanelSurface {
|
||||
height: 500px;
|
||||
width: 100%}
|
||||
|
||||
#ControlDiv {
|
||||
left: 832px;
|
||||
top: 48px;
|
||||
width: 288px;
|
||||
height: 128px}
|
||||
|
||||
#AdderDiv {
|
||||
left: 438px;
|
||||
top: 192px;
|
||||
width: 336px;
|
||||
height: 132px}
|
||||
|
||||
#ARegPanel {
|
||||
left: 12px;
|
||||
top: 48px;
|
||||
width: 312px;
|
||||
height: 128px}
|
||||
|
||||
#RRegPanel {
|
||||
left: 372px;
|
||||
top: 48px;
|
||||
width: 312px;
|
||||
height: 128px}
|
||||
|
||||
#DRegPanel {
|
||||
left: 732px;
|
||||
top: 48px;
|
||||
width: 312px;
|
||||
height: 128px}
|
||||
|
||||
#BRegPanel {
|
||||
left: 12px;
|
||||
top: 208px;
|
||||
width: 144px;
|
||||
height: 128px}
|
||||
|
||||
#PRegPanel {
|
||||
left: 180px;
|
||||
top: 208px;
|
||||
width: 144px;
|
||||
height: 128px}
|
||||
|
||||
#CRegPanel {
|
||||
left: 384px;
|
||||
top: 208px;
|
||||
width: 288px;
|
||||
height: 128px}
|
||||
|
||||
#ERegPanel {
|
||||
left: 732px;
|
||||
top: 208px;
|
||||
width: 144px;
|
||||
height: 128px}
|
||||
|
||||
#SRegPanel {
|
||||
left: 900px;
|
||||
top: 208px;
|
||||
width: 144px;
|
||||
height: 132px}
|
||||
|
||||
#AlarmPanel {
|
||||
left: 12px;
|
||||
top: 368px;
|
||||
width: 384px;
|
||||
height: 64px}
|
||||
|
||||
#DigitCheckLabel {
|
||||
left: 2px;
|
||||
top: 12px}
|
||||
#DigitCheckLamp {
|
||||
left: 18px;
|
||||
top: 404px}
|
||||
|
||||
#ProgramCheckLabel {
|
||||
left: 40px;
|
||||
top: 12px}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#CarryPanel {
|
||||
left: 224px;
|
||||
top: 0;
|
||||
width: 80px;
|
||||
height: 132px}
|
||||
|
||||
#AdderPanel {
|
||||
left: 288px;
|
||||
top: 0;
|
||||
width: 60px;
|
||||
height: 132px}
|
||||
|
||||
|
||||
|
||||
#PowerOnBtn {
|
||||
left: 380px;
|
||||
top: 330px}
|
||||
#PowerOnCaption {
|
||||
left: 380px;
|
||||
top: 360px;
|
||||
width: 24px}
|
||||
#PowerLamp {
|
||||
left: 380px;
|
||||
top: 378px}
|
||||
#PowerOffBtn {
|
||||
left: 380px;
|
||||
top: 426px}
|
||||
#PowerOffCaption {
|
||||
left: 380px;
|
||||
top: 456px;
|
||||
width: 24px}
|
||||
|
||||
|
||||
#ComputerStopCaption {
|
||||
left: 478px;
|
||||
top: 300px;
|
||||
width: 160px}
|
||||
|
||||
#OverflowLamp {
|
||||
left: 466px;
|
||||
top: 330px}
|
||||
#OverflowLampCaption {
|
||||
left: 454px;
|
||||
top: 360px;
|
||||
width: 40px}
|
||||
#ResetOverflowBtn {
|
||||
left: 461px;
|
||||
top: 416px}
|
||||
#ResetOverflowCaption {
|
||||
left: 461px;
|
||||
top: 456px;
|
||||
width: 34px}
|
||||
|
||||
#SectorLamp {
|
||||
left: 506px;
|
||||
top: 330px}
|
||||
#SectorLampCaption {
|
||||
left: 497px;
|
||||
top: 360px;
|
||||
width: 40px}
|
||||
#ResetSectorBtn {
|
||||
left: 501px;
|
||||
top: 416px}
|
||||
#ResetSectorCaption {
|
||||
left: 501px;
|
||||
top: 456px;
|
||||
width: 34px}
|
||||
|
||||
#ControlLamp {
|
||||
left: 546px;
|
||||
top: 330px}
|
||||
#ControlLampCaption {
|
||||
left: 537px;
|
||||
top: 360px;
|
||||
width: 40px}
|
||||
#ResetControlBtn {
|
||||
left: 541px;
|
||||
top: 416px}
|
||||
#ResetControlCaption {
|
||||
left: 541px;
|
||||
top: 456px;
|
||||
width: 34px}
|
||||
|
||||
#FCLamp {
|
||||
left: 586px;
|
||||
top: 330px}
|
||||
#FCLampCaption {
|
||||
left: 586px;
|
||||
top: 360px;
|
||||
width: 24px}
|
||||
|
||||
#IdleLamp {
|
||||
left: 626px;
|
||||
top: 330px}
|
||||
#IdleLampCaption {
|
||||
left: 626px;
|
||||
top: 360px;
|
||||
width: 24px}
|
||||
|
||||
#AudibleAlarmSwitch {
|
||||
position: absolute;
|
||||
left: 626px;
|
||||
top: 420px;
|
||||
width: 24px}
|
||||
#AudibleAlarmOn {
|
||||
left: 626px;
|
||||
top: 408px;
|
||||
width: 24px}
|
||||
#AudibleAlarmOff {
|
||||
left: 608px;
|
||||
top: 456px;
|
||||
line-height: 130%;
|
||||
width: 60px}
|
||||
|
||||
#ClearBtn {
|
||||
left: 710px;
|
||||
top: 374px}
|
||||
#ClearBtnCaption {
|
||||
left: 710px;
|
||||
top: 300px;
|
||||
width: 32px}
|
||||
|
||||
#LockNormalSwitch {
|
||||
position: absolute;
|
||||
left: 808px;
|
||||
top: 378px;
|
||||
width: 24px}
|
||||
#LockNormalOn {
|
||||
left: 808px;
|
||||
top: 370px;
|
||||
width: 24px}
|
||||
#LockNormalOff {
|
||||
left: 802px;
|
||||
top: 408px;
|
||||
width: 36px}
|
||||
|
||||
#TimingToggleCaption {
|
||||
left: 844px;
|
||||
top: 300px;
|
||||
width: 64px}
|
||||
|
||||
#ExecuteLamp {
|
||||
left: 844px;
|
||||
top: 330px}
|
||||
#ExecuteLampCaption {
|
||||
left: 840px;
|
||||
top: 360px;
|
||||
width: 32px}
|
||||
#ExecuteBtn {
|
||||
left: 840px;
|
||||
top: 416px}
|
||||
|
||||
#FetchLamp {
|
||||
left: 884px;
|
||||
top: 330px}
|
||||
#FetchLampCaption {
|
||||
left: 880px;
|
||||
top: 360px;
|
||||
width: 32px}
|
||||
#FetchBtn {
|
||||
left: 880px;
|
||||
top: 416px}
|
||||
|
||||
#OperationCaption {
|
||||
left: 950px;
|
||||
top: 300px;
|
||||
width: 88px}
|
||||
|
||||
#StepContinuousSwitch {
|
||||
position: absolute;
|
||||
left: 950px;
|
||||
top: 378px;
|
||||
width: 24px}
|
||||
#StepContinuousOn {
|
||||
left: 932px;
|
||||
top: 370px;
|
||||
width: 60px}
|
||||
#StepContinuousOff {
|
||||
left: 932px;
|
||||
top: 408px;
|
||||
width: 60px}
|
||||
|
||||
#VersionDiv {
|
||||
right: 12px;
|
||||
bottom: 8px;
|
||||
color: black}
|
||||
145
webUI/B220ControlConsole.html
Normal file
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>retro-220 Control Console</title>
|
||||
<!--
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220ControlConsole.html
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator Control Console page.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from B220ControlConsole.html.
|
||||
***********************************************************************/
|
||||
-->
|
||||
<meta name="Author" content="Paul Kimpel">
|
||||
<meta http-equiv="Content-Script-Type" content="text/javascript">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
|
||||
<link id=supervisoryStyleSheet rel=stylesheet type="text/css" href="B220ControlConsole.css">
|
||||
</head>
|
||||
|
||||
<body class=panelBody>
|
||||
|
||||
<div id=PanelSurface class=panelSurface>
|
||||
<img id=BurroughsMeatball src="resources/Burroughs-Meatball.png">
|
||||
<img id=BurroughsLogo src="resources/Burroughs-Logo.jpg">
|
||||
<!-- <img id=B220Logo src="resources/B220-Logo.jpg"> -->
|
||||
<div id=B220Logo>2 2 0</div>
|
||||
|
||||
<div id=IntervalTimerResetBtn class=blackButton3> </div>
|
||||
<div id=IntervalTimer>0000.0</div>
|
||||
|
||||
<!--
|
||||
<div id=AdderDiv class=panelRegister>
|
||||
<div id=CardatronPanel class=panelDiv></div>
|
||||
<div id=CarryPanel class=panelDiv></div>
|
||||
<div id=AdderPanel class=panelDiv></div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div id=ARegPanel class=panelRegister></div>
|
||||
<div id=RRegPanel class=panelRegister></div>
|
||||
<div id=DRegPanel class=panelRegister></div>
|
||||
|
||||
<div id=BRegPanel class=panelRegister></div>
|
||||
<div id=PRegPanel class=panelRegister></div>
|
||||
<div id=CRegPanel class=panelRegister></div>
|
||||
<div id=ERegPanel class=panelRegister></div>
|
||||
<div id=SRegPanel class=panelRegister></div>
|
||||
|
||||
<div id=AlarmPanel class=panelDiv>
|
||||
<button id=DigitCheckLabel class=panelLabel>DIGIT<br>CHECK</button>
|
||||
|
||||
<button id=ProgramCheckLabel class=panelLabel>PROGRAM<br>CHECK</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div id=PowerOnBtn class=blackButton3> </div>
|
||||
<div id=PowerOnCaption class=caption>ON</div>
|
||||
-->
|
||||
|
||||
<div id=PowerOffBtn class=redButton3> </div>
|
||||
<div id=PowerOffCaption class=caption>OFF</div>
|
||||
|
||||
<!--
|
||||
|
||||
<div id=ComputerStopCaption class=panelCaption>
|
||||
<span class=panelSpan>COMPUTER STOP</span>
|
||||
</div>
|
||||
|
||||
<div id=OverflowLampCaption class=caption>OVERFLOW</div>
|
||||
<div id=ResetOverflowBtn class=blackButton1> </div>
|
||||
<div id=ResetOverflowCaption class=caption>RESET</div>
|
||||
|
||||
<div id=SectorLampCaption class=caption>SECTOR</div>
|
||||
<div id=ResetSectorBtn class=blackButton1> </div>
|
||||
<div id=ResetSectorCaption class=caption>RESET</div>
|
||||
|
||||
<div id=ControlLampCaption class=caption>CONTROL</div>
|
||||
<div id=ResetControlBtn class=blackButton1> </div>
|
||||
<div id=ResetControlCaption class=caption>RESET</div>
|
||||
|
||||
<div id=FCLampCaption class=caption>F.C.</div>
|
||||
|
||||
<div id=IdleLampCaption class=caption>IDLE</div>
|
||||
|
||||
<div id=AudibleAlarmOn class=caption>ON</div>
|
||||
<div id=AudibleAlarmOff class=caption>AUD. ALARM<br>DISABLE</div>
|
||||
|
||||
<div id=ClearBtn class=redButton1> </div>
|
||||
<div id=ClearBtnCaption class=caption>CLEAR</div>
|
||||
|
||||
<div id=LockNormalOn class=caption>LOCK</div>
|
||||
<div id=LockNormalOff class=caption>NORMAL</div>
|
||||
|
||||
<div id=ExecuteBtn class=blackButton1> </div>
|
||||
<div id=FetchBtn class=blackButton1> </div>
|
||||
|
||||
<div id=TimingToggleCaption class=caption>TIMING TOGGLE</div>
|
||||
<div id=ExecuteLampCaption class=caption>EXECUTE</div>
|
||||
<div id=FetchLampCaption class=caption>FETCH</div>
|
||||
|
||||
<div id=OperationCaption class=caption>OPERATION</div>
|
||||
|
||||
<div id=StepContinuousOn class=caption>CONTINUOUS</div>
|
||||
<div id=StepContinuousOff class=caption>STEP</div>
|
||||
|
||||
<div id=StartBtn class=blackButton3> </div>
|
||||
<div id=StartCaption class=caption>START</div>
|
||||
|
||||
-->
|
||||
|
||||
<div id=VersionDiv class=caption>
|
||||
retro-220 <span id=EmulatorVersion>?.??</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id=Diagnostics style="display:none">
|
||||
<br>
|
||||
Proc Delta: <input id=ProcDelta class="rj" type=text size=10>
|
||||
|
||||
Latency: <input id=LastLatency class="rj" type=text size=10>
|
||||
|
||||
<table id=CallbackTable
|
||||
style="position:relative; top:1ex; visibility:visible; border-collapse:collapse; border-spacing:0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID
|
||||
<th>Delay
|
||||
<th>Context
|
||||
<th>#Args
|
||||
</thead>
|
||||
<tbody id=CallbackBody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
603
webUI/B220ControlConsole.js
Normal file
@@ -0,0 +1,603 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220ControlConsole.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator Control Console object.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from D205SupervisoryPanel.js.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
/**************************************/
|
||||
function B220ControlConsole(p, systemShutdown) {
|
||||
/* Constructor for the ControlConsole object */
|
||||
var h = 584;
|
||||
var w = 1064;
|
||||
var mnemonic = "ControlConsole";
|
||||
|
||||
this.config = p.config; // System Configuration object
|
||||
this.intervalToken = 0; // setInterval() token for panel refresh
|
||||
this.timerBase = performance.now(); // starting value of Interval Timer
|
||||
this.timerValue = 0; // current value of Interval Timer
|
||||
this.p = p; // B220Processor object
|
||||
this.systemShutdown = systemShutdown; // system shut-down callback
|
||||
|
||||
this.boundLamp_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.lamp_Click);
|
||||
this.boundPowerBtn_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.powerBtn_Click);
|
||||
this.boundClear_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.clear_Click);
|
||||
this.boundFlipSwitch = B220Util.bindMethod(this, B220ControlConsole.prototype.flipSwitch);
|
||||
this.boundStartBtn_Click = B220Util.bindMethod(this, B220ControlConsole.prototype.startBtn_Click);
|
||||
this.boundResetTimer = B220Util.bindMethod(this, B220ControlConsole.prototype.resetTimer);
|
||||
this.boundUpdatePanel = B220Util.bindMethod(this, B220ControlConsole.prototype.updatePanel);
|
||||
|
||||
this.doc = null;
|
||||
this.window = window.open("../webUI/B220ControlConsole.html", mnemonic,
|
||||
"location=no,scrollbars,resizable,width=" + w + ",height=" + h +
|
||||
",top=0,left=" + (screen.availWidth - w));
|
||||
this.window.addEventListener("load",
|
||||
B220Util.bindMethod(this, B220ControlConsole.prototype.consoleOnLoad));
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.displayRefreshPeriod = 50; // milliseconds
|
||||
B220ControlConsole.offSwitchClass = "./resources/ToggleDown.png";
|
||||
B220ControlConsole.onSwitchClass = "./resources/ToggleUp.png";
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.$$ = function $$(e) {
|
||||
return this.doc.getElementById(e);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.powerOnSystem = function powerOnSystem() {
|
||||
/* Powers on the system */
|
||||
|
||||
if (!this.p.poweredOn) {
|
||||
this.p.powerUp();
|
||||
this.powerLamp.set(1);
|
||||
this.window.focus();
|
||||
if (!this.intervalToken) {
|
||||
this.intervalToken = this.window.setInterval(this.boundUpdatePanel, B220ControlConsole.displayRefreshPeriod);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.powerOffSystem = function powerOffSystem() {
|
||||
/* Powers off the system */
|
||||
|
||||
if (this.p.poweredOn) {
|
||||
this.systemShutdown();
|
||||
this.powerLamp.set(0);
|
||||
if (this.intervalToken) { // if the display auto-update is running
|
||||
this.window.clearInterval(this.intervalToken); // kill it
|
||||
this.intervalToken = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.beforeUnload = function beforeUnload(ev) {
|
||||
var msg = "Closing this window will make the panel unusable.\n" +
|
||||
"Suggest you stay on the page and minimize this window instead";
|
||||
|
||||
ev.preventDefault();
|
||||
ev.returnValue = msg;
|
||||
return msg;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.displayCallbackState = function displayCallbackState() {
|
||||
/* Builds a table of outstanding callback state */
|
||||
var cb;
|
||||
var cbs;
|
||||
var e;
|
||||
var body = document.createElement("tbody");
|
||||
var oldBody = this.$$("CallbackBody");
|
||||
var row;
|
||||
var state = getCallbackState(0x03);
|
||||
var token;
|
||||
|
||||
cbs = state.delayDev;
|
||||
for (token in cbs) {
|
||||
row = document.createElement("tr");
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode(token));
|
||||
row.appendChild(e);
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode((cbs[token]||0).toFixed(2)));
|
||||
row.appendChild(e);
|
||||
|
||||
e = document.createElement("td");
|
||||
e.colSpan = 2;
|
||||
row.appendChild(e);
|
||||
body.appendChild(row);
|
||||
}
|
||||
|
||||
cbs = state.pendingCallbacks;
|
||||
for (token in cbs) {
|
||||
cb = cbs[token];
|
||||
row = document.createElement("tr");
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode(token.toString()));
|
||||
row.appendChild(e);
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode(cb.delay.toFixed(2)));
|
||||
row.appendChild(e);
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode((cb.context && cb.context.mnemonic) || "??"));
|
||||
row.appendChild(e);
|
||||
|
||||
e = document.createElement("td");
|
||||
e.appendChild(document.createTextNode((cb.args ? cb.args.length : 0).toString()));
|
||||
row.appendChild(e);
|
||||
body.appendChild(row);
|
||||
}
|
||||
|
||||
body.id = oldBody.id;
|
||||
oldBody.parentNode.replaceChild(body, oldBody);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.updatePanel = function updatePanel() {
|
||||
/* Updates the panel from the current Processor state */
|
||||
var eLevel;
|
||||
var p = this.p; // local copy of Processor object
|
||||
var stamp = performance.now();
|
||||
var text;
|
||||
var tg = p.toggleGlow;
|
||||
|
||||
// This needs to be done only if the Processor is in RUN status.
|
||||
this.timerValue = stamp - this.timerBase;
|
||||
text = (this.timerValue/1000 + 10000).toFixed(1);
|
||||
this.intervalTimer.textContent = text.substring(text.length-6);
|
||||
|
||||
return; /////////////////// DEBUG ///////////////////////////////////////////////////////
|
||||
|
||||
eLevel = (p.stopIdle ? p.togTiming : tg.glowTiming);
|
||||
|
||||
this.regA.updateGlow(tg.glowA);
|
||||
this.regB.updateGlow(tg.glowB);
|
||||
this.regC.updateGlow(tg.glowC);
|
||||
this.regD.updateGlow(tg.glowD);
|
||||
this.regR.updateGlow(tg.glowR);
|
||||
this.control.updateGlow(tg.glowCtl);
|
||||
|
||||
this.regAdder.updateGlow(tg.glowADDER);
|
||||
this.regCarry.updateGlow(tg.glowCT);
|
||||
|
||||
this.cardatronTWA.set(tg.glowTWA);
|
||||
this.cardatron3IO.set(tg.glow3IO);
|
||||
|
||||
this.overflowLamp.set(p.poweredOn && tg.glowOverflow);
|
||||
this.sectorLamp.set(p.stopSector);
|
||||
this.fcLamp.set(p.stopForbidden);
|
||||
this.controlLamp.set(p.stopControl);
|
||||
this.idleLamp.set(p.poweredOn && p.stopIdle);
|
||||
|
||||
this.executeLamp.set(p.poweredOn && (1-eLevel));
|
||||
this.fetchLamp.set(p.poweredOn && eLevel);
|
||||
|
||||
this.mainLamp.set(tg.glowMAIN);
|
||||
this.rwmLamp.set(tg.glowRWM);
|
||||
this.rwlLamp.set(tg.glowRWL);
|
||||
this.wdblLamp.set(tg.glowWDBL);
|
||||
this.actLamp.set(tg.glowACTION);
|
||||
this.accessLamp.set(tg.glowACCESS);
|
||||
this.lmLamp.set(tg.glowLM);
|
||||
this.l4Lamp.set(tg.glowL4);
|
||||
this.l5Lamp.set(tg.glowL5);
|
||||
this.l6Lamp.set(tg.glowL6);
|
||||
this.l7Lamp.set(tg.glowL7);
|
||||
|
||||
/********** DEBUG **********
|
||||
this.$$("ProcDelta").value = p.procSlackAvg.toFixed(2);
|
||||
this.$$("LastLatency").value = p.delayDeltaAvg.toFixed(2);
|
||||
this.displayCallbackState();
|
||||
***************************/
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.lamp_Click = function lamp_Click(ev) {
|
||||
/* Handles the click event within panels. Determines which lamp element was
|
||||
clicked, flips the state of the corresponding toggle in the Processor, and
|
||||
refreshes the lamp element */
|
||||
var bit; // bit number extracted from the id
|
||||
var id = ev.target.id; // id of the element clicked
|
||||
var ix = id.indexOf("_"); // offset of the "_" delimiter in the id
|
||||
var p = this.p; // local copy of processor object
|
||||
var reg; // register prefix from id
|
||||
|
||||
if (p.poweredOn) {
|
||||
if (ix < 0) {
|
||||
reg = id;
|
||||
bit = 0;
|
||||
} else if (ix > 0) {
|
||||
reg = id.substring(0, ix);
|
||||
bit = parseInt(id.substring(ix+1));
|
||||
if (isNaN(bit)) {
|
||||
bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case "A":
|
||||
p.A = p.bitFlip(p.A, bit);
|
||||
this.regA.update(p.A);
|
||||
break;
|
||||
case "B":
|
||||
p.B = p.bitFlip(p.B, bit);
|
||||
this.regB.update(p.B);
|
||||
break;
|
||||
case "C":
|
||||
p.C = p.bitFlip(p.C, bit);
|
||||
this.regC.update(p.C);
|
||||
break;
|
||||
case "D":
|
||||
p.D = p.bitFlip(p.D, bit);
|
||||
this.regD.update(p.D);
|
||||
break;
|
||||
case "R":
|
||||
p.R = p.bitFlip(p.R, bit);
|
||||
this.regR.update(p.R);
|
||||
break;
|
||||
case "ADD":
|
||||
p.ADDER = p.bitFlip(p.ADDER, bit);
|
||||
this.regAdder.update(p.ADDER);
|
||||
break;
|
||||
case "CT":
|
||||
p.CT = p.bitFlip(p.CT, bit);
|
||||
this.regCarry.update(p.CT);
|
||||
break;
|
||||
case "TWA":
|
||||
p.togTWA ^= 1;
|
||||
this.cardatronTWA.set(p.togTWA);
|
||||
break;
|
||||
case "3IO":
|
||||
p.tog3IO ^= 1;
|
||||
this.cardatron3IO.set(p.tog3IO);
|
||||
break;
|
||||
case "CTL":
|
||||
switch (bit) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
p.SHIFT = p.bitFlip(p.SHIFT, bit);
|
||||
break;
|
||||
case 5:
|
||||
p.togMT1BV5 ^= 1;
|
||||
break;
|
||||
case 6:
|
||||
p.togMT1BV4 ^= 1;
|
||||
break;
|
||||
case 7:
|
||||
p.togMT3P ^= 1;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
p.SHIFTCONTROL = p.bitFlip(p.SHIFTCONTROL, bit-8);
|
||||
break;
|
||||
case 12:
|
||||
p.togASYNC ^= 1;
|
||||
break;
|
||||
case 13:
|
||||
p.togZCT ^= 1;
|
||||
break;
|
||||
case 14:
|
||||
p.togBKPT ^= 1;
|
||||
break;
|
||||
case 15:
|
||||
p.togT0 ^= 1;
|
||||
break;
|
||||
case 16:
|
||||
p.togDELAY ^= 1;
|
||||
break;
|
||||
case 17:
|
||||
p.togPO2 ^= 1;
|
||||
break;
|
||||
case 18:
|
||||
p.togPO1 ^= 1;
|
||||
break;
|
||||
case 19:
|
||||
p.togOK ^= 1;
|
||||
break;
|
||||
case 20:
|
||||
p.togTC2 ^= 1;
|
||||
break;
|
||||
case 21:
|
||||
p.togTC1 ^= 1;
|
||||
break;
|
||||
case 22:
|
||||
p.togTF ^= 1;
|
||||
break;
|
||||
case 23:
|
||||
p.togSTART ^= 1;
|
||||
break;
|
||||
case 24:
|
||||
p.togSTEP ^= 1;
|
||||
break;
|
||||
case 25:
|
||||
p.togDIVALARM ^= 1;
|
||||
break;
|
||||
case 26:
|
||||
p.togCOUNT ^= 1;
|
||||
break;
|
||||
case 27:
|
||||
p.togSIGN ^= 1;
|
||||
break;
|
||||
case 28:
|
||||
p.togMULDIV ^= 1;
|
||||
break;
|
||||
case 29:
|
||||
p.togCLEAR ^= 1;
|
||||
break;
|
||||
case 30:
|
||||
p.togPLUSAB ^= 1;
|
||||
break;
|
||||
case 31:
|
||||
p.togCOMPL ^= 1;
|
||||
break;
|
||||
case 32:
|
||||
p.togDELTABDIV ^= 1;
|
||||
break;
|
||||
case 33:
|
||||
p.togDPCTR ^= 1;
|
||||
break;
|
||||
case 34:
|
||||
p.togADDER ^= 1;
|
||||
break;
|
||||
case 35:
|
||||
p.togBTOAIN ^= 1;
|
||||
break;
|
||||
case 36:
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
p.SPECIAL = p.bitFlip(p.SPECIAL, bit-36);
|
||||
break;
|
||||
} // switch bit
|
||||
|
||||
break;
|
||||
} // switch reg
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.clear_Click = function Clear_Click(ev) {
|
||||
/* Event handler for the various clear/reset buttons on the panel */
|
||||
|
||||
if (this.p.poweredOn) {
|
||||
switch (ev.target.id) {
|
||||
case "ClearBtn":
|
||||
this.p.clear();
|
||||
break;
|
||||
case "ClearARegBtn":
|
||||
this.p.A = 0;
|
||||
break;
|
||||
case "ClearBRegBtn":
|
||||
this.p.B = 0;
|
||||
break;
|
||||
case "ClearCRegBtn":
|
||||
this.p.C = 0;
|
||||
break;
|
||||
case "ClearDRegBtn":
|
||||
this.p.D = 0;
|
||||
break;
|
||||
case "ClearRRegBtn":
|
||||
this.p.R = 0;
|
||||
break;
|
||||
case "ClearControlBtn":
|
||||
this.p.clearControl();
|
||||
break;
|
||||
case "ResetOverflowBtn":
|
||||
this.p.setOverflow(0);
|
||||
break;
|
||||
case "ResetSectorBtn":
|
||||
this.p.stopSector = 0;
|
||||
break;
|
||||
case "ResetControlBtn":
|
||||
this.p.stopControl = 0;
|
||||
break;
|
||||
case "ExecuteBtn":
|
||||
this.p.setTimingToggle(0);
|
||||
break;
|
||||
case "FetchBtn":
|
||||
this.p.setTimingToggle(1 - this.p.sswLockNormal);
|
||||
break;
|
||||
}
|
||||
this.updatePanel();
|
||||
}
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.powerBtn_Click = function powerBtn_Click(ev) {
|
||||
/* Handler for the START button: begins execution for the current cycle */
|
||||
|
||||
switch(ev.target.id) {
|
||||
case "PowerOnBtn":
|
||||
this.powerOnSystem();
|
||||
break;
|
||||
case "PowerOffBtn":
|
||||
this.powerOffSystem();
|
||||
break;
|
||||
}
|
||||
this.updatePanel();
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.startBtn_Click = function startBtn_Click(ev) {
|
||||
/* Handler for the START button: begins execution for the current cycle */
|
||||
|
||||
this.p.start();
|
||||
this.timerBase = performance.now() - this.timerValue;
|
||||
this.updatePanel();
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.resetTimer = function resetTimer(ev) {
|
||||
/* Resets the Interval Timer display to 0000.0 */
|
||||
|
||||
this.timerBase = performance.now();
|
||||
this.timerValue = 0;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.flipSwitch = function flipSwitch(ev) {
|
||||
/* Handler for switch & knob clicks */
|
||||
|
||||
switch (ev.target.id) {
|
||||
case "AudibleAlarmSwitch":
|
||||
this.audibleAlarmSwitch.flip();
|
||||
this.config.putNode("ControlConsole.audibleAlarmSwitch",
|
||||
this.p.sswAudibleAlarm = this.audibleAlarmSwitch.state);
|
||||
break;
|
||||
case "LockNormalSwitch":
|
||||
this.lockNormalSwitch.flip();
|
||||
this.config.putNode("ControlConsole.lockNormalSwitch",
|
||||
this.p.sswLockNormal = this.lockNormalSwitch.state);
|
||||
break;
|
||||
case "StepContinuousSwitch":
|
||||
this.stepContinuousSwitch.flip();
|
||||
this.config.putNode("ControlConsole.stepContinuousSwitch",
|
||||
this.p.sswStepContinuous = this.stepContinuousSwitch.state);
|
||||
break;
|
||||
case "PulseSourceSwitch": // non-functional, just turn it back off
|
||||
this.pulseSourceSwitch.flip();
|
||||
this.config.putNode("ControlConsole.pulseSourceSwitch", 0);
|
||||
setCallback(null, this.pulseSourceSwitch, 250, this.pulseSourceSwitch.set, 0);
|
||||
break;
|
||||
case "WordContSwitch": // non-functional, just turn it back off
|
||||
this.wordContSwitch.flip();
|
||||
this.config.putNode("ControlConsole.wordContSwitch", 0);
|
||||
setCallback(null, this.wordContSwitch, 250, this.wordContSwitch.set, 0);
|
||||
break;
|
||||
case "FrequencyKnob": // non-function knob -- just step it
|
||||
this.frequencyKnob.step();
|
||||
this.config.putNode("ControlConsole.frequencyKnob", this.frequencyKnob.position);
|
||||
break;
|
||||
}
|
||||
|
||||
this.updatePanel();
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.consoleOnLoad = function consoleOnLoad() {
|
||||
/* Initializes the Supervisory Panel window and user interface */
|
||||
var body;
|
||||
var prefs = this.config.getNode("ControlConsole");
|
||||
var x;
|
||||
|
||||
this.doc = this.window.document;
|
||||
body = this.$$("PanelSurface");
|
||||
|
||||
this.intervalTimer = this.$$("IntervalTimer");
|
||||
|
||||
// Main Registers
|
||||
|
||||
this.regA = new PanelRegister(this.$$("ARegPanel"), 44, 4, "A_", "A");
|
||||
this.regB = new PanelRegister(this.$$("BRegPanel"), 16, 4, "B_", "B");
|
||||
this.regC = new PanelRegister(this.$$("CRegPanel"), 40, 4, "C_", "C");
|
||||
this.regD = new PanelRegister(this.$$("DRegPanel"), 44, 4, "D_", "D");
|
||||
this.regE = new PanelRegister(this.$$("ERegPanel"), 16, 4, "E_", "E");
|
||||
this.regR = new PanelRegister(this.$$("RRegPanel"), 44, 4, "R_", "R");
|
||||
this.regP = new PanelRegister(this.$$("PRegPanel"), 16, 4, "P_", "P");
|
||||
this.regS = new PanelRegister(this.$$("SRegPanel"), 16, 4, "S_", "S");
|
||||
|
||||
// Status Panels
|
||||
|
||||
this.digitCheckLamp = new ColoredLamp(body, null, null, "DigitCheckLamp", "redLamp lampCollar", "whiteLit");
|
||||
this.powerLamp = new ColoredLamp(body, null, null, "PowerLamp", "greenLamp", "greenLit");
|
||||
|
||||
this.overflowLamp = new ColoredLamp(body, null, null, "OverflowLamp", "redLamp", "redLit");
|
||||
|
||||
this.sectorLamp = new ColoredLamp(body, null, null, "SectorLamp", "whiteLamp", "whiteLit");
|
||||
this.controlLamp = new ColoredLamp(body, null, null, "ControlLamp", "orangeLamp", "orangeLit");
|
||||
this.fcLamp = new ColoredLamp(body, null, null, "FCLamp", "whiteLamp", "whiteLit");
|
||||
this.idleLamp = new ColoredLamp(body, null, null, "IdleLamp", "redLamp", "redLit");
|
||||
|
||||
this.executeLamp = new ColoredLamp(body, null, null, "ExecuteLamp", "whiteLamp", "whiteLit");
|
||||
this.fetchLamp = new ColoredLamp(body, null, null, "FetchLamp", "whiteLamp", "whiteLit");
|
||||
|
||||
// Organ Switches
|
||||
|
||||
this.audibleAlarmSwitch = new ToggleSwitch(body, null, null, "AudibleAlarmSwitch",
|
||||
B220ControlConsole.offSwitchClass, B220ControlConsole.onSwitchClass);
|
||||
this.audibleAlarmSwitch.set(this.p.sswAudibleAlarm = prefs.audibleAlarmSwitch);
|
||||
this.lockNormalSwitch = new ToggleSwitch(body, null, null, "LockNormalSwitch",
|
||||
B220ControlConsole.offSwitchClass, B220ControlConsole.onSwitchClass);
|
||||
this.lockNormalSwitch.set(this.p.sswLockNormal = prefs.lockNormalSwitch);
|
||||
this.stepContinuousSwitch = new ToggleSwitch(body, null, null, "StepContinuousSwitch",
|
||||
B220ControlConsole.offSwitchClass, B220ControlConsole.onSwitchClass);
|
||||
this.stepContinuousSwitch.set(this.p.sswStepContinuous = prefs.stepContinuousSwitch);
|
||||
|
||||
// Events
|
||||
this.$$("IntervalTimerResetBtn").addEventListener("click", this.boundResetTimer);
|
||||
/*****
|
||||
this.$$("ResetOverflowBtn").addEventListener("click", this.boundClear_Click);
|
||||
this.$$("ResetSectorBtn").addEventListener("click", this.boundClear_Click);
|
||||
this.$$("ResetControlBtn").addEventListener("click", this.boundClear_Click);
|
||||
this.$$("ExecuteBtn").addEventListener("click", this.boundClear_Click);
|
||||
this.$$("FetchBtn").addEventListener("click", this.boundClear_Click);
|
||||
this.$$("PowerOnBtn").addEventListener("click", this.boundPowerBtn_Click);
|
||||
*****/
|
||||
this.$$("PowerOffBtn").addEventListener("click", this.boundPowerBtn_Click);
|
||||
|
||||
this.window.addEventListener("beforeunload", B220ControlConsole.prototype.beforeUnload);
|
||||
|
||||
/*****
|
||||
this.$$("AudibleAlarmSwitch").addEventListener("click", this.boundFlipSwitch);
|
||||
this.$$("LockNormalSwitch").addEventListener("click", this.boundFlipSwitch);
|
||||
this.$$("StepContinuousSwitch").addEventListener("click", this.boundFlipSwitch);
|
||||
|
||||
this.$$("StartBtn").addEventListener("click", this.boundStartBtn_Click);
|
||||
|
||||
this.$$("ARegPanel").addEventListener("click", this.boundLamp_Click);
|
||||
this.$$("BRegPanel").addEventListener("click", this.boundLamp_Click);
|
||||
this.$$("CRegPanel").addEventListener("click", this.boundLamp_Click);
|
||||
this.$$("DRegPanel").addEventListener("click", this.boundLamp_Click);
|
||||
this.$$("RRegPanel").addEventListener("click", this.boundLamp_Click);
|
||||
*****/
|
||||
|
||||
this.$$("EmulatorVersion").textContent = B220Processor.version;
|
||||
|
||||
// Power on the system by default...
|
||||
setCallback(this.mnemonic, this, 1000, function powerOnTimer() {
|
||||
this.powerOnSystem();
|
||||
});
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220ControlConsole.prototype.shutDown = function shutDown() {
|
||||
/* Shuts down the panel */
|
||||
|
||||
if (this.intervalToken) {
|
||||
this.window.clearInterval(this.intervalToken);
|
||||
}
|
||||
this.window.removeEventListener("beforeunload", B220ControlConsole.prototype.beforeUnload);
|
||||
this.window.close();
|
||||
};
|
||||
61
webUI/B220Manifest.appcache
Normal file
@@ -0,0 +1,61 @@
|
||||
CACHE MANIFEST
|
||||
# retro-220 emulator 0.00a, 2016-12-29 10:30
|
||||
|
||||
CACHE:
|
||||
../emulator/B220Processor.js
|
||||
B220.css
|
||||
B220.html
|
||||
B220.js
|
||||
#B220CardatronControl.css
|
||||
#B220CardatronControl.html
|
||||
#B220CardatronControl.js
|
||||
#B220CardatronInput.css
|
||||
#B220CardatronInput.html
|
||||
#B220CardatronInput.js
|
||||
#B220CardatronOutput.css
|
||||
#B220CardatronOutput.html
|
||||
#B220CardatronOutput.js
|
||||
#B220CardatronZeroSuppressPanel.html
|
||||
B220Common.css
|
||||
#B220ConsoleInput.css
|
||||
#B220ConsoleInput.js
|
||||
#B220ConsoleOutput.css
|
||||
#B220ConsoleOutput.js
|
||||
B220ControlConsole.css
|
||||
B220ControlConsole.html
|
||||
B220ControlConsole.js
|
||||
#B220DataFile.css
|
||||
#B220DataFile.html
|
||||
#B220DataFile.js
|
||||
#B220DiagMonitor.html
|
||||
#B220Flexowriter.html
|
||||
#B220FramePaper.html
|
||||
#B220MagTapeControl.css
|
||||
#B220MagTapeControl.html
|
||||
#B220MagTapeControl.js
|
||||
#B220MagTapeDrive.css
|
||||
#B220MagTapeDrive.html
|
||||
#B220MagTapeDrive.js
|
||||
#B220MagTapeLoadPanel.html
|
||||
B220PanelUtil.js
|
||||
#B220PaperTapePunch.html
|
||||
#B220PaperTapeReader.html
|
||||
B220SetCallback.js
|
||||
B220SystemConfig.css
|
||||
B220SystemConfig.html
|
||||
B220SystemConfig.js
|
||||
B220Util.js
|
||||
resources/B220-Site.jpg
|
||||
#resources/DataFileTapeHead.png
|
||||
resources/DejaVuSans-Bold-webfont.ttf
|
||||
resources/DejaVuSans-Bold-webfont.woff
|
||||
resources/DejaVuSans-webfont.ttf
|
||||
resources/DejaVuSans-webfont.woff
|
||||
resources/DejaVuSansMono-webfont.ttf
|
||||
resources/DejaVuSansMono-webfont.woff
|
||||
#resources/MagTapeReel.jpg
|
||||
resources/retro-220-Logo.png
|
||||
resources/retro-Logo.png
|
||||
resources/ToggleDown.png
|
||||
resources/ToggleMid.png
|
||||
resources/ToggleUp.png
|
||||
758
webUI/B220PanelUtil.js
Normal file
@@ -0,0 +1,758 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220PanelUtil.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* JavaScript object definition for the Burroughs 220 Emulator Control
|
||||
* Panel utility constructors.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 D205PanelUtil.js.
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Neon Lamp *
|
||||
***********************************************************************/
|
||||
function NeonLamp(parent, x, y, id) {
|
||||
/* Constructor for the neon lamp objects used within panels. x & y are the
|
||||
coordinates of the lamp within its containing element; id is the DOM id */
|
||||
|
||||
this.state = 0; // current lamp state, 0=off
|
||||
this.topCaptionDiv = null; // optional top caption element
|
||||
this.bottomCaptionDiv = null; // optional bottom caption element
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("div");
|
||||
this.element.id = id;
|
||||
this.element.className = NeonLamp.lampClass;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
NeonLamp.topCaptionClass = "neonLampTopCaption";
|
||||
NeonLamp.bottomCaptionClass = "neonLampBottomCaption";
|
||||
NeonLamp.lampClass = "neonLamp";
|
||||
NeonLamp.litClass = "neonLamp neonLit";
|
||||
NeonLamp.lampLevels = 6;
|
||||
NeonLamp.levelClass = [ // css class names for the lamp levels
|
||||
NeonLamp.lampClass,
|
||||
NeonLamp.litClass + "1",
|
||||
NeonLamp.litClass + "2",
|
||||
NeonLamp.litClass + "3",
|
||||
NeonLamp.litClass + "4",
|
||||
NeonLamp.litClass + "5",
|
||||
NeonLamp.litClass];
|
||||
|
||||
/**************************************/
|
||||
NeonLamp.prototype.set = function set(state) {
|
||||
/* Changes the visible state of the lamp according to the value of "state", 0-1 */
|
||||
var newState = Math.max(Math.min(Math.round(state*NeonLamp.lampLevels + 0.4999), NeonLamp.lampLevels), 0);
|
||||
|
||||
if (this.state ^ newState) { // the state has changed
|
||||
this.state = newState;
|
||||
this.element.className = NeonLamp.levelClass[newState];
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
NeonLamp.prototype.flip = function flip() {
|
||||
/* Complements the visible state of the lamp */
|
||||
|
||||
this.set(1.0 - this.state/NeonLamp.lampLevels);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
NeonLamp.prototype.setCaption = function setCaption(caption, atBottom) {
|
||||
/* Establishes an optional caption at the top or bottom of a single lamp.
|
||||
Returns the caption element */
|
||||
var e = (atBottom ? this.bottomCaptionDiv : this.topCaptionDiv);
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
e = document.createElement("div");
|
||||
if (atBottom) {
|
||||
this.bottomCaptionDiv = e;
|
||||
e.className = NeonLamp.bottomCaptionClass;
|
||||
} else {
|
||||
this.topCaptionDiv = e;
|
||||
e.className = NeonLamp.topCaptionClass;
|
||||
}
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
this.element.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Neon Lamp Box *
|
||||
***********************************************************************/
|
||||
function NeonLampBox(parent, x, y, id, caption) {
|
||||
/* Constructor for the neon lamp-in-a-box objects used within panels.
|
||||
x & y are the coordinates of the box within its containing element;
|
||||
id is the DOM id */
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("div");
|
||||
this.element.id = id;
|
||||
this.element.className = NeonLampBox.lampBoxClass;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
this.lamp = new NeonLamp(this.element, 3, 3, id + "_Lamp");
|
||||
|
||||
this.button = document.createElement("div");
|
||||
this.button.className = NeonLampBox.lampButtonClass;
|
||||
this.button.textContent = caption;
|
||||
this.element.appendChild(this.button);
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
NeonLampBox.lampBoxClass = "lampBox";
|
||||
NeonLampBox.lampButtonClass = "lampButton";
|
||||
|
||||
/**************************************/
|
||||
NeonLampBox.prototype.set = function set(state) {
|
||||
/* Changes the visible state of the lamp according to the value of "state", 0-1 */
|
||||
|
||||
this.lamp.set(state);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
NeonLampBox.prototype.flip = function flip() {
|
||||
/* Complements the visible state of the lamp */
|
||||
|
||||
this.lamp.flip();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
NeonLampBox.prototype.setCaption = function setCaption(caption) {
|
||||
/* Establishes an optional caption on the button for a single lamp */
|
||||
|
||||
this.button.textContent = caption;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Colored Lamp *
|
||||
***********************************************************************/
|
||||
function ColoredLamp(parent, x, y, id, offClass, onClass) {
|
||||
/* Constructor for the colored lamp objects used within panels. x & y are
|
||||
the coordinates of the lamp within its containing element; id is the DOM id */
|
||||
|
||||
this.state = 0; // current lamp state, 0=off
|
||||
this.topCaptionDiv = null; // optional top caption element
|
||||
this.bottomCaptionDiv = null; // optional bottom caption element
|
||||
this.lampClass = offClass; // css styling for an "off" lamp
|
||||
this.litClass = // css styling for an "on" lamp
|
||||
offClass + " " + onClass;
|
||||
this.levelClass = [ // css class names for the lamp levels
|
||||
offClass,
|
||||
this.litClass + "1",
|
||||
this.litClass + "2",
|
||||
this.litClass + "3",
|
||||
this.litClass + "4",
|
||||
this.litClass + "5",
|
||||
this.litClass];
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("div");
|
||||
this.element.id = id;
|
||||
this.element.className = offClass;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
ColoredLamp.lampLevels = 6;
|
||||
ColoredLamp.topCaptionClass = "coloredLampTopCaption";
|
||||
ColoredLamp.bottomCaptionClass = "coloredLampBottomCaption";
|
||||
|
||||
/**************************************/
|
||||
ColoredLamp.prototype.set = function set(state) {
|
||||
/* Changes the visible state of the lamp according to the value of "state", 0-1 */
|
||||
var newState = Math.max(Math.min(Math.round(state*ColoredLamp.lampLevels + 0.4999), ColoredLamp.lampLevels), 0);
|
||||
|
||||
if (this.state != newState) { // the state has changed
|
||||
this.state = newState;
|
||||
this.element.className = this.levelClass[newState];
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ColoredLamp.prototype.flip = function flip() {
|
||||
/* Complements the visible state of the lamp */
|
||||
|
||||
this.set(ColoredLamp.lampLevels - this.state);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ColoredLamp.prototype.setCaption = function setCaption(caption, atBottom) {
|
||||
/* Establishes an optional caption at the top or bottom of a single lamp.
|
||||
Returns the caption element */
|
||||
var e = (atBottom ? this.bottomCaptionDiv : this.topCaptionDiv);
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
e = document.createElement("div");
|
||||
if (atBottom) {
|
||||
this.bottomCaptionDiv = e;
|
||||
e.className = ColoredLamp.bottomCaptionClass;
|
||||
} else {
|
||||
this.topCaptionDiv = e;
|
||||
e.className = ColoredLamp.topCaptionClass;
|
||||
}
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
this.element.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Toggle Switch *
|
||||
***********************************************************************/
|
||||
function ToggleSwitch(parent, x, y, id, offImage, onImage) {
|
||||
/* Constructor for the toggle switch objects used within panels. x & y are
|
||||
the coordinates of the switch within its containing element; id is the DOM id */
|
||||
|
||||
this.state = 0; // current switch state, 0=off
|
||||
this.topCaptionDiv = null; // optional top caption element
|
||||
this.bottomCaptionDiv = null; // optional bottom caption element
|
||||
this.offImage = offImage; // image used for the off state
|
||||
this.onImage = onImage; // image used for the on state
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("img");
|
||||
this.element.id = id;
|
||||
this.element.src = offImage;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
ToggleSwitch.topCaptionClass = "toggleSwitchTopCaption";
|
||||
ToggleSwitch.bottomCaptionClass = "toggleSwitchBottomCaption";
|
||||
|
||||
/**************************************/
|
||||
ToggleSwitch.prototype.set = function set(state) {
|
||||
/* Changes the visible state of the switch according to the low-order
|
||||
bit of "state" */
|
||||
var newState = state & 1;
|
||||
|
||||
if (this.state ^ newState) { // the state has changed
|
||||
this.state = newState;
|
||||
this.element.src = (newState ? this.onImage : this.offImage);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ToggleSwitch.prototype.flip = function flip() {
|
||||
/* Complements the visible state of the switch */
|
||||
var newState = this.state ^ 1;
|
||||
|
||||
this.state = newState;
|
||||
this.element.src = (newState ? this.onImage : this.offImage);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ToggleSwitch.prototype.setCaption = function setCaption(caption, atBottom) {
|
||||
/* Establishes an optional caption at the top or bottom of a single switch.
|
||||
Returns the caption element */
|
||||
var e = (atBottom ? this.bottomCaptionDiv : this.topCaptionDiv);
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
e = document.createElement("div");
|
||||
if (atBottom) {
|
||||
this.bottomCaptionDiv = e;
|
||||
e.className = ToggleSwitch.bottomCaptionClass;
|
||||
} else {
|
||||
this.topCaptionDiv = e;
|
||||
e.className = ToggleSwitch.topCaptionClass;
|
||||
}
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
this.element.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Three-way Toggle Switch *
|
||||
***********************************************************************/
|
||||
function ThreeWaySwitch(parent, x, y, id, offImage, onImage1, onImage2) {
|
||||
/* Constructor for the three-way toggle switch objects used within panels.
|
||||
x & y are the coordinates of the switch within its containing element;
|
||||
id is the DOM id */
|
||||
|
||||
this.state = 0; // current switch state, 0=off
|
||||
this.topCaptionDiv = null; // optional top caption element
|
||||
this.bottomCaptionDiv = null; // optional bottom caption element
|
||||
this.offImage = offImage; // image used for the off state
|
||||
this.onImage1 = onImage1; // image used for the lower on state
|
||||
this.onImage2 = onImage2; // image used for the upper on state
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("img");
|
||||
this.element.id = id;
|
||||
this.element.src = offImage;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
ThreeWaySwitch.topCaptionClass = "ToggleSwitchTopCaption";
|
||||
ThreeWaySwitch.bottomCaptionClass = "ToggleSwitchBottomCaption";
|
||||
|
||||
/**************************************/
|
||||
ThreeWaySwitch.prototype.set = function set(state) {
|
||||
/* Changes the visible state of the switch according to the value
|
||||
of "state" */
|
||||
|
||||
if (this.state != state) { // the state has changed
|
||||
switch (state) {
|
||||
case 1:
|
||||
this.state = 1;
|
||||
this.element.src = this.onImage1;
|
||||
break;
|
||||
case 2:
|
||||
this.state = 2;
|
||||
this.element.src = this.onImage2;
|
||||
break;
|
||||
default:
|
||||
this.state = 0;
|
||||
this.element.src = this.offImage;
|
||||
break;
|
||||
} // switch state
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ThreeWaySwitch.prototype.flip = function flip() {
|
||||
/* Increments the visible state of the switch */
|
||||
|
||||
this.set(this.state+1);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
ThreeWaySwitch.prototype.setCaption = function setCaption(caption, atBottom) {
|
||||
/* Establishes an optional caption at the top or bottom of a single switch.
|
||||
Returns the caption element */
|
||||
var e = (atBottom ? this.bottomCaptionDiv : this.topCaptionDiv);
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
e = document.createElement("div");
|
||||
if (atBottom) {
|
||||
this.bottomCaptionDiv = e;
|
||||
e.className = ThreeWaySwitch.bottomCaptionClass;
|
||||
} else {
|
||||
this.topCaptionDiv = e;
|
||||
e.className = ThreeWaySwitch.topCaptionClass;
|
||||
}
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
this.element.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Black Control Knob *
|
||||
***********************************************************************/
|
||||
function BlackControlKnob(parent, x, y, id, initial, positions) {
|
||||
/* Constructor for the black control knob objects used within panels. x & y are
|
||||
the coordinates of the knob within its containing element; id is the DOM id;
|
||||
initial is the 0-relative index indicating the default position of the switch;
|
||||
positions is an array indicating the angular position (in degrees, where 0
|
||||
is straight up) of each of the knob's positions */
|
||||
|
||||
this.position = 0; // current knob position
|
||||
this.direction = 1; // rotate knob clockwise(1), counter-clockwise(-1)
|
||||
this.topCaptionDiv = null; // optional top caption element
|
||||
this.bottomCaptionDiv = null; // optional bottom caption element
|
||||
this.positions = positions; // array of knob position angles
|
||||
|
||||
// visible DOM element
|
||||
this.element = document.createElement("canvas");
|
||||
this.element.id = id;
|
||||
this.element.width = BlackControlKnob.size;
|
||||
this.element.height = BlackControlKnob.size;
|
||||
this.element.className = BlackControlKnob.className;
|
||||
if (x !== null) {
|
||||
this.element.style.left = x.toString() + "px";
|
||||
}
|
||||
if (y !== null) {
|
||||
this.element.style.top = y.toString() + "px";
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this.element);
|
||||
}
|
||||
|
||||
this.set(initial); // set to its initial position
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
BlackControlKnob.topCaptionClass = "blackControlKnobTopCaption";
|
||||
BlackControlKnob.bottomCaptionClass = "blackControlKnobBottomCaption";
|
||||
BlackControlKnob.className = "blackControlKnob1";
|
||||
BlackControlKnob.size = 64; // width/height in pixels
|
||||
|
||||
/**************************************/
|
||||
BlackControlKnob.prototype.set = function set(position) {
|
||||
/* Changes the visible state of the knob according to the position index */
|
||||
var dc = this.element.getContext("2d");
|
||||
var degrees = Math.PI/180;
|
||||
var fullCircle = 360*degrees;
|
||||
var halfSize = Math.floor(BlackControlKnob.size/2);
|
||||
var quarterSize = Math.floor(BlackControlKnob.size/4);
|
||||
var silverSkirt;
|
||||
|
||||
if (position < 0) {
|
||||
this.position = 0;
|
||||
this.direction = 1;
|
||||
} else if (position < this.positions.length) {
|
||||
this.position = position;
|
||||
} else {
|
||||
this.position = this.positions.length-1;
|
||||
this.direction = -1;
|
||||
}
|
||||
|
||||
dc.save();
|
||||
dc.translate(halfSize+0.5, halfSize+0.5); // move origin to the center
|
||||
|
||||
dc.fillStyle = "#246"; // fill in the panel background (aids antialiasing)
|
||||
dc.fillRect(-halfSize, -halfSize, BlackControlKnob.size, BlackControlKnob.size);
|
||||
|
||||
silverSkirt = dc.createRadialGradient(0, 0, halfSize, 0, 0, quarterSize);
|
||||
silverSkirt.addColorStop(0.5, "#FFF");
|
||||
silverSkirt.addColorStop(1, "#CCC");
|
||||
|
||||
dc.beginPath(); // draw the outer skirt of the knob
|
||||
dc.arc(0, 0, halfSize-1, 0, fullCircle, false);
|
||||
dc.fillStyle = silverSkirt;
|
||||
dc.fill();
|
||||
|
||||
dc.beginPath(); // draw the central knob
|
||||
dc.arc(0, 0, quarterSize, 0, fullCircle, false);
|
||||
dc.fillStyle = "#000";
|
||||
dc.fill();
|
||||
|
||||
dc.beginPath(); // draw the inset on top of the knob
|
||||
dc.arc(0, 0, quarterSize-4, 0, fullCircle, false);
|
||||
dc.fillStyle = "#333";
|
||||
dc.fill();
|
||||
|
||||
dc.save(); // draw the knob indicator
|
||||
dc.rotate(this.positions[this.position]*degrees);
|
||||
dc.beginPath();
|
||||
dc.moveTo(0, -halfSize);
|
||||
dc.lineTo(-quarterSize/4, -halfSize+quarterSize/2);
|
||||
dc.lineTo(quarterSize/4, -halfSize+quarterSize/2);
|
||||
dc.closePath();
|
||||
dc.fillStyle = "#000";
|
||||
dc.fill();
|
||||
dc.restore(); // undo the rotation
|
||||
dc.restore(); // undo the translation
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
BlackControlKnob.prototype.step = function step() {
|
||||
/* Steps the knob to its next position. If it is at the last position, steps it
|
||||
to the first position */
|
||||
var position = this.position+this.direction;
|
||||
|
||||
if (position < 0) {
|
||||
this.direction = 1;
|
||||
this.set(1);
|
||||
} else if (position < this.positions.length) {
|
||||
this.set(position);
|
||||
} else {
|
||||
this.direction = -1;
|
||||
this.set(this.positions.length-2);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
BlackControlKnob.prototype.setCaption = function setCaption(caption, atBottom) {
|
||||
/* Establishes an optional caption at the top or bottom of a single switch.
|
||||
Returns the caption element */
|
||||
var e = (atBottom ? this.bottomCaptionDiv : this.topCaptionDiv);
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
e = document.createElement("div");
|
||||
if (atBottom) {
|
||||
this.bottomCaptionDiv = e;
|
||||
e.className = blackControlKnob.bottomCaptionClass;
|
||||
} else {
|
||||
this.topCaptionDiv = e;
|
||||
e.className = blackControlKnob.topCaptionClass;
|
||||
}
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
this.element.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Panel Register *
|
||||
***********************************************************************/
|
||||
function PanelRegister(parent, bits, rows, idPrefix, caption) {
|
||||
/* Constructor for the register objects used within panels:
|
||||
parent:the DOM element (usually a <div>) within which the register will be built
|
||||
bits: number of bits in register
|
||||
rows: number of rows used to display the bit lamps
|
||||
caption:optional caption displayed at the bottom of the register
|
||||
*/
|
||||
var cols = Math.floor((bits+rows-1)/rows);
|
||||
var b;
|
||||
var cx;
|
||||
var cy;
|
||||
var e;
|
||||
|
||||
this.element = parent; // containing element for the panel
|
||||
this.bits = bits; // number of bits in the register
|
||||
this.caption = caption || ""; // panel caption
|
||||
this.lastValue = 0; // prior register value
|
||||
this.lamps = new Array(bits); // bit lamps
|
||||
|
||||
cx = cols*PanelRegister.hSpacing + PanelRegister.hOffset;
|
||||
for (b=0; b<bits; b++) {
|
||||
if (b%rows == 0) {
|
||||
cy = (rows-1)*PanelRegister.vSpacing + PanelRegister.vOffset;
|
||||
cx -= PanelRegister.hSpacing;
|
||||
} else {
|
||||
cy -= PanelRegister.vSpacing;
|
||||
}
|
||||
|
||||
this.lamps[b] = new NeonLampBox(parent, cx, cy, idPrefix + b.toString());
|
||||
}
|
||||
|
||||
this.captionDiv = document.createElement("div");
|
||||
this.captionDiv.className = PanelRegister.captionClass;
|
||||
this.captionDiv.style.top = "0";
|
||||
this.captionDiv.style.left = "0";
|
||||
if (caption) {
|
||||
e = document.createElement("span");
|
||||
e.className = PanelRegister.captionSpanClass;
|
||||
e.appendChild(document.createTextNode(caption.substring(0, 1)));
|
||||
this.captionDiv.appendChild(e);
|
||||
}
|
||||
parent.appendChild(this.captionDiv);
|
||||
|
||||
this.leftClearBar = document.createElement("div");
|
||||
this.leftClearBar.className = PanelRegister.regClearBarClass;
|
||||
this.leftClearBar.style.left = "0";
|
||||
parent.appendChild(this.leftClearBar);
|
||||
|
||||
this.rightClearBar = document.createElement("div");
|
||||
this.rightClearBar.className = PanelRegister.regClearBarClass;
|
||||
this.rightClearBar.style.right = "0";
|
||||
parent.appendChild(this.rightClearBar);
|
||||
|
||||
e = document.createElement("div");
|
||||
e.className = PanelRegister.regSpacerClass;
|
||||
e.style.top = "0";
|
||||
e.style.right = "0";
|
||||
parent.appendChild(e);
|
||||
|
||||
e = document.createElement("div");
|
||||
e.className = PanelRegister.regSpacerClass;
|
||||
e.style.bottom = "0";
|
||||
e.style.left = "0";
|
||||
parent.appendChild(e);
|
||||
|
||||
e = document.createElement("div");
|
||||
e.className = PanelRegister.regSpacerClass;
|
||||
e.style.bottom = "0";
|
||||
e.style.right = "0";
|
||||
parent.appendChild(e);
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
PanelRegister.hSpacing = 24; // horizontal lamp spacing, pixels
|
||||
PanelRegister.hOffset = 24; // horizontal lamp offset within container
|
||||
PanelRegister.vSpacing = 32; // vertical lamp spacing, pixels
|
||||
PanelRegister.vOffset = 0; // vertical lamp offset within container
|
||||
PanelRegister.lampDiameter = 20; // lamp outer diameter, pixels
|
||||
PanelRegister.panelClass = "panelRegister";
|
||||
PanelRegister.captionClass = "panelRegCaption";
|
||||
PanelRegister.regSpacerClass = "panelRegSpacer";
|
||||
PanelRegister.regClearBarClass = "panelRegClearBar";
|
||||
PanelRegister.captionSpanClass = "panelRegSpan";
|
||||
PanelRegister.boxCaptionClass = "boxCaption";
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.xCoord = function xCoord(col) {
|
||||
/* Returns the horizontal lamp coordinate in pixels */
|
||||
|
||||
return ((col-1)*PanelRegister.hSpacing + PanelRegister.hOffset);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.yCoord = function yCoord(row) {
|
||||
/* Returns the vertical lamp coordinate in pixels */
|
||||
|
||||
return ((row-1)*PanelRegister.vSpacing + PanelRegister.vOffset);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.panelWidth = function panelWidth(cols) {
|
||||
/* Returns the width of a register panel in pixels */
|
||||
|
||||
return (cols-1)*PanelRegister.hSpacing + PanelRegister.hOffset*2 + PanelRegister.lampDiameter;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.panelHeight = function panelHeight(rows) {
|
||||
/* Returns the height of a register panel in pixels */
|
||||
|
||||
return (rows-1)*PanelRegister.vSpacing + PanelRegister.vOffset*2 + PanelRegister.lampDiameter;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.drawBox = function drawBox(col, lamps, rows, leftStyle, rightStyle) {
|
||||
/* Creates a box centered around a specified group of lamps in a register.
|
||||
leftStyle and rightStyle specify the left and right borders of the box using
|
||||
standard CSS border syntax. Returns the box element */
|
||||
var box = document.createElement("div");
|
||||
var rightBias = (rightStyle ? 1 : 0);
|
||||
|
||||
box.style.position = "absolute";
|
||||
box.style.left = (this.xCoord(col) - (PanelRegister.hSpacing-PanelRegister.lampDiameter)/2).toString() + "px";
|
||||
box.style.width = (PanelRegister.hSpacing*lamps - rightBias).toString() + "px";
|
||||
box.style.top = this.yCoord(1).toString() + "px";
|
||||
box.style.height = (this.yCoord(rows) - this.yCoord(1) + PanelRegister.lampDiameter).toString() + "px";
|
||||
box.style.borderLeft = leftStyle;
|
||||
box.style.borderRight = rightStyle;
|
||||
box.appendChild(document.createTextNode("\xA0"));
|
||||
this.element.appendChild(box);
|
||||
return box;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.setBoxCaption = function setBoxCaption(box, caption) {
|
||||
/* Establishes an optional caption for register lamp box.
|
||||
Returns the caption element */
|
||||
var e = box.captionDiv;
|
||||
|
||||
if (e) {
|
||||
e.textContent = caption;
|
||||
} else {
|
||||
box.captionDiv = e = document.createElement("div");
|
||||
e.className = PanelRegister.boxCaptionClass;
|
||||
e.appendChild(document.createTextNode(caption));
|
||||
box.appendChild(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.update = function update(value) {
|
||||
/* Update the register lamps from the value of the parameter. This routine
|
||||
compares the value of the register that was previously updated against the new
|
||||
one in an attempt to minimize the number of lamp flips that need to be done */
|
||||
var bitBase = 0;
|
||||
var bitNr;
|
||||
var lastMask;
|
||||
var lastValue = this.lastValue;
|
||||
var thisMask;
|
||||
var thisValue = Math.floor(Math.abs(value)) % 0x100000000000;
|
||||
|
||||
if (thisValue != lastValue) {
|
||||
this.lastValue = thisValue; // save it for next time
|
||||
do {
|
||||
// Loop through the masks 30 bits at a time so we can use Javascript bit ops
|
||||
bitNr = bitBase;
|
||||
lastMask = lastValue % 0x40000000; // get the low-order 30 bits
|
||||
lastValue = (lastValue-lastMask)/0x40000000; // shift the value right 30 bits
|
||||
thisMask = thisValue % 0x40000000; // ditto for the second value
|
||||
thisValue = (thisValue-thisMask)/0x40000000;
|
||||
|
||||
lastMask ^= thisMask; // determine which bits have changed
|
||||
while (lastMask) {
|
||||
if (lastMask & 0x01) {
|
||||
this.lamps[bitNr].set(thisMask & 0x01);
|
||||
}
|
||||
if (++bitNr <= this.bits) {
|
||||
lastMask >>>= 1;
|
||||
thisMask >>>= 1;
|
||||
} else {
|
||||
thisValue = thisMask = 0;
|
||||
lastValue = lastMask = 0;
|
||||
break; // out of inner while loop
|
||||
}
|
||||
}
|
||||
|
||||
bitBase += 30;
|
||||
} while (thisValue || lastValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
PanelRegister.prototype.updateGlow = function updateGlow(glow) {
|
||||
/* Update the register lamps from the bitwise intensity values in "glow" */
|
||||
var bitNr;
|
||||
|
||||
for (bitNr=this.bits-1; bitNr>=0; --bitNr) {
|
||||
this.lamps[bitNr].set(glow[bitNr]);
|
||||
}
|
||||
};
|
||||
275
webUI/B220SetCallback.js
Normal file
@@ -0,0 +1,275 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220SetCallback.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2014,2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* B220 emulator universal function call-back module.
|
||||
*
|
||||
* Implements a combination setTimeout() and setImmediate() facility for the
|
||||
* B220 emulator web-based user interface. setCallback() is used the same way
|
||||
* that setTimeout() is used, except that for low values of the timeout parameter,
|
||||
* it merely yields control to any other pending events and timers before calling
|
||||
* the call-back function.
|
||||
*
|
||||
* This facility is needed because modern browsers implement a minimum delay
|
||||
* when calling setTimeout(). HTML5 specs require 4ms, but browsers vary in the
|
||||
* minimum they use, and their precision in activating the call-back function
|
||||
* once the actual delay is established varies even more. This module will use
|
||||
* setTimeout() if the requested delay time is above a certain threshold, and
|
||||
* a setImmediate()-like mechanism (based on window.postMessage) if the requested
|
||||
* delay is below that threshold.
|
||||
*
|
||||
* To help compensate for the fact that the call-back function may be called
|
||||
* sooner than requested, and that due either to other activity or to browser
|
||||
* limitations the delay may be longer than requested, the timing behavior of
|
||||
* setCallback() may be divided into "categories." For each category, a separate
|
||||
* record is kept of the current total deviation between the requested delay and
|
||||
* the actual delay. A portion of this deviation is then applied to the requested
|
||||
* delay on subsequent calls in an attempt to smooth out the differences. We are
|
||||
* going for good average behavior here, and some too-quick call-backs are better
|
||||
* than consistently too-long callbacks in this environment, so that I/Os can be
|
||||
* initiated and their finish detected in finer-grained time increments.
|
||||
*
|
||||
* The SetCallback mechanism defines three functions that become members of the
|
||||
* global (window) object:
|
||||
*
|
||||
* token = setCallback(category, context, delay, fcn[, arg])
|
||||
*
|
||||
* Requests that the function "fcn" be called after "delay" milliseconds.
|
||||
* The function will be called as a method of "context", passing a
|
||||
* single optional argument "arg". The call-back "fcn" may be called
|
||||
* earlier or later than the specified delay. The string "category" (which
|
||||
* may be empty, null, or undefined) defines the category under which the
|
||||
* average delay difference will be maintained. setCallBack returns a
|
||||
* numeric token identifying the call-back event, which can be used
|
||||
* with clearCallback(). Note that passing a string in lieu of a function
|
||||
* object is not permitted.
|
||||
*
|
||||
* clearCallBack(token)
|
||||
*
|
||||
* Cancels a pending call-back event, if in fact it is still pending.
|
||||
* The "token" parameter is a value returned from setCallback().
|
||||
*
|
||||
* object = getCallbackState(optionMask)
|
||||
*
|
||||
* This is a diagnostic function intended for use in monitoring the callback
|
||||
* mechanism. It returns an object that, depending upon bits set in its mask
|
||||
* parameter, contains copies of the lastTokenNr value, poolLength
|
||||
* value, current delayDev hash, pendingCallbacks hash, and pool array.
|
||||
* The optionMask parameter supports the following bit values:
|
||||
* bit 0x01: delayDev hash
|
||||
* bit 0x02: pendingCallbacks hash
|
||||
* bit 0x04: pool array
|
||||
* The lastTokenNr and poolLength values are always returned. If no mask
|
||||
* is supplied, no additional items are returned.
|
||||
*
|
||||
* This implementation has been inspired by Domenic Denicola's shim for the
|
||||
* setImmediate() API at https://github.com/NobleJS/setImmediate, and
|
||||
* David Baron's setZeroTimeout() implemenmentation described in his blog
|
||||
* at http://dbaron.org/log/20100309-faster-timeouts.
|
||||
*
|
||||
* I stole a little of their code, too.
|
||||
*
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, cloned from retro-205 emulator D205SetCallback.js.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
(function (global) {
|
||||
/* Define a closure for the setCallback() mechanism */
|
||||
var delayDev = {NUL: 0}; // hash of delay time deviations by category
|
||||
var minTimeout = 4; // minimum setTimeout() threshold, milliseconds
|
||||
var lastTokenNr = 0; // last setCallback token return value
|
||||
var pendingCallbacks = {}; // hash of pending callbacks, indexed by token as a string
|
||||
var perf = global.performance; // cached window.performance object
|
||||
var pool = []; // pool of reusable callback objects
|
||||
var poolLength = 0; // length of active entries in pool
|
||||
var secretPrefix = "retro-205.webUI." + Date.now().toString(16);
|
||||
|
||||
/**************************************/
|
||||
function activateCallback(token) {
|
||||
/* Activates a callback after its delay period has expired */
|
||||
var category;
|
||||
var endStamp = perf.now();
|
||||
var thisCallback;
|
||||
var tokenName = token.toString();
|
||||
|
||||
thisCallback = pendingCallbacks[tokenName];
|
||||
if (thisCallback) {
|
||||
delete pendingCallbacks[tokenName];
|
||||
category = thisCallback.category;
|
||||
if (category) {
|
||||
delayDev[category] += endStamp - thisCallback.startStamp - thisCallback.delay;
|
||||
}
|
||||
try {
|
||||
thisCallback.fcn.call(thisCallback.context, thisCallback.arg);
|
||||
} catch (err) {
|
||||
console.log("B220SetCallback.activateCallback: " + err.name + ", " + err.message);
|
||||
}
|
||||
|
||||
thisCallback.context = null;
|
||||
thisCallback.fcn = null;
|
||||
thisCallback.arg = null;
|
||||
pool[poolLength++] = thisCallback;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function clearCallback(token) {
|
||||
/* Disables a pending callback, if it still exists and is still pending */
|
||||
var thisCallback;
|
||||
var tokenName = token.toString();
|
||||
|
||||
thisCallback = pendingCallbacks[tokenName];
|
||||
if (thisCallback) {
|
||||
delete pendingCallbacks[tokenName];
|
||||
if (thisCallback.isTimeout) {
|
||||
if (thisCallback.cancelToken) {
|
||||
global.clearTimeout(thisCallback.cancelToken);
|
||||
}
|
||||
}
|
||||
|
||||
thisCallback.context = null;
|
||||
thisCallback.fcn = null;
|
||||
thisCallback.arg = null;
|
||||
pool[poolLength++] = thisCallback;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function setCallback(category, context, callbackDelay, fcn, arg) {
|
||||
/* Sets up and schedules a callback for function "fcn", called with context
|
||||
"context", after a delay of "delay" ms. An optional "arg" value will be passed
|
||||
to "fcn". If the delay is less than "minTimeout", a setImmediate-like mechanism
|
||||
based on window.postsMessage() will be used; otherwise the environment's standard
|
||||
setTimeout mechanism will be used */
|
||||
var categoryName = (category || "NUL").toString();
|
||||
var delay = callbackDelay || 0; // actual delay to be generated
|
||||
var delayBias; // current amount of delay deviation
|
||||
var ratio; // ratio of delay to delayBias
|
||||
var thisCallback; // call-back object to be used
|
||||
var token = ++lastTokenNr; // call-back token number
|
||||
var tokenName = token.toString(); // call-back token ID
|
||||
|
||||
// Allocate a call-back object from the pool.
|
||||
if (poolLength <= 0) {
|
||||
thisCallback = {};
|
||||
} else {
|
||||
thisCallback = pool[--poolLength];
|
||||
pool[poolLength] = null;
|
||||
}
|
||||
|
||||
delayBias = delayDev[categoryName];
|
||||
if (!delayBias) {
|
||||
delayDev[categoryName] = 0; // bias was zero, or got a new one
|
||||
} else {
|
||||
ratio = delay/delayBias;
|
||||
if (ratio > 1) {
|
||||
delay -= delayBias;
|
||||
delayDev[categoryName] = 0;
|
||||
} else if (ratio > 0) {
|
||||
delayDev[categoryName] -= delay;
|
||||
delay = 0;
|
||||
} else if (ratio < -1) {
|
||||
delay += delayBias;
|
||||
delayDev[categoryName] = 0;
|
||||
} else {
|
||||
delayDev[categoryName] += delay;
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the call-back object and tank it in pendingCallbacks.
|
||||
thisCallback.startStamp = perf.now();
|
||||
thisCallback.category = categoryName;
|
||||
thisCallback.context = context || this;
|
||||
thisCallback.delay = delay;
|
||||
thisCallback.fcn = fcn;
|
||||
thisCallback.arg = arg;
|
||||
pendingCallbacks[tokenName] = thisCallback;
|
||||
|
||||
// Decide whether to do a time wait or just a yield.
|
||||
if (delay > minTimeout) {
|
||||
thisCallback.isTimeout = true;
|
||||
thisCallback.cancelToken = global.setTimeout(activateCallback, delay, token);
|
||||
} else {
|
||||
thisCallback.isTimeout = false;
|
||||
thisCallback.cancelToken = 0;
|
||||
global.postMessage(secretPrefix + tokenName, "*");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function onMessage(ev) {
|
||||
/* Handler for the global.onmessage event. Activates the callback */
|
||||
var payload;
|
||||
|
||||
if (ev.source === global) {
|
||||
payload = ev.data.toString();
|
||||
if (payload.substring(0, secretPrefix.length) === secretPrefix) {
|
||||
activateCallback(payload.substring(secretPrefix.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
function getCallbackState(optionMask) {
|
||||
/* Diagnostic function. Returns an object that, depending upon bits in
|
||||
the option mask, contains copies of the lastTokenNr value, poolLength
|
||||
value, current delayDev hash, pendingCallbacks hash, and pool array.
|
||||
bit 0x01: delayDev hash
|
||||
bit 0x02: pendingCallbacks hash
|
||||
bit 0x04: pool array
|
||||
If no mask is supplied, no additional items are returned */
|
||||
var e;
|
||||
var mask = optionMask || 0;
|
||||
var state = {
|
||||
lastTokenNr: lastTokenNr,
|
||||
poolLength: poolLength,
|
||||
delayDev: {},
|
||||
pendingCallbacks: {},
|
||||
pool: []};
|
||||
|
||||
if (mask & 0x01) {
|
||||
for (e in delayDev) {
|
||||
state.delayDev[e] = delayDev[e];
|
||||
}
|
||||
}
|
||||
if (mask & 0x02) {
|
||||
for (e in pendingCallbacks) {
|
||||
state.pendingCallbacks[e] = pendingCallbacks[e];
|
||||
}
|
||||
}
|
||||
if (mask & 0x04) {
|
||||
for (e=0; e<poolLength; ++e) {
|
||||
state.pool[e] = pool[e];
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/********** Outer block of anonymous closure **********/
|
||||
if (!global.setCallback && global.postMessage && !global.importScripts) {
|
||||
// Attach to the prototype of global, if possible, otherwise to global itself
|
||||
var attachee = global;
|
||||
|
||||
/*****
|
||||
if (typeof Object.getPrototypeOf === "function") {
|
||||
if ("setTimeout" in Object.getPrototypeOf(global)) {
|
||||
attachee = Object.getPrototypeOf(global);
|
||||
}
|
||||
}
|
||||
*****/
|
||||
|
||||
global.addEventListener("message", onMessage, false);
|
||||
attachee.setCallback = setCallback;
|
||||
attachee.clearCallback = clearCallback;
|
||||
attachee.getCallbackState = getCallbackState;
|
||||
}
|
||||
}(typeof global === "object" && global ? global : this));
|
||||
100
webUI/B220SystemConfig.css
Normal file
@@ -0,0 +1,100 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220SystemConfig.css
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator System Configuration web interface style sheet.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 webUI/D205SystemConfig.css.
|
||||
***********************************************************************/
|
||||
|
||||
#configBody {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0}
|
||||
|
||||
#configDiv {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 4px}
|
||||
|
||||
#PageHeading {
|
||||
position: relative;
|
||||
height: 40px;
|
||||
width: 100%}
|
||||
|
||||
#SysConfigHeading {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 18px}
|
||||
|
||||
.heading {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.25em;
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 18px}
|
||||
|
||||
#B220Logo {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background-color: #EEE;
|
||||
color: #333333;
|
||||
font-size: 6pt;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px}
|
||||
|
||||
#RetroLogoImage {
|
||||
vertical-align: bottom;
|
||||
margin: 4px}
|
||||
|
||||
#ConsoleTable,
|
||||
#CardatronTable,
|
||||
#MagTapeOptionsTable,
|
||||
#MagTapeTable {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
font-family: DejaVuSansWeb, sans-serif;
|
||||
font-size: 8pt}
|
||||
|
||||
#ConsoleTable TH,
|
||||
#ConsoleTable TD,
|
||||
#CardatronTable TH,
|
||||
#CardatronTable TD,
|
||||
#MagTapeOptionsTable TH,
|
||||
#MagTapeOptionsTable TD,
|
||||
#MagTapeTable TH,
|
||||
#MagTapeTable TD {
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
width: 4em;
|
||||
white-space: nowrap}
|
||||
|
||||
#MessageArea {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 8px;
|
||||
right: 90px;
|
||||
width: auto;
|
||||
font-size: 8pt}
|
||||
|
||||
#CancelBtn {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 80px;
|
||||
height: 20px}
|
||||
|
||||
#SaveBtn {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
height: 20px}
|
||||
464
webUI/B220SystemConfig.html
Normal file
@@ -0,0 +1,464 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>retro-220 Emulator System Configuration</title>
|
||||
<!--
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220SystemConfig.html
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator System Configuration page.
|
||||
*
|
||||
* Implements the system configuration user interface for the B220 emulator.
|
||||
*
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205/webUI/D205SystemConfig.html.
|
||||
***********************************************************************/
|
||||
-->
|
||||
<meta name="Author" content="Paul Kimpel">
|
||||
<meta http-equiv="Content-Script-Type" content="text/javascript">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B220Common.css">
|
||||
<link id=configStyleSheet rel=stylesheet type="text/css" href="B220SystemConfig.css">
|
||||
</head>
|
||||
|
||||
<body id=configBody class=deviceBody>
|
||||
|
||||
<div id=configDiv class=devicePanel>
|
||||
<div id=PageHeading>
|
||||
<span id=SysConfigHeading>Burroughs 220 System Configuration</span>
|
||||
<div id=B220Logo>
|
||||
<img id=RetroLogoImage src="./resources/retro-220-Logo.png" alt="retro-220 logo">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
|
||||
<div class=heading>Console Unit Selection:</div>
|
||||
|
||||
<table id=ConsoleTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class=center>
|
||||
<input id=ConsoleFlex type=checkbox value=1 checked>
|
||||
<td>
|
||||
<label for=ConsoleFlex>Flexowriter Printer
|
||||
<tr>
|
||||
<td class=center>
|
||||
<input id=ConsoleTapeReader type=checkbox value=1 checked>
|
||||
<td>
|
||||
<label for=ConsoleTapeReader>Paper Tape Readers (mechanical & optical)
|
||||
<tr>
|
||||
<td class=center>
|
||||
<input id=ConsoleTapePunch type=checkbox value=1 checked>
|
||||
<td>
|
||||
<label for=ConsoleTapePunch>Paper Tape Punch
|
||||
</table>
|
||||
|
||||
<div class=heading>Cardatron Unit Selection:</div>
|
||||
|
||||
<table id=CardatronTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slot<th>Type<th>Algol Glyphs<th>Greenbar<th>Zero-Suppress Columns (set on device)
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class=center>1
|
||||
<td class=center>
|
||||
<select id=Cardatron1Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR1>Card Reader 1
|
||||
<option value=CP7>Card Punch 7
|
||||
<option value=LP7>Line Printer 7
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron1AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron1Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron1ZeroSuppressCols>
|
||||
|
||||
|
||||
<tr>
|
||||
<td class=center>2
|
||||
<td class=center>
|
||||
<select id=Cardatron2Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR2>Card Reader 2
|
||||
<option value=CP6>Card Punch 6
|
||||
<option value=LP6>Line Printer 6
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron2AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron2Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron2ZeroSuppressCols>
|
||||
|
||||
<tr>
|
||||
<td class=center>3
|
||||
<td class=center>
|
||||
<select id=Cardatron3Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR3>Card Reader 3
|
||||
<option value=CP5>Card Punch 5
|
||||
<option value=LP5>Line Printer 5
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron3AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron3Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron3ZeroSuppressCols>
|
||||
|
||||
<tr>
|
||||
<td class=center>4
|
||||
<td class=center>
|
||||
<select id=Cardatron4Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR4>Card Reader 4
|
||||
<option value=CP4>Card Punch 4
|
||||
<option value=LP4>Line Printer 4
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron4AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron4Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron4ZeroSuppressCols>
|
||||
|
||||
<tr>
|
||||
<td class=center>5
|
||||
<td class=center>
|
||||
<select id=Cardatron5Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR5>Card Reader 5
|
||||
<option value=CP3>Card Punch 3
|
||||
<option value=LP3>Line Printer 3
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron5AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron5Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron5ZeroSuppressCols>
|
||||
|
||||
<tr>
|
||||
<td class=center>6
|
||||
<td class=center>
|
||||
<select id=Cardatron6Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR6>Card Reader 6
|
||||
<option value=CP2>Card Punch 2
|
||||
<option value=LP2>Line Printer 2
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron6AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron6Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron6ZeroSuppressCols>
|
||||
|
||||
<tr>
|
||||
<td class=center>7
|
||||
<td class=center>
|
||||
<select id=Cardatron7Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=CR7>Card Reader 7
|
||||
<option value=CP1>Card Punch 1
|
||||
<option value=LP1>Line Printer 1
|
||||
</select>
|
||||
<td class=center>
|
||||
<input id=Cardatron7AlgolGlyphs type=checkbox value=1>
|
||||
<td class=center>
|
||||
<input id=Cardatron7Greenbar type=checkbox value=1>
|
||||
<td id=Cardatron7ZeroSuppressCols>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<div class=heading>Magnetic Tape Unit Selection:</div>
|
||||
|
||||
<table id=MagTapeOptionsTable>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class=center>
|
||||
<input id=SuppressBMod type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<label for=SuppressBMod>Suppress B-Register Modification
|
||||
</table>
|
||||
|
||||
<table id=MagTapeTable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Unit<th>Type<th>Designate<th>Remote<th>Rewind-Ready<th>Not-Write
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class=center>A
|
||||
<td class=center>
|
||||
<select id=MagTape1Type>
|
||||
<option value=NONE>(not used)
|
||||
<option selected value=MTA>DataReader
|
||||
<option value=DFA>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape1Designate>
|
||||
<option selected value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape1Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape1RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape1NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>B
|
||||
<td class=center>
|
||||
<select id=MagTape2Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTB>DataReader
|
||||
<option value=DFB>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape2Designate>
|
||||
<option value=1>1
|
||||
<option selected value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape2Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape2RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape2NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>C
|
||||
<td class=center>
|
||||
<select id=MagTape3Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTC>DataReader
|
||||
<option value=DFC>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape3Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option selected value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape3Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape3RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape3NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>D
|
||||
<td class=center>
|
||||
<select id=MagTape4Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTD>DataReader
|
||||
<option value=DFD>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape4Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option selected value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape4Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape4RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape4NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>E
|
||||
<td class=center>
|
||||
<select id=MagTape5Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTE>DataReader
|
||||
<option value=DFE>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape5Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option selected value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape5Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape5RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape5NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>F
|
||||
<td class=center>
|
||||
<select id=MagTape6Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTF>DataReader
|
||||
<option value=DFG>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape6Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option selected value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape6Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape6RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape6NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>G
|
||||
<td class=center>
|
||||
<select id=MagTape7Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTG>DataReader
|
||||
<option value=DFG>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape7Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option selected value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape7Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape7RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape7NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>H
|
||||
<td class=center>
|
||||
<select id=MagTape8Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTH>DataReader
|
||||
<option value=DFH>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape8Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option selected value=8>8
|
||||
<option value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape8Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape8RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape8NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>I
|
||||
<td class=center>
|
||||
<select id=MagTape9Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTI>DataReader
|
||||
<option value=DFI>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape9Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option selected value=9>9
|
||||
<option value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape9Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape9RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape9NotWrite type=checkbox value=1>
|
||||
<tr>
|
||||
<td class=center>J
|
||||
<td class=center>
|
||||
<select id=MagTape10Type>
|
||||
<option selected value=NONE>(not used)
|
||||
<option value=MTJ>DataReader
|
||||
<option value=DFJ>DataFile
|
||||
</select>
|
||||
<td class=center>
|
||||
<select id=MagTape10Designate>
|
||||
<option value=1>1
|
||||
<option value=2>2
|
||||
<option value=3>3
|
||||
<option value=4>4
|
||||
<option value=5>5
|
||||
<option value=6>6
|
||||
<option value=7>7
|
||||
<option value=8>8
|
||||
<option value=9>9
|
||||
<option selected value=0>0
|
||||
<td class=center>
|
||||
<input id=MagTape10Remote type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape10RewindReady type=checkbox value=1 checked>
|
||||
<td class=center>
|
||||
<input id=MagTape10NotWrite type=checkbox value=1>
|
||||
</table>
|
||||
|
||||
|
||||
<div id=MessageArea></div>
|
||||
<button id=CancelBtn class="redButton">CANCEL</button>
|
||||
<button id=SaveBtn class="greenButton">SAVE</button>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
475
webUI/B220SystemConfig.js
Normal file
@@ -0,0 +1,475 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220SystemConfig.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator System Configuration management object.
|
||||
*
|
||||
* Defines the system configuration used internally by the emulator and the
|
||||
* methods used to manage that configuration data.
|
||||
*
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 webUI/D205SystemConfig.js.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
/**************************************/
|
||||
function B220SystemConfig() {
|
||||
/* Constructor for the SystemConfig configuration management object */
|
||||
var s;
|
||||
|
||||
this.flushTimer = 0; // timer token for flushing configuration to localStorage
|
||||
this.window = null; // configuration UI window object
|
||||
this.alertWin = window; // current base window for alert/confirm/prompt
|
||||
|
||||
// Load or create the system configuration data
|
||||
s = localStorage.getItem(this.configStorageName);
|
||||
if (!s) {
|
||||
this.createConfigData();
|
||||
} else {
|
||||
this.loadConfigData(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.configStorageName = "retro-220-Config";
|
||||
B220SystemConfig.prototype.configVersion = 1;
|
||||
B220SystemConfig.prototype.flushDelay = 60000; // flush timer setting, ms
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.$$ = function $$(id) {
|
||||
return this.window.document.getElementById(id);
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.createConfigData = function createConfigData() {
|
||||
/* Creates and initializes a new configuration data object and stores it in
|
||||
localStorage. If former state preference objects exist, these are merged into
|
||||
the new data object and then deleted */
|
||||
var pref;
|
||||
var prefs;
|
||||
var s;
|
||||
|
||||
this.configData = {
|
||||
version: this.configVersion,
|
||||
|
||||
SupervisoryPanel: {
|
||||
pulseSourceSwitch: 0,
|
||||
wordContSwitch: 0,
|
||||
frequencyKnob: 0,
|
||||
audibleAlarmSwitch: 0,
|
||||
lockNormalSwitch: 0,
|
||||
stepContinuousSwitch: 0},
|
||||
|
||||
ControlConsole: {
|
||||
hasFlexowriter: true,
|
||||
hasPaperTapeReader: true,
|
||||
hasPaperTapePunch: true,
|
||||
poSuppressSwitch: 0,
|
||||
skipSwitch: 0,
|
||||
audibleAlarmSwitch: 0,
|
||||
outputKnob: 2,
|
||||
breakpointKnob: 0,
|
||||
inputKnob: 1},
|
||||
|
||||
Flexowriter: {
|
||||
zeroSuppressSwitch: 0,
|
||||
tabSpaceSwitch: 2,
|
||||
groupingCountersSwitch: 0,
|
||||
autoStopSwitch: 0,
|
||||
powerSwitch: 1,
|
||||
wordsKnob: 0,
|
||||
linesKnob: 0,
|
||||
groupsKnob: 0},
|
||||
|
||||
Cardatron: {
|
||||
hasCardatron: true,
|
||||
units: [
|
||||
null, // unit[0] not used
|
||||
{type: "CR1", formatSelect: 0, formatCol: 1},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "LP3", algolGlyphs: true, greenBar: true, zeroSuppressCols: ""},
|
||||
{type: "CP2", algolGlyphs: true, greenBar: false, zeroSuppressCols: ""},
|
||||
{type: "CP1", algolGlyphs: true, greenBar: false, zeroSuppressCols: ""}
|
||||
]},
|
||||
|
||||
MagTape: {
|
||||
hasMagTape: true,
|
||||
suppressBSwitch: false, // false => off => suppress B-register modification
|
||||
units: [
|
||||
null, // unit[0] not used
|
||||
{type: "MTA", designate: 0, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "MTD", designate: 3, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
|
||||
{type: "MTE", designate: 4, remoteSwitch: false, rewindReadySwitch: true, notWriteSwitch: false},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"},
|
||||
{type: "NONE"}
|
||||
]}
|
||||
};
|
||||
|
||||
this.flushHandler();
|
||||
|
||||
// Convert old Supervisory Panel prefs
|
||||
s = localStorage.getItem("retro-205-SupervisoryPanel-Prefs");
|
||||
if (s) {
|
||||
try {
|
||||
prefs = JSON.parse(s);
|
||||
} finally {
|
||||
// nothing
|
||||
}
|
||||
|
||||
for (pref in prefs) {
|
||||
this.configData.SupervisoryPanel[pref] = prefs[pref];
|
||||
}
|
||||
this.flushHandler();
|
||||
localStorage.removeItem("retro-205-SupervisoryPanel-Prefs");
|
||||
}
|
||||
|
||||
// Convert old Control Console prefs
|
||||
s = localStorage.getItem("retro-205-ControlConsole-Prefs");
|
||||
if (s) {
|
||||
try {
|
||||
prefs = JSON.parse(s);
|
||||
} finally {
|
||||
// nothing
|
||||
}
|
||||
|
||||
for (pref in prefs) {
|
||||
this.configData.ControlConsole[pref] = prefs[pref];
|
||||
}
|
||||
this.flushHandler();
|
||||
localStorage.removeItem("retro-205-ControlConsole-Prefs");
|
||||
}
|
||||
|
||||
// Convert old Flexowriter prefs
|
||||
s = localStorage.getItem("retro-205-Flexowriter-Prefs");
|
||||
if (s) {
|
||||
try {
|
||||
prefs = JSON.parse(s);
|
||||
} finally {
|
||||
// nothing
|
||||
}
|
||||
|
||||
for (pref in prefs) {
|
||||
this.configData.Flexowriter[pref] = prefs[pref];
|
||||
}
|
||||
this.flushHandler();
|
||||
localStorage.removeItem("retro-205-Flexowriter-Prefs");
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.loadConfigData = function loadConfigData(jsonConfig) {
|
||||
/* Attempts to parse the JSON configuration data string and store it in
|
||||
this.configData. If the parse is unsuccessful, recreates the default configuration.
|
||||
Applies any necessary updates to older configurations */
|
||||
|
||||
try {
|
||||
this.configData = JSON.parse(jsonConfig);
|
||||
} catch (e) {
|
||||
alert("Could not parse system configuration data:\n" +
|
||||
e.message + "\nReinitializing configuration");
|
||||
this.createConfigData();
|
||||
}
|
||||
|
||||
// Apply updates
|
||||
if (this.getNode("Cardatron.hasCardatron") === undefined) {
|
||||
this.putNode("Cardatron.hasCardatron", true);
|
||||
}
|
||||
|
||||
if (this.getNode("MagTape.hasMagTape") === undefined) {
|
||||
this.putNode("MagTape.hasMagTape", true);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.flushHandler = function flushHandler() {
|
||||
/* Callback function for the flush timer. Stores the configuration data */
|
||||
|
||||
this.flushTimer = 0;
|
||||
localStorage.setItem(this.configStorageName, JSON.stringify(this.configData));
|
||||
};
|
||||
|
||||
/*************************************/
|
||||
B220SystemConfig.prototype.flush = function flush() {
|
||||
/* If the current configuration data object has been modified, stores it to
|
||||
localStorage and resets the flush timer */
|
||||
|
||||
if (this.flushTimer) {
|
||||
clearCallback(this.flushTimer);
|
||||
this.flushHandler();
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.getNode = function getNode(nodeName, index) {
|
||||
/* Retrieves a specified node of the configuration data object tree.
|
||||
"nodeName" specifies the node using dotted-path format. A blank name
|
||||
retrieves the entire tree. If the "index" parameter is specified, the final
|
||||
node in the path is assumed to be an array, and "index" used to return
|
||||
that element of the array. If a node does not exist, returns undefined */
|
||||
var name;
|
||||
var names;
|
||||
var node = this.configData;
|
||||
var top;
|
||||
var x;
|
||||
|
||||
name = nodeName.trim();
|
||||
if (name.length > 0) {
|
||||
names = name.split(".");
|
||||
top = names.length;
|
||||
for (x=0; x<top; ++x) {
|
||||
name = names[x];
|
||||
if (name in node) {
|
||||
node = node[name];
|
||||
} else {
|
||||
node = undefined;
|
||||
break; // out of for loop
|
||||
}
|
||||
} // for x
|
||||
}
|
||||
|
||||
if (index === undefined) {
|
||||
return node;
|
||||
} else {
|
||||
return node[index];
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.putNode = function putNode(nodeName, data, index) {
|
||||
/* Creates or replace a specified node of the configuration data object tree.
|
||||
"nodeName" specifies the node using dotted.path format. A blank name
|
||||
results in nothing being set. If a node does not exist, it and any necessary
|
||||
parent nodes are created. If the "index" parameter is specified, the final
|
||||
node in the path is assumed to be an array, and "index" is used to access
|
||||
that element of the array. Setting the value of a node starts a timer (if it
|
||||
is not already started). When that timer expires, the configuration data will
|
||||
be flushed to the localStorage object. This delayed storage is done so that
|
||||
several configuration changes into short order can be grouped in one flush */
|
||||
var name;
|
||||
var names;
|
||||
var node = this.configData;
|
||||
var top;
|
||||
var x;
|
||||
|
||||
name = nodeName.trim();
|
||||
if (name.length > 0) {
|
||||
names = name.split(".");
|
||||
top = names.length-1;
|
||||
for (x=0; x<top; ++x) {
|
||||
name = names[x];
|
||||
if (name in node) {
|
||||
node = node[name];
|
||||
} else {
|
||||
node = node[name] = {};
|
||||
}
|
||||
} // for x
|
||||
|
||||
if (index === undefined) {
|
||||
node[names[top]] = data;
|
||||
} else {
|
||||
node[names[top]][index] = data;
|
||||
}
|
||||
|
||||
if (!this.flushTimer) {
|
||||
this.flushTimer = setCallback("CONFIG", this, this.flushTimeout, this.flushHandler);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* System Configuration UI Support *
|
||||
***********************************************************************/
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.setListValue = function setListValue(id, value) {
|
||||
/* Sets the selection of the <select> list with the specified "id" to the
|
||||
entry with the specified "value". If no such value exists, the list
|
||||
selection is not changed */
|
||||
var e = this.$$(id);
|
||||
var opt;
|
||||
var x;
|
||||
|
||||
if (e && e.tagName == "SELECT") {
|
||||
opt = e.options;
|
||||
for (x=0; x<opt.length; ++x) {
|
||||
if (opt[x].value == value) {
|
||||
e.selectedIndex = x;
|
||||
break; // out of for loop
|
||||
}
|
||||
} // for x
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.loadConfigDialog = function loadConfigDialog() {
|
||||
/* Loads the configuration UI window with the settings from this.configData */
|
||||
var cd = this.configData; // local configuration reference
|
||||
var prefix; // unit id prefix
|
||||
var unit; // unit configuration object
|
||||
var x; // unit index
|
||||
|
||||
this.$$("ConsoleFlex").checked = cd.ControlConsole.hasFlexowriter;
|
||||
this.$$("ConsoleTapeReader").checked = cd.ControlConsole.hasPaperTapeReader;
|
||||
this.$$("ConsoleTapePunch").checked = cd.ControlConsole.hasPaperTapePunch;
|
||||
|
||||
// Cardatron units
|
||||
for (x=1; x<=7; ++x) {
|
||||
unit = cd.Cardatron.units[x];
|
||||
prefix = "Cardatron" + x;
|
||||
this.setListValue(prefix + "Type", unit.type);
|
||||
switch (unit.type.substring(0, 2)) {
|
||||
case "LP":
|
||||
this.$$(prefix + "AlgolGlyphs").checked = unit.algolGlyphs;
|
||||
this.$$(prefix + "Greenbar").checked = unit.greenBar;
|
||||
this.$$(prefix + "ZeroSuppressCols").textContent = unit.zeroSuppressCols || "";
|
||||
break;
|
||||
case "CP":
|
||||
this.$$(prefix + "AlgolGlyphs").checked = unit.algolGlyphs;
|
||||
this.$$(prefix + "Greenbar").checked = false;
|
||||
this.$$(prefix + "ZeroSuppressCols").textContent = unit.zeroSuppressCols || "";
|
||||
break;
|
||||
case "CR":
|
||||
default:
|
||||
this.$$(prefix + "AlgolGlyphs").checked = false;
|
||||
this.$$(prefix + "Greenbar").checked = false;
|
||||
this.$$(prefix + "ZeroSuppressCols").textContent = "";
|
||||
break;
|
||||
} // switch unit.type
|
||||
} // for x
|
||||
|
||||
// Magnetic Tape units
|
||||
|
||||
this.$$("SuppressBMod").checked = !cd.MagTape.suppressBSwitch;
|
||||
for (x=1; x<=10; ++x) {
|
||||
unit = cd.MagTape.units[x];
|
||||
prefix = "MagTape" + x;
|
||||
this.setListValue(prefix + "Type", unit.type);
|
||||
this.$$(prefix + "Designate").selectedIndex = unit.designate;
|
||||
this.$$(prefix + "Remote").checked = unit.remoteSwitch;
|
||||
this.$$(prefix + "RewindReady").checked = unit.rewindReadySwitch;
|
||||
this.$$(prefix + "NotWrite").checked = unit.notWriteSwitch;
|
||||
} // for x
|
||||
|
||||
this.$$("MessageArea").textContent = "205 System Configuration loaded.";
|
||||
this.window.focus();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.saveConfigDialog = function saveConfigDialog() {
|
||||
/* Saves the configuration UI window settings to this.configData and flushes
|
||||
the updated configuration to localStorage */
|
||||
var cd = this.configData; // local configuration reference
|
||||
var e; // local element reference
|
||||
var prefix; // unit id prefix
|
||||
var unit; // unit configuration object
|
||||
var x; // unit index
|
||||
|
||||
cd.ControlConsole.hasFlexowriter = this.$$("ConsoleFlex").checked;
|
||||
cd.ControlConsole.hasPaperTapeReader = this.$$("ConsoleTapeReader").checked;
|
||||
cd.ControlConsole.hasPaperTapePunch = this.$$("ConsoleTapePunch").checked;
|
||||
|
||||
// Cardatron units
|
||||
|
||||
cd.Cardatron.hasCardatron = false;
|
||||
for (x=1; x<=7; ++x) {
|
||||
unit = cd.Cardatron.units[x];
|
||||
prefix = "Cardatron" + x;
|
||||
e = this.$$(prefix + "Type");
|
||||
unit.type = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value);
|
||||
switch (unit.type.substring(0, 2)) {
|
||||
case "LP":
|
||||
cd.Cardatron.hasCardatron = true;
|
||||
unit.algolGlyphs = this.$$(prefix + "AlgolGlyphs").checked;
|
||||
unit.greenBar = this.$$(prefix + "Greenbar").checked;
|
||||
break;
|
||||
case "CP":
|
||||
cd.Cardatron.hasCardatron = true;
|
||||
unit.algolGlyphs = this.$$(prefix + "AlgolGlyphs").checked;
|
||||
unit.greenBar = false;
|
||||
break;
|
||||
case "CR":
|
||||
cd.Cardatron.hasCardatron = true;
|
||||
// no break
|
||||
default:
|
||||
unit.algolGlyphs = false;
|
||||
unit.greenBar = false;
|
||||
break;
|
||||
} // switch unit.type
|
||||
} // for x
|
||||
|
||||
|
||||
|
||||
// Magnetic Tape units
|
||||
|
||||
cd.MagTape.hasMagTape = false;
|
||||
cd.MagTape.suppressBSwitch = !this.$$("SuppressBMod").checked;
|
||||
|
||||
for (x=1; x<=10; ++x) {
|
||||
unit = cd.MagTape.units[x];
|
||||
prefix = "MagTape" + x;
|
||||
e = this.$$(prefix + "Type");
|
||||
unit.type = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value);
|
||||
unit.designate = this.$$(prefix + "Designate").selectedIndex;
|
||||
unit.remoteSwitch = this.$$(prefix + "Remote").checked;
|
||||
unit.rewindReadySwitch = this.$$(prefix + "RewindReady").checked;
|
||||
unit.notWriteSwitch = this.$$(prefix + "NotWrite").checked;
|
||||
if (unit.type != "NONE") {
|
||||
cd.MagTape.hasMagTape = true;
|
||||
}
|
||||
} // for x
|
||||
|
||||
this.flushHandler(); // store the configuration
|
||||
this.$$("MessageArea").textContent = "205 System Configuration updated.";
|
||||
this.window.close();
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.closeConfigUI = function closeConfigUI() {
|
||||
/* Closes the system configuration update dialog */
|
||||
|
||||
this.alertWin = window; // revert alerts to the global window
|
||||
window.focus();
|
||||
if (this.window) {
|
||||
if (!this.window.closed) {
|
||||
this.window.close();
|
||||
}
|
||||
this.window = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220SystemConfig.prototype.openConfigUI = function openConfigUI() {
|
||||
/* Opens the system configuration update dialog and displays the current
|
||||
system configuration */
|
||||
|
||||
function configUI_Load(ev) {
|
||||
this.$$("SaveBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, this.saveConfigDialog));
|
||||
this.$$("CancelBtn").addEventListener("click",
|
||||
B220Util.bindMethod(this, function(ev) {this.window.close()}));
|
||||
this.window.addEventListener("unload",
|
||||
B220Util.bindMethod(this, this.closeConfigUI), false);
|
||||
this.loadConfigDialog();
|
||||
}
|
||||
|
||||
this.doc = null;
|
||||
this.window = window.open("../webUI/B220SystemConfig.html", this.configStorageName,
|
||||
"location=no,scrollbars,resizable,width=640,height=800");
|
||||
this.window.moveTo(screen.availWidth-this.window.outerWidth-40,
|
||||
(screen.availHeight-this.window.outerHeight)/2);
|
||||
this.window.focus();
|
||||
this.alertWin = this.window;
|
||||
this.window.addEventListener("load",
|
||||
B220Util.bindMethod(this, configUI_Load), false);
|
||||
};
|
||||
171
webUI/B220Util.js
Normal file
@@ -0,0 +1,171 @@
|
||||
/***********************************************************************
|
||||
* retro-220/webUI B220Util.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2017, Paul Kimpel.
|
||||
* Licensed under the MIT License, see
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* Burroughs 220 Emulator common Javascript utilities module.
|
||||
************************************************************************
|
||||
* 2017-01-01 P.Kimpel
|
||||
* Original version, from retro-205 D205Util.js
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
/**************************************/
|
||||
function B220Util() {
|
||||
/* Constructor for the B220Util object */
|
||||
// Nothing to construct at present...
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateASCIIToAlgolRex = // For translation of 220-ASCII to Algol-ASCII glyphs
|
||||
/[^\r\n\xA0 $()*+,-./0-9=@A-Za-z]/g;
|
||||
B220Util.xlateASCIIToAlgolGlyph = {
|
||||
"#": "=",
|
||||
"%": "(",
|
||||
"&": "+",
|
||||
"<": ")",
|
||||
"\u00A4": ")"}; // the lozenge (¤)
|
||||
|
||||
B220Util.xlateAlgolToASCIIRex = // For translation of Algol-ASCII glyphs to 220-ASCII
|
||||
/[^\r\n\xA0 #$%&*,-./0-9<@A-Za-z\xA4]/g;
|
||||
B220Util.xlateAlgolToASCIIGlyph = {
|
||||
"=": "#",
|
||||
"(": "%",
|
||||
"+": "&",
|
||||
")": "\u00A4"}; // the lozenge (¤)
|
||||
|
||||
/**************************************/
|
||||
B220Util.$$ = function $$(e) {
|
||||
return document.getElementById(e);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.hasClass = function hasClass(e, name) {
|
||||
/* returns true if element "e" has class "name" in its class list */
|
||||
var classes = e.className;
|
||||
|
||||
if (!e) {
|
||||
return false;
|
||||
} else if (classes == name) {
|
||||
return true;
|
||||
} else {
|
||||
return (classes.search("\\b" + name + "\\b") >= 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.addClass = function addClass(e, name) {
|
||||
/* Adds a class "name" to the element "e"s class list */
|
||||
|
||||
if (!B220Util.hasClass(e, name)) {
|
||||
e.className += (" " + name);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.removeClass = function removeClass(e, name) {
|
||||
/* Removes the class "name" from the element "e"s class list */
|
||||
|
||||
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.bindMethod = function bindMethod(context, f) {
|
||||
/* Returns a new function that binds the function "f" to the object "context" */
|
||||
|
||||
return function bindMethodAnon() {return f.apply(context, arguments)};
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.deepCopy = function deepCopy(source, dest) {
|
||||
/* Performs a deep copy of the object "source" into the object "dest".
|
||||
If "dest" is null or undefined, simply returns a deep copy of "source".
|
||||
Note that this routine clones the primitive Javascript types, basic
|
||||
objects (hash tables), Arrays, Dates, RegExps, and Functions. Other
|
||||
types may be supported by extending the switch statement. Also note
|
||||
this is a static function.
|
||||
Adapted (with thanks) from the "extend" routine by poster Kamarey on 2011-03-26 at
|
||||
http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object
|
||||
*/
|
||||
var constr;
|
||||
var copy;
|
||||
var name;
|
||||
|
||||
if (source === null) {
|
||||
return source;
|
||||
} else if (!(source instanceof Object)) {
|
||||
return source;
|
||||
} else {
|
||||
constr = source.constructor;
|
||||
if (constr !== Object && constr !== Array) {
|
||||
return source;
|
||||
} else {
|
||||
switch (constr) {
|
||||
case String:
|
||||
case Number:
|
||||
case Boolean:
|
||||
case Date:
|
||||
case Function:
|
||||
case RegExp:
|
||||
copy = new constr(source);
|
||||
break;
|
||||
default:
|
||||
copy = dest || new constr();
|
||||
break;
|
||||
}
|
||||
|
||||
for (name in source) {
|
||||
copy[name] = deepCopy(source[name], null);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateToAlgolChar = function xlateToAlgolChar(c) {
|
||||
/* Translates one BIC-as-ASCII Algol glyph character to Unicode */
|
||||
|
||||
return B220Util.xlateASCIIToAlgolGlyph[c] || "?";
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateASCIIToAlgol = function xlateASCIIToAlgol(text) {
|
||||
/* Translates the BIC-as-ASCII characters in "text" to equivalent Unicode glyphs */
|
||||
|
||||
return text.replace(B220Util.xlateASCIIToAlgolRex, B220Util.xlateToAlgolChar);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateToASCIIChar = function xlateToASCIIChar(c) {
|
||||
/* Translates one Unicode Algol glyph to its BIC-as-ASCII equivalent */
|
||||
|
||||
return B220Util.xlateAlgolToASCIIGlyph[c] || "?";
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateAlgolToASCII = function xlateAlgolToASCII(text) {
|
||||
/* Translates the Unicode characters in "text" equivalent BIC-as-ASCII glyphs */
|
||||
|
||||
return text.replace(B220Util.xlateAlgolToASCIIRex, B220Util.xlateToASCIIChar);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
B220Util.xlateDOMTreeText = function xlateDOMTreeText(n, xlate) {
|
||||
/* If Node "n" is a text node, translates its value using the "xlate"
|
||||
function. For all other Node types, translates all subordinate text nodes */
|
||||
var kid;
|
||||
|
||||
if (n.nodeType == Node.TEXT_NODE) {
|
||||
n.nodeValue = xlate(n.nodeValue);
|
||||
} else {
|
||||
kid = n.firstChild;
|
||||
while (kid) {
|
||||
xlateDOMTreeText(kid, xlate);
|
||||
kid = kid.nextSibling;
|
||||
}
|
||||
}
|
||||
};
|
||||
BIN
webUI/resources/B220-Logo - White.jpg
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
webUI/resources/B220-Logo.jpg
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
webUI/resources/B220-Site.jpg
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
webUI/resources/Burroughs-Logo - White.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
webUI/resources/Burroughs-Logo-Neg.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
webUI/resources/Burroughs-Logo.jpg
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
webUI/resources/Burroughs-Meatball.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
webUI/resources/DataFileTapeHead.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
webUI/resources/MagTapeReel.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
webUI/resources/ToggleDown.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
webUI/resources/ToggleMid.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
webUI/resources/ToggleUp.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
webUI/resources/retro-Logo.png
Normal file
|
After Width: | Height: | Size: 410 B |