1
0
mirror of https://github.com/pkimpel/retro-220.git synced 2026-04-03 04:19:06 +00:00

Commit preliminary 0.00a emulator files for Processor and Control Console cloned from retro-205.

This commit is contained in:
Paul Kimpel
2016-12-29 10:27:45 -08:00
parent db25dabd6f
commit e830d6f124
29 changed files with 7697 additions and 5 deletions

3422
emulator/B220Processor.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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 &amp; Getting Started</a>
<!--
<li><a href="./webSite/HelpMenu.html">Help &amp; Getting Started</a>
<br>A menu of information resources to assist you in setting up and operating the emulator.
-->
@@ -66,10 +66,10 @@
<p>&nbsp;
<div id=footerDiv>
Copyright (c) 2016, Paul Kimpel &bull; Licensed under the <a href="LICENSE.txt">MIT License</a>
Copyright (c) 2017, Paul Kimpel &bull; 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
View 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
View 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 &amp; 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>
&nbsp;&nbsp;&nbsp;
<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
View 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
View 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}

View 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}

View 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>&nbsp;</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>&nbsp;</div>
<div id=PowerOnCaption class=caption>ON</div>
-->
<div id=PowerOffBtn class=redButton3>&nbsp;</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>&nbsp;</div>
<div id=ResetOverflowCaption class=caption>RESET</div>
<div id=SectorLampCaption class=caption>SECTOR</div>
<div id=ResetSectorBtn class=blackButton1>&nbsp;</div>
<div id=ResetSectorCaption class=caption>RESET</div>
<div id=ControlLampCaption class=caption>CONTROL</div>
<div id=ResetControlBtn class=blackButton1>&nbsp;</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>&nbsp;</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>&nbsp;</div>
<div id=FetchBtn class=blackButton1>&nbsp;</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>&nbsp;</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>
&nbsp;&nbsp;
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
View 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();
};

View 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
View 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
View 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
View 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
View 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 &amp; 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>
&nbsp;
<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>
&nbsp;
<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>
&nbsp;
<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>
&nbsp;
<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>
&nbsp;
<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>
&nbsp;
<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>
&nbsp;
</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
View 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
View 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;
}
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B