Replaced loadResource() with the more streamlined getResource(), for all your resource-getting needs (well, except for binary files, which should be coming soon)

This commit is contained in:
Jeff Parsons 2016-02-21 15:51:54 -08:00
commit f032f95611
26 changed files with 3881 additions and 3777 deletions

View file

@ -0,0 +1,8 @@
{% comment %}
Used by pages like the one in /api/v1/dump/ to implement a client-side API.
{% endcomment %}
{% for script in page.scripts %}
<script type="text/javascript" src="{{ site.baseurl }}{{ script }}"></script>
{% endfor %}

View file

@ -17,6 +17,8 @@
{% include machine-engines.html %}
{% include page-scripts.html %}
{% include google-analytics.html %}
</body>

26
api/v1/dump/README.md Normal file
View file

@ -0,0 +1,26 @@
---
layout: page
title: PCjs DiskDump and FileDump API
permalink: /api/v1/dump/
scripts: # the following list of scripts should mirror what /modules/diskdump/lib/diskdump.js requires
- /modules/shared/lib/defines.js
- /modules/shared/lib/netlib.js
- /modules/shared/lib/weblib.js
- /modules/shared/lib/diskapi.js
- /modules/shared/lib/dumpapi.js
- /modules/diskdump/lib/diskdump.js
---
PCjs DiskDump and FileDump API
===
The PCjs [DiskDump](/modules/diskdump/) and [FileDump](/modules/filedump/) API are not supported by the current
PCjs web server. When **pcjs.org** switched from a Node.js web server running on Amazon Web Services to GitHub Pages,
the server-side API had to be abandoned.
However, we're working on a client-side replacement of the API that will run
entirely in your browser, so hopefully portions of the original API will be available in the near future.
In the meantime, check out the
[Developer Notes](https://github.com/jeffpar/pcjs#user-content-developer-notes) section of the
[PCjs Project](https://github.com/jeffpar/pcjs) for instructions on running your own local cope of Node.js and the
PCjs web server.

14
api/v1/report/README.md Normal file
View file

@ -0,0 +1,14 @@
---
layout: page
title: PCjs Reporting API
permalink: /api/v1/report/
---
PCjs Reporting API
===
The PCjs Reporting API is not supported by the current PCjs web server. When **pcjs.org** switched from a Node.js
web server running on Amazon Web Services to GitHub Pages, the server-side API had to be abandoned.
However, if you're encountering a serious problem with any of the machines on **pcjs.org**, feel free to
[send us a note](mailto:Jeff@pcjs.org) about the problem, along with a link to the machine. Thanks.

View file

@ -15,6 +15,6 @@ sitemap: false
Build Your Own PC
---
{% include build.html id="build-pc" %}
{% include machine-build.html id="build-pc" %}
{% include machine.html id="custom-pc" %}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -701,7 +701,9 @@ C1PDiskController.prototype.setBinding = function(sHTMLType, sBinding, control,
sFileURL = "http://" + window.location.host + "/api/v1/dump?disk=" + sFilePath;
}
controller.println("loading " + str.getBaseName(sFilePath) + "...");
web.loadResource(sFileURL, true, null, controller, controller.loadDisk);
web.getResource(sFileURL, null, true, function(sURL, sResponse, nErrorCode) {
controller.loadDisk(sURL, sResponse, nErrorCode);
});
}
};
}(this);

View file

@ -74,7 +74,10 @@ function C1PROM(parmsROM)
if (sFileExt != DumpAPI.FORMAT.JSON && sFileExt != DumpAPI.FORMAT.HEX) {
sFileURL = web.getHost() + DumpAPI.ENDPOINT + '?' + DumpAPI.QUERY.FILE + '=' + this.sImage + '&' + DumpAPI.QUERY.FORMAT + '=' + DumpAPI.FORMAT.BYTES;
}
web.loadResource(sFileURL, true, null, this, this.convertImage);
var rom = this;
web.getResource(sFileURL, null, true, function(sURL, sResponse, nErrorCode) {
rom.convertImage(sURL, sResponse, nErrorCode);
});
}
}

View file

