Difference between revisions of "Widget:MerlinProficiencyProgress"

From Coder Merlin
(Replaced content with "<noinclude> Runs the JavaScript for the progress HTML table. </noinclude> <includeonly> <script> var username = "<!--{$userName}-->".toLowerCase(); var sessionID = "<!--...")
Tag: Replaced
(3 intermediate revisions by the same user not shown)
Line 5: Line 5:
<includeonly>
<includeonly>
<script>
<script>
// Wait for the other scripts to be ready because we need jQuery
var username = "<!--{$userName}-->".toLowerCase();
window.addEventListener('load', function () {
var sessionID = "<!--{$sessionID}-->";
   
window.addEventListener('load', (event) => {
    /**
     merlinProficiencyProgress(username, sessionID);
    * Add a row to a table
    *
    * @param  {jQuery} $table The jQuery object for the table element
    * @param  {Array} cells An array of cells to add to the table
    * @param  {Object} attrs Any attributes to set on the row
    * @return {jQuery} The row jQuery object
    */
    function addRowToTable($table, cells, attrs = {}) {
        // Figure out tbody
        const $tbody = $table.find('tbody');
       
        // Create an empty row
        let $row = $(`<tr></tr>`);
 
        // Iterate over each cell
        for (let i = 0; i < cells.length; i++) {
            // Get the cell
            const cell = cells[i];
           
            let $cell = null;
           
            // Check if it should be a th or td
            if (cell.header) {
                $cell = $('<th scope="row"></th>');
            } else {
                $cell = $('<td></td>');
            }
           
            // Set any necessary attributes
            if (cell.attributes && (typeof cell.attributes == 'object')) {
                for (let [key, value] of Object.entries(cell.attributes)) {
                    // Combine into a string if needed
                    if (Array.isArray(value)) {
                        value = value.join(' ');
                    }
                   
                    // Set the attribute
                    $cell.attr(key, value);
                }
            }
           
            // Set the cell data
            $cell.html(cell.data);
           
            // Add to the cell to the row
            $row.append($cell);
        }
 
        // Add attributes to the row
        for (const [key, value] of Object.entries(attrs)) {
            $row.attr(key, value);
        }
       
        $tbody.append($row);
 
        return $row;
    }
 
    // Fetch and process the data
    async function getData() {
        // Staging or production
        let baseUrl = "https://" + (window.location.hostname == 'www.codermerlin.com' ? 'api-server.codermerlin.com' : 'api-server-stg.codermerlin.com');
 
        // Add the path
        const username = "<!--{$userName}-->".toLowerCase();
        const sessionId = "<!--{$sessionID}-->";
        const path = `/mission-manager/users/${username}/mastery-progress/programs`;
 
        // Development
        let json;
        if (window.location.hostname == "") {
        } else {
            // Request the data
            json = await $.ajax(baseUrl + path, {
                headers: {
                    username: username,
                    sessionId: sessionId
                },
                dataType: "json"
            });
        }
 
        let rawData = json;
 
        // Re-order everything by the sequence
        const orderKey = 'masteryProgramTopicSequence';
 
        rawData.rows.sort(function(a, b) {
            if (a[orderKey] > b[orderKey]) {
                return -1;
            } else if (a[orderKey] < b[orderKey]) {
                return 1;
            } else {
                return 0;
            }
        });
 
        let data = [];
 
        const stages = ['Inevident', 'Emerging', 'Developing', 'Proficient', 'Exemplary'];
 
        for (let i = 0; i < rawData.rows.length; i++) {
            // Get the row
            let row = rawData.rows[i];
 
            // Extract the necessary info
            const points = row['pointsEarned'];
            let dataRow = {};
 
            dataRow['topic'] = row['masteryProgramTopicName'];
            dataRow['data'] = [];
           
            // Iterate over the stages
            for (let j = 0; j < stages.length; j++) {
                // Build the key for the minimum points to get to a stage
                let stageKey = stages[j].toLowerCase() + 'MinimumPoints';
 
                // The minimum points
                const minPoints = row[stageKey];
 
                // Calculate the percentage complete
                let pct = points / minPoints;
 
                // If the last stage isn't complete, the next one can't be either
                if (j > 0 && dataRow['data'][j - 1]['pct'] < 1.0) {
                    pct = 0.0;
                }
 
                let formattedPct = (pct > 0) ? Math.round(pct * 100) + '%' : '';
 
                dataRow['data'].push({
                    date: (points >= minPoints) ? 'Passed' : formattedPct,
                    pct: pct
                });
            }
 
            data.push(dataRow);
        }
 
 
        return data;
     }
 
    // Wait for the DOM
    $(function () {
        // Get a table instance
        let $table = $('table#mastery-progress-table');
       
        // Fetch the data
        let $rows = [];
        getData().then(async function (data) {
            // Iterate over each topic
            for (let i = 0; i < data.length; i++) {
                let topic = data[i];
 
                let cells = [];
 
                // Set the first row to the title
                cells.push({
                    header: true,
                    data: topic.topic,
                    attributes: {
                        style: `background-color: ${topic.data[0].date ? 'lightgreen' : 'lightgray'};`
                    }
                });
 
                // Iterate over the rest of the data
                for (let j = 0; j < topic.data.length; j++) {
                    let stage = topic.data[j];
 
                    // Calculate the RGB green value
                    const m = 15;
                    const greenColor = ((j + 1) * m) + (240 - (m * topic.data.length));
 
                    // Get the percentage rounded to 2 decimal places
                    //  4 because a percentage is a decimal anyways
                    const pct = parseFloat(stage.pct).toFixed(4);
 
                    // Background color for the cell
                    let backgroundColor = `rgb(0, ${greenColor}, 0)`;
 
                    // If not complete, the background should be blue
                    if (pct < 1.0) {
                        backgroundColor = "rgb(0, 167, 225)";
                    }
                   
                    // Append
                    cells.push({
                        header: false,
                        data: stage.date,
                        attributes: {
                            //style: `background-color: ${(stage.date) ? `rgb(0, ${greenColor}, 0)` : 'lightgray'}; text-align: center;`,
                            style: `background-image: linear-gradient(to right, ${backgroundColor} ${pct * 100}%, lightgray 0%); text-align: center;`
                        }
                    });
                }
 
                // Add to the table
                let $row = addRowToTable($table, cells, {style: 'opacity: 0.0;'});
 
                $rows.push($row);
            }
 
            for (let i = 0; i < $rows.length; i++) {
                let $row = $rows[i];
 
                // Animate
                const animationTime = 200;
 
                $row.animate({opacity: 1.0}, animationTime);
 
                // Wait for half of the animation
                await (new Promise(resolve => setTimeout(resolve, animationTime / 5)));
            }
        });
    });
});
});
</script>
</script>
</includeonly>
</includeonly>

Revision as of 13:41, 1 December 2021

Runs the JavaScript for the progress HTML table.