Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <title>Weighted Average Decision Matrix (WADM)</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" />

<div class="container">
    <div class="responsive-table">
        <table>
            <caption>Weighted Average Decision Matrix (WADM)</caption>
            <tbody data-wadm="table-body">
                <tr data-wadm="heading-row">
                    <th data-wadm="factor">Factors</th>
                    <th data-wadm="weight">Weight</th>
                    <th data-wadm="option-1" contenteditable="true">Option Name</th>
                    <th data-wadm="option-2" contenteditable="true">Option Name</th>
                </tr>
            </tbody>
        </table>
    </div>
    <div data-wadm="buttons" class="buttons flex">
        <button class="btn btn--success" data-wadm="add-factor">Add factor</button>
        <button class="btn btn--danger" data-wadm="remove-factor">Remove factor</button>
        <button class="btn btn--success" data-wadm="add-options">Add option</button>
        <button class="btn btn--danger" data-wadm="remove-options">Remove option</button>
        <button class="btn btn--primary" data-wadm="calculate">Calculate</button>
    </div>

    <h2 class="text-center">FAQs</h2>
    <!-- ACCORDION -->
    <div data-accordion="accordions">
        <div class="accordion">
            <div class="accordion__heading">
                <h2 id="wadm-work">How does WADM work?</h2>
                <i class="fas fa-plus accordion__icon" data-accordion-icon="1"></i>
            </div>
            <div class="accordion__body js-accordion__body--active" data-accordion-body="1">
                <ol>
                    <li>
                        <p>A list of factors</p>
                        <p>These are the factors that you find most important for you to decide which option you want to select.</p>
                    </li>
                    <li>
                        <p>A set of weights based on importance for the factors. </p>
                        <p>The weight is what defines the factor priority. Use number 1 through 10 where 1 is the least important, and 10 the most important.</p>
                    </li>
                    <li>
                        <p>A set of alternatives(at least two). The options you want to compare.</p>
                    </li>
                </ol>
            </div>
        </div>
        <div class="accordion">
            <div class="accordion__heading">
                <h2 id="use-wadm">How can I use WADM?</h2>
                <i class="fas fa-plus accordion__icon" data-accordion-icon="2"></i>
            </div>
            <div class="accordion__body" data-accordion-body="2">
                <ol>
                    <li>
                        <p>Add desire number of option by clicking add option button.</p>
                    </li>
                    <li>
                        <p>Add desire number of factors by clicking add factor button.</p>
                    </li>
                    <li>
                        <p>Click each cell to change its name or value. e.g. Factor Name to Price and weight 0 to 5.</p>
                    </li>
                    <li>
                        <p>Finally click the calculate button to see the result.</p>
                    </li>
                </ol>
            </div>
        </div>
    </div>

    <h2 class="text-center">Static example</h2>
    <p class="example">Imagine you want to decide what technology is best for you to learn. You have two options React or Vue. You have little current knowledge. You want to learn the easiest technology within 1 month with a supportive online community.</p>
    <div class="responsive-table">
        <table>
            <caption>Weighted Average Decision Matrix (WADM)</caption>
            <tbody>
                <tr>
                    <th>Factors</th>
                    <th>Weight</th>
                    <th>React</th>
                    <th>Angular</th>
                </tr>
                <tr>
                    <td>Community</td>
                    <td>6</td>
                    <td>6 X 5 = 30</span></td>
                    <td>6 X 4 = 24</span></td>
                </tr>
                <tr>
                    <td>Time</td>
                    <td>7</td>
                    <td>7 X 5 = 35</td>
                    <td>7 X 5 = 35</td>
                </tr>
                <tr>
                    <td>Easy</td>
                    <td>8</td>
                    <td>8 X 7 = 56</td>
                    <td>8 X 5 = 40</td>
                </tr>
                <tr>
                    <td>Current Knowledge</td>
                    <td>3</td>
                    <td>3 X 1 = 3</td>
                    <td>3 X 1 = 3</td>
                </tr>
                <tr>
                    <td>SUM</td>
                    <td>-</td>
                    <td class="winner">124</td>
                    <td>102</td>
                </tr>
            </tbody>
        </table>
    </div>
    <p class="mb-5"></p>