@ -129,7 +129,9 @@ C1PSerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sVal
if (serial.bindings["listSerial"]) {
var sFile = serial.bindings["listSerial"].value;
// serial.println("loading " + sFile + "...");
web.loadResource(sFile, true, null, serial, serial.loadFile);
web.getResource(sFile, null, true, function(sURL, sResponse, nErrorCode) {
serial.loadFile(sURL, sResponse, nErrorCode);
});
}
};
return true;
@ -228,8 +230,8 @@ C1PSerialPort.prototype.startLoad = function()
/**
* @this {C1PSerialPort}
* @param {String} sFileName
* @param {string} sFileData (null if loadResource() encountered an error)
* @param {string} sFileName
* @param {string} sFileData (null if getResource() encountered an error)
* @param {number} nResponse from server
*/
C1PSerialPort.prototype.loadFile = function(sFileName, sFileData, nResponse)
@ -245,7 +247,7 @@ C1PSerialPort.prototype.loadFile = function(sFileName, sFileData, nResponse)
this.println("auto-loading " + sFileName);
/*
* QUESTION: Is this setFocus() call strictly necessary? We're being called in the
* context of loadResource(), not some user action. If there was an original user action,
* context of getResource(), not some user action. If there was an original user action,
* then the handler for THAT action should take care to switch focus back, not us.
*/
this.cpu.setFocus();

View file

@ -36,26 +36,28 @@
"use strict";
var fs = require("fs");
var path = require("path");
var http = require("http");
var mkdirp = require("mkdirp");
var crypto = require("crypto");
var defines = require("../../shared/lib/defines");
var net = require("../../shared/lib/netlib");
var proc = require("../../shared/lib/proclib");
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var DiskAPI = require("../../shared/lib/diskapi");
var DumpAPI = require("../../shared/lib/dumpapi");
var X86 = require("../../pcjs/lib/x86");
/**
if (NODE) {
var fs = require("fs");
var path = require("path");
var http = require("http");
var mkdirp = require("mkdirp");
var crypto = require("crypto");
var defines = require("../../shared/lib/defines");
var net = require("../../shared/lib/netlib");
var proc = require("../../shared/lib/proclib");
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var DiskAPI = require("../../shared/lib/diskapi");
var DumpAPI = require("../../shared/lib/dumpapi");
var X86 = require("../../pcjs/lib/x86");
/**
* @class exports
* @property {string} name
* @property {string} version
*/
var pkg = require("../../../package.json");
var pkg = require("../../../package.json");
}
/*
* fConsole controls console messages; it is false by default but is enable by the CLI interface.
@ -425,6 +427,29 @@ DiskDump.CLI = function()
}
};
/**
* API
*
* Client-side version of the server-side function HTTPAPI.processDumpAPI(req, res).
*
* @param {Object} aParms (analogous to req.query on the server)
*/
DiskDump.API = function(aParms)
{
var sDisk = aParms[DumpAPI.QUERY.DISK];
var sFormat = aParms[DumpAPI.QUERY.FORMAT] || DumpAPI.FORMAT.JSON;
var fComments = (aParms[DumpAPI.QUERY.COMMENTS]? true : false);
var disk = new DiskDump(sDisk, null, sFormat, fComments);
disk.loadFile(function(err) {
if (!err) {
var sResponse = disk.convertToJSON();
if (sResponse) web.downloadJSON(sResponse);
}
});
};
/**
* outputDisk(err, disk, sDiskPath, sOutputFile, fOverwrite, sManifestTitle)
*
@ -983,7 +1008,7 @@ DiskDump.prototype.dumpBuffer = function(sKey, buf, len, cbItem, offData)
* @this {DiskDump}
* @param {string} sTrackSig
* @param {number} nTrackNum
* @param {number} nTrackType
* @param {number|null} nTrackType
* @param {number} [nTrackLoad]
* @return {string}
*/
@ -2784,4 +2809,9 @@ DiskDump.prototype.convertToIMG = function()
return this.bufDisk;
};
module.exports = DiskDump;
if (NODE) {
module.exports = DiskDump;
} else {
var aParms = web.getURLParameters();
DiskDump.API(aParms);
}

View file

@ -14,5 +14,8 @@
],
"bin": {
"diskdump": "./bin/diskdump"
},
"dependencies": {
"mkdirp": "^0.3.5"
}
}

View file

@ -13,6 +13,9 @@
}
],
"bin": {
"example": "./bin/htmlout"
"htmlout": "./bin/htmlout"
},
"dependencies": {
"mkdirp": "^0.3.5"
}
}

View file

