JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

Inheritance type: 
<button class='type_btn auto_bg' data-type='auto'>Tetrasomic</button>
<button class='type_btn allo_bg' data-type='allo'>Bisomic</button>

<div id='tetra_container'>
    <div id='p1'>[parent 1 dropdowns here]</div>
    <div id='p2'>[parent 2 dropdowns here]</div>
    <div id='custom'></div>
    <div id='table'>[table here]</div>
</div>
<hr>

CSS

input[type='text'] {
    width: 30px;
}

.type_btn {
    padding: 5px 10px;
    border: none;
    border-radius: 5px;
    margin: 5px 5px;
}
.type_btn:hover {
    cursor: pointer;
}

#tetra_container {
    padding: 10px;
    margin: 10px auto;
    border-radius: 5px;
}
.auto_bg {
    background-color: lavender;
}
.allo_bg {
    background-color: peachpuff;
}

table {
    border-collapse: collapse;
    width: 100%;
    margin: 10px auto;
}
table td {
    padding: 5px;
    text-align: center;
    border: 1px solid grey;
    background-color: #fff;
}
.td_empty {
    border: none;
    background-color: transparent;
}
.td_mother {
    background-color: pink;
}
.td_father {
    background-color: skyblue;
}

JavaScript

class TetraPunnett {

    constructor(type = "auto"){
        this.alleles = [1,2,3,4]; // default choices
        this.p1 = [];
        this.p2 = [];
        this.createDropdowns(1);
        this.createDropdowns(2);
        this.createCustomFields();
        this.setType(type);
    }
    
    // Tetrasomic or bisomic inheritance?
    // generateTable() will work in different way.
    setType(t){
        this.type = t;
        this.dimension = 6;
        this.alternates = [
            [1,2,3],
            [1,2,4],
            [1,4,5],
            [1,3,4],
            [1,3,5],
            [3,4,5]
        ];
        if(t == "allo"){
            this.dimension = 4;
            this.alternates = [
                [1,2],
                [1,3]
            ];
        }
        // Change background colour.
        $("#tetra_container").removeClass().addClass(t + "_bg");
        // Re-generate table.
        this.generateTable();
    }
    
    // Make 8 input fields for alleles.
    createCustomFields(){
        let html = "Enter between 2 and 8 custom alleles:<br>";
        for(let i = 1; i <= 8; i++){
            html += "<input type='text' id='custom_" + i + "'>";
        }
        html += "<button id='custom_btn'>Use</button>";
        $("#custom").html(html);
    }
    
    // Take inputs, set as available alleles.
    enterAlleles(){
        this.alleles = [];
        for(let i = 1; i <= 8; i++){
            let val = $("#custom_" + i).val();
            if(val != "" && !this.alleles.includes(val)){
                this.alleles.push(val);
            }
        }
        if(this.alleles.length < 2){
           throw "Must have at least 2 different alleles to use.";
        }
        this.createDropdowns(1);
        this.createDropdowns(2);
        this.test();
        this.generateTable();
    }
    
    // 4 selects per parent, with all allele options.
    createDropdowns(parent){
        let options = "",
            selects = "";
            
        this["p" +...