</div>
              
            
!

CSS

              
                :root {
    --white: hsl(0, 0%, 100%);
    --black: hsl(0, 0%, 0%);
    --gary-light: hsl(0, 0%, 95%);
    --yellow: hsl(60, 100%, 50%);
    --primary: hsl(211, 100%, 43%);
    --success: hsl(152, 69%, 27%);
    --danger: hsl(354, 61%, 45%);
    --primary-hover: hsl(211, 100%, 36%);
    --success-hover: hsl(152, 69%, 20%);
    --danger-hover: hsl(354, 61%, 38%);
}

*,
*::after,
*::before {
    box-sizing: border-box;
}

body {
    line-height: 1.5;
    font-size: 1.125rem;
}

h1,
h2,
h3 {
    line-height: 1;
}

.container {
    width: 90%;
    max-width: 1600px;
    margin-inline: auto;
}

.responsive-table {
    overflow-x: auto;
    margin-bottom: 1rem;
}

table,
td,
th {
    border: 1px solid;
}

table {
    border-collapse: collapse;
    width: 100%;
}

th,
td {
    text-align: center;
    font-size: 1rem;
}

td {
    padding: 0.625rem;
}

tr:nth-child(even) {
    background-color: var(--gary-light);
}

.btn {
    color: var(--white);
    border: none;
    border-radius: 0.25rem;
    cursor: pointer;
    display: inline-block;
    text-align: center;
    text-decoration: none;
    vertical-align: middle;
    padding: 0.375rem 0.75rem;
    transition: background-color 0.15s ease-in-out;

    &-outline {
        background-color: transparent;
        border: 1px solid black;
        color: var(--black);
    }

    &--primary {
        background-color: var(--primary);
        &:hover {
            background-color: var(--primary-hover);
        }
    }

    &--danger {
        background-color: var(--danger);
        &:hover {
            background-color: var(--danger-hover);
        }
    }

    &--success {
        background-color: var(--success);
        &:hover {
            background-color: var(--success-hover);
        }
    }
}

.buttons {
    max-width: 70%;
    margin-inline: auto;
    text-align: center;
}

.text-center {
    text-align: center;
}

.winner {
    background-color: var(--yellow);
}

.flex {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    row-gap: var(--row-gap, 0);
    -moz-column-gap: var(--col-gap, 0);
    column-gap: var(--col-gap, 0);
    --row-gap: 1rem;
}

@media only screen and (min-width: 37.5em) {
    .flex {
        flex-direction: row;
        --col-gap: 2%;
    }

    .flex > * {
        flex-basis: 49%;
    }
}

@media only screen and (min-width: 75em) {
    .flex > * {
        flex-basis: 32%;
    }
}

// ACCORDION
.accordion {
    padding: 10px;
    background-color: var(--gary-light);
    color: var(--black);
    margin-block: 10px;
    border-radius: 5px;

    &__heading {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 10px;

        & h2 {
            font-size: 1.2rem;
        }
    }

    &__icon {
        cursor: pointer;
        color: var(--black);
        font-size: 20px;
    }

    &__body {
        padding: 10px 20px;
        animation: accordion-animation 0.5s ease-in-out;
        display: none;
    }
}

.js-accordion__body--active {
    display: block;
}

.mb-5 {
    margin-bottom: 5rem;
}

.example {
    max-width: 600px;
    text-align: center;
    margin-inline: auto;
}

              
            
!

JS

              
                // WADM GLOBAL VARIABLES

interface WADM {
    readonly button: HTMLButtonElement;
    readonly table_body: HTMLElement;
    readonly heading_row: HTMLTableRowElement;
    criteriaNumber: number;
}
const WADM: WADM = {
    button: document.querySelector(
        '[data-wadm="buttons"]'
    )! as HTMLButtonElement,
    table_body: document.querySelector(
        '[data-wadm="table-body"]'
    )! as HTMLElement,
    heading_row: document.querySelector(
        '[data-wadm="heading-row"]'
    )! as HTMLTableRowElement,
    criteriaNumber: 1
};