@ -280,7 +280,10 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
if (!sStatePath) {
this.setReady();
} else {
web.loadResource(sStatePath, true, null, this, this.doneLoad);
var cmp = this;
web.getResource(sStatePath, null, true, function(sURL, sResource, nErrorCode) {
cmp.doneLoad(sURL, sResource, nErrorCode);
});
}
if (!this.bindings["power"]) this.fAutoPower = true;
@ -436,15 +439,14 @@ Computer.prototype.doneLoad = function(sURL, sStateData, nErrorCode)
/**
* wait(fn, parms)
*
* wait() waits until every component is ready (including ourselves, the last component we check),
* then calls the specified Computer method.
* wait() waits until every component is ready (including ourselves, the last component we check), then calls the
* specified Computer method.
*
* TODO: As with web.loadResource(), the Closure Compiler makes it difficult for us to define
* a function type for "fn" that works in all cases; sometimes we want to pass a function that takes
* only a "number", and other times we want to pass a function that takes only an "Array" (the type
* will mirror that of the "parms" parameter). However, the Closure Compiler insists that both functions
* must be declared as accepting both types of parameters. So once again, we must use an untyped function
* declaration, instead of something stricter like:
* TODO: The Closure Compiler makes it difficult for us to define a function type for "fn" that works in all cases;
* sometimes we want to pass a function that takes only a "number", and other times we want to pass a function that
* takes only an "Array" (the type will mirror that of the "parms" parameter). However, the Closure Compiler insists
* that both functions must be declared as accepting both types of parameters. So once again, we must use an untyped
* function declaration, instead of something stricter like:
*
* param {function(this:Computer, (number|Array|undefined)): undefined} fn
*
@ -845,7 +847,7 @@ Computer.prototype.powerReport = function(stateComputer)
* Power every component "down" and optionally save the machine state.
*
* There's one scenario that powerOff() isn't currently able to deal with very effectively: what to do when
* the user switches away while it's still being restored, causing Disk loadResource() calls to fail. The
* the user switches away while it's still being restored, causing Disk getResource() calls to fail. The
* Disk component calls notify() when that happens -- see Disk.mount() -- but the FDC and HDC controllers don't
* notify *us* of those problems, so Computer assumes that the restore was completely successful, when in fact
* it was only partially successful.
@ -1178,7 +1180,7 @@ Computer.prototype.verifyUserID = function(sUserID)
var fMessages = DEBUG && this.messageEnabled();
if (fMessages) this.printMessage("verifyUserID(" + sUserID + ")");
var sRequest = web.getHost() + UserAPI.ENDPOINT + '?' + UserAPI.QUERY.REQ + '=' + UserAPI.REQ.VERIFY + '&' + UserAPI.QUERY.USER + '=' + sUserID;
var response = web.loadResource(sRequest);
var response = web.getResource(sRequest);
var nErrorCode = response[0];
var sResponse = response[1];
if (!nErrorCode && sResponse) {
@ -1278,24 +1280,24 @@ Computer.prototype.storeServerState = function(sUserID, sState, fSync)
* TODO: Determine whether or not any browsers cancel our request if we're called during a browser "shutdown" event,
* and whether or not it matters if we do an async request (currently, we're not, to try to ensure the request goes through).
*/
var data = {};
data[UserAPI.QUERY.REQ] = UserAPI.REQ.STORE;
data[UserAPI.QUERY.USER] = sUserID;
data[UserAPI.QUERY.STATE] = State.key(this, Computer.APPVERSION);
data[UserAPI.QUERY.DATA] = sState;
var dataPost = {};
dataPost[UserAPI.QUERY.REQ] = UserAPI.REQ.STORE;
dataPost[UserAPI.QUERY.USER] = sUserID;
dataPost[UserAPI.QUERY.STATE] = State.key(this, Computer.APPVERSION);
dataPost[UserAPI.QUERY.DATA] = sState;
var sRequest = web.getHost() + UserAPI.ENDPOINT;
if (!fSync) {
web.loadResource(sRequest, true, data);
web.getResource(sRequest, dataPost, true);
} else {
var response = web.loadResource(sRequest, false, data);
var sResponse = response[1];
if (response[0]) {
var response = web.getResource(sRequest, dataPost);
var sResponse = response[0];
if (response[1]) {
if (sResponse) {
var i = sResponse.indexOf('\n');
if (i > 0) sResponse = sResponse.substr(0, i);
if (!sResponse.indexOf("Error: ")) sResponse = sResponse.substr(7);
}
sResponse = '{"' + UserAPI.RES.CODE + '":' + response[0] + ',"' + UserAPI.RES.DATA + '":"' + sResponse + '"}';
sResponse = '{"' + UserAPI.RES.CODE + '":' + response[1] + ',"' + UserAPI.RES.DATA + '":"' + sResponse + '"}';
}
if (DEBUG && this.messageEnabled()) this.printMessage(sResponse);
return JSON.parse(sResponse);
@ -1359,7 +1361,7 @@ Computer.prototype.onReset = function()
* or not to unload/reload all their original auto-mounted disk images.
*
* However, if we started with a predefined state (ie, sStatePath is set), we take this shortcut, because
* we don't (yet) have code in place to gracefully reload the initial state (requires calling loadResource()
* we don't (yet) have code in place to gracefully reload the initial state (requires calling getResource()
* again); alternatively, we could avoid throwing that state away, but it seems better to save the memory.
*
* TODO: Make this more graceful, so that we can stop using the reloadPage() sledgehammer.

View file

@ -1099,8 +1099,10 @@ Disk.prototype.load = function(sDiskName, sDiskPath, file, fnNotify, controller)
}
}
}
var result = web.loadResource(sDiskURL, true, null, this, this.doneLoad);
return result.length > 0;
var disk = this;
return !!web.getResource(sDiskURL, null, true, function(sURL, sResponse, nErrorCode) {
disk.doneLoad(sURL, sResponse, nErrorCode);
});
};
/**
@ -2032,8 +2034,11 @@ Disk.prototype.readRemoteSectors = function(iCylinder, iHead, iSector, nSectors,
sParms += '&' + DiskAPI.QUERY.ADDR + '=' + iCylinder + ':' + iHead + ':' + iSector + ':' + nSectors;
sParms += '&' + DiskAPI.QUERY.MACHINE + '=' + this.controller.getMachineID();
sParms += '&' + DiskAPI.QUERY.USER + '=' + this.controller.getUserID();
var disk = this;
var sDiskURL = web.getHost() + DiskAPI.ENDPOINT + '?' + sParms;
web.loadResource(sDiskURL, fAsync, null, this, this.doneReadRemoteSectors, [iCylinder, iHead, iSector, nSectors, fAsync, done]);
web.getResource(sDiskURL, null, fAsync, function(sURL, sResponse, nErrorCode) {
disk.doneReadRemoteSectors(sURL, sResponse, nErrorCode, [iCylinder, iHead, iSector, nSectors, fAsync, done]);
});
return;
}
if (done) done(-1, false);
@ -2121,17 +2126,20 @@ Disk.prototype.writeRemoteSectors = function(iCylinder, iHead, iSector, nSectors
}
if (this.fRemote) {
var data = {};
var dataPost = {};
this.fWriteInProgress = true;
data[DiskAPI.QUERY.ACTION] = DiskAPI.ACTION.WRITE;
data[DiskAPI.QUERY.VOLUME] = this.sDiskPath;
data[DiskAPI.QUERY.CHS] = this.nCylinders + ':' + this.nHeads + ':' + this.nSectors + ':' + this.cbSector;
data[DiskAPI.QUERY.ADDR] = iCylinder + ':' + iHead + ':' + iSector + ':' + nSectors;
data[DiskAPI.QUERY.MACHINE] = this.controller.getMachineID();
data[DiskAPI.QUERY.USER] = this.controller.getUserID();
data[DiskAPI.QUERY.DATA] = JSON.stringify(abSectors);
dataPost[DiskAPI.QUERY.ACTION] = DiskAPI.ACTION.WRITE;
dataPost[DiskAPI.QUERY.VOLUME] = this.sDiskPath;
dataPost[DiskAPI.QUERY.CHS] = this.nCylinders + ':' + this.nHeads + ':' + this.nSectors + ':' + this.cbSector;
dataPost[DiskAPI.QUERY.ADDR] = iCylinder + ':' + iHead + ':' + iSector + ':' + nSectors;
dataPost[DiskAPI.QUERY.MACHINE] = this.controller.getMachineID();
dataPost[DiskAPI.QUERY.USER] = this.controller.getUserID();
dataPost[DiskAPI.QUERY.DATA] = JSON.stringify(abSectors);
var disk = this;
var sDiskURL = web.getHost() + DiskAPI.ENDPOINT;
return web.loadResource(sDiskURL, fAsync, data, this, this.doneWriteRemoteSectors, [iCylinder, iHead, iSector, nSectors, fAsync]);
web.getResource(sDiskURL, dataPost, fAsync, function(sURL, sResponse, nErrorCode) {
disk.doneWriteRemoteSectors(sURL, sResponse, nErrorCode, [iCylinder, iHead, iSector, nSectors, fAsync]);
});
}
return false;
};
@ -2188,7 +2196,7 @@ Disk.prototype.disconnectRemoteDisk = function()
sParms += '&' + DiskAPI.QUERY.MACHINE + '=' + this.controller.getMachineID();
sParms += '&' + DiskAPI.QUERY.USER + '=' + this.controller.getUserID();
var sDiskURL = web.getHost() + DiskAPI.ENDPOINT + '?' + sParms;
web.loadResource(sDiskURL, true);
web.getResource(sDiskURL, null, true);
this.fRemote = false;
}
};

View file

@ -117,7 +117,10 @@ function ROM(parmsROM)
if (sFileExt != DumpAPI.FORMAT.JSON && sFileExt != DumpAPI.FORMAT.HEX) {
sFileURL = web.getHost() + DumpAPI.ENDPOINT + '?' + DumpAPI.QUERY.FILE + '=' + this.sFilePath + '&' + DumpAPI.QUERY.FORMAT + '=' + DumpAPI.FORMAT.BYTES + '&' + DumpAPI.QUERY.DECIMAL + '=true';
}
web.loadResource(sFileURL, true, null, this, this.doneLoad);
var rom = this;
web.getResource(sFileURL, null, true, function(sURL, sResponse, nErrorCode) {
rom.doneLoad(sURL, sResponse, nErrorCode);
});
}
}

View file

@ -200,13 +200,12 @@ function Video(parmsVideo, canvas, context, textarea, container)
*/
this.fHasFocus = false;
var video = this;
/*
* Here's the gross code to handle full-screen support across all supported browsers. The lack of standards
* is exasperating; browsers can't agree on 'full' or 'Full, 'request' or 'Request', 'screen' or 'Screen', and
* while some browsers honor other browser prefixes, most browsers don't.
*/
var video = this;
this.fGecko = web.isUserAgent("Gecko/");
var i, sEvent, asPrefixes = ['', 'moz', 'webkit', 'ms'];
@ -288,7 +287,9 @@ function Video(parmsVideo, canvas, context, textarea, container)
if (sFileExt != "json") {
sFileURL = web.getHost() + DumpAPI.ENDPOINT + '?' + DumpAPI.QUERY.FILE + '=' + sFileURL + '&' + DumpAPI.QUERY.FORMAT + '=' + DumpAPI.FORMAT.BYTES;
}
web.loadResource(sFileURL, true, null, this, this.doneLoad);
web.getResource(sFileURL, null, true, function(sURL, sResponse, nErrorCode) {
video.doneLoad(sURL, sResponse, nErrorCode);
});
}
}

