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
|
// ==UserScript==
// @name University of Toronto Arts & Science Exam Schedule Filter
// @namespace https://alxu.ca/
// @match http://www.artsci.utoronto.ca/current/exams/*
// @version 1.0
// @grant none
// @downloadURL https://alxu.ca/uoft-artsci-exam-filter.user.js
// @require https://www.kryogenix.org/code/browser/sorttable/sorttable.js#sha512=33bdc388d816cab2190ee33918143074a3d1bc8da315b0d6117eb8233d8a7ed51752aa26419296c06120c6faee6053d4589fca2a7590846139d69e84cb600808
// @run-at document-end
// ==/UserScript==
/*
* Copyright 2017 Alex Xu, released under GPLv3 or later
*
* Firefox: Install Greasemonkey: https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/ then (re-)open this file.
* Chrome: Install Tampermonkey: https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo then (re-)open this file.
* Note that installing this script directly will also work, but sorting will not be supported, and in addition, on Windows/Mac the script will be automatically and permanently disabled once Chrome restarts.
*/
(function () {
"use strict";
if (document.title.indexOf("Timetable") === -1)
return;
var tbl = document.getElementsByClassName("vertical")[0],
trs = tbl.querySelectorAll("tr:not(:first-child)");
var storage = localStorage.getItem("filterinfo");
if (storage)
try {
storage = JSON.parse(storage);
} catch (e) {
if (!(e instanceof SyntaxError))
throw e;
}
if (!storage)
storage = {};
var parseCourses = function (mycoursesstr) {
var mycourses = {names: [], sections: []};
mycoursesstr.split(/[ ,;]/).forEach(function (c) {
// merge multiple delimiters
if (!c)
return;
var cspl = c.split(/[\/:]/);
if (cspl[1])
mycourses.sections[mycourses.names.length] = cspl[1].toUpperCase();
mycourses.names.push(cspl[0].toUpperCase());
});
return mycourses;
};
// the meat.
var dofilter = function (myname, mycourses) {
var getCI = function (name) {
return mycourses.names.findIndex(function (mycname) {
return name.indexOf(mycname) > -1;
});
};
var checkCourse = function (tr) {
var ch = tr.children,
s = ch[1].innerHTML;
// if we don't have any courses, match everything instead of nothing
if (mycourses.names.length) {
var courseindex = getCI(ch[0].innerHTML);
if (courseindex === -1)
return false;
var l = s.match(/L?[0-9]+/);
if (l && mycourses.sections[courseindex] && l[0].indexOf(mycourses.sections[courseindex]) === -1)
return false;
}
if (myname) {
var nr = s.match(/([A-Z]+) - ([A-Z]+)/);
if (nr && (myname < nr[1] || myname > nr[2]))
return false;
}
return true;
};
for (var i = trs.length - 1; i >= 0; i--) {
trs[i].style.display = checkCourse(trs[i]) ? '' : 'none';
}
};
var ourctnr = document.createElement("div");
ourctnr.appendChild(document.createTextNode("Filter by name: "));
var makeInput = function (attr, size) {
var input = document.createElement("input");
input.type = "text";
input.size = size;
if (storage[attr])
input.value = storage[attr];
input.addEventListener("input", function () {
storage[attr] = this.value.toUpperCase();
// in theory we could cache this, but it's fast enough
dofilter(storage.name, parseCourses(storage.courses));
localStorage.setItem("filterinfo", JSON.stringify(storage));
}, false);
ourctnr.appendChild(input);
};
makeInput("name", "4");
ourctnr.appendChild(document.createTextNode(", courses: "));
makeInput("courses", "50");
ourctnr.appendChild(document.createElement("br"));
ourctnr.appendChild(document.createTextNode("Courses should be separated by spaces and sections preceded by slash."));
ourctnr.appendChild(document.createElement("br"));
ourctnr.appendChild(document.createTextNode("Example: ABC101 XYZ201/L0301"));
tbl.parentNode.insertBefore(ourctnr, tbl);
if (storage.name || storage.courses)
window.requestAnimationFrame(function () {
dofilter(storage.name, parseCourses(storage.courses));
if (typeof sorttable !== "undefined") {
sorttable.init();
sorttable.makeSortable(tbl);
sorttable.innerSortFunction.apply(tbl.getElementsByTagName("th")[2], []);
}
});
if (typeof sorttable !== "undefined")
for (var i = trs.length - 1; i >= 0; i--) {
var dateEl = trs[i].children[2],
dateSplit = dateEl.innerHTML.split(" "); // ["MON", "1", "JAN"]
dateEl.setAttribute("sorttable_customkey", dateSplit[2] + dateSplit[1]); // "JAN1"
}
}());
|