From 79fb14fdbfeb8db27399f98a1324a1cc3ad4538a Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Wed, 20 Apr 2016 12:09:59 -0700 Subject: [PATCH] Support for machines other than PCjs and C1Pjs --- Gruntfile.js | 8 +-- modules/htmlout/lib/htmlout.js | 16 ++--- modules/markout/lib/markout.js | 8 ++- modules/pc8080/lib/video.js | 10 ++-- modules/pcjs/lib/video.js | 10 ++-- modules/shared/lib/embed.js | 78 +++++++++++++++++-------- modules/shared/templates/components.xsl | 47 ++++++++------- 7 files changed, 109 insertions(+), 68 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 180fc0862..ad217bc1b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -321,7 +321,7 @@ module.exports = function(grunt) { }, // src: pkg.pcJSFiles, src: tmpPCjs, - dest: "./versions/" + pkg.name + "/" + pkg.version + "/pc.js" + dest: "./versions/pcjs/" + pkg.version + "/pc.js" }, "pc-dbg.js": { /* @@ -336,7 +336,7 @@ module.exports = function(grunt) { }, // src: pkg.pcJSFiles, src: tmpPCjs, - dest: "./versions/" + pkg.name + "/" + pkg.version + "/pc-dbg.js" + dest: "./versions/pcjs/" + pkg.version + "/pc-dbg.js" }, "pc8080.js": { TEMPcompilerOpts: { @@ -348,7 +348,7 @@ module.exports = function(grunt) { }, // src: pkg.pc8080Files, src: tmpPC8080, - dest: "./versions/" + pkg.name + "/" + pkg.version + "/pc8080.js" + dest: "./versions/pc8080/" + pkg.version + "/pc8080.js" }, "pc8080-dbg.js": { /* @@ -363,7 +363,7 @@ module.exports = function(grunt) { }, // src: pkg.pc8080Files, src: tmpPC8080, - dest: "./versions/" + pkg.name + "/" + pkg.version + "/pc8080-dbg.js" + dest: "./versions/pc8080/" + pkg.version + "/pc8080-dbg.js" } }, copy: { diff --git a/modules/htmlout/lib/htmlout.js b/modules/htmlout/lib/htmlout.js index 9981f0efa..3283afd46 100644 --- a/modules/htmlout/lib/htmlout.js +++ b/modules/htmlout/lib/htmlout.js @@ -164,8 +164,9 @@ var sManifestXMLFile = "manifest.xml"; * the closing tag, and JS files are added just before the closing tag. */ var aMachineFiles = { - 'c1p': pkg.c1pCSSFiles.concat(pkg.c1pJSFiles), - 'pc': pkg.pcCSSFiles.concat(pkg.pcJSFiles) + 'c1p': pkg.c1pCSSFiles.concat(pkg.c1pJSFiles), + 'pc': pkg.pcCSSFiles.concat(pkg.pcJSFiles), + 'pc8080': pkg.pcCSSFiles.concat(pkg.pc8080Files) }; var aMachineFileTypes = { 'head': [".css"], // put BOTH ".css" and ".js" here if convertMDMachineLinks() embeds its own scripts @@ -1427,10 +1428,11 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS * or "development" stylesheets in ("/modules/pcjs/templates"|"/modules/c1pjs/templates"). * * The common denominator in both sets is either "/pc" or "/c1p", which in turn indicates the class of machine - * (ie, "PC" or "C1P"). + * (ie, "PCjs" or "C1Pjs"). */ - var sMachineClass = (sStyleSheet.indexOf("/pc") >= 0? "PC" : (sStyleSheet.indexOf("/c1p") >= 0? "C1P" : null)); - if (sMachineClass) { + aMatch = sStyleSheet.match(/\/(pc|c1p)([^/]*)/); + if (aMatch) { + var sMachineClass = aMatch[1].toUpperCase() + aMatch[2]; /* * Since the MarkOut module already contains the ability to embed a machine definition with * one simple line of Markdown-like magic, we'll create such a line and let MarkOut do the rest. @@ -1445,7 +1447,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS * options is a comma-delimited series of, well, options; the only option we currently output is "debugger" * if a element is present in the machine XML. */ - var sMachineID = "machine" + sMachineClass; // fallback to either "machinePC" or "machineC1P" if no ID found + var sMachineID = "machine" + sMachineClass; // fallback to either "machinePCjs" or "machineC1Pjs" if no ID found aMatch = sXML.match(/]*>/); if (aMatch) sMachineID = aMatch[2]; @@ -1455,7 +1457,7 @@ HTMLOut.prototype.getMachineXML = function(sToken, sIndent, aParms, sXMLFile, sS * embedding inside an existing HTML document, so any "machine.xsl" stylesheet must be remapped * to a corresponding "components.xsl" stylesheet (which is what the next line does). */ - var sMachineDef = sMachineClass + "js:" + sMachineID + ":" + sStyleSheet.replace("machine.xsl", "components.xsl"); + var sMachineDef = sMachineClass + ":" + sMachineID + ":" + sStyleSheet.replace("machine.xsl", "components.xsl"); sMachineDef += (sXML.indexOf(" 0? ":*:debugger" : ":*:none"); sMachineDef += (sStateFile? ":" + sStateFile : ""); diff --git a/modules/markout/lib/markout.js b/modules/markout/lib/markout.js index 3b30bc680..a56e718d9 100644 --- a/modules/markout/lib/markout.js +++ b/modules/markout/lib/markout.js @@ -1169,7 +1169,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) * Start looking for Markdown-style machine links now... */ var cMatches = 0; - var reMachines = /\[(.*?)]\((.*?)\s*"(PC|C1P)js([:!|])(.*?)"\)/gi; + var reMachines = /\[(.*?)]\((.*?)\s*"(PC|C1P)([a-z0-9-]*)([:!|])(.*?)"\)/gi; while ((aMatch = reMachines.exec(sBlock))) { @@ -1177,10 +1177,12 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock) if (sMachineXMLFile.slice(-1) == "/") sMachineXMLFile += "machine.xml"; sMachine = aMatch[3].toUpperCase(); + if (aMatch[4] != "js") sMachine += aMatch[4]; var sMachineFunc = "embed" + sMachine; var sMachineClass = sMachine.toLowerCase(); - var aMachineParms = aMatch[5].split(aMatch[4]); - var sMachineMessage = "Waiting for " + sMachine + "js to load"; + var aMachineParms = aMatch[6].split(aMatch[5]); + if (aMatch[4] == "js") sMachine += aMatch[4]; + var sMachineMessage = "Waiting for " + sMachine + " to load"; sMachineID = aMachineParms[0]; sMachineXSLFile = aMachineParms[1] || ""; diff --git a/modules/pc8080/lib/video.js b/modules/pc8080/lib/video.js index 458d563d9..da05a0e7e 100644 --- a/modules/pc8080/lib/video.js +++ b/modules/pc8080/lib/video.js @@ -121,12 +121,12 @@ Video.init = function() eVideo.onresize(); } /* - * The following is a related hack that allows the user to force the machine to use a particular aspect - * ratio if an 'aspect' URL parameter is set. Initially, it's just for testing purposes until we figure - * out a better UI. And note that we use our web.onPageEvent() helper function to make sure we don't - * trample any other 'onresize' handler(s) attached to the window object. + * The following is a related hack that allows the user to force the screen to use a particular aspect + * ratio if an 'aspect' attribute or URL parameter is set. Initially, it's just for testing purposes + * until we figure out a better UI. And note that we use our web.onPageEvent() helper function to make + * sure we don't trample any other 'onresize' handler(s) attached to the window object. */ - var aspect = +Component.parmsURL['aspect']; + var aspect = +(parmsVideo['aspect'] || Component.parmsURL['aspect']); /* * No 'aspect' parameter yields NaN, which is falsey, and anything else must satisfy my arbitrary * constraints of 0.3 <= aspect <= 3.33, to prevent any useless (or worse, browser-blowing) results. diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 0f6fb0e98..f5fa8ae96 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -7275,12 +7275,12 @@ Video.init = function() eVideo.onresize(); } /* - * The following is a related hack that allows the user to force the machine to use a particular aspect - * ratio if an 'aspect' URL parameter is set. Initially, it's just for testing purposes until we figure - * out a better UI. And note that we use our web.onPageEvent() helper function to make sure we don't - * trample any other 'onresize' handler(s) attached to the window object. + * The following is a related hack that allows the user to force the screen to use a particular aspect + * ratio if an 'aspect' attribute or URL parameter is set. Initially, it's just for testing purposes + * until we figure out a better UI. And note that we use our web.onPageEvent() helper function to make + * sure we don't trample any other 'onresize' handler(s) attached to the window object. */ - var aspect = +Component.parmsURL['aspect']; + var aspect = +(parmsVideo['aspect'] || Component.parmsURL['aspect']); /* * No 'aspect' parameter yields NaN, which is falsey, and anything else must satisfy my arbitrary * constraints of 0.3 <= aspect <= 3.33, to prevent any useless (or worse, browser-blowing) results. diff --git a/modules/shared/lib/embed.js b/modules/shared/lib/embed.js index 3c7c16bcf..7107a86be 100644 --- a/modules/shared/lib/embed.js +++ b/modules/shared/lib/embed.js @@ -56,7 +56,7 @@ var fAsync = true; var cAsyncMachines = 0; /** - * loadXML(sFile, idMachine, sParms, fResolve, display, done) + * loadXML(sFile, idMachine, sAppClass, sParms, fResolve, display, done) * * This is the preferred way to load all XML and XSL files. It uses getResource() * to load them as strings, which parseXML() can massage before parsing/transforming them. @@ -81,12 +81,13 @@ var cAsyncMachines = 0; * * @param {string} sXMLFile * @param {string|null|undefined} idMachine + * @param {string|null|undefined} sAppClass * @param {string|null|undefined} sParms * @param {boolean} fResolve is true to resolve any "ref" attributes * @param {function(string)} display * @param {function(string,Object)} done (string contains the unparsed XML string data, and Object contains a parsed XML object) */ -function loadXML(sXMLFile, idMachine, sParms, fResolve, display, done) +function loadXML(sXMLFile, idMachine, sAppClass, sParms, fResolve, display, done) { var doneLoadXML = function(sURLName, sXML, nErrorCode) { if (nErrorCode) { @@ -94,14 +95,14 @@ function loadXML(sXMLFile, idMachine, sParms, fResolve, display, done) done(sXML, null); return; } - parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done); + parseXML(sXML, sXMLFile, idMachine, sAppClass, sParms, fResolve, display, done); }; display("Loading " + sXMLFile + "..."); web.getResource(sXMLFile, null, fAsync, doneLoadXML); } /** - * parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done) + * parseXML(sXML, sXMLFile, idMachine, sAppClass, sParms, fResolve, display, done) * * Generates an XML document from an XML string. This function also provides a work-around for XSLT's * lack of support for the document() function (at least on some browsers), by replacing every reference @@ -110,12 +111,13 @@ function loadXML(sXMLFile, idMachine, sParms, fResolve, display, done) * @param {string} sXML * @param {string|null} sXMLFile * @param {string|null|undefined} idMachine + * @param {string|null|undefined} sAppClass * @param {string|null|undefined} sParms * @param {boolean} fResolve is true to resolve any "ref" attributes; default is false * @param {function(string)} display * @param {function(string,Object)} done (string contains the unparsed XML string data, and Object contains a parsed XML object) */ -function parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done) +function parseXML(sXML, sXMLFile, idMachine, sAppClass, sParms, fResolve, display, done) { var buildXML = function(sXML, sError) { if (sError) { @@ -159,13 +161,23 @@ function parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done) if (typeof resources == 'object') sURL = null; // turn off URL inclusion if we have embedded resources sXML = sXML.replace(/(]*\sid=)(['"]).*?\2/, "$1$2" + idMachine + "$2" + (sParms? " parms='" + sParms + "'" : "") + (sURL? ' url="' + sURL + '"' : '')); } - /* - * Non-COMPILED kludge to replace the version number template in the XSL file (which we assume we're reading, - * since fResolve is false) with whatever XMLVERSION we extracted from the XML file (see corresponding kludge below). - */ - if (!COMPILED && !fResolve && XMLVERSION) { - sXML = sXML.replace(/1.x.x<\/xsl:variable>/, '' + XMLVERSION + ''); + + if (!fResolve) { + /* + * I'm trying to switch to a shared components.xsl (at least for all PC-class machines), + * but in the interim, that means hacking the XSL file on the fly to reflect the chosen class. + */ + sXML = sXML.replace(/().*?(<\/xsl:variable>)/, "$1" + sAppClass + "$2"); + + /* + * Non-COMPILED kludge to replace the version number template in the XSL file (which we assume we're reading, + * since fResolve is false) with whatever XMLVERSION we extracted from the XML file (see corresponding kludge below). + */ + if (!COMPILED && XMLVERSION) { + sXML = sXML.replace(/1.x.x<\/xsl:variable>/, '' + XMLVERSION + ''); + } } + /* * If the resource we requested is not really an XML file (or the file didn't exist and the server simply returned * a message like "Cannot GET /devices/pc/machine/5150/cga/64kb/donkey/machine.xml"), we'd like to display a more @@ -200,7 +212,7 @@ function parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done) * we want to continue supporting older Internet Explorer browsers (ie, back to IE9). */ /** @namespace window.ActiveXObject */ - if (window.ActiveXObject || 'ActiveXObject' in window) { // second test is required for IE11 on Windows 8.1 + if (window.ActiveXObject || 'ActiveXObject' in window) { // second test is required for IE11 on Windows 8.1 xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc['loadXML'](sXML); @@ -404,11 +416,13 @@ function embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms) sXSLFile = "/versions/" + sAppClass + "/" + sVersion + "/components.xsl"; } } - var loadXSL = function(sXML, xml) { + + var processXML = function(sXML, xml) { if (!xml) { displayError(sXML); return; } + /* * 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. @@ -417,15 +431,18 @@ function embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms) var aMatch = sXML.match(/<\?xml-stylesheet[^>]* href=(['"])[^'"]*?\/([0-9.]*)\/([^'"]*)\1/); if (aMatch) XMLVERSION = aMatch[2]; } + var transformXML = function(sXSL, xsl) { if (!xsl) { displayError(sXSL); return; } + /* * Record the XSL file, in case someone wants to save the entire machine later. */ Component.addMachineResource(idMachine, sXSLFile, sXSL); + /* * The template in components.xsl now generates a "machine div" that makes * the div we required the caller of embedMachine() to provide redundant, so instead @@ -440,6 +457,7 @@ function embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms) * 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 @@ -485,12 +503,13 @@ function embedMachine(sName, sVersion, idMachine, sXMLFile, sXSLFile, sParms) displayError("unable to transform XML: unsupported browser"); } }; - loadXML(sXSLFile, null, null, false, displayMessage, transformXML); + loadXML(sXSLFile, null, sAppClass, null, false, displayMessage, transformXML); }; + if (sXMLFile.charAt(0) != '<') { - loadXML(sXMLFile, idMachine, sParms, true, displayMessage, loadXSL); + loadXML(sXMLFile, idMachine, sAppClass, sParms, true, displayMessage, processXML); } else { - parseXML(sXMLFile, null, idMachine, sParms, false, displayMessage, loadXSL); + parseXML(sXMLFile, null, idMachine, sAppClass, sParms, false, displayMessage, processXML); } } else { displayError("missing machine element: " + idMachine); @@ -531,16 +550,27 @@ function embedPC(idMachine, sXMLFile, sXSLFile, sParms) } /** - * Prevent the Closure Compiler from renaming functions we want to export, by adding them - * as (named) properties of a global object. + * embedPC8080(idMachine, sXMLFile, sXSLFile, sParms) + * + * @param {string} idMachine + * @param {string} sXMLFile + * @param {string} sXSLFile + * @param {string} [sParms] + * @return {boolean} true if successful, false if error */ -if (APPNAME == "PCjs") { - window['embedPC'] = embedPC; +function embedPC8080(idMachine, sXMLFile, sXSLFile, sParms) +{ + if (fAsync) web.enablePageEvents(false); + return embedMachine("PC8080", APPVERSION, idMachine, sXMLFile, sXSLFile, sParms); } -if (APPNAME == "C1Pjs") { - window['embedC1P'] = embedC1P; -} +/** + * Prevent the Closure Compiler from renaming functions we want to export, + * by adding them as (named) properties of a global object. + */ +if (APPNAME == "C1Pjs") window['embedC1P'] = embedC1P; +if (APPNAME == "PCjs") window['embedPC'] = embedPC; +if (APPNAME == "PC8080") window['embedPC8080'] = embedPC8080; window['enableEvents'] = web.enablePageEvents; -window['sendEvent'] = web.sendPageEvent; +window['sendEvent'] = web.sendPageEvent; diff --git a/modules/shared/templates/components.xsl b/modules/shared/templates/components.xsl index 13805b4b0..62b87d22f 100644 --- a/modules/shared/templates/components.xsl +++ b/modules/shared/templates/components.xsl @@ -11,6 +11,7 @@ pc + pcjs pcjs 1.x.x www.pcjs.org @@ -58,7 +59,13 @@ float: -
+ + + js + + + +
@@ -204,7 +211,7 @@ -
+
@@ -226,11 +233,11 @@
-
[XML]
+
[XML]
- -