View file

@ -58,7 +58,7 @@ var cAsyncMachines = 0;
/**
* loadXML(sFile, idMachine, sParms, fResolve, display, done)
*
* This is the preferred way to load all XML and XSL files. It uses loadResource()
* 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.
*
* For example, since I've been unable to get the XSLT document() function to work inside any
@ -97,7 +97,7 @@ function loadXML(sXMLFile, idMachine, sParms, fResolve, display, done)
parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done);
};
display("Loading " + sXMLFile + "...");
web.loadResource(sXMLFile, fAsync, null, null, doneLoadXML);
web.getResource(sXMLFile, null, fAsync, doneLoadXML);
}
/**
@ -177,7 +177,7 @@ function parseXML(sXML, sXMLFile, idMachine, sParms, fResolve, display, done)
* Supposedly, the IE XML DOM parser will throw an exception, but I haven't tested that, and unless all other
* browsers do that, that's not helpful.
*
* The best I can do at this stage (assuming web.loadResource() didn't drop any error information on the floor)
* The best I can do at this stage (assuming web.getResource() didn't drop any error information on the floor)
* is verify that the requested resource "looks like" valid XML (in other words, it begins with a '<').
*/
var xmlDoc = null;
@ -308,7 +308,7 @@ function resolveXML(sXML, display, done)
};
display("Loading " + sRefFile + "...");
web.loadResource(sRefFile, fAsync, null, null, doneReadXML);
web.getResource(sRefFile, null, fAsync, doneReadXML);
return;
}
done(sXML, null);

