This commit is contained in:
Kevin Dao
2019-08-05 21:10:20 -05:00
8 changed files with 570 additions and 271 deletions

View File

@@ -31,6 +31,7 @@
animation: spin 2s linear infinite; animation: spin 2s linear infinite;
} }
@keyframes spin { @keyframes spin {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
@@ -73,10 +74,16 @@
.dateTimePlace { .dateTimePlace {
margin-left: 5px; margin-left: 5px;
margin-bottom: 0px;
font-size: smaller; font-size: smaller;
font-weight: bold; font-weight: bold;
} }
#chartcontainer {
max-width: 100%;
height: 250px;
}
#chart { #chart {
min-width: auto; min-width: auto;
max-width: 100%; max-width: 100%;

View File

@@ -1,6 +1,8 @@
updateBadge(true); updateBadge(true);
var grades;
loadDataBase()
/* Handle messages and their commands from content and popup scripts*/ /* Handle messages and their commands from content and popup scripts*/
chrome.runtime.onMessage.addListener(function(request, sender, response) { chrome.runtime.onMessage.addListener(function (request, sender, response) {
switch (request.command) { switch (request.command) {
case "courseStorage": case "courseStorage":
if (request.action == "add") { if (request.action == "add") {
@@ -31,6 +33,8 @@ chrome.runtime.onMessage.addListener(function(request, sender, response) {
case "updateCourseList": case "updateCourseList":
updateTabs(); updateTabs();
break; break;
case "gradesQuery":
executeQuery(request.query, response);
default: default:
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
const method = request.method ? request.method.toUpperCase() : "GET"; const method = request.method ? request.method.toUpperCase() : "GET";
@@ -51,35 +55,35 @@ chrome.runtime.onMessage.addListener(function(request, sender, response) {
}); });
/* Initially set the course data in storage */ /* Initially set the course data in storage */
chrome.runtime.onInstalled.addListener(function(details) { chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") { if (details.reason == "install") {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
if (!data.savedCourses) { if (!data.savedCourses) {
var arr = new Array(); var arr = new Array();
chrome.storage.sync.set({ chrome.storage.sync.set({
savedCourses: arr savedCourses: arr
}, function() { }, function () {
console.log('initial course list'); console.log('initial course list');
}); });
chrome.storage.sync.set({ chrome.storage.sync.set({
courseConflictHighlight: true courseConflictHighlight: true
}, function() { }, function () {
console.log('initial highlighting: true'); console.log('initial highlighting: true');
}); });
chrome.storage.sync.set({ chrome.storage.sync.set({
loadAll: true loadAll: true
}, function() { }, function () {
console.log('initial loadAll: true'); console.log('initial loadAll: true');
}); });
} }
}); });
} else if (details.reason == "update") { } else if (details.reason == "update") {
console.log("updated"); console.log("updated");
chrome.storage.sync.get('loadAll', function(data) { chrome.storage.sync.get('loadAll', function (data) {
if (data.loadAll == undefined) { if (data.loadAll == undefined) {
chrome.storage.sync.set({ chrome.storage.sync.set({
loadAll: true loadAll: true
}, function() { }, function () {
console.log('initial loadAll: true'); console.log('initial loadAll: true');
}); });
} }
@@ -88,8 +92,39 @@ chrome.runtime.onInstalled.addListener(function(details) {
}); });
function executeQuery(query, sendResponse) {
console.log(grades)
var res = grades.exec(query)[0];
sendResponse({
data: res,
});
}
/* Load the database*/
function loadDataBase() {
sql = window.SQL;
loadBinaryFile('grades.db', function (data) {
var sqldb = new SQL.Database(data);
grades = sqldb;
});
}
/* load the database from file */
function loadBinaryFile(path, success) {
var xhr = new XMLHttpRequest();
xhr.open("GET", chrome.extension.getURL(path), true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
var data = new Uint8Array(xhr.response);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
success(arr.join(""));
};
xhr.send();
};
function updateBadge(first) { function updateBadge(first) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
if (data.savedCourses) { if (data.savedCourses) {
let text = ""; let text = "";
if (data.savedCourses.length > 0) { if (data.savedCourses.length > 0) {
@@ -105,7 +140,7 @@ function updateBadge(first) {
}); });
timeout = 200; timeout = 200;
} }
setTimeout(function() { setTimeout(function () {
chrome.browserAction.setBadgeBackgroundColor({ chrome.browserAction.setBadgeBackgroundColor({
color: '#bf5700' color: '#bf5700'
}); });
@@ -117,7 +152,7 @@ function updateBadge(first) {
/* Find all the conflicts in the courses and send them out/ if there is even a conflict*/ /* Find all the conflicts in the courses and send them out/ if there is even a conflict*/
function checkConflicts(sendResponse) { function checkConflicts(sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var conflicts = []; var conflicts = [];
var courses = data.savedCourses; var courses = data.savedCourses;
for (var i = 0; i < courses.length; i++) { for (var i = 0; i < courses.length; i++) {
@@ -144,7 +179,7 @@ function checkConflicts(sendResponse) {
/* Find if the course at unique and with currdatearr is contained in the saved courses and if it conflicts with any other courses*/ /* Find if the course at unique and with currdatearr is contained in the saved courses and if it conflicts with any other courses*/
function isSingleConflict(currdatearr, unique, sendResponse) { function isSingleConflict(currdatearr, unique, sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var courses = data.savedCourses; var courses = data.savedCourses;
var conflict = false; var conflict = false;
for (var i = 0; i < courses.length; i++) { for (var i = 0; i < courses.length; i++) {
@@ -188,7 +223,7 @@ function isConflict(adtarr, bdtarr) {
/* Add the requested course to the storage*/ /* Add the requested course to the storage*/
function add(request, sender, sendResponse) { function add(request, sender, sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var courses = data.savedCourses; var courses = data.savedCourses;
if (!contains(courses, request.course.unique)) { if (!contains(courses, request.course.unique)) {
courses.push(request.course) courses.push(request.course)
@@ -206,7 +241,7 @@ function add(request, sender, sendResponse) {
} }
/* Find and Remove the requested course from the storage*/ /* Find and Remove the requested course from the storage*/
function remove(request, sender, sendResponse) { function remove(request, sender, sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var courses = data.savedCourses; var courses = data.savedCourses;
console.log(courses); console.log(courses);
var index = 0; var index = 0;
@@ -227,7 +262,7 @@ function remove(request, sender, sendResponse) {
/* Find if the unique is already contained within the storage*/ /* Find if the unique is already contained within the storage*/
function alreadyContains(unique, sendResponse) { function alreadyContains(unique, sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var courses = data.savedCourses; var courses = data.savedCourses;
sendResponse({ sendResponse({
alreadyContains: contains(courses, unique) alreadyContains: contains(courses, unique)
@@ -247,7 +282,7 @@ function contains(courses, unique) {
} }
function updateTabs() { function updateTabs() {
chrome.tabs.query({}, function(tabs) { chrome.tabs.query({}, function (tabs) {
for (var i = 0; i < tabs.length; i++) { for (var i = 0; i < tabs.length; i++) {
chrome.tabs.sendMessage(tabs[i].id, { chrome.tabs.sendMessage(tabs[i].id, {
command: "updateCourseList" command: "updateCourseList"
@@ -260,7 +295,7 @@ const UPDATE_INTERVAL = 1000 * 60 * 16;
setInterval(updateStatus, UPDATE_INTERVAL); setInterval(updateStatus, UPDATE_INTERVAL);
// updateStatus(); // updateStatus();
function updateStatus(sendResponse) { function updateStatus(sendResponse) {
chrome.storage.sync.get('savedCourses', function(data) { chrome.storage.sync.get('savedCourses', function (data) {
var courses = data.savedCourses; var courses = data.savedCourses;
var nochange = true; var nochange = true;
for (let i = 0; i < courses.length; i++) { for (let i = 0; i < courses.length; i++) {
@@ -268,25 +303,29 @@ function updateStatus(sendResponse) {
let c = courses[i]; let c = courses[i];
let oldstatus = c.status; let oldstatus = c.status;
let oldlink = c.link; let oldlink = c.link;
$.ajax({url: oldlink, success: function(result){ $.ajax({
if(result){ url: oldlink,
console.log(result); success: function (result) {
var object = $('<div/>').html(result).contents(); if (result) {
let newstatus = object.find('[data-th="Status"]').text(); console.log(result);
let registerlink = object.find('td[data-th="Add"] a'); var object = $('<div/>').html(result).contents();
if (registerlink) { let newstatus = object.find('[data-th="Status"]').text();
registerlink = registerlink.attr('href'); let registerlink = object.find('td[data-th="Add"] a');
if (registerlink) {
registerlink = registerlink.attr('href');
}
var haschanged = (newstatus == oldstatus && registerlink == oldlink);
if (!haschanged) {
console.log(c.unique + ' updated from ' + oldstatus + " to " + newstatus + " and " + oldlink + " to " + registerlink);
}
nochange &= haschanged;
c.registerlink = registerlink;
c.status = newstatus;
} }
var haschanged = (newstatus == oldstatus && registerlink == oldlink); }
if (!haschanged) { });
console.log(c.unique + ' updated from ' + oldstatus + " to " + newstatus + " and " + oldlink + " to " + registerlink);
}
nochange &= haschanged;
c.registerlink = registerlink;
c.status = newstatus;
}}});
} catch (e) { } catch (e) {
console.log(e); console.log(e);
console.log('Not logged into UT Coursebook. Could not update class statuses.'); console.log('Not logged into UT Coursebook. Could not update class statuses.');

2
js/config.js Normal file
View File

@@ -0,0 +1,2 @@
const fadetime = 150;
const butdelay = 75;

View File

@@ -1,4 +1,3 @@
var grades;
var rmpLink; var rmpLink;
var next; var next;
var bottom; var bottom;
@@ -20,18 +19,11 @@ var semesterCode;
var isIndividual = false; var isIndividual = false;
var done = true; var done = true;
const days = new Map([
["M", "Monday"],
["T", "Tuesday"],
["W", "Wednesday"],
["TH", "Thursday"],
["F", "Friday"]
]);
const fadetime = 150;
const butdelay = 75;
//This extension may be super lit, but you know what's even more lit? //This extension may be super lit, but you know what's even more lit?
//Matthew Tran's twitter and insta: @MATTHEWTRANN and @matthew.trann //Matthew Tran's twitter and insta: @MATTHEWTRANN and @matthew.trann
console.log('UT Registration Plus is running on this page.');
if (document.querySelector('#fos_fl')) { if (document.querySelector('#fos_fl')) {
let params = (new URL(document.location)).searchParams; let params = (new URL(document.location)).searchParams;
@@ -44,14 +36,17 @@ if (document.querySelector('#fos_fl')) {
} }
} }
} }
next = $("#next_nav_link");
chrome.storage.sync.get('loadAll', function (data) {
if (data.loadAll) {
$('[title*="next listing"]').remove();
}
});
loadDataBase();
next = $("#next_nav_link");
if (next) {
chrome.storage.sync.get('loadAll', function (data) {
if (data.loadAll) {
$('[title*="next listing"]').remove();
}
});
}
//make heading and modal //make heading and modal
if (!$("#kw_results_table").length) { if (!$("#kw_results_table").length) {
$("table thead th:last-child").after('<th scope=col>Plus</th>'); $("table thead th:last-child").after('<th scope=col>Plus</th>');
@@ -111,7 +106,7 @@ if (!$("#kw_results_table").length) {
//update the conflicts //update the conflicts
update(0); update(0);
/*Handle the button clicks*/ /*Handle the button clicks*/
$("tbody").on('click', '#distButton', function () { $("body").on('click', '#distButton', function () {
var row = $(this).closest('tr'); var row = $(this).closest('tr');
$('.modal-content').stop().animate({ $('.modal-content').stop().animate({
scrollTop: 0 scrollTop: 0
@@ -205,7 +200,7 @@ function loadNextPages() {
nextpage.find('tbody>tr').each(function () { nextpage.find('tbody>tr').each(function () {
let hasCourseHead = $(this).find('td').hasClass("course_header"); let hasCourseHead = $(this).find('td').hasClass("course_header");
if (!(hasCourseHead && $(this).has('th').length == 0)) { if (!(hasCourseHead && $(this).has('th').length == 0)) {
$(this).append(`<td data-th="Plus"><input type="image" class="distButton" id="distButton" style="vertical-align: bottom; display:block;" width="20" height="20" src='${chrome.extension.getURL('images/disticon.png')}'/></td>`); $(this).append(`<td data-th="Plus"><input type="image" class="distButton" id="distButton" style="vertical-align: bottom;" width="20" height="20" src='${chrome.extension.getURL('images/disticon.png')}'/></td>`);
// if ($(this).find('td[data-th="Status"]').text().includes('waitlisted')) { // if ($(this).find('td[data-th="Status"]').text().includes('waitlisted')) {
// $(this).find('td').each(function () { // $(this).find('td').each(function () {
// $(this).css('background-color', '#E0E0E0'); // $(this).css('background-color', '#E0E0E0');
@@ -338,7 +333,7 @@ function Course(coursename, unique, profname, datetimearr, status, link, registe
/*For a row, get all the course information and add the date-time-lines*/ /*For a row, get all the course information and add the date-time-lines*/
function getCourseInfo(row) { function getCourseInfo(row) {
console.log('WHAT'); console.log(row);
semesterCode = new URL(window.location.href).pathname.split('/')[4]; semesterCode = new URL(window.location.href).pathname.split('/')[4];
$("h2.dateTimePlace").remove(); $("h2.dateTimePlace").remove();
$('table').find('tr').each(function () { $('table').find('tr').each(function () {
@@ -452,27 +447,29 @@ function getDistribution(sem) {
query += "and sem like '%" + sem + "%'"; query += "and sem like '%" + sem + "%'";
} }
query += "order by a1+a2+a3+b1+b2+b3+c1+c2+c3+d1+d2+d3+f desc"; query += "order by a1+a2+a3+b1+b2+b3+c1+c2+c3+d1+d2+d3+f desc";
var res = grades.exec(query)[0]; chrome.runtime.sendMessage({
var output = ""; command: "gradesQuery",
if (!sem) { query: query
openDialog(department, coursename, "aggregate", profname, res); }, function (response) {
} else { var res = response.data;
var data; if (!sem) {
if (typeof res == 'undefined' || profname == "") { openDialog(department, coursename, "aggregate", profname, res);
data = [];
} else { } else {
data = res.values[0]; var data;
if (typeof res == 'undefined' || profname == "") {
data = [];
} else {
data = res.values[0];
}
setChart(data);
} }
setChart(data); });
}
} }
/*Open the modal and show all the data*/ /*Open the modal and show all the data*/
function openDialog(dep, cls, sem, professor, res) { function openDialog(dep, cls, sem, professor, res) {
$("#myModal").fadeIn(fadetime); $("#myModal").fadeIn(fadetime);
//initial text on the "save course button" //initial text on the "save course button"
chrome.runtime.sendMessage({ chrome.runtime.sendMessage({
command: "alreadyContains", command: "alreadyContains",
unique: uniquenum unique: uniquenum
@@ -487,35 +484,11 @@ function openDialog(dep, cls, sem, professor, res) {
var data; var data;
$("#semesters").empty(); $("#semesters").empty();
if (typeof res == 'undefined' || profname == "") { if (typeof res == 'undefined' || profname == "") {
data = [];
$("#semesters").append("<option>No Data</option>") $("#semesters").append("<option>No Data</option>")
data = [];
} else { } else {
var semesters = res.values[0][18].split(","); var semesters = res.values[0][18].split(",");
semesters.sort(function (a, b) { semesters.sort(semesterSort);
var as = a.split(' ')[0];
var ay = parseInt(a.split(' ')[1]);
var bs = b.split(' ')[0];
var by = parseInt(b.split(' ')[1]);
if (ay < by) {
return -1;
}
if (ay > by) {
return 1;
}
var seas = {
"Spring": 0,
"Fall": 1,
"Summer": 2,
"Winter": 3
}
if (seas[as] < seas[bs]) {
return -1;
}
if (seas[as] > seas[bs]) {
return 1;
}
return 0;
});
semesters.reverse().unshift('Aggregate'); semesters.reverse().unshift('Aggregate');
var sems = []; var sems = [];
for (var i = 0; i < semesters.length; i++) { for (var i = 0; i < semesters.length; i++) {
@@ -568,112 +541,7 @@ function close() {
function setChart(data) { function setChart(data) {
//set up the chart //set up the chart
chart = Highcharts.chart('chart', { chart = Highcharts.chart('chart', buildChartConfig(data), function (chart) { // on complete
chart: {
type: 'column',
backgroundColor: ' #fefefe',
spacingLeft: 10
},
title: {
text: null
},
subtitle: {
text: null
},
legend: {
enabled: false
},
xAxis: {
title: {
text: 'Grades'
},
categories: [
'A',
'A-',
'B+',
'B',
'B-',
'C+',
'C',
'C-',
'D+',
'D',
'D-',
'F'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Students'
}
},
credits: {
enabled: false
},
lang: {
noData: "The professor hasn't taught this class :("
},
tooltip: {
headerFormat: '<span style="font-size:small; font-weight:bold">{point.key}</span><table>',
pointFormat: '<td style="color:{black};padding:0;font-size:small; font-weight:bold;"><b>{point.y:.0f} Students</b></td>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
bar: {
pointPadding: 0.2,
borderWidth: 0
},
series: {
animation: {
duration: 700
}
}
},
series: [{
name: 'Grades',
data: [{
y: data[6],
color: '#4CAF50'
}, {
y: data[7],
color: '#8BC34A'
}, {
y: data[8],
color: '#CDDC39'
}, {
y: data[9],
color: '#FFEB3B'
}, {
y: data[10],
color: '#FFC107'
}, {
y: data[11],
color: '#FFA000'
}, {
y: data[12],
color: '#F57C00'
}, {
y: data[13],
color: '#FF5722'
}, {
y: data[14],
color: '#FF5252'
}, {
y: data[15],
color: '#E64A19'
}, {
y: data[16],
color: '#F44336'
}, {
y: data[17],
color: '#D32F2F'
}]
}]
}, function (chart) { // on complete
if (data.length == 0) { if (data.length == 0) {
//if no data, then show the message and hide the series //if no data, then show the message and hide the series
chart.renderer.text('Could not find data for this Instructor teaching this Course.', 100, 120) chart.renderer.text('Could not find data for this Instructor teaching this Course.', 100, 120)
@@ -716,77 +584,59 @@ function getDescription() {
// console.log(window.location.href); // console.log(window.location.href);
// console.log(profurl); // console.log(profurl);
console.log('hello'); console.log('hello');
$.ajax({url: profurl, success: function(response){ $.ajax({
if (response) { url: profurl,
console.log(profurl); success: function (response) {
var output = ""; if (response) {
var object = $('<div/>').html(response).contents(); console.log(profurl);
object.find('#details > p').each(function () { var output = "";
var sentence = $(this).text(); var object = $('<div/>').html(response).contents();
if (sentence.indexOf("Prerequisite") == 0) { object.find('#details > p').each(function () {
sentence = "<li style='font-weight: bold;' class='descriptionli'>" + sentence + "</li>"; var sentence = $(this).text();
} else if (sentence.indexOf("May be") >= 0) { if (sentence.indexOf("Prerequisite") == 0) {
sentence = "<li style='font-style: italic;' class='descriptionli'>" + sentence + "</li>"; sentence = "<li style='font-weight: bold;' class='descriptionli'>" + sentence + "</li>";
} else if (sentence.indexOf("Restricted to") == 0) { } else if (sentence.indexOf("May be") >= 0) {
sentence = "<li style='color:red;' class='descriptionli'>" + sentence + "</li>"; sentence = "<li style='font-style: italic;' class='descriptionli'>" + sentence + "</li>";
} else { } else if (sentence.indexOf("Restricted to") == 0) {
sentence = "<li class='descriptionli'>" + sentence + "</li>"; sentence = "<li style='color:red;' class='descriptionli'>" + sentence + "</li>";
} else {
sentence = "<li class='descriptionli'>" + sentence + "</li>";
}
output += sentence;
});
description = output;
console.log(response);
if (!description) {
description = "<p style='color:red;font-style:bold'>There was an error. Please refresh the page and/or log back in using your UT EID and password.</p>"
}
$("#description").animate({
'opacity': 0
}, 200, function () {
$(this).html(description).animate({
'opacity': 1
}, 200);
});
var first = object.find('td[data-th="Instructor"]').text();
first = first.substring(first.indexOf(", "), first.indexOf(" ", first.indexOf(", ") + 2));
first = first.substring(2);
rmpLink = `http://www.ratemyprofessors.com/search.jsp?queryBy=teacherName&schoolName=university+of+texas+at+austin&queryoption=HEADER&query=${first} ${profname};&facetSearch=true`;
if (profname == "") {
eCISLink = `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?s_in_action_sw=S&s_in_search_type_sw=C&s_in_max_nbr_return=10&s_in_search_course_dept=${department}&s_in_search_course_num=${course_nbr}`;
} else {
eCISLink = `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?&s_in_action_sw=S&s_in_search_type_sw=N&s_in_search_name=${profname.substring(0, 1) + profname.substring(1).toLowerCase()}%2C%20${first.substring(0, 1) + first.substring(1).toLowerCase()}`;
} }
output += sentence;
});
description = output;
console.log(response);
if (!description) {
description = "<p style='color:red;font-style:bold'>You have been logged out. Please refresh the page and log back in using your UT EID and password.</p>"
}
$("#description").animate({
'opacity': 0
}, 200, function () {
$(this).html(description).animate({
'opacity': 1
}, 200);
});
var first = object.find('td[data-th="Instructor"]').text();
first = first.substring(first.indexOf(", "), first.indexOf(" ", first.indexOf(", ") + 2));
first = first.substring(2);
rmpLink = `http://www.ratemyprofessors.com/search.jsp?queryBy=teacherName&schoolName=university+of+texas+at+austin&queryoption=HEADER&query=${first} ${profname};&facetSearch=true`;
if (profname == "") {
eCISLink = `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?s_in_action_sw=S&s_in_search_type_sw=C&s_in_max_nbr_return=10&s_in_search_course_dept=${department}&s_in_search_course_num=${course_nbr}`;
} else { } else {
eCISLink = `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?&s_in_action_sw=S&s_in_search_type_sw=N&s_in_search_name=${profname.substring(0, 1) + profname.substring(1).toLowerCase()}%2C%20${first.substring(0, 1) + first.substring(1).toLowerCase()}`; description = "<p style='color:red;font-style:bold'>You have been logged out. Please refresh the page and log back in using your UT EID and password.</p>"
$("#description").animate({
'opacity': 0
}, 200, function () {
$(this).html(description).animate({
'opacity': 1
}, 200);
});
rmpLink = "http://www.ratemyprofessors.com/campusRatings.jsp?sid=1255";
eCISLink = "http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?";
} }
} else {
description = "<p style='color:red;font-style:bold'>You have been logged out. Please refresh the page and log back in using your UT EID and password.</p>"
$("#description").animate({
'opacity': 0
}, 200, function () {
$(this).html(description).animate({
'opacity': 1
}, 200);
});
rmpLink = "http://www.ratemyprofessors.com/campusRatings.jsp?sid=1255";
eCISLink = "http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?";
} }
}});
}
/* Load the database*/
function loadDataBase() {
sql = window.SQL;
loadBinaryFile('grades.db', function (data) {
var sqldb = new SQL.Database(data);
grades = sqldb;
}); });
} }
/* load the database from file */
function loadBinaryFile(path, success) {
var xhr = new XMLHttpRequest();
xhr.open("GET", chrome.extension.getURL(path), true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
var data = new Uint8Array(xhr.response);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
success(arr.join(""));
};
xhr.send();
};

1
js/jquery.initialize.min.js vendored Normal file
View File

@@ -0,0 +1 @@
(function($){"use strict";var combinators=[" ",">","+","~"];var fraternisers=["+","~"];var complexTypes=["ATTR","PSEUDO","ID","CLASS"];function grok(msobserver){if(!$.find.tokenize){msobserver.isCombinatorial=true;msobserver.isFraternal=true;msobserver.isComplex=true;return}msobserver.isCombinatorial=false;msobserver.isFraternal=false;msobserver.isComplex=false;var token=$.find.tokenize(msobserver.selector);for(var i=0;i<token.length;i++){for(var j=0;j<token[i].length;j++){if(combinators.indexOf(token[i][j].type)!=-1)msobserver.isCombinatorial=true;if(fraternisers.indexOf(token[i][j].type)!=-1)msobserver.isFraternal=true;if(complexTypes.indexOf(token[i][j].type)!=-1)msobserver.isComplex=true}}}var MutationSelectorObserver=function(selector,callback,options){this.selector=selector.trim();this.callback=callback;this.options=options;grok(this)};var msobservers=[];msobservers.initialize=function(selector,callback,options){var seen=[];var callbackOnce=function(){if(seen.indexOf(this)==-1){seen.push(this);$(this).each(callback)}};$(options.target).find(selector).each(callbackOnce);var msobserver=new MutationSelectorObserver(selector,callbackOnce,options);this.push(msobserver);var observer=new MutationObserver(function(mutations){var matches=[];for(var m=0;m<mutations.length;m++){if(mutations[m].type=="attributes"){if(mutations[m].target.matches(msobserver.selector))matches.push(mutations[m].target);if(msobserver.isFraternal)matches.push.apply(matches,mutations[m].target.parentElement.querySelectorAll(msobserver.selector));else matches.push.apply(matches,mutations[m].target.querySelectorAll(msobserver.selector))}if(mutations[m].type=="childList"){for(var n=0;n<mutations[m].addedNodes.length;n++){if(!(mutations[m].addedNodes[n]instanceof Element))continue;if(mutations[m].addedNodes[n].matches(msobserver.selector))matches.push(mutations[m].addedNodes[n]);if(msobserver.isFraternal)matches.push.apply(matches,mutations[m].addedNodes[n].parentElement.querySelectorAll(msobserver.selector));else matches.push.apply(matches,mutations[m].addedNodes[n].querySelectorAll(msobserver.selector))}}}for(var i=0;i<matches.length;i++)$(matches[i]).each(msobserver.callback)});var defaultObeserverOpts={childList:true,subtree:true,attributes:msobserver.isComplex};observer.observe(options.target,options.observer||defaultObeserverOpts);return observer};$.fn.initialize=function(callback,options){return msobservers.initialize(this.selector,callback,$.extend({},$.initialize.defaults,options))};$.initialize=function(selector,callback,options){return msobservers.initialize(selector,callback,$.extend({},$.initialize.defaults,options))};$.initialize.defaults={target:document.documentElement,observer:null}})(jQuery);

152
js/util.js Normal file
View File

@@ -0,0 +1,152 @@
const days = new Map([
["M", "Monday"],
["T", "Tuesday"],
["W", "Wednesday"],
["TH", "Thursday"],
["F", "Friday"]
]);
const semOrder = {
"Spring": 0,
"Fall": 1,
"Summer": 2,
"Winter": 3
}
function buildQuery(course_data, sem) {
let query = !sem ? "select * from agg" : "select * from grades";
query += " where dept like '%" + course_data["department"] + "%'";
query += " and prof like '%" + course_data["prof_name"].replace(/'/g, "") + "%'";
query += " and course_nbr like '%" + course_data["number"] + "%'";
if (sem) {
query += "and sem like '%" + sem + "%'";
}
return query + "order by a1+a2+a3+b1+b2+b3+c1+c2+c3+d1+d2+d3+f desc";
}
function semesterSort(semA, semB) {
let aName = semA.split(' ')[0];
let aYear = parseInt(semA.split(' ')[1]);
let bName = semB.split(' ')[0];
let bYear = parseInt(semB.split(' ')[1]);
if (aYear < bYear)
return -1;
if (aYear > bYear)
return 1;
if (semOrder[aName] < semOrder[bName])
return -1;
if (semOrder[aName] > semOrder[bName])
return 1;
return 0;
}
function buildChartConfig(data) {
return {
chart: {
type: 'column',
backgroundColor: ' #fefefe',
spacingLeft: 10
},
title: {
text: null
},
subtitle: {
text: null
},
legend: {
enabled: false
},
xAxis: {
title: {
text: 'Grades'
},
categories: [
'A',
'A-',
'B+',
'B',
'B-',
'C+',
'C',
'C-',
'D+',
'D',
'D-',
'F'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Students'
}
},
credits: {
enabled: false
},
lang: {
noData: "The professor hasn't taught this class :("
},
tooltip: {
headerFormat: '<span style="font-size:small; font-weight:bold">{point.key}</span><table>',
pointFormat: '<td style="color:{black};padding:0;font-size:small; font-weight:bold;"><b>{point.y:.0f} Students</b></td>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
bar: {
pointPadding: 0.2,
borderWidth: 0
},
series: {
animation: {
duration: 700
}
}
},
series: [{
name: 'Grades',
data: [{
y: data[6],
color: '#4CAF50'
}, {
y: data[7],
color: '#8BC34A'
}, {
y: data[8],
color: '#CDDC39'
}, {
y: data[9],
color: '#FFEB3B'
}, {
y: data[10],
color: '#FFC107'
}, {
y: data[11],
color: '#FFA000'
}, {
y: data[12],
color: '#F57C00'
}, {
y: data[13],
color: '#FF5722'
}, {
y: data[14],
color: '#FF5252'
}, {
y: data[15],
color: '#E64A19'
}, {
y: data[16],
color: '#F44336'
}, {
y: data[17],
color: '#D32F2F'
}]
}]
}
}

241
js/utplanner.js Normal file
View File

@@ -0,0 +1,241 @@
if ($('html').hasClass('gr__utexas_collegescheduler_com')) {
$.initialize("table.section-detail-grid", function () {
$(this).find('thead>tr').append('<th> Plus</th')
$(this).find('tbody>tr').each(function () {
$(this).append(`<td data-th="Plus"><input type="image" class="distButton" id="distButton" style="vertical-align: bottom;" width="20" height="20" src='${chrome.extension.getURL('images/disticon.png')}'/></td>`);
})
});
}
curr_course = {}
var modhtml = `<div class=modal id=myModal>
<div class=modal-content>
<span class=close>×</span>
<div class=card>
<div class=cardcontainer>
<h2 class=title id="title">Computer Fluency (C S 302)</h2>
<h2 class=profname id="profname">with Bruce Porter</h2>
<div id="topbuttons" class=topbuttons>
<button class=matbut id="rateMyProf" style="background: #4CAF50;"> RMP </button>
<button class=matbut id="eCIS" style="background: #CDDC39;"> eCIS </button>
<button class=matbut id="Syllabi"> Past Syllabi </button>
</div>
</div>
</div>
<div class=card style='text-align:center'>
<select id="semesters" style='text-align-last:center;color:#666666;fill:#666666;'></select>
<div class="loader" id='loader' style="position:absolute;"></div>
<div id="chartcontainer" class=cardcontainer>
<div id=chart></div>
</div>
</div>
</div>
</div>`;
$("body").prepend(modhtml);
$("body").on('click', '#distButton', function () {
var row = $(this).closest('tr');
console.log(row.text())
$('.modal-content').stop().animate({
scrollTop: 0
}, 500);
$(this).blur();
getCourseInfo(row)
});
function getCourseInfo(row) {
let rowdata = $(row).find('td').slice(3).toArray().map(x => $(x).text().trim());
let [uniquenum, department, coursenum, coursename, profname, notes, rawtime] = rowdata
let profinit = ""
if (profname !== undefined && profname != "Staff") {
profinit = profname.split(',')[1].trim();
profname = profname.split(',')[0].trim();
}
let times = rawtime.split('\n').map(x => x.trim());
var course_data = {
"unique": uniquenum,
"department": department,
"number": coursenum,
"name": coursename,
"prof_name": profname,
"initial": profinit,
"notes": notes,
"times": times,
}
curr_course = course_data;
getDistribution(course_data);
var modal = document.getElementById('myModal');
window.onclick = function (event) {
if (event.target == modal) {
close();
}
}
}
function badData(course_data, res) {
return typeof res == 'undefined' || course_data["prof_name"] == "Staff";
}
$("#semesters").on('change', function () {
var sem = $(this).val();
sem = sem == "Aggregate" ? undefined : sem;
getDistribution(curr_course, sem);
});
function showLoading(loading) {
if (loading) {
$('#loader').css('display', 'inline-block');
$("#chart").hide();
} else {
$('#loader').hide();
$("#chart").show();
}
}
function openDialog(course_data, res) {
$("#title").text(buildTitle(course_data))
$("#topbuttons").before(buildTimeTitle(course_data["times"]));
$("#profname").text(buildProfTitle(course_data));
$("#myModal").fadeIn(fadetime);
buildSemestersDropdown(course_data, res)
var data;
if (badData(course_data, res)) {
data = [];
} else {
data = res.values[0];
}
setChart(data);
}
function buildProfTitle(course_data) {
const {
initial,
prof_name
} = course_data;
return `with ${initial?initial+". ":""}${prof_name}`;
}
function buildSemestersDropdown(course_data, res) {
$("#semesters").empty();
if (badData(course_data, res)) {
$("#semesters").append("<option>No Data</option>")
} else {
var semesters = res.values[0][18].split(",");
semesters.sort(semesterSort);
semesters.reverse().unshift('Aggregate');
var sems = [];
for (var i = 0; i < semesters.length; i++) {
sems.push($(`<option value="${semesters[i]}">${semesters[i]}</option>`));
}
$("#semesters").append(sems);
}
}
/*Query the grades database*/
function getDistribution(course_data, sem) {
showLoading(true);
let query = buildQuery(course_data, sem);
chrome.runtime.sendMessage({
command: "gradesQuery",
query: query
}, function (response) {
var res = response.data;
if (!sem) {
openDialog(course_data, res);
} else {
var data = badData(course_data, res) ? [] : res.values[0];
setChart(data);
}
});
}
function buildTitle(course_data) {
return `${course_data["name"]} (${course_data["department"]} ${course_data["number"]})`
}
function buildTimeTitle(times) {
$("h2.dateTimePlace").remove();
var lines = []
for (var i = 0; i < times.length; i++) {
date = times[i].substring(0, times[i].indexOf(' ')).toUpperCase();
time = times[i].substring(times[i].indexOf(' ') + 1, times[i].lastIndexOf('-')).trim();
place = times[i].substring(times[i].lastIndexOf('-') + 1).trim();
lines.push($(`<h2 class="dateTimePlace">${makeLine(date, time, place)}</th>`));
}
return lines
}
function close() {
$("#myModal").fadeOut(fadetime);
}
function makeLine(date, time, place) {
var arr = seperateDays(date)
var output = prettifyDaysText(arr)
var building = place.substring(0, place.search(/\d/) - 1);
building = building == "" ? "Undecided Location" : building;
return `${output} at ${time.replace(/\./g, '').replace(/\-/g, ' to ')} in <a style='font-size:medium' target='_blank' href='https://maps.utexas.edu/buildings/UTM/${building}'>${building}</>`;
}
function seperateDays(date) {
let arr = [];
for (var i = 0; i < date.length; i++) {
let letter = date.charAt(i);
if (letter == "T" && i < date.length - 1 && date.charAt(i + 1) == "H") {
arr.push(days.get("TH"));
} else {
if (letter != "H") {
arr.push(days.get(letter));
}
}
}
return arr;
}
function prettifyDaysText(arr) {
var output = "";
if (arr.length > 2) {
for (var i = 0; i < arr.length; i++) {
if (i < arr.length - 1)
output += arr[i] + ", "
if (i == arr.length - 2)
output += "and ";
if (i == arr.length - 1)
output += arr[i];
}
} else if (arr.length == 2) {
output = arr[0] + " and " + arr[1];
} else {
output = arr[0];
}
return output
}
function setChart(data) {
//set up the chart
showLoading(false);
chart = Highcharts.chart('chart', buildChartConfig(data), function (chart) { // on complete
if (data.length == 0) {
//if no data, then show the message and hide the series
chart.renderer.text('Could not find data for this Instructor teaching this Course.', 100, 120)
.css({
fontSize: '20px',
width: '300px',
align: 'center',
left: '160px'
})
.add();
$.each(chart.series, function (i, ser) {
ser.hide();
});
}
});
}

View File

@@ -9,14 +9,21 @@
"declarativeContent", "declarativeContent",
"storage", "storage",
"*://*.utdirect.utexas.edu/apps/registrar/course_schedule/*", "*://*.utdirect.utexas.edu/apps/registrar/course_schedule/*",
"*://*.utexas.collegescheduler.com/*",
"*://*.catalog.utexas.edu/ribbit/", "*://*.catalog.utexas.edu/ribbit/",
"*://*.registrar.utexas.edu/schedules/*", "*://*.registrar.utexas.edu/schedules/*",
"*://*.login.utexas.edu/login/*" "*://*.login.utexas.edu/login/*"
], ],
"content_scripts": [{ "content_scripts": [{
"css": ["css/styles.css"], "css": ["css/styles.css"],
"js": ["js/moment.min.js", "js/sql-memory-growth.js", "js/highcharts.js", "js/jquery-3.3.1.min.js", "js/content.js"], "js": ["js/moment.min.js", "js/highcharts.js", "js/jquery-3.3.1.min.js", "js/jquery.initialize.min.js", "js/config.js", "js/util.js",
"js/content.js"
],
"matches": ["https://utdirect.utexas.edu/apps/registrar/course_schedule/*"] "matches": ["https://utdirect.utexas.edu/apps/registrar/course_schedule/*"]
}, {
"css": ["css/styles.css"],
"js": ["js/moment.min.js", "js/highcharts.js", "js/jquery-3.3.1.min.js", "js/jquery.initialize.min.js", "js/config.js", "js/util.js", "js/utplanner.js"],
"matches": ["https://utexas.collegescheduler.com/*"]
}, { }, {
"css": ["css/styles.css"], "css": ["css/styles.css"],
"js": ["js/moment.min.js", "js/sql-memory-growth.js", "js/highcharts.js", "js/jquery-3.3.1.min.js", "js/import.js"], "js": ["js/moment.min.js", "js/sql-memory-growth.js", "js/highcharts.js", "js/jquery-3.3.1.min.js", "js/import.js"],
@@ -26,7 +33,7 @@
"grades.db", "images/disticon.png" "grades.db", "images/disticon.png"
], ],
"background": { "background": {
"scripts": ["js/jquery-3.3.1.min.js", "js/background.js", "js/moment.min.js"], "scripts": ["js/jquery-3.3.1.min.js", "js/sql-memory-growth.js", "js/background.js", "js/moment.min.js"],
"persistent": true "persistent": true
}, },
"browser_action": { "browser_action": {