From 13589a4b02c2461e439424bde5a3ed91fcc77831 Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 09:21:24 +0800 Subject: [PATCH 1/6] Calculate cumulative gpa, adds optional parameter creditHour to Course class Signed-off-by: Suhas Hariharan --- src/js/models/Course.js | 15 ++++++- src/js/saspowerschoolff.js | 81 +++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/src/js/models/Course.js b/src/js/models/Course.js index e90e3054..66e78bb7 100644 --- a/src/js/models/Course.js +++ b/src/js/models/Course.js @@ -28,6 +28,7 @@ export default class Course { #finalPercent; #link; #assignments; + #creditHour; /** * Create new course instance @@ -37,19 +38,25 @@ export default class Course { * @param {String} [grade] current grade for the course * @param {Number?} [finalPercent] current final percent of the course * @param {Assignment[]} [assignments] number of missing assignments + * @param {Number?} [creditHour] number of credit hours this course counts for, optional */ - constructor (name, link, grade, finalPercent, assignments) { + constructor (name, link, grade, finalPercent, assignments, creditHour) { this.#name = name; this.#link = link; this.#grade = grade; this.#finalPercent = finalPercent; this.#assignments = assignments; + this.#creditHour = creditHour; } get name () { return this.#name; } + get creditHour () { + return this.#creditHour; + } + get link () { return this.#link; } @@ -62,6 +69,10 @@ export default class Course { this.#grade = g; } + set creditHour (c) { + this.#creditHour = c; + } + get finalPercent () { return this.#finalPercent; } @@ -77,4 +88,4 @@ export default class Course { set assignments (assignments) { this.#assignments = assignments; } -} +} \ No newline at end of file diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index 8c186e21..40d6a1b5 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -2,6 +2,8 @@ * * @copyright Copyright (c) 2018-2020 Gary Kim * + * @copyright Copyright (c) 2020 Suhas Hariharan + * * @author Gary Kim * * @license GNU AGPL version 3 only @@ -128,6 +130,7 @@ function main_page () { } } $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Current Semester GPA (${second_semester ? 'S2' : 'S1'}): ${calculate_gpa(courses)}`); + if (second_semester) { fetch("https://powerschool.sas.edu.sg/guardian/termgrades.html") .then((response) => { @@ -150,6 +153,8 @@ function main_page () { $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Last Semester GPA (S1): ${calculate_gpa(courses_first_semester)}`); } }); + $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(``); + $("#calculateCumulative").click(show_cumulative_gpa); } // Hypo Grade Calculator const HypoGradesDiv = document.createElement('div'); @@ -162,6 +167,12 @@ function main_page () { }, }).$mount(".hypo-grade-div-fixed"); } +function show_cumulative_gpa () { + $("#calculateCumulative").hide(); + calculate_cumulative_gpa().then(cumulative_gpa => { + $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Cumulative GPA(Completed Semesters): ${cumulative_gpa.toFixed(2)}`); + }); +} function class_page () { // Show final percent const number = extractFinalPercent($("table.linkDescList").html()); @@ -188,6 +199,74 @@ function login_page () { }); } +function calculate_cumulative_gpa () { + const list_of_gpas = []; + const all_courses = []; + const credit_hour_list = []; + let element_list = []; + const fetches = []; + // Fetches grade history page + const gpas = fetch("https://powerschool.sas.edu.sg/guardian/termgrades.html") + .then(response => response.text()) + .then(data => { + const el = document.createElement("html"); + el.innerHTML = data; + const tabs = el.getElementsByClassName("tabs")[0].getElementsByTagName("li"); + for (let i = 0; i < tabs.length; i++) { + // Iterates through semesters and adds each list of courses to all_courses list + fetches.push( + fetch(tabs[i].getElementsByTagName("a")[0].href) + .then(res => res.text()) + .then(function (data2) { + let courses = []; + const semester = document.createElement("html"); + semester.innerHTML = data2; + element_list = semester.getElementsByClassName("box-round")[0].getElementsByTagName("table")[0]; + element_list = element_list.getElementsByTagName("tbody")[0].getElementsByTagName("tr"); + for (let t = 2; t < element_list.length; t++) { + if (element_list[t].innerText.trim() === ("S2")) { + all_courses.push(courses); + courses = []; + } + if (element_list[t].getElementsByTagName("th").length > 0) { + continue; + } else { + const $prev_course = element_list[t]; + // Creates course object with each course from grade history page + const course = new Course($prev_course.getElementsByTagName("td")[0].textContent.trim(), "", + $prev_course.getElementsByTagName("td")[1].textContent.trim(), 0, "", parseFloat($prev_course.getElementsByTagName("td")[4].innerText)); + + courses.push(course); + } + } + all_courses.push(courses); + })); + } + // Calculates cumulative GPA based on credit hours per semester and gpa for each semester. + const cumulative_gpa = Promise.all(fetches).then(function () { + let total_count = 0; + let total_gpa = 0; + for (let i = 0; i < all_courses.length; i++) { + let count = 0; + list_of_gpas.push(calculate_gpa(all_courses[i])); + for (let t = 0; t < all_courses[i].length; t++) { + count += all_courses[i][t].creditHour; + } + // Adds all credit hours to overall credit hour count + total_count += count; + // Adds each amount of credit hours per semester to list + credit_hour_list.push(count); + } + for (let i = 0; i < all_courses.length; i++) { + total_gpa += ((credit_hour_list[i] / total_count) * list_of_gpas[i]); + } + return (total_gpa); + }); + return cumulative_gpa; + }); + return gpas; +} + function html2node (html_string) { return html2nodelist(html_string)[0]; } @@ -195,4 +274,4 @@ function html2nodelist (html_string) { const temp = document.createElement('template'); temp.innerHTML = html_string; return temp.content.childNodes; -} +} \ No newline at end of file From 73804230f65e96542ef8676741ea04fff39ab04b Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 09:28:14 +0800 Subject: [PATCH 2/6] fixed eslint errors Signed-off-by: Suhas Hariharan --- src/js/models/Course.js | 2 +- src/js/saspowerschoolff.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/models/Course.js b/src/js/models/Course.js index 66e78bb7..10e70ed5 100644 --- a/src/js/models/Course.js +++ b/src/js/models/Course.js @@ -88,4 +88,4 @@ export default class Course { set assignments (assignments) { this.#assignments = assignments; } -} \ No newline at end of file +} diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index 40d6a1b5..e418a434 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -274,4 +274,4 @@ function html2nodelist (html_string) { const temp = document.createElement('template'); temp.innerHTML = html_string; return temp.content.childNodes; -} \ No newline at end of file +} From 207f7b353886f857b6f403b239c7d7448534a953 Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 12:00:42 +0800 Subject: [PATCH 3/6] Cumulative GPA now calculates curent semester as well Signed-off-by: Suhas Hariharan --- src/js/saspowerschoolff.js | 41 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index e418a434..0ca610f2 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -72,6 +72,15 @@ function analytics_message (action_input) { const href = window.location.href.split("?")[0]; browser.runtime.sendMessage({ action: "analytics_send", args: { url: href, action: action_input } }); } +function calculate_credit_hours (text) { + if (text.substr(0, 2) === "IS") { + return 0.25; + } else if (text.includes("A-B")) { + return 1; + } else { + return 0.5; + } +} function main_page () { const student_name = document.querySelector('#userName').querySelector('span').innerText; let second_semester = false; @@ -108,7 +117,7 @@ function main_page () { if (gradeToGPA($first_grade.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { - course: new Course("", `https://powerschool.sas.edu.sg/guardian/${$first_grade.attr('href')}`, $first_grade.text()), + course: new Course("", `https://powerschool.sas.edu.sg/guardian/${$first_grade.attr('href')}`, $first_grade.text(), 0, ""), showMissing: false, }, }).$mount($first_grade.get(0)); @@ -119,7 +128,9 @@ function main_page () { } if ($course.length === 1) { const temp = $course.parents().eq(1).children("td[align=left]").text().match(".*(?=Details)")[0]; - courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text())); + let creditHour = 0; + creditHour = calculate_credit_hours($($course.parents().get(1)).find("td").get(0).textContent); + courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "", creditHour)); if (gradeToGPA($course.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { @@ -153,9 +164,12 @@ function main_page () { $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Last Semester GPA (S1): ${calculate_gpa(courses_first_semester)}`); } }); - $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(``); - $("#calculateCumulative").click(show_cumulative_gpa); } + $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(``); + // passing courses in to possibly include current semester GPA if term has not finished yet. + $("#calculateCumulative").click(function () { + show_cumulative_gpa(courses); + }); // Hypo Grade Calculator const HypoGradesDiv = document.createElement('div'); HypoGradesDiv.classList.add("hypo-grade-div-fixed"); @@ -167,10 +181,10 @@ function main_page () { }, }).$mount(".hypo-grade-div-fixed"); } -function show_cumulative_gpa () { +function show_cumulative_gpa (courses) { $("#calculateCumulative").hide(); - calculate_cumulative_gpa().then(cumulative_gpa => { - $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Cumulative GPA(Completed Semesters): ${cumulative_gpa.toFixed(2)}`); + calculate_cumulative_gpa(courses).then(cumulative_gpa => { + $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Cumulative GPA: ${cumulative_gpa.toFixed(2)}`); }); } function class_page () { @@ -199,7 +213,7 @@ function login_page () { }); } -function calculate_cumulative_gpa () { +function calculate_cumulative_gpa (current_courses) { const list_of_gpas = []; const all_courses = []; const credit_hour_list = []; @@ -243,6 +257,17 @@ function calculate_cumulative_gpa () { })); } // Calculates cumulative GPA based on credit hours per semester and gpa for each semester. + let include_current_semester = false; + if (current_courses.length !== 0) { + for (let i = 0; i < current_courses.length; i++) { + if (current_courses[i].link.includes("begdate")) { + include_current_semester = true; + } + } + } + if (include_current_semester) { + all_courses.push(current_courses); + } const cumulative_gpa = Promise.all(fetches).then(function () { let total_count = 0; let total_gpa = 0; From 31009355caa7f402d1514cf4c0e9e7a780add424 Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 17:01:42 +0800 Subject: [PATCH 4/6] Renamed total_add function to calculate_credit_hours and removed previous calculate_credit_hours function Signed-off-by: Suhas Hariharan --- src/js/helpers.js | 25 ++++++++++++++----------- src/js/saspowerschoolff.js | 18 ++++-------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/js/helpers.js b/src/js/helpers.js index 455ccbb4..878d07b3 100644 --- a/src/js/helpers.js +++ b/src/js/helpers.js @@ -104,7 +104,7 @@ function calculate_gpa (courses) { let sum = 0; for (var i = 0; i < courses.length; i++) { if (gradeToGPA(courses[i].grade) !== -1) { - const multiplier = total_add(courses[i].name); + const multiplier = calculate_credit_hours(courses[i].name); courses_with_grades += multiplier; sum += multiplier * (gradeToGPA(courses[i].grade) + course_boost(courses[i].name, courses[i].grade)); } @@ -113,16 +113,7 @@ function calculate_gpa (courses) { return '0.00'; } return (sum / courses_with_grades).toFixed(2); - function total_add (course_name) { - const double_effect_courses = [`English 10/American History`, `English 9/World History`]; - if (double_effect_courses.includes(course_name)) { - return 2; - } - if (/^(I Service: |IS: )/.test(course_name)) { - return 0.5; - } - return 1; - } + function course_boost (course_name, grade) { if (gradeToGPA(grade) < 1.8) { return 0; @@ -134,6 +125,17 @@ function calculate_gpa (courses) { } } +function calculate_credit_hours (course_name) { + const double_effect_courses = [`English 10/American History`, `English 9/World History`]; + if (double_effect_courses.includes(course_name)) { + return 2; + } + if (/^(I Service: |IS: )/.test(course_name)) { + return 0.5; + } + return 1; +} + /** * Extract the final percent from the course page html. * @param {String} html course page html @@ -184,4 +186,5 @@ export { calculate_gpa, extractFinalPercent, assignments, + calculate_credit_hours, }; diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index 0ca610f2..55ceb98d 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -29,7 +29,7 @@ import $ from 'jquery'; const browser = require('webextension-polyfill'); -import { calculate_gpa, extractFinalPercent, gradeToGPA } from './helpers'; +import { calculate_gpa, extractFinalPercent, gradeToGPA, calculate_credit_hours } from './helpers'; // Vue Components import Vue from 'vue'; @@ -72,15 +72,7 @@ function analytics_message (action_input) { const href = window.location.href.split("?")[0]; browser.runtime.sendMessage({ action: "analytics_send", args: { url: href, action: action_input } }); } -function calculate_credit_hours (text) { - if (text.substr(0, 2) === "IS") { - return 0.25; - } else if (text.includes("A-B")) { - return 1; - } else { - return 0.5; - } -} + function main_page () { const student_name = document.querySelector('#userName').querySelector('span').innerText; let second_semester = false; @@ -117,7 +109,7 @@ function main_page () { if (gradeToGPA($first_grade.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { - course: new Course("", `https://powerschool.sas.edu.sg/guardian/${$first_grade.attr('href')}`, $first_grade.text(), 0, ""), + course: new Course("", `https://powerschool.sas.edu.sg/guardian/${$first_grade.attr('href')}`, $first_grade.text()), showMissing: false, }, }).$mount($first_grade.get(0)); @@ -128,9 +120,7 @@ function main_page () { } if ($course.length === 1) { const temp = $course.parents().eq(1).children("td[align=left]").text().match(".*(?=Details)")[0]; - let creditHour = 0; - creditHour = calculate_credit_hours($($course.parents().get(1)).find("td").get(0).textContent); - courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "", creditHour)); + courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "", calculate_credit_hours(temp.trim()))); if (gradeToGPA($course.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { From cad6e665ba46c8e448d42c69d042d69bc1e40fce Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 19:06:43 +0800 Subject: [PATCH 5/6] Modified course class to automatically calculate credit hours Signed-off-by: Suhas Hariharan --- src/js/models/Course.js | 5 +++-- src/js/saspowerschoolff.js | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/js/models/Course.js b/src/js/models/Course.js index 10e70ed5..ec13e894 100644 --- a/src/js/models/Course.js +++ b/src/js/models/Course.js @@ -21,6 +21,7 @@ * along with this program. If not, see . * */ +import { calculate_credit_hours } from '../helpers'; export default class Course { #name; @@ -40,13 +41,13 @@ export default class Course { * @param {Assignment[]} [assignments] number of missing assignments * @param {Number?} [creditHour] number of credit hours this course counts for, optional */ - constructor (name, link, grade, finalPercent, assignments, creditHour) { + constructor (name, link, grade, finalPercent, assignments) { this.#name = name; this.#link = link; this.#grade = grade; this.#finalPercent = finalPercent; this.#assignments = assignments; - this.#creditHour = creditHour; + this.#creditHour = calculate_credit_hours(this.#name); } get name () { diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index 55ceb98d..be045cbc 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -29,7 +29,7 @@ import $ from 'jquery'; const browser = require('webextension-polyfill'); -import { calculate_gpa, extractFinalPercent, gradeToGPA, calculate_credit_hours } from './helpers'; +import { calculate_gpa, extractFinalPercent, gradeToGPA } from './helpers'; // Vue Components import Vue from 'vue'; @@ -120,7 +120,7 @@ function main_page () { } if ($course.length === 1) { const temp = $course.parents().eq(1).children("td[align=left]").text().match(".*(?=Details)")[0]; - courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "", calculate_credit_hours(temp.trim()))); + courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "")); if (gradeToGPA($course.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { @@ -238,7 +238,7 @@ function calculate_cumulative_gpa (current_courses) { const $prev_course = element_list[t]; // Creates course object with each course from grade history page const course = new Course($prev_course.getElementsByTagName("td")[0].textContent.trim(), "", - $prev_course.getElementsByTagName("td")[1].textContent.trim(), 0, "", parseFloat($prev_course.getElementsByTagName("td")[4].innerText)); + $prev_course.getElementsByTagName("td")[1].textContent.trim(), 0, ""); courses.push(course); } From c164579bb72ea6b1e4eed3e4f6bd55c703b08391 Mon Sep 17 00:00:00 2001 From: Suhas Hariharan Date: Tue, 17 Mar 2020 23:00:37 +0800 Subject: [PATCH 6/6] Ensures middle school grades are not counted, slightly alters cumulative gpa message Signed-off-by: Suhas Hariharan --- src/js/saspowerschoolff.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/js/saspowerschoolff.js b/src/js/saspowerschoolff.js index be045cbc..47b1edf4 100644 --- a/src/js/saspowerschoolff.js +++ b/src/js/saspowerschoolff.js @@ -120,7 +120,7 @@ function main_page () { } if ($course.length === 1) { const temp = $course.parents().eq(1).children("td[align=left]").text().match(".*(?=Details)")[0]; - courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text(), 0, "")); + courses.push(new Course(temp.trim(), `https://powerschool.sas.edu.sg/guardian/${$course.attr('href')}`, $course.text())); if (gradeToGPA($course.text()) !== -1) { new (Vue.extend(ClassGrade))({ propsData: { @@ -174,7 +174,7 @@ function main_page () { function show_cumulative_gpa (courses) { $("#calculateCumulative").hide(); calculate_cumulative_gpa(courses).then(cumulative_gpa => { - $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Cumulative GPA: ${cumulative_gpa.toFixed(2)}`); + $("table[border='0'][cellpadding='3'][cellspacing='1'][width='100%']").prepend(`Cumulative GPA(9-12): ${cumulative_gpa.toFixed(2)}`); }); } function class_page () { @@ -216,8 +216,8 @@ function calculate_cumulative_gpa (current_courses) { const el = document.createElement("html"); el.innerHTML = data; const tabs = el.getElementsByClassName("tabs")[0].getElementsByTagName("li"); - for (let i = 0; i < tabs.length; i++) { - // Iterates through semesters and adds each list of courses to all_courses list + // Iterate until the end of tabs or until no longer at a high school semester. + for (let i = 0; i < tabs.length && /HS$/.test(tabs[i].innerText); i++) { fetches.push( fetch(tabs[i].getElementsByTagName("a")[0].href) .then(res => res.text())