View file

@ -325,35 +325,29 @@ net.downloadFile = function(sURL, sFile, done)
};
/**
* loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
* getResource(sURL, dataPost, fAsync, done)
*
* Request the specified resource (sURL), and once the request is complete,
* optionally call the specified method (fnNotify) of the specified component (componentNotify).
*
* TODO: Figure out how we can strongly type the fnNotify parameter, because the Closure Compiler has issues with:
*
* {function(this:Component, string, (string|null), number, (number|string|null|Object|Array|undefined))} [fnNotify]
*
* NOTE: This function is a mirror image of the weblib version, for server-side component testing within Node;
* since it is NOT intended for production use, it may make liberal use of synchronous functions, warning messages, etc.
* Request the specified resource (sURL), and once the request is complete, notify done().
*
* @param {string} sURL
* @param {Object|null} [dataPost] for a POST request (default is a GET request)
* @param {boolean} [fAsync] is true for an asynchronous request
* @param {Object|null} [data] for a POST request (default is a GET request)
* @param {Component} [componentNotify]
* @param {function(...)} [fnNotify]
* @param {number|string|null|Object|Array} [pNotify] optional fnNotify parameter
* @return {Array} containing errorCode and responseText (empty array if async request)
* @param {function(string,string,number)} [done]
* @return {Array|null} Array containing [sResource, nErrorCode], or null if no response yet
*/
net.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNotify) {
var nErrorCode = -1;
var sResponse = null;
net.getResource = function(sURL, dataPost, fAsync, done)
{
var nErrorCode = -1, sResource = null, response = null;
if (net.isRemote(sURL)) {
console.log('net.loadResource("' + sURL + '"): unimplemented');
console.log('net.getResource("' + sURL + '"): unimplemented');
} else {
if (!sServerRoot) {
sServerRoot = path.join(path.dirname(fs.realpathSync(__filename)), "../../../");
}
/*
* TODO: Revisit why we pass back sBaseName instead of the original sURL....
*/
var sBaseName = str.getBaseName(sURL);
var sFile = path.join(sServerRoot, sURL);
if (fAsync) {
@ -362,21 +356,14 @@ net.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
* TODO: If err is set, is there an error code we should return (instead of -1)?
*/
if (!err) {
sResponse = s;
sResource = s;
nErrorCode = 0;
}
if (fnNotify) {
if (!componentNotify) {
fnNotify(sBaseName, sResponse, nErrorCode, pNotify);
} else {
fnNotify.call(componentNotify, sBaseName, sResponse, nErrorCode, pNotify);
}
}
if (done) done(sBaseName, sResource, nErrorCode);
});
return [];
} else {
try {
sResponse = fs.readFileSync(sFile, {encoding: "utf8"});
sResource = fs.readFileSync(sFile, {encoding: "utf8"});
nErrorCode = 0;
} catch(err) {
/*
@ -384,16 +371,11 @@ net.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
*/
console.log(err.message);
}
if (fnNotify) {
if (!componentNotify) {
fnNotify(sBaseName, sResponse, nErrorCode, pNotify);
} else {
fnNotify.call(componentNotify, sBaseName, sResponse, nErrorCode, pNotify);
if (done) done(sBaseName, sResource, nErrorCode);
response = [sResource, nErrorCode];
}
}
}
}
return [nErrorCode, sResponse];
return response;
};
if (NODE) module.exports = net;

