minor fixes and small features

This commit is contained in:
Guy Sandler 2026-08-31 20:51:07 -07:00
parent ca072f236d
commit eaa2a85295
15 changed files with 2610 additions and 2534 deletions

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Nur beim Hover anzeigen" "message": "Nur beim Hover anzeigen"
}, },
"card_letter": {
"message": "Notenbuchstaben anzeigen"
},
"due": { "due": {
"message": "Fällig" "message": "Fällig"
}, },

View File

@ -119,6 +119,9 @@
"grade_hover": { "grade_hover": {
"message": "Show Only On Hover" "message": "Show Only On Hover"
}, },
"card_letter": {
"message": "Show letter grade"
},
"due": { "due": {
"message": "Due" "message": "Due"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Mostrar solo al pasar el mouse" "message": "Mostrar solo al pasar el mouse"
}, },
"card_letter": {
"message": "Mostrar letra de la nota"
},
"due": { "due": {
"message": "Pendiente" "message": "Pendiente"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Afficher uniquement au survol" "message": "Afficher uniquement au survol"
}, },
"card_letter": {
"message": "Afficher la note en lettres"
},
"due": { "due": {
"message": "Exigible" "message": "Exigible"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Mostra solo al passaggio del mouse" "message": "Mostra solo al passaggio del mouse"
}, },
"card_letter": {
"message": "Mostra voto in lettere"
},
"due": { "due": {
"message": "Dovuto" "message": "Dovuto"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "ホバー時のみ表示" "message": "ホバー時のみ表示"
}, },
"card_letter": {
"message": "成績をアルファベットで表示"
},
"due": { "due": {
"message": "期限" "message": "期限"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Mostrar apenas ao passar o mouse" "message": "Mostrar apenas ao passar o mouse"
}, },
"card_letter": {
"message": "Mostrar nota em letra"
},
"due": { "due": {
"message": "Devido" "message": "Devido"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Показывать только при наведении" "message": "Показывать только при наведении"
}, },
"card_letter": {
"message": "Показывать буквенную оценку"
},
"due": { "due": {
"message": "Должный" "message": "Должный"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "Visa endast vid svävning" "message": "Visa endast vid svävning"
}, },
"card_letter": {
"message": "Visa bokstavsbetyg"
},
"due": { "due": {
"message": "Förfaller" "message": "Förfaller"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "仅在悬停时显示" "message": "仅在悬停时显示"
}, },
"card_letter": {
"message": "显示字母成绩"
},
"due": { "due": {
"message": "到期的" "message": "到期的"
}, },

View File

@ -74,6 +74,9 @@
"grade_hover": { "grade_hover": {
"message": "仅在悬停时显示" "message": "仅在悬停时显示"
}, },
"card_letter": {
"message": "顯示字母成績"
},
"due": { "due": {
"message": "到期的" "message": "到期的"
}, },

View File

@ -176,6 +176,10 @@
<input type="checkbox" id="grade_hover" name="grade_hover"> <input type="checkbox" id="grade_hover" name="grade_hover">
<label for="grade_hover" class="sub-text" data-i18n="grade_hover">Show only when hovering</label> <label for="grade_hover" class="sub-text" data-i18n="grade_hover">Show only when hovering</label>
</div> </div>
<div class="sub-option" style="margin-top:5px">
<input type="checkbox" id="card_letter" name="card_letter">
<label for="card_letter" class="sub-text" data-i18n="card_letter">Show letter grade</label>
</div>
</div> </div>
</div> </div>
<div class="option-container" style="display:none"> <div class="option-container" style="display:none">

View File

