Merge branch 'master' into gh-pages

This commit is contained in:
Jeff Parsons 2017-02-07 17:58:01 -08:00
commit 536196d236
11 changed files with 178 additions and 45 deletions

View file

@ -388,6 +388,12 @@ specified page; e.g.:
http://localhost:8088/?aspect=2.0
- *resume*: set it to a numeric value (0-3) to override a machine's *resume* setting; e.g.:
http://localhost:8088/?resume=0
More information about the *resume* attribute is available in the [documentation](/docs/pcx86/computer/#attributes).
Updating PCjs
---

View file

@ -81,10 +81,10 @@ However, I've gradually switched to the more conventional JavaScript object nota
``` javascript
ChipSet.PIC_LO = {
OCW2_EOI: 0x20, // non-specific EOI (end-of-interrupt)
OCW2_EOI_SPEC: 0x60, // specific EOI
OCW2_EOI_ROT: 0xA0, // rotate on non-specific EOI
OCW2_EOI_ROTSPEC: 0xE0 // rotate on specific EOI
OCW2_EOI: 0x20, // non-specific EOI (end-of-interrupt)
OCW2_EOI_SPEC: 0x60, // specific EOI
OCW2_EOI_ROT: 0xA0, // rotate on non-specific EOI
OCW2_EOI_ROTSPEC: 0xE0 // rotate on specific EOI
};
```
@ -104,7 +104,7 @@ To ensure that debug-only code is not simply *disabled* but also *removed*, the
``` javascript
if (DEBUG) {
[code to be removed by the Closure Compiler]
[code to be removed by the Closure Compiler]
}
```

View file

@ -6,6 +6,7 @@ machines:
- id: test1170
type: pdp11
debugger: true
sticky: top
---
{% include machine.html id="test1170" %}
@ -46,8 +47,62 @@ Debugger commands described below to load and execute these "toggle-ins".
Load Address 300
Exam Display = 070707 ... Relocation works
With the PDPjs Debugger, the above "toggle-in" is easily entered with the following commands (the semicolons are optional;
they just make it easier to paste an entire set of commands into the Debugger at once):
Step 1: Load ADDR register with 200:
{% include machine-command.html type='clickOnce' label='LOAD 200' machine='test1170' command='script' value='set Panel SR 200;toggle Panel LOAD' %}
Step 2: Deposit 012737 at ADDR 200:
{% include machine-command.html type='clickOnce' label='DEPOSIT 012737' machine='test1170' command='script' value='set Panel SR 012737;toggle Panel DEP' %}
Step 3: Deposit 000400 at ADDR 202:
{% include machine-command.html type='clickOnce' label='DEPOSIT 000400' machine='test1170' command='script' value='set Panel SR 000400;toggle Panel DEP' %}
Step 4: Deposit 177572 at ADDR 204:
{% include machine-command.html type='clickOnce' label='DEPOSIT 177572' machine='test1170' command='script' value='set Panel SR 177572;toggle Panel DEP' %}
Step 5: Deposit 012737 at ADDR 206:
{% include machine-command.html type='clickOnce' label='DEPOSIT 012737' machine='test1170' command='script' value='set Panel SR 012737;toggle Panel DEP' %}
Step 6: Deposit 070707 at ADDR 210:
{% include machine-command.html type='clickOnce' label='DEPOSIT 070707' machine='test1170' command='script' value='set Panel SR 070707;toggle Panel DEP' %}
Step 7: Deposit 000200 at ADDR 212:
{% include machine-command.html type='clickOnce' label='DEPOSIT 000200' machine='test1170' command='script' value='set Panel SR 000200;toggle Panel DEP' %}
Step 8: Deposit 000000 at ADDR 214:
{% include machine-command.html type='clickOnce' label='DEPOSIT 000000' machine='test1170' command='script' value='set Panel SR 000000;toggle Panel DEP' %}
Step 9: Load ADDR register with 300:
{% include machine-command.html type='clickOnce' label='LOAD 300' machine='test1170' command='script' value='set Panel SR 300;toggle Panel LOAD' %}
Step 10: Deposit 300 at ADDR 300:
{% include machine-command.html type='clickOnce' label='DEPOSIT 300' machine='test1170' command='script' value='toggle Panel DEP' %}
Step 11: Load ADDR register with 17772300:
{% include machine-command.html type='clickOnce' label='LOAD 17772300' machine='test1170' command='script' value='set Panel SR 17772300;toggle Panel LOAD' %}
Step 12: Deposit 077406 at ADDR 17772300:
{% include machine-command.html type='clickOnce' label='DEPOSIT 077406' machine='test1170' command='script' value='set Panel SR 077406;toggle Panel DEP' %}
Step 13: Load ADDR register with 17772340:
{% include machine-command.html type='clickOnce' label='LOAD 17772340' machine='test1170' command='script' value='set Panel SR 17772340;toggle Panel LOAD' %}
Step 14: Deposit 000001 at ADDR 17772340:
{% include machine-command.html type='clickOnce' label='DEPOSIT 000001' machine='test1170' command='script' value='set Panel SR 000001;toggle Panel DEP' %}
Step 15: Load ADDR register with 200:
{% include machine-command.html type='clickOnce' label='LOAD 200' machine='test1170' command='script' value='set Panel SR 200;toggle Panel LOAD' %}
Step 16: Set ENABLE and toggle START:
{% include machine-command.html type='clickOnce' label='START' machine='test1170' command='script' value='set Panel ENABLE 1; toggle Panel START' %}
Step 17: Load ADDR register with 300:
{% include machine-command.html type='clickOnce' label='LOAD 300' machine='test1170' command='script' value='set Panel SR 300;toggle Panel LOAD' %}
Step 18: Examine ADDR 300:
{% include machine-command.html type='clickOnce' label='EXAM' machine='test1170' command='script' value='toggle Panel EXAM' %}
Alternatively, with the PDPjs Debugger, the above "toggle-in" is easily entered with the following commands (the
semicolons are optional; they just make it easier to paste an entire set of commands into the Debugger at once):
e 200 012737 000400 177572 012737 070707 000200 000000;
e 300 000300;

View file

@ -46,7 +46,8 @@ This machine is ready to boot [XXDP+ Diagnostics](/disks/dec/rl02k/xxdp/) ("BOOT
We need to select a drive to load the [RL02K XXDP+ Diagnostics Disk](/disks/dec/rl02k/xxdp/), and since it is
an RL02K disk, we need to use an RL02 drive. A typical PDP-11 machine with a single [RL11 Disk Controller](/devices/pdp11/rl11/)
could contain up to four such drives, which we refer to as RL0 through RL3.
could contain up to four such drives, which we refer to as RL0 through RL3. And since we want to boot the XXDP
disk, we need to select drive RL0, since the boot code on the disk appears to assume drive 0.
To automatically boot the [RL02K XXDP+ Diagnostics Disk](/disks/dec/rl02k/xxdp/) and run the **EKBAD0** diagnostic,
press: {% include machine-command.html type='button' label='Run EKBAD0' machine='test1170' command='runEKBAD0' %}

View file

@ -34,7 +34,8 @@ At the prompt, type "BOOT RL0". The following text should appear:
.
NOTE: Any RL11 disk drive (RL0-RL3) can be used. RL0 was selected for demonstration purposes.
NOTE: In theory, any RL11 disk drive (RL0-RL3) could be used. However, the boot code on the disk appears to assume
drive 0, so RL0 should be selected.
PDPjs has been tested with the following diagnostics:

View file

@ -68,7 +68,7 @@ function eb(a,b,c){gb[a]&&b&&(gb[a][b]=c)}function Wa(a){window&&window.alert(a)
function lb(a,b){var c;if(void 0!==a){var d;b&&(b=0<(d=b.indexOf("."))?b.substr(0,d+1):"");for(d=0;d<bb.length;d++)if(c)c==bb[d]&&(c=null);else if(!(a!=bb[d].type||b&&bb[d].id.indexOf(b)))return bb[d]}return null}function mb(a){var b=null;if(a=a.getAttribute("data-value"))try{b=eval("("+a+")")}catch(c){Wa(c.message+" ("+a+")")}return b}function nb(a,b,c){var d;b&&(void 0===d&&(d="Panel"),(d=lb(d,a.id))&&(b=d.na[b])&&a.Cb(null,c,b))}
function ob(a,b){b=pb(b.parentNode,"pcx86-control");for(var c=0;c<b.length;c++)for(var d=b[c].childNodes,e=0;e<d.length;e++){var f=d[e];if(1===f.nodeType){var g=f.getAttribute("class");if(g)for(var h=g.split(" "),k=0;k<h.length;k++)switch(g=h[k],g){case "pcx86-binding":(g=mb(f))&&g.binding&&a.Cb(g.type,g.binding,f,g.value),k=h.length}}}}
function pb(a,b,c){c&&(b+="-"+c+"-object");if(a.getElementsByClassName)return a.getElementsByClassName(b);var d;c=[];a=a.getElementsByTagName("*");var e=new RegExp("(^| )"+b+"( |$)");b=0;for(d=a.length;b<d;b++)e.test(a[b].className)&&c.push(a[b]);return c}
function qb(a,b,c){for(var d=!0;c<b.length;){var e=b[c],f=e[0],g=null;0<=sb.indexOf(f)&&(g=function(c){return function(){qb(a,b,c)}}(c+1));var h=tb[f];if(h)if(!g)d=h(e[1],e[2],e[3]);else{if(!h(g,e[1],e[2],e[3]))break}else{var d=!1,k=lb(e[1],a);if(k)if(h=ub[f])d=h(k,e[2],e[3]);else if(h=k.exports)if(h=h[f])if(d=!0,!g)d=h.call(k,e[2],e[3]);else if(!h.call(k,g,e[2],e[3]))break}if(!d){Wa("Script error ("+f+")");break}c++}return d}l=ab.prototype;
function qb(a,b,c){for(var d=!0;c<b.length;){var e=b[c],f=e[0],g=null;0<=sb.indexOf(f)&&(g=function(c){return function(){qb(a,b,c)}}(c+1));var h=tb[f];if(h)if(!g)d=h(e[1],e[2],e[3]);else{if(!h(g,e[1],e[2],e[3]))break}else{var d=!1,k=lb(e[1],a);if(k)if(h=ub[f])d=h(k,e[2],e[3]);else{var m=k.exports;if(m&&(h=m[f]))if(d=!0,!g)d=h.call(k,e[2],e[3]);else if(!h.call(k,g,e[2],e[3]))break}}if(!d){Wa("Script error: "+f+(h?" failed":" unrecognized"));break}c++}return d}l=ab.prototype;
l.toString=function(){return this.name?this.name:this.id||this.type};
l.Cb=function(a,b,c){switch(b){case "clear":return this.na[b]||(this.na[b]=c,c.onclick=function(a){return function(){a.na.print&&(a.na.print.value="")}}(this)),!0;case "print":return this.na[b]||(this.Ie=this.na[b]=c,c.value="",this.P=function(a){return function(b,c){8192<a.value.length&&(a.value=a.value.substr(a.value.length-4096));a.value+=(void 0!==c?c+": ":"")+(b||"")+"\n";a.scrollTop=a.scrollHeight}}(c),this.Fa=function(a){this.P(a,this.be)}),!0;default:return!1}};l.log=function(){};l.P=function(){};
l.status=function(a){this.P(this.be+": "+a)};l.Fa=function(a,b,c){c=c||this.type;b||Wa((c?c+": ":"")+a)};function vb(a,b){a.ea.error=!0;a.Fa(b)}function wb(a,b){b&&(a.ea.ready?b():a.pg=b);return a.ea.ready}function yb(a,b){a.ea.error||(a.ea.ready=!1!==b,a.ea.ready&&(b=a.pg,a.pg=null,b&&b()))}function zb(a,b){a.ea.pf&&(b?a.ea.$g=!0:void 0===b&&a.P(a.toString()+" busy"));return a.ea.pf}

View file

@ -66,7 +66,7 @@ function Pa(a){var b=!1;window&&(b=window.confirm(a));return b}function Qa(a){va
function Sa(a,b){var c;if(void 0!==a){var d;b&&(b=0<(d=b.indexOf("."))?b.substr(0,d+1):"");for(d=0;d<Ma.length;d++)if(c)c==Ma[d]&&(c=null);else if(!(a!=Ma[d].type||b&&Ma[d].id.indexOf(b)))return Ma[d]}return null}function Ta(a){var b=null;if(a=a.getAttribute("data-value"))try{b=eval("("+a+")")}catch(c){r(c.message+" ("+a+")")}return b}function Ua(a,b,c){var d;b&&(void 0===d&&(d="Panel"),(d=Sa(d,a.id))&&(b=d.ia[b])&&a.wb(null,c,b))}
function Va(a,b){b=Wa(b.parentNode,"pcx86-control");for(var c=0;c<b.length;c++)for(var d=b[c].childNodes,e=0;e<d.length;e++){var f=d[e];if(1===f.nodeType){var g=f.getAttribute("class");if(g)for(var h=g.split(" "),l=0;l<h.length;l++)switch(g=h[l],g){case "pcx86-binding":(g=Ta(f))&&g.binding&&a.wb(g.type,g.binding,f,g.value),l=h.length}}}}
function Wa(a,b,c){c&&(b+="-"+c+"-object");if(a.getElementsByClassName)return a.getElementsByClassName(b);var d;c=[];a=a.getElementsByTagName("*");var e=new RegExp("(^| )"+b+"( |$)");b=0;for(d=a.length;b<d;b++)e.test(a[b].className)&&c.push(a[b]);return c}
function Xa(a,b,c){for(var d=!0;c<b.length;){var e=b[c],f=e[0],g=null;0<=Ya.indexOf(f)&&(g=function(c){return function(){Xa(a,b,c)}}(c+1));var h=Za[f];if(h)if(!g)d=h(e[1],e[2],e[3]);else{if(!h(g,e[1],e[2],e[3]))break}else{var d=!1,l=Sa(e[1],a);if(l)if(h=ab[f])d=h(l,e[2],e[3]);else if(h=l.exports)if(h=h[f])if(d=!0,!g)d=h.call(l,e[2],e[3]);else if(!h.call(l,g,e[2],e[3]))break}if(!d){r("Script error ("+f+")");break}c++}return d}k=t.prototype;
function Xa(a,b,c){for(var d=!0;c<b.length;){var e=b[c],f=e[0],g=null;0<=Ya.indexOf(f)&&(g=function(c){return function(){Xa(a,b,c)}}(c+1));var h=Za[f];if(h)if(!g)d=h(e[1],e[2],e[3]);else{if(!h(g,e[1],e[2],e[3]))break}else{var d=!1,l=Sa(e[1],a);if(l)if(h=ab[f])d=h(l,e[2],e[3]);else{var m=l.exports;if(m&&(h=m[f]))if(d=!0,!g)d=h.call(l,e[2],e[3]);else if(!h.call(l,g,e[2],e[3]))break}}if(!d){r("Script error: "+f+(h?" failed":" unrecognized"));break}c++}return d}k=t.prototype;
k.toString=function(){return this.name?this.name:this.id||this.type};
k.wb=function(a,b,c){switch(b){case "clear":return this.ia[b]||(this.ia[b]=c,c.onclick=function(a){return function(){a.ia.print&&(a.ia.print.value="")}}(this)),!0;case "print":return this.ia[b]||(this.Cf=this.ia[b]=c,c.value="",this.lc=function(a){return function(b,c){8192<a.value.length&&(a.value=a.value.substr(a.value.length-4096));a.value+=(void 0!==c?c+": ":"")+(b||"")+"\n";a.scrollTop=a.scrollHeight}}(c),this.Aa=function(a){this.lc(a,this.Td)}),!0;default:return!1}};k.log=function(){};k.lc=function(){};
k.status=function(a){this.lc(this.Td+": "+a)};k.Aa=function(a,b,c){c=c||this.type;b||r((c?c+": ":"")+a)};function bb(a,b){a.ca.error=!0;a.Aa(b)}function cb(a,b){b&&(a.ca.ready?b():a.Ff=b);return a.ca.ready}function db(a,b){a.ca.error||(a.ca.ready=!1!==b,a.ca.ready&&(b=a.Ff,a.Ff=null,b&&b()))}function eb(a,b){if(a.ca.lg)return a.ca.wf=!1,a.ca.lg=!1;if(a.ca.error)return a.lc(a.toString()+" error"),!1;a.ca.wf=b;return a.ca.wf}k.Ob=function(){return this.ca.Pb=!0};

View file

@ -1301,7 +1301,13 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
if (!aParms) continue;
sReplacement = "";
sMachineID = findParm(aParms, 'machine');
var sControl = findParm(aParms, 'type') || 'button';
var sSingle = "false,";
var sControl = findParm(aParms, 'type');
if (sControl == "clickOnce") {
sControl = "";
sSingle = "true,";
}
sControl = sControl || "button";
var sControlType = sControl == 'button'? ' type="button"' : '';
if (this.aMachineDefs[sMachineID]) {
var sCommand = findParm(aParms, 'command');
@ -1312,7 +1318,7 @@ MarkOut.prototype.convertMDMachineLinks = function(sBlock)
} else if (sValue) {
sValue = sValue.replace(/"/g, "&quot;");
}
sReplacement = '<' + sControl + sControlType + ' onclick="commandMachine(';
sReplacement = '<' + sControl + sControlType + ' onclick="commandMachine(this,' + sSingle;
sReplacement += "'" + sMachineID + "',";
sReplacement += "'" + findParm(aParms, 'component') + "',";
sReplacement += "'" + sCommand + "',";

View file

@ -162,7 +162,7 @@ class PanelPDP11 extends Component {
'TEST': [0, 0, true, false, this.processLEDTest]
};
for (var i = 0; i < 22; i++) {
this.switches['S'+i] = [0, 0, false, false, this.processSwitchReg, i];
this.switches['S'+i] = [0, 0, false, false, this.processSRSwitch, i];
}
/** @type {ComputerPDP11} */
@ -179,14 +179,23 @@ class PanelPDP11 extends Component {
/*
* The 'hold' and 'toggle' exports, which map to holdSwitch() and toggleSwitch(), both press and release
* the specified switch, but processCommands() considers a 'hold' function to be asynchronous, which means it
* will be passed a callback function that can be used to implement a delay. toggleSwitch() doesn't support
* a delay, so it should only be used with toggles (eg, 'ENABLE'), not momentary switches (eg, 'TEST').
* the specified switch, but processCommands() considers a 'hold' function to be asynchronous, which means
* that holdSwitch() will be passed a callback function that can be used to implement a delay between the
* press and the release, whereas toggleSwitch() will not.
*
* holdSwitch() only makes sense for momentary switches (eg, 'TEST'), where a visual delay might be nice.
* If the switch isn't momentary, or no delay is desired, then use toggleSwitch(); it will be more efficient.
*
* Finally, for switches that are toggles (eg, 'ENABLE'), you can use setSwitch() to set it to a specific
* state: zero for "off" and non-zero for "on". setSwitch() also supports meta-switches like "SR", using
* the entire value to set a series of switches at once; the value is assumed to be octal unless overridden
* by a prefix (eg, "0x") or suffix (eg, ".").
*/
this['exports'] = {
'hold': this.holdSwitch,
'toggle': this.toggleSwitch,
'reset': this.resetSwitches
'reset': this.resetSwitches,
'set': this.setSwitch
};
this.setReady();
@ -255,7 +264,7 @@ class PanelPDP11 extends Component {
*/
setSR(value)
{
this.setSwitches(value);
this.setSRSwitches(value);
}
/**
@ -631,6 +640,28 @@ class PanelPDP11 extends Component {
return true;
}
/**
* setSwitch(sBinding, sValue)
*
* @this {PanelPDP11}
* @param {string} sBinding
* @param {string} sValue
* @return {boolean}
*/
setSwitch(sBinding, sValue)
{
if (sBinding == "SR") {
return this.setSRSwitches(Str.parseInt(sValue, 8))
}
var sw = this.switches[sBinding];
if (sw) {
sw[1] = +sValue? 1 : 0;
this.displaySwitch(sBinding, sw[1]);
return true;
}
return false;
}
/**
* toggleSwitch(sBinding)
*
@ -736,12 +767,16 @@ class PanelPDP11 extends Component {
processStart(value, index)
{
if (!value && !this.cpu.isRunning()) {
this.cpu.setPC(this.regAddr);
/*
* TODO: Verify what the PDP-11/70 Handbook means when it says that when the 'START' switch
* is depressed, "the computer system will be cleared." I take it to mean that it performs
* the equivalent of a RESET instruction.
*/
this.cpu.resetCPU();
/*
* The PDP-11/70 Handbook goes on to say: "If the system needs to be initialized but execution
* is not wanted, the START switch should be depressed while the HALT/ENABLE switch is in the HALT
@ -955,18 +990,18 @@ class PanelPDP11 extends Component {
/*
* This is another one of my "innovations": when you're done testing the LEDs, all the switches reset as well.
*/
this.setSwitches(0);
this.setSRSwitches(0);
}
}
/**
* processSwitchReg(value, index)
* processSRSwitch(value, index)
*
* @this {PanelPDP11}
* @param {number} value (normally 0 or 1, but we only depend on it being zero or non-zero)
* @param {number} index
*/
processSwitchReg(value, index)
processSRSwitch(value, index)
{
if (value) {
this.regSwitches |= 1 << index;
@ -1066,31 +1101,37 @@ class PanelPDP11 extends Component {
}
/**
* hasSwitches(value)
* hasSRSwitches(value)
*
* @this {PanelPDP11}
* @return {boolean}
*/
hasSwitches()
hasSRSwitches()
{
return this.bindings[PanelPDP11.SWITCH.S0] !== undefined;
}
/**
* setSwitches(value)
* setSRSwitches(value)
*
* @this {PanelPDP11}
* @param {number} value
* @param {number|undefined} value
* @return {boolean}
*/
setSwitches(value)
setSRSwitches(value)
{
if (this.hasSwitches()) {
this.regSwitches = value;
if (this.hasSRSwitches() && !isNaN(value)) {
this.regSwitches = value | 0;
for (var i = 0; i < 22; i++) {
this.switches['S'+i][1] = (value & (1 << i))? 1 : 0;
this.switches['S'+i][1] = (this.regSwitches & (1 << i))? 1 : 0;
}
/*
* This (re)displays ALL switches, not merely the SR switches, but that's OK.
*/
this.displaySwitches();
return true;
}
return false;
}
/**

View file

@ -621,11 +621,19 @@ class Component {
/**
* Component.getScriptCommands(sScript)
*
* Backslash sequences like \n, \r, and \\ have already been converted to LF, CR and backslash
* characters, since the entire script string was injected into a JavaScript function call, so
* any backslash sequence that JavaScript supports was automatically converted.
* This is a simple parser that breaks sScript into an array of commands, where each command
* is an array of tokens, where tokens are sequences of characters separated by any of: tab, space,
* carriage-return (CR), line-feed (LF), semicolon, single-quote, or double-quote; if a quote is
* used, all characters up to the next matching quote become part of the token, allowing any of the
* other separators to be part of the token. CR, LF and semicolon also serve to terminate a command,
* with semicolon being preferred, because it's 1) more visible, and 2) essential when the entire
* script is a multi-line string where all CR/LF were replaced by spaces (which is what Jekyll does,
* and since we can't change Jekyll, it's what our own MarkDown Front Matter parser does as well;
* see convertMD() in markout.js, where the aCommandDefs array is built).
*
* The complete list of backslash sequences supported by JavaScript:
* Backslash sequences like \n, \r, and \\ have already been converted to LF, CR and backslash
* characters, since the entire script string is injected into a JavaScript function call, so any
* backslash sequence that JavaScript supports is automatically converted:
*
* \0 \' \" \\ \n \r \v \t \b \f \uXXXX \xXX
* ^J ^M ^K ^I ^H ^L
@ -717,11 +725,21 @@ class Component {
static processCommands(idMachine, aaCommands, iCommand)
{
var fSuccess = true;
// var dbg = Component.getComponentByType("Debugger", idMachine);
while (iCommand < aaCommands.length) {
var aTokens = aaCommands[iCommand];
var sCommand = aTokens[0];
/*
* It's possible to route this output to the Debugger window with dbg.println()
* instead, but it's a bit too confusing mingling script output in a window that
* already mingles Debugger and machine output.
*/
Component.println('script: ' + aTokens.join(' '));
var fnCallReady = null;
if (Component.asyncCommands.indexOf(sCommand) >= 0) {
fnCallReady = function processNextCommand(iNextCommand) {
@ -731,26 +749,26 @@ class Component {
}(iCommand + 1);
}
var fnScript = Component.globalCommands[sCommand];
if (fnScript) {
var fnCommand = Component.globalCommands[sCommand];
if (fnCommand) {
if (!fnCallReady) {
fSuccess = fnScript(aTokens[1], aTokens[2], aTokens[3]);
fSuccess = fnCommand(aTokens[1], aTokens[2], aTokens[3]);
} else {
if (!fnScript(fnCallReady, aTokens[1], aTokens[2], aTokens[3])) break;
if (!fnCommand(fnCallReady, aTokens[1], aTokens[2], aTokens[3])) break;
}
}
else {
fSuccess = false;
var component = Component.getComponentByType(aTokens[1], idMachine);
if (component) {
fnScript = Component.componentCommands[sCommand];
if (fnScript) {
fSuccess = fnScript(component, aTokens[2], aTokens[3]);
fnCommand = Component.componentCommands[sCommand];
if (fnCommand) {
fSuccess = fnCommand(component, aTokens[2], aTokens[3]);
}
else {
var exports = component['exports'];
if (exports) {
var fnCommand = exports[sCommand];
fnCommand = exports[sCommand];
if (fnCommand) {
fSuccess = true;
if (!fnCallReady) {
@ -765,7 +783,7 @@ class Component {
}
if (!fSuccess) {
Component.alertUser("Script error (" + sCommand + ")");
Component.alertUser("Script error: " + sCommand + (fnCommand? " failed" : " unrecognized"));
break;
}

View file

@ -88,7 +88,7 @@ function addStickyMachine(idMachine, sPosition)
}
/**
* commandMachine(idMachine, sComponent, sCommand, sValue)
* commandMachine(control, fSingle, idMachine, sComponent, sCommand, sValue)
*
* Note that this script is not compiled into any of the machines, since "sticky machines" are feature of the PCjs
* website rather than of the machines. And since the machines are compiled, all their code and data is completely
@ -103,14 +103,19 @@ function addStickyMachine(idMachine, sPosition)
* component is found, then its 'exports' table is checked for an entry matching the specified command string, and if
* an entry is found, then the corresponding function is called with the specified data.
*
* @param {Object} control
* @param {boolean} fSingle
* @param {string} idMachine
* @param {string} sComponent
* @param {string} sCommand
* @param {string} [sValue]
* @return {boolean}
*/
function commandMachine(idMachine, sComponent, sCommand, sValue)
function commandMachine(control, fSingle, idMachine, sComponent, sCommand, sValue)
{
if (fSingle) {
control.disabled = true;
}
if (sCommand == "script" && window.processMachineScript) {
return window.processMachineScript(idMachine, sComponent, sValue);
}