View file

@ -44,7 +44,7 @@ if (NODE) {
* savePC(idMachine, sPCJSFile)
*
* @param {string} idMachine
* @param {string} [sPCJSFile]
* @param {string} sPCJSFile
* @return {boolean} true if successful, false if error
*/
function savePC(idMachine, sPCJSFile)
@ -61,7 +61,9 @@ function savePC(idMachine, sPCJSFile)
sPCJSFile = "/versions/pcjs/" + (XMLVERSION || APPVERSION) + "/pc" + (dbg? "-dbg" : "") + ".js";
}
}
web.loadResource(sPCJSFile, true, null, null, downloadCSS, [idMachine, str.getBaseName(sPCJSFile, true), sParms, sState]);
web.getResource(sPCJSFile, null, true, function(sURL, sResponse, nErrorCode) {
downloadCSS(sURL, sResponse, nErrorCode, [idMachine, str.getBaseName(sPCJSFile, true), sParms, sState]);
});
return true;
}
web.alertUser("Unable to identify machine '" + idMachine + "'");
@ -94,7 +96,9 @@ function downloadCSS(sURL, sPCJS, nErrorCode, aMachineInfo)
*/
downloadPC(sURL, null, 0, aMachineInfo);
} else {
web.loadResource(sCSSFile, true, null, null, downloadPC, aMachineInfo);
web.getResource(sCSSFile, null, true, function(sURL, sResponse, nErrorCode) {
downloadPC(sURL, sResponse, nErrorCode, aMachineInfo);
});
}
return;
}

