Initial cleanup
This commit is contained in:
parent
a5e3e6a59d
commit
efab8c7147
12 changed files with 0 additions and 1906 deletions
|
|
@ -1,327 +0,0 @@
|
|||
/*
|
||||
* parallelAdder.js
|
||||
* by Jeff Parsons, May 11, 2012
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creation of a ParallelAdder object is controlled by the following properties of the
|
||||
* parmsAdder object:
|
||||
*
|
||||
* idResident: ID of the resident register
|
||||
* idIncident: ID of the incident register
|
||||
* idCarries: ID of the carries register
|
||||
*
|
||||
* However, by the time we're called, initParallelAdders() has already looked up the
|
||||
* corresponding Register components by the above IDs (so that we don't have to be
|
||||
* involved in the "wiring" process) and passes them to us as:
|
||||
*
|
||||
* regResident
|
||||
* regIncident
|
||||
* regCarries
|
||||
*
|
||||
* Our constructor also creates an internal Register object (regScratch) that's used
|
||||
* to make a copy of the carry bits in the "carries" register after each internal add cycle.
|
||||
*/
|
||||
function ParallelAdder(parmsAdder, regResident, regIncident, regCarries)
|
||||
{
|
||||
Component.call(this, "ParallelAdder", parmsAdder);
|
||||
this.regResident = regResident;
|
||||
this.regIncident = regIncident;
|
||||
this.regCarries = regCarries;
|
||||
this.aBitsResident = regResident.getBits();
|
||||
this.aBitsIncident = regIncident.getBits();
|
||||
this.aBitsCarries = regCarries.getBits();
|
||||
this.regScratch = new Register({nBits:regCarries.count()});
|
||||
this.aBitsScratch = this.regScratch.getBits();
|
||||
}
|
||||
|
||||
Component.subclass(Component, ParallelAdder, {
|
||||
/*
|
||||
* These functions implement the necessary Register interfaces that other components,
|
||||
* like the Selector, expect us to support.
|
||||
*/
|
||||
count: function() {
|
||||
return this.regResident.count();
|
||||
},
|
||||
readBit: function(iBit) {
|
||||
return this.regResident.readBit(iBit);
|
||||
},
|
||||
writeBit: function(iBit, b) {
|
||||
this.regResident.writeBit(iBit, b);
|
||||
},
|
||||
/*
|
||||
* These are the functions unique to ParallelAdder.
|
||||
*/
|
||||
add: function(fnNotify) {
|
||||
this.stopSteps();
|
||||
this.cCarryCycles = 0;
|
||||
this.regResident.writeUndefined(false);
|
||||
this.regResident.updateAll();
|
||||
this.regIncident.writeUndefined(false);
|
||||
this.regIncident.updateAll();
|
||||
this.firstStep(this.stepAddRegisters, fnNotify);
|
||||
},
|
||||
stop: function() {
|
||||
this.stopSteps();
|
||||
this.regResident.stopSteps();
|
||||
this.regIncident.stopSteps();
|
||||
},
|
||||
stepAddRegisters: function(n) {
|
||||
this.cCarryCycles++;
|
||||
/*
|
||||
* We call the next step directly, to give this step something concrete to do;
|
||||
* we could have incorporated that code into this step, but it seems cleaner this way.
|
||||
*/
|
||||
this.stepClearCarries(n);
|
||||
if (this.cCarryCycles == 1)
|
||||
this.addStep(this.stepAddIncidentBits);
|
||||
else
|
||||
this.addStep(this.stepAddScratchBits);
|
||||
this.addStep(this.stepCheckCarries);
|
||||
return true;
|
||||
},
|
||||
stepClearCarries: function(n) {
|
||||
this.printStep(n, "Clearing carry bits");
|
||||
this.regCarries.writeAll(false);
|
||||
if (n !== undefined)
|
||||
this.regCarries.updateAll();
|
||||
return true;
|
||||
},
|
||||
stepCheckCarries: function(n) {
|
||||
if (!this.cCarries) {
|
||||
this.printStep(n, "No carries, addition complete");
|
||||
return false;
|
||||
}
|
||||
this.printStep(n, "Copying carry bits to scratch");
|
||||
this.regScratch.copyAll(this.regCarries);
|
||||
return true;
|
||||
},
|
||||
stepAddIncidentBits: function(n) {
|
||||
this.cCarries = 0;
|
||||
/*
|
||||
* The following table describes the 4 possible cases of resident(i) and incident(i) bits,
|
||||
* and what result(i) and carry(i+1) bits must be generated in each of those cases to simulate
|
||||
* the addition of a resident and incident bit:
|
||||
*
|
||||
* case resident(i) incident(i) result(i) carry(i+1)
|
||||
* ---- ----------- ----------- --------- ----------
|
||||
* 1 false "+" false "=" false false
|
||||
* 2 false "+" true "=" true false
|
||||
* 3 true "+" false "=" true false
|
||||
* 4 true "+" true "=" false true
|
||||
*
|
||||
* Prior to adding the incident bits, we cleared all the carry bits, so we only have to *set* carry bits,
|
||||
* never *clear* them. As for the result bits, they must be written back to the resident bits register,
|
||||
* so we must always write the resident result bit -- which you can tell from the table above is equivalent
|
||||
* to an XOR operation (ie, true if only ONE of either the resident or incident bits is true, false if BOTH
|
||||
* are false or true).
|
||||
*/
|
||||
this.printStep(n, "Adding incident bits");
|
||||
for (var i=0; i < this.aBitsIncident.length; i++) {
|
||||
bIncident = this.aBitsIncident[i];
|
||||
bResident = this.aBitsResident[i];
|
||||
if (bResident && bIncident) {
|
||||
if (i+1 < this.aBitsCarries.length) {
|
||||
this.aBitsCarries[i+1] = true;
|
||||
this.cCarries++;
|
||||
}
|
||||
}
|
||||
this.aBitsResident[i] = (bResident? !bIncident : bIncident); // the closest thing we have to a logical XOR operation
|
||||
}
|
||||
if (n !== undefined) {
|
||||
this.regResident.updateAll();
|
||||
this.regCarries.updateAll();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
stepAddScratchBits: function(n) {
|
||||
this.cCarries = 0;
|
||||
/*
|
||||
* We take advantage of the fact that on iteration i, all scratch bits below bit index i must be zero,
|
||||
* so we can start checking scratch bits (ie, the carry bits from the previous iteration) at bit index "cCarryCycles".
|
||||
*
|
||||
* NOTE: We should assert that all bits below that index are indeed zero, and that we never end up here when
|
||||
* cCarryCycles == aBitsScratch.length (because there shouldn't have been any saved carries from the length-1 iteration).
|
||||
*/
|
||||
this.printStep(n, "Adding previous carry bits");
|
||||
for (var i=this.cCarryCycles; i < this.aBitsScratch.length; i++) {
|
||||
bScratch = this.aBitsScratch[i];
|
||||
bResident = this.aBitsResident[i];
|
||||
if (bResident && bScratch) {
|
||||
if (i+1 < this.aBitsCarries.length) {
|
||||
this.aBitsCarries[i+1] = true;
|
||||
this.cCarries++;
|
||||
}
|
||||
}
|
||||
this.aBitsResident[i] = (bResident? !bScratch : bScratch); // the closest thing we have to a logical XOR operation
|
||||
}
|
||||
if (n !== undefined) {
|
||||
this.regResident.updateAll();
|
||||
this.regCarries.updateAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* initParallelAdders()
|
||||
*
|
||||
* Initializes all the necessary HTML to construct the component as spec'ed.
|
||||
*
|
||||
* Note that each element (e) of class "parallelAdder" is expected to have a "data-value"
|
||||
* attribute containing the same JSON-encoded parameters that the ParallelAdder constructor
|
||||
* expects; specifically:
|
||||
*
|
||||
* idResident: ID of register containing "resident" binary digits
|
||||
* idIncident: ID of register containing "incident" binary digits
|
||||
* idCarries: ID of register used for recording resulting carries
|
||||
*/
|
||||
function initParallelAdders()
|
||||
{
|
||||
var aeAdders = Component.getElementsByClass(window.document, "parallelAdder");
|
||||
for (var iAdder=0; iAdder < aeAdders.length; iAdder++) {
|
||||
var eAdder = aeAdders[iAdder];
|
||||
var parmsAdder = Component.getComponentParms(eAdder);
|
||||
//
|
||||
// Let's find all the prerequisite register components next....
|
||||
//
|
||||
var regResident = Component.getComponentByID(parmsAdder.idResident);
|
||||
var regIncident = Component.getComponentByID(parmsAdder.idIncident);
|
||||
var regCarries = Component.getComponentByID(parmsAdder.idCarries);
|
||||
|
||||
if (!regResident) regResident = new Register();
|
||||
if (!regIncident) regIncident = new Register();
|
||||
if (!regCarries) regCarries = new Register();
|
||||
|
||||
//
|
||||
// Now we can create the ParallelAdder object, record it, and wire it up to the associated document elements.
|
||||
//
|
||||
var adder = new ParallelAdder(parmsAdder, regResident, regIncident, regCarries);
|
||||
initParallelAdderControls(adder, eAdder);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* initParallelAdderControls(reg, eReg)
|
||||
*
|
||||
* For each Adder object created by initParallelAdders(), this function looks for any controls that have been defined
|
||||
* along with the adder element in the current document, and "wires" them as needed.
|
||||
*
|
||||
* The following controls are supported:
|
||||
*
|
||||
* One optional 'output' control of class "status"
|
||||
* One optional 'button' control of class "add"
|
||||
* One optional 'button' control of class "test"
|
||||
* One optional 'button' control of class "step" (if this exists, it will override any "step" setting above)
|
||||
*/
|
||||
function initParallelAdderControls(adder, eAdder)
|
||||
{
|
||||
adder.eAdder = eAdder;
|
||||
var aeControls = Component.getElementsByClass(eAdder.parentNode, "controls");
|
||||
for (var iControl = 0; iControl < aeControls.length; iControl++) {
|
||||
var aeChildren = aeControls[iControl].childNodes;
|
||||
for (var i=0; i < aeChildren.length; i++) {
|
||||
var e = aeChildren[i];
|
||||
if (e.nodeType != document.ELEMENT_NODE)
|
||||
continue;
|
||||
var sClass = e.getAttribute("class");
|
||||
if (e.nodeName == "BUTTON" && sClass == "add") {
|
||||
e.onclick = function() {
|
||||
adder.stop();
|
||||
addParallelValues(adder);
|
||||
};
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "test") {
|
||||
adder.eTest = e;
|
||||
e.onclick = function() {addStartParallelTest(adder);};
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "step") {
|
||||
adder.setStep(e);
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "DIV" && sClass == "status") {
|
||||
adder.setStatusUpdate(
|
||||
function(e) {
|
||||
return function(s) {
|
||||
e.innerHTML = (s? "<span>"+s+"</span>" : "");
|
||||
};
|
||||
}(e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Add" button.
|
||||
*/
|
||||
function addParallelValues(adder)
|
||||
{
|
||||
adder.stop();
|
||||
var vResident = adder.regResident.getValue();
|
||||
// adder.printStatus("Resident register loaded: " + vResident);
|
||||
var vIncident = adder.regIncident.getValue();
|
||||
// adder.printStatus("Incident register loaded: " + vIncident);
|
||||
adder.add(function() {
|
||||
var s1 = "Success", s2 = "==";
|
||||
var vResult = adder.regResident.getValue();
|
||||
if (vResult != vResident + vIncident) {s1 = "Error"; s2 = "!=";}
|
||||
adder.printStatus(s1 + ": result (" + vResult + ") " + s2 + " resident (" + vResident + ") + incident (" + vIncident + ")");
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Test" button.
|
||||
*/
|
||||
function addParallelTestValues(adder)
|
||||
{
|
||||
adder.cTests++;
|
||||
var vResident = Math.random() * 0.5;
|
||||
var vIncident = Math.random() * 0.5;
|
||||
adder.regResident.writeValue(vResident, function() {
|
||||
vResident = adder.regResident.getValue();
|
||||
// adder.printStatus("Resident register loaded: " + vResident);
|
||||
adder.regIncident.writeValue(vIncident, function() {
|
||||
vIncident = adder.regIncident.getValue();
|
||||
// adder.printStatus("Incident register loaded: " + vIncident);
|
||||
adder.add(function() {
|
||||
var vResult = adder.regResident.getValue();
|
||||
adder.cTotalCycles += adder.cCarryCycles - 1; // we don't want to count the initial addition, just the addition of carries
|
||||
adder.printStatus("Addition complete: " + vResult + " (" + adder.cCarryCycles + " carry cycles, " + (adder.cTotalCycles/adder.cTests) + " average)");
|
||||
if (vResult != vResident + vIncident)
|
||||
adder.printStatus("Error: result (" + vResult + ") != resident (" + vResident + ") + incident (" + vIncident + "): " + (vResident + vIncident));
|
||||
else
|
||||
if (adder.cTests < 1000) {
|
||||
addParallelTestValues(adder);
|
||||
return;
|
||||
}
|
||||
addStopParallelTest(adder);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addStartParallelTest(adder)
|
||||
{
|
||||
adder.stop();
|
||||
adder.eTest.innerHTML = "Stop";
|
||||
adder.eTest.onclick = function() {addStopParallelTest(adder);};
|
||||
adder.cTests = 0;
|
||||
adder.cTotalCycles = 0;
|
||||
addParallelTestValues(adder);
|
||||
}
|
||||
|
||||
function addStopParallelTest(adder)
|
||||
{
|
||||
adder.stop();
|
||||
adder.eTest.innerHTML = "Test";
|
||||
adder.eTest.onclick = function() {addStartParallelTest(adder);};
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all the components on the page.
|
||||
*/
|
||||
web.onInit(initParallelAdders);
|
||||
|
|
@ -1,583 +0,0 @@
|
|||
/*
|
||||
* register.js
|
||||
* by Jeff Parsons, May 7, 2012
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creation of a Register object is controlled by the following properties of the
|
||||
* parmsReg object:
|
||||
*
|
||||
* nBits: number of bits
|
||||
* signed: true if signed (default), false otherwise
|
||||
* bit0Exp: the power-of-two for bit 0 (default is zero)
|
||||
* labels: true for labels, false otherwise (default)
|
||||
*
|
||||
* A Register object can be as small as a single bit, and in fact, a 1-bit Register
|
||||
* is exactly how you would create the equivalent of a Bit object. However, the more
|
||||
* common use of this class is to create a bit array.
|
||||
*
|
||||
* Internally, the bit indexes of a register correspond to the array indexes of aBits
|
||||
* (ie, aBits[0] contains the value for bit 0, aBits[1] is bit 1, etc). And the lowest
|
||||
* bit index represents the lowest power-of-two of the value represented by the register.
|
||||
*
|
||||
* The display of a Register object "cell" is handled by the given updateBit() function:
|
||||
*
|
||||
* updateBit(iBit, f)
|
||||
*
|
||||
* If f is undefined, the cell will be blanked; otherwise, either a "0" or a "1" will be
|
||||
* displayed. However, that's just the standard implementation; the caller is free to
|
||||
* define any other behavior (Remember: a register shouldn't care what it looks like).
|
||||
*
|
||||
* Internally, there are also "helper" properties (eg, decimalValue) and methods
|
||||
* (eg, writeValue()) used, for example, to help write data into the register.
|
||||
* Here's a list of some of them (it's difficult to promise that this list will be kept
|
||||
* up-to-date):
|
||||
*
|
||||
* decimalValue: a decimal floating-point value being written to the register
|
||||
* decimalPower: a power-of-two used to help convert decimalValue to binary
|
||||
* decimalBit: a bit index used to help convert decimalValue to binary
|
||||
* decimalSave: saves the initial decimal value, for visual comparison purposes
|
||||
*/
|
||||
var MAX_FRACTIONAL_DIGITS = 12;
|
||||
|
||||
function Register(parmsReg, updateBit) {
|
||||
Component.call(this, "Reg", parmsReg);
|
||||
if (parmsReg === undefined) {
|
||||
parmsReg = {nBits:40, signed:true, bit0Exp:0, labels:true};
|
||||
}
|
||||
this.aBits = new Array(parmsReg.nBits);
|
||||
this.signed = parmsReg.signed;
|
||||
this.bit0Exp = parmsReg.bit0Exp;
|
||||
this.labels = parmsReg.labels;
|
||||
/*
|
||||
* BUGBUG: Compute a reasonable value for this based on how many significant decimal digits
|
||||
* (ie, to the right of the decimal point) correspond to the smallest given negative power-of-two.
|
||||
*/
|
||||
this.fixedDigits = (this.bit0Exp < 0? MAX_FRACTIONAL_DIGITS : 0);
|
||||
this.upperBound = Math.pow(2, this.bit0Exp + this.aBits.length - (this.signed? 1 : 0));
|
||||
this.lowerBound = (this.signed? -this.upperBound : 0);
|
||||
this.updateBit = (updateBit === undefined? function(iBit, f) {} : updateBit);
|
||||
}
|
||||
|
||||
Component.subclass(Component, Register, {
|
||||
/*
|
||||
* getBits() is used for "direct" access to the bits; use readBit() and writeBit() to
|
||||
* access and change individual bits when speed isn't important. Note that changing bits
|
||||
* directly, as well as calling the write or copy functions, bypasses display updates, so
|
||||
* use updateBit() or updateAll() to update the display of one bit or the entire register
|
||||
* as needed. Alternatively, use modifyBit() or modifyAll() to both change and display a
|
||||
* single bit or the entire register.
|
||||
*/
|
||||
count: function() {
|
||||
return this.aBits.length;
|
||||
},
|
||||
getBits: function() {
|
||||
return this.aBits;
|
||||
},
|
||||
readBit: function(iBit) {
|
||||
return this.aBits[iBit];
|
||||
},
|
||||
writeBit: function(iBit, b) {
|
||||
this.aBits[iBit] = b;
|
||||
},
|
||||
writeAll: function(b) {
|
||||
for (var iBit=0; iBit < this.aBits.length; iBit++)
|
||||
this.aBits[iBit] = b;
|
||||
},
|
||||
writeUndefined: function(b) {
|
||||
for (var iBit=0; iBit < this.aBits.length; iBit++)
|
||||
if (this.aBits[iBit] === undefined)
|
||||
this.aBits[iBit] = b;
|
||||
},
|
||||
notBit: function(iBit) {
|
||||
this.aBits[iBit] = !this.aBits[iBit];
|
||||
},
|
||||
notAll: function() {
|
||||
for (var iBit=0; iBit < this.aBits.length; iBit++)
|
||||
this.aBits[iBit] = !this.aBits[iBit];
|
||||
},
|
||||
copyAll: function(reg) {
|
||||
for (var iBit=0; iBit < this.aBits.length; iBit++)
|
||||
this.aBits[iBit] = reg.aBits[iBit];
|
||||
},
|
||||
updateAll: function() {
|
||||
for (var iBit=0; iBit < this.aBits.length; iBit++)
|
||||
this.updateBit(iBit, this.aBits[iBit]);
|
||||
this.refreshLiveValue();
|
||||
},
|
||||
modifyBit: function(iBit, b) {
|
||||
this.writeBit(iBit, b);
|
||||
this.updateBit(iBit, b);
|
||||
this.refreshLiveValue();
|
||||
},
|
||||
modifyAll: function(b) {
|
||||
this.writeAll(b);
|
||||
this.updateAll();
|
||||
},
|
||||
readValue: function() {
|
||||
this.stopSteps();
|
||||
this.printDecimal();
|
||||
this.writeUndefined(false);
|
||||
this.updateAll();
|
||||
this.fPostOp = 0;
|
||||
this.decimalSave = undefined;
|
||||
this.decimalValue = 0;
|
||||
this.decimalBit = this.aBits.length - 1;
|
||||
if (this.signed && this.aBits[this.decimalBit]) {
|
||||
this.fPostOp = -1;
|
||||
}
|
||||
this.decimalExp = this.bit0Exp + this.decimalBit;
|
||||
this.decimalPower = Math.pow(2, this.decimalExp);
|
||||
this.firstStep(this.stepCompareBitToPower);
|
||||
return this.decimalValue; // NOTE: this return value is valid ONLY if single-stepping has been disabled
|
||||
},
|
||||
writeValue: function(v, fnNotify) {
|
||||
this.stopSteps();
|
||||
this.modifyAll(undefined);
|
||||
/*
|
||||
* There are two obvious ways to handle negative values: one is to negate at the beginning,
|
||||
* producing a positive value, and convert as we would any other positive value; when done,
|
||||
* flip all the bits and add a bit at index 0 (ie, a traditional two's-complement conversion).
|
||||
*
|
||||
* However, this variation is better: make the value positive, subtract a bit at index 0,
|
||||
* convert as before, and then flip all the bits. It doesn't matter what order we perform the
|
||||
* two's-complement conversion steps, and performing a "pre-subtraction" against the input value
|
||||
* is cheaper for us than performing a "post-addition" on the output value (because we can
|
||||
* use internal math operations on the input value, whereas the output value is stored only as
|
||||
* an array of bits).
|
||||
*
|
||||
* One downside: when stepping through the conversion process, it may seem odd to see the
|
||||
* initial value modified ever so slightly (eg, -0.5 converted to 0.499999999998181). We could
|
||||
* add an additional explicit step to clear up any potential confusion.
|
||||
*/
|
||||
this.fPostOp = 0;
|
||||
this.decimalSave = v;
|
||||
if (v < 0) {
|
||||
v = -v;
|
||||
v -= Math.pow(2, this.bit0Exp);
|
||||
// BUGBUG: Assert that v is still positive (for tiny negative values of v, this will be a concern)
|
||||
this.fPostOp = 1;
|
||||
}
|
||||
this.decimalValue = v;
|
||||
this.decimalBit = this.aBits.length - 1;
|
||||
if (this.signed) {
|
||||
this.modifyBit(this.decimalBit, 0);
|
||||
this.decimalBit--;
|
||||
}
|
||||
this.decimalExp = this.bit0Exp + this.decimalBit;
|
||||
this.decimalPower = Math.pow(2, this.decimalExp);
|
||||
this.firstStep(this.stepCompareDecimalToPower, fnNotify);
|
||||
},
|
||||
getValue: function() {
|
||||
var decimalValue = 0;
|
||||
var decimalBit = this.aBits.length - 1;
|
||||
var fPostNegate = this.signed && this.aBits[decimalBit];
|
||||
var decimalExp = this.bit0Exp + decimalBit;
|
||||
var decimalPower = Math.pow(2, decimalExp);
|
||||
do {
|
||||
if (this.aBits[decimalBit])
|
||||
decimalValue += decimalPower;
|
||||
if (decimalBit == 0) break;
|
||||
decimalBit--;
|
||||
decimalPower /= 2;
|
||||
} while (true);
|
||||
if (fPostNegate) {
|
||||
decimalValue = -(Math.pow(2, this.bit0Exp + this.aBits.length) - decimalValue);
|
||||
}
|
||||
return decimalValue;
|
||||
},
|
||||
setLiveUpdate: function(updateLiveValue) {
|
||||
this.updateLiveValue = updateLiveValue;
|
||||
this.refreshLiveValue();
|
||||
},
|
||||
refreshLiveValue: function() {
|
||||
if (this.updateLiveValue) {
|
||||
this.updateLiveValue(this.getValue());
|
||||
}
|
||||
},
|
||||
printDecimal: function(v) {
|
||||
if (this.updateDecimal !== undefined) {
|
||||
/*
|
||||
* We allow v to be undefined, as way as signalling that we are beginning a fresh
|
||||
* conversion; we will be calling printDecimal() again at the completion of the conversion,
|
||||
* and v will be defined at that point.
|
||||
*/
|
||||
this.updateDecimal(v);
|
||||
if (v !== undefined && this.log)
|
||||
console.log(this.toString() + ": updated decimal value to " + v.toFixed(this.fixedDigits));
|
||||
}
|
||||
},
|
||||
setDecimalUpdate: function(updateDecimal) {
|
||||
this.updateDecimal = updateDecimal;
|
||||
},
|
||||
/*
|
||||
* The following "step" functions implement writeValue().
|
||||
*
|
||||
* Once writeValue() has initialized all the internal decimal variables, it calls
|
||||
* the first step indirectly, via firstStep(), which in turns invokes other
|
||||
* steps, based on whether the current decimal power is greater than or equal to
|
||||
* the current decimal value.
|
||||
*/
|
||||
stepCompareDecimalToPower: function(n) {
|
||||
this.printStep(n, "Comparing decimal value (" + this.decimalValue + ") to 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")");
|
||||
if (this.decimalValue >= this.decimalPower) {
|
||||
this.addStep(this.stepSetDecimalBit);
|
||||
this.addStep(this.stepReduceDecimalValue);
|
||||
}
|
||||
else {
|
||||
this.addStep(this.stepClearDecimalBit);
|
||||
}
|
||||
if (!this.addStep(this.stepReduceDecimalPower))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
stepSetDecimalBit: function(n) {
|
||||
this.printStep(n, "Setting bit " + this.decimalBit);
|
||||
this.writeBit(this.decimalBit, true);
|
||||
if (n !== undefined) {
|
||||
this.updateBit(this.decimalBit, true);
|
||||
this.refreshLiveValue();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
stepClearDecimalBit: function(n) {
|
||||
this.printStep(n, "Clearing bit " + this.decimalBit);
|
||||
this.writeBit(this.decimalBit, false);
|
||||
if (n !== undefined) {
|
||||
this.updateBit(this.decimalBit, false);
|
||||
this.refreshLiveValue();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
stepReduceDecimalValue: function(n) {
|
||||
this.printStep(n, "Reducing decimal value by 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")"); // this.decimalPower.toFixed(this.fixedDigits));
|
||||
this.decimalValue -= this.decimalPower;
|
||||
if (n !== undefined) this.printDecimal(this.decimalValue);
|
||||
return true;
|
||||
},
|
||||
stepReduceDecimalPower: function(n) {
|
||||
if (this.decimalBit == 0) {
|
||||
var sStep = "Processed bit 0";
|
||||
if (this.fPostOp > 0) {
|
||||
sStep = "Inverting all bits";
|
||||
this.notAll();
|
||||
this.updateAll();
|
||||
}
|
||||
else if (this.fPostOp < 0) {
|
||||
sStep = "Negating result";
|
||||
this.decimalValue = -(Math.pow(2, this.bit0Exp + this.aBits.length) - this.decimalValue);
|
||||
}
|
||||
this.printStep(n, sStep + ", conversion" + (this.decimalSave !== undefined? " of " + this.decimalSave.toFixed(this.fixedDigits) : "") + " complete");
|
||||
if (n === undefined) {
|
||||
/*
|
||||
* Since the conversion was performed without single-stepping, we need to update the register via
|
||||
* updateAll() if this was a writeValue() operation (ie, decimalSave is defined); similarly, we need
|
||||
* to update the decimal value via printDecimal() if this was a readValue() operation.
|
||||
*/
|
||||
if (this.decimalSave !== undefined)
|
||||
this.updateAll();
|
||||
}
|
||||
/*
|
||||
* printDecimal() may have never been called during the conversion, since we only call it when the value has been
|
||||
* reduced. So we always print at the end.
|
||||
*/
|
||||
this.printDecimal(this.decimalValue);
|
||||
return false;
|
||||
}
|
||||
this.printStep(n, "Reducing power-of-two");
|
||||
this.decimalBit--;
|
||||
this.decimalExp--;
|
||||
this.decimalPower /= 2;
|
||||
return true;
|
||||
},
|
||||
/*
|
||||
* The following "step" functions implement readValue().
|
||||
*
|
||||
* Because we take the same "top-down" approach that writeValue() took (ie, from highest power/left-most bit down to
|
||||
* lowest power/right-most bit), we can use the same stepReduceDecimalPower step function that writeValue() used; both
|
||||
* procedures stop after they've processed bit 0.
|
||||
*/
|
||||
stepCompareBitToPower: function(n) {
|
||||
this.printStep(n, "Testing bit " + this.decimalBit);
|
||||
if (this.aBits[this.decimalBit])
|
||||
this.addStep(this.stepIncreaseDecimalValue);
|
||||
if (!this.addStep(this.stepReduceDecimalPower))
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
stepIncreaseDecimalValue: function(n) {
|
||||
this.printStep(n, "Increasing decimal value by 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")"); // this.decimalPower.toFixed(this.fixedDigits));
|
||||
this.decimalValue += this.decimalPower;
|
||||
if (n !== undefined) this.printDecimal(this.decimalValue);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* initRegisters()
|
||||
*
|
||||
* Initializes all the necessary HTML to construct every register as spec'ed.
|
||||
*
|
||||
* This function operates on every element (e) of class "register" and inserts
|
||||
* the appropriate HTML child elements of class "bitCell".
|
||||
*
|
||||
* Note that each element (e) of class "register" is expected to have a "data-value"
|
||||
* attribute containing the same JSON-encoded parameters that the Register constructor
|
||||
* expects.
|
||||
*/
|
||||
function initRegisters()
|
||||
{
|
||||
var aeRegs = Component.getElementsByClass(window.document, "register");
|
||||
for (var iReg=0; iReg < aeRegs.length; iReg++) {
|
||||
var eReg = aeRegs[iReg];
|
||||
var parmsReg = Component.getComponentParms(eReg);
|
||||
var sHTML = "";
|
||||
var nExp = parmsReg.bit0Exp + parmsReg.nBits - 1;
|
||||
for (var iCell=0; iCell < parmsReg.nBits; iCell++,nExp--) {
|
||||
var sLabel = "";
|
||||
sBitClass = "bitCell";
|
||||
if (iCell == 0) {
|
||||
sBitClass += " bitCellLeft";
|
||||
if (parmsReg.signed) sLabel = "+/-";
|
||||
}
|
||||
var sCellID = "r" + iReg + "c" + iCell;
|
||||
var sCell = "<div id=\"" + sCellID + "\" class=\"" + sBitClass + "\"></div>\n";
|
||||
if (!parmsReg.labels) {
|
||||
sHTML += sCell;
|
||||
}
|
||||
else {
|
||||
if (!sLabel) sLabel = "2<sup>" + nExp + "</sup>";
|
||||
sHTML += "<div class=\"bitBucket\">\n" + sCell + "<div class=\"bitLabel\">" + sLabel + "</div>\n</div>\n";
|
||||
}
|
||||
}
|
||||
eReg.innerHTML = sHTML;
|
||||
if (parmsReg.id) {
|
||||
eReg.setAttribute("id", "reg" + parmsReg.id);
|
||||
}
|
||||
|
||||
//
|
||||
// Now that all the document elements have been defined, create an array that refers
|
||||
// to all "bitCell" elements in bit index order (ie, reverse of display order).
|
||||
//
|
||||
var aeBits = [];
|
||||
var aeCells = Component.getElementsByClass(eReg, "bitCell");
|
||||
for (var i=aeCells.length-1; i >= 0; i--) {
|
||||
aeBits.push(aeCells[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Now we can create the Register object, record it, and wire it up to the associated document elements.
|
||||
//
|
||||
var reg = new Register(parmsReg, function(aeBitsParm) {
|
||||
return function(iBit, f) {
|
||||
var s = (f===undefined? " " : (f? "1":"0"));
|
||||
aeBitsParm[iBit].innerHTML = s;
|
||||
};
|
||||
}(aeBits)
|
||||
);
|
||||
|
||||
for (var i=0; i < aeBits.length; i++) {
|
||||
aeBits[i].onclick = function(regParm, iParm) {
|
||||
//
|
||||
// If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
|
||||
// also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
|
||||
// instead. If that's true, and if we ever care to get more details about the click event, then we might
|
||||
// have to worry about that (eg, define a local var: "var event = window.event || e").
|
||||
//
|
||||
return function() {
|
||||
toggleRegisterBit(regParm, iParm);
|
||||
};
|
||||
}(reg, i);
|
||||
}
|
||||
|
||||
initRegisterControls(reg, eReg);
|
||||
|
||||
//
|
||||
// For testing purposes, we could tweak a few of the bits, just to see if all the "wiring" works.
|
||||
//
|
||||
// reg.modifyBit(7, true);
|
||||
// reg.modifyBit(9, false);
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* initRegisterControls(reg, eReg)
|
||||
*
|
||||
* For each Register object created by initRegisters(), this function looks for any controls that have been defined
|
||||
* along with the register element in the current document, and "wires" them as needed.
|
||||
*
|
||||
* The following controls are supported:
|
||||
*
|
||||
* One optional 'input' control of class "value"
|
||||
* One optional 'output' control of class "value"
|
||||
* One optional 'output' control of class "status"
|
||||
* One optional 'button' control of class "random"
|
||||
* One optional 'button' control of class "write"
|
||||
* One optional 'button' control of class "read"
|
||||
* One optional 'button' control of class "clear"
|
||||
* One optional 'button' control of class "step" (if this exists, it will override any "step" setting above)
|
||||
*/
|
||||
function initRegisterControls(reg, eReg)
|
||||
{
|
||||
var aeControls = Component.getElementsByClass(eReg.parentNode, "controls");
|
||||
for (var iControl = 0; iControl < aeControls.length; iControl++) {
|
||||
var aeChildren = aeControls[iControl].childNodes;
|
||||
var eDecimal = null, eRandom = null, eWrite = null, eRead = null;
|
||||
for (var i=0; i < aeChildren.length; i++) {
|
||||
var e = aeChildren[i];
|
||||
if (e.nodeType != document.ELEMENT_NODE)
|
||||
continue;
|
||||
var sClass = e.getAttribute("class");
|
||||
if (e.nodeName == "INPUT" && sClass == "value") {
|
||||
eDecimal = e;
|
||||
reg.setDecimalUpdate(
|
||||
function(e) {
|
||||
return function(v) {
|
||||
e.value = (v !== undefined? v.toFixed(reg.fixedDigits) : "");
|
||||
};
|
||||
}(e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "DIV" && sClass == "value") {
|
||||
reg.setLiveUpdate(
|
||||
function(e) {
|
||||
return function(v) {
|
||||
e.innerHTML = (v !== undefined? "<span>Live value: " + v.toFixed(reg.fixedDigits) + "</span>" : "");
|
||||
};
|
||||
}(e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "DIV" && sClass == "status") {
|
||||
reg.setStatusUpdate(
|
||||
function(e) {
|
||||
return function(s) {
|
||||
e.innerHTML = (s? "<span>" + s + "</span>" : "");
|
||||
};
|
||||
}(e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "random") {
|
||||
eRandom = e;
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "write") {
|
||||
eWrite = e;
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "read") {
|
||||
eRead = e;
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "clear") {
|
||||
e.onclick = function() { clearRegisterValue(reg); };
|
||||
continue;
|
||||
}
|
||||
if (e.nodeName == "BUTTON" && sClass == "step") {
|
||||
reg.setStep(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (eRandom && eDecimal) {
|
||||
eRandom.onclick = function(eDecimal) {
|
||||
return function() { randomizeRegisterValue(reg, eDecimal); };
|
||||
}(eDecimal);
|
||||
}
|
||||
if (eWrite && eDecimal) {
|
||||
eWrite.onclick = function(eDecimal) {
|
||||
return function() { writeRegisterValue(reg, eDecimal); };
|
||||
}(eDecimal);
|
||||
}
|
||||
if (eRead) {
|
||||
eRead.onclick = function(eDecimal) {
|
||||
return function() { readRegisterValue(reg, eDecimal); };
|
||||
}(eDecimal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for all of the individual register "bitCell" elements.
|
||||
*/
|
||||
function toggleRegisterBit(reg, iBit)
|
||||
{
|
||||
reg.modifyBit(iBit, reg.readBit(iBit) === false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Random" button.
|
||||
*
|
||||
* It calls reg.stopSteps() to stop any internal operation currently in progress (eg,
|
||||
* a previous writeValue() or readValue() operation), but it doesn't attempt to write the new value into
|
||||
* the register; that's the "Write" button's job, once the user chooses to accept the new value.
|
||||
*/
|
||||
function randomizeRegisterValue(reg, eDecimal)
|
||||
{
|
||||
/*
|
||||
* NOTE: eDecimal is an <input> element, so set the "value" property rather than the "innerHTML" property.
|
||||
*/
|
||||
reg.stopSteps();
|
||||
eDecimal.value = Math.random().toFixed(reg.fixedDigits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Write" button.
|
||||
*
|
||||
* This takes whatever input value the user has entered (either manually or by clicking the "Random" button)
|
||||
* and calls reg.writeValue() to begin the process of converting the decimal floating-point value to binary and
|
||||
* writing the result to the register.
|
||||
*
|
||||
* If we ever add a user control (eg, a drop-down list) to select a step delay, then we can call setStep()
|
||||
* to change the delay from whatever default delay was selected. Note that a setStep() delay of 0 disables all
|
||||
* single-step output, allowing the operation to run at full speed.
|
||||
*/
|
||||
function writeRegisterValue(reg, eDecimal)
|
||||
{
|
||||
reg.stopSteps();
|
||||
var v = parseFloat(eDecimal.value);
|
||||
if (isNaN(v))
|
||||
v = 0;
|
||||
if (v >= reg.lowerBound && v < reg.upperBound) {
|
||||
reg.writeValue(v);
|
||||
}
|
||||
else {
|
||||
reg.printStatus("Error: decimal value " + v + " out of bounds (" + reg.lowerBound + " <= v < " + reg.upperBound + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Read" button.
|
||||
*
|
||||
* This starts the reg.readValue() procedure, which does return a value, but it's meaningful only if
|
||||
* single-stepping has been disabled. It doesn't matter, because either way, reg.readValue() insures that
|
||||
* that the decimal field is zeroed at the beginning of the procedure and updated at the end (not to mention
|
||||
* intermediate intervals if single-stepping is enabled), so there's no need to update the field here.
|
||||
*
|
||||
* If we ever add a user control (eg, a drop-down list) to select a step delay, then we can call setStep()
|
||||
* to change the delay from whatever default delay was selected. Note that a setStep() delay of 0 disables all
|
||||
* single-step output, allowing the operation to run at full speed.
|
||||
*/
|
||||
function readRegisterValue(reg, eDecimal)
|
||||
{
|
||||
reg.stopSteps();
|
||||
reg.readValue();
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handler for the "Clear" button.
|
||||
*/
|
||||
function clearRegisterValue(reg)
|
||||
{
|
||||
reg.stopSteps();
|
||||
reg.modifyAll(false);
|
||||
reg.printDecimal();
|
||||
reg.printStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all the registers on the page.
|
||||
*/
|
||||
web.onInit(initRegisters);
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
/*
|
||||
* selector.js
|
||||
* by Jeff Parsons, May 24, 2012
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creation of a Selector object is controlled by the following properties of the
|
||||
* parmsSel object:
|
||||
*
|
||||
* nGates: number of gates
|
||||
* color: color of the gate(s)
|
||||
* single: true if single gate image to be used, false otherwise (default)
|
||||
* idSource: ID of the source (eg, component with matching number of bits)
|
||||
* idTarget: ID of the target (eg, component with matching number of bits)
|
||||
* sourceStart: starting bit index of source corresponding to gate index 0
|
||||
* targetStart: starting bit index of target corresponding to gate index 0
|
||||
*
|
||||
* However, by the time we're called, initSelectors() has already looked up the
|
||||
* corresponding source and target components by the above IDs (so that we don't
|
||||
* have to be involved in the "wiring" process) and passes them to us as:
|
||||
*
|
||||
* regSource
|
||||
* regTarget
|
||||
*
|
||||
* A Selector object can be a single gate or an array of gates. The behavior of
|
||||
* these gates is extensible, but by default, gates do nothing more than propagate
|
||||
* bits from a "source" input to a "target" output whenever they are "selected".
|
||||
*
|
||||
* Internally, the gate indexes of a Selector correspond to the array indexes of
|
||||
* aGates (ie, aGates[0] contains the [source, target, selected] triplet for gate
|
||||
* index 0). The source, target and selected values for each gate triplet are stored
|
||||
* at positions GATE_SOURCE, GATE_TARGET, and GATE_SELECTED.
|
||||
*
|
||||
* The display of individual gates is handled by the given updateGate() function:
|
||||
*
|
||||
* updateGate(iGate, f)
|
||||
*
|
||||
* If f is true, the gate should be displayed in an "selected" state, otherwise it
|
||||
* should be displayed in a "deselected" state.
|
||||
*/
|
||||
function Selector(parmsSel, regSource, regTarget, updateGate) {
|
||||
Component.call(this, "Sel", parmsSel);
|
||||
this.aGates = new Array(parmsSel.nGates);
|
||||
this.selected = false; // the selected state of the entire selector
|
||||
this.single = (parmsSel.single === true);
|
||||
this.source = regSource;
|
||||
this.target = regTarget;
|
||||
var sourceIndex = (parmsSel.sourceStart? parmsSel.sourceStart : 0);
|
||||
var targetIndex = (parmsSel.targetStart? parmsSel.targetStart : 0);
|
||||
var sourceCount = (this.source? this.source.count() : -1); // bit index limit for the given source
|
||||
var targetCount = (this.target? this.target.count() : -1); // bit index limit for the given target
|
||||
for (var iGate=0; iGate < this.aGates.length; iGate++) {
|
||||
var s = sourceIndex;
|
||||
var t = targetIndex;
|
||||
if (sourceIndex < 0 || sourceIndex >= sourceCount) s = -1;
|
||||
if (targetIndex < 0 || targetIndex >= targetCount) t = -1;
|
||||
this.aGates[iGate] = [s, t, false];
|
||||
sourceIndex++;
|
||||
targetIndex++;
|
||||
}
|
||||
this.updateGate = (updateGate === undefined? function(iGate, f) {} : updateGate);
|
||||
this.updateAll();
|
||||
}
|
||||
|
||||
var GATE_SOURCE = 0;
|
||||
var GATE_TARGET = 1;
|
||||
var GATE_SELECTED = 2;
|
||||
|
||||
Component.subclass(Component, Selector, {
|
||||
count: function() {
|
||||
return this.aGates.length;
|
||||
},
|
||||
selectGate: function(iGate, f) {
|
||||
this.aGates[iGate][GATE_SELECTED] = f;
|
||||
if (f) {
|
||||
var sourceIndex = this.aGates[iGate][GATE_SOURCE];
|
||||
var targetIndex = this.aGates[iGate][GATE_TARGET];
|
||||
if (sourceIndex >= 0 && targetIndex >= 0)
|
||||
this.target.writeBit(targetIndex, this.source.readBit(sourceIndex));
|
||||
}
|
||||
},
|
||||
selectAll: function(f) {
|
||||
this.selected = f;
|
||||
for (var iGate=0; iGate < this.aGates.length; iGate++) {
|
||||
this.selectGate(iGate, f);
|
||||
}
|
||||
},
|
||||
updateAll: function() {
|
||||
for (var iGate=0; iGate < this.aGates.length; iGate++)
|
||||
this.updateGate(iGate, this.aGates[iGate][GATE_SELECTED]);
|
||||
this.target.updateAll();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* initSelectors()
|
||||
*
|
||||
* Initializes all the necessary HTML to construct every Selector gate or
|
||||
* gate-array as spec'ed.
|
||||
*
|
||||
* This function operates on every element (e) of class "selector" and inserts
|
||||
* the appropriate HTML child elements of class "gate".
|
||||
*
|
||||
* Note that each element (e) of class "selector" is expected to have a "data-value"
|
||||
* attribute containing the same JSON-encoded parameters that the Selector constructor
|
||||
* expects.
|
||||
*/
|
||||
function initSelectors()
|
||||
{
|
||||
var aeSels = Component.getElementsByClass(window.document, "selector");
|
||||
for (var iSel=0; iSel < aeSels.length; iSel++) {
|
||||
var eSel = aeSels[iSel];
|
||||
var parmsSel = Component.getComponentParms(eSel);
|
||||
|
||||
//
|
||||
// Let's find the specified source/target components next, because if nGates isn't defined,
|
||||
// then we will set a default value equal to the number of bits in the source component, if any.
|
||||
//
|
||||
var regSource = Component.getComponentByID(parmsSel.idSource);
|
||||
var regTarget = Component.getComponentByID(parmsSel.idTarget);
|
||||
if (parmsSel.nGates === undefined) {
|
||||
parmsSel.nGates = (regSource? regSource.count() : 1);
|
||||
}
|
||||
|
||||
var nGate = 1;
|
||||
var sHTML = "";
|
||||
if (parmsSel.single) {
|
||||
sHTML += "<div class=\"gate gateLarge\"><img src=\"/my_modules/shared/images/selector.png\"/></div>\n";
|
||||
}
|
||||
else {
|
||||
for (var iGate=0; iGate < parmsSel.nGates; iGate++,nGate++) {
|
||||
sHTML += "<div class=\"gate gateSmall\"><img src=\"/my_modules/shared/images/selector.png\"/></div>\n";
|
||||
}
|
||||
}
|
||||
eSel.innerHTML = sHTML;
|
||||
if (parmsSel.id) {
|
||||
eSel.setAttribute("id", "sel" + parmsSel.id);
|
||||
}
|
||||
|
||||
//
|
||||
// Now that all the document elements have been defined, we can
|
||||
// create an array that refers to all "gate" elements in bit index order
|
||||
// (ie, reverse of display order).
|
||||
//
|
||||
var aeGates = [];
|
||||
var aeCells = Component.getElementsByClass(eSel, "gate");
|
||||
for (var i=aeCells.length-1; i >= 0; i--) {
|
||||
aeGates.push(aeCells[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Now we can create the Selector object, record it, and wire it up to the associated document elements.
|
||||
//
|
||||
var sel = new Selector(parmsSel, regSource, regTarget, function(ae, color, single) {
|
||||
return function(iGate, f) {
|
||||
var s = (f===true? "white": color);
|
||||
ae[single?0:iGate].style.backgroundColor = s;
|
||||
};
|
||||
}(aeGates, parmsSel.color, parmsSel.single)
|
||||
);
|
||||
|
||||
for (var i=0; i < aeGates.length; i++) {
|
||||
aeGates[i].onclick = function (selParm) {
|
||||
return function() {
|
||||
selectSelector(selParm);
|
||||
};
|
||||
}(sel);
|
||||
}
|
||||
|
||||
initSelectorControls(sel, eSel);
|
||||
|
||||
//
|
||||
// For testing purposes, we could tweak a few of the gates, just to see if all the "wiring" works.
|
||||
//
|
||||
// sel.selectGate(7, true);
|
||||
// sel.selectGate(9, false);
|
||||
//
|
||||
}
|
||||
if (aeSels.length == 0)
|
||||
console.log("warning: no selectors on page");
|
||||
}
|
||||
|
||||
/*
|
||||
* initSelectorControls(sel, eSel)
|
||||
*
|
||||
* For each Selector object created by initSelectors(), this function looks for any controls that have been defined
|
||||
* along with the selector element in the current document, and "wires" them as needed.
|
||||
*
|
||||
* The following controls are supported:
|
||||
*
|
||||
* One optional 'button' control of class "select"
|
||||
*/
|
||||
function initSelectorControls(sel, eSel)
|
||||
{
|
||||
var aeControls = Component.getElementsByClass(eSel.parentNode, "controls");
|
||||
for (var iControl = 0; iControl < aeControls.length; iControl++) {
|
||||
var aeChildren = aeControls[iControl].childNodes;
|
||||
for (var i=0; i < aeChildren.length; i++) {
|
||||
var e = aeChildren[i];
|
||||
if (e.nodeType != document.ELEMENT_NODE)
|
||||
continue;
|
||||
var sClass = e.getAttribute("class");
|
||||
if (e.nodeName == "BUTTON" && sClass == "select") {
|
||||
e.onclick = function(e) {
|
||||
return function() { selectSelector(sel, e); };
|
||||
}(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called by the anonymous click handlers for the "Select" button.
|
||||
*/
|
||||
function selectSelector(sel, e)
|
||||
{
|
||||
sel.selectAll(!sel.selected);
|
||||
sel.updateAll();
|
||||
if (e !== undefined) {
|
||||
e.innerHTML = (f? "Deselect" : "Select");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all the selectors on the page.
|
||||
*/
|
||||
web.onInit(initSelectors);
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* stepper.js
|
||||
* by Jeff Parsons, June 24, 2012
|
||||
*
|
||||
* Stepper methods extracted from the original Component class.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The Stepper class defines a set of stepping functions used to help drive multi-step
|
||||
* operations that a component may want to "single-step." The setStep() function determines
|
||||
* the delay, if any, between the steps. If there is no delay, then all the supplied
|
||||
* "step" functions are called directly. Otherwise, any delay (even a minimal delay of 0ms)
|
||||
* results in the creation and queuing of step objects. Every step object contains:
|
||||
*
|
||||
* fn: step function pointer
|
||||
* n: step number
|
||||
*
|
||||
* and is stored in a simple array (aStep) used to enqueue/dequeue the step objects.
|
||||
*
|
||||
* firstStep() gets the ball rolling by queuing the first "step" function. That initial
|
||||
* "step" function, as well as any or all subsequent "step" functions, call addStep()
|
||||
* to add more steps to the queue as needed. As each "step" function successfully finishes
|
||||
* (by returning true), the next "step" function is dequeued and called. As soon as a
|
||||
* "step" function returns false, the dequeuing process stops, and any remaining steps
|
||||
* in the queue are ignored. If the queue empties before that happens, then we essentially
|
||||
* repeat firstStep(), and the process continues.
|
||||
*
|
||||
* If a negative millisecond delay (-1) has been set via setStep(), then both firstStep()
|
||||
* and addStep() call their respective "step" functions directly, instead of queuing them.
|
||||
* That option should be used only for very brief steps, otherwise the browser will appear
|
||||
* to hang if the stepping functions never yield.
|
||||
*
|
||||
* Also, when "step" functions are called directly, the step number (n) is omitted from the
|
||||
* calls, so that the "step" function can quickly determine whether to bypass its internal print
|
||||
* operations. printStep() will automatically bypass, since it has access to the step number,
|
||||
* but if you want to maximize speed, then either always check for an undefined step number, or
|
||||
* use separate "step" functions that omit both the step number and the print operations altogether.
|
||||
*
|
||||
* NOTE: the stepping functions use printStatus() indirectly, via printStep(). However,
|
||||
* there may be times when a component wants to reserve its "status" control for more pertinent
|
||||
* messages. In those cases, the component can pass a "quiet" setting to setStep().
|
||||
*/
|
||||
|
||||
function Stepper() {
|
||||
}
|
||||
|
||||
Stepper.prototype = {
|
||||
/*
|
||||
* initStep(parms) accepts any or all of the following parameter (parms) properties:
|
||||
*
|
||||
* step: millisecond step setting (0 for minimum delay when single-stepping, -1 for direct calls instead of steps)
|
||||
*/
|
||||
initStep: function(parms) {
|
||||
this.msStep = parms.step;
|
||||
this.quiet = (this.msStep == 0);
|
||||
},
|
||||
/*
|
||||
* setStep(ms, quiet)
|
||||
*
|
||||
* ms can be any of:
|
||||
*
|
||||
* 1) non-negative number of milliseconds
|
||||
* 2) -1 to call all step functions directly without delay
|
||||
* 3) an HTML element (eg, a button) that will control stepping via its "onclick" handler
|
||||
*
|
||||
* Note that even 0 is a supported millisecond delay, albeit a minimal one, insuring that scripts
|
||||
* don't run too long without yielding.
|
||||
*
|
||||
* If quiet, then printStep() messages will not be passed to printStatus(); however, if logging is
|
||||
* enabled (refer to this.fLog), printStep() messages will still be logged.
|
||||
*/
|
||||
setStep: function(ms, quiet) {
|
||||
this.msStep = ms;
|
||||
this.quiet = quiet;
|
||||
},
|
||||
stopSteps: function() {
|
||||
if (this.timerSteps !== undefined)
|
||||
clearTimeout(this.timerSteps);
|
||||
if (this.timerNotify !== undefined)
|
||||
clearTimeout(this.timerNotify);
|
||||
this.aSteps = [];
|
||||
this.cSteps = 0;
|
||||
this.timerSteps = undefined;
|
||||
this.fnNotify = undefined;
|
||||
this.timerNotify = undefined;
|
||||
if (!this.quiet) this.printStatus(); // "clear" the status field, if any, as well
|
||||
},
|
||||
firstStep: function(fn, fnNotify) {
|
||||
this.fnNotify = fnNotify;
|
||||
this.timerNotify = undefined;
|
||||
if (this.msStep == -1) {
|
||||
while (fn.call(this))
|
||||
;
|
||||
if (this.fnNotify) this.timerNotify = setTimeout(this.fnNotify, 0);
|
||||
return;
|
||||
}
|
||||
this.kickStep(fn);
|
||||
this.nextStep(0);
|
||||
},
|
||||
kickStep: function(fn) {
|
||||
this.addStep(function(n) {
|
||||
// this.log(this.toString() + ": Step " + n + ": automatic kickStep");
|
||||
if (!fn.call(this, n))
|
||||
return false;
|
||||
return this.kickStep(fn);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
addStep: function(fn) {
|
||||
if (this.msStep == -1) {
|
||||
return fn.call(this);
|
||||
}
|
||||
var step = {fn:fn, n:++this.cSteps};
|
||||
this.aSteps.push(step);
|
||||
return true;
|
||||
},
|
||||
removeStep: function($this) {
|
||||
$this.timerSteps = undefined;
|
||||
if (typeof $this.msStep == "object")
|
||||
$this.msStep.onclick = null;
|
||||
var step = $this.aSteps.shift();
|
||||
if (step === undefined)
|
||||
return false;
|
||||
return $this.doStep(step);
|
||||
},
|
||||
doStep: function(step) {
|
||||
if (!step.fn.call(this, step.n)) {
|
||||
if (this.fnNotify) this.timerNotify = setTimeout(this.fnNotify, 0);
|
||||
return false;
|
||||
}
|
||||
return this.nextStep(this.msStep);
|
||||
},
|
||||
nextStep: function(ms) {
|
||||
if (this.aSteps.length == 0) {
|
||||
console.warn("Component.nextStep(): unexpected end of steps");
|
||||
return false;
|
||||
}
|
||||
if (typeof ms == "number") {
|
||||
/*
|
||||
* IE doesn't support:
|
||||
*
|
||||
* setTimeout(this.removeStep, ms, this);
|
||||
*
|
||||
* so we're forced to do this instead:
|
||||
*
|
||||
* var thisParm = this;
|
||||
* setTimeout(function() {thisParm.removeStep(thisParm);}, ms);
|
||||
*/
|
||||
var thisParm = this;
|
||||
this.timerSteps = setTimeout(function() {thisParm.removeStep(thisParm);}, ms);
|
||||
}
|
||||
else
|
||||
if (typeof ms == "object") {
|
||||
ms.onclick = function(regParm) {
|
||||
/*
|
||||
* If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
|
||||
* also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
|
||||
* instead. If that's true, and if we ever care to get more details about the click event, then we might
|
||||
* have to worry about that (eg, define a local var: "var event = window.event || e").
|
||||
*/
|
||||
return function() {
|
||||
return regParm.removeStep(regParm);
|
||||
};
|
||||
}(this);
|
||||
}
|
||||
else
|
||||
alert("unexpected step parameter (" + ms + ")");
|
||||
return true;
|
||||
},
|
||||
printStep: function(n, s) {
|
||||
if (n !== undefined) {
|
||||
if (!this.quiet)
|
||||
this.printStatus("Step " + n + ": " + s);
|
||||
else if (this.fLog)
|
||||
this.log(this.toString() + ": Step " + n + ": " + s);
|
||||
}
|
||||
},
|
||||
/*
|
||||
* printStatus(s)
|
||||
*
|
||||
* Passes any string (s) to the associated HTML element of class "status", if any;
|
||||
* pass a blank string, or nothing at all, to clear the contents of the associated
|
||||
* "status" element.
|
||||
*
|
||||
* If there's no "status" element associated with this component, then status messages
|
||||
* are simply thrown away. However, if logging is enabled (ie, parms.log was true),
|
||||
* all status messages are still logged.
|
||||
*/
|
||||
printStatus: function(s) {
|
||||
if (this.updateStatus !== undefined) {
|
||||
this.updateStatus(s);
|
||||
}
|
||||
if (this.fLog && s) {
|
||||
this.log(this.toString() + ": " + s);
|
||||
}
|
||||
},
|
||||
/*
|
||||
* setStatusUpdate(s)
|
||||
*
|
||||
* Sets the "updateStatus" handler that printStatus() uses to display any status messages.
|
||||
*/
|
||||
setStatusUpdate: function(updateStatus) {
|
||||
this.updateStatus = updateStatus;
|
||||
}
|
||||
};
|
||||
|
||||
Component.extend(Component.prototype, Stepper.prototype);
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2012-08-28" license="http://www.gnu.org/licenses/gpl.html" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
|
||||
<!ENTITY nbsp " "> <!ENTITY sect "§"> <!ENTITY copy "©"> <!ENTITY para "¶"> <!ENTITY ndash "–"> <!ENTITY mdash "—">
|
||||
<!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡">
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:param name="rootDir" select="''"/>
|
||||
<xsl:param name="generator" select="'client'"/>
|
||||
<xsl:output doctype-system="about:legacy-compat"/>
|
||||
|
||||
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
|
||||
<xsl:include href="components.xsl"/>
|
||||
<xsl:include href="register.xsl"/>
|
||||
|
||||
<xsl:template match="/">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>jsmachines.net</title>
|
||||
<xsl:call-template name="commonStyles"/>
|
||||
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
|
||||
<xsl:if test="//register">
|
||||
<xsl:call-template name="registerIncludes"/>
|
||||
</xsl:if>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page justified">
|
||||
<xsl:apply-templates/>
|
||||
<h4>Return to <a href="/outline.xml">Outline</a></h4>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
.component:before, .component:after {
|
||||
content:"";
|
||||
display:table;
|
||||
}
|
||||
.component:after {
|
||||
clear:both;
|
||||
}
|
||||
.component {
|
||||
zoom:1; /* For IE 6/7 (trigger hasLayout) */
|
||||
font-size: medium;
|
||||
}
|
||||
.component .label {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.label.left {
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
width: 2em;
|
||||
}
|
||||
.component .container {
|
||||
display: inline-block;
|
||||
}
|
||||
.controls, .controls div, .controls input, .controls button {
|
||||
float: left;
|
||||
margin: 2px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
input.value {
|
||||
width: 16em;
|
||||
height: 1em;
|
||||
font-size: medium;
|
||||
border: 1px solid black;
|
||||
line-height: 1em; /* the equivalent of "vertical-align: middle" for single-line elements */
|
||||
text-align: right;
|
||||
}
|
||||
.status, .value {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.status span, .value span {
|
||||
font-size: small;
|
||||
vertical-align: 10%;
|
||||
}
|
||||
.status sup {
|
||||
vertical-align: baseline;
|
||||
position: relative;
|
||||
bottom: .33em;
|
||||
}
|
||||
.status sub {
|
||||
vertical-align: baseline;
|
||||
position: relative;
|
||||
bottom: -.33em;
|
||||
}
|
||||
.selector {
|
||||
float: left;
|
||||
border: 1px solid black;
|
||||
background-color: white;
|
||||
}
|
||||
.selector:before, .selector:after {
|
||||
content:"";
|
||||
display:table;
|
||||
}
|
||||
.selector:after {
|
||||
clear:both;
|
||||
}
|
||||
/* For IE 6/7 (trigger hasLayout) */
|
||||
.selector {
|
||||
zoom:1;
|
||||
}
|
||||
.gateSmall, .gateLarge {
|
||||
float: left;
|
||||
}
|
||||
.gateSmall, .gateSmall img {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
}
|
||||
.gateLarge, .gateLarge img {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2014-03-28" license="http://www.gnu.org/licenses/gpl.html" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other required entities may be defined below (see entities.dtd). -->
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:template name="componentStyles">
|
||||
<xsl:param name="component"></xsl:param>
|
||||
<link rel="stylesheet" type="text/css" href="/my_modules/ecpjs-client/templates/{$component}.css"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="componentScripts">
|
||||
<xsl:param name="component"></xsl:param>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$component = 'components'">
|
||||
<script type="text/javascript" src="/my_modules/shared/lib/component.js"></script>
|
||||
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/stepper.js"></script>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/{$component}.js"></script>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="componentIncludes">
|
||||
<xsl:param name="component"></xsl:param>
|
||||
<xsl:call-template name="componentStyles"><xsl:with-param name="component" select="$component"/></xsl:call-template>
|
||||
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="$component"/></xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="component[@ref]">
|
||||
<xsl:variable name="component" select="name(.)"/>
|
||||
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
|
||||
<xsl:apply-templates select="document($componentFile)"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="component[not(@ref)]">
|
||||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="class" select="@class"/>
|
||||
<xsl:with-param name="parms" select="@parms"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="component">
|
||||
<xsl:param name="class"></xsl:param>
|
||||
<xsl:param name="parms">none:null</xsl:param>
|
||||
<xsl:variable name="id">
|
||||
<!-- Values allowed: ID of component, blank if none (default) -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="@id"><xsl:value-of select="@id"/></xsl:when>
|
||||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="name">
|
||||
<!-- Values allowed: name of component, blank if none (default) -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="name"><xsl:value-of select="name"/></xsl:when>
|
||||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="pos">
|
||||
<!-- Values allowed: left (default), center, or blank for no relative positional preference -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="@pos"><xsl:value-of select="@pos"/></xsl:when>
|
||||
<xsl:otherwise>left</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="step">
|
||||
<!-- Values allowed: number of milliseconds per step, 0 for quick/quiet stepping with yields (default), -1 for no yields -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="@step"><xsl:value-of select="@step"/></xsl:when>
|
||||
<xsl:otherwise>0</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="log">
|
||||
<!-- Values allowed: true to enable console logging, false to disable (default) -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="@log"><xsl:value-of select="@log"/></xsl:when>
|
||||
<xsl:otherwise>false</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<div class="component {$pos}">
|
||||
<xsl:apply-templates select="name"/>
|
||||
<div class="container">
|
||||
<xsl:if test="control[@pos = 'top']">
|
||||
<div class="controls">
|
||||
<xsl:apply-templates select="control[@pos = 'top']" mode="component"/>
|
||||
</div>
|
||||
<div style="clear:both"></div>
|
||||
</xsl:if>
|
||||
<xsl:if test="control[@pos = 'left']">
|
||||
<div class="controls">
|
||||
<xsl:apply-templates select="control[@pos = 'left']" mode="component"/>
|
||||
</div>
|
||||
</xsl:if>
|
||||
<div class="{$class}" data-value="id:'{$id}',name:'{$name}',step:{$step},log:{$log},{$parms}"></div>
|
||||
<xsl:if test="control[@pos = 'right']">
|
||||
<div class="controls">
|
||||
<xsl:apply-templates select="control[@pos = 'right']" mode="component"/>
|
||||
</div>
|
||||
</xsl:if>
|
||||
<xsl:if test="control[not(@pos)]">
|
||||
<div style="clear:both"></div>
|
||||
<div class="controls">
|
||||
<xsl:apply-templates select="control[not(@pos)]" mode="component"/>
|
||||
</div>
|
||||
</xsl:if>
|
||||
<xsl:if test="control[@pos = 'bottom']">
|
||||
<div style="clear:both"></div>
|
||||
<div class="controls">
|
||||
<xsl:apply-templates select="control[@pos = 'bottom']" mode="component"/>
|
||||
</div>
|
||||
</xsl:if>
|
||||
</div>
|
||||
</div>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="name">
|
||||
<xsl:variable name="pos">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@pos"><xsl:value-of select="@pos"/></xsl:when>
|
||||
<xsl:otherwise></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<div class="label {$pos}"><xsl:apply-templates/></div>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="control" mode="component">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@type = 'input'">
|
||||
<input class="{@class}" type="text" value=""/>
|
||||
</xsl:when>
|
||||
<xsl:when test="@type = 'output'">
|
||||
<div class="{@class}"></div>
|
||||
</xsl:when>
|
||||
<xsl:when test="@type = 'button'">
|
||||
<button class="{@class}"><xsl:value-of select="."/></button>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2012-08-28" license="http://www.gnu.org/licenses/gpl.html" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
|
||||
<!ENTITY nbsp " "> <!ENTITY sect "§"> <!ENTITY copy "©"> <!ENTITY para "¶"> <!ENTITY ndash "–"> <!ENTITY mdash "—">
|
||||
<!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡">
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:param name="rootDir" select="''"/>
|
||||
<xsl:param name="generator" select="'client'"/>
|
||||
<xsl:output doctype-system="about:legacy-compat"/>
|
||||
|
||||
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
|
||||
<xsl:include href="components.xsl"/>
|
||||
<xsl:include href="register.xsl"/>
|
||||
|
||||
<xsl:template match="/device">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>jsmachines.net</title>
|
||||
<xsl:call-template name="commonStyles"/>
|
||||
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
|
||||
<xsl:if test="//register">
|
||||
<xsl:call-template name="registerIncludes"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="//component[@class='parallelAdder']">
|
||||
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="'parallelAdder'"/></xsl:call-template>
|
||||
</xsl:if>
|
||||
<xsl:if test="//component[@class='selector']">
|
||||
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="'selector'"/></xsl:call-template>
|
||||
</xsl:if>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page justified">
|
||||
<xsl:apply-templates/>
|
||||
<h4>Return to <a href="/outline.xml">Outline</a></h4>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons" creator="http://www.pcjs.org/" created="2012-05-05T19:53:00" modified="2012-05-05T19:53:00" license="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
|
||||
<!ENTITY nbsp " "> <!ENTITY sect "§"> <!ENTITY copy "©"> <!ENTITY para "¶"> <!ENTITY ndash "–"> <!ENTITY mdash "—">
|
||||
<!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡">
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:param name="rootDir" select="''"/>
|
||||
<xsl:param name="generator" select="'client'"/>
|
||||
<xsl:output doctype-system="about:legacy-compat"/>
|
||||
|
||||
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
|
||||
<!-- The next two lines were added to support embedding components in documents -->
|
||||
<xsl:include href="components.xsl"/>
|
||||
<xsl:include href="register.xsl"/>
|
||||
|
||||
<xsl:template match="/document">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><xsl:value-of select="title"/><xsl:text> | jsmachines.net</xsl:text></title>
|
||||
<xsl:call-template name="commonStyles"/>
|
||||
<!-- The next two lines were added to support embedding components in documents -->
|
||||
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
|
||||
<xsl:call-template name="registerIncludes"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page justified">
|
||||
<h4 style="float:right">Return to <a href="/manuals/ecp/outline.xml">Outline</a></h4>
|
||||
<xsl:call-template name="document"><xsl:with-param name="parent" select="'true'"/></xsl:call-template>
|
||||
<h4>Return to <a href="/manuals/ecp/outline.xml">Outline</a></h4>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="document">
|
||||
<xsl:param name="parent">false</xsl:param>
|
||||
<xsl:param name="ref"></xsl:param>
|
||||
<xsl:if test="not(parent)">
|
||||
<h1><xsl:value-of select="title"/><xsl:apply-templates select="title/footlink"/></h1>
|
||||
<xsl:if test="author"><p><xsl:text>By </xsl:text><xsl:call-template name="authors"/></p></xsl:if>
|
||||
<xsl:apply-templates select="date"/>
|
||||
<xsl:apply-templates select="synopsis"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="parent">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$parent = 'true'">
|
||||
<h2><xsl:apply-templates select="parent"/></h2>
|
||||
<h3><xsl:apply-templates select="title"/></h3>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<h2>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$ref = ''"><xsl:apply-templates select="title"/></xsl:when>
|
||||
<xsl:otherwise><a href="{$ref}"><xsl:apply-templates select="title"/></a></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</h2>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
<xsl:if test="excerpt">
|
||||
<h4><xsl:apply-templates select="excerpt"/></h4>
|
||||
</xsl:if>
|
||||
<xsl:if test="@ref">
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@ref,'.pdf')">
|
||||
<a href="{@ref}"><img src="/my_modules/shared/images/pdf-192.jpg"/></a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<p>[<a href="{@ref}">Link</a>]</p>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
<xsl:if test="content">
|
||||
<xsl:if test="content/p[@name]">
|
||||
<h4><xsl:text>Discusses: </xsl:text>
|
||||
<xsl:for-each select="content/p[@name]">
|
||||
<xsl:if test="position() != 1"><xsl:text>, </xsl:text></xsl:if>
|
||||
<a href="#{@id}"><xsl:value-of select="@name"/></a>
|
||||
</xsl:for-each>
|
||||
</h4>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="content"/>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="include"/>
|
||||
<xsl:apply-templates select="video"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="date">
|
||||
<p><xsl:call-template name="formatDate"><xsl:with-param name="date" select="."/></xsl:call-template></p>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="author">
|
||||
<p><xsl:text>By </xsl:text><xsl:value-of select="."/></p>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="synopsis">
|
||||
<p><xsl:text>Synopsis: </xsl:text><em><xsl:value-of select="."/></em></p>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="content">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="video">
|
||||
<xsl:variable name="controls"><xsl:if test="@controls">controls</xsl:if></xsl:variable>
|
||||
<div class="center">
|
||||
<video width="{@width}" height="{@height}" controls="{$controls}">
|
||||
<xsl:apply-templates select="source"/>
|
||||
Your browser does not support HTML5 video play-back.
|
||||
</video>
|
||||
</div>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="source">
|
||||
<source src="{@src}" type="{@type}"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="include">
|
||||
<xsl:if test="@ref">
|
||||
<xsl:variable name="documentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
|
||||
<xsl:apply-templates select="document($documentFile)/document" mode="include">
|
||||
<xsl:with-param name="parent" select="@parent"/>
|
||||
<xsl:with-param name="link" select="@link"/>
|
||||
<xsl:with-param name="ref" select="@ref"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="document" mode="include">
|
||||
<xsl:param name="parent">false</xsl:param>
|
||||
<xsl:param name="link">false</xsl:param>
|
||||
<xsl:param name="ref"></xsl:param>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$link = 'true'">
|
||||
<xsl:if test="$parent = 'true'">
|
||||
<h2><xsl:apply-templates select="parent"/></h2>
|
||||
</xsl:if>
|
||||
<h3><a href="{$ref}"><xsl:value-of select="title"/></a></h3>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:call-template name="document"><xsl:with-param name="parent" select="$parent"/><xsl:with-param name="ref" select="$ref"/></xsl:call-template>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<hr/>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons" creator="http://www.pcjs.org/" created="2012-05-05T19:53:00" modified="2012-05-05T19:53:00" license="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
|
||||
<!ENTITY nbsp " "> <!ENTITY sect "§"> <!ENTITY copy "©"> <!ENTITY para "¶"> <!ENTITY ndash "–"> <!ENTITY mdash "—">
|
||||
<!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡">
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:param name="rootDir" select="''"/>
|
||||
<xsl:param name="generator" select="'client'"/>
|
||||
<xsl:output doctype-system="about:legacy-compat"/>
|
||||
|
||||
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
|
||||
|
||||
<xsl:template match="/outline">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><xsl:value-of select="title"/><xsl:text> | jsmachines.net</xsl:text></title>
|
||||
<xsl:call-template name="commonStyles"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<xsl:apply-templates/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
.register {
|
||||
float: left;
|
||||
}
|
||||
.bitBucket {
|
||||
float: left;
|
||||
width: 19px;
|
||||
height: 38px;
|
||||
}
|
||||
.bitCell {
|
||||
float: left;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-right: -1px;
|
||||
margin-bottom: -1px;
|
||||
border: 1px solid black;
|
||||
text-align: center;
|
||||
line-height: 19px; /* the equivalent of "vertical-align: middle" for single-line elements */
|
||||
}
|
||||
.bitCellLeft {
|
||||
border-left: 1px solid black;
|
||||
}
|
||||
.bitLabel {
|
||||
font-size: xx-small;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2014-03-28" license="http://www.gnu.org/licenses/gpl.html" -->
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other required entities may be defined below (see entities.dtd). -->
|
||||
]>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:template name="registerIncludes">
|
||||
<link rel="stylesheet" type="text/css" href="/my_modules/ecpjs-client/templates/register.css"/>
|
||||
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/register.js"></script>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="register[@ref]">
|
||||
<xsl:variable name="component" select="name(.)"/>
|
||||
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
|
||||
<xsl:apply-templates select="document($componentFile)"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="register[not(@ref)]">
|
||||
<xsl:variable name="nBits">
|
||||
<!-- Values allowed: positive integer defining number of bits, default of 40 (ECP default) -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="nBits"><xsl:value-of select="nBits"/></xsl:when>
|
||||
<xsl:when test="@nBits"><xsl:value-of select="@nBits"/></xsl:when>
|
||||
<xsl:otherwise>40</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="signed">
|
||||
<!-- Values allowed: true if left-most bit is sign bit (ECP default), false if not -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="signed"><xsl:value-of select="signed"/></xsl:when>
|
||||
<xsl:when test="@signed"><xsl:value-of select="@signed"/></xsl:when>
|
||||
<xsl:otherwise>true</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="bit0Exp">
|
||||
<!-- Values allowed: integer power of two corresponding to right-most bit, default of -39 (ECP default) -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="bit0Exp"><xsl:value-of select="bit0Exp"/></xsl:when>
|
||||
<xsl:when test="@bit0Exp"><xsl:value-of select="@bit0Exp"/></xsl:when>
|
||||
<xsl:otherwise>-39</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="labels">
|
||||
<!-- Values allowed: true if bits should be labeled, false if not (default)-->
|
||||
<xsl:choose>
|
||||
<xsl:when test="labels"><xsl:value-of select="labels"/></xsl:when>
|
||||
<xsl:when test="@labels"><xsl:value-of select="@labels"/></xsl:when>
|
||||
<xsl:otherwise>false</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:call-template name="component">
|
||||
<xsl:with-param name="class">register</xsl:with-param>
|
||||
<xsl:with-param name="parms">nBits:<xsl:value-of select="$nBits"/>,signed:<xsl:value-of select="$signed"/>,bit0Exp:<xsl:value-of select="$bit0Exp"/>,labels:<xsl:value-of select="$labels"/></xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
Loading…
Reference in a new issue