// ==UserScript==
// @name MyGCC plus
// @namespace https://github.com/jakethurman/mygcc-plus
// @version 1.50
// @description mygcc-plus
// @downloadURL https://github.com/jakethurman/mygcc-plus/raw/master/mygcc-plus.user.js
// @author Jake Thurman and Ian Spryn
// @match https://my.gcc.edu/ICS**
// @match https://my.gcc.edu/ics**
// ==/UserScript==
/*
To use this script
1. Install the TamperMokey plugin for google chrome (or GreeseMonkey for Firefox)
2. Navigate to: https://github.com/JakeThurman/mygcc-plus/raw/master/mygcc-plus.user.js
To update:
- Navigate to the given url, or use the tampermonkey "Check for userscript updates" feature;
Customizing:
- Settings are at the bottom of the page, in the footer of mygcc
Features:
1. Courses is always expanded
2. Auto logs you in (OPTIONAL)
3. Keeps you logged in (usually)
4. Looks better (OPTIONAL)
5. Courses links go to Coursework page (OPTIONAL)
6. CTRL+, to jump to courses
7. The "Low Hanging Fruit" bugs of MyGCC are fixed
a. examples: page jumps down to the bottom when you laod the page
portlets on sign-up page are no longer cut off
*/
(function () {
'use strict';
var util = (function () {
function getMostCommonEl(arr) {
return arr.sort((a, b) =>
arr.filter(v => v === a).length
- arr.filter(v => v === b).length
).pop();
}
// Source taken from _.once
function memoize(func) {
var ran = false, memo;
return function () {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
}
function urlCombine(a, b) {
a = a.endsWith("/") ? a.slice(0, -1) : a;
return a + b;
}
function onError(e) {
console.error(e);
}
function getStringAcronym(str) {
return (str.match(/\b(\w)/g) || []).join("");
}
return {
getMostCommonEl,
memoize,
urlCombine,
onError,
getStringAcronym,
};
})();
var getOptionContainer = util.memoize(function () {
return $("
")
.appendTo($("#GRCbottombar"))
.css({ "padding-left": "20%" });
});
function addTextAndIcon(element, text, icon) {
if (text !== null) {
if (text instanceof Array) {
for (let str of text) {
var textElement = document.createElement('p');
textElement.textContent = str;
element.appendChild(textElement)
}
} else {
var textElement = document.createElement('p');
textElement.textContent = text;
element.appendChild(textElement)
}
}
if (icon !== null) {
var iconElement = document.createElement('i');
iconElement.style.fontSize = "40px";
iconElement.classList = "material-icons"
iconElement.textContent = icon;
element.appendChild(iconElement);
}
}
function createButtonTable(inputs) {
let elePerLine = 2;
var table = document.createElement('table');
table.classList = "upload-table-buttons"
table.style.margin = "0 auto"; //center it
var tr, i = 0;
//I spent an hour trying to get this to work with a for-loop
//Apparently, tr.appendChild(input) removes the element from the inputs array. WHYYYY
while (inputs.length > 0) {
let input = inputs[0]
if (i % elePerLine == 0) {
tr = document.createElement('tr');
table.appendChild(tr)
}
input.classList.add('my-gcc-plus-button')
if (input.id.includes('btnEdit')) {
input.classList.add("my-gcc-plus-button");
input.classList.add("my-gcc-plus-button-default");
input.src = "https://fonts.gstatic.com/s/i/materialicons/edit/v1/24px.svg";
} else if (input.id.includes('btnDelete')) {
input.classList.add("my-gcc-plus-button-red");
input.src = "https://fonts.gstatic.com/s/i/materialicons/delete_outline/v1/24px.svg";
}
var td = document.createElement('td')
td.appendChild(input);
tr.appendChild(td);
i++;
}
return table;
}
function convertToButton(element, text, icon, color = "default") {
if (color) {
element.classList.add('my-gcc-plus-button');
element.classList.add('my-gcc-plus-button-' + color);
} else {
element.classList.add('my-gcc-plus-button-inactive');
}
element.innerHTML = null
addTextAndIcon(element, text, icon)
return element;
}
function createButton(type, id = null, text = null, icon = null, color = "default", onclick = null, href = null, inputs = null) {
var element = document.createElement(type)
if (id != null) element.id = id;
if (color) {
element.classList = "my-gcc-plus-button";
element.classList.add("my-gcc-plus-button-" + color);
} else {
element.classList = "my-gcc-plus-button-inactive";
}
addTextAndIcon(element, text, icon)
if (type == 'button') {
element.setAttribute("type", "button");
} else if (type == 'a') {
element.target = "_blank" //open in new tab
}
if (onclick != null) element.setAttribute('onclick', onclick);
if (href != null) {
element.href = href;
}
if (inputs !== null) {
var container = document.createElement('div');
element.style.marginBottom = "20px";
container.appendChild(element);
container.appendChild(createButtonTable(inputs));
return container;
}
return element;
}
function updateUploadAndSubmitButtons() {
/*
Upload button
*/
var uploadButton = document.getElementById('pg0_V_UploadAssignmentDetails__hypUploadFile');
if (uploadButton) {
uploadButton.classList.add('my-gcc-plus-button')
uploadButton.classList.add('my-gcc-plus-button-default')
//allign the upload button and submit button
uploadButton.parentNode.style.margin = "0 auto 30px auto"
uploadButton.parentNode.style.display = "flex"
uploadButton.parentNode.style.alignItems = "center"
uploadButton.parentNode.parentNode.style.display = "flex"
}
/*
Submit button
*/
var submitButton = document.getElementById('pg0_V_UploadAssignmentDetails__lbtnTurnIn');
if (submitButton) {
submitButton.classList.add('my-gcc-plus-button')
//Custom CSS for an assignment page with an overdue submission.
if (document.querySelector('.lateAssignment') !== null) {
submitButton.classList.add("my-gcc-plus-button-red")
} else {
submitButton.classList.add('my-gcc-plus-button-blue')
}
//add click listener that will remove the edit and delete buttons below each uploaded file
$("#pg0_V_UploadAssignmentDetails__lbtnTurnIn").click(function () {
$(".upload-table-buttons").remove()
})
}
}
try {
var t_jq0 = performance.now();
// Local storage keys for mygcc username and password
var local_storage_username_key = "mygccplus_un",
local_storage_password_key = "mygccplus_pw",
local_storage_restyle_key = "mygccplus_style",
local_storage_goto_coursework_key = "mygccplus_goto_coursework",
ss_just_logged_in = "mygccplus_justloggedin",
ss_last_page = "mygccplus_lastpage",
ss_just_logged_in_2 = "mygccplus_justloggedin_noloop",
ss_should_auto_log_in = "mygccplus_auto_log_in";
// Fix redirect on login
var justLoggedIn = JSON.parse(sessionStorage[ss_just_logged_in] || "false");
var justLoggedIn2 = JSON.parse(sessionStorage[ss_just_logged_in_2] || "false");
//default autoLogIn to true if localStorage is null
var autoLogIn = JSON.parse(localStorage.getItem(ss_should_auto_log_in)) != null ? JSON.parse(localStorage.getItem(ss_should_auto_log_in) || "false") : true;
var lastPage = sessionStorage[ss_last_page];
if (autoLogIn) {
if (justLoggedIn && !justLoggedIn2 && (!document.refferer || document.referrer.indexOf("my.gcc.edu") >= 0)) {
// Clear loggin flag so we don't infinity loop
sessionStorage.setItem(ss_just_logged_in, JSON.stringify(false));
sessionStorage.setItem(ss_just_logged_in_2, JSON.stringify(true));
try {
//Go back if we can!
if (lastPage) {
history.back();
}
}
catch (e) {
util.onError(e);
}
}
}
// Setup
var interval = 1000 * 60; // After a minute
setTimeout(function callback() {
try {
// Load the home page every minute
// just to trick MyGCC into not logging us out!
$.get("/ICS/", function () {
setTimeout(callback, interval);
});
}
catch (e) {
util.onError(e);
}
// ajaxUtil.callAsmxWebService('services/sessionkeepalive.asmx/Ping'); //come back to see if I can use this for more efficient solution?
}, interval);
lastPage = location.href;
function saveCredentials(username, password) {
try {
localStorage.setItem(local_storage_username_key, username);
localStorage.setItem(local_storage_password_key, password);
console.log(username)
console.log(password)
} catch (e) {
alert(e);
}
}
if (autoLogIn) {
// Capture click on submit button on invalid login page to get username and password
$("#siteNavBar_welcomeBackBarLoggedOut_ButtonLogin").click(function (e) {
//if true, this is a real click and not a programmatic click
if (e.hasOwnProperty('originalEvent'))
saveCredentials(document.getElementsByName("userName")[0].value, document.getElementsByName("password")[0].value)
return true
});
// If username and password are in local storage
if (localStorage.getItem(local_storage_username_key) !== null && localStorage.getItem(local_storage_password_key) !== null) {
// If username and password DOM inputs are in DOM
if (document.getElementsByName("userName")[0] && document.getElementsByName("password")[0]) {
// Set username and password inputs with username and password already in local storage
document.getElementsByName("userName")[0].value = localStorage.getItem(local_storage_username_key);
document.getElementsByName("password")[0].value = localStorage.getItem(local_storage_password_key);
sessionStorage.setItem(ss_just_logged_in, JSON.stringify(true));
// Click the submit button
$("#siteNavBar_welcomeBackBarLoggedOut_ButtonLogin").click();
}
} else {
// Capture click on submit button to get username and password on homepage
$("#siteNavBar_welcomeBackBarLoggedOut_ButtonLogin").click(function () {
saveCredentials(document.getElementsByName("userName")[0].value, document.getElementsByName("password")[0].value)
return true
});
}
}
var t_jq1 = performance.now();
var ralewayFont = document.createElement('link');
ralewayFont.href = 'https://fonts.googleapis.com/css?family=Raleway&display=swap'
ralewayFont.rel = 'stylesheet';
document.head.appendChild(ralewayFont);
var manjariFont = document.createElement('link');
manjariFont.href = 'https://fonts.googleapis.com/css?family=Manjari&display=swap'
manjariFont.rel = 'stylesheet';
document.head.appendChild(manjariFont);
var materialIcons = document.createElement('link');
materialIcons.href = 'https://fonts.googleapis.com/icon?family=Material+Icons'
materialIcons.rel = 'stylesheet';
document.head.appendChild(materialIcons);
//Make the courswork portlet 100% wide instead of 50% wide
if ((window.location.href.indexOf("Attendance") > -1) || (window.location.href.indexOf("Course_Information") > -1) || (window.location.href.indexOf("Coursework") > -1) || (window.location.href.indexOf("Gradebook") > -1)) {
$(".portlet-column").addClass("portlet-max-width");
}
//Fix portlets going beyond their alotted space when your screen is too tiny
$("iframe").addClass("proper-iframe-borders");
//A really nasty way to move the "Student Dining Options" and "Contact Information" because it's too big to fit on a tiny screen with 50% width. Good job GCC. Good. Job.
//Don't even bother trying to understand what I did. Just trust the force, Luke.
if ($(window).width() < 1750) {
if (window.location.href.indexOf("Sign-Up") > -1) {
$("
", { "class": "portlet-grid-modified" })
.insertAfter($(".portlet-grid"))
$("
", { "class": "row-modified" })
.appendTo($(".portlet-grid-modified"))
$("
", { "class": "new-portlets" })
.appendTo($(".portlet-grid-modified"))
$("
", { "class": "holder" })
.appendTo($(".portlet-grid-modified"))
.append($("#pg2_Universal"))
.append($("#pg6_Universal"));
$(".portlet-grid-modified").addClass("portlet-grid");
$(".row-modified").addClass("row");
}
}
// Add option in footer for styling
var doStyling = addOption(local_storage_restyle_key, "Restyle Site", true);
var headerSize = addMultiOption("mygcc-plus--header-height", "Header Height", [
{ key: "tall", text: "Tall" },
{ key: "normal", text: "Normal" },
{ key: "shortest", text: "Short" }
], "shortest");
var hideAds = addOption("mygcc-plus--hide-ads", "Hide Ads (except on Home)", true);
var shadowsOrBorders = addMultiOption("mygcc-plus-shadow-border", "Choose shadows or borders for UI", [
{ key: "shadows", text: "Shadows" },
{ key: "borders", text: "Borders" }
], "shadows");
addOption(ss_should_auto_log_in, "Automatically log you in", true, true);
if (headerSize === "shortest") {
$("
", { "id": "space" }).insertAfter($("#masthead"));
// If we're NOT on login page, then we need can hide the header's background color
// becauase it's no longer needed as a backdrop for the login fields
if (!document.getElementById("siteNavBar_welcomeBackBarLoggedOut_ButtonLogin")) {
$("