Add posts and old grade-calc
Fix small bugs >bad commit
This commit is contained in:
268
public/grade-calc/vanilla.js
Normal file
268
public/grade-calc/vanilla.js
Normal file
@@ -0,0 +1,268 @@
|
||||
(()=>{
|
||||
const cont = `
|
||||
<div class="about-container block">
|
||||
<h2>About</h2>
|
||||
Check out the <a href="https://github.com/lambdapaul/www/blob/master/public/grade-calc/README.md">README.md</a> file
|
||||
to learn more about the configuration structure.
|
||||
<h3>Usage</h3>
|
||||
<ol>
|
||||
<li>Either configure the calculator using the text box below or load one from the existing JSON files to
|
||||
generate one.</li>
|
||||
<li>Click <code>Generate</code>.</li>
|
||||
<li>Enter the input values.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="calculator-container block">
|
||||
</div>
|
||||
<div class="json-textarea block">
|
||||
<h2>Configuration</h2>
|
||||
<h3>Load config from file</h3>
|
||||
<ul>
|
||||
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/map2302.json')">MAP2302 - ODE I Fall 2019 (map2302.json)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eee3307c.json')">EEE3307C - Electronics I Spring 2021 (eee3307c.json)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eel4742c.json')">EEL4742C - Embedded Systems Spring 2021 (eel4742c.json)</a></li>
|
||||
<li><a href="javascript:void(0)" onclick="loadConfig('/grade-calc/config/eel4781.json')">EEL4781 - Computer Comm. Networks Spring 2021 (eel4781.json)</a></li>
|
||||
</ul>
|
||||
<div class="button-container">
|
||||
<button class="button" onclick="generate()">Generate →</button>
|
||||
</div>
|
||||
<textarea id="json" id="" rows="30"></textarea>
|
||||
|
||||
</div><span class="clear"></span>`;
|
||||
document.querySelector('.grade-calc').innerHTML = cont;
|
||||
})(); // eh
|
||||
|
||||
function generate() {
|
||||
let calcSection = document.querySelector(".calculator-container");
|
||||
calcSection.innerHTML = "";
|
||||
try {
|
||||
conf = JSON.parse(document.getElementById("json").value);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
calcSection.innerHTML = e;
|
||||
return;
|
||||
}
|
||||
let cb = (out) => {
|
||||
for (let o of out) {
|
||||
calcSection.appendChild(o);
|
||||
}
|
||||
}
|
||||
gc = new __GradeCalc(conf, cb);
|
||||
|
||||
calcSection.appendChild(gc.elemTotal);
|
||||
}
|
||||
|
||||
function loadConfig(filename) {
|
||||
var client = new XMLHttpRequest();
|
||||
client.open('GET', filename);
|
||||
client.onreadystatechange = function () {
|
||||
document.getElementById("json").value = (client.responseText);
|
||||
}
|
||||
client.send();
|
||||
}
|
||||
|
||||
class __GradeCalc {
|
||||
maxscore = 0;
|
||||
sections = [];
|
||||
inputSection = [];
|
||||
outputSection = [];
|
||||
fields = [];
|
||||
grades = [];
|
||||
ugrades = [];
|
||||
both = false;
|
||||
totalOutput = null;
|
||||
|
||||
constructor(config, outCallback) {
|
||||
this.totalOutput = document.createElement("div");
|
||||
let dConfig = JSON.parse(JSON.stringify(config)); // dirty clone
|
||||
let sanConfig = [];
|
||||
for (let conf of dConfig) {
|
||||
if (conf.percentage === undefined || conf.name === undefined)
|
||||
continue;
|
||||
if (conf.title === undefined)
|
||||
conf.title = conf.name[0].toUpperCase() + conf.name.slice(1);
|
||||
sanConfig.push(conf);
|
||||
}
|
||||
this.config = sanConfig;
|
||||
for (let [i, conf] of this.config.entries()) {
|
||||
this.maxscore += conf.percentage;
|
||||
|
||||
this.inputSection[i] = [];
|
||||
this.outputSection[i] = document.createElement("div");
|
||||
|
||||
if (conf.bothMethods) {
|
||||
this.both = true;
|
||||
}
|
||||
|
||||
this.sections[i] = (this.createSection(i));
|
||||
}
|
||||
|
||||
for (let [k, v] of this.fields.entries()) {
|
||||
for (let field of v) {
|
||||
this.addInputEventListener(k, field);
|
||||
}
|
||||
}
|
||||
|
||||
outCallback(this.sections);
|
||||
}
|
||||
|
||||
createSection(id) {
|
||||
let conf = this.config[id];
|
||||
|
||||
var section = document.createElement("div");
|
||||
section.classList.add(conf.name);
|
||||
|
||||
var heading = document.createElement("h2");
|
||||
heading.innerHTML = `${conf.title} (${conf.percentage}%)`;
|
||||
|
||||
section.appendChild(heading);
|
||||
|
||||
if (conf.info !== undefined)
|
||||
section.appendChild(document.createTextNode(conf.info));
|
||||
|
||||
this.fields[id] = [];
|
||||
if (conf.points !== undefined) {
|
||||
for (var i = 0; i < conf.points.length; i++) {
|
||||
section.appendChild(this.createInputSection(id, i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
section.appendChild(this.createInputSection(id, 0, true));
|
||||
}
|
||||
|
||||
|
||||
section.appendChild(this.outputSection[id]);
|
||||
return section;
|
||||
}
|
||||
|
||||
createInputSection(sectId, inputId, soleInput = false) {
|
||||
let conf = this.config[sectId];
|
||||
let inputSection = document.createElement("div");
|
||||
inputSection.classList.add("input-section");
|
||||
|
||||
let label = document.createElement("label");
|
||||
if (soleInput)
|
||||
label.innerHTML = `${conf.title} Score: `;
|
||||
else
|
||||
label.innerHTML = `${conf.title} ${inputId + 1} Score: `;
|
||||
|
||||
let field = document.createElement("input");
|
||||
field.classList.add(`input`);
|
||||
field.classList.add(`${conf.name}-score`);
|
||||
this.fields[sectId][inputId] = field;
|
||||
|
||||
let suffix = (soleInput) ? "%" : ` / ${conf.points[inputId]} pts`;
|
||||
|
||||
inputSection.appendChild(label);
|
||||
inputSection.appendChild(field);
|
||||
inputSection.appendChild(document.createTextNode(suffix));
|
||||
|
||||
this.inputSection[sectId][inputId] = inputSection;
|
||||
return inputSection;
|
||||
}
|
||||
|
||||
addInputEventListener(id, field, event = "keyup") {
|
||||
let conf = this.config[id];
|
||||
field.addEventListener(event, () => {
|
||||
if (conf.output !== undefined && conf.output)
|
||||
this.showSectionGrade(id);
|
||||
this.showTotalGrade();
|
||||
});
|
||||
}
|
||||
|
||||
calculateSectionGrade(id, unweighted = false) {
|
||||
let conf = this.config[id];
|
||||
let fields = this.fields[id];
|
||||
if (fields === undefined)
|
||||
return;
|
||||
if (conf.points === undefined) {
|
||||
return parseFloat(fields[0].value);
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
|
||||
if (unweighted) {
|
||||
let counter = 0;
|
||||
for (let [i, field] of fields.entries()) {
|
||||
let val = parseFloat(field.value);
|
||||
if (isNaN(val))
|
||||
continue;
|
||||
total += val / conf.points[i];
|
||||
counter++;
|
||||
}
|
||||
|
||||
return (total / counter * 100);
|
||||
}
|
||||
|
||||
total = fields.reduce((acc, cur) => {
|
||||
let c = parseFloat(cur.value);
|
||||
if (isNaN(c))
|
||||
return acc;
|
||||
return acc + parseFloat(c);
|
||||
}, 0);
|
||||
|
||||
let max_total = 0;
|
||||
for (let [i, field] of conf.points.entries()) {
|
||||
if (isNaN(parseFloat(fields[i].value)))
|
||||
continue;
|
||||
max_total += field;
|
||||
}
|
||||
|
||||
return (total / max_total * 100);
|
||||
}
|
||||
|
||||
showSectionGrade(id) {
|
||||
let conf = this.config[id];
|
||||
let grade = this.calculateSectionGrade(id);
|
||||
let ugrade = this.calculateSectionGrade(id, true);
|
||||
|
||||
|
||||
this.grades[id] = grade * parseFloat(conf.percentage) / 100;
|
||||
this.ugrades[id] = ugrade * parseFloat(conf.percentage) / 100;
|
||||
|
||||
grade = !isNaN(grade) ? grade.toFixed(2) : "...";
|
||||
ugrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
|
||||
if (conf.bothMethods) {
|
||||
this.outputSection[id].innerHTML
|
||||
= `Score (weighted): ${grade}%<br> Score (unweighted): ${ugrade}%`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.outputSection[id].innerHTML = `Score: ${grade}`;
|
||||
}
|
||||
|
||||
showTotalGrade() {
|
||||
for (let [k, conf] of this.config.entries()) {
|
||||
if (!conf.output) {
|
||||
this.grades[k] = this.calculateSectionGrade(k) * parseFloat(conf.percentage) / 100;
|
||||
this.ugrades[k] = this.calculateSectionGrade(k, true) * parseFloat(conf.percentage) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
let grade = this.grades.reduce((a, c) => {
|
||||
if (isNaN(c))
|
||||
return a;
|
||||
return a + c
|
||||
}, 0);
|
||||
let ugrade = this.ugrades.reduce((a, c) => {
|
||||
if (isNaN(c))
|
||||
return a;
|
||||
return a + c
|
||||
}, 0);
|
||||
|
||||
grade = !isNaN(grade) ? grade.toFixed(2) : "...";
|
||||
ugrade = !isNaN(ugrade) ? ugrade.toFixed(2) : "...";
|
||||
if (this.both) {
|
||||
this.totalOutput.innerHTML
|
||||
= `Total Score (weighted): ${grade}%<br> Total Score (unweighted): ${ugrade}%`;
|
||||
return;
|
||||
}
|
||||
|
||||
this.totalOutput.innerHTML = `Total Score: ${grade}%`;
|
||||
}
|
||||
|
||||
get elemTotal() {
|
||||
return this.totalOutput;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user