NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name SIM Undergrad Student Timetable iCal Generator // @version 1.2 // @namespace https://simconnect.simge.edu.sg/ // @namespace https://simconnect1.simge.edu.sg/ // @description Adds a "Download iCalendar .ics" button to SIMConnect timetable list view. // @include https://simconnect1.simge.edu.sg:444/psc/csprd*/EMPLOYEE/HRMS/c/SA_LEARNER_SERVICES.SSR_SSENRL_LIST.GBL* // @updateURL https://openuserjs.org/meta/John_Doe/SIM_Undergrad_Student_Timetable_iCal_Generator.meta.js // @downloadURL https://openuserjs.org/install/John_Doe/SIM_Undergrad_Student_Timetable_iCal_Generator.user.js // @require https://cdn.jsdelivr.net/gh/nwcell/ics.js/ics.deps.min.js // @grant none // @license MIT // ==/UserScript== /*===================================================== Thanks ====================================================== Travis Krause - ics.js Kyle Hornberg - ics.js Eli Grey - FileSaver.js, Blob.js ======================================================= Script ======================================================*/ (function () { "use strict"; //Takes in a date (type:string) of the format DD/MM/YYYY, returns the date in the format MM/DD/YYYY. function convertDateFormat(dateString) { var splitArr = dateString.split("/"); return splitArr[1] + "/" + splitArr[0] + "/" + splitArr[2]; } //Takes in a range (type:string) and splits at the hyphen, returns an array of both split sides. function splitRange(inputRange) { var splitArr = inputRange.split(" - "); return splitArr; } function iCalGen() { observer.disconnect(); //Parse Tables and Assign Events into iCal variable var cal = ics(); var moduleNameArr = document.getElementsByClassName("PAGROUPDIVIDER"); //Module Name Element for (i = 0; i < moduleNameArr.length; i++) { var moduleName = (moduleNameArr[i].innerText); var classDescription = ""; var moduleClassTable = document.getElementById("CLASS_MTG_VW$scroll$" + i); //Table Element Containing Class Listings var moduleClassRows = moduleClassTable.getElementsByTagName("tr"); for (j = 1; j < moduleClassRows.length; j++) { var moduleClassColumns = moduleClassRows[j].children; //Checks for component header (Lecture/Tutorial) and refreshes description. if (moduleClassColumns[0].firstElementChild.firstElementChild.innerHTML != " ") { classDescription = moduleClassColumns[1].firstElementChild.firstElementChild.innerText + " " + moduleClassColumns[2].firstElementChild.firstElementChild.innerText; } //Parses for and formats rest of required variables. var timeRange = moduleClassColumns[3].firstElementChild.firstElementChild.innerText.slice(3); timeRange = timeRange.replace(new RegExp("AM", 'g'), " AM"); //Formatting for ics.js timeRange = timeRange.replace(new RegExp("PM", 'g'), " PM"); //Formatting for ics.js timeRange = splitRange(timeRange); var startTime = timeRange[0]; var endTime = timeRange[1]; var dateRange = moduleClassColumns[6].firstElementChild.firstElementChild.innerText; dateRange = splitRange(dateRange); var startDate = convertDateFormat(dateRange[0]); var endDate = convertDateFormat(dateRange[1]); var location = moduleClassColumns[4].firstElementChild.firstElementChild.innerText; //Adds events into calendar object. cal.addEvent(moduleName, classDescription, location, startDate + " " + startTime, endDate + " " + endTime); } } //Gets Footer Section var footerId = document.URL.match(/csprd_(\d+)/); if (footerId !== null) { footerId = "win" + footerId[1] + "divDERIVED_SSTSNAV_SSS_SUBFOOT_LINKS"; } else { footerId = "win0divDERIVED_SSTSNAV_SSS_SUBFOOT_LINKS"; } var footerDiv = document.getElementById(footerId); var footerRow = footerDiv.getElementsByTagName("tr"); //Create Separator Cell var footerSep = document.createElement('td'); footerSep.innerHTML = " "; var footerSep2 = footerSep.cloneNode(true); var footerSep3 = footerSep.cloneNode(true); //Create Download Link Cell var downloadIcs = document.createElement('a'); downloadIcs.onclick = function () { cal.download('Timetable'); }; downloadIcs.id = "downloadIcs"; downloadIcs.href = "javascript:;"; downloadIcs.className = "SSSFOOTERLINK"; downloadIcs.appendChild(document.createTextNode('Download iCalendar .ics')); var downloadIcsCell = document.createElement('td'); downloadIcsCell.appendChild(downloadIcs); //Appends New Cells footerRow[0].appendChild(footerSep); footerRow[0].appendChild(downloadIcsCell); footerRow[0].appendChild(footerSep2); footerRow[0].appendChild(footerSep3); observer.observe(targetNode, config); } var targetNode = document.documentElement; var config = { attributes: false, childList: true, subtree: true }; var observer = new MutationObserver( function (mutationsList, observer) { if (document.getElementById("ACE_STDNT_ENRL_SSV2$0") != null && document.getElementById("downloadIcs") == null) { iCalGen(); } } ); iCalGen(); })();