@ -49,6 +49,7 @@ chrome.runtime.onInstalled.addListener(function () {
"custom_assignments": [], "custom_assignments": [],
"custom_assignments_overflow": ["custom_assignments"], "custom_assignments_overflow": ["custom_assignments"],
"grade_hover": false, "grade_hover": false,
"card_letter": true,
// "hide_completed": false, // "hide_completed": false,
"num_todo_items": 10, "num_todo_items": 10,
"custom_font": { "link": "", "family": "" }, "custom_font": { "link": "", "family": "" },

View File

@ -877,6 +877,7 @@ function applyOptionsChanges(changes) {
break; break;
case "dashboard_grades": case "dashboard_grades":
case "grade_hover": case "grade_hover":
case "card_letter":
if (!grades) getGrades(); if (!grades) getGrades();
insertGrades(); insertGrades();
break; break;
@ -4156,6 +4157,20 @@ function populateSidebarFromNav(sidebarContent) {
const navMenu = document.getElementById("menu"); const navMenu = document.getElementById("menu");
let hasDashboardButton = false; let hasDashboardButton = false;
// Keep the global-search trigger last in the sidebar. The search button's
// placement pass and this populate pass run on independent rAF callbacks,
// so either can execute first. If the search button was appended before
// the nav buttons exist, slot the nav buttons in ahead of it so Search
// always stays at the bottom of the sidebar.
const searchBtn = sidebarContent.querySelector("#canvasrefined-gs-sidebar-btn");
const insertNavButton = (text, href, icon) => {
const button = createSidebarButton(text, href, sidebarContent, icon);
if (searchBtn && searchBtn.parentNode === sidebarContent) {
sidebarContent.insertBefore(button, searchBtn);
}
return button;
};
if (navMenu) { if (navMenu) {
const menuItems = navMenu.querySelectorAll("a[id^='global_nav'], .globalNavExternalTool a"); const menuItems = navMenu.querySelectorAll("a[id^='global_nav'], .globalNavExternalTool a");
menuItems.forEach(item => { menuItems.forEach(item => {
@ -4217,14 +4232,14 @@ function populateSidebarFromNav(sidebarContent) {
} }
if (itemId === "global_nav_dashboard_link") hasDashboardButton = true; if (itemId === "global_nav_dashboard_link") hasDashboardButton = true;
const button = createSidebarButton(text, href, sidebarContent, icon); const button = insertNavButton(text, href, icon);
if (itemId) button.dataset.navItemId = itemId; if (itemId) button.dataset.navItemId = itemId;
addSidebarButtonBadge(button, getNavBadgeCount(item)); addSidebarButtonBadge(button, getNavBadgeCount(item));
}); });
} }
if (!hasDashboardButton) { if (!hasDashboardButton) {
createSidebarButton("Dashboard", `${domain}/`, sidebarContent, customIcons["global_nav_dashboard_link"]); insertNavButton("Dashboard", `${domain}/`, customIcons["global_nav_dashboard_link"]);
} }
} }
function updateSidebar(expanded, sidebarList, expander) { function updateSidebar(expanded, sidebarList, expander) {
@ -4837,6 +4852,18 @@ function runiframeChecker() {
Dashboard grades Dashboard grades
*/ */
// Map a percentage to a letter grade using the user's configurable GPA
// calculator cutoffs (A+ down to F). Returns null when no grade is present.
function percentToLetterGrade(percent) {
const bounds = options.gpa_calc_bounds;
if (!bounds || typeof percent !== "number") return null;
for (const letter of Object.keys(bounds)) {
const cutoff = bounds[letter]?.cutoff;
if (typeof cutoff === "number" && percent >= cutoff) return letter;
}
return null;
}
function insertGrades() { function insertGrades() {
if (options.dashboard_grades === true) { if (options.dashboard_grades === true) {
grades.then(data => { grades.then(data => {
@ -4850,7 +4877,12 @@ function insertGrades() {
let gradepercent = grade.enrollments[0].has_grading_periods === true ? grade.enrollments[0].current_period_computed_current_score : grade.enrollments[0].computed_current_score; let gradepercent = grade.enrollments[0].has_grading_periods === true ? grade.enrollments[0].current_period_computed_current_score : grade.enrollments[0].computed_current_score;
//let gradepercent = grade.enrollments[0].computed_current_score; //let gradepercent = grade.enrollments[0].computed_current_score;
let percent = (gradepercent || "--") + "%"; let percent = (gradepercent || "--") + "%";
let gradeContainer = cards[i].querySelector(".canvasrefined-card-grade") || makeElement("a", cards[i].querySelector(".ic-DashboardCard__header"), { "className": "canvasrefined-card-grade", "textContent": percent }); if (options.card_letter === true) {
const letter = percentToLetterGrade(gradepercent);
if (letter) percent = `${letter} ${percent}`;
}
let gradeContainer = cards[i].querySelector(".canvasrefined-card-grade") || makeElement("a", cards[i].querySelector(".ic-DashboardCard__header"), { "className": "canvasrefined-card-grade" });
gradeContainer.textContent = percent;
if (options.grade_hover === true) { if (options.grade_hover === true) {
gradeContainer.classList.add("canvasrefined-hover-only"); gradeContainer.classList.add("canvasrefined-hover-only");
} else { } else {
@ -6101,6 +6133,8 @@ function onGlobalSearchShortcut(e) {
function openGlobalSearchModal() { function openGlobalSearchModal() {
if (document.getElementById("canvasrefined-global-search-modal")) return; if (document.getElementById("canvasrefined-global-search-modal")) return;
// Show the platform-appropriate modifier in keybind hints (⌘ on Mac).
const modKey = /Mac|iPhone|iPad/.test(navigator.platform) ? "\u2318" : "Ctrl";
const modal = document.createElement("div"); const modal = document.createElement("div");
modal.id = "canvasrefined-global-search-modal"; modal.id = "canvasrefined-global-search-modal";
modal.className = "canvasrefined-gs-modal"; modal.className = "canvasrefined-gs-modal";
@ -6116,7 +6150,8 @@ function openGlobalSearchModal() {
<div class="canvasrefined-gs-footer"> <div class="canvasrefined-gs-footer">
<span><kbd>\u2191</kbd><kbd>\u2193</kbd> navigate</span> <span><kbd>\u2191</kbd><kbd>\u2193</kbd> navigate</span>
<span><kbd>Enter</kbd> open</span> <span><kbd>Enter</kbd> open</span>
<span><kbd>Ctrl</kbd>+<kbd>Enter</kbd> new tab</span> <span><kbd>${modKey}</kbd>+<kbd>Enter</kbd> new tab</span>
<span><kbd>${modKey}</kbd>+<kbd>K</kbd> toggle search</span>
<span><kbd>Esc</kbd> close</span> <span><kbd>Esc</kbd> close</span>
</div> </div>
</div>`; </div>`;

View File

@ -25,6 +25,7 @@ const syncedSubOptions = [
"todo_ignore_card_colors", "todo_ignore_card_colors",
"todo_remove_icons", "todo_remove_icons",
"grade_hover", "grade_hover",
"card_letter",
// "hide_completed", // "hide_completed",
"num_todo_items", "num_todo_items",
"hover_preview", "hover_preview",
@ -126,6 +127,7 @@ const defaultOptions = {
"custom_assignments": [], "custom_assignments": [],
"custom_assignments_overflow": ["custom_assignments"], "custom_assignments_overflow": ["custom_assignments"],
"grade_hover": false, "grade_hover": false,
"card_letter": true,
// "hide_completed": false, // "hide_completed": false,
"num_todo_items": 10, "num_todo_items": 10,
"custom_font": { "link": "", "family": "" }, "custom_font": { "link": "", "family": "" },
@ -949,6 +951,7 @@ function setup() {
"todo_ignore_card_colors", "todo_ignore_card_colors",
"todo_remove_icons", "todo_remove_icons",
"grade_hover", "grade_hover",
"card_letter",
// "hide_completed", // "hide_completed",
"hover_preview", "hover_preview",
"customBackgroundDaily", "customBackgroundDaily",