var isChrome = window.chrome; var SettingsClicked = false var MenuOptionsOpen = false; var UserInitalCode = ''; var currentSelectedDate = new Date(); var WhatsNewOpen = false; var LessonInterval; var stringToHTML = function (str, styles=false) { var parser = new DOMParser(); var str = DOMPurify.sanitize(str, { ADD_ATTR: ['onclick']}); var doc = parser.parseFromString(str, "text/html"); if(styles){doc.body.style.cssText = "height: auto; overflow: scroll; margin: 0px; background: var(--background-primary);"} return doc.body; }; const ShortcutLinks = { YouTube: { link: "https://www.youtube.com/", viewBox: "0 0 24 24", icon: "M10,15L15.19,12L10,9V15M21.56,7.17C21.69,7.64 21.78,8.27 21.84,9.07C21.91,9.87 21.94,10.56 21.94,11.16L22,12C22,14.19 21.84,15.8 21.56,16.83C21.31,17.73 20.73,18.31 19.83,18.56C19.36,18.69 18.5,18.78 17.18,18.84C15.88,18.91 14.69,18.94 13.59,18.94L12,19C7.81,19 5.2,18.84 4.17,18.56C3.27,18.31 2.69,17.73 2.44,16.83C2.31,16.36 2.22,15.73 2.16,14.93C2.09,14.13 2.06,13.44 2.06,12.84L2,12C2,9.81 2.16,8.2 2.44,7.17C2.69,6.27 3.27,5.69 4.17,5.44C4.64,5.31 5.5,5.22 6.82,5.16C8.12,5.09 9.31,5.06 10.41,5.06L12,5C16.19,5 18.8,5.16 19.83,5.44C20.73,5.69 21.31,6.27 21.56,7.17Z" }, Outlook: { link: "https://outlook.office365.com/mail/inbox", viewBox: "0 0 24 24", icon: "M8.56 12.03Q8.56 12.41 8.5 12.76 8.39 13.1 8.2 13.38 8 13.65 7.71 13.81 7.41 13.97 7 13.97 6.58 13.97 6.29 13.8 6 13.63 5.81 13.35 5.62 13.07 5.54 12.72 5.45 12.37 5.45 12 5.45 11.64 5.54 11.28 5.62 10.93 5.81 10.65 6 10.37 6.31 10.2 6.61 10.03 7.03 10.03 7.46 10.03 7.75 10.2 8.05 10.38 8.23 10.66 8.41 10.95 8.5 11.3 8.56 11.66 8.56 12.03M22 12V19.81Q22 20.2 21.73 20.5 21.45 20.75 21.06 20.75H7.94Q7.55 20.75 7.27 20.5 7 20.2 7 19.81V17H2.83Q2.5 17 2.24 16.76 2 16.5 2 16.17V7.83Q2 7.5 2.24 7.24 2.5 7 2.83 7H8.25V4.13Q8.25 3.76 8.5 3.5 8.76 3.25 9.13 3.25H19.87Q20.24 3.25 20.5 3.5 20.75 3.76 20.75 4.13V11.04L21.79 11.64H21.8Q21.88 11.7 21.94 11.8 22 11.89 22 12M17 5.13V7.63H19.5V5.13M17 8.88V11.38H19.5V8.88M17 12.63V14.15L19.54 12.63M12.63 5.13V7.63H15.75V5.13M12.63 8.88V11.38H15.75V8.88M12.63 12.63V14.32L14.64 15.56L15.75 14.9V12.63M9.5 5.13V7H11.27Q11.33 7 11.38 7.04V5.12M7 15.32Q7.73 15.32 8.32 15.06 8.9 14.8 9.31 14.35 9.71 13.9 9.91 13.28 10.12 12.66 10.13 11.94 10.13 11.25 9.92 10.65 9.72 10.06 9.32 9.62 8.93 9.18 8.37 8.93 7.8 8.68 7.08 8.68 6.31 8.68 5.71 8.93 5.12 9.18 4.71 9.63 4.3 10.09 4.09 10.71 3.88 11.34 3.88 12.08 3.88 12.78 4.09 13.38 4.31 13.97 4.71 14.4 5.11 14.83 5.68 15.08 6.26 15.32 7 15.32M8.25 19.5H18.57L12 15.4V16.17Q12 16.5 11.76 16.76 11.5 17 11.17 17H8.25M20.75 19.39V13.36L15.83 16.31Z", }, Office: { link: "http://office.com", viewBox: "0 0 24 24", icon: "M19.94 5.59V18.39Q19.94 19.06 19.55 19.59 19.16 20.11 18.5 20.29L12.77 21.94Q12.65 21.97 12.5 22H12.28Q11.95 22 11.68 21.91 11.41 21.82 11.13 21.67L7.38 19.55Q7.17 19.43 7.05 19.24 6.93 19.05 6.93 18.81 6.93 18.45 7.19 18.2 7.44 17.95 7.8 17.95H12.66V6.14L9 7.44Q8.57 7.6 8.3 8 8.03 8.38 8.03 8.85V15.58Q8.03 16 7.82 16.34 7.62 16.68 7.25 16.88L5.53 17.82Q5.29 17.95 5.05 17.95 4.64 17.95 4.35 17.66 4.06 17.37 4.06 16.95V7.47Q4.06 6.95 4.33 6.5 4.61 6 5.06 5.74L11.22 2.24Q11.43 2.12 11.67 2.06 11.91 2 12.15 2 12.32 2 12.46 2.03 12.6 2.05 12.77 2.1L18.5 3.69Q18.83 3.78 19.09 3.96 19.35 4.14 19.54 4.39 19.74 4.65 19.84 4.95 19.94 5.26 19.94 5.59M18.62 18.39V5.59Q18.62 5.36 18.5 5.19 18.35 5 18.13 4.96L15.31 4.18Q15 4.09 14.65 4 14.32 3.89 14 3.81V20.21L18.13 19Q18.35 18.96 18.5 18.79 18.62 18.62 18.62 18.39Z" }, Spotify: { link: "https://accounts.spotify.com/en/login", viewBox: "0 0 24 24", icon: "M17.9,10.9C14.7,9 9.35,8.8 6.3,9.75C5.8,9.9 5.3,9.6 5.15,9.15C5,8.65 5.3,8.15 5.75,8C9.3,6.95 15.15,7.15 18.85,9.35C19.3,9.6 19.45,10.2 19.2,10.65C18.95,11 18.35,11.15 17.9,10.9M17.8,13.7C17.55,14.05 17.1,14.2 16.75,13.95C14.05,12.3 9.95,11.8 6.8,12.8C6.4,12.9 5.95,12.7 5.85,12.3C5.75,11.9 5.95,11.45 6.35,11.35C10,10.25 14.5,10.8 17.6,12.7C17.9,12.85 18.05,13.35 17.8,13.7M16.6,16.45C16.4,16.75 16.05,16.85 15.75,16.65C13.4,15.2 10.45,14.9 6.95,15.7C6.6,15.8 6.3,15.55 6.2,15.25C6.1,14.9 6.35,14.6 6.65,14.5C10.45,13.65 13.75,14 16.35,15.6C16.7,15.75 16.75,16.15 16.6,16.45M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" }, Google: { link: "https://google.com", viewBox: "0 0 24 24", icon: "M12,20L15.46,14H15.45C15.79,13.4 16,12.73 16,12C16,10.8 15.46,9.73 14.62,9H19.41C19.79,9.93 20,10.94 20,12A8,8 0 0,1 12,20M4,12C4,10.54 4.39,9.18 5.07,8L8.54,14H8.55C9.24,15.19 10.5,16 12,16C12.45,16 12.88,15.91 13.29,15.77L10.89,19.91C7,19.37 4,16.04 4,12M15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9A3,3 0 0,1 15,12M12,4C14.96,4 17.54,5.61 18.92,8H12C10.06,8 8.45,9.38 8.08,11.21L5.7,7.08C7.16,5.21 9.44,4 12,4M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" }, DuckDuckGo: { link: "https://duckduckgo.com/", viewBox: "0 0 32 32", icon: "M16 0c-8.839 0-16 7.161-16 16s7.161 16 16 16c8.839 0 16-7.161 16-16s-7.161-16-16-16zM16 30.667c-8.099 0-14.667-6.568-14.667-14.667s6.568-14.667 14.667-14.667c8.099 0 14.667 6.568 14.667 14.667s-6.568 14.667-14.667 14.667zM29.625 16c0 6.406-4.422 11.776-10.38 13.234-0.359-0.698-0.708-1.359-1-1.917 0.859 0.328 2.573 0.953 2.943 0.818 0.505-0.193 0.38-4.198-0.182-4.328-0.453-0.099-2.177 1.12-2.859 1.615l0.047 0.208c0.104 0.526 0.193 1.323 0.042 1.661 0 0.005-0.005 0.016-0.005 0.016-0.021 0.047-0.052 0.089-0.094 0.12-0.375 0.25-1.438 0.38-2 0.25-0.031-0.005-0.057-0.016-0.089-0.026-0.922 0.526-2.677 1.479-3 1.297-0.438-0.255-0.5-3.573-0.438-4.385 0.047-0.615 2.203 0.38 3.255 0.906 0.234-0.219 0.802-0.365 1.307-0.417-0.76-1.849-1.318-3.969-0.979-5.474 0 0.005 0.005 0.005 0.005 0.005 0.474 0.328 3.641 1.401 5.214 1.37s4.151-0.99 3.87-1.766c-0.281-0.771-2.849 0.682-5.521 0.432-1.984-0.182-2.333-1.073-1.896-1.719 0.552-0.818 1.557 0.151 3.214-0.344 1.661-0.495 3.984-1.38 4.844-1.859 1.995-1.115-0.833-1.573-1.5-1.266-0.63 0.297-2.828 0.849-3.849 1.094 0.568-2.021-0.807-5.531-2.344-7.068-0.5-0.5-1.271-0.813-2.141-0.979-0.333-0.458-0.87-0.896-1.63-1.302-1.474-0.771-3.156-1.047-4.797-0.781l-0.031 0.005-0.042 0.005 0.005 0.005c-0.198 0.036-0.318 0.104-0.479 0.13 0.198 0.021 0.943 0.37 1.411 0.557-0.234 0.089-0.552 0.146-0.797 0.245-0.094 0.016-0.182 0.036-0.271 0.073-0.229 0.109-0.406 0.5-0.401 0.688 1.12-0.115 2.776-0.031 3.99 0.328-0.859 0.12-1.646 0.344-2.214 0.646-0.021 0.010-0.042 0.021-0.068 0.036-0.068 0.026-0.141 0.057-0.198 0.089-1.823 0.958-2.63 3.203-2.151 5.896 0.432 2.432 2.219 10.786 3.052 14.755-5.297-1.87-9.094-6.917-9.094-12.854 0-7.526 6.099-13.625 13.625-13.625s13.625 6.099 13.625 13.625zM12.125 12.776c-0.557 0-1.010 0.453-1.010 1.010s0.453 1.010 1.010 1.010c1.349 0 1.349-2.021 0-2.021zM12.578 13.708c-0.146 0-0.26-0.115-0.26-0.26 0-0.141 0.115-0.26 0.26-0.26 0.349 0 0.349 0.521 0 0.521zM18.875 12.318c-0.49-0.016-0.901 0.375-0.901 0.87 0 0.49 0.411 0.885 0.901 0.865 1.156 0 1.156-1.734 0-1.734zM19.26 13.12c-0.12 0-0.224-0.099-0.224-0.224 0-0.12 0.104-0.224 0.224-0.224 0.302 0 0.302 0.448 0 0.448zM12.417 10.859c0 0-0.76-0.344-1.5 0.12-0.74 0.469-0.714 0.943-0.714 0.943s-0.391-0.875 0.656-1.307c1.047-0.427 1.557 0.245 1.557 0.245zM19.401 10.792c0 0-0.547-0.313-0.974-0.307-0.875 0.010-1.109 0.396-1.109 0.396s0.146-0.917 1.26-0.734c0.365 0.068 0.672 0.307 0.823 0.646z" }, CoolMathGames: { link: "https://coolmathgames.com/", viewBox: "0 0 24 24", icon: "M16.5,9L13.5,12L16.5,15H22V9M9,16.5V22H15V16.5L12,13.5M7.5,9H2V15H7.5L10.5,12M15,7.5V2H9V7.5L12,10.5L15,7.5Z" }, SACE: { link: "https://apps.sace.sa.edu.au/students-online/login.do", viewBox: "0 0 125.2 125", icon: "M103,40.1H84.8v-18C84.8,9.9,74.8,0,62.6,0C50.4,0,40.3,9.9,40.3,22.1c0,12.2,10,22.1,22.2,22.1h18.1v36H44.5v-18c0-12.2-10-22.1-22.2-22.1S0,50,0,62.2s10,22.1,22.2,22.1h18.1v18c0,12.2,10,22.1,22.2,22.1s22.2-9.9,22.2-22.1v-18h18.1c12.4,0,22.4-9.9,22.4-22.1S115.2,40.1,103,40.1z M40.3,80.2H22.2c-10,0-18.1-8.1-18.1-18s8.1-18,18.1-18s18.1,8.1,18.1,18V80.2zM80.7,102.3c0,9.9-8.1,18-18.1,18s-18.1-8.1-18.1-18v-18h36.2V102.3z M80.7,40.1H62.6c-10,0-18.1-8.1-18.1-18c0-9.9,8.1-18,18.1-18s18.1,8.1,18.1,18V40.1z M102.9,80.2H84.8v-36h18.1c10,0,18.1,8.1,18.1,18S112.9,80.2,102.9,80.2z" }, GoogleScholar: { link: "https://scholar.google.com", viewBox: "0 0 24 24", icon: "M21.35,11.1H12.18V13.83H18.69C18.36,17.64 15.19,19.27 12.19,19.27C8.36,19.27 5,16.25 5,12C5,7.9 8.2,4.73 12.2,4.73C15.29,4.73 17.1,6.7 17.1,6.7L19,4.72C19,4.72 16.56,2 12.1,2C6.42,2 2.03,6.8 2.03,12C2.03,17.05 6.16,22 12.25,22C17.6,22 21.5,18.33 21.5,12.91C21.5,11.76 21.35,11.1 21.35,11.1V11.1Z" }, Gmail: { link: "https://mail.google.com", viewBox: "0 0 24 24", icon: "M20,18H18V9.25L12,13L6,9.25V18H4V6H5.2L12,10.25L18.8,6H20M20,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6C22,4.89 21.1,4 20,4Z" }, Netflix: { link: "https://netflix.com", viewBox: "0 0 24 24", icon: "M6.5,2H10.5L13.44,10.83L13.5,2H17.5V22C16.25,21.78 14.87,21.64 13.41,21.58L10.5,13L10.43,21.59C9.03,21.65 7.7,21.79 6.5,22V2Z" } } var MenuitemSVGKey = { "welcome": ` `, "assessments": ` `, "courses": ` `, "dashboard": ` `, "messages": ` `, "notices": ` `, "portals": ` `, "reports": ` `, "settings": ` `, "timetable": ` ` } function loading() { loadinghtml = stringToHTML( `
v${chrome.runtime.getManifest().version}
` ); var html = document.getElementsByTagName("html")[0]; html.append(loadinghtml.firstChild); } function AppendLoadingSymbol(givenID, position) { loadingsymbol = stringToHTML(`
`).firstChild document.querySelector(position).appendChild(loadingsymbol) } function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function SetDisplayNone(ElementName) { return `li[data-key=${ElementName}]{display:var(--menuHidden) !important; transition: 1s;}`; } function ApplyCSSToHiddenMenuItems() { var stylesheetInnerText = ""; chrome.storage.local.get(null, function (result) { for (let i = 0; i < Object.keys(result.menuitems).length; i++) { if (!Object.values(result.menuitems)[i].toggle) { stylesheetInnerText += SetDisplayNone(Object.keys(result.menuitems)[i]); console.log( `[BestSEQTA] Hiding ${Object.keys(result.menuitems)[i]} menu item` ); } } MenuItemStyle = document.createElement("style"); MenuItemStyle.innerText = stylesheetInnerText; document.head.appendChild(MenuItemStyle); }); } function OpenWhatsNewPopup() { const background = document.createElement('div'); background.id = "whatsnewbk"; background.classList.add('whatsnewBackground'); const container = document.createElement('div'); container.classList.add('whatsnewContainer'); var header = stringToHTML(`

What's New

BestSEQTA V${chrome.runtime.getManifest().version}

`).firstChild; imagecont = document.createElement('div'); imagecont.classList.add('whatsnewImgContainer'); var image = document.createElement('img'); image.src = chrome.runtime.getURL('icons/betterseqta-dark-icon.png'); image.classList.add('whatsnewImg') imagecont.append(image); textcontainer = document.createElement('div'); textcontainer.classList.add('whatsnewTextContainer'); textheader = stringToHTML('

DESIGN OVERHAUL

').firstChild; textcontainer.append(textheader); text = stringToHTML( `

3.1.0 - Complete overhaul

  • Upgraded Manifest to V3
  • Fixed transitional glitches
  • News feature wouldn't refresh until cookies were cleared
  • 3.0.1 - Bug fixes and working on manifest V3

    3.0.0 - Started BestSEQTA

    2.0.7 - Added support to other domains + Minor bug fixes

  • Fixed BestSEQTA not loading on some pages
  • Fixed text colour of notices being unreadable
  • Fixed pages not reloading when saving changes
  • 2.0.2 - Minor bug fixes

  • Fixed indicator for current lesson
  • Fixed text colour for DM messages list in Light mode
  • Fixed user info text colour
  • Sleek New Layout

  • Updated with a new font and presentation, BestSEQTA has never looked better.
  • New Updated Sidebar

  • Condensed appearance with new updated icons.
  • Independent Light Mode and Dark Mode

  • Dark mode and Light mode are now available to pick alongside your chosen Theme Colour. Your Theme Colour will now become an accent colour for the page. Light/Dark mode can be toggled with the new button, found in the top-right of the menu bar.
  • Create Custom Shortcuts

  • Found in the BestSEQTA Settings menu, custom shortcuts can now be created with a name and URL of your choice.
  • ` ).firstChild; footer = stringToHTML(`
    Report bugs and feedback:
    `).firstChild exitbutton = document.createElement('div') exitbutton.innerText = 'x'; exitbutton.id = 'whatsnewclosebutton'; container.append(header); container.append(imagecont); container.append(textcontainer); container.append(text); container.append(footer); container.append(exitbutton); document.getElementById('container').append(background); document.getElementById('container').append(container); chrome.storage.local.remove(["justupdated"]); var bkelement = document.getElementById('whatsnewbk'); bkelement.addEventListener('click', function () { DeleteWhatsNew(); WhatsNewOpen = false; }) var closeelement = document.getElementById('whatsnewclosebutton'); closeelement.addEventListener('click', function (e) { DeleteWhatsNew(); WhatsNewOpen = false; }) } async function finishLoad() { var loadingbk = document.getElementById("loading"); loadingbk.style.opacity = "0"; await delay(501); loadingbk.remove(); chrome.storage.local.get(["justupdated"], function (result) { if (result.justupdated) { WhatsNewOpen = true; OpenWhatsNewPopup(); } }) } async function DeleteWhatsNew() { var bkelement = document.getElementById('whatsnewbk'); var popup = document.getElementsByClassName("whatsnewContainer")[0]; bkelement.classList.add('whatsnewfadeout'); popup.classList.add('whatsnewzoomout'); await delay(500); bkelement.remove(); popup.remove(); } function CreateBackground() { // Creating and inserting 3 divs containing the background applied to the pages var bklocation = document.getElementById("container"); var menu = document.getElementById("menu"); var bk = document.createElement("div"); bk.classList.add("bg"); bklocation.insertBefore(bk, menu); var bk2 = document.createElement("div"); bk2.classList.add("bg"); bk2.classList.add("bg2"); bklocation.insertBefore(bk2, menu); var bk3 = document.createElement("div"); bk3.classList.add("bg"); bk3.classList.add("bg3"); bklocation.insertBefore(bk3, menu); } function waitForElm(selector) { return new Promise((resolve) => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver((mutations) => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true, }); }); } var LoadingDone = false; async function RunColourCheck(element) { if (typeof element.contentDocument.documentElement.childNodes[1] == 'undefined') { await delay(1000); RunColourCheck(element); } else { element.contentDocument.documentElement.childNodes[1].style.color = "white"; } } function GetiFrameCSSElement() { var cssFile = chrome.runtime.getURL("inject/iframe.css"); var fileref = document.createElement("link"); fileref.setAttribute("rel", "stylesheet"); fileref.setAttribute("type", "text/css"); fileref.setAttribute("href", cssFile); return fileref; } function CheckiFrameItems() { // Injecting CSS File to the webpage to overwrite iFrame default CSS fileref = GetiFrameCSSElement(); const observer = new MutationObserver(function (mutations_list) { mutations_list.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { if (added_node.tagName == "IFRAME") { chrome.storage.local.get(["DarkMode"], function (result) { DarkModeResult = result.DarkMode if (DarkModeResult) { RunColourCheck(added_node); if (added_node.contentDocument.documentElement.childNodes[1].style.color != "white") { added_node.contentDocument.documentElement.childNodes[1].style.color = "white"; } if ( !added_node.contentDocument.documentElement.firstChild.innerHTML.includes( "iframe.css" ) ) { added_node.contentDocument.documentElement.firstChild.appendChild( fileref ); } added_node.addEventListener("load", function () { if (added_node.contentDocument.documentElement.childNodes[1].style.color != "white") { added_node.contentDocument.documentElement.childNodes[1].style.color = "white"; } if ( !added_node.contentDocument.documentElement.firstChild.innerHTML.includes( "iframe.css" ) ) { added_node.contentDocument.documentElement.firstChild.appendChild( fileref ); } }); } }); } }); }); }); observer.observe(document.body, { subtree: true, childList: true, }); } function SortMessagePageItems(messagesParentElement) { filterbutton = document.createElement('div'); filterbutton.classList.add("messages-filterbutton"); filterbutton.innerText = "Filter"; header = document.getElementsByClassName('MessageList__MessageList___3DxoC')[0].firstChild; header.append(filterbutton); const observer = new MutationObserver(function (mutations_list) { mutations_list.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { if (added_node.dataset.message) { // Check if added_node.firstChild.title is in block list } }); }); }); observer.observe(messagesParentElement, { subtree: true, childList: true, }); } function LoadPageElements() { AddBetterSEQTAElements(true); var sublink = window.location.href.split("/")[4]; switch (sublink) { case "news": console.log("[BestSEQTA] Started Init"); chrome.storage.local.get(null, function (result) { if (result.onoff) { SendNewsPage(); // Sends similar HTTP Post Request for the notices chrome.storage.local.get(null, function (result) { if (result.notificationcollector) { var xhr3 = new XMLHttpRequest(); xhr3.open( "POST", `${location.origin}/seqta/student/heartbeat?`, true ); xhr3.setRequestHeader( "Content-Type", "application/json; charset=utf-8" ); xhr3.onreadystatechange = function () { if (xhr3.readyState === 4) { var Notifications = JSON.parse(xhr3.response); var alertdiv = document.getElementsByClassName( "notifications__bubble___1EkSQ" )[0]; if (typeof alertdiv == 'undefined') { console.log("[BestSEQTA] No notifications currently") } else { alertdiv.textContent = Notifications.payload.notifications.length; } } }; xhr3.send( JSON.stringify({ timestamp: "1970-01-01 00:00:00.0", hash: "#?page=/home", }) ); } }); finishLoad(); } }); break; case "home": window.location.replace(`${location.origin}/#?page=/home`); LoadInit(); break; case undefined: window.location.replace(`${location.origin}/#?page=/home`); LoadInit(); break; default: finishLoad(); // Sends similar HTTP Post Request for the notices chrome.storage.local.get(null, function (result) { if (result.notificationcollector) { var xhr3 = new XMLHttpRequest(); xhr3.open( "POST", `${location.origin}/seqta/student/heartbeat?`, true ); xhr3.setRequestHeader( "Content-Type", "application/json; charset=utf-8" ); xhr3.onreadystatechange = function () { if (xhr3.readyState === 4) { var Notifications = JSON.parse(xhr3.response); var alertdiv = document.getElementsByClassName( "notifications__bubble___1EkSQ" )[0]; if (typeof alertdiv == 'undefined') { console.log("[BestSEQTA] No notifications currently") } else { alertdiv.textContent = Notifications.payload.notifications.length; } } }; xhr3.send( JSON.stringify({ timestamp: "1970-01-01 00:00:00.0", hash: "#?page=/home", }) ); } }); break; } const observer = new MutationObserver(function (mutations_list) { mutations_list.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { if (added_node.classList.contains('messages')) { element = document.getElementById('title').firstChild; element.innerText = "Direct Messages"; document.title = "Direct Messages ― SEQTA Learn"; SortMessagePageItems(added_node); } else if (added_node.classList.contains('notices')) { CheckNoticeTextColour(added_node); } }); }); }); observer.observe(document.querySelector('#main'), { subtree: false, childList: true, }); } function CheckNoticeTextColour(notice) { const observer = new MutationObserver(function (mutations_list) { mutations_list.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { chrome.storage.local.get(['DarkMode'], function (result) { Darkmode = result.DarkMode; if (added_node.classList.contains('notice')) { var hex = added_node.style.cssText.split(' ')[1]; var threshold = GetThresholdofHex(hex); if (Darkmode && threshold < 100) { added_node.style.cssText = "--color: undefined;"; } } }) }); }); }); observer.observe(notice, { subtree: true, childList: true, }); } function tryLoad() { waitForElm(".login").then((elm) => { LoadingDone = true; finishLoad(); }); waitForElm(".day-container").then((elm) => { LoadingDone = true; finishLoad(); }); waitForElm("[data-key=welcome]").then((elm) => { elm.classList.remove('active') }); waitForElm(".code").then((elm) => { if (!elm.innerText.includes("BestSEQTA")) LoadPageElements(); }); // Waits for page to call on load, run scripts document.addEventListener( "load", function () { CheckiFrameItems(); }, true ); } function ChangeMenuItemPositions(storage) { menuorder = storage; var menuList = document.querySelector('#menu').firstChild.childNodes; listorder = [] for (let i = 0; i < menuList.length; i++) { namevalue = menuList[i].dataset.key a = menuorder.indexOf(menuList[i].dataset.key) listorder.push(a) } var newArr = [] for (var i = 0; i < listorder.length; i++) { newArr[listorder[i]] = menuList[i] } listItemsDOM = document.getElementById('menu').firstChild for (let i = 0; i < newArr.length; i++) { const element = newArr[i]; if (element) { element.setAttribute('data-checked', 'true') listItemsDOM.appendChild(element); } } } async function ObserveMenuItemPosition() { chrome.storage.local.get(null, function (result) { menuorder = result.menuorder if (menuorder && result.onoff) { const observer = new MutationObserver(function (mutations_list) { mutations_list.forEach(function (mutation) { mutation.addedNodes.forEach(function (added_node) { if (!added_node.dataset.checked && !MenuOptionsOpen) { if (MenuitemSVGKey[added_node.dataset.key]) { ReplaceMenuSVG(added_node, MenuitemSVGKey[added_node.dataset.key]) } ChangeMenuItemPositions(menuorder); } }); }); }); observer.observe(document.querySelector('#menu').firstChild, { subtree: true, childList: true, }); } }) } function AppendElementsToDisabledPage() { AddBetterSEQTAElements(false); settingsStyle = document.createElement('style') settingsStyle.innerText = ` .addedButton { position: absolute !important; right: 50px; width: 35px; height: 35px; padding: 6px !important; overflow: unset !important; border-radius: 50%; margin: 7px !important; cursor: pointer; color: white !important; } .addedButton svg { margin: 6px; } .outside-container { top: 48px !important; } ` document.head.append(settingsStyle) } function ColorLuminance(hex, lum) { // validate hex string hex = String(hex).replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } lum = lum || 0; // convert to decimal and change luminosity var rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16); rgb += ("00" + c).substring(c.length); } return rgb; } chrome.storage.onChanged.addListener(function (changes) { if (changes.selectedColor) { rbg = GetThresholdofHex(changes.selectedColor.newValue) if (rbg > 210) { document.documentElement.style.setProperty('--text-color', 'black'); document.documentElement.style.setProperty('--betterseqta-logo', `url(${chrome.runtime.getURL('icons/betterseqta-dark-full.png')})`); } else { document.documentElement.style.setProperty('--text-color', 'white'); document.documentElement.style.setProperty('--betterseqta-logo', `url(${chrome.runtime.getURL('icons/betterseqta-light-full.png')})`); } document.documentElement.style.setProperty('--better-main', changes.selectedColor.newValue); // document.documentElement.style.setProperty('--better-sub', ColorLuminance(changes.selectedColor.newValue, -0.15)); if (changes.selectedColor.newValue == '#ffffff') { document.documentElement.style.setProperty('--better-light', '#b7b7b7'); } else { document.documentElement.style.setProperty('--better-light', ColorLuminance(changes.selectedColor.newValue, 0.99)); } } if (changes.customshortcuts.newValue) { if (changes.customshortcuts.oldValue.length > 0) { CreateCustomShortcutDiv(changes.customshortcuts.newValue[(changes.customshortcuts.oldValue.length)]); } else { CreateCustomShortcutDiv(changes.customshortcuts.newValue[0]); } } }) var PageLoaded = false; async function CheckLoadOnPeriods() { if (!PageLoaded) { await delay(1000); var code = document.getElementsByClassName('code')[0]; if (code && !UserInitalCode) { LoadPageElements(); finishLoad(); PageLoaded = true; } if (!code) { CheckLoadOnPeriods(); } } } function RunFunctionOnTrue(storedSetting) { // If the option is 'on', open BetterSEQTA if (typeof storedSetting.onoff == 'undefined') { chrome.runtime.sendMessage({ type: "setDefaultStorage" }); } if (storedSetting.onoff) { console.log("[BestSEQTA] Enabled"); // Injecting CSS File to the webpage to overwrite SEQTA's default CSS var cssFile = chrome.runtime.getURL("inject/injected.css"); var fileref = document.createElement("link"); fileref.setAttribute("rel", "stylesheet"); fileref.setAttribute("type", "text/css"); fileref.setAttribute("href", cssFile); document.head.appendChild(fileref); document.getElementsByTagName("html")[0].appendChild(fileref); document.documentElement.style.setProperty('--better-sub', "#161616"); document.documentElement.style.setProperty('--better-alert-highlight', "#c61851"); if (storedSetting.DarkMode) { document.documentElement.style.setProperty('--background-primary', "#232323"); document.documentElement.style.setProperty('--background-secondary', "#1a1a1a"); document.documentElement.style.setProperty('--text-primary', "white"); } else { document.documentElement.style.setProperty('--background-primary', "#ffffff"); document.documentElement.style.setProperty('--background-secondary', "#e5e7eb"); document.documentElement.style.setProperty('--text-primary', "black"); } document.querySelector('link[rel*="icon"]').href = chrome.runtime.getURL("icons/icon-48.png"); rbg = GetThresholdofHex(storedSetting.selectedColor); if (rbg > 210) { document.documentElement.style.setProperty('--text-color', 'black'); document.documentElement.style.setProperty('--betterseqta-logo', `url(${chrome.runtime.getURL('icons/betterseqta-dark-full.png')})`); } else { document.documentElement.style.setProperty('--text-color', 'white'); document.documentElement.style.setProperty('--betterseqta-logo', `url(${chrome.runtime.getURL('icons/betterseqta-light-full.png')})`); } document.documentElement.style.setProperty('--better-main', storedSetting.selectedColor); // document.documentElement.style.setProperty('--better-sub', ColorLuminance(storedSetting.selectedColor, -0.15)); if (storedSetting.selectedColor == '#ffffff') { document.documentElement.style.setProperty('--better-light', '#b7b7b7'); } else { document.documentElement.style.setProperty('--better-light', ColorLuminance(storedSetting.selectedColor, 0.95)); } ApplyCSSToHiddenMenuItems(); loading(); CheckLoadOnPeriods(); if (!isChrome || isChrome == "undefined") { tryLoad(); } window.addEventListener("load", function () { tryLoad(); }); } else { if (!isChrome || isChrome == "undefined") { waitForElm(".code").then((elm) => { AppendElementsToDisabledPage(); }); } window.addEventListener("load", function () { waitForElm(".code").then((elm) => { AppendElementsToDisabledPage(); }); }); }; } async function CheckForMenuList() { if (!MenuItemMutation) { try { if (document.getElementById('menu').firstChild) { ObserveMenuItemPosition(); MenuItemMutation = true; } } catch (error) { return; } } } var MenuItemMutation = false; var NonSEQTAPage = false; var IsSEQTAPage = false; document.addEventListener( "load", function () { CheckForMenuList(); var weblink = window.location.origin if (document.childNodes[1].textContent?.includes("Copyright (c) SEQTA Software") && document.title.includes("SEQTA Learn") && !IsSEQTAPage) { IsSEQTAPage = true; console.log("[BestSEQTA] Verified SEQTA Page"); var link = document.createElement("link"); link.href = chrome.runtime.getURL("inject/documentload.css"); link.type = "text/css"; link.rel = "stylesheet"; document.getElementsByTagName("html")[0].appendChild(link); chrome.storage.local.get(null, function (items) { RunFunctionOnTrue(items); }); } if ( !document.childNodes[1].textContent?.includes("SEQTA") && !NonSEQTAPage ) { NonSEQTAPage = true; } }, true ); function RunExtensionSettingsJS() { const whatsnewsettings = document.getElementById('whatsnewsettings'); whatsnewsettings.addEventListener('click', function () { if (!WhatsNewOpen) { WhatsNewOpen = true; OpenWhatsNewPopup(); } }); const onoffselection = document.querySelector("#onoff"); const notificationcollector = document.querySelector("#notification"); const lessonalert = document.querySelector("#lessonalert"); const aboutsection = document.querySelector("#aboutsection"); const shortcutsection = document.querySelector("#shortcutsection"); const miscsection = document.querySelector('#miscsection'); const mainpage = document.querySelector("#mainpage"); const colorpicker = document.querySelector("#colorpicker"); const animatedbk = document.querySelector('#animatedbk'); const customshortcutbutton = document.getElementsByClassName('custom-shortcuts-button')[0]; const customshortcutdiv = document.getElementsByClassName('custom-shortcuts-container')[0]; const customshortcutsubmit = document.getElementsByClassName('custom-shortcuts-submit')[0]; const customshortcutinputname = document.querySelector('#shortcutname'); const customshortcutinputurl = document.querySelector('#shortcuturl'); const shortcutmenuitemselection = document.getElementsByClassName('menushortcut')[0]; const applybutton = document.querySelector('#applychanges') const navbuttons = document.getElementsByClassName("navitem"); const menupages = document.getElementsByClassName("menu-page") const allinputs = document.getElementsByTagName('input'); const menupage = document.querySelector("#menupage"); const shortcutpage = document.querySelector("#shortcutpage"); const miscpage = document.querySelector('#miscpage'); var shortcutbuttons = document.getElementsByClassName("shortcutitem"); var validURL = false; var validName = false; const github = document.getElementById("github"); function openGithub() { chrome.runtime.sendMessage({ type: "githubTab" }); } function resetActive() { for (let i = 0; i < navbuttons.length; i++) { navbuttons[i].classList.remove('activenav'); } for (let i = 0; i < menupages.length; i++) { menupages[i].classList.add('hiddenmenu'); } } function FindSEQTATab() { chrome.runtime.sendMessage({ type: "reloadTabs", }); } /* Store the currently selected settings using chrome.storage.local. */ function storeSettings() { chrome.storage.local.set({ onoff: onoffselection.checked }, function () { FindSEQTATab(); }); } function storeNotificationSettings() { chrome.storage.local.set( { notificationcollector: notificationcollector.checked }); chrome.storage.local.set({ lessonalert: lessonalert.checked }); chrome.storage.local.set({ animatedbk: animatedbk.checked }); } function StoreAllSettings() { chrome.storage.local.get(["shortcuts"], function (result) { var shortcuts = Object.values(result)[0]; for (var i = 0; i < shortcutbuttons.length; i++) { shortcuts[i].enabled = shortcutbuttons[i].checked; } chrome.storage.local.set({ shortcuts: shortcuts }); }); FindSEQTATab(); } /* Update the options UI with the settings values retrieved from storage, or the default settings if the stored settings are empty. */ function updateUI(restoredSettings) { if (typeof restoredSettings.onoff == 'undefined') { chrome.runtime.sendMessage({ type: "setDefaultStorage" }); chrome.storage.local.get(null, function (result) { updateUI(result); }); } else { onoffselection.checked = restoredSettings.onoff; notificationcollector.checked = restoredSettings.notificationcollector; lessonalert.checked = restoredSettings.lessonalert; animatedbk.checked = restoredSettings.animatedbk; chrome.storage.local.get(["shortcuts"], function (result) { var shortcuts = Object.values(result)[0]; for (var i = 0; i < shortcutbuttons.length; i++) { shortcutbuttons[i].checked = shortcuts[i].enabled; } chrome.storage.local.set({ shortcuts: shortcuts }); }); } } function CreateShortcutDiv(name) { div = stringtoHTML(` `).firstChild; shortcutmenuitemselection.append(div); const deletebutton = document.getElementById(`delete-${name}`); deletebutton.addEventListener('click', function () { DeleteCustomShortcut(name); applybutton.style.left = "4px"; }); } function AddCustomShortcuts() { chrome.storage.local.get(["customshortcuts"], function (result) { var customshortcuts = Object.values(result)[0]; for (let i = 0; i < customshortcuts.length; i++) { const element = customshortcuts[i]; CreateShortcutDiv( element.name, ) } }); } function DeleteCustomShortcut(name) { item = document.querySelector(`[data-customshortcut="${name}"]`); item.remove(); chrome.storage.local.get(["customshortcuts"], function (result) { var customshortcuts = Object.values(result)[0]; for (let i = 0; i < customshortcuts.length; i++) { if (customshortcuts[i].name == name) { customshortcuts.splice(i, 1); } } chrome.storage.local.set({ customshortcuts: customshortcuts }); }); } function CustomShortcutMenu() { customshortcutinputname.value = ''; customshortcutinputurl.value = ''; validURL = false; validName = false; customshortcutsubmit.classList.remove("customshortcut-submit-valid"); if (customshortcutdiv.classList.contains('custom-shortcuts-container-shown')) { customshortcutdiv.classList.remove('custom-shortcuts-container-shown') } else { customshortcutdiv.classList.add('custom-shortcuts-container-shown') }; } function CreateCustomShortcut() { const shortcutname = customshortcutinputname.value; var shortcuturl = customshortcutinputurl.value; if (!(shortcuturl.includes('http'))) { shortcuturl = "https://" + shortcuturl; } chrome.storage.local.get(["customshortcuts"], function (result) { var customshortcuts = Object.values(result)[0]; customshortcuts.push({ name: shortcutname, url: shortcuturl, icon: (shortcutname[0]).toUpperCase() }); chrome.storage.local.set({ customshortcuts: customshortcuts }); }); CreateShortcutDiv( shortcutname ); document.getElementsByClassName("shortcut-container")[0].style.display = "block"; } function onError(e) { console.error(e); } chrome.storage.local.get(null, function (result) { document.getElementsByClassName('clr-field')[0].style.color = result.selectedColor; colorpicker.value = result.selectedColor; updateUI(result); }); github.addEventListener("click", openGithub); aboutsection.addEventListener("click", () => { resetActive(); aboutsection.classList.add('activenav'); menupage.classList.remove('hiddenmenu') }); shortcutsection.addEventListener("click", () => { resetActive(); shortcutsection.classList.add('activenav'); shortcutpage.classList.remove('hiddenmenu') }); miscsection.addEventListener("click", () => { resetActive(); miscsection.classList.add('activenav'); miscpage.classList.remove('hiddenmenu') }); customshortcutbutton.addEventListener("click", () => { CustomShortcutMenu(); }) customshortcutsubmit.addEventListener("click", () => { if (validName && validURL) { CreateCustomShortcut(); CustomShortcutMenu() } }); var sameName = false; customshortcutinputname.addEventListener("input", function () { sameName = false; chrome.storage.local.get(["customshortcuts"], function (result) { var customshortcuts = Object.values(result)[0]; for (let i = 0; i < customshortcuts.length; i++) { if (customshortcuts[i].name == customshortcutinputname.value) { sameName = true; } } if (customshortcutinputname.value.length > 0 && customshortcutinputname.value.length < 22 && !sameName) { validName = true; } else { validName = false; } if (validName && validURL) { customshortcutsubmit.classList.add("customshortcut-submit-valid"); } else { customshortcutsubmit.classList.remove("customshortcut-submit-valid"); } }); }); customshortcutinputurl.addEventListener("input", function () { if (customshortcutinputurl.value.length > 0 && customshortcutinputurl.value.includes('.')) { validURL = true; } else { validURL = false; } if (validName && validURL) { customshortcutsubmit.classList.add("customshortcut-submit-valid"); } else { customshortcutsubmit.classList.remove("customshortcut-submit-valid"); } }) AddCustomShortcuts(); onoffselection.addEventListener("change", storeSettings); notificationcollector.addEventListener( "change", storeNotificationSettings ); lessonalert.addEventListener("change", storeNotificationSettings) animatedbk.addEventListener("change", storeNotificationSettings) for (let i = 0; i < allinputs.length; i++) { if (allinputs[i].id != 'colorpicker' && allinputs[i].id != "shortcuturl" && allinputs[i].id != "shortcutname") { allinputs[i].addEventListener("change", () => { applybutton.style.left = "4px" }) } } applybutton.addEventListener('click', () => { StoreAllSettings(); applybutton.style.left = "-150px" }) colorpicker.addEventListener("input", function () { var colorPreview = document.querySelector('#clr-color-preview') if (colorPreview.style.color) { var hex = colorPreview.style.color.split("(")[1].split(")")[0]; hex = hex.split(","); var b = hex.map(function (x) { //For each array element x = parseInt(x).toString(16); //Convert to a base16 string return (x.length == 1) ? "0" + x : x; //Add zero if we get only one character }) b = "#" + b.join(""); chrome.storage.local.set({ selectedColor: b }) } }) } function CallExtensionSettings() { // Injecting CSS File to the webpage to overwrite iFrame default CSS var cssFile = chrome.runtime.getURL("popup/info.css"); var fileref = document.createElement("link"); fileref.setAttribute("rel", "stylesheet"); fileref.setAttribute("type", "text/css"); fileref.setAttribute("href", cssFile); document.head.append(fileref); var jsFile = chrome.runtime.getURL("popup/coloris.js"); var fileref = document.createElement("script"); fileref.setAttribute("src", jsFile); document.head.append(fileref); var cssFile = chrome.runtime.getURL("popup/coloris.css"); var fileref = document.createElement("link"); fileref.setAttribute("rel", "stylesheet"); fileref.setAttribute("type", "text/css"); fileref.setAttribute("href", cssFile); document.head.append(fileref); NextPageImage = chrome.runtime.getURL('popup/page.png') Settings = stringToHTML(``) document.body.append(Settings.firstChild) var container = document.getElementById('container'); var extensionsettings = document.getElementById('ExtensionPopup'); container.onclick = function () { if (!SettingsClicked) { extensionsettings.classList.add('hidden'); } SettingsClicked = false } } function ApplyDraggableFunctions() { var listItens = document.querySelectorAll('.draggable'); [].forEach.call(listItens, function (item) { addEventsDragAndDrop(item); }); } // Code By Webdevtrick ( https://webdevtrick.com ) var remove = document.querySelector('.draggable'); function dragStart(e) { this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', this.innerHTML); }; function dragEnter(e) { this.classList.add('over'); } function dragLeave(e) { e.stopPropagation(); this.classList.remove('over'); } function dragOver(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; return false; } function dragDrop(e) { if (dragSrcEl != this) { const parentA = this.parentNode; const siblingA = this.nextSibling === dragSrcEl ? this : this.nextSibling; // Move `this` to before the `dragSrcEl` dragSrcEl.parentNode.insertBefore(this, dragSrcEl); // Move `dragSrcEl` to before the sibling of `this` parentA.insertBefore(dragSrcEl, siblingA); // Save position of all menu items children = parentA.childNodes; // console.log(children) listorder = [] for (let i = 0; i < children.length; i++) { const elm = children[i] listorder.push(elm.dataset.key) } chrome.storage.local.set({ menuorder: listorder }) } return false; } function dragEnd(e) { var listItens = document.querySelectorAll('.draggable'); [].forEach.call(listItens, function (item) { item.classList.remove('over'); }); this.style.opacity = '1'; } function addEventsDragAndDrop(el) { el.addEventListener('dragstart', dragStart, false); el.addEventListener('dragenter', dragEnter, false); el.addEventListener('dragover', dragOver, false); el.addEventListener('dragleave', dragLeave, false); el.addEventListener('drop', dragDrop, false); el.addEventListener('dragend', dragEnd, false); } function cloneAttributes(target, source) { [...source.attributes].forEach(attr => { target.setAttribute(attr.nodeName, attr.nodeValue) }) } function OpenMenuOptions() { chrome.storage.local.get(null, function (result) { var container = document.getElementById('container'); var menu = document.getElementById('menu'); if (result.defaultmenuorder.length == '0') { childnodes = menu.firstChild.childNodes; newdefaultmenuorder = []; for (let i = 0; i < childnodes.length; i++) { const element = childnodes[i]; newdefaultmenuorder.push(element.dataset.key) chrome.storage.local.set({ defaultmenuorder: newdefaultmenuorder }) } } childnodes = menu.firstChild.childNodes; if (result.defaultmenuorder.length != childnodes.length) { for (let i = 0; i < childnodes.length; i++) { const element = childnodes[i]; if (!result.defaultmenuorder.indexOf(element.dataset.key)) { newdefaultmenuorder = result.defaultmenuorder; newdefaultmenuorder.push(element.dataset.key); chrome.storage.local.set({ defaultmenuorder: newdefaultmenuorder }) } } } MenuOptionsOpen = true; cover = document.createElement('div'); cover.classList.add('notMenuCover'); menu.style.zIndex = '20'; menu.style.setProperty('--menuHidden', 'flex'); container.append(cover); menusettings = document.createElement('div'); menusettings.classList.add('editmenuoption-container'); defaultbutton = document.createElement('div'); defaultbutton.classList.add('editmenuoption'); defaultbutton.innerText = 'Restore Default'; defaultbutton.id = 'restoredefaultoption'; savebutton = document.createElement('div'); savebutton.classList.add('editmenuoption'); savebutton.innerText = 'Save'; savebutton.id = 'restoredefaultoption'; menusettings.appendChild(defaultbutton); menusettings.appendChild(savebutton); menu.appendChild(menusettings); ListItems = menu.firstChild.childNodes; for (let i = 0; i < ListItems.length; i++) { const element = ListItems[i]; element.classList.add('draggable'); element.setAttribute('draggable', true) if (element.classList.contains('hasChildren')) { element.classList.remove('active'); menu.firstChild.classList.remove('noscroll'); } MenuItemToggle = stringToHTML(`
    `).firstChild element.append(MenuItemToggle); if (!element.dataset.betterseqta) { var a = document.createElement('section'); a.innerHTML = element.innerHTML; cloneAttributes(a, element); menu.firstChild.insertBefore(a, element); element.remove(); } } if (Object.keys(result.menuitems).length == 0) { menubuttons = menu.firstChild.childNodes; var menuItems = {}; for (var i = 0; i < menubuttons.length; i++) { var id = menubuttons[i].dataset.key; const element = {} element.toggle = true; menuItems[id] = element; } chrome.storage.local.set({ menuitems: menuItems }); } var menubuttons = document.getElementsByClassName('menuitem'); chrome.storage.local.get(["menuitems"], function (result) { var menuItems = result.menuitems; buttons = document.getElementsByClassName('menuitem'); for (var i = 0; i < buttons.length; i++) { var id = buttons[i].id; if (menuItems[id]) { buttons[i].checked = menuItems[id].toggle; } if (!menuItems[id]) { buttons[i].checked = true; } } }); ApplyDraggableFunctions(); function StoreMenuSettings() { chrome.storage.local.get(["menuitems"], function (result) { var menuItems = {}; menubuttons = menu.firstChild.childNodes; button = document.getElementsByClassName('menuitem'); for (var i = 0; i < menubuttons.length; i++) { var id = menubuttons[i].dataset.key; const element = {} element.toggle = button[i].checked; menuItems[id] = element; } chrome.storage.local.set({ menuitems: menuItems }); }); } function changeDisplayProperty(element) { if (!element.checked) { element.parentNode.parentNode.style.display = 'var(--menuHidden)'; } if (element.checked) { element.parentNode.parentNode.style.setProperty('display', 'flex', 'important'); } } for (let i = 0; i < menubuttons.length; i++) { const element = menubuttons[i]; element.addEventListener('change', () => { StoreMenuSettings(); changeDisplayProperty(element); }) } function closeAll() { ListItems = menu.firstChild.childNodes; menusettings.remove(); cover.remove(); MenuOptionsOpen = false; menu.style.setProperty('--menuHidden', 'none'); for (let i = 0; i < ListItems.length; i++) { const element = ListItems[i]; element.classList.remove('draggable'); element.setAttribute('draggable', false) if (!element.dataset.betterseqta) { var a = document.createElement('li'); a.innerHTML = element.innerHTML; cloneAttributes(a, element); menu.firstChild.insertBefore(a, element); element.remove(); } } switches = menu.querySelectorAll('.onoffswitch') for (let i = 0; i < switches.length; i++) { switches[i].remove() } StoreMenuSettings(); } cover.addEventListener('click', closeAll) savebutton.addEventListener('click', closeAll) defaultbutton.addEventListener('click', function () { chrome.storage.local.get(null, function (response) { const options = response.defaultmenuorder chrome.storage.local.set({ menuorder: options }) ChangeMenuItemPositions(options); for (let i = 0; i < menubuttons.length; i++) { const element = menubuttons[i]; element.checked = true; element.parentNode.parentNode.style.setProperty('display', 'flex', 'important'); } StoreMenuSettings(); }) }) }) } function ReplaceMenuSVG(element, svg) { item = element.firstChild; item.firstChild.remove(); if (element.dataset.key == "messages") { element.firstChild.innerText = "Direct Messages"; } newsvg = stringToHTML(svg).firstChild; item.insertBefore(newsvg, item.firstChild); } function AddBetterSEQTAElements(toggle) { var code = document.getElementsByClassName("code")[0]; // Replaces students code with the version of BetterSEQTA if (code != null) { if (!code.innerHTML.includes("BestSEQTA")) { UserInitalCode = code.innerText; code.innerText = `BestSEQTA v${chrome.runtime.getManifest().version}`; code.setAttribute('data-hover', 'Click for user code'); code.addEventListener('click', function () { var code = document.getElementsByClassName("code")[0]; if (code.innerText.includes('BestSEQTA')) { code.innerText = UserInitalCode; code.setAttribute('data-hover', 'Click for BestSEQTA version') } else { code.innerText = `BestSEQTA v${chrome.runtime.getManifest().version}` code.setAttribute('data-hover', 'Click for user code'); } }) if (toggle) { // Creates Home menu button and appends it as the first child of the list chrome.storage.local.get(['animatedbk'], function (result) { if (result.animatedbk) { CreateBackground(); } else { document.getElementById('container').style.background = "var(--background-secondary)"; } }) var titlebar = document.createElement('div'); titlebar.classList.add("titlebar"); container = document.getElementById('content'); container.append(titlebar); var NewButtonStr = `
  • `; var NewButton = stringToHTML(NewButtonStr); var menu = document.getElementById("menu"); var List = menu.firstChild; List.insertBefore(NewButton.firstChild, List.firstChild); fetch(`${location.origin}/seqta/student/login`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({ "mode": "normal", "query": null, "redirect_url": location.origin }) }) .then((result) => result.json()) .then((response) => { info = response.payload; var titlebar = document.getElementsByClassName('titlebar')[0]; titlebar.append(stringToHTML(`
    `).firstChild) var userinfostr = `

    ${info.userDesc}

    ${UserInitalCode}

    ` var userinfo = stringToHTML(userinfostr).firstChild titlebar.append(userinfo) var logoutbutton = document.getElementsByClassName('logout')[0]; var userInfosvgdiv = document.getElementById('logouttooltip'); userInfosvgdiv.appendChild(logoutbutton); fetch(`${location.origin}/seqta/student/load/message/people`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({ "mode": "student" }) }) .then((result) => result.json()) .then((response) => { students = response.payload; var index = students.findIndex(function (person) { return person.firstname == (info.userDesc.split(' ')[0]) && person.surname == (info.userDesc.split(' ')[1]) }); houseelement = document.getElementsByClassName("userInfohouse")[0]; if (students[index].house) { houseelement.style.background = students[index].house_colour; colorresult = GetThresholdofHex(students[index].house_colour); if (colorresult > 300) { houseelement.style.color = "black"; } else { houseelement.style.color = "white"; } houseelement.innerText = students[index].year + students[index].house; } else { houseelement.innerText = students[index].year; } }) }) var NewsButtonStr = `
  • `; var NewsButton = stringToHTML(NewsButtonStr); List.appendChild(NewsButton.firstChild) editmenu = document.createElement('div'); editmenu.classList.add('editmenu'); svg = stringToHTML('') editmenu.append(svg.firstChild) menu.appendChild(editmenu); a = document.createElement('div'); a.classList.add('icon-cover'); a.id = 'icon-cover'; menu.appendChild(a); var editmenu = document.querySelector("#editmenu"); editmenu.addEventListener("click", function () { if (!MenuOptionsOpen) { OpenMenuOptions(); } }) var menuCover = document.querySelector("#icon-cover"); menuCover.addEventListener("click", function () { location.href = '../#?page=/home' SendHomePage(); document.getElementById('menu').firstChild.classList.remove('noscroll'); }) // Creates the home container when the menu button is pressed var homebutton = document.getElementById("homebutton"); homebutton.addEventListener("click", function () { if (!MenuOptionsOpen) { SendHomePage(); } }); // Creates the news container when the menu button is pressed var newsbutton = document.getElementById("newsbutton"); newsbutton.addEventListener("click", function () { if (!MenuOptionsOpen) { SendNewsPage(); } }); } CallExtensionSettings(); RunExtensionSettingsJS(); if (toggle) { // Creates settings and dashboard buttons next to alerts var SettingsButton = stringToHTML( `` ); var ContentDiv = document.getElementById("content"); ContentDiv.append(SettingsButton.firstChild); chrome.storage.local.get(['DarkMode'], function (result) { Darkmode = result.DarkMode; tooltipstring = GetLightDarkModeString(Darkmode); var LightDarkModeButton = stringToHTML(``); ContentDiv.append(LightDarkModeButton.firstChild); LightDarkModeElement = document.getElementById('LightDarkModeButton'); if (Darkmode) { LightDarkModeElement.firstChild.innerHTML = `` } else { LightDarkModeElement.firstChild.innerHTML = `` } darklightText = document.getElementById('darklighttooliptext'); LightDarkModeElement.addEventListener('click', function () { chrome.storage.local.get(['DarkMode'], function (result) { alliframes = document.getElementsByTagName('iframe'); fileref = GetiFrameCSSElement(); if (!result.DarkMode) { document.documentElement.style.setProperty('--background-primary', "#232323"); document.documentElement.style.setProperty('--background-secondary', "#1a1a1a"); document.documentElement.style.setProperty('--text-primary', "white"); LightDarkModeElement.firstChild.innerHTML = `` for (let i = 0; i < alliframes.length; i++) { const element = alliframes[i]; element.contentDocument.documentElement.childNodes[1].style.color = "white"; element.contentDocument.documentElement.firstChild.appendChild(fileref); } } else { document.documentElement.style.setProperty('--background-primary', "#ffffff"); document.documentElement.style.setProperty('--background-secondary', "#e5e7eb"); document.documentElement.style.setProperty('--text-primary', "black"); LightDarkModeElement.firstChild.innerHTML = `` for (let i = 0; i < alliframes.length; i++) { const element = alliframes[i]; element.contentDocument.documentElement.childNodes[1].style.color = "black"; element.contentDocument.documentElement.firstChild.lastChild.remove(); } } tooltipstring = GetLightDarkModeString(!result.DarkMode); darklightText.innerText = tooltipstring; chrome.storage.local.set({ DarkMode: !result.DarkMode }); }); }); }); } else { // Creates settings and dashboard buttons next to alerts var SettingsButton = stringToHTML( `` ); var ContentDiv = document.getElementById("content"); ContentDiv.append(SettingsButton.firstChild); } var AddedSettings = document.getElementById("AddedSettings"); var extensionsettings = document.getElementById("ExtensionPopup") AddedSettings.addEventListener("click", function () { extensionsettings.classList.toggle('hidden'); SettingsClicked = true }); } } } function GetLightDarkModeString(darkmodetoggle) { if (darkmodetoggle) { tooltipstring = "Switch to light theme"; } else { tooltipstring = "Switch to dark theme"; } return tooltipstring; } function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function ChangeCurrentPage(newpage) { window.location.replace(`${location.origin}"/#?page=/" + ${newpage}`); } function CheckCurrentLesson(lesson, num) { var startTime = lesson.from; var endTime = lesson.until; // Gets current time currentDate = new Date(); // Takes start time of current lesson and makes it into a Date function for comparison startDate = new Date(currentDate.getTime()); startDate.setHours(startTime.split(":")[0]); startDate.setMinutes(startTime.split(":")[1]); startDate.setSeconds("00"); // Takes end time of current lesson and makes it into a Date function for comparison endDate = new Date(currentDate.getTime()); endDate.setHours(endTime.split(":")[0]); endDate.setMinutes(endTime.split(":")[1]); endDate.setSeconds("00"); // Gets the difference between the start time and current time var difference = startDate.getTime() - currentDate.getTime(); // Converts the difference into minutes var minutes = Math.floor(difference / 1000 / 60); // Checks if current time is between the start time and end time of current tested lesson valid = startDate < currentDate && endDate > currentDate; id = lesson.code + num const date = new Date() var elementA = document.getElementById(id); if (!elementA) { clearInterval(LessonInterval); } else { if (currentSelectedDate.toLocaleDateString('en-au') == date.toLocaleDateString('en-au')) { if (valid) { // Apply the activelesson class to increase the box-shadow of current lesson elementA.classList.add("activelesson"); } else { // Removes the activelesson class to ensure only the active lesson have the class if (elementA != null) { elementA.classList.remove("activelesson"); } } } } // If 5 minutes before the start of another lesson: if (minutes == 5) { chrome.storage.local.get('lessonalert', function (result) { if (result.lessonalert) { // Checks if notifications are supported if (!window.Notification) { console.log("Browser does not support notifications."); } else { // check if permission is already granted if (Notification.permission === "granted") { // show notification here } else { // request permission from user Notification.requestPermission() .then(function (p) { if (p === "granted") { // show notification here var notify = new Notification("Next Lesson in 5 Minutes:", { body: "Subject: " + lesson.description + " \nRoom: " + lesson.room + " \nTeacher: " + lesson.staff, }); } else { console.log("User blocked notifications."); } }) .catch(function (err) { console.error(err); }); } } } }); } } function hexToRGB(hex) { var r = parseInt(hex.slice(1, 3), 16), g = parseInt(hex.slice(3, 5), 16), b = parseInt(hex.slice(5, 7), 16); return { 'r': r, 'g': g, 'b': b } } function GetThresholdofHex(hex) { var rgb = hexToRGB(hex) return Math.sqrt(rgb.r ** 2 + rgb.g ** 2 + rgb.b ** 2) } function CheckCurrentLessonAll(lessons) { // Checks each lesson and sets an interval to run every 60 seconds to continue updating LessonInterval = setInterval( function () { for (i = 0; i < lessons.length; i++) { CheckCurrentLesson(lessons[i], i + 1); } }.bind(lessons), 60000 ); } function MakeLessonDiv(lesson, num) { assessmentstring = "" var lessonstring = `

    ${lesson?.description ?? "Unknown"}

    ${lesson?.staff ?? "Unknown"}

    ${lesson?.room ?? "Unknown"}

    ${lesson?.from ?? "Unknown"} - ${lesson?.until ?? "Unknown"}

    ${lesson?.attendanceTitle ?? "Unknown"}
    ` if (lesson.programmeID != 0) { lessonstring += `
    ${assessmentsicon}
    ${coursesicon}
    ` } if (lesson.assessments.length > 0) { for (let i = 0; i < lesson.assessments.length; i++) { const element = lesson.assessments[i] assessmentstring += `

    ${element.title}

    ` } lessonstring += `
    ${assessmentstring}
    ` } lessonstring += '
    '; var lessondiv = stringToHTML(lessonstring); return lessondiv; } function CheckUnmarkedAttendance(lessonattendance) { if (lessonattendance) { var lesson = lessonattendance.label; } else { var lesson = " "; } return lesson; } function callHomeTimetable(date, change) { // Creates a HTTP Post Request to the SEQTA page for the students timetable var xhr = new XMLHttpRequest(); xhr.open( "POST", `${location.origin}/seqta/student/load/timetable?`, true ); // Sets the response type to json xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8"); xhr.onreadystatechange = function () { // Once the response is ready if (xhr.readyState === 4) { var serverResponse = JSON.parse(xhr.response); lessonArray = []; var DayContainer = document.getElementById("day-container") // If items in response: if (serverResponse.payload.items.length > 0) { if (!DayContainer.innerText || change) { // console.log(serverResponse.payload.items.length); for (let i = 0; i < serverResponse.payload.items.length; i++) { lessonArray.push(serverResponse.payload.items[i]); } lessonArray.sort(function (a, b) { return a.from.localeCompare(b.from); }); // If items in the response, set each corresponding value into divs // lessonArray = lessonArray.splice(1) GetLessonColours().then((colours) => { subjects = colours; for (let i = 0; i < lessonArray.length; i++) { subjectname = `timetable.subject.colour.${lessonArray[i].code}` subject = subjects.find(element => element.name === subjectname) if (!subject) { lessonArray[i].colour = `--item-colour: #8e8e8e;` } else { lessonArray[i].colour = `--item-colour: ${subject.value};` result = GetThresholdofHex(subject.value); if (result > 300) { lessonArray[i].invert = true; } } // Removes seconds from the start and end times lessonArray[i].from = lessonArray[i].from.substring(0, 5); lessonArray[i].until = lessonArray[i].until.substring(0, 5); // Checks if attendance is unmarked, and sets the string to " ". lessonArray[i].attendanceTitle = CheckUnmarkedAttendance( lessonArray[i].attendance) } // If on home page, apply each lesson to HTML with information in each div DayContainer.innerText = ''; for (let i = 0; i < lessonArray.length; i++) { var div = MakeLessonDiv(lessonArray[i], i + 1); // Append each of the lessons into the day-container if (lessonArray[i].invert) { div.firstChild.classList.add('day-inverted'); } DayContainer.append(div.firstChild); } const today = new Date(); if (currentSelectedDate.getDate() == today.getDate()) { for (i = 0; i < lessonArray.length; i++) { CheckCurrentLesson(lessonArray[i], i + 1); } // For each lesson, check the start and end times CheckCurrentLessonAll(lessonArray); } }) } } else { if (!DayContainer.innerText || change) { DayContainer.innerText = ''; var dummyDay = document.createElement("div"); dummyDay.classList.add("day-empty"); img = document.createElement('img') img.src = chrome.runtime.getURL('icons/betterseqta-light-icon.png') text = document.createElement('p') text.innerText = "No lessons available." dummyDay.append(img); dummyDay.append(text); DayContainer.append(dummyDay); } } } }; xhr.send( JSON.stringify({ // Information sent to SEQTA page as a request with the dates and student number from: date, until: date, // Funny number student: 69, }) ); } function GetUpcomingAssessments() { func = fetch(`${location.origin}/seqta/student/assessment/list/upcoming?`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({ "student": 69 }) }) return func .then((result) => result.json()) .then(response => (response.payload)) } function GetActiveClasses() { func = fetch(`${location.origin}/seqta/student/load/subjects?`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({}) }) return func .then((result) => result.json()) .then(response => (response.payload)) } function comparedate(obj1, obj2) { if (obj1.date < obj2.date) { return -1; } if (obj1.date > obj2.date) { return 1; } return 0; } function CreateElement(type, class_, id, innerText, innerHTML, style) { element = document.createElement(type); if (class_ !== undefined) { element.classList.add(class_); } if (id !== undefined) { element.id = id; } if (innerText !== undefined) { element.innerText = innerText; } if (innerHTML !== undefined) { element.innerHTML = innerHTML; } if (style !== undefined) { element.style = style; } return element } function createAssessmentDateDiv(date, value, datecase = undefined) { var options = { weekday: 'long', month: 'long', day: 'numeric' }; const FormattedDate = new Date(date) const assessments = value.assessments; const container = value.div; DateTitleDiv = document.createElement('div'); DateTitleDiv.classList.add('upcoming-date-title'); if (datecase) { datetitle = document.createElement('h5'); datetitle.classList.add('upcoming-special-day') datetitle.innerText = datecase; DateTitleDiv.append(datetitle); container.setAttribute('data-day', datecase); } DateTitle = document.createElement('h5') DateTitle.innerText = FormattedDate.toLocaleDateString("en-AU", options); DateTitleDiv.append(DateTitle); container.append(DateTitleDiv); assessmentContainer = document.createElement('div') assessmentContainer.classList.add('upcoming-date-assessments'); for (let i = 0; i < assessments.length; i++) { const element = assessments[i]; item = document.createElement('div') item.classList.add('upcoming-assessment'); item.setAttribute('data-subject', element.code); item.id = `assessment${element.id}`; item.style = element.colour; titlediv = document.createElement('div'); titlediv.classList.add('upcoming-subject-title'); titlesvg = stringToHTML(` `).firstChild titlediv.append(titlesvg); detailsdiv = document.createElement('div'); detailsdiv.classList.add('upcoming-details'); detailstitle = document.createElement('h5'); detailstitle.innerText = `${element.subject} assessment`; subject = document.createElement('p'); subject.innerText = element.title; subject.classList.add('upcoming-assessment-title'); subject.onclick = function () { location.href = `../#?page=/assessments/${element.programmeID}:${element.metaclassID}&item=${element.id}` }; detailsdiv.append(detailstitle); detailsdiv.append(subject); item.append(titlediv); item.append(detailsdiv); assessmentContainer.append(item); fetch(`${location.origin}/seqta/student/assessment/submissions/get`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({ "assessment": element.id, "metaclass": element.metaclassID, "student": 69 }) }) .then((result) => result.json()) .then((response) => { if (response.payload.length > 0) { const assessment = document.querySelector(`#assessment${element.id}`); // ticksvg = stringToHTML(``).firstChild // ticksvg.classList.add('upcoming-tick'); // assessment.append(ticksvg); submittedtext = document.createElement('div') submittedtext.classList.add('upcoming-submittedtext'); submittedtext.innerText = "Submitted"; assessment.append(submittedtext); } }) } container.append(assessmentContainer); return container; } function CheckSpecialDay(date1, date2) { if ( date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && (date1.getDate() - 1) === date2.getDate() ) { return "Yesterday"; } if ( date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate() ) { TodayinUpcoming = true; return "Today"; } if ( date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && (date1.getDate() + 1) === date2.getDate() ) { TomorrowinUpcoming = true; return "Tomorrow"; } } function CreateDateCheckedDiv(text, date) { upcomingitemcontainer = document.querySelector('#upcoming-items') container = CreateElement(type = 'div', class_ = 'upcoming-date-container'); datecontainer = CreateElement(type = 'div', class_ = 'upcoming-date-title'); titletext = CreateElement(type = 'h5', class_ = 'upcoming-special-day', id = undefined, innerText = text); titledate = CreateElement(type = 'h5', class_ = undefined, id = undefined, innerText = date); textcontainer = CreateElement('div', 'upcoming-blank') textblank = CreateElement('p'); textblank.innerText = 'No assessments due'; textcontainer.append(textblank) datecontainer.append(titletext); datecontainer.append(titledate); container.append(datecontainer); container.append(textcontainer) upcomingitemcontainer.append(container); } function CreateSubjectFilter(subjectcode, itemcolour, checked) { label = CreateElement('label', "upcoming-checkbox-container") label.innerText = subjectcode; input = CreateElement('input'); input.type = "checkbox"; input.checked = checked; input.id = `filter-${subjectcode}`; label.style = itemcolour; span = CreateElement('span', 'upcoming-checkmark') label.append(input); label.append(span); input.addEventListener('change', function (change) { chrome.storage.local.get(null, function (storage) { filters = storage.subjectfilters; id = change.target.id.split('-')[1] filters[id] = change.target.checked chrome.storage.local.set({ subjectfilters: filters }) }) }) return label } function CreateFilters(subjects) { chrome.storage.local.get(null, function (result) { filteroptions = result.subjectfilters filterdiv = document.querySelector('#upcoming-filters') for (let i = 0; i < subjects.length; i++) { const element = subjects[i]; if (!filteroptions.hasOwnProperty(element.code)) { filteroptions[element.code] = true; chrome.storage.local.set({ subjectfilters: filteroptions }); } elementdiv = CreateSubjectFilter(element.code, element.colour, filteroptions[element.code]) filterdiv.append(elementdiv) } }) } function CreateUpcomingSection(assessments) { upcomingitemcontainer = document.querySelector('#upcoming-items') homecontainer = document.querySelector('#home-container') overdueDates = []; upcomingDates = {}; TodayinUpcoming = false; TomorrowinUpcoming = false; // date = '2022/3/20'; // var Today = new Date(date); var Today = new Date(); // Removes overdue assessments from the upcoming assessments array and pushes to overdue array for (let i = 0; i < assessments.length; i++) { const element = assessments[i]; assessmentdue = new Date(element.due); CheckSpecialDay(Today, assessmentdue) if (assessmentdue < Today) { if (!CheckSpecialDay(Today, assessmentdue)) { overdueDates.push(element); assessments.splice(i, 1); i--; } } } var options = { weekday: 'long', month: 'long', day: 'numeric' }; if (!TodayinUpcoming) { text = Today.toLocaleDateString("en-AU", options); CreateDateCheckedDiv("Today", text); } function addTomorrowinUpcoming() { // var TomorrowDate = new Date(date); var TomorrowDate = new Date(); TomorrowDate.setDate((TomorrowDate.getDate() + 1)) textDate = TomorrowDate.toLocaleDateString("en-AU", options); CreateDateCheckedDiv("Tomorrow", textDate); } if (!TomorrowinUpcoming && !TodayinUpcoming) { addTomorrowinUpcoming(); } GetLessonColours().then((colours) => { subjects = colours; for (let i = 0; i < assessments.length; i++) { subjectname = `timetable.subject.colour.${assessments[i].code}` subject = subjects.find(element => element.name === subjectname) if (!subject) { assessments[i].colour = `--item-colour: #8e8e8e;` } else { assessments[i].colour = `--item-colour: ${subject.value};` result = GetThresholdofHex(subject.value); } } for (let i = 0; i < activeSubjects.length; i++) { const element = activeSubjects[i]; subjectname = `timetable.subject.colour.${element.code}` colour = colours.find(element => element.name === subjectname); if (!colour) { element.colour = `--item-colour: #8e8e8e;` } else { element.colour = `--item-colour: ${colour.value};` result = GetThresholdofHex(colour.value); if (result > 300) { element.invert = true; } } } CreateFilters(activeSubjects); for (let i = 0; i < assessments.length; i++) { const element = assessments[i]; if (!upcomingDates[element.due]) { dateObj = new Object(); dateObj.div = CreateElement(type = 'div', class_ = 'upcoming-date-container') dateObj.assessments = []; upcomingDates[element.due] = dateObj; } assessmentDateDiv = upcomingDates[element.due]; assessmentDateDiv.assessments.push(element); } for (var date in upcomingDates) { assessmentdue = new Date(upcomingDates[date].assessments[0].due); specialcase = CheckSpecialDay(Today, assessmentdue); if (specialcase) { assessmentDate = createAssessmentDateDiv(date, upcomingDates[date], datecase = specialcase); } else { assessmentDate = createAssessmentDateDiv(date, upcomingDates[date]); } if (specialcase === 'Yesterday') { upcomingitemcontainer.insertBefore(assessmentDate, upcomingitemcontainer.firstChild); } else { upcomingitemcontainer.append(assessmentDate) } if (specialcase === 'Today' && !TomorrowinUpcoming) { addTomorrowinUpcoming(); } } chrome.storage.local.get(null, function (result) { FilterUpcomingAssessments(result.subjectfilters); }) }) } function AddPlaceHolderToParent(parent, numberofassessments) { textcontainer = CreateElement('div', 'upcoming-blank') textblank = CreateElement('p', 'upcoming-hiddenassessment'); s = ""; if (numberofassessments > 1) { s = "s"; } textblank.innerText = `${numberofassessments} hidden assessment${s} due`; textcontainer.append(textblank); textcontainer.setAttribute('data-hidden', true); parent.append(textcontainer); } function FilterUpcomingAssessments(subjectoptions) { for (var item in subjectoptions) { subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`); for (let i = 0; i < subjectdivs.length; i++) { const element = subjectdivs[i]; if (!subjectoptions[item]) { element.classList.add('hidden'); } if (subjectoptions[item]) { element.classList.remove('hidden'); } element.parentNode.classList.remove('hidden'); children = element.parentNode.parentNode.children for (let i = 0; i < children.length; i++) { const element = children[i]; if (element.hasAttribute('data-hidden')) { element.remove(); } } if (element.parentNode.children.length == element.parentNode.querySelectorAll(".hidden").length) { if (element.parentNode.querySelectorAll(".hidden").length > 0) { if (!element.parentNode.parentNode.hasAttribute('data-day')) { element.parentNode.parentNode.classList.add('hidden'); } else { AddPlaceHolderToParent(element.parentNode.parentNode, element.parentNode.querySelectorAll(".hidden").length) } } } else { element.parentNode.parentNode.classList.remove('hidden'); } } } } chrome.storage.onChanged.addListener(function (changes) { if (changes.subjectfilters) { FilterUpcomingAssessments(changes.subjectfilters.newValue); } }) function GetLessonColours() { func = fetch(`${location.origin}/seqta/student/load/prefs?`, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8", }, body: JSON.stringify({ "request": "userPrefs", "asArray": true, "user": 69 }) }) return func .then((result) => result.json()) .then(response => (response.payload)) } function CreateCustomShortcutDiv(element) { // Creates the stucture and element information for each seperate shortcut var shortcut = document.createElement("a"); shortcut.setAttribute("href", element.url); shortcut.setAttribute("target", "_blank"); var shortcutdiv = document.createElement("div"); shortcutdiv.classList.add("shortcut"); shortcutdiv.classList.add("customshortcut"); image = stringToHTML(`${element.icon}`).firstChild image.classList.add("shortcuticondiv"); var text = document.createElement("p"); text.textContent = element.name; shortcutdiv.append(image); shortcutdiv.append(text); shortcut.append(shortcutdiv); document.getElementById("shortcuts").append(shortcut); } function AddCustomShortcutsToPage() { chrome.storage.local.get(["customshortcuts"], function (result) { var customshortcuts = Object.values(result)[0]; if (customshortcuts.length > 0) { document.getElementsByClassName("shortcut-container")[0].style.display = "block"; for (let i = 0; i < customshortcuts.length; i++) { const element = customshortcuts[i]; CreateCustomShortcutDiv(element); } } }); } function SendHomePage() { setTimeout(function () { // Sends the html data for the home page console.log("[BestSEQTA] Started Loading Home Page"); document.title = "Home ― SEQTA Learn"; var element = document.querySelector("[data-key=home]"); // Apply the active class to indicate clicked on home button element.classList.add("active"); // Remove all current elements in the main div to add new elements var main = document.getElementById("main"); main.innerHTML = ""; const titlediv = document.getElementById('title').firstChild; titlediv.innerText = "Home"; document.querySelector('link[rel*="icon"]').href = chrome.runtime.getURL("icons/icon-48.png"); currentSelectedDate = new Date(); // Creates the root of the home page added to the main div var htmlStr = `
    `; var html = stringToHTML(htmlStr); // Appends the html file to main div // Note : firstChild of html is done due to needing to grab the body from the stringToHTML function main.append(html.firstChild); // Gets the current date const date = new Date(); // Formats the current date used send a request for timetable and notices later var TodayFormatted = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); // Replaces actual date with a selected date. Used for testing. // TodayFormatted = "2020-08-31"; // Creates the shortcut container into the home container var ShortcutStr = `
    `; var Shortcut = stringToHTML(ShortcutStr); // Appends the shortcut container into the home container document.getElementById("home-container").append(Shortcut.firstChild); // Creates the container div for the timetable portion of the home page var TimetableStr = `

    Today's Lessons

    `; var Timetable = stringToHTML(TimetableStr); // Appends the timetable container into the home container document.getElementById("home-container").append(Timetable.firstChild); var timetablearrowback = document.getElementById('home-timetable-back') var timetablearrowforward = document.getElementById('home-timetable-forward') function SetTimetableSubtitle() { var homelessonsubtitle = document.getElementById('home-lesson-subtitle'); const date = new Date(); if (date.getYear() == currentSelectedDate.getYear() && date.getMonth() == currentSelectedDate.getMonth()) { if (date.getDate() == currentSelectedDate.getDate()) { // Change text to Today's Lessons homelessonsubtitle.innerText = "Today's Lessons"; } else if ((date.getDate() - 1) == currentSelectedDate.getDate()) { // Change text to Yesterday's Lessons homelessonsubtitle.innerText = "Yesterday's Lessons"; } else if ((date.getDate() + 1) == currentSelectedDate.getDate()) { // Change text to Tomorrow's Lessons homelessonsubtitle.innerText = "Tomorrow's Lessons"; } else { // Change text to date of the day homelessonsubtitle.innerText = `${currentSelectedDate.toLocaleString('en-us', { weekday: 'short' })} ${currentSelectedDate.toLocaleDateString('en-au')}`; } } else { // Change text to date of the day homelessonsubtitle.innerText = `${currentSelectedDate.toLocaleString('en-us', { weekday: 'short' })} ${currentSelectedDate.toLocaleDateString('en-au')}`; } } function changeTimetable(value) { currentSelectedDate.setDate(currentSelectedDate.getDate() + value); FormattedDate = currentSelectedDate.getFullYear() + "-" + (currentSelectedDate.getMonth() + 1) + "-" + currentSelectedDate.getDate(); callHomeTimetable(FormattedDate, true); SetTimetableSubtitle(); } timetablearrowback.addEventListener('click', function () { changeTimetable(-1) }) timetablearrowforward.addEventListener('click', function () { changeTimetable(1) }) assessmentsicon = `` coursesicon = `` function createNewShortcut(link, icon, viewBox, title) { // Creates the stucture and element information for each seperate shortcut var shortcut = document.createElement("a"); shortcut.setAttribute("href", link); shortcut.setAttribute("target", "_blank"); var shortcutdiv = document.createElement("div"); shortcutdiv.classList.add("shortcut"); image = stringToHTML(``).firstChild image.classList.add("shortcuticondiv"); var text = document.createElement("p"); text.textContent = title; shortcutdiv.append(image); shortcutdiv.append(text); shortcut.append(shortcutdiv); document.getElementById("shortcuts").append(shortcut); } // Adds the shortcuts to the shortcut container chrome.storage.local.get(["shortcuts"], function (result) { var shortcuts = Object.values(result)[0]; for (let i = 0; i < shortcuts.length; i++) { if (shortcuts[i].enabled) { Itemname = (shortcuts[i].name).replace(/ /g, '') createNewShortcut( ShortcutLinks[Itemname].link, ShortcutLinks[Itemname].icon, ShortcutLinks[Itemname].viewBox, shortcuts[i].name ); } } AddCustomShortcutsToPage(); // Checks if shortcut container is empty if (document.getElementById("shortcuts").childElementCount == 0) { // If there are no shortcuts, hide the container document.getElementsByClassName("shortcut-container")[0].style.display = "none"; } }); // Creates the upcoming container and appends to the home container var upcomingcontainer = document.createElement('div'); upcomingcontainer.classList.add('upcoming-container'); upcomingcontainer.classList.add('border'); upcomingtitlediv = CreateElement('div', 'upcoming-title'); upcomingtitle = document.createElement('h2'); upcomingtitle.classList.add('home-subtitle'); upcomingtitle.innerText = 'Upcoming Assessments'; upcomingtitlediv.append(upcomingtitle); upcomingfilterdiv = CreateElement('div', 'upcoming-filters', 'upcoming-filters'); upcomingtitlediv.append(upcomingfilterdiv) upcomingcontainer.append(upcomingtitlediv); upcomingitems = document.createElement('div'); upcomingitems.id = 'upcoming-items'; upcomingitems.classList.add('upcoming-items'); upcomingcontainer.append(upcomingitems); document.getElementById("home-container").append(upcomingcontainer); // Creates the notices container into the home container var NoticesStr = `

    Notices

    `; var Notices = stringToHTML(NoticesStr); // Appends the shortcut container into the home container document.getElementById("home-container").append(Notices.firstChild); callHomeTimetable(TodayFormatted); // Sends similar HTTP Post Request for the notices var xhr2 = new XMLHttpRequest(); xhr2.open( "POST", `${location.origin}/seqta/student/load/notices?`, true ); xhr2.setRequestHeader("Content-Type", "application/json; charset=utf-8"); xhr2.onreadystatechange = function () { if (xhr2.readyState === 4) { var NoticesPayload = JSON.parse(xhr2.response); var NoticeContainer = document.getElementById("notice-container"); if (NoticesPayload.payload.length == 0) { if (!NoticeContainer.innerText) { // If no notices: display no notices var dummyNotice = document.createElement("div"); dummyNotice.textContent = "No notices for today."; dummyNotice.classList.add("dummynotice"); NoticeContainer.append(dummyNotice); } } else { if (!NoticeContainer.innerText) { // For each element in the response json: chrome.storage.local.get(["DarkMode"], function (result) { for (let i = 0; i < NoticesPayload.payload.length; i++) { // Create a div, and place information from json response var NewNotice = document.createElement("div"); NewNotice.classList.add("notice"); var title = stringToHTML( `

    ` + NoticesPayload.payload[i].title + `

    ` ); NewNotice.append(title.firstChild); if (NoticesPayload.payload[i].label_title != undefined) { var label = stringToHTML( `
    ` + NoticesPayload.payload[i].label_title + `
    ` ); NewNotice.append(label.firstChild); } var staff = stringToHTML( `
    ` + NoticesPayload.payload[i].staff + `
    ` ); NewNotice.append(staff.firstChild); // Converts the string into HTML var content = stringToHTML(NoticesPayload.payload[i].contents, styles=true); for (let i = 0; i < content.childNodes.length; i++) { NewNotice.append(content.childNodes[i]); } // Gets the colour for the top section of each notice var colour = NoticesPayload.payload[i].colour; if (typeof (colour) == "string") { rgb = GetThresholdofHex(colour); DarkModeResult = result.DarkMode if (rgb < 100 && DarkModeResult) { colour = undefined; } } var colourbar = document.createElement("div"); colourbar.classList.add("colourbar"); colourbar.style.background = "var(--colour)"; NewNotice.style = `--colour: ${colour}`; // Appends the colour bar to the new notice NewNotice.append(colourbar); // Appends the new notice into the notice container NoticeContainer.append(NewNotice); } }); } } } }; // Data sent as the POST request xhr2.send(JSON.stringify({ date: TodayFormatted })); // Sends similar HTTP Post Request for the notices chrome.storage.local.get(null, function (result) { if (result.notificationcollector) { var xhr3 = new XMLHttpRequest(); xhr3.open( "POST", `${location.origin}/seqta/student/heartbeat?`, true ); xhr3.setRequestHeader( "Content-Type", "application/json; charset=utf-8" ); xhr3.onreadystatechange = function () { if (xhr3.readyState === 4) { var Notifications = JSON.parse(xhr3.response); var alertdiv = document.getElementsByClassName( "notifications__bubble___1EkSQ" )[0]; if (typeof alertdiv == 'undefined') { console.log("[BestSEQTA] No notifications currently") } else { alertdiv.textContent = Notifications.payload.notifications.length; } } }; xhr3.send( JSON.stringify({ timestamp: "1970-01-01 00:00:00.0", hash: "#?page=/home", }) ); } }); GetUpcomingAssessments() .then((assessments) => { GetActiveClasses().then((classes) => { // Gets all subjects for the student for (let i = 0; i < classes.length; i++) { const element = classes[i]; if (element.hasOwnProperty('active')) { // Finds the active class list with the current subjects activeClassList = classes[i] } } activeSubjects = activeClassList.subjects activeSubjectCodes = [] // Gets the code for each of the subjects and puts them in an array for (let i = 0; i < activeSubjects.length; i++) { const element = activeSubjects[i]; activeSubjectCodes.push(element.code) } CurrentAssessments = [] for (let i = 0; i < assessments.length; i++) { const element = assessments[i]; if (activeSubjectCodes.includes(element.code)) { CurrentAssessments.push(element) } } CurrentAssessments.sort(comparedate); CreateUpcomingSection(CurrentAssessments, activeSubjects); // Run function to check if gap between assessments > 7 days? }) }); }, 8); } function SendNewsPage() { setTimeout(function () { // Sends the html data for the home page console.log("[BestSEQTA] Started Loading News Page"); document.title = "News ― SEQTA Learn"; var element = document.querySelector("[data-key=news]"); // Apply the active class to indicate clicked on home button element.classList.add("active"); // Remove all current elements in the main div to add new elements var main = document.getElementById("main"); main.innerHTML = ""; // Creates the root of the home page added to the main div var htmlStr = `

    Latest Headlines - ABC News

    `; var html = stringToHTML(htmlStr); // Appends the html file to main div // Note : firstChild of html is done due to needing to grab the body from the stringToHTML function main.append(html.firstChild); const titlediv = document.getElementById('title').firstChild; titlediv.innerText = "News"; AppendLoadingSymbol("newsloading", "#news-container"); chrome.runtime.sendMessage({ type: "sendNews" }, function (response) { newsarticles = response.news.articles; var newscontainer = document.querySelector('#news-container'); document.getElementById('newsloading').remove(); for (let i = 0; i < newsarticles.length; i++) { newsarticle = document.createElement('a'); newsarticle.classList.add('NewsArticle'); newsarticle.href = newsarticles[i].url; newsarticle.target = '_blank'; articleimage = document.createElement('div'); articleimage.classList.add('articleimage') if (newsarticles[i].urlToImage == 'null') { articleimage.style.backgroundImage = `url(${chrome.runtime.getURL("icons/betterseqta-light-outline.png")})`; articleimage.style.width = '20%' articleimage.style.margin = '0 7.5%'; } else { articleimage.style.backgroundImage = `url(${newsarticles[i].urlToImage})`; } articletext = document.createElement('div'); articletext.classList.add('ArticleText') title = document.createElement('a'); title.innerText = newsarticles[i].title; title.href = newsarticles[i].url; title.target = '_blank'; description = document.createElement('p'); description.innerHTML = newsarticles[i].description; articletext.append(title); articletext.append(description); newsarticle.append(articleimage); newsarticle.append(articletext); newscontainer.append(newsarticle); } }); }, 8); } function EnabledDisabledToBool(input) { if (input == "enabled") { return true; } if (input == "disabled") { return false; } } function LoadInit() { console.log("[BestSEQTA] Started Init"); chrome.storage.local.get(null, function (result) { if (result.onoff) { SendHomePage(); } }); }