Disk in current drive can now be saved as an IMG file, and groundwork has been laid for saving an entire machine
This commit is contained in:
parent
092f07fa9b
commit
9c2ec7a20b
17 changed files with 1684 additions and 1549 deletions
|
|
@ -215,7 +215,7 @@ Component.subclass = function(subclass, superclass, methods, statics)
|
|||
* This enables any component to locate another component by ID (see Component.getComponentByID())
|
||||
* or by type (see Component.getComponentByType()).
|
||||
*/
|
||||
Component.all = [];
|
||||
Component.components = [];
|
||||
|
||||
/**
|
||||
* Component.add(component)
|
||||
|
|
@ -225,11 +225,57 @@ Component.all = [];
|
|||
Component.add = function(component)
|
||||
{
|
||||
/*
|
||||
* This just generates a lot of useless noise, handy in the early days, not so much these days...
|
||||
* This just generates a lot of useless noise, handy in the early days, not so much these days....
|
||||
*
|
||||
* if (DEBUG) Component.log("Component.add(" + component.type + "," + component.id + ")");
|
||||
*/
|
||||
Component.all[Component.all.length] = component;
|
||||
Component.components.push(component);
|
||||
};
|
||||
|
||||
/*
|
||||
* Every machine on the page are now recorded as well, by their machine ID. We then record the various resources
|
||||
* used by that machine.
|
||||
*/
|
||||
Component.machines = {};
|
||||
|
||||
/**
|
||||
* Component.addMachine(idMachine)
|
||||
*
|
||||
* @param {string} idMachine
|
||||
*/
|
||||
Component.addMachine = function(idMachine)
|
||||
{
|
||||
Component.machines[idMachine] = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Component.addMachineResource(idMachine, sName, data)
|
||||
*
|
||||
* @param {string} idMachine
|
||||
* @param {string} sName (name of the resource)
|
||||
* @param {*} data
|
||||
*/
|
||||
Component.addMachineResource = function(idMachine, sName, data)
|
||||
{
|
||||
Component.assert(Component.machines[idMachine]);
|
||||
if (Component.machines[idMachine]) {
|
||||
if (!Component.machines[idMachine][sName]) {
|
||||
Component.machines[idMachine][sName] = [];
|
||||
}
|
||||
Component.machines[idMachine][sName].push(data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Component.getMachineResources(idMachine, sName)
|
||||
*
|
||||
* @param {string} idMachine
|
||||
* @param {string} sName (name of the resource)
|
||||
* @return {Array|undefined}
|
||||
*/
|
||||
Component.getMachineResources = function(idMachine, sName)
|
||||
{
|
||||
return Component.machines[idMachine] && Component.machines[idMachine][sName];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -343,8 +389,8 @@ Component.error = function(s)
|
|||
/**
|
||||
* Component.getComponents(idRelated)
|
||||
*
|
||||
* We could store components as properties of an 'all' object, using the component's ID,
|
||||
* and change this linear lookup into a property lookup, but some components may have no ID.
|
||||
* We could store components as properties, using the component's ID, and change
|
||||
* this linear lookup into a property lookup, but some components may have no ID.
|
||||
*
|
||||
* @param {string} [idRelated] of related component
|
||||
* @return {Array} of components
|
||||
|
|
@ -366,8 +412,8 @@ Component.getComponents = function(idRelated)
|
|||
else
|
||||
idRelated = "";
|
||||
}
|
||||
for (i = 0; i < Component.all.length; i++) {
|
||||
var component = Component.all[i];
|
||||
for (i = 0; i < Component.components.length; i++) {
|
||||
var component = Component.components[i];
|
||||
if (!idRelated || !component.id.indexOf(idRelated)) {
|
||||
aComponents.push(component);
|
||||
}
|
||||
|
|
@ -378,8 +424,8 @@ Component.getComponents = function(idRelated)
|
|||
/**
|
||||
* Component.getComponentByID(id, idRelated)
|
||||
*
|
||||
* We could store components as properties of an 'all' object, using the component's ID,
|
||||
* and change this linear lookup into a property lookup, but some components may have no ID.
|
||||
* We could store components as properties, using the component's ID, and change
|
||||
* this linear lookup into a property lookup, but some components may have no ID.
|
||||
*
|
||||
* @param {string} id of the desired component
|
||||
* @param {string} [idRelated] of related component
|
||||
|
|
@ -397,9 +443,9 @@ Component.getComponentByID = function(id, idRelated)
|
|||
if (idRelated && (i = idRelated.indexOf('.')) > 0) {
|
||||
id = idRelated.substr(0, i + 1) + id;
|
||||
}
|
||||
for (i = 0; i < Component.all.length; i++) {
|
||||
if (Component.all[i].id === id) {
|
||||
return Component.all[i];
|
||||
for (i = 0; i < Component.components.length; i++) {
|
||||
if (Component.components[i].id === id) {
|
||||
return Component.components[i];
|
||||
}
|
||||
}
|
||||
Component.log("Component ID '" + id + "' not found", "warning");
|
||||
|
|
@ -431,13 +477,13 @@ Component.getComponentByType = function(sType, idRelated, componentPrev)
|
|||
idRelated = "";
|
||||
}
|
||||
}
|
||||
for (i = 0; i < Component.all.length; i++) {
|
||||
for (i = 0; i < Component.components.length; i++) {
|
||||
if (componentPrev) {
|
||||
if (componentPrev == Component.all[i]) componentPrev = null;
|
||||
if (componentPrev == Component.components[i]) componentPrev = null;
|
||||
continue;
|
||||
}
|
||||
if (sType == Component.all[i].type && (!idRelated || !Component.all[i].id.indexOf(idRelated))) {
|
||||
return Component.all[i];
|
||||
if (sType == Component.components[i].type && (!idRelated || !Component.components[i].id.indexOf(idRelated))) {
|
||||
return Component.components[i];
|
||||
}
|
||||
}
|
||||
Component.log("Component type '" + sType + "' not found", "warning");
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
/* global document: true, window: true, XSLTProcessor: false, APPNAME: false, APPVERSION: false, DEBUG: true */
|
||||
|
||||
if (NODE) {
|
||||
var Component;
|
||||
var Component = require("./component");
|
||||
var str = require("./strlib");
|
||||
var web = require("./weblib");
|
||||
}
|
||||
|
|
@ -52,8 +52,8 @@ if (NODE) {
|
|||
* notification events at the start of the embedding process (web.enablePageEvents(false)) and
|
||||
* re-enable them at the end (web.enablePageEvents(true)).
|
||||
*/
|
||||
var cMachines = 0;
|
||||
var fAsync = true;
|
||||
var cAsyncMachines = 0;
|
||||
|
||||
/**
|
||||
* loadXML(sFile, idMachine, sParms, fResolve, display, done)
|
||||
|
|
@ -305,27 +305,28 @@ function resolveXML(sXML, display, done)
|
|||
}
|
||||
|
||||
/**
|
||||
* embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
||||
* embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms)
|
||||
*
|
||||
* This allows to you embed a machine on a web page, by transforming the machine XML into HTML.
|
||||
*
|
||||
* @param {string} sName is the app name (eg, "PCjs")
|
||||
* @param {string} sVersion is the app version (eg, "1.15.7")
|
||||
* @param {string} idElement
|
||||
* @param {string} idMachine
|
||||
* @param {string} sXMLFile
|
||||
* @param {string} sXSLFile
|
||||
* @param {string} [sParms]
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
||||
function embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms)
|
||||
{
|
||||
var eMachine, eWarning, fSuccess = true;
|
||||
|
||||
cMachines++;
|
||||
cAsyncMachines++;
|
||||
Component.addMachine(idMachine);
|
||||
|
||||
var doneMachine = function() {
|
||||
Component.assert(cMachines > 0);
|
||||
if (!--cMachines) {
|
||||
Component.assert(cAsyncMachines > 0);
|
||||
if (!--cAsyncMachines) {
|
||||
if (fAsync) web.enablePageEvents(true);
|
||||
}
|
||||
};
|
||||
|
|
@ -358,7 +359,7 @@ function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
|||
};
|
||||
|
||||
try {
|
||||
eMachine = document.getElementById(idElement);
|
||||
eMachine = document.getElementById(idMachine);
|
||||
if (eMachine) {
|
||||
var sAppClass = sName.toLowerCase(); // eg, "pcjs" or "c1pjs"
|
||||
if (!sXSLFile) {
|
||||
|
|
@ -380,6 +381,7 @@ function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
|||
displayError(sXML);
|
||||
return;
|
||||
}
|
||||
Component.addMachineResource(idMachine, 'xml', sXML);
|
||||
/*
|
||||
* Non-COMPILED kludge to extract the version number from the stylesheet path in the machine XML file;
|
||||
* we don't need this code in COMPILED (non-DEBUG) releases, because APPVERSION is hard-coded into them.
|
||||
|
|
@ -393,82 +395,75 @@ function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
|||
displayError(sXSL);
|
||||
return;
|
||||
}
|
||||
if (xsl) {
|
||||
/*
|
||||
* The <machine> template in components.xsl now generates a "machine div" that makes
|
||||
* the div we required the caller of embedMachine() to provide redundant, so instead
|
||||
* of appending this fragment to the caller's node, we REPLACE the caller's node.
|
||||
* This works only because because we ALSO inject the caller's "machine div" ID into
|
||||
* the fragment's ID during parseXML().
|
||||
*
|
||||
* eMachine.innerHTML = sFragment;
|
||||
*
|
||||
* Also, if the transform function fails, make sure you're using the appropriate
|
||||
* "components.xsl" and not a "machine.xsl", because the latter will not produce valid
|
||||
* embeddable HTML (and is the most common cause of failure at this final stage).
|
||||
*/
|
||||
displayMessage("Processing " + sXMLFile + "...");
|
||||
/*
|
||||
* Beginning with Microsoft Edge and the corresponding release of Windows 10, all the
|
||||
* 'ActiveXObject' crud has gone away; but of course, this code must remain in place if
|
||||
* we want to continue supporting older Internet Explorer browsers (ie, back to IE9).
|
||||
*/
|
||||
if (window.ActiveXObject || 'ActiveXObject' in window) { // second test is required for IE11 on Windows 8.1
|
||||
var sFragment = xml['transformNode'](xsl);
|
||||
if (sFragment) {
|
||||
eMachine.outerHTML = sFragment;
|
||||
Component.addMachineResource(idMachine, 'xsl', sXSL);
|
||||
/*
|
||||
* The <machine> template in components.xsl now generates a "machine div" that makes
|
||||
* the div we required the caller of embedMachine() to provide redundant, so instead
|
||||
* of appending this fragment to the caller's node, we REPLACE the caller's node.
|
||||
* This works only because because we ALSO inject the caller's "machine div" ID into
|
||||
* the fragment's ID during parseXML().
|
||||
*
|
||||
* eMachine.innerHTML = sFragment;
|
||||
*
|
||||
* Also, if the transform function fails, make sure you're using the appropriate
|
||||
* "components.xsl" and not a "machine.xsl", because the latter will not produce valid
|
||||
* embeddable HTML (and is the most common cause of failure at this final stage).
|
||||
*/
|
||||
displayMessage("Processing " + sXMLFile + "...");
|
||||
/*
|
||||
* Beginning with Microsoft Edge and the corresponding release of Windows 10, all the
|
||||
* 'ActiveXObject' crud has gone away; but of course, this code must remain in place if
|
||||
* we want to continue supporting older Internet Explorer browsers (ie, back to IE9).
|
||||
*/
|
||||
if (window.ActiveXObject || 'ActiveXObject' in window) { // second test is required for IE11 on Windows 8.1
|
||||
var sFragment = xml['transformNode'](xsl);
|
||||
if (sFragment) {
|
||||
eMachine.outerHTML = sFragment;
|
||||
doneMachine();
|
||||
} else {
|
||||
displayError("transformNodeToObject failed");
|
||||
}
|
||||
}
|
||||
else if (document.implementation && document.implementation.createDocument) {
|
||||
var xsltProcessor = new XSLTProcessor();
|
||||
xsltProcessor['importStylesheet'](xsl);
|
||||
var eFragment = xsltProcessor['transformToFragment'](xml, document);
|
||||
if (eFragment) {
|
||||
/*
|
||||
* This fails in Microsoft Edge...
|
||||
*
|
||||
var machine = eFragment.getElementById(idMachine);
|
||||
if (!machine) {
|
||||
displayError("machine generation failed: " + idMachine);
|
||||
} else
|
||||
*/
|
||||
if (eMachine.parentNode) {
|
||||
eMachine.parentNode.replaceChild(eFragment, eMachine);
|
||||
doneMachine();
|
||||
} else {
|
||||
displayError("transformNodeToObject failed");
|
||||
}
|
||||
}
|
||||
else if (document.implementation && document.implementation.createDocument) {
|
||||
var xsltProcessor = new XSLTProcessor();
|
||||
xsltProcessor['importStylesheet'](xsl);
|
||||
var eFragment = xsltProcessor['transformToFragment'](xml, document);
|
||||
if (eFragment) {
|
||||
/*
|
||||
* This fails in Microsoft Edge...
|
||||
*
|
||||
var machine = eFragment.getElementById(idElement);
|
||||
if (!machine) {
|
||||
displayError("machine generation failed: " + idElement);
|
||||
} else
|
||||
*/
|
||||
if (eMachine.parentNode) {
|
||||
eMachine.parentNode.replaceChild(eFragment, eMachine);
|
||||
doneMachine();
|
||||
} else {
|
||||
displayError("invalid machine element: " + idElement);
|
||||
}
|
||||
} else {
|
||||
displayError("transformToFragment failed");
|
||||
displayError("invalid machine element: " + idMachine);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Perhaps I should have performed this test at the outset; on the other hand, I'm
|
||||
* not aware of any browsers don't support one or both of the above XSLT transformation
|
||||
* methods, so treat this as a bug.
|
||||
*/
|
||||
displayError("unable to transform XML: unsupported browser");
|
||||
displayError("transformToFragment failed");
|
||||
}
|
||||
} else {
|
||||
displayError("failed to load XSL file: " + sXSLFile);
|
||||
/*
|
||||
* Perhaps I should have performed this test at the outset; on the other hand, I'm
|
||||
* not aware of any browsers don't support one or both of the above XSLT transformation
|
||||
* methods, so treat this as a bug.
|
||||
*/
|
||||
displayError("unable to transform XML: unsupported browser");
|
||||
}
|
||||
};
|
||||
if (xml) {
|
||||
loadXML(sXSLFile, null, null, false, displayMessage, transformXML);
|
||||
} else {
|
||||
displayError("failed to load XML file: " + sXMLFile);
|
||||
}
|
||||
loadXML(sXSLFile, null, null, false, displayMessage, transformXML);
|
||||
};
|
||||
if (sXMLFile.charAt(0) != '<') {
|
||||
loadXML(sXMLFile, idElement, sParms, true, displayMessage, loadXSL);
|
||||
loadXML(sXMLFile, idMachine, sParms, true, displayMessage, loadXSL);
|
||||
} else {
|
||||
parseXML(sXMLFile, null, idElement, sParms, false, displayMessage, loadXSL);
|
||||
parseXML(sXMLFile, null, idMachine, sParms, false, displayMessage, loadXSL);
|
||||
}
|
||||
} else {
|
||||
displayError("missing machine element: " + idElement);
|
||||
displayError("missing machine element: " + idMachine);
|
||||
}
|
||||
} catch(e) {
|
||||
displayError(e.message);
|
||||
|
|
@ -477,32 +472,54 @@ function embedMachine(sName, sVersion, idElement, sXMLFile, sXSLFile, sParms)
|
|||
}
|
||||
|
||||
/**
|
||||
* embedC1P(idElement, sXMLFile, sXSLFile)
|
||||
* embedC1P(idMachine, sXMLFile, sXSLFile)
|
||||
*
|
||||
* @param {string} idElement
|
||||
* @param {string} idMachine
|
||||
* @param {string} sXMLFile
|
||||
* @param {string} sXSLFile
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
function embedC1P(idElement, sXMLFile, sXSLFile)
|
||||
function embedC1P(idMachine, sXMLFile, sXSLFile)
|
||||
{
|
||||
if (fAsync) web.enablePageEvents(false);
|
||||
return embedMachine("C1Pjs", APPVERSION, idElement, sXMLFile, sXSLFile);
|
||||
return embedMachine("C1Pjs", APPVERSION, idMachine, sXMLFile, sXSLFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* embedPC(idElement, sXMLFile, sXSLFile, sParms)
|
||||
* embedPC(idMachine, sXMLFile, sXSLFile, sParms)
|
||||
*
|
||||
* @param {string} idElement
|
||||
* @param {string} idMachine
|
||||
* @param {string} sXMLFile
|
||||
* @param {string} sXSLFile
|
||||
* @param {string} [sParms]
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
function embedPC(idElement, sXMLFile, sXSLFile, sParms)
|
||||
function embedPC(idMachine, sXMLFile, sXSLFile, sParms)
|
||||
{
|
||||
if (fAsync) web.enablePageEvents(false);
|
||||
return embedMachine("PCjs", APPVERSION, idElement, sXMLFile, sXSLFile, sParms);
|
||||
return embedMachine("PCjs", APPVERSION, idMachine, sXMLFile, sXSLFile, sParms);
|
||||
}
|
||||
|
||||
/**
|
||||
* savePC(idMachine)
|
||||
*
|
||||
* @param {string} idMachine
|
||||
* @return {boolean} true if successful, false if error
|
||||
*/
|
||||
function savePC(idMachine)
|
||||
{
|
||||
var cmp = Component.getComponentByType("Computer", idMachine);
|
||||
var dbg = Component.getComponentByType("Debugger", idMachine);
|
||||
if (cmp) {
|
||||
var sPCJSFile = "/versions/pcjs/" + XMLVERSION + "/pc" + (dbg? "-dbg" : "") + ".js";
|
||||
var sPCJSCode = web.loadResource(sPCJSFile);
|
||||
/*
|
||||
* Next, we need to enumerate the FDC drives and "dump" the disks in them....
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
web.alertUser("Unable to identify machine '" + idMachine + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -511,6 +528,7 @@ function embedPC(idElement, sXMLFile, sXSLFile, sParms)
|
|||
*/
|
||||
if (APPNAME == "PCjs") {
|
||||
window['embedPC'] = embedPC;
|
||||
window['savePC'] = savePC;
|
||||
}
|
||||
|
||||
if (APPNAME == "C1Pjs") {
|
||||
|
|
|
|||
Loading…
Reference in a new issue