GPA meter

A user script to show GPA on aims page

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         GPA meter
// @namespace    https://greasyfork.org/en/users/674736-jatin-sharma
// @description  A user script to show GPA on aims page
// @include      https://aims.iith.ac.in/aims/courseReg/myCrsHistoryPage*
// @author       Jatin Sharma ([email protected])
// @version      0.4
// @grant        none
// ==/UserScript==

/* jshint esversion: 6 */
/* global $ */

(function () {
    'use strict';

    let exclude_list = [
        'Minor Core',
        'Honors Core',
        'Honours project',
        'Honours coursework',
        'FCC',
        'Additional',
        'Audit',
    ];

    const grade_values = {
        'A+': 10,
        'A' : 10,
        'A-': 9,
        'B' : 8,
        'B-': 7,
        'C' : 6,
        'C-': 5,
        'D' : 4,
        'FR': 0,
        'FS': 0
    };
    // console.log('Student ID: ', studentId);

    let append_checkbox = (parent, is_checked) => {
        parent.append('<input style="float:right" class="cgpa-cal-check" type="checkbox" ' + (is_checked ? 'checked' : '') + ' />');
    };

    let add_checkboxes = () => {
        let courses_checked = new Set();
        $(".cgpa-cal-check").remove();
        let elems = $(".hierarchyLi.dataLi").not(".hierarchyHdr, .hierarchySubHdr");
        elems.each((i, el) => {
            let course_id = el.children[0].textContent.trim();
            let type = el.children[4].textContent.trim();
            let grade = el.children[7].textContent.trim();
            let is_checked = !(courses_checked.has(course_id) || exclude_list.includes(type) || grade == "" || grade == "I");
            if (is_checked) courses_checked.add(course_id);
            append_checkbox($(el.children[0]), is_checked);
        });
    }

    let add_courseCategoryDropdown = () => {
        let courseCategoryDropDown = `
        <select class="catSel" style="width: auto; background: aliceblue; border-radius: 5px">
            <option value="Additional">Additional</option>
            <option value="Audit">Audit</option>
            <option value="Liberal Arts Elective">Liberal Arts Elective</option>
            <option value="Departmental Core Laboratory">Departmental Core Laboratory</option>
            <option value="Departmental Elective">Departmental Elective</option>
            <option value="Departmental Core Theory">Departmental Core Theory</option>
            <option value="Basic Sciences">Basic Sciences</option>
            <option value="Professional Ethics">Professional Ethics</option>
            <option value="Seminar">Seminar</option>
            <option value="Thesis">Thesis</option>
            <option value="Basic Engineering Skills">Basic Engineering Skills</option>
            <option value="Free Elective">Free Elective</option>
            <option value="FCC">FCC</option>
            <option value="Creative Arts">Creative Arts</option>
        </select>`;

        let elems = $(".hierarchyLi.dataLi").not(".hierarchyHdr, .hierarchySubHdr").children('.col5');
        $('.col5').css({ "width": "220px" });
        $('.col1').css({ "width": "75px" });
        $('.col4').css({ "width": "80px" });
        elems.each((i, el) => {
            let origCategory = el.innerText.trim();
            el.dataset.origCategory = origCategory;
            el.innerHTML = '';
            el.insertAdjacentHTML('afterbegin', courseCategoryDropDown);
            $(el.children[0]).val(origCategory).change();
        });
        $('.catSel').on('change', (e) => {
            let origCategory = e.target.parentElement.dataset.origCategory;
            if (e.target.value === origCategory) {
                e.target.style.backgroundColor = "aliceblue";
                e.target.removeAttribute('title');
            } else {
                e.target.style.backgroundColor = "mistyrose";
                e.target.title = `Orig: ${origCategory}`;
            }

        });
        $('.catSel').tooltip();
        $('.catSel').tooltip('option', 'track', true);
        $('#courseHistoryUI .col8').attr('contenteditable','true');
    };


    let show_total_gpa = () => {
        $('#gpa_button').val('Calculating');
        $('#gpa_bar').remove();
        let cg_total_grades = 0;
        let cg_total_credits = 0;
        let total_credits = 0;

        if ($(".cgpa-cal-check").length == 0) {
            add_checkboxes();
            add_courseCategoryDropdown();
        }
        let elems = $('.cgpa-cal-check:checked').parent().parent()

        let categoryMap = {
            'Departmental Core Theory': 0,
            'Departmental Elective': 0,
            'Free Elective': 0,
            'Liberal Arts Elective': 0,
            'Creative Arts': 0,
            'Basic Sciences': 0,
            'Basic Engineering Skills': 0,
            'Additional': 0
        };


        let deptMap = {};

        elems.each((i, el) => {
            let type = el.children[4].children[0].value;

            let course_id = el.children[0].textContent.trim();
            let grade = el.children[7].textContent.trim();
            let credits = Number(el.children[2].textContent.trim());
            total_credits += credits;
            categoryMap[type] = credits + (categoryMap[type] || 0);

            let deptId = course_id.slice(0, 2);
            deptMap[deptId] = credits + (deptMap[deptId] || 0);

            if (grade in grade_values) {
                grade = grade_values[grade];
                cg_total_grades += credits * grade;
                cg_total_credits += credits;
            }
        });
        let gpa = (cg_total_grades / cg_total_credits).toFixed(2);

        console.log(categoryMap);
        console.log(deptMap);

        let generateRow = (title, val) => `<li class="hierarchyLi">
            <span class="" style="margin-left: 100px; width:300px">${title}</span>
            <span class="" style="margin-left: 400px;">${val}</span>
        </li>`;

        $('#gpa_button').val('Show Gpa');
        $('#courseHistoryUI').before(
            `<ul id="gpa_bar" class="subCnt">
                <li class="hierarchyLi hierarchyHdr changeHdrCls">TOTAL GPA</li>
                ${generateRow('Total GPA of graded courses', gpa)}
                ${Object.entries(categoryMap).map((entry) => generateRow(entry[0], entry[1])).join('\n')}
                ${generateRow('Total credits', total_credits)}
            </ul>`);
    }

    let get_course_changes_csv = () => `Course Code,Course Name,Credits,From Course Type,To Course Type,Semester\n`+
                $('.catSel')
                .filter( (i, el) => el.value !== el.parentElement.dataset.origCategory )
                .map((i, el) => ``+
                    `${el.parentElement.parentElement.children[0].textContent.trim()},`+
                    `${el.parentElement.parentElement.children[1].textContent.trim()},`+
                    `${Number(el.parentElement.parentElement.children[2].textContent.trim())},`+
                    `${el.parentElement.dataset.origCategory},`+
                    `${el.value},`+
                    `${el.parentElement.parentElement.parentElement.children[0].children[0].textContent.trim()}`)
                .get().reverse().join('\n');

    $("#studentCourseSearch").before(
        `<input id="getcoursechanges_button" class="btn" title="Copy CSV of Course Type Changes to clipboard"`+
        `value="Copy Changes" style="padding: 5px 7px; margin-right:10px;" type="button"></input>`
    );
    $('#getcoursechanges_button').click(() => {
        let text = get_course_changes_csv();
        console.log(text);
        navigator.clipboard.writeText(text).then(function() {
            console.log('CSV Copied to clipboard');
        }, function(err) {
            console.error('Async: Could not copy text: ', err);
            alert('Could not copy to clipboard. Please find the CSV in your browser console');
        });
    });


    $("#studentCourseSearch").before(
        '<input id="gpa_button" class="btn" value="Show Gpa" style="padding: 5px 7px; margin-right:10px;" type="button"></input>'
    );
    $('#gpa_button').click(show_total_gpa);
//    console.log('All assets are loaded')
})();