deleted everything lmao
This commit is contained in:
40
README.md
40
README.md
@@ -1,40 +0,0 @@
|
|||||||
|
|
||||||
# UT Registration Plus
|
|
||||||
## (or Sriram's Sexy Scheduling Script)
|
|
||||||
[Try it for yourself on the Chrome Web Store](https://chrome.google.com/webstore/detail/hboadpjkoaieogjimneceaahlppnipaa)
|
|
||||||
|
|
||||||
|
|
||||||
We've all been there. 20 tabs of Rate My Professor, Catalyst, and the UT Course Catalog open and you still don't know what classes to take.
|
|
||||||
This extension tries to streamline most of the unnecessary steps and headaches of registering for classes at UT Austin.
|
|
||||||
|
|
||||||
|
|
||||||
- For each class on the UT Course Catalog it provides a "breakdown" popup, with quick and easy links to the RateMyProfessor and eCIS pages of the professor, as well as syllabi from when the professor taught the class in the past.
|
|
||||||
|
|
||||||
- Gets the course description and highlight the important information like prerequisites, restrictions, etc.
|
|
||||||
|
|
||||||
- Shows an aggregate graph of the grade distributions for when the professor taught the class in the past.
|
|
||||||
|
|
||||||
- Gives you the ability to "Save Courses" and view them in the extension popup. This lets you see any schedule conflicts, and makes copy-pasting the unique code much easier when you're actually registering.
|
|
||||||
|
|
||||||
- Highlights and crosses-out what courses on the UT Course Catalog would conflict with your currently saved courses, making selecting courses that fit with your schedule so much easier.
|
|
||||||
|
|
||||||
- Display's a weekly schedule based on your saved courses
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://lh3.googleusercontent.com/X5hqHGPU-F2lF3_shT2injxd40eFYXLJfZVxpU1v2w1YvFRW1jQMEXu2yzWHKKpqn5huJL-NEHY=w640-h400-e365">
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://lh3.googleusercontent.com/ZCRxTFKFjpGm5ZRMv2iHzMqdnrQHUx_Ih_XhGhy2O4Yn29YccvU5yXXrWXKuVKsNAmEJJ0As4xc=w640-h400-e365">
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://lh3.googleusercontent.com/3iRi25wDnVqgzc7pnYUXQq1TvdPpAeDjCmIF9hLU-WKmlchEYQUh_xU-XV00fEbKUr2XVKGkOw=w640-h400-e365">
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://lh3.googleusercontent.com/x95blI5D1mseNPLOtHETlLmoVtHm0eeye9uyeWSDd5W6m6fSoZxMMMyQTGUFo5swoTgRivGVyw=w640-h400-e365">
|
|
||||||
</p>
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://lh3.googleusercontent.com/bbey8OGOTtJWUaHGVIU5wewbWg6X6s-gjD15RwXHhvgH_9kax2mE4bcrjem_iZGH-q5z6NT7g94=w640-h400-e365">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
# 2.0 coming soon....
|
|
||||||
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<!-- This file is the html file serving the "My Schedule / Calendar" page. -->
|
|
||||||
<head>
|
|
||||||
<link rel='stylesheet' href='css/fullcalendar.min.css' />
|
|
||||||
<link rel='stylesheet' href='css/_materialFullCalendar.css' />
|
|
||||||
<script src='js/lib/jquery-3.3.1.min.js'></script>
|
|
||||||
<script src='js/lib/moment.min.js'></script>
|
|
||||||
<script src='js/lib/fullcalendar.min.js'></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div style='display:flex'>
|
|
||||||
<div id='calendar' style="flex-grow: 1"></div>
|
|
||||||
<div class="card" id="header"
|
|
||||||
style="text-align:center;margin:5px 0px 0px 15px;display: inline-table;padding-bottom: 5px;">
|
|
||||||
<h1 id='hours'
|
|
||||||
style="font-size:30px;font-weight:500; border-bottom: 3px solid black;display: inline-block;padding-bottom: 5px;margin-bottom: 5px;">
|
|
||||||
0
|
|
||||||
hours</h1>
|
|
||||||
<h1 id='num' style="font-size:20px;font-weight:500; margin: 2px;">0
|
|
||||||
Courses</h1>
|
|
||||||
<br>
|
|
||||||
<div style="margin:5px;display: flex;flex-direction: column;">
|
|
||||||
<button id="clear" class="matbut"
|
|
||||||
style="font-size:medium; background:#4CAF50;margin: 10px;white-space: nowrap;text-align: center;">Clear
|
|
||||||
All</button>
|
|
||||||
<button id="save" class="matbut"
|
|
||||||
style="font-size:medium; background:#FF9800;margin: 10px;white-space: nowrap;text-align: center;">Save
|
|
||||||
as PNG</button>
|
|
||||||
<button id="export" class="matbut"
|
|
||||||
style="font-size:medium; background:#FF0000;margin: 10px;white-space: nowrap;text-align: center;">Export
|
|
||||||
Cal</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
<script src='js/config.js'></script>
|
|
||||||
<script src='js/lib/html2canvas.min.js'></script>
|
|
||||||
<script src='js/lib/ics.min.js'></script>
|
|
||||||
<script src='js/Template.js'></script>
|
|
||||||
<script src='js/util.js'></script>
|
|
||||||
<script src='js/calendar.js'></script>
|
|
||||||
@@ -1,344 +0,0 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
This is the Material Design theme for FullCalendar Weekly Agenda view
|
|
||||||
|
|
||||||
Creation Date: Aug 19th 2015
|
|
||||||
Author: Jacky Liang
|
|
||||||
Version: FullCalendar 2.4.0
|
|
||||||
Tested Using the Following FC Settings:
|
|
||||||
|
|
||||||
editable: false,
|
|
||||||
handleWindowResize: true,
|
|
||||||
weekends: false, // Hide weekends
|
|
||||||
defaultView: 'agendaWeek', // Only show week view
|
|
||||||
header: false, // Hide buttons/titles
|
|
||||||
minTime: '07:30:00', // Start time for the calendar
|
|
||||||
maxTime: '22:00:00', // End time for the calendar
|
|
||||||
columnFormat: {
|
|
||||||
week: 'ddd' // Only show day of the week names
|
|
||||||
},
|
|
||||||
displayEventTime: true,
|
|
||||||
allDayText: 'Online/TBD'
|
|
||||||
|
|
||||||
Note: This has NOT been tested on Monthly or Daily views.
|
|
||||||
|
|
||||||
Colors: Use the following - https://www.google.com/design/spec/style/color.html#color-color-palette
|
|
||||||
at the 700 level. An opacity of 0.65 is automatically applied to the
|
|
||||||
700 level colors to generate a soft and pleasing look.
|
|
||||||
|
|
||||||
Color were applied to each event using the following code:
|
|
||||||
|
|
||||||
events.push({
|
|
||||||
title: 'This is a Material Design event!',
|
|
||||||
start: 'someStartDate',
|
|
||||||
end: 'someEndDate',
|
|
||||||
color: '#C2185B'
|
|
||||||
});
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
.fc-state-highlight {
|
|
||||||
opacity: 0;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styling for each event from Schedule */
|
|
||||||
|
|
||||||
.fc-time-grid-event.fc-v-event.fc-event {
|
|
||||||
border-radius: 4px;
|
|
||||||
border: none;
|
|
||||||
padding: 5px;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.3);
|
|
||||||
transition: 0.3s;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.html2canvas-container {
|
|
||||||
width: 3000px !important;
|
|
||||||
height: 3000px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.fc-time-grid-event.fc-v-event.fc-event:hover {
|
|
||||||
box-shadow: 0 8px 12px 0 rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bolds the name of the event and inherits the font size */
|
|
||||||
|
|
||||||
.fc-event {
|
|
||||||
font-size: small !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove the header border from Schedule */
|
|
||||||
|
|
||||||
.fc td,
|
|
||||||
.fc th {
|
|
||||||
border-style: ridge !important;
|
|
||||||
border-width: 1px !important;
|
|
||||||
padding: 4px 3px 0px 3px !important;
|
|
||||||
vertical-align: top !important;
|
|
||||||
border-left-width: 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-row fc-widget-header {
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc td {
|
|
||||||
border-top-width: 0;
|
|
||||||
padding: 3px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-widget-header {
|
|
||||||
background-color: #cc5500;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inherits background for each event from Schedule. */
|
|
||||||
|
|
||||||
.fc-event .fc-bg {
|
|
||||||
z-index: 1 !important;
|
|
||||||
background: inherit !important;
|
|
||||||
opacity: 0.25 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Normal font weight for the time in each event */
|
|
||||||
|
|
||||||
.fc-time-grid-event .fc-time {
|
|
||||||
font-weight: normal !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply same opacity to all day events */
|
|
||||||
|
|
||||||
.fc-ltr .fc-h-event.fc-not-end,
|
|
||||||
.fc-rtl .fc-h-event.fc-not-start {
|
|
||||||
opacity: 0.65 !important;
|
|
||||||
margin-left: 12px !important;
|
|
||||||
padding: 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply same opacity to all day events */
|
|
||||||
|
|
||||||
.fc-day-grid-event.fc-h-event.fc-event.fc-not-start.fc-end {
|
|
||||||
opacity: 0.65 !important;
|
|
||||||
margin-left: 12px !important;
|
|
||||||
padding: 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Material design button */
|
|
||||||
|
|
||||||
.matbut {
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
|
||||||
margin: 10px 10px 10px 0px;
|
|
||||||
padding: 10px 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: medium;
|
|
||||||
font-style: bold;
|
|
||||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.matbut {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.matbut:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 100%;
|
|
||||||
transform: scale(1, 1) translate(-50%);
|
|
||||||
transform-origin: 50% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ripple {
|
|
||||||
0% {
|
|
||||||
transform: scale(0, 0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
20% {
|
|
||||||
transform: scale(25, 25);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(40, 40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.matbut:focus:not(:active)::after {
|
|
||||||
animation: ripple 1s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-button {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
min-height: 36px;
|
|
||||||
min-width: 88px;
|
|
||||||
line-height: 36px;
|
|
||||||
vertical-align: middle;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-webkit-align-items: center;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 2px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
outline: none;
|
|
||||||
border: 0;
|
|
||||||
padding: 0 6px;
|
|
||||||
margin: 6px 8px;
|
|
||||||
letter-spacing: 0.01em;
|
|
||||||
background: transparent;
|
|
||||||
color: currentColor;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
|
||||||
font-style: inherit;
|
|
||||||
font-variant: inherit;
|
|
||||||
font-family: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
overflow: hidden;
|
|
||||||
-webkit-transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
||||||
transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-button:hover {
|
|
||||||
background-color: rgba(158, 158, 158, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-button:focus,
|
|
||||||
.fc-button:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The active button box is ugly so the active button will have the same appearance of the hover */
|
|
||||||
|
|
||||||
.fc-state-active {
|
|
||||||
background-color: rgba(158, 158, 158, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not raised button */
|
|
||||||
|
|
||||||
.fc-state-default {
|
|
||||||
box-shadow: None;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1;
|
|
||||||
padding-top: 300px;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgb(0, 0, 0);
|
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#classname {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: -10px;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: #fefefe;
|
|
||||||
margin: auto;
|
|
||||||
max-height: 85%;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 15px;
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: 35%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#prof {
|
|
||||||
font-size: medium;
|
|
||||||
margin-bottom: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#info {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body a:link,
|
|
||||||
body a:visited {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #3c87a3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-size: medium;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc td,
|
|
||||||
.fc th {
|
|
||||||
border-color: #E7E7E7;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-time-grid .fc-slats td {
|
|
||||||
height: 1.5em;
|
|
||||||
border-bottom: initial;
|
|
||||||
border-color: #E7E7E7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Close Button */
|
|
||||||
|
|
||||||
.close {
|
|
||||||
color: #aaaaaa;
|
|
||||||
float: right;
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close:hover,
|
|
||||||
.close:focus {
|
|
||||||
color: #000;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
transition: 0.3s;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.cardcontainer {
|
|
||||||
padding: 2px 16px;
|
|
||||||
display: block;
|
|
||||||
transition: width 300ms ease-in-out, height 300ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tbody {
|
|
||||||
border-width: 0px;
|
|
||||||
}
|
|
||||||
5
css/fullcalendar.min.css
vendored
5
css/fullcalendar.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,81 +0,0 @@
|
|||||||
.version {
|
|
||||||
padding: 0px 5px 5px 0px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.creator-tag {
|
|
||||||
margin: 10px 5px 5px 0px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options-card {
|
|
||||||
width: 400px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
height: auto;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#version-container {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options-header {
|
|
||||||
padding: 16px 16px 0px 16px;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#contributors_container {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 30;
|
|
||||||
padding: 5px 20px 20px 20px;
|
|
||||||
width: auto;
|
|
||||||
margin-right: 20%;
|
|
||||||
margin-left: 20%;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#contributor-list {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 1rem;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.contributor-card {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 5px;
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
text-align: center;
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contributor-card img {
|
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contributor-name {
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contributor-username {
|
|
||||||
margin: 0 0 5px 0;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contributor-title {
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.open-source-tag {
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
563
css/popup.css
563
css/popup.css
@@ -1,563 +0,0 @@
|
|||||||
.card {
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
transition: 0.3s;
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
padding: 3px 16px 3px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
padding: 10px 0px 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
width: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
min-width: 370px;
|
|
||||||
min-height: 400px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conflict_message{
|
|
||||||
font-size:small;
|
|
||||||
font-weight:bold;
|
|
||||||
color:red;
|
|
||||||
margin:5px 5px 5px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 5px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_card {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_item {
|
|
||||||
padding: 0px 5px 5px 5px;
|
|
||||||
overflow-y: auto;
|
|
||||||
max-height:400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_item_subtext {
|
|
||||||
font-size:medium;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty_message {
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: large;
|
|
||||||
margin: 60px 30px 200px 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#empty #main {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#empty span {
|
|
||||||
font-size: small;
|
|
||||||
display: table;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.time_line_days {
|
|
||||||
display:inline-block;
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time_line_hours {
|
|
||||||
margin-left:10px;
|
|
||||||
display:inline-block;
|
|
||||||
width: 50%;
|
|
||||||
text-align:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time_line_location {
|
|
||||||
float:right;
|
|
||||||
display:inline-block;
|
|
||||||
text-align:right;
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.time_line_location_link {
|
|
||||||
color:#3c87a3;
|
|
||||||
text-decoration:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more_info_button{
|
|
||||||
background: #2196F3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remove_button {
|
|
||||||
background: #F44336;
|
|
||||||
}
|
|
||||||
|
|
||||||
.register_button {
|
|
||||||
background: #4CAF50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings_button {
|
|
||||||
margin-right: 2px;
|
|
||||||
border: 0px;
|
|
||||||
border-radius: 50%;
|
|
||||||
transition: 0.3s;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.settings_button:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings_button:hover {
|
|
||||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.16), 0 4px 15px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected {
|
|
||||||
box-shadow: 0 0 0 1pt #FF9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings_button:focus:after:hover {
|
|
||||||
outline: 0;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy_button {
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 0px;
|
|
||||||
border: none;
|
|
||||||
font-size: 15px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 50%;
|
|
||||||
transition: .2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy_button:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.16);
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
padding: 4px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy_button_icon {
|
|
||||||
color:white;
|
|
||||||
float:left;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 3px;
|
|
||||||
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.16);
|
|
||||||
font-size: x-large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header_container{
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header_buttons {
|
|
||||||
padding: 5px 10px 5px 10px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header_button {
|
|
||||||
font-size:15px !important;
|
|
||||||
margin: 7px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.clear_button {
|
|
||||||
background:#4CAF50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ris_button {
|
|
||||||
background:#FF9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.schedule_button {
|
|
||||||
background: #FF0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
display: flex;
|
|
||||||
vertical-align: middle;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
transition: 0.3s;
|
|
||||||
padding: 7px 5px 5px 7px;
|
|
||||||
margin: 0px 5px 0px 0px;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material_button {
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
|
||||||
margin: 10px 10px 10px 0px;
|
|
||||||
padding: 10px 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: medium;
|
|
||||||
font-style: bold;
|
|
||||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_name_truncate_box {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
width: 80%;
|
|
||||||
color:white;
|
|
||||||
margin:5px;
|
|
||||||
display:inline-block;
|
|
||||||
font-size:large;
|
|
||||||
align-items:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings_divider {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
display:inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search_button {
|
|
||||||
background-color:white;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
.course_list_item_options {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.import_button {
|
|
||||||
background-color:white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options_button {
|
|
||||||
background-color:white;
|
|
||||||
margin-right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings_icon {
|
|
||||||
color:#FF9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_item_time_box {
|
|
||||||
font-weight:bold;
|
|
||||||
padding:10px;
|
|
||||||
margin:0px 5px 0px 15px;
|
|
||||||
font-size:small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_item_options_button_container {
|
|
||||||
border-radius:0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course_list_item_options_buttons{
|
|
||||||
float:right;
|
|
||||||
margin:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
float:right;
|
|
||||||
font-size:small;
|
|
||||||
display:inline-block;
|
|
||||||
margin-top:10px;
|
|
||||||
color:white;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material_button:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 100%;
|
|
||||||
transform: scale(1, 1) translate(-50%);
|
|
||||||
transform-origin: 50% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 100%;
|
|
||||||
transform: scale(1, 1) translate(-50%);
|
|
||||||
transform-origin: 50% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1;
|
|
||||||
padding-top: 100px;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgb(0, 0, 0);
|
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: #fefefe;
|
|
||||||
margin: auto;
|
|
||||||
max-height: 85%;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Close Button */
|
|
||||||
|
|
||||||
.close {
|
|
||||||
color: #aaaaaa;
|
|
||||||
float: right;
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes ripple {
|
|
||||||
0% {
|
|
||||||
transform: scale(0, 0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
20% {
|
|
||||||
transform: scale(25, 25);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(40, 40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.material_button:focus:not(:active)::after {
|
|
||||||
animation: ripple 1s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.card:focus:not(:active)::after {
|
|
||||||
animation: ripple 1s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
input {
|
|
||||||
border-radius: 5px;
|
|
||||||
color: rgba(0, 0, 45, 0.48)
|
|
||||||
}
|
|
||||||
|
|
||||||
input:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=number]::-webkit-inner-spin-button,
|
|
||||||
input[type=number]::-webkit-outer-spin-button {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-popup {
|
|
||||||
background: white;
|
|
||||||
color: #747474;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
position: absolute;
|
|
||||||
margin: auto;
|
|
||||||
bottom: 42px;
|
|
||||||
right: 20px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: inherit;
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.flex-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-style {
|
|
||||||
border: 1px solid #979797;
|
|
||||||
margin: 5px 0px;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: none;
|
|
||||||
background: transparent no-repeat 90% 50%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-style:after {
|
|
||||||
content: '\e5c5';
|
|
||||||
font-family: 'Material Icons';
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
font-size: 24px;
|
|
||||||
color: rgba(0, 0, 45, 0.48);
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-style select {
|
|
||||||
padding: 5px 8px;
|
|
||||||
border: none;
|
|
||||||
color: rgba(0, 0, 45, 0.48);
|
|
||||||
box-shadow: none;
|
|
||||||
background: transparent;
|
|
||||||
background-image: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 120px;
|
|
||||||
word-break: normal;
|
|
||||||
-ms-word-break: normal;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-style select:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.class_id_input {
|
|
||||||
display: none;
|
|
||||||
border: 1px solid #979797;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin: 10px 0px;
|
|
||||||
padding: 5px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.class_id_input::placeholder {
|
|
||||||
color: rgba(0, 0, 45, 0.48);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-button {
|
|
||||||
float: right;
|
|
||||||
font-size: inherit;
|
|
||||||
padding: 7px 11px;
|
|
||||||
margin: 8px 0px;
|
|
||||||
background-color: #FF9800;
|
|
||||||
}
|
|
||||||
|
|
||||||
#import-export-popup {
|
|
||||||
background: white;
|
|
||||||
color: #747474;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
position: absolute;
|
|
||||||
margin: auto;
|
|
||||||
bottom: 42px;
|
|
||||||
right: 10px;
|
|
||||||
border-radius: inherit;
|
|
||||||
width: 140px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.simple-menu-option {
|
|
||||||
display: inline-block;
|
|
||||||
color: rgba(0, 0, 45, 0.48);
|
|
||||||
border: none;
|
|
||||||
background-color: white;
|
|
||||||
font-size: 15px;
|
|
||||||
overflow: hidden;
|
|
||||||
vertical-align: middle;
|
|
||||||
cursor: pointer;
|
|
||||||
text-align: left;
|
|
||||||
padding: 10px 0px 5px 5px;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simple-menu-option i {
|
|
||||||
font-size: 19px;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-top: 0px;
|
|
||||||
margin-left: 0px;
|
|
||||||
margin-right: 3px;
|
|
||||||
margin-bottom: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.simple-menu-option:hover {
|
|
||||||
background-color: rgba(177, 175, 175, 0.200);
|
|
||||||
transition-duration: 0.4s;
|
|
||||||
/* color: #FF9800; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.simple-menu-option:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hide {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta{
|
|
||||||
margin:0;
|
|
||||||
color:#FF9800;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding: 7px 5px 5px 7px;
|
|
||||||
margin: 0px 5px 0px 5px;
|
|
||||||
font-size: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-metric{
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-container{
|
|
||||||
margin: 5px 5px 10px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-box{
|
|
||||||
color: rgba(0, 0, 45, 0.48);
|
|
||||||
border: 1px solid #8C8C8C;
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 7px;
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-box::placeholder {
|
|
||||||
color: rgba(0, 0, 45, 0.345);
|
|
||||||
}
|
|
||||||
308
css/styles.css
308
css/styles.css
@@ -1,308 +0,0 @@
|
|||||||
.modal {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1;
|
|
||||||
padding-top: 75px;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgb(0, 0, 0);
|
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: #fefefe;
|
|
||||||
margin: auto;
|
|
||||||
max-height: 85%;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #888;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
border: 10px solid #f3f3f3;
|
|
||||||
border-top: 10px solid #FF9800;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
display: none;
|
|
||||||
animation: spin 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
color: #aaaaaa;
|
|
||||||
float: right;
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: x-large;
|
|
||||||
font-weight: bold;
|
|
||||||
padding-top: 5px;
|
|
||||||
line-height: 1;
|
|
||||||
padding-left: 5px;
|
|
||||||
margin: 5px 0px 5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.distButton {
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.chartloader {
|
|
||||||
position: absolute;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-top: 50px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profname {
|
|
||||||
margin-left: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
font-size: medium;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dateTimePlace {
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-bottom: 0px;
|
|
||||||
margin-top: 0px;
|
|
||||||
font-size: smaller;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#chartcontainer {
|
|
||||||
max-width: 100%;
|
|
||||||
height: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#chart {
|
|
||||||
min-width: auto;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 250px;
|
|
||||||
margin: 0 auto;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
transition: 0.3s;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.2), 0 4px 20px 0 rgba(0, 0, 0, 0.19);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardcontainer {
|
|
||||||
padding: 2px 16px;
|
|
||||||
transition: width 300ms ease-in-out, height 300ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close:hover,
|
|
||||||
.close:focus {
|
|
||||||
color: #000;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbuttons .material-button {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rmp-button {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.ecis-button {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.textbook-button{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-button {
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
|
||||||
margin: 10px 10px 10px 0px;
|
|
||||||
padding: 10px 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: medium;
|
|
||||||
font-style: bold;
|
|
||||||
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
|
|
||||||
background: #ff9800;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-button:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
opacity: 0;
|
|
||||||
border-radius: 100%;
|
|
||||||
transform: scale(1, 1) translate(-50%);
|
|
||||||
transform-origin: 50% 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ripple {
|
|
||||||
0% {
|
|
||||||
transform: scale(0, 0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
15% {
|
|
||||||
transform: scale(25, 25);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(40, 40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.material-button:focus:not(:active)::after {
|
|
||||||
animation: ripple 1s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#snackbar {
|
|
||||||
visibility: hidden;
|
|
||||||
min-width: 250px;
|
|
||||||
margin-left: -200px;
|
|
||||||
background-color: #333;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 16px;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1;
|
|
||||||
left: 50%;
|
|
||||||
bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.descriptionli {
|
|
||||||
padding: 0px 5px 5px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#snackbar.show {
|
|
||||||
visibility: visible;
|
|
||||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
|
||||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
#semesters {
|
|
||||||
padding: 5px;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#semesters:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .tooltiptext {
|
|
||||||
visibility: hidden;
|
|
||||||
background-color: black;
|
|
||||||
background:rgba(1,1,1,0.5);
|
|
||||||
color: #fff;
|
|
||||||
text-align: left;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 10px;
|
|
||||||
max-width: 100px;
|
|
||||||
margin-left: 5px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
z-index: 2;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip:hover .tooltiptext {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@-webkit-keyframes fadein {
|
|
||||||
from {
|
|
||||||
bottom: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
bottom: 30px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadein {
|
|
||||||
from {
|
|
||||||
bottom: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
bottom: 30px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes fadeout {
|
|
||||||
from {
|
|
||||||
bottom: 30px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
bottom: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeout {
|
|
||||||
from {
|
|
||||||
bottom: 30px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
bottom: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
theme: jekyll-theme-cayman
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["ACC","ADV","ASE","AFR","AFS","ASL","AMS","AHC","ANT","ALD","ARA","ARE","ARI","ARC","AED","ARH","ART","AET","AAS","ANS","AST","BSN","BEN","BCH","BIO","BME","BDP","B A","BAX","BGS","CHE","CH","CHI","C E","CLA","C C","CGS","COM","CLD","CMS","CRP","C L","COE","CSE","C S","CON","CTI","CRW","CDI","EDC","CZ","DAN","DSC","D S","DES","DEV","D B","DRS","DCH","ECO","ELP","EDP","E E","ECE","EER","EMA","ENM","E M","E S","E","ESL","ENS","EVE","EVS","EUP","EUS","FIN","F A","FLU","FR","F H","G E","GRG","GEO","GER","GSD","GOV","GRS","GK","GUI","HAR","H S","HCT","HED","HEB","HIN","HIS","HDF","HDO","H E","HMN","ILA","I","ISP","INF","ITD","I B","IRG","ISL","ITL","ITC","JPN","J S","J","KIN","KOR","LAR","LTC","LAT","LAL","LAS","LAW","LEB","L A","LAH","LIN","MAL","MAN","MIS","MFG","MNS","MKT","MSE","M","M E","MDV","MAS","MEL","MES","M S","MOL","MUS","NSC","N S","NEU","NOR","N","NTR","OBO","OPR","O M","ORI","ORG","PER","PRS","PGE","PGS","PHM","PHL","PED","P S","PHY","PIA","POL","POR","PRC","PSY","P A","PBH","P R","RIM","RTF","R E","R S","RHE","R M","RUS","REE","SAN","SAX","STC","STM","S C","SEL","S S","S W","SOC","SPN","SPC","SED","SLH","STA","SDS","SUS","SWE","TAM","TXA","T D","TRO","TRU","TBA","TUR","T C","UKR","UGS","UDN","URB","URD","UTS","UTL","VIA","VIO","V C","VAS","VOI","WGS","WRT","YID","YOR"]
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB |
BIN
icons/icon16.png
BIN
icons/icon16.png
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
BIN
icons/icon32.png
BIN
icons/icon32.png
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
BIN
icons/icon48.png
BIN
icons/icon48.png
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.5 KiB |
196
js/Template.js
196
js/Template.js
@@ -1,196 +0,0 @@
|
|||||||
class Template {}
|
|
||||||
|
|
||||||
Template.Main = class {
|
|
||||||
static modal() {
|
|
||||||
return `<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 <a id="professor_link">Bruce Porter</a></h2>
|
|
||||||
<div id="topbuttons" class=topbuttons>
|
|
||||||
<button class=material-button id="rateMyProf" style="background: #4CAF50;"> RMP </button>
|
|
||||||
<button class=material-button id="eCIS" style="background: #CDDC39;"> eCIS </button>
|
|
||||||
<button class=material-button id="textbook" style="background: #FFC107;"> Textbook </button>
|
|
||||||
<button class=material-button id="Syllabi"> Past Syllabi </button>
|
|
||||||
<button class=material-button id="saveCourse" value="add" style="background: #F44336;"> Save Course +</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class=card>
|
|
||||||
<div class=cardcontainer style="">
|
|
||||||
<div class="chartloader">
|
|
||||||
<div class="loader" id='descload'></div>
|
|
||||||
</div>
|
|
||||||
<ul class=description id="description" style="list-style-type:disc"></ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class=card style='text-align:center'>
|
|
||||||
<select id="semesters" style='text-align-last:center;color:#666666;fill:#666666;'>
|
|
||||||
</select>
|
|
||||||
<div class="chartloader">
|
|
||||||
<div class="loader" id='chartload'></div>
|
|
||||||
</div>
|
|
||||||
<div id="chartcontainer" class=cardcontainer>
|
|
||||||
<div id=chart></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
static extension_button() {
|
|
||||||
return `<td data-th="Plus"><input type="image" class="distButton" id="distButton" width="20" height="20" src='${chrome.extension.getURL("images/disticon.png")}'/></td>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Template.Catalog = class {
|
|
||||||
static loading() {
|
|
||||||
return `<div style="text-align:center">
|
|
||||||
<div class="loader" id='loader'></div>
|
|
||||||
<br>
|
|
||||||
<h1 id="nextlabel"style="color: #FF9800;display:none;">Loading Courses</h1>
|
|
||||||
<h1 id="retrylabel"style="color: #F44336;display:none;">Failed to Load Courses</h1>
|
|
||||||
<br>
|
|
||||||
<button class=material-button id="retry" style="background: #F44336;display:none;">Retry</button>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Template.UTPlanner = class {
|
|
||||||
static modal() {
|
|
||||||
return `<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" style="margin-bottom:0px;">with Bruce Porter</h2>
|
|
||||||
<div id="topbuttons" class=topbuttons>
|
|
||||||
<button class=material-button id="moreInfo" style="background: #2196F3;"> More Info </button>
|
|
||||||
<button class=material-button id="textbook" style="background: #FFC107;"> Textbook </button>
|
|
||||||
<button class=material-button id="Syllabi"> Past Syllabi </button>
|
|
||||||
<button class=material-button id="saveCourse" value="add" style="background: #F44336;opacity:.4;"> Unable to Save</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="chartloader">
|
|
||||||
<div class="loader" id='chartload'></div>
|
|
||||||
</div>
|
|
||||||
<div id="chartcontainer" class=cardcontainer>
|
|
||||||
<div id=chart></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Template.Calendar = class {
|
|
||||||
static line(line) {
|
|
||||||
let { days, start_time, end_time, location_link, location_full } = line;
|
|
||||||
return `<p class='time' style='font-size:large;'>
|
|
||||||
<span style='display:inline-block;'>${days}:</span>
|
|
||||||
<span style='margin-left:10px;display:inline-block;text-align:center;'>${start_time} to ${end_time}</span>
|
|
||||||
<span style='float:right;display:inline-block;text-align:right;width: 25%;'>
|
|
||||||
<a target='_blank' style='color:#3c87a3;text-decoration:none;'href='${location_link}'>${location_full}</a>
|
|
||||||
</span>
|
|
||||||
</p>`;
|
|
||||||
}
|
|
||||||
static modal() {
|
|
||||||
return `<div id="myModal" class="modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<span class="close">×</span>
|
|
||||||
<div class="card">
|
|
||||||
<div id="colorStrip" style="height:10px;"></div>
|
|
||||||
<div class="cardcontainer">
|
|
||||||
<div id='header'>
|
|
||||||
<div style="display:flex;">
|
|
||||||
<h2 id="classname">Classname</h2>
|
|
||||||
</div>
|
|
||||||
<p id="prof">Prof</p>
|
|
||||||
</div>
|
|
||||||
<button id="info" class="matbut" style="font-size:medium; margin-right: auto; margin-left:auto; background: #2196F3;">More Info</button>
|
|
||||||
<button id="register" class="matbut" style="font-size:medium; margin-right: auto; margin-left:10px; background: #4CAF50;">Register</button>
|
|
||||||
<button id="remove" class="matbut" style="font-size:medium;margin:10px;background: #FF0000;">Remove</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Template.Popup = class {
|
|
||||||
static list_item(i, list_tile_color, unique, department, number, profname, list_sub_color, line) {
|
|
||||||
return `<li id='${i}' class='course_list_item'>
|
|
||||||
<div class='card course_list_card'>
|
|
||||||
<div class='container' style='background:${list_tile_color}'>
|
|
||||||
<button class='copy_button' title='Copy Unique #' value='${unique}'>
|
|
||||||
<i id='copyicon' class="material-icons copy_button_icon">content_copy</i>
|
|
||||||
</button>
|
|
||||||
<h4 class='course_name_truncate_box'>
|
|
||||||
<b>${department} ${number} <span class='course_list_item_subtext'> with ${profname} (${unique})</span></b>
|
|
||||||
</h4>
|
|
||||||
<p id='arrow' class='arrow'>►</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id='moreInfo' class='course_list_item_options'>
|
|
||||||
<p style='background-color:${list_sub_color};' class='course_list_item_time_box'>${line}</p>
|
|
||||||
<div id='infoButtons' class='course_list_item_options_button_container'>
|
|
||||||
<button class='material_button course_list_item_options_buttons remove_button' id='listRemove'>Remove</button>
|
|
||||||
<button class='material_button course_list_item_options_buttons register_button' id='register'>Register</button>
|
|
||||||
<button class='material_button course_list_item_options_buttons more_info_button' id='listMoreInfo'>More Info</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static conflict_message(conflict_message) {
|
|
||||||
return `<p id='conflict' class='conflict_message'>${conflict_message}</>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static line(line) {
|
|
||||||
let { days, start_time, end_time, location_link, location_full } = line;
|
|
||||||
|
|
||||||
return `<span class='time_line_days'>${days}:</span>
|
|
||||||
<span class='time_line_hours'>${start_time} to ${end_time}</span>
|
|
||||||
<span class='time_line_location'>
|
|
||||||
<a target='_blank' class= 'time_line_location_link' href='${location_link}'>${location_full}</a>
|
|
||||||
</span>
|
|
||||||
<br>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Template.Import = class {
|
|
||||||
static import_button() {
|
|
||||||
return `<button class='material-button' id='import' style='margin:15px 0px;'>${Text.button_text_default}</button><br>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static waitlist_import_button() {
|
|
||||||
return `<button class='material-button' id='import_waitlist' style='margin:0px'>${Text.waitlist_button_text_default}</button><br>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static store_waitlist_message() {
|
|
||||||
return `<h1 id="nextlabel"style="color: #FF9800;display:none;"></h1>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Template.Options = class {
|
|
||||||
static options_row(key, enabled) {
|
|
||||||
let button_text = enabled ? "Turn Off" : "Turn On";
|
|
||||||
let button_color = enabled ? Colors.closed : Colors.open;
|
|
||||||
let label_text = capitalizeString(key.replace(/([A-Z]+)*([A-Z][a-z])/g, "$1 $2"));
|
|
||||||
return `<h2 style="padding: 5px 16px 5px 16px; font-weight: normal;display: inline-block;text-align:left;">
|
|
||||||
${label_text}
|
|
||||||
</h2>
|
|
||||||
<button id="${key}" value=${enabled} class="material-button" style="display:inline-block;font-size:medium; float:right; background:${button_color}">
|
|
||||||
${button_text}
|
|
||||||
</button>
|
|
||||||
<br>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static contributor_card(username, name, image_url, profile_url) {
|
|
||||||
return `<div class='card contributor-card' id="${username}" data-url="${profile_url}">
|
|
||||||
<img class='contributor-image' src="${image_url}"></img>
|
|
||||||
${name ? `<p class='contributor-name'>${name}</p>` : ""}
|
|
||||||
<p class='contributor-username'>${username}</p>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
487
js/background.js
487
js/background.js
@@ -1,487 +0,0 @@
|
|||||||
console.log(`UT Registration Plus background page: ${window.location.href}`);
|
|
||||||
var grades; // caching the grades database in memory for faster queries
|
|
||||||
var current_semesters = {};
|
|
||||||
var departments = [];
|
|
||||||
var should_open = false; // toggled flag for automatically opening popup on new pages when 'more info' hit
|
|
||||||
|
|
||||||
// these are the default options that the extension currently supports
|
|
||||||
const default_options = {
|
|
||||||
loadAll: true,
|
|
||||||
courseConflictHighlight: true,
|
|
||||||
storeWaitlist: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
onStartup();
|
|
||||||
|
|
||||||
function onStartup() {
|
|
||||||
updateBadge(true);
|
|
||||||
loadDataBase();
|
|
||||||
getCurrentSemesters();
|
|
||||||
getCurrentDepartments();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle messages and their commands from content and popup scripts*/
|
|
||||||
chrome.runtime.onMessage.addListener(function (request, sender, response) {
|
|
||||||
switch (request.command) {
|
|
||||||
case "courseStorage":
|
|
||||||
if (request.action == "add") {
|
|
||||||
add(request, sender, response);
|
|
||||||
}
|
|
||||||
if (request.action == "remove") {
|
|
||||||
remove(request, sender, response);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "isSingleConflict":
|
|
||||||
isSingleConflict(request.dtarr, request.unique, response);
|
|
||||||
break;
|
|
||||||
case "checkConflicts":
|
|
||||||
checkConflicts(response);
|
|
||||||
break;
|
|
||||||
case "updateBadge":
|
|
||||||
updateBadge();
|
|
||||||
break;
|
|
||||||
case "updateStatus":
|
|
||||||
updateStatus(response);
|
|
||||||
break;
|
|
||||||
case "alreadyContains":
|
|
||||||
alreadyContains(request.unique, response);
|
|
||||||
break;
|
|
||||||
case "updateCourseList":
|
|
||||||
updateTabs();
|
|
||||||
break;
|
|
||||||
case "gradesQuery":
|
|
||||||
executeQuery(request.query, response);
|
|
||||||
break;
|
|
||||||
case "currentSemesters":
|
|
||||||
response({ semesters: current_semesters });
|
|
||||||
getCurrentSemesters();
|
|
||||||
break;
|
|
||||||
case "currentDepartments":
|
|
||||||
response({ departments: departments });
|
|
||||||
break;
|
|
||||||
case "setOpen":
|
|
||||||
should_open = true;
|
|
||||||
chrome.tabs.create({ url: request.url });
|
|
||||||
break;
|
|
||||||
case "shouldOpen":
|
|
||||||
response({ open: should_open });
|
|
||||||
should_open = false;
|
|
||||||
break;
|
|
||||||
case "getOptionsValue":
|
|
||||||
getOptionsValue(request.key, response);
|
|
||||||
break;
|
|
||||||
case "setOptionsValue":
|
|
||||||
setOptionsValue(request.key, request.value, response);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const method = request.method ? request.method.toUpperCase() : "GET";
|
|
||||||
xhr.open(method, request.url, true);
|
|
||||||
console.log(request);
|
|
||||||
xhr.onload = () => {
|
|
||||||
console.log(xhr.responseUrl);
|
|
||||||
response(xhr.responseText);
|
|
||||||
};
|
|
||||||
xhr.onerror = () => response(xhr.statusText);
|
|
||||||
if (method == "POST") {
|
|
||||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
||||||
}
|
|
||||||
xhr.send(request.data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Initially set the course data in storage */
|
|
||||||
chrome.runtime.onInstalled.addListener(function (details) {
|
|
||||||
if (details.reason == "install") {
|
|
||||||
setDefaultOptions();
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
if (!data.savedCourses) {
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (details.reason == "update") {
|
|
||||||
// if there's been an update, call setDefaultOptions in case their settings have gotten wiped
|
|
||||||
setDefaultOptions();
|
|
||||||
console.log("updated");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
chrome.storage.onChanged.addListener(function (changes) {
|
|
||||||
for (key in changes) {
|
|
||||||
if (key === "savedCourses") {
|
|
||||||
updateBadge(false, changes.savedCourses.newValue); // update the extension popup badge whenever the savedCourses have been changed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get the value of an option if it exists
|
|
||||||
function getOptionsValue(key, sendResponse) {
|
|
||||||
chrome.storage.sync.get("options", function (data) {
|
|
||||||
if (!data.options) {
|
|
||||||
setDefaultOptions();
|
|
||||||
} else {
|
|
||||||
sendResponse({
|
|
||||||
value: data.options[key],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the value of an option if it exists
|
|
||||||
function setOptionsValue(key, value, sendResponse) {
|
|
||||||
chrome.storage.sync.get("options", function (data) {
|
|
||||||
let new_options = data.options;
|
|
||||||
if (!data.options) {
|
|
||||||
// if there are no options set, set the defaults
|
|
||||||
setDefaultOptions();
|
|
||||||
new_options = default_options;
|
|
||||||
}
|
|
||||||
new_options[key] = value;
|
|
||||||
chrome.storage.sync.set(
|
|
||||||
{
|
|
||||||
options: new_options,
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
sendResponse({
|
|
||||||
value: new_options[key],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the default options if the options haven't been set before
|
|
||||||
function setDefaultOptions() {
|
|
||||||
chrome.storage.sync.get("options", function (data) {
|
|
||||||
if (!data.options) {
|
|
||||||
chrome.storage.sync.set(
|
|
||||||
{
|
|
||||||
options: default_options,
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
console.log("default options:", default_options);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getCurrentSemesters() {
|
|
||||||
let webData;
|
|
||||||
if(Object.keys(current_semesters).length > 0) {
|
|
||||||
chrome.storage.local.set({
|
|
||||||
semesterCache: current_semesters
|
|
||||||
});
|
|
||||||
}
|
|
||||||
async function goFetch(linkend="") {
|
|
||||||
console.log("lk " + linkend)
|
|
||||||
return fetch("https://registrar.utexas.edu/schedules/" + linkend)
|
|
||||||
.then((response) => {
|
|
||||||
return response.text()
|
|
||||||
.then((data) => {
|
|
||||||
return data;
|
|
||||||
}).catch((err) => {
|
|
||||||
console.log(err);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await goFetch().then((data) => {webData = data});
|
|
||||||
if(webData == null) {
|
|
||||||
webData = ""
|
|
||||||
}
|
|
||||||
let arr = webData.split("\n");
|
|
||||||
let i = 0
|
|
||||||
for(let row=0; row<arr.length; row++) {
|
|
||||||
let currentRow = arr[row]
|
|
||||||
if(currentRow.startsWith('<li><a href="https://registrar.utexas.edu/schedules/') && currentRow[52] != "a") {
|
|
||||||
let newWebData;
|
|
||||||
|
|
||||||
// let start = currentRow.indexOf('Schedule">')+10;
|
|
||||||
let start = Math.max(currentRow.lastIndexOf('Summer'), Math.max(currentRow.lastIndexOf('Spring'), currentRow.lastIndexOf('Fall')))
|
|
||||||
let end = currentRow.indexOf('</a></li>');
|
|
||||||
console.log(currentRow)
|
|
||||||
console.log(start + " " + end)
|
|
||||||
let name = currentRow.substring(start,end);
|
|
||||||
console.log("my name: " + name)
|
|
||||||
|
|
||||||
let num = currentRow.indexOf('"https://registrar.utexas.edu/schedules/">')+53;
|
|
||||||
let numend = currentRow.indexOf('" target');
|
|
||||||
let short_sem_num = currentRow.substring(num,numend);
|
|
||||||
current_semesters[name] = "code";
|
|
||||||
|
|
||||||
await goFetch(short_sem_num).then((data) => {newWebData = data});
|
|
||||||
arr2 = newWebData.split("\n")
|
|
||||||
|
|
||||||
for(let row2=0; row2<arr2.length; row2++) {
|
|
||||||
if(arr2[row2].startsWith('<div class="gobutton"><a href="')) {
|
|
||||||
let start2 = arr2[row2].indexOf('<div class="gobutton"><a href="')+31;
|
|
||||||
let end2 = arr2[row2].indexOf('" target="');
|
|
||||||
var scheduleLink = arr2[row2].substring(start2,end2);
|
|
||||||
var sem_num = scheduleLink.substring(scheduleLink.lastIndexOf("/") + 1).trim();
|
|
||||||
if (current_semesters[name] != sem_num) {
|
|
||||||
current_semesters[name] = sem_num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the utexas review api for getting the list of departments
|
|
||||||
function getCurrentDepartments() {
|
|
||||||
$.get("https://raw.githubusercontent.com/sghsri/UT-Registration-Plus/master/docs/departments.json", function (response) {
|
|
||||||
if (response) {
|
|
||||||
departments = JSON.parse(response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the badge text to reflect the new changes
|
|
||||||
function updateBadge(first, new_changes) {
|
|
||||||
if (new_changes) {
|
|
||||||
updateBadgeText(first, new_changes);
|
|
||||||
} else {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
let courses = data.savedCourses;
|
|
||||||
updateBadgeText(first, courses);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the badge text to show the number of courses that have been saved by the user
|
|
||||||
function updateBadgeText(first, courses) {
|
|
||||||
let badge_text = courses.length > 0 ? `${courses.length}` : "";
|
|
||||||
let flash_time = !first ? 200 : 0;
|
|
||||||
chrome.browserAction.setBadgeText({
|
|
||||||
text: badge_text,
|
|
||||||
});
|
|
||||||
if (!first) {
|
|
||||||
// if isn't the first install of the extension, flash the badge to bring attention to it
|
|
||||||
chrome.browserAction.setBadgeBackgroundColor({
|
|
||||||
color: Colors.badge_flash,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setTimeout(function () {
|
|
||||||
chrome.browserAction.setBadgeBackgroundColor({
|
|
||||||
color: Colors.badge_default,
|
|
||||||
});
|
|
||||||
}, flash_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find all the conflicts in the courses and send them out/ if there is even a conflict*/
|
|
||||||
function checkConflicts(sendResponse) {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
var conflicts = [];
|
|
||||||
var courses = data.savedCourses;
|
|
||||||
for (let i = 0; i < courses.length; i++) {
|
|
||||||
for (let j = i + 1; j < courses.length; j++) {
|
|
||||||
let course_a = courses[i];
|
|
||||||
let course_b = courses[j];
|
|
||||||
if (isConflict(course_a.datetimearr, course_b.datetimearr)) conflicts.push([course_a, course_b]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendResponse({
|
|
||||||
isConflict: conflicts.length !== 0,
|
|
||||||
between: conflicts.length ? conflicts : undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
var courses = data.savedCourses;
|
|
||||||
var conflict_list = [];
|
|
||||||
var conflict = false;
|
|
||||||
var contains = false;
|
|
||||||
for (let i = 0; i < courses.length; i++) {
|
|
||||||
let course = courses[i];
|
|
||||||
if (isConflict(currdatearr, course.datetimearr)) {
|
|
||||||
conflict = true;
|
|
||||||
conflict_list.push(course);
|
|
||||||
}
|
|
||||||
if (!contains && isSameCourse(course, unique)) {
|
|
||||||
contains = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendResponse({
|
|
||||||
isConflict: conflict,
|
|
||||||
alreadyContains: contains,
|
|
||||||
conflictList: conflict_list,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if conflict between two date-time-arrs*/
|
|
||||||
function isConflict(adtarr, bdtarr) {
|
|
||||||
for (var i = 0; i < adtarr.length; i++) {
|
|
||||||
var current_day = adtarr[i][0];
|
|
||||||
var current_times = adtarr[i][1];
|
|
||||||
for (var j = 0; j < bdtarr.length; j++) {
|
|
||||||
var next_day = bdtarr[j][0];
|
|
||||||
var next_times = bdtarr[j][1];
|
|
||||||
if (next_day == current_day) {
|
|
||||||
if (current_times[0] < next_times[1] && current_times[1] > next_times[0]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the requested course to the storage*/
|
|
||||||
function add(request, sender, sendResponse) {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
var courses = data.savedCourses;
|
|
||||||
if (!contains(courses, request.course.unique)) {
|
|
||||||
courses.push(request.course);
|
|
||||||
console.log(courses);
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: courses,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
sendResponse({
|
|
||||||
done: "Added: (" + request.course.unique + ") " + request.course.coursename,
|
|
||||||
label: "Remove Course -",
|
|
||||||
value: "remove",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/* Find and Remove the requested course from the storage*/
|
|
||||||
function remove(request, sender, sendResponse) {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
var courses = data.savedCourses;
|
|
||||||
console.log(courses);
|
|
||||||
var index = 0;
|
|
||||||
while (index < courses.length && courses[index].unique != request.course.unique) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
courses.splice(index, 1);
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: courses,
|
|
||||||
});
|
|
||||||
sendResponse({
|
|
||||||
done: "Removed: (" + request.course.unique + ") " + request.course.coursename,
|
|
||||||
label: "Add Course +",
|
|
||||||
value: "add",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find if the unique is already contained within the storage*/
|
|
||||||
function alreadyContains(unique, sendResponse) {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
var courses = data.savedCourses;
|
|
||||||
sendResponse({
|
|
||||||
alreadyContains: contains(courses, unique),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// find if a course with the current unique number exists in the user's saved courses
|
|
||||||
function contains(courses, unique) {
|
|
||||||
var i = 0;
|
|
||||||
while (i < courses.length) {
|
|
||||||
if (isSameCourse(courses[i], unique)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// does it have the same unique number as provided
|
|
||||||
function isSameCourse(course, unique) {
|
|
||||||
return course.unique == unique;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a message to every tab open to updateit's course list (and thus recalculate its conflicts highlighting)
|
|
||||||
function updateTabs() {
|
|
||||||
chrome.tabs.query({}, function (tabs) {
|
|
||||||
for (var i = 0; i < tabs.length; i++) {
|
|
||||||
chrome.tabs.sendMessage(tabs[i].id, {
|
|
||||||
command: "updateCourseList",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// const UPDATE_INTERVAL = 1000 * 60 * 16;
|
|
||||||
// setInterval(updateStatus, UPDATE_INTERVAL);
|
|
||||||
// // updateStatus();
|
|
||||||
|
|
||||||
// function updateStatus(sendResponse) {
|
|
||||||
// chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
// var courses = data.savedCourses;
|
|
||||||
// var no_change = true;
|
|
||||||
// for (let i = 0; i < courses.length; i++) {
|
|
||||||
// try {
|
|
||||||
// let c = courses[i];
|
|
||||||
// let old_status = c.status;
|
|
||||||
// let old_link = c.link;
|
|
||||||
// $.ajax({
|
|
||||||
// url: old_link,
|
|
||||||
// success: function (result) {
|
|
||||||
// if (result) {
|
|
||||||
// console.log(result);
|
|
||||||
// var object = $("<div/>").html(result).contents();
|
|
||||||
// let new_status = object.find('[data-th="Status"]').text();
|
|
||||||
// let register_link = object.find('td[data-th="Add"] a');
|
|
||||||
// if (register_link) register_link = register_link.attr("href");
|
|
||||||
// var haschanged = new_status == old_status && register_link == old_link;
|
|
||||||
// if (!haschanged) console.log(c.unique + " updated from " + old_status + " to " + new_status + " and " + old_link + " to " + register_link);
|
|
||||||
// no_change &= haschanged;
|
|
||||||
// c.registerlink = register_link;
|
|
||||||
// c.status = new_status;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// } catch (e) {
|
|
||||||
// console.log(e);
|
|
||||||
// console.log("Not logged into UT Coursebook. Could not update class statuses.");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (!no_change) {
|
|
||||||
// chrome.storage.sync.set({
|
|
||||||
// savedCourses: courses,
|
|
||||||
// });
|
|
||||||
// console.log("updated status");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// execute a query on the grades database
|
|
||||||
function executeQuery(query, sendResponse) {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
291
js/calendar.js
291
js/calendar.js
@@ -1,291 +0,0 @@
|
|||||||
var color_counter = 0;
|
|
||||||
var {
|
|
||||||
calendar_fade_time,
|
|
||||||
button_delay
|
|
||||||
} = Timing;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var saved_courses = [];
|
|
||||||
var curr_course = {}
|
|
||||||
|
|
||||||
$("#calendar").after(Template.Calendar.modal());
|
|
||||||
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
// Iterate through each saved course and add to 'event'
|
|
||||||
saved_courses = data.savedCourses;
|
|
||||||
console.log(saved_courses);
|
|
||||||
let event_source = buildEventSource(saved_courses);
|
|
||||||
|
|
||||||
$("#calendar").fullCalendar({
|
|
||||||
editable: false, // Don't allow editing of events
|
|
||||||
handleWindowResize: true,
|
|
||||||
weekends: false, // will hide Saturdays and Sundays
|
|
||||||
slotDuration: "00:30:00", // 15 minute intervals on vertical column
|
|
||||||
slotEventOverlap: false, // No overlapping between events
|
|
||||||
defaultView: "agendaWeek", // Only show week view
|
|
||||||
header: false, // Hide buttons/titles
|
|
||||||
minTime: "08:00:00", // Start time
|
|
||||||
maxTime: "21:00:01", // End time
|
|
||||||
columnHeaderFormat: "ddd", // Only show day of the week names
|
|
||||||
displayEventTime: true, // Display event time
|
|
||||||
allDaySlot: false,
|
|
||||||
Duration: {
|
|
||||||
hours: 1
|
|
||||||
},
|
|
||||||
height: 'auto',
|
|
||||||
events: event_source,
|
|
||||||
slotLabelFormat: [
|
|
||||||
'h:mm A' // lower level of text
|
|
||||||
],
|
|
||||||
eventRender: function (event, element, view) {
|
|
||||||
$(element).css("padding", "5px").css("margin-bottom", "5px");
|
|
||||||
},
|
|
||||||
eventClick: function (data, event, view) {
|
|
||||||
displayModal(data)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function displayModal(data) {
|
|
||||||
$("#myModal").fadeIn(calendar_fade_time);
|
|
||||||
$("#colorStrip").css('background-color', data.color);
|
|
||||||
curr_course = saved_courses[data.index];
|
|
||||||
setUpModal()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setUpModal() {
|
|
||||||
let {
|
|
||||||
coursename,
|
|
||||||
unique,
|
|
||||||
datetimearr,
|
|
||||||
profname,
|
|
||||||
status,
|
|
||||||
registerlink
|
|
||||||
} = curr_course;
|
|
||||||
$("#classname").html(`${coursename} <span style='font-size:small'>(${unique})</span>`);
|
|
||||||
buildTimeTitle(datetimearr);
|
|
||||||
$("#prof").html(`with <span style='font-weight:bold;'>${capitalizeString(profname)}</span>`);
|
|
||||||
setRegisterButton(status, registerlink)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setRegisterButton(status, registerlink) {
|
|
||||||
if (canNotRegister(status, registerlink))
|
|
||||||
$("#register").text("Can't Register").css("background-color", Colors.closed);
|
|
||||||
else if (status.includes("waitlisted"))
|
|
||||||
$("#register").text("Join Waitlist").css("background-color", Colors.waitlisted);
|
|
||||||
else
|
|
||||||
$("#register").text("Register").css("background-color", Colors.open);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildTimeTitle(datetimearr) {
|
|
||||||
$('#timelines').remove();
|
|
||||||
var arr = convertDateTimeArrToLine(datetimearr)
|
|
||||||
var output = "";
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
let line = arr[i];
|
|
||||||
output += Template.Calendar.line(line);
|
|
||||||
}
|
|
||||||
$("#header").after(`<div id='timelines'>${output}</div`);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Iterate through each saved course and add to 'event'
|
|
||||||
function buildEventSource(saved_courses) {
|
|
||||||
color_counter = 0;
|
|
||||||
let event_source = [];
|
|
||||||
var hours = 0;
|
|
||||||
for (let i = 0; i < saved_courses.length; i++) {
|
|
||||||
let {
|
|
||||||
coursename,
|
|
||||||
datetimearr
|
|
||||||
} = saved_courses[i];
|
|
||||||
let number = separateCourseNameParts(coursename).number;
|
|
||||||
let class_length = parseInt(number.charAt(0));
|
|
||||||
let multi_semester_code = number.slice(-1);
|
|
||||||
if (["A","B"].includes(multi_semester_code)) {
|
|
||||||
hours += Math.floor(class_length/2);
|
|
||||||
} else if (["X","Y","Z"].includes(multi_semester_code)) {
|
|
||||||
hours += Math.floor(class_length/3);
|
|
||||||
} else {
|
|
||||||
hours += class_length;
|
|
||||||
}
|
|
||||||
for (let j = 0; j < datetimearr.length; j++) {
|
|
||||||
let session = datetimearr[j]; // One single session for a class
|
|
||||||
let event_obj = setEventForSection(session, color_counter, i);
|
|
||||||
event_source.push(event_obj);
|
|
||||||
}
|
|
||||||
color_counter++;
|
|
||||||
}
|
|
||||||
displayMetaData(hours, saved_courses);
|
|
||||||
return event_source;
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayMetaData(hours, saved_courses) {
|
|
||||||
$("#hours").text(hours + " Hours");
|
|
||||||
$("#num").text(saved_courses.length + " Courses");
|
|
||||||
}
|
|
||||||
|
|
||||||
//create the event object for every section
|
|
||||||
function setEventForSection(session, colorCounter, i) {
|
|
||||||
let full_day = days.get(session[0]);
|
|
||||||
let course = saved_courses[i];
|
|
||||||
let {
|
|
||||||
coursename,
|
|
||||||
profname,
|
|
||||||
} = course;
|
|
||||||
let {
|
|
||||||
department,
|
|
||||||
number
|
|
||||||
} = separateCourseNameParts(coursename)
|
|
||||||
beg_day = calculateBeginningDate(full_day)
|
|
||||||
start_date = formatCalculateDate(beg_day, full_day, session[1][0]);
|
|
||||||
end_date = formatCalculateDate(beg_day, full_day, session[1][1]);
|
|
||||||
|
|
||||||
event_obj = {
|
|
||||||
title: `${department}-${number} with ${capitalizeString(profname)}`,
|
|
||||||
start: start_date,
|
|
||||||
end: end_date,
|
|
||||||
color: Colors.material_colors[colorCounter],
|
|
||||||
building: session[2],
|
|
||||||
index: i,
|
|
||||||
allday: false
|
|
||||||
};
|
|
||||||
return event_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatCalculateDate(beg_day, full_day, hour) {
|
|
||||||
return beg_day + moment().day(full_day)._d.toString().split(" ")[2] + "T" + hour + ":00";
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateBeginningDate(full_day) {
|
|
||||||
var year = moment().day(full_day)._d.toString().split(" ")[3];
|
|
||||||
var month_num = moment(moment().day(full_day)._d.toString().split(" ")[1], "MMM").format('MM');
|
|
||||||
return `${year}-${month_num}-`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateCalendar() {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
saved_courses = data.savedCourses
|
|
||||||
let event_source = buildEventSource(saved_courses);
|
|
||||||
$('#calendar').fullCalendar('removeEventSources');
|
|
||||||
$("#calendar").fullCalendar('addEventSource', event_source, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
chrome.runtime.onMessage.addListener(
|
|
||||||
function (request, sender, sendResponse) {
|
|
||||||
if (request.command == "updateCourseList" || request.command == "courseAdded") {
|
|
||||||
updateCalendar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
$("#info").click(() => {
|
|
||||||
openMoreInfoWithOpenModal(curr_course.link);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$("#save").click(() => {
|
|
||||||
takePicture();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$("#clear").click(() => {
|
|
||||||
/*Clear the list and the storage of courses*/
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: []
|
|
||||||
});
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
updateCalendar();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$("#remove").click(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "courseStorage",
|
|
||||||
course: curr_course,
|
|
||||||
action: "remove"
|
|
||||||
}, function () {
|
|
||||||
$("#myModal").fadeOut(calendar_fade_time);
|
|
||||||
updateCalendar();
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
});
|
|
||||||
}, button_delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$("#register").click(function () {
|
|
||||||
let {
|
|
||||||
registerlink,
|
|
||||||
status
|
|
||||||
} = curr_course;
|
|
||||||
if (!canNotRegister(status, registerlink)) {
|
|
||||||
setTimeout(() => {
|
|
||||||
window.open(registerlink);
|
|
||||||
}, button_delay);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#export").click(function () {
|
|
||||||
var cal = ics();
|
|
||||||
var calendarEvents = $('#calendar').fullCalendar('clientEvents');
|
|
||||||
for (i in calendarEvents) {
|
|
||||||
var event = calendarEvents[i];
|
|
||||||
buildICSFile(cal, event);
|
|
||||||
}
|
|
||||||
cal.download("My_Course_Calendar");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function buildICSFile(cal, event) {
|
|
||||||
let {
|
|
||||||
title,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
building
|
|
||||||
} = event;
|
|
||||||
let class_name = title.split('with')[0];
|
|
||||||
let description = `with ${title.split('with')[1]}`;
|
|
||||||
let time = start._d.toUTCString();
|
|
||||||
cal.addEvent(class_name, description, building, start._i, end._i, {
|
|
||||||
rrule: `RRULE:FREQ=WEEKLY;BYDAY=${time.substring(0, time.indexOf(",") - 1).toUpperCase()};INTERVAL=1`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function takePicture() {
|
|
||||||
var width = $("#calendar").width() * window.devicePixelRatio;
|
|
||||||
var height = $("#calendar").height() * window.devicePixelRatio;
|
|
||||||
let cropper = document.createElement('canvas').getContext('2d');
|
|
||||||
html2canvas(document.querySelector("#calendar"), Export.png_options).then(c => {
|
|
||||||
cropper.canvas.width = width;
|
|
||||||
cropper.canvas.height = height;
|
|
||||||
cropper.drawImage(c, 0, 0);
|
|
||||||
var a = document.createElement('a');
|
|
||||||
a.href = cropper.canvas.toDataURL("image/png");
|
|
||||||
a.download = 'mySchedule.png';
|
|
||||||
a.click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*Close Modal when hit escape*/
|
|
||||||
$(document).keydown((e) => {
|
|
||||||
if (e.keyCode == 27) {
|
|
||||||
$("#myModal").fadeOut(calendar_fade_time);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.close').click(function () {
|
|
||||||
close();
|
|
||||||
});
|
|
||||||
$('#myModal').click(function (event) {
|
|
||||||
if (event.target.id == 'myModal') {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
$("#myModal").fadeOut(calendar_fade_time);
|
|
||||||
}
|
|
||||||
87
js/config.js
87
js/config.js
@@ -1,87 +0,0 @@
|
|||||||
class Timing {}
|
|
||||||
Timing.fade_time = 100;
|
|
||||||
Timing.calendar_fade_time = 100;
|
|
||||||
Timing.button_delay = 75;
|
|
||||||
|
|
||||||
class Colors {}
|
|
||||||
Colors.material_colors = [
|
|
||||||
"#4CAF50",
|
|
||||||
"#CDDC39",
|
|
||||||
"#FFC107",
|
|
||||||
"#2196F3",
|
|
||||||
"#F57C00",
|
|
||||||
"#9C27B0",
|
|
||||||
"#FF5722",
|
|
||||||
"#673AB7",
|
|
||||||
"#FF5252",
|
|
||||||
"#E91E63",
|
|
||||||
"#009688",
|
|
||||||
"#00BCD4",
|
|
||||||
"#4E342E",
|
|
||||||
"#424242",
|
|
||||||
"#9E9E9E",
|
|
||||||
];
|
|
||||||
Colors.open = "#4CAF50";
|
|
||||||
Colors.waitlisted = "#FF9800";
|
|
||||||
Colors.closed = "#FF5722";
|
|
||||||
Colors.no_status = "#607D8B";
|
|
||||||
|
|
||||||
Colors.open_light = "#C8E6C9";
|
|
||||||
Colors.waitlisted_light = "#FFE0B2";
|
|
||||||
Colors.closed_light = "#FFCCBC";
|
|
||||||
Colors.no_status_light = "#CFD8DC";
|
|
||||||
|
|
||||||
Colors.highlight_conflict = "#F44336";
|
|
||||||
Colors.highlight_default = "#333333";
|
|
||||||
Colors.highlight_saved = "#4CAF50";
|
|
||||||
|
|
||||||
Colors.badge_flash = "#FF5722";
|
|
||||||
Colors.badge_default = "#bf5700";
|
|
||||||
|
|
||||||
class Export {}
|
|
||||||
Export.png_options = {
|
|
||||||
foreignObjectRendering: true,
|
|
||||||
logging: true,
|
|
||||||
removeContainer: true,
|
|
||||||
async: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Popup {}
|
|
||||||
Popup.num_semesters = 2;
|
|
||||||
|
|
||||||
class Text {}
|
|
||||||
Text.emptyText = function () {
|
|
||||||
let arr = [
|
|
||||||
"Doesn't Look Like Anything To Me.",
|
|
||||||
"You Can't Fail Classes You're Not In.",
|
|
||||||
"Pro-Tip: Don't Take O-Chem.",
|
|
||||||
"Jendy's Fofofo™",
|
|
||||||
"Fine Dining at Jester City Limits",
|
|
||||||
"Rec Sports is full and it's only 2pm.",
|
|
||||||
"Hope Domino is doing well rn 🥺",
|
|
||||||
"The year is 2055 and Welch still isn't finished.",
|
|
||||||
"Wear a Mask.",
|
|
||||||
"Motivation dropping faster than ur GPA",
|
|
||||||
"No Work Happens On PCL 5th Floor.",
|
|
||||||
"Sophomore But Freshman By Credit.",
|
|
||||||
"Pain is temporary, GPA is forever.",
|
|
||||||
"You've Yee'd Your Last Haw.",
|
|
||||||
"lol everything is already waitlisted.",
|
|
||||||
"At Least You're Not At A&M.",
|
|
||||||
`It's ${moment().format("h:mm")} and OU Still Sucks.`,
|
|
||||||
"TeXAs iS BaCK GuYZ",
|
|
||||||
"'Academically Challenged'",
|
|
||||||
"Does McCombs teach Parseltongue?",
|
|
||||||
"Feel bad if you say Wampus.",
|
|
||||||
"No Cruce Enfrente Del Bus.",
|
|
||||||
"Midterm 1 has been Unmuted",
|
|
||||||
"Omae Wa Mou Shindeiru...",
|
|
||||||
"Bevo Bucks are the new Bitcoin",
|
|
||||||
];
|
|
||||||
let index = Math.floor(Math.random() * arr.length);
|
|
||||||
|
|
||||||
return arr[index];
|
|
||||||
};
|
|
||||||
Text.button_text_default = "<span style='font-size:small'>Import to </span><b>UT Reg +<b>";
|
|
||||||
Text.waitlist_button_text_default = "<span style='font-size:small'>Import Waitlists to </span><b>UT Reg +<b>";
|
|
||||||
Text.button_success = "Courses Saved!";
|
|
||||||
@@ -1,627 +0,0 @@
|
|||||||
console.log(`UT Registration Plus is running on this page: ${window.location.href}`);
|
|
||||||
|
|
||||||
var curr_course = {}
|
|
||||||
|
|
||||||
var semester_code = new URL(window.location.href).pathname.split('/')[4];
|
|
||||||
var done_loading = true;
|
|
||||||
|
|
||||||
var next = $("#next_nav_link");
|
|
||||||
if (next) {
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "getOptionsValue",
|
|
||||||
key: "loadAll",
|
|
||||||
}, function (response) {
|
|
||||||
if(response.value){
|
|
||||||
$('[title*="next listing"]').remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//This extension may be super lit, but you know what's even more lit?
|
|
||||||
//Matthew Tran's twitter and insta: @MATTHEWTRANN and @matthew.trann
|
|
||||||
|
|
||||||
if (document.querySelector('#fos_fl')) {
|
|
||||||
let params = (new URL(document.location)).searchParams;
|
|
||||||
let dep = params.get("fos_fl");
|
|
||||||
let level = params.get("level");
|
|
||||||
if (dep && level) {
|
|
||||||
if (dep.length == 3 && (level == 'U' || level == 'L' || level == 'G')) {
|
|
||||||
document.querySelector('#fos_fl').value = dep;
|
|
||||||
document.querySelector('#level').value = level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//make heading and modal
|
|
||||||
if (!$("#kw_results_table").length) {
|
|
||||||
$("table").after(Template.Catalog.loading());
|
|
||||||
$("#container").prepend(Template.Main.modal());
|
|
||||||
$("#myModal").prepend("<div id='snackbar'>save course popup...</div>");
|
|
||||||
|
|
||||||
// now add to the table
|
|
||||||
$("table thead th:last-child").after('<th scope=col>Plus</th>');
|
|
||||||
$('table').find('tr').each(function () {
|
|
||||||
if (!($(this).find('td').hasClass("course_header")) && $(this).has('th').length == 0) {
|
|
||||||
$(this).append(Template.Main.extension_button());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isIndividualCoursePage()){
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "shouldOpen",
|
|
||||||
}, function (response) {
|
|
||||||
if(response.open){
|
|
||||||
$("#distButton").click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateListConflictHighlighting();
|
|
||||||
|
|
||||||
$("body").on('click', '#distButton', function () {
|
|
||||||
var row = $(this).closest('tr');
|
|
||||||
$('.modal-content').stop().animate({
|
|
||||||
scrollTop: 0
|
|
||||||
}, 500);
|
|
||||||
$(this).blur();
|
|
||||||
curr_course = getCourseInfo(row);
|
|
||||||
getDistribution(curr_course);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function updateLinks(course_info, first_name) {
|
|
||||||
let {
|
|
||||||
prof_name,
|
|
||||||
number
|
|
||||||
} = course_info;
|
|
||||||
course_info["first_name"] = first_name;
|
|
||||||
course_info["links"]["rate_my_prof"] = `http://www.ratemyprofessors.com/search.jsp?queryBy=teacherName&schoolName=university+of+texas+at+austin&queryoption=HEADER&query=${first_name} ${prof_name};&facetSearch=true`;
|
|
||||||
course_info["links"]["ecis"] = profname ? `http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?&s_in_action_sw=S&s_in_search_type_sw=N&s_in_search_name=${prof_name}%2C%20${first_name}` :
|
|
||||||
`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=${number}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildCourseLinks(course_info) {
|
|
||||||
let {
|
|
||||||
department,
|
|
||||||
number,
|
|
||||||
unique,
|
|
||||||
prof_name
|
|
||||||
} = course_info
|
|
||||||
links = {
|
|
||||||
"textbook": `https://www.universitycoop.com/adoption-search-results?sn=${semester_code}__${department}__${number}__${unique}`,
|
|
||||||
"syllabi": `https://utdirect.utexas.edu/apps/student/coursedocs/nlogon/?year=&semester=&department=${department}&course_number=${number}&course_title=&unique=&instructor_first=&instructor_last=${prof_name}&course_type=In+Residence&search=Search`,
|
|
||||||
//default ones (before first name can be used)
|
|
||||||
"rate_my_prof": "http://www.ratemyprofessors.com/campusRatings.jsp?sid=1255",
|
|
||||||
"ecis": "http://utdirect.utexas.edu/ctl/ecis/results/index.WBX?"
|
|
||||||
}
|
|
||||||
course_info["links"] = links;
|
|
||||||
return course_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildBasicCourseInfo(row, course_name, individual) {
|
|
||||||
let {
|
|
||||||
name,
|
|
||||||
department,
|
|
||||||
number
|
|
||||||
} = separateCourseNameParts(course_name);
|
|
||||||
let instructor_text = $(row).find('td[data-th="Instructor"]').text();
|
|
||||||
let has_initial = instructor_text.indexOf(',') > 0;
|
|
||||||
course_info = {
|
|
||||||
"full_name": course_name,
|
|
||||||
"name": name,
|
|
||||||
"department": department,
|
|
||||||
"number": number,
|
|
||||||
"individual": individual ? individual : $(row).find('td[data-th="Unique"] a').prop('href'),
|
|
||||||
"register": $(row).find('td[data-th="Add"] a').prop('href'),
|
|
||||||
"unique": $(row).find('td[data-th="Unique"]').text(),
|
|
||||||
"status": $(row).find('td[data-th="Status"]').text(),
|
|
||||||
"prof_name": instructor_text ? has_initial ? capitalizeString(instructor_text.split(', ')[0]) : capitalizeString(instructor_text) : "Undecided",
|
|
||||||
"initial": instructor_text && has_initial ? instructor_text.split(', ')[1].substring(0, 1) : "",
|
|
||||||
"time_data": {
|
|
||||||
"days": $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim()),
|
|
||||||
"times": $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim()),
|
|
||||||
"places": $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim())
|
|
||||||
},
|
|
||||||
"links": {}
|
|
||||||
}
|
|
||||||
return buildCourseLinks(course_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*For a row, get all the course information and add the date-time-lines*/
|
|
||||||
function getCourseInfo(row) {
|
|
||||||
let course_name = "";
|
|
||||||
let course_row = {}
|
|
||||||
let individual = undefined;
|
|
||||||
if (isIndividualCoursePage()) {
|
|
||||||
course_name = $("#details h2").text();
|
|
||||||
course_row = $('table');
|
|
||||||
individual = document.URL;
|
|
||||||
} else {
|
|
||||||
$('table').find('tr').each(function () {
|
|
||||||
if ($(this).find('td').hasClass("course_header")) {
|
|
||||||
course_name = $(this).find('td').text() + "";
|
|
||||||
}
|
|
||||||
if ($(this).is(row)) {
|
|
||||||
course_row = row;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
curr_course = buildBasicCourseInfo(course_row, course_name, individual);
|
|
||||||
getDescription(curr_course);
|
|
||||||
return curr_course;
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveCourse() {
|
|
||||||
console.log(curr_course);
|
|
||||||
console.log(JSON.stringify(curr_course));
|
|
||||||
let {
|
|
||||||
full_name,
|
|
||||||
unique,
|
|
||||||
prof_name,
|
|
||||||
status,
|
|
||||||
individual,
|
|
||||||
register
|
|
||||||
} = curr_course;
|
|
||||||
let dtarr = getDayTimeArray(undefined, curr_course);
|
|
||||||
|
|
||||||
var c = new Course(full_name, unique, prof_name, dtarr, status, individual, register);
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "courseStorage",
|
|
||||||
course: c,
|
|
||||||
action: $("#saveCourse").val()
|
|
||||||
}, function (response) {
|
|
||||||
$("#saveCourse").text(response.label);
|
|
||||||
$("#saveCourse").val(response.value);
|
|
||||||
$("#snackbar").text(response.done);
|
|
||||||
toggleSnackbar();
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "updateCourseList"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the course list to show if the row contains a course that conflicts with the saved course is one of the saved courses */
|
|
||||||
function updateListConflictHighlighting(start = 0) {
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "getOptionsValue",
|
|
||||||
key: "courseConflictHighlight",
|
|
||||||
}, function (response) {
|
|
||||||
let canHighlight = response.value;
|
|
||||||
$('table').find('tr').each(function (i) {
|
|
||||||
if (i >= start) {
|
|
||||||
if (!($(this).find('td').hasClass("course_header")) && $(this).has('th').length == 0) {
|
|
||||||
var unique = $(this).find('td[data-th="Unique"]').text();
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "isSingleConflict",
|
|
||||||
dtarr: getDayTimeArray(this),
|
|
||||||
unique: unique
|
|
||||||
}, (response) => {
|
|
||||||
let {
|
|
||||||
isConflict,
|
|
||||||
alreadyContains,
|
|
||||||
conflictList
|
|
||||||
} = response
|
|
||||||
updateTextHighlighting($(this).find('td'), canHighlight, isConflict, alreadyContains, conflictList, $(this), unique);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTextHighlighting(tds, canHighlight, isConflict, alreadyContains, conflictList, row, unique) {
|
|
||||||
conflict_texts = row.find('.tooltiptext');
|
|
||||||
let unique_list = conflictList.filter(function(course){
|
|
||||||
if(course.unique != unique){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}).map(function(course){
|
|
||||||
let { name, department, number} = separateCourseNameParts(course.coursename);
|
|
||||||
return `${department} ${number} (${course.unique})`;
|
|
||||||
});
|
|
||||||
if(isConflict && unique_list.length){
|
|
||||||
if(conflict_texts){
|
|
||||||
row.find('.tooltiptext').remove();
|
|
||||||
}
|
|
||||||
row.addClass('tooltip');
|
|
||||||
row.append(`<span class='tooltiptext'><span style='text-decoration: underline;'>Conflicts:<br></span> ${unique_list.join('<br>')}</span>`);
|
|
||||||
} else {
|
|
||||||
row.removeClass('tooltip');
|
|
||||||
conflict_texts.remove();
|
|
||||||
}
|
|
||||||
let current_color = rgb2hex(tds.css('color'));
|
|
||||||
if (isConflict && canHighlight && !alreadyContains) {
|
|
||||||
if (current_color != Colors.highlight_conflict){
|
|
||||||
tds.css('color', Colors.highlight_conflict).css('text-decoration', 'line-through').css('font-weight', 'normal')
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (!alreadyContains) {
|
|
||||||
if (tds.css('color') != Colors.highlight_default)
|
|
||||||
tds.css('color', Colors.highlight_default).css('text-decoration', 'none').css('font-weight', 'normal');
|
|
||||||
}
|
|
||||||
if (alreadyContains) {
|
|
||||||
if (tds.css('color') != Colors.highlight_saved)
|
|
||||||
tds.css('color', Colors.highlight_saved).css('text-decoration', 'none').css('font-weight', 'bold');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* For a row, get the date-time-array for checking conflicts*/
|
|
||||||
function getDayTimeArray(row, course_info) {
|
|
||||||
var day_time_array = []
|
|
||||||
let days = course_info ? course_info["time_data"]["days"] : $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
let times = course_info ? course_info["time_data"]["times"] : $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
let places = course_info ? course_info["time_data"]["places"] : $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
for (var i = 0; i < days.length; i++) {
|
|
||||||
let date = days[i];
|
|
||||||
let time = times[i];
|
|
||||||
let place = places[i];
|
|
||||||
for (var j = 0; j < date.length; j++) {
|
|
||||||
let letter = date.charAt(j);
|
|
||||||
if (letter == "T" && j < date.length - 1 && date.charAt(j + 1) == "H") {
|
|
||||||
day_time_array.push(["TH", convertTime(time), place]);
|
|
||||||
} else {
|
|
||||||
if (letter != "H")
|
|
||||||
day_time_array.push([letter, convertTime(time), place]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return day_time_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertDateTimeArrToLine(date, time, place) {
|
|
||||||
let arr = separateDays(date)
|
|
||||||
let output = prettifyDaysText(arr)
|
|
||||||
let building = place.substring(0, place.search(/\d/) - 1);
|
|
||||||
building = building ? building : "Undecided Location";
|
|
||||||
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 badData(course_data, res) {
|
|
||||||
return typeof res == 'undefined' || course_data["prof_name"] == "Undecided";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Query the grades database*/
|
|
||||||
function getDistribution(course_data, sem) {
|
|
||||||
toggleChartLoading(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(course_info) {
|
|
||||||
$("h2.dateTimePlace").remove();
|
|
||||||
let {
|
|
||||||
days,
|
|
||||||
times,
|
|
||||||
places
|
|
||||||
} = course_info["time_data"]
|
|
||||||
var lines = [];
|
|
||||||
for (let i = 0; i < days.length; i++) {
|
|
||||||
var date = days[i];
|
|
||||||
var time = times[i];
|
|
||||||
var place = places[i];
|
|
||||||
lines.push($(`<h2 class="dateTimePlace">${convertDateTimeArrToLine(date, time, place)}</th>`));
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function displayBasicCourseInfo(course_info){
|
|
||||||
$("#title").text(buildTitle(course_info))
|
|
||||||
$("#topbuttons").before(buildTimeTitle(course_info));
|
|
||||||
$("#profname").text(buildProfTitle(course_info));
|
|
||||||
$("#myModal").fadeIn(Timing.fade_time);
|
|
||||||
console.log(course_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Open the modal and show all the data*/
|
|
||||||
function openDialog(course_info, res) {
|
|
||||||
displayBasicCourseInfo(course_info);
|
|
||||||
//initial text on the "save course button"
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "alreadyContains",
|
|
||||||
unique: course_info["unique"]
|
|
||||||
}, function (response) {
|
|
||||||
|
|
||||||
let button_text = response.alreadyContains ? "Remove Course -" : "Add Course +";
|
|
||||||
let button_val = response.alreadyContains ? "remove" : "add";
|
|
||||||
$("#saveCourse").text(button_text);
|
|
||||||
$("#saveCourse").val(button_val);
|
|
||||||
});
|
|
||||||
buildSemestersDropdown(course_info, res)
|
|
||||||
var data = []
|
|
||||||
if (!badData(course_info, res))
|
|
||||||
data = res.values[0];
|
|
||||||
allowClosing();
|
|
||||||
setChart(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function setChart(data) {
|
|
||||||
// set up the chart
|
|
||||||
toggleChartLoading(false);
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var error_message = "<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>";
|
|
||||||
|
|
||||||
function buildFormattedDescription(description_lines) {
|
|
||||||
let description = ""
|
|
||||||
for (let i in description_lines) {
|
|
||||||
let sentence = description_lines[i];
|
|
||||||
if (sentence.indexOf("Prerequisite") == 0)
|
|
||||||
sentence = `<li style='font-weight: bold;' class='descriptionli'>${sentence}</li>`;
|
|
||||||
else if (sentence.indexOf("May be") >= 0)
|
|
||||||
sentence = `<li style='font-style: italic;' class='descriptionli'>${sentence}</li>`;
|
|
||||||
else if (sentence.indexOf("Restricted to") == 0)
|
|
||||||
sentence = `<li style='color:red;' class='descriptionli'>${sentence}</li>`;
|
|
||||||
else
|
|
||||||
sentence = `<li class='descriptionli'>${sentence}</li>`;
|
|
||||||
description += sentence;
|
|
||||||
}
|
|
||||||
if (!description)
|
|
||||||
description = error_message;
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
function extractFirstName(response_node) {
|
|
||||||
let full_name = response_node.find('td[data-th="Instructor"]').text().split(', ');
|
|
||||||
let first = full_name[full_name.length - 1];
|
|
||||||
first = first.indexOf(' ') > 0 ? first.split(' ')[0] : first;
|
|
||||||
return capitalizeString(first);
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayDescription(description) {
|
|
||||||
toggleDescriptionLoading(false);
|
|
||||||
$("#description").animate({
|
|
||||||
'opacity': 0
|
|
||||||
}, 200, function () {
|
|
||||||
$(this).html(description).animate({
|
|
||||||
'opacity': 1
|
|
||||||
}, 200);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Get the course description from the profurl and highlight the important elements, as well as set the eCIS, and rmp links.*/
|
|
||||||
function getDescription(course_info) {
|
|
||||||
toggleDescriptionLoading(true);
|
|
||||||
$.ajax({
|
|
||||||
url: course_info["individual"],
|
|
||||||
success: function (response) {
|
|
||||||
if (response) {
|
|
||||||
let response_node = htmlToNode(response);
|
|
||||||
description_lines = response_node.find('#details > p').toArray().map(x => $(x).text());
|
|
||||||
displayDescription(buildFormattedDescription(description_lines));
|
|
||||||
let first_name = extractFirstName(response_node);
|
|
||||||
updateLinks(course_info, first_name);
|
|
||||||
} else {
|
|
||||||
displayDescription(error_message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadNextPages(num_pages) {
|
|
||||||
if (num_pages === undefined) num_pages = 1;
|
|
||||||
if (num_pages == 0) return;
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "getOptionsValue",
|
|
||||||
key: "loadAll",
|
|
||||||
}, function (response) {
|
|
||||||
if(response.value){
|
|
||||||
let link = next.prop('href');
|
|
||||||
if (done_loading && next && link) {
|
|
||||||
toggleLoadingPage(true);
|
|
||||||
$.get(link, function (response) {
|
|
||||||
if (response) {
|
|
||||||
var next_page = htmlToNode(response);
|
|
||||||
var current = $('tbody');
|
|
||||||
var old_length = $('tbody tr').length;
|
|
||||||
var last = current.find('.course_header>h2:last').text();
|
|
||||||
next = next_page.find("#next_nav_link");
|
|
||||||
toggleLoadingPage(false);
|
|
||||||
var new_rows = [];
|
|
||||||
next_page.find('tbody>tr').each(function () {
|
|
||||||
let has_course_header = $(this).find('td').hasClass("course_header");
|
|
||||||
if (!(has_course_header && $(this).has('th').length == 0))
|
|
||||||
$(this).append(Template.Main.extension_button());
|
|
||||||
if (!(has_course_header && last == $(this).find('td').text()))
|
|
||||||
new_rows.push($(this));
|
|
||||||
});
|
|
||||||
current.append(new_rows);
|
|
||||||
updateListConflictHighlighting(old_length + 1)
|
|
||||||
}
|
|
||||||
loadNextPages(num_pages-1);
|
|
||||||
}).fail(function () {
|
|
||||||
toggleLoadingPage(false);
|
|
||||||
$("#retrylabel").css('display', 'inline-block');
|
|
||||||
$('#retry').css('display', 'inline-block');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#myModal").on('click', '#saveCourse', function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
saveCourse();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#Syllabi").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["syllabi"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
$("#rateMyProf").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["rate_my_prof"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
$("#eCIS").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["ecis"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
$("#textbook").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["textbook"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
$("#semesters").on('change', function () {
|
|
||||||
let sem = $(this).val();
|
|
||||||
sem = sem == "Aggregate" ? undefined : sem;
|
|
||||||
getDistribution(curr_course, sem);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#retry").click(function () {
|
|
||||||
$("#retrylabel").hide();
|
|
||||||
$(this).hide();
|
|
||||||
loadNextPages();
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggleLoadingPage(loading) {
|
|
||||||
if (loading) {
|
|
||||||
done_loading = false;
|
|
||||||
$('#loader').css('display', 'inline-block');
|
|
||||||
$("#nextlabel").css('display', 'inline-block');
|
|
||||||
} else {
|
|
||||||
done_loading = true;
|
|
||||||
$('#loader').hide();
|
|
||||||
$("#nextlabel").hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleChartLoading(loading) {
|
|
||||||
if (loading) {
|
|
||||||
$('#chartload').css('display', 'inline-block');
|
|
||||||
$("#chart").hide();
|
|
||||||
} else {
|
|
||||||
$('#chartload').hide();
|
|
||||||
$("#chart").show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleDescriptionLoading(loading) {
|
|
||||||
if (loading) {
|
|
||||||
$('#descload').css('display', 'inline-block');
|
|
||||||
} else {
|
|
||||||
$('#descload').hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleSnackbar() {
|
|
||||||
setTimeout(function () {
|
|
||||||
$("#snackbar").attr("class", "show");
|
|
||||||
}, 200);
|
|
||||||
setTimeout(function () {
|
|
||||||
$("#snackbar").attr("class", "");
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function allowClosing() {
|
|
||||||
$('.close').click(function () {
|
|
||||||
close();
|
|
||||||
});
|
|
||||||
$('#myModal').click(function (event) {
|
|
||||||
if (event.target.id == 'myModal') {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
$("#myModal").fadeOut(Timing.fade_time);
|
|
||||||
$("#snackbar").attr("class", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Listen for update mssage coming from popup or calendar or other course catalog pages*/
|
|
||||||
chrome.runtime.onMessage.addListener(
|
|
||||||
function (request, sender, sendResponse) {
|
|
||||||
if (request.command == "updateCourseList") {
|
|
||||||
updateListConflictHighlighting(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$(document).keydown(function (e) {
|
|
||||||
/*Close Modal when hit escape*/
|
|
||||||
if (e.keyCode == 27) {
|
|
||||||
close();
|
|
||||||
} else if (e.keyCode == 13 && $('#myModal').is(':visible')) {
|
|
||||||
saveCourse();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$(window).scroll(function () {
|
|
||||||
if ($(document).height() <= $(window).scrollTop() + $(window).height() + 150)
|
|
||||||
loadNextPages();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
$(window).on('load', function () {
|
|
||||||
loadNextPages(3);
|
|
||||||
});
|
|
||||||
164
js/import.js
164
js/import.js
@@ -1,164 +0,0 @@
|
|||||||
var waitlist;
|
|
||||||
var sem;
|
|
||||||
$(function () {
|
|
||||||
waitlist = !(window.location.href.includes('https://utdirect.utexas.edu/registration/classlist.WBX'));
|
|
||||||
sem = waitlist ? $('[name="s_ccyys"]').val() : $("option[selected='selected']").val();
|
|
||||||
if (waitlist) {
|
|
||||||
$("[href='#top']").before(Template.Import.import_button());
|
|
||||||
$("[name='wl_see_my_waitlists']").before(Template.Import.store_waitlist_message());
|
|
||||||
$("[name='wl_see_my_waitlists']").after(Template.Import.waitlist_import_button());
|
|
||||||
extractWaitlistInfo();
|
|
||||||
} else {
|
|
||||||
$("table").after(Template.Import.import_button());
|
|
||||||
}
|
|
||||||
$("#import").prepend("<div id='snackbar'>import snackbar..</div>");
|
|
||||||
|
|
||||||
$("#import").click(function () {
|
|
||||||
search_nodes = waitlist ? $(".tbg").last().find(".tbon>td:first-child") : $("tr>td:first-child");
|
|
||||||
$(search_nodes).each(function () {
|
|
||||||
importCourse($(this), true);
|
|
||||||
})
|
|
||||||
importButtonAnimation($(this));
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#import_waitlist").click(function () {
|
|
||||||
search_nodes = $("tr.tb span:first-child");
|
|
||||||
$(search_nodes).each(function () {
|
|
||||||
importCourse($(this), false);
|
|
||||||
})
|
|
||||||
importButtonAnimation($(this));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function extractWaitlistInfo(){
|
|
||||||
let class_boxes = $("[name='wl_see_my_waitlists']>table");
|
|
||||||
let waitlist_info = [];
|
|
||||||
$(class_boxes).each(function(){
|
|
||||||
let data = $(this).find('tr.tb span');
|
|
||||||
let unique_num = $(data[0]).text().trim();
|
|
||||||
let class_name = $(data[1]).text().trim().split('\n').filter(part => part.trim() != '').map(part => part.trim()).join(' ');
|
|
||||||
let waitlist_size = $(this).find('tr.tbon:eq(2) td:eq(1)').text().trim().split(' of ')[1];
|
|
||||||
|
|
||||||
waitlist_info.push({
|
|
||||||
"id": unique_num,
|
|
||||||
"class": class_name,
|
|
||||||
"wait": waitlist_size,
|
|
||||||
"time": moment().format('DD-MM-YYYY HH:mm:ss')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.log(waitlist_info);
|
|
||||||
return waitlist_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function importButtonAnimation(button) {
|
|
||||||
let is_waitlisted_button = $(button).attr('id') == "import_waitlist";
|
|
||||||
let return_text = is_waitlisted_button ? Text.waitlist_button_text_default : Text.button_text_default;
|
|
||||||
$(button).text(Text.button_success).css("background-color", Colors.open);
|
|
||||||
setTimeout(function () {
|
|
||||||
$(button).html(return_text).css('background-color', Colors.waitlisted);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function importCourse(unique_node, force) {
|
|
||||||
let unique = $(unique_node).text().replace(/\s/g, '').substring(0,5);
|
|
||||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${sem}/${unique}/`;
|
|
||||||
buildAddCourse(link, force)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildAddCourse(link, force) {
|
|
||||||
$.get(link, function (response) {
|
|
||||||
if (response) {
|
|
||||||
let simp_course = buildSimplifiedCourseObject(response, link, force);
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "courseStorage",
|
|
||||||
course: simp_course,
|
|
||||||
action: "add"
|
|
||||||
}, function () {
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "updateCourseList"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildSimplifiedCourseObject(response, link, force) {
|
|
||||||
let imported_course = getCourseObject(htmlToNode(response), link);
|
|
||||||
let {
|
|
||||||
full_name,
|
|
||||||
unique,
|
|
||||||
prof_name,
|
|
||||||
individual,
|
|
||||||
status,
|
|
||||||
register
|
|
||||||
} = curr_course;
|
|
||||||
let dtarr = getDayTimeArray(undefined, curr_course);
|
|
||||||
if(force === true) {
|
|
||||||
status = "open" //forces the green status for courses a user is already registered for
|
|
||||||
}
|
|
||||||
return new Course(full_name, unique, prof_name, dtarr, status, individual, register);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*For a row, get all the course information and add the date-time-lines*/
|
|
||||||
function getCourseObject(response_node, individual) {
|
|
||||||
let course_name = $(response_node).find("#details h2").text();
|
|
||||||
let course_row = $(response_node).find('table');
|
|
||||||
curr_course = buildBasicCourseInfo(course_row, course_name, individual);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildBasicCourseInfo(row, course_name, individual) {
|
|
||||||
let {
|
|
||||||
name,
|
|
||||||
department,
|
|
||||||
number
|
|
||||||
} = separateCourseNameParts(course_name);
|
|
||||||
let instructor_text = $(row).find('td[data-th="Instructor"]').text();
|
|
||||||
let has_initial = instructor_text.indexOf(',') > 0;
|
|
||||||
course_info = {
|
|
||||||
"full_name": course_name,
|
|
||||||
"name": name,
|
|
||||||
"department": department,
|
|
||||||
"number": number,
|
|
||||||
"individual": individual ? individual : $(row).find('td[data-th="Unique"] a').prop('href'),
|
|
||||||
"register": $(row).find('td[data-th="Add"] a').prop('href'),
|
|
||||||
"unique": $(row).find('td[data-th="Unique"]').text(),
|
|
||||||
"status": $(row).find('td[data-th="Status"]').text(),
|
|
||||||
"prof_name": instructor_text ? has_initial ? capitalizeString(instructor_text.split(', ')[0]) : capitalizeString(instructor_text) : "Undecided",
|
|
||||||
"initial": instructor_text && has_initial ? instructor_text.split(', ')[1].substring(0, 1) : "",
|
|
||||||
"time_data": {
|
|
||||||
"days": $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim()),
|
|
||||||
"times": $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim()),
|
|
||||||
"places": $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim())
|
|
||||||
},
|
|
||||||
"links": {}
|
|
||||||
}
|
|
||||||
return course_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For a row, get the date-time-array for checking conflicts*/
|
|
||||||
function getDayTimeArray(row, course_info) {
|
|
||||||
var day_time_array = []
|
|
||||||
let days = course_info ? course_info["time_data"]["days"] : $(row).find('td[data-th="Days"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
let times = course_info ? course_info["time_data"]["times"] : $(row).find('td[data-th="Hour"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
let places = course_info ? course_info["time_data"]["places"] : $(row).find('td[data-th="Room"]>span').toArray().map(x => $(x).text().trim());
|
|
||||||
for (var i = 0; i < days.length; i++) {
|
|
||||||
let date = days[i];
|
|
||||||
let time = times[i];
|
|
||||||
let place = places[i];
|
|
||||||
for (var j = 0; j < date.length; j++) {
|
|
||||||
let letter = date.charAt(j);
|
|
||||||
if (letter == "T" && j < date.length - 1 && date.charAt(j + 1) == "H") {
|
|
||||||
day_time_array.push(["TH", convertTime(time), place]);
|
|
||||||
} else {
|
|
||||||
if (letter != "H")
|
|
||||||
day_time_array.push([letter, convertTime(time), place]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return day_time_array;
|
|
||||||
}
|
|
||||||
1
js/lib/fullcalendar.min.js
vendored
1
js/lib/fullcalendar.min.js
vendored
File diff suppressed because one or more lines are too long
8737
js/lib/highcharts.js
8737
js/lib/highcharts.js
File diff suppressed because it is too large
Load Diff
6
js/lib/html2canvas.min.js
vendored
6
js/lib/html2canvas.min.js
vendored
File diff suppressed because one or more lines are too long
231
js/lib/ics.min.js
vendored
231
js/lib/ics.min.js
vendored
@@ -1,231 +0,0 @@
|
|||||||
/*! ics.js Wed Aug 20 2014 17:23:02 */
|
|
||||||
var saveAs = saveAs || function (e) {
|
|
||||||
"use strict";
|
|
||||||
if (typeof e === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var t = e.document,
|
|
||||||
n = function () {
|
|
||||||
return e.URL || e.webkitURL || e
|
|
||||||
},
|
|
||||||
r = t.createElementNS("http://www.w3.org/1999/xhtml", "a"),
|
|
||||||
o = "download" in r,
|
|
||||||
a = function (e) {
|
|
||||||
var t = new MouseEvent("click");
|
|
||||||
e.dispatchEvent(t)
|
|
||||||
},
|
|
||||||
i = /constructor/i.test(e.HTMLElement) || e.safari,
|
|
||||||
f = /CriOS\/[\d]+/.test(navigator.userAgent),
|
|
||||||
u = function (t) {
|
|
||||||
(e.setImmediate || e.setTimeout)(function () {
|
|
||||||
throw t
|
|
||||||
}, 0)
|
|
||||||
},
|
|
||||||
s = "application/octet-stream",
|
|
||||||
d = 1e3 * 40,
|
|
||||||
c = function (e) {
|
|
||||||
var t = function () {
|
|
||||||
if (typeof e === "string") {
|
|
||||||
n().revokeObjectURL(e)
|
|
||||||
} else {
|
|
||||||
e.remove()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setTimeout(t, d)
|
|
||||||
},
|
|
||||||
l = function (e, t, n) {
|
|
||||||
t = [].concat(t);
|
|
||||||
var r = t.length;
|
|
||||||
while (r--) {
|
|
||||||
var o = e["on" + t[r]];
|
|
||||||
if (typeof o === "function") {
|
|
||||||
try {
|
|
||||||
o.call(e, n || e)
|
|
||||||
} catch (a) {
|
|
||||||
u(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
p = function (e) {
|
|
||||||
if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)) {
|
|
||||||
return new Blob([String.fromCharCode(65279), e], {
|
|
||||||
type: e.type
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
},
|
|
||||||
v = function (t, u, d) {
|
|
||||||
if (!d) {
|
|
||||||
t = p(t)
|
|
||||||
}
|
|
||||||
var v = this,
|
|
||||||
w = t.type,
|
|
||||||
m = w === s,
|
|
||||||
y, h = function () {
|
|
||||||
l(v, "writestart progress write writeend".split(" "))
|
|
||||||
},
|
|
||||||
S = function () {
|
|
||||||
if ((f || m && i) && e.FileReader) {
|
|
||||||
var r = new FileReader;
|
|
||||||
r.onloadend = function () {
|
|
||||||
var t = f ? r.result : r.result.replace(/^data:[^;]*;/, "data:attachment/file;");
|
|
||||||
var n = e.open(t, "_blank");
|
|
||||||
if (!n) e.location.href = t;
|
|
||||||
t = undefined;
|
|
||||||
v.readyState = v.DONE;
|
|
||||||
h()
|
|
||||||
};
|
|
||||||
r.readAsDataURL(t);
|
|
||||||
v.readyState = v.INIT;
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!y) {
|
|
||||||
y = n().createObjectURL(t)
|
|
||||||
}
|
|
||||||
if (m) {
|
|
||||||
e.location.href = y
|
|
||||||
} else {
|
|
||||||
var o = e.open(y, "_blank");
|
|
||||||
if (!o) {
|
|
||||||
e.location.href = y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v.readyState = v.DONE;
|
|
||||||
h();
|
|
||||||
c(y)
|
|
||||||
};
|
|
||||||
v.readyState = v.INIT;
|
|
||||||
if (o) {
|
|
||||||
y = n().createObjectURL(t);
|
|
||||||
setTimeout(function () {
|
|
||||||
r.href = y;
|
|
||||||
r.download = u;
|
|
||||||
a(r);
|
|
||||||
h();
|
|
||||||
c(y);
|
|
||||||
v.readyState = v.DONE
|
|
||||||
});
|
|
||||||
return
|
|
||||||
}
|
|
||||||
S()
|
|
||||||
},
|
|
||||||
w = v.prototype,
|
|
||||||
m = function (e, t, n) {
|
|
||||||
return new v(e, t || e.name || "download", n)
|
|
||||||
};
|
|
||||||
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
|
|
||||||
return function (e, t, n) {
|
|
||||||
t = t || e.name || "download";
|
|
||||||
if (!n) {
|
|
||||||
e = p(e)
|
|
||||||
}
|
|
||||||
return navigator.msSaveOrOpenBlob(e, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.abort = function () {};
|
|
||||||
w.readyState = w.INIT = 0;
|
|
||||||
w.WRITING = 1;
|
|
||||||
w.DONE = 2;
|
|
||||||
w.error = w.onwritestart = w.onprogress = w.onwrite = w.onabort = w.onerror = w.onwriteend = null;
|
|
||||||
return m
|
|
||||||
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content);
|
|
||||||
if (typeof module !== "undefined" && module.exports) {
|
|
||||||
module.exports.saveAs = saveAs
|
|
||||||
} else if (typeof define !== "undefined" && define !== null && define.amd !== null) {
|
|
||||||
define("FileSaver.js", function () {
|
|
||||||
return saveAs
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var ics = function (e, t) {
|
|
||||||
"use strict"; {
|
|
||||||
if (!(navigator.userAgent.indexOf("MSIE") > -1 && -1 == navigator.userAgent.indexOf("MSIE 10"))) {
|
|
||||||
void 0 === e && (e = "default"), void 0 === t && (t = "Calendar");
|
|
||||||
var r = -1 !== navigator.appVersion.indexOf("Win") ? "\r\n" : "\n",
|
|
||||||
n = [],
|
|
||||||
i = ["BEGIN:VCALENDAR", "PRODID:" + t, "VERSION:2.0"].join(r),
|
|
||||||
o = r + "END:VCALENDAR",
|
|
||||||
a = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
|
|
||||||
return {
|
|
||||||
events: function () {
|
|
||||||
return n
|
|
||||||
},
|
|
||||||
calendar: function () {
|
|
||||||
return i + r + n.join(r) + o
|
|
||||||
},
|
|
||||||
addEvent: function (t, i, o, l, u, s) {
|
|
||||||
if (void 0 === t || void 0 === i || void 0 === o || void 0 === l || void 0 === u) return !1;
|
|
||||||
if (s && !s.rrule) {
|
|
||||||
if ("YEARLY" !== s.freq && "MONTHLY" !== s.freq && "WEEKLY" !== s.freq && "DAILY" !== s.freq) throw "Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";
|
|
||||||
if (s.until && isNaN(Date.parse(s.until))) throw "Recurrence rrule 'until' must be a valid date string";
|
|
||||||
if (s.interval && isNaN(parseInt(s.interval))) throw "Recurrence rrule 'interval' must be an integer";
|
|
||||||
if (s.count && isNaN(parseInt(s.count))) throw "Recurrence rrule 'count' must be an integer";
|
|
||||||
if (void 0 !== s.byday) {
|
|
||||||
if ("[object Array]" !== Object.prototype.toString.call(s.byday)) throw "Recurrence rrule 'byday' must be an array";
|
|
||||||
if (s.byday.length > 7) throw "Recurrence rrule 'byday' array must not be longer than the 7 days in a week";
|
|
||||||
s.byday = s.byday.filter(function (e, t) {
|
|
||||||
return s.byday.indexOf(e) == t
|
|
||||||
});
|
|
||||||
for (var c in s.byday)
|
|
||||||
if (a.indexOf(s.byday[c]) < 0) throw "Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var g = new Date(l),
|
|
||||||
d = new Date(u),
|
|
||||||
f = new Date,
|
|
||||||
S = ("0000" + g.getFullYear().toString()).slice(-4),
|
|
||||||
E = ("00" + (g.getMonth() + 1).toString()).slice(-2),
|
|
||||||
v = ("00" + g.getDate().toString()).slice(-2),
|
|
||||||
y = ("00" + g.getHours().toString()).slice(-2),
|
|
||||||
A = ("00" + g.getMinutes().toString()).slice(-2),
|
|
||||||
T = ("00" + g.getSeconds().toString()).slice(-2),
|
|
||||||
b = ("0000" + d.getFullYear().toString()).slice(-4),
|
|
||||||
D = ("00" + (d.getMonth() + 1).toString()).slice(-2),
|
|
||||||
N = ("00" + d.getDate().toString()).slice(-2),
|
|
||||||
h = ("00" + d.getHours().toString()).slice(-2),
|
|
||||||
I = ("00" + d.getMinutes().toString()).slice(-2),
|
|
||||||
R = ("00" + d.getMinutes().toString()).slice(-2),
|
|
||||||
M = ("0000" + f.getFullYear().toString()).slice(-4),
|
|
||||||
w = ("00" + (f.getMonth() + 1).toString()).slice(-2),
|
|
||||||
L = ("00" + f.getDate().toString()).slice(-2),
|
|
||||||
O = ("00" + f.getHours().toString()).slice(-2),
|
|
||||||
p = ("00" + f.getMinutes().toString()).slice(-2),
|
|
||||||
Y = ("00" + f.getMinutes().toString()).slice(-2),
|
|
||||||
U = "",
|
|
||||||
V = "";
|
|
||||||
y + A + T + h + I + R != 0 && (U = "T" + y + A + T, V = "T" + h + I + R);
|
|
||||||
var B, C = S + E + v + U,
|
|
||||||
j = b + D + N + V,
|
|
||||||
m = M + w + L + ("T" + O + p + Y);
|
|
||||||
if (s)
|
|
||||||
if (s.rrule) B = s.rrule;
|
|
||||||
else {
|
|
||||||
if (B = "rrule:FREQ=" + s.freq, s.until) {
|
|
||||||
var x = new Date(Date.parse(s.until)).toISOString();
|
|
||||||
B += ";UNTIL=" + x.substring(0, x.length - 13).replace(/[-]/g, "") + "000000Z"
|
|
||||||
}
|
|
||||||
s.interval && (B += ";INTERVAL=" + s.interval), s.count && (B += ";COUNT=" + s.count), s.byday && s.byday.length > 0 && (B += ";BYDAY=" + s.byday.join(","))
|
|
||||||
}(new Date).toISOString();
|
|
||||||
var H = ["BEGIN:VEVENT", "UID:" + n.length + "@" + e, "CLASS:PUBLIC", "DESCRIPTION:" + i, "DTSTAMP;VALUE=DATE-TIME:" + m, "DTSTART;VALUE=DATE-TIME:" + C, "DTEND;VALUE=DATE-TIME:" + j, "LOCATION:" + o, "SUMMARY;LANGUAGE=en-us:" + t, "TRANSP:TRANSPARENT", "END:VEVENT"];
|
|
||||||
return B && H.splice(4, 0, B), H = H.join(r), n.push(H), H
|
|
||||||
},
|
|
||||||
download: function (e, t) {
|
|
||||||
if (n.length < 1) return !1;
|
|
||||||
t = void 0 !== t ? t : ".ics", e = void 0 !== e ? e : "calendar";
|
|
||||||
var a, l = i + r + n.join(r) + o;
|
|
||||||
if (-1 === navigator.userAgent.indexOf("MSIE 10")) a = new Blob([l]);
|
|
||||||
else {
|
|
||||||
var u = new BlobBuilder;
|
|
||||||
u.append(l), a = u.getBlob("text/x-vCalendar;charset=" + document.characterSet)
|
|
||||||
}
|
|
||||||
return saveAs(a, e + t), l
|
|
||||||
},
|
|
||||||
build: function () {
|
|
||||||
return !(n.length < 1) && i + r + n.join(r) + o
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("Unsupported Browser")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
2
js/lib/jquery-3.3.1.min.js
vendored
2
js/lib/jquery-3.3.1.min.js
vendored
File diff suppressed because one or more lines are too long
1
js/lib/jquery.initialize.min.js
vendored
1
js/lib/jquery.initialize.min.js
vendored
@@ -1 +0,0 @@
|
|||||||
(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);
|
|
||||||
1
js/lib/moment.min.js
vendored
1
js/lib/moment.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,60 +0,0 @@
|
|||||||
var manifestData = chrome.runtime.getManifest();
|
|
||||||
$("#version").text(manifestData.version);
|
|
||||||
|
|
||||||
chrome.storage.sync.get("options", function (data) {
|
|
||||||
if (data.options) {
|
|
||||||
console.log(data.options);
|
|
||||||
Object.keys(data.options).forEach(key => {
|
|
||||||
let enabled = data.options[key];
|
|
||||||
$("#options_container").append(Template.Options.options_row(key, enabled));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("body").on("click", "button", function () {
|
|
||||||
let key = $(this).attr("id");
|
|
||||||
let old_status = $(this).val() === "true";
|
|
||||||
let new_status = !old_status;
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{
|
|
||||||
command: "setOptionsValue",
|
|
||||||
key: key,
|
|
||||||
value: new_status,
|
|
||||||
},
|
|
||||||
function (response) {
|
|
||||||
console.log(response.value);
|
|
||||||
toggle(key, response.value);
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$.get("https://api.github.com/repos/sghsri/UT-Registration-Plus/stats/contributors", data => {
|
|
||||||
data = data.sort((a, b) => b.total - a.total);
|
|
||||||
console.log("data", data);
|
|
||||||
for (var contributorData of data) {
|
|
||||||
$.get(`https://api.github.com/users/${contributorData.author.login}`, userData => {
|
|
||||||
let fullData = { ...contributorData, ...userData };
|
|
||||||
let { login, avatar_url, html_url, name } = fullData;
|
|
||||||
if(name){
|
|
||||||
$("#contributor-list").append(Template.Options.contributor_card(login, name, avatar_url, html_url));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$("#contributor-list").append(Template.Options.contributor_card("", login, avatar_url, html_url));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("body").on("click", ".contributor-card", function () {
|
|
||||||
console.log("hello world");
|
|
||||||
window.open($(this).data("url"), "_blank");
|
|
||||||
});
|
|
||||||
|
|
||||||
function toggle(key, value) {
|
|
||||||
let button_text = value ? "Turn Off" : "Turn On";
|
|
||||||
let button_color = value ? Colors.closed : Colors.open;
|
|
||||||
$(`#${key}`).text(button_text);
|
|
||||||
$(`#${key}`).css("background", button_color);
|
|
||||||
$(`#${key}`).val(value);
|
|
||||||
}
|
|
||||||
437
js/popup.js
437
js/popup.js
@@ -1,437 +0,0 @@
|
|||||||
var courses;
|
|
||||||
|
|
||||||
setCourseList();
|
|
||||||
getSemesters();
|
|
||||||
getDepartments();
|
|
||||||
|
|
||||||
var can_remove = true;
|
|
||||||
|
|
||||||
function setCourseList() {
|
|
||||||
$("#courseList").empty();
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
updateConflicts();
|
|
||||||
courses = data.savedCourses;
|
|
||||||
handleEmpty();
|
|
||||||
let hours = 0;
|
|
||||||
// build and append the course list element
|
|
||||||
for (var i = 0; i < courses.length; i++) {
|
|
||||||
let { coursename, unique, profname, status, datetimearr } = courses[i];
|
|
||||||
profname = capitalizeString(profname);
|
|
||||||
let line = buildTimeLines(datetimearr);
|
|
||||||
let list_tile_color = getStatusColor(status);
|
|
||||||
let list_sub_color = getStatusColor(status, true);
|
|
||||||
let { department, number } = separateCourseNameParts(coursename);
|
|
||||||
let class_length = parseInt(number.charAt(0));
|
|
||||||
let multi_semester_code = number.slice(-1);
|
|
||||||
if (["A", "B"].includes(multi_semester_code)) {
|
|
||||||
hours += Math.floor(class_length / 2);
|
|
||||||
} else if (["X", "Y", "Z"].includes(multi_semester_code)) {
|
|
||||||
hours += Math.floor(class_length / 3);
|
|
||||||
} else {
|
|
||||||
hours += class_length;
|
|
||||||
}
|
|
||||||
let list_html = Template.Popup.list_item(i, list_tile_color, unique, department, number, profname, list_sub_color, line);
|
|
||||||
$("#courseList").append(list_html);
|
|
||||||
}
|
|
||||||
$("#meta-metric").text(hours);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert from the dtarr and maek the time lines*/
|
|
||||||
function buildTimeLines(datetimearr) {
|
|
||||||
let lines = convertDateTimeArrToLine(datetimearr);
|
|
||||||
let output = "";
|
|
||||||
if (lines.length == 0) {
|
|
||||||
output = "<span style='font-size:medium;'>This class has no meeting times.</span>";
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
|
||||||
let line = lines[i];
|
|
||||||
output += Template.Popup.line(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the conflict messages */
|
|
||||||
function updateConflicts() {
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{
|
|
||||||
command: "checkConflicts",
|
|
||||||
},
|
|
||||||
function (response) {
|
|
||||||
console.log("updateConflicts -> response", response);
|
|
||||||
if (response.isConflict) {
|
|
||||||
var between = response.between;
|
|
||||||
let conflict_message = "";
|
|
||||||
for (var i = 0; i < between.length; i++) {
|
|
||||||
let courseA = between[i][0];
|
|
||||||
let courseB = between[i][1];
|
|
||||||
conflict_message += `CONFLICT: ${formatShortenedCourseName(courseA)} and ${formatShortenedCourseName(courseB)}`;
|
|
||||||
if (i != between.length - 1) conflict_message += "<br>";
|
|
||||||
}
|
|
||||||
$(Template.Popup.conflict_message(conflict_message)).prependTo("#courseList").hide().fadeIn(200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prettify the name for the conflict messages*/
|
|
||||||
function formatShortenedCourseName(course) {
|
|
||||||
let { number, department } = separateCourseNameParts(course.coursename);
|
|
||||||
return `${department} ${number} (${course.unique})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).click(function (event) {
|
|
||||||
$target = $(event.target);
|
|
||||||
|
|
||||||
// If we're not clicking on search button or search popup, and popup is visible, hide it
|
|
||||||
if (!$target.closest("#search").length && !$target.closest("#search-popup").length && $("#search-popup").is(":visible")) {
|
|
||||||
hideSearchPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're not clicking on import/export button or imp/exp popup, and popup is visible, hide it
|
|
||||||
if (!$target.closest("#impexp").length && !$target.closest("#import-export-popup").length && $("#import-export-popup").is(":visible")) {
|
|
||||||
hideImportExportPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#clear").click(function () {
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: [],
|
|
||||||
});
|
|
||||||
$("#courseList").empty();
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
showEmpty();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#RIS").click(function () {
|
|
||||||
chrome.tabs.create({
|
|
||||||
url: "https://utdirect.utexas.edu/registrar/ris.WBX",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#calendar").click(function () {
|
|
||||||
chrome.tabs.create({
|
|
||||||
url: "calendar.html",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#impexp").click(function () {
|
|
||||||
if ($("#impexp>i").text() == "close") {
|
|
||||||
hideImportExportPopup();
|
|
||||||
} else {
|
|
||||||
if ($("#search>i").text() == "close") {
|
|
||||||
hideSearchPopup();
|
|
||||||
}
|
|
||||||
showImportExportPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#search").click(function () {
|
|
||||||
if ($("#search>i").text() == "close") {
|
|
||||||
hideSearchPopup();
|
|
||||||
} else {
|
|
||||||
if ($("#impexp>i").text() == "close") {
|
|
||||||
hideImportExportPopup();
|
|
||||||
}
|
|
||||||
showSearchPopup();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#import-class").click(function () {
|
|
||||||
$("#import_input").click();
|
|
||||||
console.log("back to improting");
|
|
||||||
});
|
|
||||||
|
|
||||||
function isImportedValid(imported_courses) {
|
|
||||||
return imported_courses && imported_courses.length && (imported_courses.length == 0 || validateCourses(imported_courses));
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#import_input").change(function (e) {
|
|
||||||
console.log("hello");
|
|
||||||
var files = e.target.files;
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function () {
|
|
||||||
try {
|
|
||||||
var imported_courses = JSON.parse(this.result);
|
|
||||||
if (isImportedValid(imported_courses)) {
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
savedCourses: imported_courses,
|
|
||||||
});
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
setCourseList();
|
|
||||||
hideImportExportPopup();
|
|
||||||
$("#import_input").val("");
|
|
||||||
} else {
|
|
||||||
Alert("There was an error.");
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.readAsText(files[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
function exportCourses(url) {
|
|
||||||
var exportlink = document.createElement("a");
|
|
||||||
exportlink.setAttribute("href", url);
|
|
||||||
exportlink.setAttribute("download", "my_courses.json");
|
|
||||||
exportlink.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createBlob(export_courses) {
|
|
||||||
return new Blob([JSON.stringify(export_courses, null, 4)], {
|
|
||||||
type: "octet/stream",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#export-class").click(function () {
|
|
||||||
chrome.storage.sync.get("savedCourses", function (data) {
|
|
||||||
let export_courses = data.savedCourses;
|
|
||||||
if (export_courses.length > 0) {
|
|
||||||
let url = window.URL.createObjectURL(createBlob(export_courses));
|
|
||||||
exportCourses(url);
|
|
||||||
} else {
|
|
||||||
alert("No Saved Courses to Export.");
|
|
||||||
}
|
|
||||||
hideImportExportPopup();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function openSearch(semester, department, level, courseCode) {
|
|
||||||
var link = "";
|
|
||||||
if (courseCode) {
|
|
||||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester}/results/?search_type_main=COURSE&fos_cn=${department}&course_number=${courseCode}`;
|
|
||||||
} else {
|
|
||||||
link = `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester}/results/?fos_fl=${department}&level=${level}&search_type_main=FIELD`;
|
|
||||||
}
|
|
||||||
chrome.tabs.create({ url: link });
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#search-class").click(() => {
|
|
||||||
let semester = $("#semesters").find(":selected").val();
|
|
||||||
let department = $("#department").find(":selected").val();
|
|
||||||
let level = $("#level").find(":selected").val();
|
|
||||||
let courseCode = $("#courseCode").val();
|
|
||||||
openSearch(semester, department, level, courseCode);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#options_button").click(function () {
|
|
||||||
chrome.tabs.create({
|
|
||||||
url: "options.html",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#courseList")
|
|
||||||
.on("mouseover", ".copy_button", function () {
|
|
||||||
$(this).addClass("shadow");
|
|
||||||
})
|
|
||||||
.on("mouseleave", ".copy_button", function () {
|
|
||||||
$(this).removeClass("shadow");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#courseList").on("click", ".copy_button", function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
copyButtonAnimation($(this));
|
|
||||||
let unique = $(this).val();
|
|
||||||
copyUnique(unique);
|
|
||||||
});
|
|
||||||
|
|
||||||
function copyUnique(unique) {
|
|
||||||
var temp = $("<input>");
|
|
||||||
$("body").append(temp);
|
|
||||||
temp.val(unique).select();
|
|
||||||
document.execCommand("copy");
|
|
||||||
temp.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#courseList").on("click", "li", function () {
|
|
||||||
let clicked_item = $(this).closest("li");
|
|
||||||
let curr_course = courses[$(clicked_item).attr("id")];
|
|
||||||
handleMoreInfo(clicked_item, curr_course);
|
|
||||||
handleRegister(clicked_item, curr_course);
|
|
||||||
handleRemove(clicked_item, curr_course);
|
|
||||||
toggleTimeDropdown(clicked_item);
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleRegister(clicked_item, curr_course) {
|
|
||||||
let { status, registerlink } = curr_course;
|
|
||||||
let register_button = $(clicked_item).find("#register");
|
|
||||||
let can_not_register = canNotRegister(status, registerlink);
|
|
||||||
let register_text = can_not_register ? "Can't Register" : status.includes("waitlisted") ? "Join Waitlist" : "Register";
|
|
||||||
let register_color = can_not_register ? Colors.closed : status.includes("waitlisted") ? Colors.waitlisted : Colors.open;
|
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
register_text = "No Status";
|
|
||||||
register_color = Colors.no_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(register_button).text(register_text).css("background-color", register_color);
|
|
||||||
|
|
||||||
if (!can_not_register) {
|
|
||||||
$(register_button).click(function () {
|
|
||||||
setCurrentTabUrl(registerlink);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleRemove(clicked_item, curr_course) {
|
|
||||||
let list = $(clicked_item).closest("ul");
|
|
||||||
$(clicked_item)
|
|
||||||
.find("#listRemove")
|
|
||||||
.click(function () {
|
|
||||||
if (can_remove) {
|
|
||||||
can_remove = false;
|
|
||||||
$(list)
|
|
||||||
.find("#conflict")
|
|
||||||
.fadeOut(300, function () {
|
|
||||||
$(clicked_item).remove();
|
|
||||||
});
|
|
||||||
subtractHours(curr_course);
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{
|
|
||||||
command: "courseStorage",
|
|
||||||
course: curr_course,
|
|
||||||
action: "remove",
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
$(clicked_item).fadeOut(200);
|
|
||||||
if ($(list).children(":visible").length === 1) showEmpty();
|
|
||||||
can_remove = true;
|
|
||||||
updateConflicts();
|
|
||||||
updateAllTabsCourseList();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function subtractHours(curr_course) {
|
|
||||||
let curr_total_hours = parseInt($("#meta-metric").text());
|
|
||||||
let curr_course_number = separateCourseNameParts(curr_course.coursename).number;
|
|
||||||
let class_length = parseInt(curr_course_number.charAt(0));
|
|
||||||
let multi_semester_code = curr_course_number.slice(-1);
|
|
||||||
if (["A", "B"].includes(multi_semester_code)) {
|
|
||||||
$("#meta-metric").text(curr_total_hours - Math.floor(class_length / 2));
|
|
||||||
} else if (["X", "Y", "Z"].includes(multi_semester_code)) {
|
|
||||||
$("#meta-metric").text(curr_total_hours - Math.floor(class_length / 3));
|
|
||||||
} else {
|
|
||||||
$("#meta-metric").text(curr_total_hours - class_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMoreInfo(clicked_item, curr_course) {
|
|
||||||
$(clicked_item)
|
|
||||||
.find("#listMoreInfo")
|
|
||||||
.click(function () {
|
|
||||||
openMoreInfoWithOpenModal(curr_course.link);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEmpty() {
|
|
||||||
if (courses.length != 0) {
|
|
||||||
$("#empty").hide();
|
|
||||||
$("#courseList").show();
|
|
||||||
} else {
|
|
||||||
showEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyButtonAnimation(copy_button) {
|
|
||||||
$(copy_button).find("i").text("check");
|
|
||||||
$(copy_button).stop(true, false).removeAttr("style").removeClass("shadow", {
|
|
||||||
duration: 200,
|
|
||||||
});
|
|
||||||
$(copy_button)
|
|
||||||
.find("i")
|
|
||||||
.delay(400)
|
|
||||||
.queue(function (n) {
|
|
||||||
$(this).text("content_copy");
|
|
||||||
$(this).parent().removeClass("shadow");
|
|
||||||
if ($(this).parent().is(":hover")) {
|
|
||||||
$(this).parent().addClass("shadow");
|
|
||||||
}
|
|
||||||
n();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTimeDropdown(clicked_item) {
|
|
||||||
let more_info_button = $(clicked_item).find("#moreInfo");
|
|
||||||
let arrow = $(clicked_item).find("#arrow");
|
|
||||||
if ($(more_info_button).is(":hidden")) {
|
|
||||||
$(more_info_button).fadeIn(200);
|
|
||||||
$(arrow).css("transform", "rotate(90deg)");
|
|
||||||
} else {
|
|
||||||
$(more_info_button).fadeOut(200);
|
|
||||||
$(arrow).css("transform", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showEmpty() {
|
|
||||||
$("#courseList").hide();
|
|
||||||
$("#empty").fadeIn(200);
|
|
||||||
$("#main").html(Text.emptyText());
|
|
||||||
$("#meta-metric").text("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideSearchPopup() {
|
|
||||||
$("#search>i").text("search");
|
|
||||||
$("#semcon").hide();
|
|
||||||
$("#depcon").hide();
|
|
||||||
$("#semesters").hide();
|
|
||||||
$("#levcon").hide();
|
|
||||||
$("#search-popup").addClass("hide");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSearchPopup() {
|
|
||||||
$("#search>i").text("close");
|
|
||||||
$("#class_id_input").show();
|
|
||||||
$("#semesters").show();
|
|
||||||
$("#semcon").show();
|
|
||||||
$("#depcon").show();
|
|
||||||
$("#levcon").show();
|
|
||||||
$("#search-popup").removeClass("hide");
|
|
||||||
}
|
|
||||||
|
|
||||||
function hideImportExportPopup() {
|
|
||||||
$("#import-export-popup").addClass("hide");
|
|
||||||
$("#impexp>i").text("import_export");
|
|
||||||
}
|
|
||||||
|
|
||||||
function showImportExportPopup() {
|
|
||||||
$("#impexp>i").text("close");
|
|
||||||
$("#import-export-popup").removeClass("hide");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSemesters() {
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{
|
|
||||||
command: "currentSemesters",
|
|
||||||
},
|
|
||||||
function (response) {
|
|
||||||
let { semesters } = response;
|
|
||||||
let semester_names = Object.keys(semesters);
|
|
||||||
for (let i = 0; i < semester_names.length; i++) {
|
|
||||||
let name = semester_names[i];
|
|
||||||
$("#semesters").append(`<option value='${semesters[name]}'>${name}</option>`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDepartments() {
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{
|
|
||||||
command: "currentDepartments",
|
|
||||||
},
|
|
||||||
function (response) {
|
|
||||||
let { departments } = response;
|
|
||||||
console.log(departments);
|
|
||||||
for (let i = 0; i < departments.length; i++) {
|
|
||||||
let abv = departments[i];
|
|
||||||
$("#department").append(`<option value='${abv}'>${abv}</option>`);
|
|
||||||
}
|
|
||||||
// $("#department").val('C S');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
242
js/utPlanner.js
242
js/utPlanner.js
@@ -1,242 +0,0 @@
|
|||||||
let semester_code = "";
|
|
||||||
curr_course = {}
|
|
||||||
|
|
||||||
chrome.runtime.sendMessage({
|
|
||||||
command: "currentSemesters"
|
|
||||||
}, function(response){
|
|
||||||
let semester_text = $('.row:contains(Semester)').find('span').text();
|
|
||||||
let key = semester_text.split(' ').reverse().join(' ');
|
|
||||||
semester_code = response.semesters[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
$.initialize("table.section-detail-grid", function () {
|
|
||||||
$(this).find('thead>tr').append('<th> Plus</th')
|
|
||||||
$(this).find('tbody>tr').each(function () {
|
|
||||||
$(this).append(Template.Main.extension_button());
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
$("body").prepend(Template.UTPlanner.modal());
|
|
||||||
$("body").on('click', '#distButton', function () {
|
|
||||||
var row = $(this).closest('tr');
|
|
||||||
$('.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,
|
|
||||||
"individual": `https://utdirect.utexas.edu/apps/registrar/course_schedule/${semester_code}/${uniquenum}/`,
|
|
||||||
"times": times,
|
|
||||||
}
|
|
||||||
curr_course = buildCourseLinks(course_data);
|
|
||||||
getDistribution(course_data);
|
|
||||||
var modal = document.getElementById('myModal');
|
|
||||||
window.onclick = function (event) {
|
|
||||||
if (event.target == modal) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildCourseLinks(course_info) {
|
|
||||||
console.log(semester_code);
|
|
||||||
let {
|
|
||||||
department,
|
|
||||||
number,
|
|
||||||
unique,
|
|
||||||
prof_name
|
|
||||||
} = course_info
|
|
||||||
links = {
|
|
||||||
"textbook": `https://www.universitycoop.com/adoption-search-results?sn=${semester_code}__${department}__${number}__${unique}`,
|
|
||||||
"syllabi": `https://utdirect.utexas.edu/apps/student/coursedocs/nlogon/?year=&semester=&department=${department}&course_number=${number}&course_title=&unique=&instructor_first=&instructor_last=${prof_name}&course_type=In+Residence&search=Search`,
|
|
||||||
}
|
|
||||||
course_info["links"] = links;
|
|
||||||
return course_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#Syllabi").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["syllabi"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
$("#textbook").click(function () {
|
|
||||||
setTimeout(function () {
|
|
||||||
window.open(curr_course["links"]["textbook"]);
|
|
||||||
}, Timing.button_delay);
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#moreInfo").click(function () {
|
|
||||||
openMoreInfoWithOpenModal(curr_course["individual"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function toggleChartLoading(loading) {
|
|
||||||
if (loading) {
|
|
||||||
$('#chartload').css('display', 'inline-block');
|
|
||||||
$("#chart").hide();
|
|
||||||
} else {
|
|
||||||
$('#chartload').hide();
|
|
||||||
$("#chart").show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function openDialog(course_data, res) {
|
|
||||||
console.log(course_data);
|
|
||||||
$("#title").text(buildTitle(course_data))
|
|
||||||
$("#topbuttons").before(buildTimeTitle(course_data["times"]));
|
|
||||||
$("#profname").text(buildProfTitle(course_data));
|
|
||||||
$("#myModal").fadeIn(Timing.fade_time);
|
|
||||||
buildSemestersDropdown(course_data, res)
|
|
||||||
var data = []
|
|
||||||
if (!badData(course_data, res))
|
|
||||||
data = res.values[0];
|
|
||||||
setChart(data);
|
|
||||||
allowClosing();
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
toggleChartLoading(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 makeLine(date, time, place) {
|
|
||||||
var arr = separateDays(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 setChart(data) {
|
|
||||||
//set up the chart
|
|
||||||
toggleChartLoading(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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function standardizeName(department, number, name){
|
|
||||||
return `${department} ${number} ${name}`
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function allowClosing() {
|
|
||||||
$('.close').click(function () {
|
|
||||||
close();
|
|
||||||
});
|
|
||||||
$('#myModal').click(function (event) {
|
|
||||||
if (event.target.id == 'myModal') {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
$("#myModal").fadeOut(Timing.fade_time);
|
|
||||||
$("#snackbar").attr("class", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$(document).keydown(function (e) {
|
|
||||||
/*Close Modal when hit escape*/
|
|
||||||
if (e.keyCode == 27) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
386
js/util.js
386
js/util.js
@@ -1,386 +0,0 @@
|
|||||||
const days = new Map([
|
|
||||||
["M", "Monday"],
|
|
||||||
["T", "Tuesday"],
|
|
||||||
["W", "Wednesday"],
|
|
||||||
["TH", "Thursday"],
|
|
||||||
["F", "Friday"]
|
|
||||||
]);
|
|
||||||
|
|
||||||
function getStatusColor(status, sub = false) {
|
|
||||||
let color = "black";
|
|
||||||
if (status.includes("open")) {
|
|
||||||
color = sub ? Colors.open_light : Colors.open;
|
|
||||||
} else if (status.includes("waitlisted")) {
|
|
||||||
color = sub ? Colors.waitlisted_light : Colors.waitlisted;
|
|
||||||
} else if (status.includes("closed") || status.includes("cancelled")) {
|
|
||||||
color = sub ? Colors.closed_light : Colors.closed;
|
|
||||||
} else {
|
|
||||||
color = sub ? Colors.no_status_light : Colors.no_status;
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Course object for passing to background*/
|
|
||||||
function Course(coursename, unique, profname, datetimearr, status, link, registerlink) {
|
|
||||||
this.coursename = coursename;
|
|
||||||
this.unique = unique;
|
|
||||||
this.profname = profname;
|
|
||||||
this.datetimearr = datetimearr;
|
|
||||||
this.status = status;
|
|
||||||
this.link = link;
|
|
||||||
this.registerlink = registerlink;
|
|
||||||
}
|
|
||||||
|
|
||||||
function capitalizeString(string) {
|
|
||||||
//if one word, and if multiple words:
|
|
||||||
let output = "";
|
|
||||||
words = string.split(/[. ,\/ -]/);
|
|
||||||
for (let i in words) {
|
|
||||||
word = words[i];
|
|
||||||
capitalizedWord = word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
||||||
output += capitalizedWord + " ";
|
|
||||||
}
|
|
||||||
return output.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
function separateCourseNameParts(name) {
|
|
||||||
let num_index = name.search(/\d/);
|
|
||||||
department = name.substring(0, num_index).trim();
|
|
||||||
number = name.substring(num_index, name.indexOf(" ", num_index)).trim();
|
|
||||||
name = capitalizeString(name.substring(name.indexOf(" ", num_index)).trim());
|
|
||||||
return {
|
|
||||||
name: name,
|
|
||||||
department: department,
|
|
||||||
number: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function separateDays(date, simple=false) {
|
|
||||||
let arr = [];
|
|
||||||
for (var i = 0; i < date.length; i++) {
|
|
||||||
let letter = date.charAt(i);
|
|
||||||
let separated_letter = letter;
|
|
||||||
if (letter == "T" && i < date.length - 1 && date.charAt(i + 1) == "H") {
|
|
||||||
arr.push(simple ? "TH" : days.get("TH"));
|
|
||||||
} else {
|
|
||||||
if (letter != "H") {
|
|
||||||
arr.push(simple ? letter : days.get(letter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*Convert time to 24hour format*/
|
|
||||||
function convertTime(time) {
|
|
||||||
var converted = time.replace(/\./g, '').split("-");
|
|
||||||
for (var i = 0; i < 2; i++) {
|
|
||||||
converted[i] = moment(converted[i], ["h:mm A"]).format("HH:mm");
|
|
||||||
}
|
|
||||||
return converted;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 isIndividualCoursePage(){
|
|
||||||
return $("#textbook_button").length != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function updateAllTabsCourseList() {
|
|
||||||
chrome.tabs.query({}, function (tabs) {
|
|
||||||
for (var i = 0; i < tabs.length; i++) {
|
|
||||||
chrome.tabs.sendMessage(tabs[i].id, {
|
|
||||||
command: "updateCourseList"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function htmlToNode(response) {
|
|
||||||
return $('<div/>').html(response).contents();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCurrentTabUrl(link) {
|
|
||||||
chrome.tabs.query({
|
|
||||||
currentWindow: true,
|
|
||||||
active: true
|
|
||||||
}, function (tab) {
|
|
||||||
chrome.tabs.update(tab.id, {
|
|
||||||
url: link
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openMoreInfoWithOpenModal(link){
|
|
||||||
chrome.runtime.sendMessage({ command: "setOpen", url: link });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function semesterSort(semA, semB) {
|
|
||||||
let semOrder = {
|
|
||||||
"Spring": 0,
|
|
||||||
"Fall": 1,
|
|
||||||
"Summer": 2,
|
|
||||||
"Winter": 3
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert from the dtarr and maek the time lines*/
|
|
||||||
function convertDateTimeArrToLine(datetimearr) {
|
|
||||||
var output = [];
|
|
||||||
var dtmap = makeDateTimeMap(datetimearr);
|
|
||||||
var timearr = Array.from(dtmap.keys());
|
|
||||||
var temporary = Array.from(dtmap.values())
|
|
||||||
var dayarr = []
|
|
||||||
var locarr = []
|
|
||||||
for(x in temporary) {
|
|
||||||
dayarr.push(temporary[x][0])
|
|
||||||
locarr.push(temporary[x][1])
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < dayarr.length; i++) {
|
|
||||||
//var place = findLocation(dayarr[i], timearr[i], datetimearr);
|
|
||||||
var place = locarr[i]
|
|
||||||
var building = place.substring(0, place.search(/\d/)).trim();
|
|
||||||
building = building ? building : "Undecided Location"
|
|
||||||
var timearrsplit = timearr[i].split(',')
|
|
||||||
output.push({
|
|
||||||
"days": dayarr[i],
|
|
||||||
"start_time": timearrsplit[0],
|
|
||||||
"end_time": timearrsplit[1],
|
|
||||||
"location_link": `https://maps.utexas.edu/buildings/UTM/${building}`,
|
|
||||||
"location_full": place
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeDateTimeMap(datetimearr) {
|
|
||||||
var dtmap = new Map([]);
|
|
||||||
for (var i = 0; i < datetimearr.length; i++) {
|
|
||||||
datetimearr[i][1][0] = moment(datetimearr[i][1][0], ["HH:mm A"]).format("h:mm A");
|
|
||||||
datetimearr[i][1][1] = moment(datetimearr[i][1][1], ["HH:mm A"]).format("h:mm A");
|
|
||||||
}
|
|
||||||
for (var i = 0; i < datetimearr.length; i++) {
|
|
||||||
var instance = datetimearr[i]
|
|
||||||
var day = String(instance[0])
|
|
||||||
var timeslot = String(instance[1])
|
|
||||||
var location = String(instance[2])
|
|
||||||
var key = timeslot + "," + location
|
|
||||||
if (dtmap.has(key) && dtmap.get(key)[1] === location) {
|
|
||||||
dtmap.set(key, [dtmap.get(key)[0] + day, location]);
|
|
||||||
} else {
|
|
||||||
dtmap.set(key, [day, location]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dtmap
|
|
||||||
}
|
|
||||||
//find the location of a class given its days and timearrs.
|
|
||||||
function findLocation(day, timearr, datetimearr) {
|
|
||||||
for (let i = 0; i < datetimearr.length; i++) {
|
|
||||||
var dtl = datetimearr[i];
|
|
||||||
if (day.includes(dtl[0])) {
|
|
||||||
if (JSON.stringify(timearr) == JSON.stringify(reformatDateTime(dtl[1]))) {
|
|
||||||
return dtl[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function validateCourses(courses) {
|
|
||||||
for (var i = 0; i < courses.length; i++) {
|
|
||||||
if (!validateCourseObject(courses[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateCourseObject(course) {
|
|
||||||
var is_valid = true;
|
|
||||||
var props = ["coursename", "datetimearr", "link", "profname", "status", "unique"];
|
|
||||||
for (let j = 0; j < props.length; j++) {
|
|
||||||
is_valid &= course.hasOwnProperty(props[j]);
|
|
||||||
}
|
|
||||||
return is_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function reformatDateTime(dtl1) {
|
|
||||||
let output = "";
|
|
||||||
for (let i = 0; i < dtl1.length; i++) {
|
|
||||||
output += dtl1[i];
|
|
||||||
if (i != dtl1.length - 1) {
|
|
||||||
output += ",";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgb2hex(rgb) {
|
|
||||||
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
|
||||||
|
|
||||||
function hex(x) {
|
|
||||||
return ("0" + parseInt(x).toString(16)).slice(-2);
|
|
||||||
}
|
|
||||||
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function canNotRegister(status, register_link) {
|
|
||||||
return status.includes("closed") || status.includes("cancelled") || !status || !register_link
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
{
|
|
||||||
"manifest_version": 2,
|
|
||||||
"name": "UT Registration Plus",
|
|
||||||
"version": "1.2.2.7",
|
|
||||||
"options_page": "options.html",
|
|
||||||
"description": "Improves the course registration process at the University of Texas at Austin!",
|
|
||||||
"permissions": [
|
|
||||||
"storage",
|
|
||||||
"*://*.utdirect.utexas.edu/apps/registrar/course_schedule/*",
|
|
||||||
"*://*.utexas.collegescheduler.com/*",
|
|
||||||
"*://*.catalog.utexas.edu/ribbit/",
|
|
||||||
"*://*.registrar.utexas.edu/schedules/*",
|
|
||||||
"*://*.login.utexas.edu/login/*"
|
|
||||||
],
|
|
||||||
"content_scripts": [
|
|
||||||
{
|
|
||||||
"css": ["css/styles.css"],
|
|
||||||
"js": [
|
|
||||||
"js/config.js",
|
|
||||||
"js/lib/moment.min.js",
|
|
||||||
"js/lib/highcharts.js",
|
|
||||||
"js/lib/jquery-3.3.1.min.js",
|
|
||||||
"js/lib/jquery.initialize.min.js",
|
|
||||||
"js/util.js",
|
|
||||||
"js/Template.js",
|
|
||||||
"js/courseCatalog.js"
|
|
||||||
],
|
|
||||||
"matches": ["https://utdirect.utexas.edu/apps/registrar/course_schedule/*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"css": ["css/styles.css"],
|
|
||||||
"js": [
|
|
||||||
"js/config.js",
|
|
||||||
"js/lib/moment.min.js",
|
|
||||||
"js/lib/highcharts.js",
|
|
||||||
"js/lib/jquery-3.3.1.min.js",
|
|
||||||
"js/lib/jquery.initialize.min.js",
|
|
||||||
"js/util.js",
|
|
||||||
"js/Template.js",
|
|
||||||
"js/utPlanner.js"
|
|
||||||
],
|
|
||||||
"matches": ["https://utexas.collegescheduler.com/*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"css": ["css/styles.css"],
|
|
||||||
"js": ["js/config.js", "js/lib/moment.min.js", "js/lib/highcharts.js", "js/lib/jquery-3.3.1.min.js", "js/Template.js", "js/util.js", "js/import.js"],
|
|
||||||
"matches": ["https://utdirect.utexas.edu/registrar/waitlist/wl_see_my_waitlists.WBX", "https://utdirect.utexas.edu/registration/classlist.WBX*"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"web_accessible_resources": ["grades.db", "images/disticon.png"],
|
|
||||||
"background": {
|
|
||||||
"scripts": ["js/lib/jquery-3.3.1.min.js", "js/lib/sql-memory-growth.js", "js/lib/moment.min.js", "js/config.js", "js/util.js", "js/background.js"],
|
|
||||||
"persistent": true
|
|
||||||
},
|
|
||||||
"browser_action": {
|
|
||||||
"default_popup": "popup.html",
|
|
||||||
"default_icon": {
|
|
||||||
"16": "icons/icon16.png",
|
|
||||||
"32": "icons/icon32.png",
|
|
||||||
"48": "icons/icon48.png",
|
|
||||||
"128": "icons/icon128.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"icons": {
|
|
||||||
"16": "icons/icon16.png",
|
|
||||||
"32": "icons/icon32.png",
|
|
||||||
"48": "icons/icon48.png",
|
|
||||||
"128": "icons/icon128.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
options.html
30
options.html
@@ -1,30 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<!-- This file is serving as the template for the options page -->
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<link rel="stylesheet" href="css/styles.css" />
|
|
||||||
<link rel="stylesheet" href="css/options.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="version-container">
|
|
||||||
<p class="version">(v<span id="version"></span>)</p>
|
|
||||||
</div>
|
|
||||||
<div class="card options-card" id="header">
|
|
||||||
<h2 class="options-header"><u>Options</u></h2>
|
|
||||||
<div id="options_container"></div>
|
|
||||||
<p class="creator-tag"><a href="https://sghsri.github.io">Sriram Hariharan</a> (2018)</p>
|
|
||||||
</div>
|
|
||||||
<div class="card options-card" id="contributors_container">
|
|
||||||
<h3 class="contributor-title">Amazing people who've contributed to the extension!</h3>
|
|
||||||
<p class="creator-tag open-source-tag">Code is open source here <a href="https://github.com/sghsri/UT-Registration-Plus">here</a> :)</p>
|
|
||||||
<div id="contributor-list"></div>
|
|
||||||
</div>
|
|
||||||
<script src="js/config.js"></script>
|
|
||||||
<script src="js/lib/jquery-3.3.1.min.js"></script>
|
|
||||||
<script src="js/util.js"></script>
|
|
||||||
<script src="js/Template.js"></script>
|
|
||||||
<script src="js/options.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
90
popup.html
90
popup.html
@@ -1,90 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<!-- This file is serving as the page for the browser action popup -->
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="css/popup.css">
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="card" id="card-header" class='header_container'>
|
|
||||||
<div id="buttons" class="header_buttons">
|
|
||||||
<button id="clear" class="material_button header_button clear_button">Clear All</button>
|
|
||||||
<button id="RIS" class="material_button header_button ris_button">Registrar Info </button>
|
|
||||||
<button id="calendar" class="material_button header_button schedule_button">My Schedule</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ul id="courseList" class='course_list'></ul>
|
|
||||||
<h2 id="empty" class='empty_message'>
|
|
||||||
<div id="main">Doesn't Look Like Anything To Me.</div>
|
|
||||||
<span>(No Courses Saved)</span>
|
|
||||||
</h2>
|
|
||||||
<div class="settings_divider"></div>
|
|
||||||
<input type="file" id="import_input" accept=".json" class="hide" />
|
|
||||||
<div>
|
|
||||||
<div id="meta-data" class="meta-container">
|
|
||||||
<p class="meta"> <span class="meta-metric" id="meta-metric">17</span> hr</p>
|
|
||||||
</div>
|
|
||||||
<div class="settings">
|
|
||||||
<button title='Search' class="settings_button search_button" id='search'>
|
|
||||||
<i class="material-icons settings_icon">search</i>
|
|
||||||
</button>
|
|
||||||
<div id="search-popup" class="hide">
|
|
||||||
<div class="flex-container">
|
|
||||||
<div id='semcon' class="select-style item">
|
|
||||||
<label>
|
|
||||||
<select id="semesters"></select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id='depcon' class="select-style item">
|
|
||||||
<label>
|
|
||||||
<select id="department"></select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id='levcon' class="select-style item">
|
|
||||||
<label>
|
|
||||||
<select id="level">
|
|
||||||
<option value="L">Lower</option>
|
|
||||||
<option value="U">Upper</option>
|
|
||||||
<option value="G">Grad</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input class = "input-box" placeholder="Course # (optional)" type="text" id="courseCode"></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button id="search-class" class="material_button search-button">Search</button>
|
|
||||||
</div>
|
|
||||||
<button title='Import/Export' class="settings_button import_button" id='impexp'>
|
|
||||||
<i class="material-icons settings_icon">import_export</i>
|
|
||||||
</button>
|
|
||||||
<div id="import-export-popup" class="hide">
|
|
||||||
<div class="flex-container">
|
|
||||||
<button id="import-class" class="simple-menu-option">
|
|
||||||
<i class="material-icons">file_upload</i>Import Classes
|
|
||||||
</button>
|
|
||||||
<button id="export-class" class="simple-menu-option">
|
|
||||||
<i class="material-icons">file_download</i>Export Classes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button title='Options' class="settings_button options_button" id='options_button'>
|
|
||||||
<i class="material-icons settings_icon">settings</i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="js/lib/jquery-3.3.1.min.js"></script>
|
|
||||||
<script src="js/lib/moment.min.js"></script>
|
|
||||||
<script src="js/Template.js"></script>
|
|
||||||
<script src="js/config.js"></script>
|
|
||||||
<script src="js/util.js"></script>
|
|
||||||
<script src="js/popup.js"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
42
todo.md
42
todo.md
@@ -1,42 +0,0 @@
|
|||||||
# To Do
|
|
||||||
*Last Updated: 11/28/19*
|
|
||||||
|
|
||||||
## Features:
|
|
||||||
- [ ] work on UT Planner & Coursicle
|
|
||||||
- [ ] work on multiple schedules
|
|
||||||
- [ ] polish
|
|
||||||
- [ ] more 'at a glance info'
|
|
||||||
- [ ] Rearrange Courses
|
|
||||||
- [ ] Firefox Support
|
|
||||||
- [ ] RMP (cumulative score for class based off CIS, RMP, grade dist., etc.)
|
|
||||||
- [ ] Conflict indicator ( Possible different section? )
|
|
||||||
- [ ] Compare classes mode
|
|
||||||
|
|
||||||
## Known Bugs:
|
|
||||||
- [ ] Screenshotting calendar on zoomed browser cuts off image.
|
|
||||||
|
|
||||||
## Completed:
|
|
||||||
- [x] unneeded Logout message on individual course pages
|
|
||||||
- [x] RMP not working on individual course pages
|
|
||||||
- [x] Textbook button (amber)
|
|
||||||
- [x] Calendar popup
|
|
||||||
- [x] online classes no times in popup link
|
|
||||||
- [x] load all courses on first pages
|
|
||||||
- [x] Location in popup extra info
|
|
||||||
- [x] Export calendar format
|
|
||||||
- [x] import courses from class schedule screen
|
|
||||||
- [x] all semester's grade distribution
|
|
||||||
- [x] import into and export from UT registration plus
|
|
||||||
- [x] Showing the icon on the flags pages
|
|
||||||
- [x] Easter egg, no course messages
|
|
||||||
- [x] clean upcalendar export and add more options to screen
|
|
||||||
- [x] search by unique number
|
|
||||||
- [x] Fix the update/install bug
|
|
||||||
- [x] Redesign footer menu
|
|
||||||
|
|
||||||
for FIXING DB:
|
|
||||||
|
|
||||||
ALTER TABLE agg ADD semesters
|
|
||||||
|
|
||||||
update agg
|
|
||||||
set semesters = (select group_concat(sem) from grades where agg.prof = grades.prof and agg.course_nbr = grades.course_nbr and agg.dept = grades.dept);
|
|
||||||
Reference in New Issue
Block a user