/*********************************************************************** * 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, memorySize: 5000, // 11-digit words ControlConsole: { PCS1SW: 0, // Program Control Switches 1-0 PCS2SW: 0, PCS3SW: 0, PCS4SW: 0, PCS5SW: 0, PCW6SW: 0, PCS7SW: 0, PCS8SW: 0, PCS9SW: 0, PCS0SW: 0, SONSW: 0, // S-register on SUNITSSW: 0, // S-register units STOCSW: 0, // S-to-C stop STOPSW: 0}, // S-to-P stop ConsoleOutput: { units: [ {type: "TTYA", zeroSuppress: 0, mapMemory: 0, unitMask: 0x001, remote: 1, format: 0, columns: 72, tabs: "9,17,25,33,41,49,57,65,73,81"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"} ]}, Cardatron: { hasCardatron: true, units: [ null, // unit[0] not used {type: "CR1", formatSelect: 0, formatCol: 1}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "NONE"}, {type: "LP2", algolGlyphs: true, greenBar: true, 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(); }; /**************************************/ 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 0) { names = name.split("."); top = names.length-1; for (x=0; x 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 max) { alert(caption + " must be in the range (" + min + ", " + max + ")"); n = Number.NaN; } return n; } // System Properties e = this.$$("SystemMemorySize"); x = parseInt(e.options[e.selectedIndex], 10); cd.memorySize = (isNaN(x) ? 5000 : x); // Console Output units for (x=0; x<=10; ++x) { unit = cd.ConsoleOutput.units[x]; prefix = "ConsoleOut" + x; e = this.$$(prefix + "Type"); unit.type = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value); mask = 0x001; unit.unitMask = 0; if (this.$$(prefix + "_SPO").checked) { unit.unitMask |= mask; } for (y=1; y<=10; ++y) { mask <<= 1; if (this.$$(prefix + "_" + y).checked) { unit.unitMask |= mask; } } // for y e = this.$$(prefix + "Format"); unit.format = (e.selectedIndex < 0 ? "NONE" : e.options[e.selectedIndex].value); unit.columns = (unit.columns ? unit.columns : 72); unit.tabs = (unit.tabs ? unit.tabs : "1,9,17,25,33,41,49,57,65,73"); } // for x // 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 = "220 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.$$("DefaultsBtn").addEventListener("click", B220Util.bindMethod(this, function(ev) { this.createConfigData(); this.loadConfigDialog(); })); 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=800,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); };