interface WADM_WEIGHT_AND_OPTIONS {
    [key: string]: NodeListOf<HTMLTableColElement>;
}
const WADM_WEIGHT_AND_OPTIONS: WADM_WEIGHT_AND_OPTIONS = {};
const OPTION_SUM: number[] = [];

// WADM GLOBAL Event Listener
WADM.button.addEventListener("click", (e: Event) => {
    const target = e.target as HTMLElement;
    const button_data = target.dataset.wadm;

    if (button_data === "calculate") {
        calculate();
    } else if (button_data === "add-options") {
        addOption();
    } else if (button_data === "remove-options") {
        removeOption();
    } else if (button_data === "add-factor") {
        addFactor();
    } else if (button_data === "remove-factor") {
        removeFactor();
    }
});

// WADM GLOBAL FUNCTIONS
function addOption() {
    const option_data = getLastChild(WADM.heading_row);
    const option_number = Number(option_data.split("-")[1]);
    WADM.heading_row.insertAdjacentHTML(
        "beforeend",
        `<th contenteditable="true" data-wadm="option-${
            option_number + 1
        }">Option name</th>`
    );
}

function removeOption() {
    if (getLastChild(WADM.heading_row) === "option-2") {
        alert("You need at least two options to use WADM");
        return;
    }
    removeLastChild(WADM.heading_row);
}

function addFactor() {
    let total_column = getHeadingRowChildren();

    let row_data = "";
    for (const column of total_column) {
        const WADMValue = column.getAttribute("data-wadm");

        const dataAttributeValue =
            WADMValue === "factor"
                ? `${WADMValue}-${WADM.criteriaNumber}`
                : `${WADMValue}-factor-${WADM.criteriaNumber}`;
        const columnValue = WADMValue === "factor" ? "Factor Name" : 0;

        row_data += `<td contenteditable="true" data-wadm="${dataAttributeValue}">${columnValue}</td>`;
    }
    WADM.criteriaNumber += 1;
    WADM.table_body.insertAdjacentHTML("beforeend", `<tr>${row_data}</tr>`);
}

function removeFactor() {
    WADM.criteriaNumber = WADM.criteriaNumber > 1 ? WADM.criteriaNumber-- : 1;
    if (isAllowed("There is no factor to remove.")) {
        removeLastChild(WADM.table_body);
    }
}

function isAllowed(message: string) {
    const IsHeadingRow = getLastChild(WADM.table_body);
    if (IsHeadingRow) {
        alert(message);
        return false;
    }
    return true;
}

function calculate() {
    if (isAllowed("You must add a factor to calculate the result")) {
        selectWeightAndOptionEl();
        updateUIAndOptionSum();
        renderCalculation();
        disableAllButton();
        setTimeout(() => {
            alert("You need to refresh the page to use again");
        }, 3000);
    }
}

function selectWeightAndOptionEl() {
    const weightFactors = document.querySelectorAll(
        '[data-wadm^="weight-factor"]'
    ) as NodeListOf<HTMLTableColElement>;
    addWeightAndOption(weightFactors, "weight");

    let totalOptions = getHeadingRowChildren().length - 2;
    while (totalOptions > 0) {
        const wadm_option = document.querySelectorAll(
            `[data-wadm^='option-${totalOptions}-factor']`
        ) as NodeListOf<HTMLTableColElement>;
        addWeightAndOption(wadm_option, "option", totalOptions);
        totalOptions--;
    }
}

function updateUIAndOptionSum() {
    const optionsLength = Object.keys(WADM_WEIGHT_AND_OPTIONS).length;
    let optionNumber = 1;
    while (optionNumber < optionsLength) {
        updateOptionUI(
            WADM_WEIGHT_AND_OPTIONS[`option-${optionNumber}-factor`],
            optionNumber
        );
        OPTION_SUM.push(calEachOptionSum(`option-${optionNumber}-sum`));
        optionNumber++;
    }
}

