diff options
Diffstat (limited to 'contents/ui/kanvas.js')
-rw-r--r-- | contents/ui/kanvas.js | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/contents/ui/kanvas.js b/contents/ui/kanvas.js new file mode 100644 index 0000000..6ed64ac --- /dev/null +++ b/contents/ui/kanvas.js @@ -0,0 +1,158 @@ +function callApi(path, perPage, callback) { + let xhr = new XMLHttpRequest() + let apiUrl = `${apiEndpoint}${path}` + if (perPage >= 1) { + // add pagination parameter + apiUrl += `${path.includes("?") ? "&" : "?"}per_page=${perPage}` + } + xhr.open("GET", apiUrl) + xhr.setRequestHeader("Authorization", authHeader) + xhr.onload = () => { + if (xhr.status == 200) { + try { + let json = JSON.parse(xhr.responseText) + if (callback) { callback(json) } + } catch (e) { + if (e instanceof SyntaxError) { + console.error(`Cannot parse response for ${path} as JSON:\n${xhr.responseText}`) + } else { throw e } + } + } else { + console.error(`XHR failed when retrieving ${path} (status ${xhr.status}):\n${xhr.responseText}`) + } + } + xhr.send() +} + +function syncCanvas() { + const courses = plasmoid.configuration.courses.split("\n").map( + // each line in the "courses" config consists of + // a numeric course id, a space, and a course code + line => { + const spaceIndex = line.indexOf(" ") + return {id: line.slice(0, spaceIndex), code: line.slice(spaceIndex + 1)} + } + ) + let courseIndices = {} // reverse look-up table to sort by courses + for (let i = 0; i < courses.length; i++) { + courseIndices[courses[i].id] = i + } + + const showSubmittedAssignments = plasmoid.configuration.showSubmittedAssignments + + // we need user id to check submission status + callApi("/users/self", 0, user => { + syncCourses(courses, courseIndices, showSubmittedAssignments, user.id) + }) +} + +// fetch asynchronously, but display in this order: +// important -> normal -> finished +// when an activity is both important and finished, important takes priority +function syncCourses(courses, courseIndices, showSubmittedAssignments, userId) { + announcementsModel.clear() + assignmentsModel.clear() + + let announcementIndices = { + important: 0, // actually constant, kept for symmetry + normal: 0, + finished: 0, + } + let assignmentIndices = { + important: 0, + normal: 0, + finished: 0, + } + + for (let course of courses) { + const courseIdx = courseIndices[course.id] + callApi(`/announcements?context_codes[]=course_${course.id}`, 50, announcements => { + announcements.forEach(announcement => { + const info = { + type: "announcement", + activityId: announcement.id, + courseId: course.id, + course: course.code, + title: announcement.title, + url: announcement.html_url, + important: plasmoid.configuration.importantAnnouncements.includes(announcement.id.toString()), + finished: plasmoid.configuration.finishedAnnouncements.includes(announcement.id.toString()), + } + + // figure out where we insert it into list + let idx = 0 + let endIdx = 0 // actually past the end + if (info.important) { + idx = announcementIndices.important + endIdx = announcementIndices.normal + announcementIndices.normal++ + announcementIndices.finished++ + } else if (!info.finished) { + idx = announcementIndices.normal + endIdx = announcementIndices.finished + announcementIndices.finished++ + } else { + idx = announcementIndices.finished + endIdx = announcementsModel.count + } + + for (; idx < endIdx; idx++) { + const annc = announcementsModel.get(idx) + if (courseIndices[course.id] < courseIndices[annc.courseId]) { + // we are just past the end of this course + // insert this announcement here + break + } + } + announcementsModel.insert(idx, info) + }) + }) + + callApi(`/courses/${course.id}/assignments`, 50, assignments => { + assignments.forEach(assignment => { + callApi(`/courses/${course.id}/assignments/${assignment.id}/submissions/${userId}`, 0, submission => { + const submitted = submission.workflow_state == "submitted" || + submission.workflow_state == "graded" + if (submitted && !showSubmittedAssignments) return // discard this + + const info = { + type: "assignment", + activityId: assignment.id, + courseId: course.id, + course: course.code, + title: assignment.name, + dueAt: assignment.due_at || "", // if null, use empty string to suppress errors + submitted: submitted, + url: assignment.html_url, + important: plasmoid.configuration.importantAssignments.includes(assignment.id.toString()), + finished: plasmoid.configuration.finishedAssignments.includes(assignment.id.toString()), + } + + let idx = 0 + let endIdx = 0 + if (info.important) { + idx = assignmentIndices.important + endIdx = assignmentIndices.normal + assignmentIndices.normal++ + assignmentIndices.finished++ + } else if (!info.finished) { + idx = assignmentIndices.normal + endIdx = assignmentIndices.finished + assignmentIndices.finished++ + } else { + idx = assignmentIndices.finished + endIdx = assignmentsModel.count + } + + for (; idx < endIdx; idx++) { + const annc = assignmentsModel.get(idx) + if (courseIndices[course.id] < courseIndices[annc.courseId]) { + break + } + } + assignmentsModel.insert(idx, info) + }) + }) + }) + } +} |