diff --git a/BetterResults.js b/BetterResults.js index 33e07e0..63b96a0 100644 --- a/BetterResults.js +++ b/BetterResults.js @@ -2,7 +2,7 @@ const sidebar_selector = ".sidebar-results>:first-child"; let wideToolbarCallback = function (mutationsList, _) { for (let mutation of mutationsList) { - if (mutation.type == 'childList' && mutation.removedNodes.length != 0) { + if (mutation.type == "childList" && mutation.removedNodes.length != 0) { for (const node of mutation.removedNodes) { if (node.id == "show-grid") { console.log("Readding grid afther smartschool removed it"); @@ -16,16 +16,27 @@ let wideToolbarCallback = function (mutationsList, _) { let wideToolbarObserver = new MutationObserver(wideToolbarCallback); let smscMainCallback = function (mutationsList, observer) { - wideToolbarObserver.observe($(sidebar_selector)[0], { attributes: false, childList: true, subtree: false }); + wideToolbarObserver.observe($(sidebar_selector)[0], { + attributes: false, + childList: true, + subtree: false, + }); onLoad(); addButton(); }; let smscMainObserver = new MutationObserver(smscMainCallback); -smscMainObserver.observe($('#smscMain')[0], { attributes: false, childList: true, subtree: false }); +smscMainObserver.observe($("#smscMain")[0], { + attributes: false, + childList: true, + subtree: false, +}); function totalToStr(total_numerator, total_denominator) { - return (Math.round(total_numerator / total_denominator * 1000) / 10).toString() + '%'; + return ( + (Math.round((total_numerator / total_denominator) * 1000) / 10).toString() + + "%" + ); } function addButton() { @@ -41,161 +52,388 @@ function addButton() { .addClass("optionWrapper-IEDUX") .addClass("button-mJfIq") .append( - $("").addClass("icon-dus_u").attr("src", chrome.runtime.getURL("static/img/icon_128.png")).attr("width", 24).attr("height", 24).attr("id", "show-grid-icon") - ).append( - $("").addClass("label-dOebJ").text("Grid").attr("id", "show-grid-label") - ).click(openGrid) + $("") + .addClass("icon-dus_u") + .attr("src", chrome.runtime.getURL("static/img/icon_128.png")) + .attr("width", 24) + .attr("height", 24) + .attr("id", "show-grid-icon"), + ) + .append( + $("") + .addClass("label-dOebJ") + .text("Grid") + .attr("id", "show-grid-label"), + ) + .click(openGrid), ); console.log("Added button"); } function makeGrid() { let loading = $("

Loading!

"); - fetch('/results/api/v1/evaluations?itemsOnPage=500').then(r => r.json()).then(results => { - let data = {}; - let course_to_graphic = {}; - let latest_period = null; - for (const result of results) { - if (result["type"] != "normal") { - continue; - } - let period = result["period"]["name"]; - if (latest_period === null) { - latest_period = period; - } - if (!(period in data)) { - data[period] = {}; - } + fetch("/results/api/v1/evaluations?itemsOnPage=500") + .then((r) => r.json()) + .then((results) => { + let data = {}; + let course_to_graphic = {}; + let latest_period = null; + for (const result of results) { + if (result["type"] != "normal") { + continue; + } + let period = result["period"]["name"]; + if (latest_period === null) { + latest_period = period; + } + if (!(period in data)) { + data[period] = {}; + } - period = data[period]; - for (const course of result["courses"]) { - course_to_graphic[course["name"]] = course["graphic"]; - const course_name = course["name"]; - if (!(course_name in period)) { - period[course_name] = []; + period = data[period]; + for (const course of result["courses"]) { + course_to_graphic[course["name"]] = course["graphic"]; + const course_name = course["name"]; + if (!(course_name in period)) { + period[course_name] = []; + } + period[course_name].push({ + date: result["date"], + name: result["name"], + graphic: result["graphic"], + }); } - period[course_name].push({ "date": result["date"], "name": result["name"], "graphic": result["graphic"] }); } - } - - for (let period_name of Object.keys(data)) { - let period = data[period_name]; - let grid = $("
").attr("id", "period").append($("

").text(period_name + ":")); - let table = $("").attr("id", "result-table"); - - let longest = 0; - for (let [_, course] of Object.entries(period)) { - course.sort((a, b) => { return a["date"].localeCompare(b["date"]); }); - if (course.length > longest) { - longest = course.length; + let grids = {}; + let all_subjects = new Set(); + for (let period_name of Object.keys(data)) { + for (let course of Object.keys(data[period_name])) { + all_subjects.add(course); } } - // Add row for disclamer - let disc_row = $(""); - for (let i = 0; i < longest + 1; i++) { - disc_row.append($("
").addClass("hidden-cell")); + all_subjects = Array.from(all_subjects).sort(); + let all_periods = Object.keys(data); + + let summary_grid = $("
") + .attr("id", "period") + .append($("

").text("Overzicht:")); + let summary_table = $("").attr("id", "result-table"); + + let sum_header = $(""); + sum_header.append($(""); - if (course_to_graphic[course_name].type == "icon") { - row.append($(""); + overallRow.append($("
").text("Vak")); + for (let period_name of all_periods) { + sum_header.append($("").text(period_name)); } - disc_row.append($("").attr("id", "disclamer").text("!")); - table.append(disc_row); + sum_header.append($("").text("Totaal")); + summary_table.append(sum_header); - let overallTotalNumerator = 0; - let overallTotalDenominator = 0; + let period_totals = {}; + for (let period_name of all_periods) { + period_totals[period_name] = { num: 0, den: 0 }; + } + let grand_total_num = 0; + let grand_total_den = 0; - for (let [course_name, course] of Object.entries(period)) { + for (let course_name of all_subjects) { let row = $("
").append( - $("") - .addClass("icon-label icon-label--24 smsc-svg--" + course_to_graphic[course_name]["value"] + "--24") - .text(course_name) - )); + + if ( + course_name in course_to_graphic && + course_to_graphic[course_name].type == "icon" + ) { + row.append( + $("").append( + $("") + .addClass( + "icon-label icon-label--24 smsc-svg--" + + course_to_graphic[course_name]["value"] + + "--24", + ) + .text(course_name), + ), + ); } else { row.append($("").text(course_name)); } - let total_numerator = 0; - let total_denominator = 0; + let subj_total_num = 0; + let subj_total_den = 0; + + for (let period_name of all_periods) { + let p_num = 0; + let p_den = 0; + if (data[period_name] && data[period_name][course_name]) { + for (let result of data[period_name][course_name]) { + let desc = result["graphic"]["description"]; + let match = desc.match(/^([\d\,\.]+)\/([\d\,\.]+)$/); + if (match) { + p_num += parseFloat(match[1].replace(",", ".")); + p_den += parseFloat(match[2].replace(",", ".")); + } + } + } - for (const result of course) { - const desc = result["graphic"]["description"]; - const color = result["graphic"]["color"]; - const name = result["name"]; - let cellDesc = desc || "/"; // If desc is empty, use "-/-" + let cell = $(""); + if (p_den != 0) { + cell.text(totalToStr(p_num, p_den)); + if (p_num / p_den < 0.5) cell.addClass("is-low"); + subj_total_num += p_num; + subj_total_den += p_den; + period_totals[period_name].num += p_num; + period_totals[period_name].den += p_den; + } + row.append(cell); + } - row.append($("") - .addClass("c-" + color + "-combo--300") - .attr({ id: "details", content: name }) - .text(cellDesc)); + let tot_cell = $("").addClass("total"); + if (subj_total_den != 0) { + tot_cell.text(totalToStr(subj_total_num, subj_total_den)); + if (subj_total_num / subj_total_den < 0.5) + tot_cell.addClass("is-low"); + grand_total_num += subj_total_num; + grand_total_den += subj_total_den; + } + row.append(tot_cell); + summary_table.append(row); + } - let match = desc.match(/^([\d\,\.]+)\/([\d\,\.]+)$/); - if (match) { - total_numerator += parseFloat(match[1].replace(',', '.')); - total_denominator += parseFloat(match[2].replace(',', '.')); + let overallRow = $("
").text("Totaal")); + for (let period_name of all_periods) { + let cell = $("").addClass("total"); + if (period_totals[period_name].den != 0) { + let p_num = period_totals[period_name].num; + let p_den = period_totals[period_name].den; + cell.text(totalToStr(p_num, p_den)); + if (p_num / p_den < 0.5) cell.addClass("is-low"); + } + overallRow.append(cell); + } + let grandTotCell = $("").addClass("total"); + if (grand_total_den != 0) { + grandTotCell.text(totalToStr(grand_total_num, grand_total_den)); + if (grand_total_num / grand_total_den < 0.5) + grandTotCell.addClass("is-low"); + } + overallRow.append(grandTotCell); + summary_table.append(overallRow); + summary_grid.append( + $("
").attr("id", "table-container").append(summary_table), + ); + grids["Overzicht"] = summary_grid; + + for (let period_name of Object.keys(data)) { + let period = data[period_name]; + + let grid = $("
") + .attr("id", "period") + .append($("

").text(period_name + ":")); + let table = $("").attr("id", "result-table"); + + let longest = 0; + for (let [_, course] of Object.entries(period)) { + course.sort((a, b) => { + return a["date"].localeCompare(b["date"]); + }); + if (course.length > longest) { + longest = course.length; } } + let overallTotalNumerator = 0; + let overallTotalDenominator = 0; + + for (let [course_name, course] of Object.entries(period)) { + let row = $(""); + if (course_to_graphic[course_name].type == "icon") { + row.append( + $(""); + overallTotalRow.append($(""); - overallTotalRow.append($("
").append( + $("") + .addClass( + "icon-label icon-label--24 smsc-svg--" + + course_to_graphic[course_name]["value"] + + "--24", + ) + .text(course_name), + ), + ); + } else { + row.append($("").text(course_name)); + } - for (let i = 0; i < longest - course.length; i++) { - row.append($("")); + let total_numerator = 0; + let total_denominator = 0; + + for (const result of course) { + const desc = result["graphic"]["description"]; + const color = result["graphic"]["color"]; + const name = result["name"]; + let cellDesc = desc || "/"; // If desc is empty, use "-/-" + + row.append( + $("") + .addClass("c-" + color + "-combo--300") + .attr({ id: "details", content: name }) + .text(cellDesc), + ); + + let match = desc.match(/^([\d\,\.]+)\/([\d\,\.]+)$/); + if (match) { + total_numerator += parseFloat(match[1].replace(",", ".")); + total_denominator += parseFloat(match[2].replace(",", ".")); + } + } + + for (let i = 0; i < longest - course.length; i++) { + row.append($("")); + } + + let last_cell = $("").addClass("total"); + if (total_denominator != 0) { + last_cell.text(totalToStr(total_numerator, total_denominator)); + if (total_numerator / total_denominator < 0.5) { + last_cell.addClass("is-low"); + } + } + row.append(last_cell); + + overallTotalNumerator += total_numerator; + overallTotalDenominator += total_denominator; + + table.append(row); } - let last_cell = $("").addClass("total"); - if (total_denominator != 0) { - last_cell.text(totalToStr(total_numerator, total_denominator)); - if (total_numerator / total_denominator < 0.5) { - last_cell.addClass('is-low'); + let overallTotalRow = $("
").text("Totaal")); + for (let i = 0; i < longest; i++) { + overallTotalRow.append($("")); + } + let overallTotalCell = $("").addClass("total"); + if (overallTotalDenominator != 0) { + overallTotalCell.text( + totalToStr(overallTotalNumerator, overallTotalDenominator), + ); + if (overallTotalNumerator / overallTotalDenominator < 0.5) { + overallTotalCell.addClass("is-low"); } } - row.append(last_cell); + overallTotalRow.append(overallTotalCell); + table.append(overallTotalRow); + + grid.append($("
").attr("id", "table-container").append(table)); + grid.append( + $("
") + .addClass("disclaimer-text") + .text( + "Deze totalen kunnen afwijken van uw werkelijke resultaten doordat niet altijd alle gegevens gekend zijn.", + ), + ); + grids[period_name] = grid; + } - overallTotalNumerator += total_numerator; - overallTotalDenominator += total_denominator; + let modal = $("
").attr("id", "content-container"); + let period_picker = $("
").addClass("period-picker"); + let period_header = $("
").addClass("period-header"); + let period_active_label = $("") + .addClass("period-active-label") + .text("Overzicht"); + let period_dropdown = $("
").addClass("period-dropdown"); + let period_toggle = $("
").text("Total")); - for (let i = 0; i < longest; i++) { - overallTotalRow.append($("")); + for (let period_name of ordered_periods) { + let option_row = $("").addClass("total"); - if (overallTotalDenominator != 0) { - overallTotalCell.text(totalToStr(overallTotalNumerator, overallTotalDenominator)); - if (overallTotalNumerator / overallTotalDenominator < 0.5) { - overallTotalCell.addClass('is-low'); - } + + period_menu.on("change", ".period-radio", function () { + const period_name = $(this).attr("data-period"); + selected_period = period_name; + renderPeriodButtonLabel(); + renderSelectedPeriods(); + period_dropdown.removeClass("open"); + }); + + function positionPeriodMenu() { + const rect = period_toggle[0].getBoundingClientRect(); + period_menu.css({ + top: rect.bottom + 6 + "px", + left: rect.left + "px", + width: Math.max(rect.width, 240) + "px", + }); } - overallTotalRow.append(overallTotalCell); - table.append(overallTotalRow); - grid.append($("
").attr("id", "table-container").append(table)); - data[period_name] = grid; - } + period_toggle.on("click", function (e) { + e.stopPropagation(); + const willOpen = !period_dropdown.hasClass("open"); + period_dropdown.toggleClass("open"); + if (willOpen) { + positionPeriodMenu(); + } + }); - let modal = $("
").attr("id", "content-container"); - let period_buttons = $("
"); - let main_grid = $("
").attr("id", "period-container"); - for (let [period_name, grid] of Object.entries(data).reverse()) { - // We are using two lambda's sice otherwice they will all use the same scope. - period_buttons.append($("