function addWeightAndOption(
    wadm_option: NodeListOf<HTMLTableColElement>,
    colName: string,
    factorNumber?: number
): void {
    let key = `${colName}-${factorNumber}-factor`;
    if (colName === "weight") {
        key = `${colName}-factor`;
    }
    for (const _ in wadm_option) {
        WADM_WEIGHT_AND_OPTIONS[key] = wadm_option;
    }
}

function updateOptionUI(
    option: NodeListOf<HTMLTableColElement>,
    optionNumber: number
) {
    const weight = WADM_WEIGHT_AND_OPTIONS["weight-factor"];
    const weightLength = weight.length;

    let factorNumber = 0;
    while (factorNumber < weightLength) {
        const weightValue = weight[factorNumber].textContent;
        const factorValue = option[factorNumber].textContent;
        option[
            factorNumber
        ].innerHTML = `${weightValue} X ${factorValue} = <span class="option-${optionNumber}-sum">${
            Number(weightValue) * Number(factorValue)
        }</span>`;
        factorNumber += 1;
    }
}

function calEachOptionSum(optionEl: string) {
    const option = document.querySelectorAll(`.${optionEl}`);
    let sum = 0;
    for (const key of option) {
        sum += Number(key.textContent);
    }
    return sum;
}

function renderCalculation() {
    let optionsData = "";

    OPTION_SUM.forEach((element, index) => {
        const maxNumber = Math.max(...OPTION_SUM);
        const maxNumberIndex = OPTION_SUM.findIndex(
            (number) => number === maxNumber
        );
        if (index == maxNumberIndex) {
            optionsData += `<td class="winner" data-wadm="option-${
                index + 1
            }-sum">${element}</td>`;
            return;
        }
        optionsData += `<td data-wadm="option-${
            index + 1
        }-sum">${element}</td>`;
    });
    //  Use class="sum" in <tr> if you want to highlight the entire row and uncomment tr.sum css rule.
    const rowData = `<tr><td data-wadm="sum">SUM</td><td data-wadm="weight-sum">-</td>${optionsData}</tr>`;
    WADM.table_body.insertAdjacentHTML("beforeend", rowData);
}

function getHeadingRowChildren(): HTMLCollection {
    return WADM.heading_row.children!;
}

function getLastChild(parentElement: HTMLElement): string {
    return parentElement.lastElementChild!.getAttribute("data-wadm")!;
}

function removeLastChild(parentElement: HTMLElement): void {
    parentElement.lastElementChild!.remove();
}

function disableAllButton() {
    const actionButtons = document.querySelectorAll(
        ".btn"
    )! as NodeListOf<HTMLButtonElement>;
    for (const button of actionButtons) {
        button.disabled = true;
    }
}

// ACCORDION

const accParEl = document.querySelector(
    '[data-accordion="accordions"]'
) as HTMLDivElement;
const accBodyEls = document.querySelectorAll(
    "[data-accordion-body]"
) as NodeListOf<HTMLDivElement>;

accParEl?.addEventListener("click", (event: Event) => {
    const target = event.target as HTMLElement;
    target.getAttribute("data-accordion-icon");
    if (target.hasAttribute("data-accordion-icon")) {
        const iconValue = target.dataset.accordionIcon;
        let initIconValue: number = 1;
        for (const accBodyEl of accBodyEls) {
            const iconEl = document.querySelector(
                `[data-accordion-icon='${initIconValue}']`
            )!;
            const bodyValue = accBodyEl.dataset.accordionBody;
            const bodyEl = document.querySelector(
                `[data-accordion-body='${bodyValue}']`
            );

            if (iconValue === bodyValue) {
                bodyEl?.classList.toggle("js-accordion__body--active");
                iconEl.classList.replace("fa-plus", "fa-minus");
            } else {
                bodyEl?.classList.remove("js-accordion__body--active");
                iconEl.classList.replace("fa-minus", "fa-plus");
            }
            initIconValue++;
        }
    }
});

              
            
!
999px

Console