@@ -48,7 +48,7 @@ const grade_gpa = {
4848 * @param {string } grade The grade to convert.
4949 * @returns {number } The corresponding grade point average.
5050 */
51- function gradeToGPA ( grade ) {
51+ function gradeToGPA ( grade ) {
5252 if ( grade in grade_gpa ) {
5353 return grade_gpa [ grade ] ;
5454 }
@@ -72,7 +72,7 @@ const grade_fp = {
7272 * @param {string } grade The grade to convert.
7373 * @returns {number } The corresponding final percent.
7474 */
75- function gradeToFP ( grade ) {
75+ function gradeToFP ( grade ) {
7676 if ( grade in grade_fp ) {
7777 return grade_fp [ grade ] ;
7878 }
@@ -93,7 +93,7 @@ const fprange = {
9393 '0-15' : 'F' ,
9494} ;
9595
96- function fpToGrade ( finalPercent ) {
96+ function fpToGrade ( finalPercent ) {
9797 return getKeyRange ( fprange , parseFloat ( parseFloat ( finalPercent ) . toFixed ( 2 ) ) ) ;
9898}
9999
@@ -102,7 +102,7 @@ function fpToGrade (finalPercent) {
102102 * @param {Course[] } courses The courses for which the overall grade point average should be calculated.
103103 * @returns {string } The grade point average to the hundredth place.
104104 */
105- function calculate_gpa ( courses ) {
105+ function calculate_gpa ( courses ) {
106106 let courses_with_grades = 0 ;
107107 let sum = 0 ;
108108 for ( var i = 0 ; i < courses . length ; i ++ ) {
@@ -117,7 +117,7 @@ function calculate_gpa (courses) {
117117 }
118118 return ( sum / courses_with_grades ) . toFixed ( 2 ) ;
119119
120- function course_boost ( course_name , grade ) {
120+ function course_boost ( course_name , grade ) {
121121 if ( gradeToGPA ( grade ) < 1.8 ) {
122122 return 0 ;
123123 }
@@ -128,7 +128,7 @@ function calculate_gpa (courses) {
128128 }
129129}
130130
131- function calculate_credit_hours ( course_name ) {
131+ function calculate_credit_hours ( course_name ) {
132132 const double_effect_courses = [ `English 10/American History` , `English 9/World History` ] ;
133133 if ( double_effect_courses . includes ( course_name ) ) {
134134 return 2 ;
@@ -144,7 +144,7 @@ function calculate_credit_hours (course_name) {
144144 * @param {String } html course page html
145145 * @returns {Number|undefined } The final percent
146146 */
147- function extractFinalPercent ( html ) {
147+ function extractFinalPercent ( html ) {
148148 let number ;
149149 try {
150150 let current_string = html . match ( / (? = d o c u m e n t \. w r i t e ) .* / g) [ 1 ] ;
@@ -166,7 +166,7 @@ function extractFinalPercent (html) {
166166 * @param {String } semester string representing semester that the request is for
167167 * @returns {Number|undefined } The final percent
168168 */
169- async function getFinalPercent ( frn , semester ) {
169+ async function getFinalPercent ( frn , semester ) {
170170 let number ;
171171 try {
172172 await fetch ( `https://powerschool.sas.edu.sg/guardian/scores_ms_guardian.html?frn=${ frn } &fg=${ semester } ` , { credentials : "same-origin" } ) . then ( response => response . text ( ) ) . then ( response => {
@@ -188,11 +188,11 @@ async function getFinalPercent (frn, semester) {
188188 * @param {Node } table node representing table
189189 * @returns {String[] } List of all categories
190190 */
191- function extractGradeCategories ( table ) {
191+ function extractGradeCategories ( table ) {
192192 const table_rows = table . getElementsByTagName ( "tr" ) ;
193193 const category_set = new Set ( ) ;
194194 for ( let i = 1 ; i < table_rows . length - 1 ; i ++ ) {
195- category_set . add ( table_rows [ i ] . getElementsByTagName ( "td" ) [ 1 ] . getElementsByTagName ( "a " ) [ 0 ] . innerText ) ;
195+ category_set . add ( table_rows [ i ] . getElementsByTagName ( "td" ) [ 1 ] . getElementsByTagName ( "span " ) [ 1 ] . innerText ) ;
196196 }
197197 return Array . from ( category_set ) ;
198198}
@@ -201,32 +201,32 @@ function extractGradeCategories (table) {
201201 * Extract all assignments from a class.
202202 * @returns {ClassAssignment[] } List of all assignments
203203 */
204- function extractAssignmentList ( ) {
205- const table = document . querySelector ( "#content-main > div.box-round > table:nth-child(4) > tbody" ) ;
204+ function extractAssignmentList ( ) {
205+ const table = document . querySelector ( "table.zebra.grid > tbody" ) ;
206206 const assignments = [ ] ;
207207 [ ...table . querySelectorAll ( 'tr' ) ] . slice ( 1 , - 1 ) . forEach ( ( e , i ) => {
208208 const curr = e . querySelectorAll ( 'td' ) ;
209- assignments . push ( new ClassAssignment ( i , curr [ 0 ] . innerHTML , curr [ 1 ] . innerText , curr [ 2 ] . innerHTML , isIndicatorPresent ( curr [ 3 ] ) , isIndicatorPresent ( curr [ 4 ] ) , isIndicatorPresent ( curr [ 5 ] ) , isIndicatorPresent ( curr [ 6 ] ) , isIndicatorPresent ( curr [ 7 ] ) , curr [ 9 ] . innerHTML , curr [ 11 ] . innerHTML ) ) ;
209+ assignments . push ( new ClassAssignment ( i , curr [ 0 ] . innerHTML , curr [ 1 ] . innerText , curr [ 2 ] . innerHTML , isIndicatorPresent ( curr [ 4 ] ) , isIndicatorPresent ( curr [ 5 ] ) , isIndicatorPresent ( curr [ 6 ] ) , isIndicatorPresent ( curr [ 7 ] ) , isIndicatorPresent ( curr [ 8 ] ) , curr [ 11 ] . innerHTML , curr [ 12 ] . innerHTML . trim ( ) ) ) ;
210210 } ) ;
211211 return assignments ;
212212}
213213/**
214- * Return whether the given row contains an indicator of any kind(i.e missing, late)
214+ * Return whether the given row contains an indicator of any kind(i.e missing, late)
215215 * @param {Element } node Node representing individual row of each assignment
216216 * @returns {boolean } boolean representing whether input has child nodes and are set to visible.
217217 */
218- function isIndicatorPresent ( node ) {
219- return node . hasChildNodes ( ) && node . childNodes [ 0 ] . style . display !== 'none' ;
218+ function isIndicatorPresent ( node ) {
219+ return node . hasChildNodes ( ) && node . querySelector ( "div.ps-icon" ) ;
220220}
221221/**
222222 * Return Assignment instances for the given class page.
223223 * @param {Element } node Root node element of the class page.
224224 * @returns {Assignment[] } Assignments in this course
225225 */
226- function assignments ( node ) {
226+ function assignmentsFromNode ( node ) {
227227 const tr = [ ] ;
228228 // Find assignments table, get it's rows, take out the header and legend rows.
229- [ ...node . querySelector ( 'table[align=center ' ) . querySelectorAll ( 'tr' ) ] . slice ( 1 , - 1 ) . forEach ( ( e , i ) => {
229+ [ ...node . querySelector ( 'table.zebra.grid ' ) . querySelectorAll ( 'tr' ) ] . slice ( 1 , - 1 ) . forEach ( ( e , i ) => {
230230 const curr = e . querySelectorAll ( 'td' ) ;
231231 const assignment = new Assignment ( curr [ 2 ] ?. innerText || "" , curr [ curr . length - 1 ] ?. innerText || "" , i ) ;
232232 const missingIcon = e . querySelector ( 'img[src="/images/icon_missing.gif"]' ) ;
@@ -238,19 +238,58 @@ function assignments (node) {
238238 return tr ;
239239}
240240
241+ /**
242+ * Return Assignment instances for the given class page.
243+ * @param {String } student_id student id for the current user
244+ * @param {String } sectino_id section id for the course being requested
245+ * @param {String } start_date start date in YYYY-MM-DD format
246+ * @param {String } end_date end date in YYYY-MM-DD format
247+ * @returns {Assignment[] } Assignments in this course
248+ */
249+ function assignmentsFromAPI ( studentId , sectionId , startDate , endDate ) {
250+ const assignmentList = [ ] ;
251+ try {
252+ fetch ( 'https://powerschool.sas.edu.sg/ws/xte/assignment/lookup' , {
253+ method : "POST" , headers : {
254+ 'Content-Type' : 'application/json'
255+ } ,
256+ body : JSON . stringify ( {
257+ "student_ids" : [ studentId ] ,
258+ "section_ids" : [ sectionId ] ,
259+ "start_date" : startDate ,
260+ "end_date" : endDate
261+ } ) , credentials : "same-origin"
262+ } ) . then ( response => response . json ( ) ) . then ( response => {
263+ for ( let i = 0 ; i < response . length ; i ++ ) {
264+ if ( response [ i ] . _assignmentsections ?. length ) {
265+ const assignmentData = response [ i ] . _assignmentsections [ 0 ] ;
266+ const assignment = new Assignment ( assignmentData . name , assignmentData . _assignmentscores [ 0 ] ?. actualscoreentered || "" , i ) ;
267+ if ( assignmentData . _assignmentscores [ 0 ] ?. ismissing || null ) {
268+ assignment . addStatus ( Assignment . statuses . MISSING ) ;
269+ }
270+ assignmentList . push ( assignment ) ;
271+ }
272+ }
273+ } ) ;
274+ } catch ( e ) {
275+ return [ ] ;
276+ }
277+ return assignmentList ;
278+ }
279+
241280/**
242281 * Return course title of active class page
243282 * @returns {String } Course title
244283 */
245- function extractCourseTitle ( ) {
246- return document . getElementsByTagName ( 'h2' ) [ 0 ] . innerHTML ;
284+ function extractCourseTitle ( ) {
285+ return document . querySelector ( "tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(1)" ) . innerText
247286}
248287
249288/**
250289 * Retrieve category weighting for class from local storage
251290 * @returns {Map<String, Object> } Map of weighting assigned to each category for course
252291 */
253- async function getSavedCategoryWeighting ( ) {
292+ async function getSavedCategoryWeighting ( ) {
254293 const courseName = extractCourseTitle ( ) + "-catmap" ;
255294 const catmap = await browser . storage . local . get ( courseName ) ;
256295 if ( catmap === undefined || ( Object . keys ( catmap ) . length === 0 && catmap . constructor === Object ) || catmap [ courseName ] === undefined ) return false ;
@@ -261,7 +300,7 @@ async function getSavedCategoryWeighting () {
261300 * Save category weighting for class to local storage
262301 * @param {Map<String, Object> } catmap Map of weighting assigned to each category for course
263302 */
264- async function saveCategoryWeighting ( catmap ) {
303+ async function saveCategoryWeighting ( catmap ) {
265304 const courseName = extractCourseTitle ( ) ;
266305 const data = { } ;
267306 data [ courseName + "-catmap" ] = catmap ;
@@ -274,7 +313,7 @@ async function saveCategoryWeighting (catmap) {
274313 * @param {String } username users full name
275314 * @returns {Promise<Course[]> } list of courses objects for that user
276315 */
277- async function getSavedGrades ( username ) {
316+ async function getSavedGrades ( username ) {
278317 const courses = [ ] ;
279318 const user_data = ( await browser . storage . local . get ( "user_data" ) ) . user_data ;
280319 if ( user_data !== undefined ) {
@@ -303,7 +342,7 @@ async function getSavedGrades (username) {
303342 * @param {String } username users full name
304343 * @param {Course[] } courses list of course objects to save
305344 */
306- async function saveGradesLocally ( username , courses ) {
345+ async function saveGradesLocally ( username , courses ) {
307346 const data = await getLocalConfig ( ) || { } ;
308347
309348 if ( data . opted_in === undefined ) {
@@ -338,7 +377,7 @@ async function saveGradesLocally (username, courses) {
338377 * @async
339378 * @returns {Config } an object representing the user's config from the browser's local storage
340379 */
341- async function getLocalConfig ( ) {
380+ async function getLocalConfig ( ) {
342381 const data = await browser . storage . local . get ( null ) ;
343382 return data ;
344383}
@@ -347,7 +386,7 @@ async function getLocalConfig () {
347386 * Retrieves the default extension config for new users.
348387 * @returns {Config } an object representing the default config.
349388 */
350- function getDefaultConfig ( ) {
389+ function getDefaultConfig ( ) {
351390 const data = { opted_in : { changed : false , value : false } , percent_main_page : { changed : false , value : true } } ;
352391 return data ;
353392}
@@ -366,7 +405,8 @@ export {
366405 getFinalPercent ,
367406 extractGradeCategories ,
368407 extractAssignmentList ,
369- assignments ,
408+ assignmentsFromNode ,
409+ assignmentsFromAPI ,
370410 calculate_credit_hours ,
371411 getSavedGrades ,
372412 saveGradesLocally ,
0 commit comments