View file

@ -171,37 +171,23 @@ web.notice = function(s, fPrintOnly, id)
};
/**
* loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
* getResource(sURL, dataPost, fAsync, done)
*
* Request the specified resource (sURL), and once the request is complete,
* optionally call the specified method (fnNotify) of the specified component (componentNotify).
*
* TODO: Figure out how we can strongly type the fnNotify parameter, because the Closure Compiler has issues with:
*
* {function(this:Component, string, (string|null), number, (number|string|null|Object|Array|undefined))} [fnNotify]
* Request the specified resource (sURL), and once the request is complete, notify done().
*
* @param {string} sURL
* @param {Object|null} [dataPost] for a POST request (default is a GET request)
* @param {boolean} [fAsync] is true for an asynchronous request
* @param {Object} [data] for a POST request (default is a GET request)
* @param {Component} [componentNotify]
* @param {function(...)} [fnNotify]
* @param {number|string|null|Object|Array} [pNotify] optional fnNotify info parameter
* @return {Array} containing errorCode and responseText (empty array if fAsync is true)
* @param {function(string,string,number)} [done]
* @return {Array|null} Array containing [sResource, nErrorCode], or null if no response yet
*/
web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNotify)
web.getResource = function(sURL, dataPost, fAsync, done)
{
var nErrorCode = 0;
var sURLData = null;
var nErrorCode = 0, sResource = null, response = null;
if (typeof resources == 'object' && (sURLData = resources[sURL])) {
if (fnNotify) {
if (!componentNotify) {
fnNotify(sURL, sURLData, nErrorCode, pNotify);
} else {
fnNotify.call(componentNotify, sURL, sURLData, nErrorCode, pNotify);
}
}
return [nErrorCode, sURLData];
if (typeof resources == 'object' && (sResource = resources[sURL])) {
if (done) done(sURL, sResource, nErrorCode);
return [sResource, nErrorCode];
}
if (NODE) {
@ -212,7 +198,7 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
* if (!Component) Component = require("./component");
*/
var net = require("./netlib");
return net.loadResource(sURL, fAsync, data, componentNotify, fnNotify, pNotify);
return net.getResource(sURL, dataPost, fAsync, done);
}
var xmlHTTP = (window.XMLHttpRequest? new window.XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP"));
@ -228,64 +214,52 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
*
* xmlHTTP.onreadystatechange = undefined;
*/
sURLData = xmlHTTP.responseText;
sResource = xmlHTTP.responseText;
/*
* The normal "success" case is an HTTP status code of 200, but when testing with files loaded
* from the local file system (ie, when using the "file:" protocol), we have to be a bit more "flexible".
*/
if (xmlHTTP.status == 200 || !xmlHTTP.status && sURLData.length && web.getHostProtocol() == "file:") {
if (MAXDEBUG) web.log("xmlHTTP.onreadystatechange(" + sURL + "): returned " + sURLData.length + " bytes");
if (xmlHTTP.status == 200 || !xmlHTTP.status && sResource.length && web.getHostProtocol() == "file:") {
if (MAXDEBUG) web.log("xmlHTTP.onreadystatechange(" + sURL + "): returned " + sResource.length + " bytes");
}
else {
nErrorCode = xmlHTTP.status || -1;
web.log("xmlHTTP.onreadystatechange(" + sURL + "): error code " + nErrorCode);
}
if (fnNotify) {
if (!componentNotify) {
fnNotify(sURL, sURLData, nErrorCode, pNotify);
} else {
fnNotify.call(componentNotify, sURL, sURLData, nErrorCode, pNotify);
}
}
if (done) done(sURL, sResource, nErrorCode);
}
};
}
if (data) {
var sData = "";
for (var p in data) {
if (!data.hasOwnProperty(p)) continue;
if (sData) sData += "&";
sData += p + '=' + encodeURIComponent(data[p]);
if (dataPost) {
var sDataPost = "";
for (var p in dataPost) {
if (!dataPost.hasOwnProperty(p)) continue;
if (sDataPost) sDataPost += "&";
sDataPost += p + '=' + encodeURIComponent(dataPost[p]);
}
sData = sData.replace(/%20/g, '+');
if (MAXDEBUG) web.log("web.loadResource(POST " + sURL + "): " + sData.length + " bytes");
sDataPost = sDataPost.replace(/%20/g, '+');
if (MAXDEBUG) web.log("web.getResource(POST " + sURL + "): " + sDataPost.length + " bytes");
xmlHTTP.open("POST", sURL, !!fAsync); // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
xmlHTTP.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlHTTP.send(sData);
xmlHTTP.send(sDataPost);
} else {
if (MAXDEBUG) web.log("web.loadResource(GET " + sURL + ")");
if (MAXDEBUG) web.log("web.getResource(GET " + sURL + ")");
xmlHTTP.open("GET", sURL, !!fAsync); // ensure that fAsync is a valid boolean (Internet Explorer xmlHTTP functions insist on it)
xmlHTTP.send();
}
var response = [];
if (!fAsync) {
sURLData = xmlHTTP.responseText;
sResource = xmlHTTP.responseText;
if (xmlHTTP.status == 200) {
if (MAXDEBUG) web.log("web.loadResource(" + sURL + "): returned " + sURLData.length + " bytes");
response = sResource;
if (MAXDEBUG) web.log("web.getResource(" + sURL + "): returned " + sResource.length + " bytes");
} else {
nErrorCode = xmlHTTP.status || -1;
web.log("web.loadResource(" + sURL + "): error code " + nErrorCode);
response = nErrorCode = xmlHTTP.status || -1;
web.log("web.getResource(" + sURL + "): error code " + nErrorCode);
}
if (fnNotify) {
if (!componentNotify) {
fnNotify(sURL, sURLData, nErrorCode, pNotify);
} else {
fnNotify.call(componentNotify, sURL, sURLData, nErrorCode, pNotify);
}
}
response = [nErrorCode, sURLData];
if (done) done(sURL, sResource, nErrorCode);
response = [sResource, nErrorCode];
}
return response;
};
@ -305,15 +279,15 @@ web.loadResource = function(sURL, fAsync, data, componentNotify, fnNotify, pNoti
*/
web.sendReport = function(sApp, sVer, sURL, sUser, sType, sReport, sHostName)
{
var data = {};
data[ReportAPI.QUERY.APP] = sApp;
data[ReportAPI.QUERY.VER] = sVer;
data[ReportAPI.QUERY.URL] = sURL;
data[ReportAPI.QUERY.USER] = sUser;
data[ReportAPI.QUERY.TYPE] = sType;
data[ReportAPI.QUERY.DATA] = sReport;
var dataPost = {};
dataPost[ReportAPI.QUERY.APP] = sApp;
dataPost[ReportAPI.QUERY.VER] = sVer;
dataPost[ReportAPI.QUERY.URL] = sURL;
dataPost[ReportAPI.QUERY.USER] = sUser;
dataPost[ReportAPI.QUERY.TYPE] = sType;
dataPost[ReportAPI.QUERY.DATA] = sReport;
var sReportURL = (sHostName? sHostName : "http://" + SITEHOST) + ReportAPI.ENDPOINT;
web.loadResource(sReportURL, true, data);
web.getResource(sReportURL, dataPost, true);
};
/**
@ -596,7 +570,7 @@ web.isMobile = function()
web.getURLParameters = function(sParms)
{
var aParms = {};
if (window) { // an alternative to "if (typeof module === 'undefined')" if require("defines") has been invoked
if (window) { // an alternative to "if (typeof module === 'undefined')" if require("defines") was used
if (!sParms) {
/*
* Note that window.location.href returns the entire URL, whereas window.location.search
@ -616,6 +590,45 @@ web.getURLParameters = function(sParms)
return aParms;
};
/**
* downloadJSON()
*
* @param {string} sJSON
* @param {string} [sFileName]
*/
web.downloadJSON = function(sJSON, sFileName)
{
var link, sAlert;
var fDownload = !!sFileName;
var sURI = "data:application/json,";
if (!web.isUserAgent("Firefox")) {
fDownload = false;
sURI += encodeURI(sJSON);
} else {
sURI += encodeURIComponent(sJSON);
if (fDownload) {
link = document.createElement('a');
if (typeof link.download != 'string') fDownload = false;
}
}
if (fDownload) {
link.href = sURI;
link.download = sFileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
sAlert = 'Check your Downloads folder for "' + sFileName + '".';
} else {
window.open(sURI);
sAlert = 'Check your browser for a new window/tab containing the requested data.';
}
web.alertUser(sAlert);
};
/**
* onCountRepeat(n, fn, fnComplete, msDelay)
*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long