-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcalendar_background.js
149 lines (128 loc) · 3.78 KB
/
calendar_background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
const daysOfWeek = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const today = new Date();
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
function sameDate(a, b) {
return a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
}
function getSemanticDate(date) {
if (sameDate(date, today)) {
return "Today";
}
if (sameDate(date, tomorrow)) {
return "Tomorrow";
}
return daysOfWeek[date.getDay()];
}
function getEventTypeAndTitle(title) {
if (title.includes(" - Due")) {
return {
type: "Assignment",
title: title.slice(0, -6),
};
}
if (title.includes(" - Availability Ends")) {
return {
type: "Quiz",
title: title.slice(0, -20),
};
}
if (title.toLowerCase().includes("office hour")) {
return {
type: "Office Hours",
title,
};
}
return {
type: "Lecture",
title,
};
}
/**
* Removes redudant AMs and PMs.
*
* 12:30 PM -> 12:30 PM
* 1:25 PM - 2:25 PM -> 1:25 - 2:25 PM
* 10:15 AM - 11:45 AM -> 10:15 - 11:45 AM
* 11:00 AM - 2:00 PM -> 11:00 AM - 2:00 PM
*/
function removeRedundantPM(time) {
const matches = time.match(/( [A,P]M)/g);
if (matches.length === 2 && matches[0] === matches[1]) {
const index = time.indexOf(matches[0]);
return time.slice(0, index) + time.slice(index + 3);
}
return time;
}
// Extracts the href from an event
// myCourses makes this more complicated than it needs to be
function extractHref(element) {
const anchors = $(element).find("a");
if (anchors.length === 1) {
// The href is hidden in a template, so we have to do some voodoo
return $($(element).find("template").prop("content"))
.find("a")
.attr("href");
}
// Otherwise it's pretty simple
return $(anchors[1]).attr("href");
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
// We'll only handle "calendar" requests
if (request.type !== "calendar") {
return;
}
// The first network request sets the calendar page to the "Agenda" view
// Otherwise it may be on another view and our scraping won't work
$.post("https://mycourses.rit.edu/d2l/le/calendar/6605/periodfilter/save", {
periodFilter: 5, // 5 is for "Agenda"
d2l_referrer: request.token, // comes from myCourses local storage
}).always(({ status }) => {
// For some reason jQuery's .done() method never works for this request
// So we just use .always() and double check for success here
if (status !== 200) {
sendResponse(null);
}
// Now we actually request the calendar page
$.get("https://mycourses.rit.edu/d2l/le/calendar/6605")
.done((response) => {
const eventGroups = [];
$(response)
.find("div > div > .d2l-collapsepane")
.each(function () {
// For each event group...
const dateText = $(this).find("h2").text()
const newGroup = {
date: dateText.substring(0, dateText.length - 6),
events: [],
};
$(this)
.find("li")
.each(function () {
// For each assignment...
newGroup.events.push({
...getEventTypeAndTitle($(this).find("h3").text()),
course: $(this).find(".d2l-le-calendar-dot-name").text(),
time: removeRedundantPM(
$($(this).find(".d2l-textblock")[0]).text()
),
href: extractHref(this),
});
});
eventGroups.push(newGroup);
});
sendResponse(eventGroups);
})
.fail(() => sendResponse(null));
});
// This keeps the message channel open until we call sendResponse
return true;
});