diff --git a/src/SEQTA.js b/src/SEQTA.js new file mode 100644 index 00000000..0669679f --- /dev/null +++ b/src/SEQTA.js @@ -0,0 +1,3254 @@ +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +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) { + var parser = new DOMParser(); + var doc = parser.parseFromString(str, "text/html"); + 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" + }, + EducationPerfect: { + link: "https://app.educationperfect.com", + viewBox: "0 0 24 24", + } +} + +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.0.2 - The custom shortcut feature wasn't working +

3.0.1 - Bug fixes and removing redundant code +

3.0.0 - The beginning of BestSEQTA, I am forking the project to take it in a new direction +

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] Your inbox is clean") + + } + 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] Your inbox is clean") + + } + 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.extension.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.extension.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 }); + }); + } + } + + var stringtoHTML = function (str) { + var parser = new DOMParser(); + var doc = parser.parseFromString(str, "text/html"); + return doc.body; + }; + + 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) { + rbg = hexToRGB(hex) + return Math.sqrt(rbg.r ** 2 + rbg.g ** 2 + rbg.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] 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.extension.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); + 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] Your inbox is clean") + + } + 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(); + } + + }); +} diff --git a/src/background.js b/src/background.js new file mode 100644 index 00000000..0a4bb7d1 --- /dev/null +++ b/src/background.js @@ -0,0 +1,222 @@ +function ReloadSEQTAPages() { + chrome.tabs.query({}, function (tabs) { + for (let tab of tabs) { + if (tab.title.includes("SEQTA Learn")) { + chrome.tabs.reload(tab.id); + } + } + }); +} + +chrome.runtime.onMessage.addListener(function (request, sender) { + if (request.type == "reloadTabs") { + ReloadSEQTAPages(); + } + else if (request.type == "githubTab") { + chrome.tabs.create({ url: "github.com/OG-RandomTechChannel/BestSEQTA" }); + } + else if (request.type == "setDefaultStorage") { + console.log('setting default values') + SetStorageValue(DefaultValues); + } + else if (request.type == "addPermissions") { + if (typeof (chrome.declarativeContent) != 'undefined') { + chrome.declarativeContent.onPageChanged.removeRules(undefined, function () { + }); + } + chrome.permissions.request({ permissions: ["declarativeContent"], origins: ["*://*/*"] }, function (granted) { + if (granted) { + rules = [ + { + conditions: [ + new chrome.declarativeContent.PageStateMatcher({ + pageUrl: { urlContains: 'site.seqta.com.au', schemes: ['https'] }, + }) + ], + actions: [new chrome.declarativeContent.RequestContentScript({ js: ["SEQTA.js"] })] + }, + { + conditions: [ + new chrome.declarativeContent.PageStateMatcher({ + pageUrl: { urlContains: 'learn.', schemes: ['https'] }, + }) + ], + actions: [new chrome.declarativeContent.RequestContentScript({ js: ["SEQTA.js"] })] + }, + + ] + for (let i = 0; i < rules.length; i++) { + chrome.declarativeContent.onPageChanged.addRules([rules[i]]); + } + alert("Permissions granted. Reload SEQTA pages to see changes. If this workaround doesn't work, please contact the developer."); + + } + }); + } + + +}); + +var NewsJSON = {}; + + + +chrome.runtime.onMessage.addListener( + function (request, sender, sendResponse) { + if (request.type === "sendNews") { + + // 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(); + + var from = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + (date.getDate() - 1); + console.log(TodayFormatted) + console.log(from) + + // var url = `https://newsapi.org/v2/everything?sources=abc-news&from=${TodayFormatted}&sortBy=popularity&apiKey=17c0da766ba347c89d094449504e3080`; + var url = `https://newsapi.org/v2/everything?domains=abc.net.au&from=${from}&apiKey=17c0da766ba347c89d094449504e3080` + + function GetNews() { + fetch(url) + .then((result) => result.json()) + .then((response) => { + if (response.code == 'rateLimited') { + url += '%00'; + GetNews(); + } + else { + sendResponse({ news: response }) + } + }) + } + + GetNews(); + + + + return true; + } + } +); + +const DefaultValues = { + onoff: true, + animatedbk: true, + lessonalert: true, + notificationcollector: true, + defaultmenuorder: [], + menuitems: {}, + menuorder: [], + subjectfilters: {}, + selectedColor: '#1a1a1a', + DarkMode: true, + shortcuts: [ + { + name: "YouTube", + enabled: false + }, + { + name: "Outlook", + enabled: true + }, + { + name: "Office", + enabled: true + }, + { + name: "Spotify", + enabled: false + }, + { + name: "Google", + enabled: true + }, + { + name: "DuckDuckGo", + enabled: false + }, + { + name: "Cool Math Games", + enabled: false + }, + { + name: "SACE", + enabled: false + }, + { + name: "Google Scholar", + enabled: false + }, + { + name: "Gmail", + enabled: false + }, + { + name: "Netflix", + enabled: false + }, + { + Name: "educationperfect", + enabled: false + } + ], + customshortcuts: [] +} + +function SetStorageValue(object) { + for (var i in object) { + chrome.storage.local.set({ [i]: object[i] }) + } + +} + +function UpdateCurrentValues(details) { + console.log(details) + + chrome.storage.local.get(null, function (items) { + var CurrentValues = items; + + const NewValue = Object.assign({}, DefaultValues, CurrentValues) + + function CheckInnerElement(element) { + for (let i in element) { + if (typeof element[i] === 'object') { + if (typeof DefaultValues[i].length == 'undefined') { + NewValue[i] = Object.assign({}, DefaultValues[i], CurrentValues[i]) + } + else { // If the object is an array, turn it back after + length = DefaultValues[i].length; + NewValue[i] = Object.assign({}, DefaultValues[i], CurrentValues[i]) + NewArray = []; + for (let j = 0; j < length; j++) { + NewArray.push(NewValue[i][j]); + + } + NewValue[i] = NewArray; + + } + + } + } + } + CheckInnerElement(DefaultValues); + + if (items["customshortcuts"]) { + NewValue["customshortcuts"] = items["customshortcuts"]; + } + + SetStorageValue(NewValue); + }) +} + +chrome.runtime.onInstalled.addListener(function (event) { + chrome.storage.local.remove(["justupdated"]); + UpdateCurrentValues(); + if (/*chrome.runtime.getManifest().version > event.previousVersion || */ event.reason == 'install') { + chrome.storage.local.set({ justupdated: true }); + } +}); + + diff --git a/src/icons/betterseqta-dark-full.png b/src/icons/betterseqta-dark-full.png new file mode 100644 index 00000000..8f64af72 Binary files /dev/null and b/src/icons/betterseqta-dark-full.png differ diff --git a/src/icons/betterseqta-dark-icon.png b/src/icons/betterseqta-dark-icon.png new file mode 100644 index 00000000..fe411c65 Binary files /dev/null and b/src/icons/betterseqta-dark-icon.png differ diff --git a/src/icons/betterseqta-light-full.png b/src/icons/betterseqta-light-full.png new file mode 100644 index 00000000..d57783cb Binary files /dev/null and b/src/icons/betterseqta-light-full.png differ diff --git a/src/icons/betterseqta-light-icon.png b/src/icons/betterseqta-light-icon.png new file mode 100644 index 00000000..e6ea7f8a Binary files /dev/null and b/src/icons/betterseqta-light-icon.png differ diff --git a/src/icons/betterseqta-light-outline.png b/src/icons/betterseqta-light-outline.png new file mode 100644 index 00000000..a5a48125 Binary files /dev/null and b/src/icons/betterseqta-light-outline.png differ diff --git a/src/icons/icon-32.png b/src/icons/icon-32.png new file mode 100644 index 00000000..39badb19 Binary files /dev/null and b/src/icons/icon-32.png differ diff --git a/src/icons/icon-48.png b/src/icons/icon-48.png new file mode 100644 index 00000000..118431bd Binary files /dev/null and b/src/icons/icon-48.png differ diff --git a/src/icons/icon-64.png b/src/icons/icon-64.png new file mode 100644 index 00000000..0e8763a6 Binary files /dev/null and b/src/icons/icon-64.png differ diff --git a/src/inject/documentload.css b/src/inject/documentload.css new file mode 100644 index 00000000..3efd9d8c --- /dev/null +++ b/src/inject/documentload.css @@ -0,0 +1,18 @@ +/* // This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . */ + +html { + background: #161616 !important; + background-color: #161616; + font-family: Rubik, Roboto !important; +} diff --git a/src/inject/iframe.css b/src/inject/iframe.css new file mode 100644 index 00000000..0483e5b2 --- /dev/null +++ b/src/inject/iframe.css @@ -0,0 +1,33 @@ +/* // This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . */ + +html, p, div, span { + color: white !important; + text-shadow: 1px 1px 2px #161616, 0 0 1em #161616; +} + +blockquote.forward > .preamble { + color: rgba(255, 255, 255, 0.7) !important; +} + +blockquote.forward > .preamble > .date > .value, +blockquote.forward > .preamble > .sender > .value { + color: rgba(255, 255, 255, 0.7) !important; +} +blockquote.forward > .preamble > .date > .label, +blockquote.forward > .preamble > .sender > .label { + color: rgba(255, 255, 255, 0.7) !important; +} +table th { + background-color: #161616; +} \ No newline at end of file diff --git a/src/inject/injected.css b/src/inject/injected.css new file mode 100644 index 00000000..c94bd2b9 --- /dev/null +++ b/src/inject/injected.css @@ -0,0 +1,2354 @@ +/* // This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . */ +@import url('https://fonts.googleapis.com/css?family=Rubik:300,400,500,600'); + +:root { + background-color: var(--better-main) !important; + background: var(--better-main) !important; + --navy: #1a1a1a !important; +} + +body, +html { + font-family: Rubik, sans-serif !important; +} + +#container { + transition: 200ms; +} + +* { + font-family: Rubik, sans-serif !important; + --theme-fg-parts: white; +} + +#title { + color: var(--text-primary); + font-weight: 500 !important; +} + +.connectedNotificationsWrapper>div>button>svg>g { + fill: var(--background-primary) !important; +} + +#main { + color: var(--text-primary); +} + +.forums { + color: var(--text-color); +} + +.defaultWelcome { + background: var(--better-main); +} + +.addedButton { + position: absolute !important; + right: 105px; + top: 31px; + padding: 6px !important; + overflow: unset !important; + border-radius: 10px !important; + cursor: pointer; + + background: var(--text-primary) !important; + border-radius: 10px; + color: var(--background-primary) !important; + height: 35px; + justify-content: center; + width: 35px !important; +} + +#main>.dashboard { + background: unset; +} + +#main>.dashboard>.dashlet { + background: var(--background-primary); +} + +.dashlet-notes>ul { + background: var(--background-primary); +} + +.dashlet-notes>ul>li { + color: var(--text-primary); +} + +ul.magicDelete>li:hover { + background: var(--better-sub); +} + +.dashlet-notes>.editor { + background: unset; +} + +ul.magicDelete>li.deleting { + background: unset; +} + +.addedButton svg { + margin: 6px; + fill: var(--background-primary); +} + +#menu, +.sub, +.nav { + background: var(--better-main) !important; + color: var(--text-color) !important; +} + +.tooltip { + z-index: 5 !important; +} + +#menu li, +#menu section { + margin: 3px 20px; + border-bottom: none; + box-shadow: none; + border-radius: 12px; + padding: 12px; + color: var(--text-color); + display: flex; + white-space: nowrap; +} + +#menu section>label { + align-items: center; + box-sizing: border-box; + cursor: inherit; + display: flex; + flex: 1; + font-weight: 700; + padding: 0; + white-space: nowrap; +} + +#menu { + width: 270px; + background: var(--better-main); + border-right: none; + font-family: Rubik, sans-serif !important; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + z-index: 10; +} + +#menu li>label>svg, +#menu section>label>svg { + margin: 0 10px 0 4px; + width: 28px !important; + height: 28px !important; +} + +#menu li.active>.sub>ul>.item { + box-shadow: inset 3px 0 var(--item-colour, transparent); + border-radius: 0px 15px 15px 0px; + transition: 100ms; +} + +#menu li.active>.sub>ul>.item:hover { + box-shadow: inset 6px 0 var(--item-colour, transparent); + transition: 100ms; +} + +#menu li.active>.sub>ul>.active { + box-shadow: inset 6px 0 var(--item-colour, transparent); + transition: 100ms; + background: rgba(0, 0, 0, 0.3); +} + +#menu li>label, +#menu section>label { + text-transform: none; + font-size: 16px; +} + +#userActions { + display: none; +} + +html { + background-color: var(--better-main) !important; +} + +.student #menu>ul::before { + background-image: var(--betterseqta-logo); +} + +#menu li:hover { + background: rgba(0, 0, 0, 0.15); +} + +#main>.timetablepage>.container { + background-color: var(--background-primary); +} + +#content { + transition: 0.4s; + left: 270px; + background: unset; +} + +@media (max-width: 900px) { + #menuToggle { + visibility: visible; + } + + #menu { + -webkit-transform: translatex(-270px); + transform: translatex(-270px); + } + + .menuShown #menu { + -webkit-transform: translatex(0); + transform: translatex(0); + } + + #content { + left: 0; + } + + .menuShown #content { + -webkit-transform: translatex(270px); + transform: translatex(270px); + } +} + +/* #menu:hover { + width: 300px; + transition: 1s; +} */ +/* #menu:hover ~ #content { + left: 300px; + transition: 1s; +} */ +.welcome>.portalPageView>.powerPortalPage>.Body__body___3pGxr>.Container__container___33GlY>.Document__document___1KJCG>.Canvas__canvas___OBdCZ { + background-color: unset !important; + background-image: unset !important; + background-size: unset; + position: absolute; + top: 0; + width: 100%; + height: 100vh; + background-repeat: no-repeat; + background-position: center; + background-position: 10% 10%; + color: var(--text-primary) !important; +} + +.Module__wrapper___2sbOo { + background: var(--background-primary) !important; + color: var(--text-primary) !important; +} + +.composer>.Body__body___3pGxr>.Container__container___33GlY>.Document__document___1KJCG>.Canvas__canvas___OBdCZ { + background-color: unset !important; + background-image: unset !important; + background: var(--background-secondary) !important; + color: white !important; +} + +#main>.notices>.notice>.label, +#main>.notices>.notice>.staff, +#main>.notices>.notice>h2 { + color: var(--text-primary); + color: var(--colour); +} + +#main>.course>.content>.homework>.content, +#main>.course>.content>.resources>.content { + color: var(--text-primary); + opacity: 0.8; +} + +#main>.notices>.notice>.contents { + background: var(--background-primary); +} + +#main>.notices>.notice { + --colour: unset; +} + +#title { + background: var(--background-primary); + height: 80px; + box-shadow: rgb(0 0 0 / 35%) 0px 5px 15px; + min-height: 48px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + z-index: 1; +} + +.bg { + animation: slide 3s ease-in-out infinite alternate; + background-image: linear-gradient(-60deg, + var(--better-main) 50%, + var(--background-secondary) 50%); + bottom: 0; + left: -50%; + opacity: 0.5; + position: fixed; + right: -50%; + top: 0; + z-index: 0 !important; + overflow: hidden; +} + +.bg2 { + animation-direction: alternate-reverse; + animation-duration: 4s; +} + +.bg3 { + animation-duration: 5s; +} + +@keyframes slide { + 0% { + transform: translateX(-25%); + } + + 100% { + transform: translateX(25%); + } +} + +.home-root { + width: 100%; + display: flex; + color: var(--text-primary); + font-size: unset; +} + +.home-subtitle { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + color: var(--text-color); +} + +.timetable-arrows { + padding: 5px; +} + +.timetable-arrows svg { + margin: 0 5px; + cursor: pointer; +} + +.timetable-arrows svg:hover { + color: #bebebe; +} + +.notice a { + background: rgba(var(--theme-bg-parts), 0.5) !important; +} + +.home-container { + max-width: 1050px; + margin: 20px auto; + width: 1050px; +} + +.home-container h1 { + text-align: center; + font-weight: 400; + font-size: 3em !important; + font-weight: 300; + margin: 30px auto 0; + background-color: var(--background-primary); + height: 3em; + align-items: center; + justify-content: center; + display: flex; + width: 94%; + -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); +} + +.timetable-container { + width: 94%; + margin: 50px auto; + height: 19em; + background-color: var(--better-main); + display: flex; + flex-direction: column; + -webkit-box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +.day-container { + background-color: var(--background-primary); + transition: 200ms; + width: 100%; + height: 15em; + display: flex; + flex-direction: row; + border-radius: 0px 0px 15px 15px; +} + +.notices-container { + width: 94%; + margin: 50px auto; + max-height: 60em; + background-color: var(--better-main); + display: flex; + flex-direction: column; + -webkit-box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +.notice-container { + background-color: var(--better-main); + width: 100%; + max-height: 55em; + overflow-y: auto; + display: flex; + flex-direction: column; + border-bottom-left-radius: 15px; + border-bottom-right-radius: 15px; +} + +.timetable-container h2 { + margin: 20px; + font-size: 20px; + font-weight: 400; +} + +.notices-container h2 { + margin: 20px; + font-size: 20px; + font-weight: 400; +} + +.notice { + position: relative; + width: 95%; + padding: 20px; + display: flex; + flex-direction: column; + margin: 0px auto 7px; + background: var(--background-primary); + transition: 200ms; + box-shadow: inset 0px 5px 20px 1px rgba(0, 0, 0, 0.3); + padding-bottom: 25px; + color: var(--text-primary); +} + +.dummynotice { + width: 100%; + padding: 20px; + margin: 7px auto; + box-shadow: inset 0px 5px 20px 1px rgba(0, 0, 0, 0.3); + background: var(--background-primary); +} + +.Empty__Empty___2F6rn { + color: var(--text-primary); +} + +.shortcut-container { + border: 2px solid var(--better-main); + width: 94%; + margin: 10px auto 50px; + background-color: var(--better-main); + display: flex; + flex-direction: column; + -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); +} + +.border { + border-radius: 15px; +} + +.shortcut-container h2 { + margin: 20px; + font-size: 20px; + font-weight: 400; +} + +.shortcuts { + background-color: var(--better-main); + width: 100%; + padding-top: 10px; + padding-bottom: 10px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; +} + +.shortcuts a { + text-decoration: none !important; + color: var(--text-primary); + display: flex; + border: unset !important; + background-color: unset !important; + margin: 5px 20px; + padding: 0; + border-radius: 50px; +} + +.shortcut { + height: 4em; + width: 15em; + max-width: 15em; + background: var(--background-primary); + color: var(--text-primary); + display: flex; + border-radius: 5px; + position: relative; +} + +.customshortcut::after { + content: 'User Created Shortcut'; + position: absolute; + top: -4px; + right: -15px; + font-size: 8px; + padding: 2px 5px; + background: var(--better-alert-highlight); + border-radius: 8px; + color: white; +} + +.shortcut:hover { + background: var(--background-secondary); +} + +.shortcut p { + margin: auto 0px auto 5px; + font-size: 20px; + width: 150px; + word-wrap: break-word; + line-height: 20px; +} + +.colourbar { + width: 100%; + height: 3px; + position: absolute; + top: 0; + left: 0; +} + +.notice h3 { + margin: 0; + font-size: 25px; +} + +.notice h5 { + margin: 12px 0px; + font-size: 13px; + font-weight: 200; +} + +.notice h6 { + margin: 0px 0px 40px 0px; + font-weight: 100; + color: #c9c9c9; +} + +.day { + box-shadow: inset 0px 0px 10px 0.1px var(--better-sub); + width: 100%; + display: flex; + flex-direction: column; + box-shadow: inset 0px 6px 0 var(--item-colour, transparent); + transition: 200ms; + position: relative; + height: 15em; + color: var(--text-primary); + font-family: Rubik, sans-serif; +} + +.day-container :first-child { + border-bottom-left-radius: 15px; +} + +.day-container :last-child { + border-bottom-right-radius: 15px; +} + +.clickable { + cursor: pointer; +} + +.day:hover { + background: var(--background); + transition: 200ms; +} + +#main>.notices>.notice>.contents { + background: var(--background); +} + +#main>.notices>.notice { + background: var(--background); +} + +.day h2 { + margin: 0; + padding: 8px; + padding-top: 14px; + font-size: 20px !important; + font-weight: 500; + min-height: 46px; + height: 36%; +} + +.day h3 { + padding: 0px 5px; + padding-left: 8px; + margin: 0; + font-size: 13px !important; + font-weight: 400; + color: #7a7a7a; +} + +.day h4 { + position: absolute; + bottom: 35px; + margin: 0; + padding: 2px; + padding-left: 8px; + font-size: 16px !important; + font-weight: 500; +} + +.day h5 { + margin: 0; + padding: 5px; + padding-left: 8px; + position: absolute; + bottom: 0; + right: 0; + font-size: 10px !important; + font-weight: 500; +} + +.day-empty { + font-size: 30px; + display: flex; + align-items: center; +} + +.day-empty img { + margin: 20px; + height: 50%; +} + +.day-empty p { + margin: 0; +} + +.waitWindow { + background: var(--better-main); +} + +.modaliser { + background-color: var(--better-main); +} + +.alert-container { + height: 35em; + width: 22em; + background-color: var(--better-sub); + position: absolute; + right: 0; + top: 0; + border-radius: 0px 0px 40px 40px; + text-align: center; + display: flex; +} + +.alert-button { + height: 20px; + width: 20px; + padding: 10px; + text-align: center; + margin: 20px auto 0px auto; + cursor: pointer; +} + +.connectedNotificationsWrapper>div>button { + height: 45px; + width: 45px; +} + +.notifications__notifications___3mmLY.notifications__hasItems___gXxzx>button { + background: white; + color: var(--better-sub); +} + +.notifications__notifications___3mmLY>button { + padding: 8px; +} + +.legacy-root button>svg, +.legacy-root a>svg { + height: 25px; + width: 24px; +} + +.notifications__notifications___3mmLY>button>.notifications__bubble___1EkSQ { + background: var(--better-alert-highlight); + width: 25px; + height: 25px; +} + +.legacy-root button::after { + background: white; +} + +.legacy-root button:not([disabled]):focus { + border-color: var(--better-sub); +} + +.notifications__notifications___3mmLY.notifications__shown___1kPoT>button { + background-color: #e6e6e6; + border-bottom-left-radius: 100%; +} + +.notifications__list___rp2L2 { + border: 4px solid var(--background-secondary); + background: var(--background-primary); +} + +.notifications__item___2ErJN { + background: var(--background-primary) !important; + border-left: 4px solid var(--better-main) !important; + margin-bottom: 4px !important; +} + +.notifications__item___2ErJN:hover { + background: var(--background-secondary) !important; +} + +.connectedNotificationsWrapper>div>button+div { + color: var(--text-primary); + top: 80px; + right: 10px; +} + +#menu li.active { + background: #ffffff !important; +} + +#menu li:first-child { + margin-top: 5px; +} + +.notifications__actions___1UX7r { + background: var(--background-secondary); +} + +.notifications__items___2hCdv { + border-bottom: unset; + height: 540px; + display: flex; + flex-direction: column; +} + +.notifications__item___2ErJN>.notifications__dismiss___zveKV { + background: rgba(0, 0, 0, 0.1) !important; + color: var(--text-primary); + margin: auto 0; +} + +#main>.messages { + color: var(--text-primary); +} + +.Viewer__sidebar___1Btu4 { + background: var(--background-secondary); + color: var(--text-primary); +} + +.LabelList__LabelList___2RJFf>li.LabelList__selected___3Egk7 { + color: var(--text-primary); +} + +.Viewer__sidebar___1Btu4>header { + background: unset; +} + +.MessageList__MessageList___3DxoC { + background: var(--background-primary); +} + +.Input__Input___3RSTI>input { + color: var(--text-primary); + background: var(--better-main); +} + +.Avatar__Avatar___gE5kx.Avatar__staff___4gVLs { + --person-colour: var(--better-light); +} + +.LabelList__LabelList___2RJFf>li.LabelList__selected___3Egk7 { + background: var(--background-primary); +} + +.Viewer__Viewer___32BH- { + background: var(--better-main); +} + +.Message__Message___3oJaU { + background: var(--background-primary); +} + +iframe.userHTML { + color: white !important; + background: var(--background-primary); +} + +.userHTML>div:first-of-type { + color: var(--text-primary); +} + +#main>.reports>.item>.report { + background: var(--background-primary); + filter: brightness(0.90); +} + +#main>.reports { + background: var(--background-secondary); +} + +#main>.reports>.item>.report>.year { + background: var(--better-light); + color: var(--text-color); +} + +#main>.reports>.item>.report>.term { + color: var(--text-color); + background: var(--better-main); +} + +.Collapsible__Collapsible___3O8P3>.Collapsible__header___-Afvq { + background: var(--background-secondary); +} + +.AssessmentList__AssessmentList___1GdCl>.AssessmentList__searchFilter___3N70o+.AssessmentList__items___3LcmQ { + color: var(--text-primary); +} + +.Thermoscore__Thermoscore___2tWMi { + background-image: unset; + background-color: var(--background-secondary); +} + +#toolbar { + color: var(--text-primary); + background: unset; +} + +.programmeNavigator>.navigator, +.programmeNavigator>.navigator>li>ul { + background: var(--background-primary); + color: var(--text-primary); +} + +.programmeNavigator>.navigator>.week>.lessons>.lesson:hover { + background: var(--background-secondary); +} + +.programmeNavigator>.navigator>.search { + background: var(--better-light); +} + +.programmeNavigator>.navigator>.week>.lessons>.lesson.selected, +.programmeNavigator>.navigator>.cover.selected { + background: var(--better-light); + color: var(--text-color) !important; +} + +#main>.course>.content>h1 { + color: var(--text-primary); +} + +#main>.course>.content>.outline>h2, +#main>.course>.content>.homework>h2, +#main>.course>.content>.resources>h2 { + color: var(--text-primary); +} + +::-webkit-scrollbar { + width: 10px; + height: 10px; + transition: 1.0s; +} + +::-webkit-scrollbar-thumb { + background-color: var(--better-light); + background-clip: padding-box; + border: 2px solid transparent; + transition: 1.0s; +} + +::-webkit-scrollbar-thumb:vertical:hover, +::-webkit-scrollbar-thumb:horizontal:hover { + background-color: var(--better-light); +} + +::-webkit-scrollbar-track { + background-color: transparent; +} + + + +::-webkit-scrollbar-thumb:vertical:active, +::-webkit-scrollbar-thumb:horizontal:active { + background: var(--better-light); + +} + +::-webkit-scrollbar-corner { + background: none; +} + +:root, +html, +body, +div, +ol, +ul { + scrollbar-width: thin !important; + scrollbar-color: var(--better-light) var(--better-sub) !important; +} + + +.connectedNotificationsWrapper>div>button { + color: var(--text-primary) !important; +} + +.programmeNavigator { + width: 400px; + background: var(--background-primary); +} + +#userActions>.details>.code { + text-transform: initial; +} + +.SelectedAssessment__SelectedAssessment___3Bu5D { + color: var(--text-primary); +} + +.TabSet__TabSet___Vo-SZ>.TabSet__tabContainer___3iIRe { + background: unset; +} + +.BasicPanel__BasicPanel___1GP6s { + background: var(--background-primary); +} + +.legacy-root .uiFileHandler { + background: var(--background-secondary); + margin: 8px 0px 0px 0px; + -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); +} + +.dailycal>.header { + color: var(--text-primary); +} + +#main>.timetablepage>.container>.dailycal { + color: var(--text-primary); +} + +#main>.timetablepage>.note { + color: var(--text-primary); +} + +.uiFileHandlerPanel { + background: var(--better-main); + color: var(--text-primary); +} + +.Rubric__Rubric___2AAKS>.Rubric__line___JCC3Y { + background: unset; +} + +#main>.course>.content>.header>.coverImage.blurred { + display: none; + background-image: unset !important; + height: 0px; + width: 0px; +} + +.coverImage, +blurred { + display: none; +} + +.icon-cover { + position: absolute; + top: 0; + left: 0; + width: 70%; + height: 64px; + cursor: pointer; +} + +.uiSlidePane>.pane>.header { + color: var(--text-color); + background-color: var(--better-main); +} + +.activelesson { + box-shadow: inset 0px 10px 0 var(--item-colour, transparent) !important; +} + +.formattedText>.wrapper>.cke>.cke_inner>.cke_contents { + background: var(--background-primary); +} + +.formattedText>.footer { + background-color: var(--background-primary); +} + +.uiSlidePane>.pane { + background-color: var(--background-secondary); + color: var(--text-primary); +} + +.anyoneSelect.filterBox { + background: var(--background-secondary); +} + +.cke_toolbox { + background: unset !important; +} + +#cke_1_top a:hover { + background: #5a5a5a; +} + +.legacy-root button.depressed, +.legacy-root button.toggled { + background: #797979; +} + +.cke_toolbox>.cke_toolbar .cke_combo_on>.cke_combo_button, +.cke_toolbox>.cke_toolbar .cke_button_on { + background-color: #797979 !important; +} + +.legacy-root input.singleSelect:focus { + background: var(--background-secondary); + color: var(--text-primary) !important; +} + +ul.singleSelect, +ul.buttonChecklist, +ul.buttonMenu, +ul.colourButtonOptions, +ul.uiSplitButtonList, +.contactFormPanel { + background: var(--background-primary) !important; + border: solid 4px var(--background-primary); + color: var(--text-primary); +} + +.legacy-root input, +.legacy-root textarea, +.legacy-root select, +.legacy-root option, +.legacy-root .input { + background: var(--background-secondary); + color: var(--text-primary); +} + +body { + background: var(--better-light); + overflow: hidden; +} + +#main>.notices>.notice { + color: var(--text-primary); +} + +.shortcuticondiv { + height: 39px; + width: 39px; + border-radius: 50%; + padding: 0; + margin: auto 0px auto 10px; + background-repeat: no-repeat; + background-size: contain; +} + +.forumView>.messages>.thread, +.forumView>.messages>.deletedPlaceholder, +.forumView>.addMessage, +.forumView .greeting, +.forumView .assessment { + background: var(--better-main); +} + +.dailycal>.content>.wrapper>.days>tbody>tr>td>.entriesWrapper>.entry { + /* border-radius: 15px; */ + padding: 3px; + /* width: 93% !important; */ + /* height: 60px !important; */ +} + +.Viewer__Viewer___32BH- { + background: unset; +} + +.weekend { + display: none !important; +} + +.days { + width: 80% !important; + margin: 0 auto !important; +} + +.hidden { + display: none; +} + +.cke_toolbox { + background: var(--better-main); +} + +.modaliser { + display: none; +} + +.MessageList__MessageList___3DxoC>ol>li.MessageList__unread___3imtO { + box-shadow: inset 3px 0 rgb(255, 255, 255); +} + +.connectedNotificationsWrapper>div>button { + background: var(--text-primary) !important; + border-radius: 10px !important; + color: var(--background-primary) !important; + height: 42px; + justify-content: center; + right: 47px; + top: 28px; + width: 42px; + z-index: 2; +} + +#userActions>.details>.name::before { + content: ""; + width: 14px; + height: 12px; + background-image: url(/icons/betterseqta-light-outline.png); + display: inline-block; + background-size: 18px 18px; + color: #fff; + margin-right: 2px; + background-position: center; + vertical-align: top; +} + +#userActions>.details { + opacity: unset !important; + color: var(--text-color); +} + +.defaultWelcomeWrapper { + background: unset !important; +} + +.clr-swatches button::after, +.clr-dark .clr-preview::after, +.clr-field button::after { + opacity: unset; + padding-top: unset; + -webkit-transform: unset; + transform: unset; + -webkit-transform-origin: unset; + transform-origin: unset; + visibility: unset; + -webkit-animation-name: unset !important; + animation-name: unset !important; + background-color: currentColor !important; +} + +.clr-swatches button { + align-items: unset; + display: block; + padding: unset; + transition: none; +} + +.clr-clear { + display: none !important; +} + +.clr-preview::before, +.clr-preview::after { + visibility: unset; + -webkit-transform-origin: unset; + transform-origin: unset; + -webkit-transform: unset; + transform: unset; + padding-top: unset; + opacity: unset; + +} + +#clr-color-preview { + margin: 15px 0 20px 20px; + border: 0; + border-radius: 50%; + overflow: hidden; + cursor: pointer; +} + +.MessageList__MessageList___3DxoC>ol>li.MessageList__selected___1SJNz { + background: var(--better-main); + color: var(--text-color); +} + +.NewsArticle { + border-radius: 5px !important; + width: 94%; + padding: 0 !important; + margin: 10px auto 50px !important; + background: var(--background-primary) !important; + color: var(--text-primary); + display: flex; + flex-direction: row; + -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); +} + +.articleimage { + width: 35%; + background-position: center; + background-size: cover; + min-height: 18em; + background-repeat: no-repeat; +} + +.NewsArticle img { + width: 35%; +} + +.ArticleText a { + padding: 10px 20px; + margin: 0; + font-weight: 800; + font-size: 2em; + background: none; +} + +.NewsArticle:hover>.ArticleText a { + text-decoration: underline; +} + +.ArticleText p { + padding: 10px 20px; + margin: 0; + font-size: 1.5em; +} + +.ArticleText { + display: flex; + flex-direction: column; + width: 65%; + height: 100%; +} + +.editmenu { + position: absolute; + right: 0; + height: 64px; + align-items: center; + display: flex; + width: 20%; + justify-content: center; +} + +.editmenu svg:hover>path { + fill: #aaaaaa; +} + +.editmenu svg:hover { + cursor: pointer; +} + +.notMenuCover { + width: 100%; + height: 100%; + background: black; + position: absolute; + z-index: 19; + opacity: 0.4; +} + +#menu { + --menuHidden: none; +} + +.editmenuoption { + padding: 8px; + background: var(--better-light); + border-radius: 5px; + margin: 0 10px; + cursor: pointer; +} + +.editmenuoption-container { + width: 100%; + height: 42px; + background: var(--background-primary); + bottom: 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.logout { + background: none !important; + padding: 5px 10px; +} + +#logouttooltip { + width: 50px !important; + margin-left: -28px !important; + top: 105% !important; +} + +.svg { + transform-origin: center; + position: absolute; + top: 50%; + left: 50%; +} + +.logo { + transform: translate(-50%, -50%); +} + +.big-circle { + margin: -88px; + animation-timing-function: ease; + animation: spin 3s linear infinite; + -moz-animation: spin 3s linear infinite; +} + +.small-circle { + margin: -66px; + animation-timing-function: ease; + animation: spin 3s linear infinite; + -moz-animation: spin 3s linear infinite; +} + +.outer-circle { + margin: -108px; + animation-direction: alternate-reverse; + animation: spinback 1s linear infinite; + -moz-animation: spinback 1s linear infinite; +} + +@-moz-keyframes spin { + 100% { + -moz-transform: rotate(360deg); + } +} + +@-webkit-keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + } +} + +@keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinback { + 100% { + -webkit-transform: rotate(-360deg); + transform: rotate(-360deg); + } +} + +.day-button { + height: 25px; + width: 25px; + position: absolute; + bottom: 20px; +} + +#userActions>.details>.code { + overflow: visible !important; +} + +.code { + position: relative; + cursor: pointer; +} + +.code:before { + content: attr(data-hover); + visibility: hidden; + opacity: 0; + width: 160px; + background-color: #1a1a1a; + color: var(--text-primary); + text-align: center; + border-radius: 5px; + padding: 5px 0; + transition: opacity 0.4 ease-in-out; + position: absolute; + z-index: 20; + left: 0; + top: -25px; +} + +.code:hover:before { + opacity: 1; + visibility: visible; +} + +#menu { + color: var(--text-color); +} + +#menuToggle { + color: var(--text-primary); + top: 23px !important; + z-index: 2; +} + +.day-empty { + font-size: 30px; + display: flex; + align-items: center; +} + +.day-empty img { + margin: 20px; + height: 50%; +} + +.day-empty p { + margin: 0; +} + +.notifications__actions___1UX7r>button { + background: none !important; + border: 1px solid white; +} + +.upcoming-submittedtext { + align-self: center; + padding: 8px 25px; + background: var(--item-colour); + color: white; + border-radius: 30px; +} + +.upcoming-container { + width: 94%; + margin: 50px auto; + max-height: 60em; + background-color: var(--better-main); + display: flex; + flex-direction: column; + -webkit-box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); + box-shadow: 0px 5px 16px 6px rgba(0, 0, 0, 0.3); +} + +.upcoming-items { + background-color: var(--better-sub); + width: 100%; + max-height: 55em; + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.upcoming-container h2 { + margin: 20px; + font-size: 20px; + font-weight: 400; +} + +.upcoming-subject-title { + color: var(--text-primary); + width: 15%; + font-size: 20px; + text-align: center; + padding: 5px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 5px 0px 0px 5px; + background: var(--item-colour); +} + +.upcoming-assessment-title { + color: var(--text-primary); + font-size: 10px; +} + +.upcoming-assessment { + border: 2px solid var(--item-colour); + margin: 5px 50px; + height: 6em; + padding: 0px; + border-radius: 10px; +} + +.upcoming-assessment { + display: flex; +} + +.upcoming-date-container { + margin-bottom: 20px; +} + +.upcoming-date-title { + padding: 12px; + font-size: 20px; +} + +.upcoming-details { + width: 60%; + display: flex; + flex-direction: column; + justify-content: center; + padding: 0px 12px; +} + +.upcoming-details h5 { + text-transform: uppercase; + color: #aaaaaa; + padding: 0px 4px; +} + +.upcoming-details p { + font-size: 15px; + padding: 4px; +} + +.upcoming-details p:hover { + cursor: pointer; + text-decoration: underline; +} + +.upcoming-special-day { + font-size: 20px +} + +.upcoming-blank { + display: flex; + border-bottom: 2px solid #bebebe; + margin: 5px 50px; + height: 2em; + padding: 0px; +} + +.upcoming-blank p { + padding: 0; + margin: 0; +} + +.upcoming-tick { + align-self: center; +} + +.upcoming-title { + display: flex; + align-content: space-between; +} + +.upcoming-title h2 { + width: 25%; +} + +.upcoming-filters { + display: flex; + height: 26px; + width: 65%; + align-self: center; + align-items: center; + color: var(--text-color); + padding: 5px; + overflow-x: scroll; + overflow-y: hidden; +} + + +.upcoming-checkbox-container { + display: block; + position: relative; + padding: none !important; + padding-left: 25px !important; + padding-right: 10px !important; + cursor: pointer; + font-size: 12px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + height: 20px; + align-items: center; + display: flex; + + +} + +/* Hide the browser's default checkbox */ +.upcoming-checkbox-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; + padding: 0; +} + +/* Create a custom checkbox */ +.upcoming-checkmark { + position: absolute; + top: 0; + left: 0; + height: 15px; + width: 15px; + border: 3px solid var(--item-colour); + border-radius: 5px; + color: var(--text-color); +} + +/* On mouse-over, add a grey background color */ +.upcoming-checkbox-container:hover input~.upcoming-checkmark { + filter: brightness(0.8); +} + +/* When the checkbox is checked, add a blue background */ +.upcoming-checkbox-container input:checked~.upcoming-checkmark { + background-color: var(--item-colour); +} + +/* Create the checkmark/indicator (hidden when not checked) */ +.upcoming-checkmark:after { + content: ""; + position: absolute; + display: none; +} + +/* Show the checkmark when checked */ +.upcoming-checkbox-container input:checked~.upcoming-checkmark:after { + display: block; +} + +/* Style the checkmark/indicator */ +.upcoming-checkbox-container .upcoming-checkmark:after { + left: 3.5px; + top: 0px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.upcoming-hiddenassessment { + color: #797979; +} + +.calendarEventEditor>.tabset>.item { + border-radius: 0 !important; +} + +.MessageList__MessageList___3DxoC>header { + display: flex; + justify-content: space-between; +} + +.Input__Input___3RSTI { + width: 100%; +} + +.messages-filterbutton { + height: 34px; + width: 25%; + background: var(--better-main); + border-radius: 5px; + display: none; + justify-content: center; + align-items: center; + color: var(--text-color); + cursor: pointer; +} + + + +.day { + box-shadow: inset 0px 0px 10px 0.1px var(--better-sub); + width: 100%; + display: flex; + flex-direction: column; + box-shadow: inset 0px 6px 0 var(--item-colour, transparent); + transition: 200ms; + position: relative; + height: 15em; + color: var(--text-primary); + background: var(--background-primary); + font-family: Rubik, sans-serif; +} + +.day-container :first-child { + border-bottom-left-radius: 15px; +} + +.day-container :last-child { + border-bottom-right-radius: 15px; +} + +.clickable { + cursor: pointer; +} + +.day:hover { + background: var(--background-secondary); + transition: 200ms; +} + +#main>.notices>.notice>.contents { + background: var(--background-primary); +} + +#main>.notices>.notice { + background: var(--background-primary); +} + +.day h2 { + margin: 0; + padding: 8px; + padding-top: 14px; + font-size: 20px !important; + font-weight: 400; + min-height: 46px; + height: 33%; + overflow: hidden; + display: -webkit-box !important; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; +} + +.day h3 { + padding: 0px 5px; + padding-left: 8px; + margin: 0; + font-size: 13px !important; + font-weight: 400; + color: #7a7a7a; +} + +.day h4 { + position: absolute; + bottom: 45px; + margin: 0; + padding: 2px; + padding-left: 8px; + font-size: 16px !important; + font-weight: 500; +} + +.day h5 { + margin: 0; + padding: 5px; + padding-left: 8px; + position: absolute; + bottom: 0; + right: 0; + font-size: 10px !important; + font-weight: 500; +} + +.day-empty { + font-size: 30px; + display: flex; + align-items: center; +} + +.day-empty img { + margin: 20px; + height: 50%; +} + +.day-empty p { + margin: 0; +} + +.upcoming-container { + width: 94%; + margin: 50px auto; + max-height: 60em; + background-color: var(--better-main); + display: flex; + flex-direction: column; + -webkit-box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +.upcoming-items { + background-color: var(--background-primary); + transition: 200ms; + width: 100%; + max-height: 55em; + overflow-y: auto; + display: flex; + flex-direction: column; + color: var(--text-primary); + transition: 200ms; + border-bottom-left-radius: 15px; + border-bottom-right-radius: 15px; +} + +.upcoming-container h2 { + margin: 20px; + font-size: 20px; + font-weight: 400; +} + +.upcoming-assessment-title { + color: var(--text-primary); + transition: 200ms; + font-size: 10px; + margin: 0; +} + +.upcoming-assessment { + border: 3px solid var(--item-colour); + margin: 5px 50px; + height: 6em; + padding: 0px; + border-radius: 10px; +} + +.upcoming-assessment { + display: flex; +} + +.upcoming-date-container { + margin-bottom: 20px; +} + +.upcoming-date-title h5 { + margin: 0; + font-weight: 500; +} + +.upcoming-date-title { + padding: 12px; + font-size: 20px; +} + +.upcoming-details { + width: 60%; + display: flex; + flex-direction: column; + justify-content: center; + padding: 0px 12px; +} + +.upcoming-details h5 { + text-transform: uppercase; + color: #aaaaaa; + padding: 0px 4px; + margin: 0; +} + +.upcoming-details p { + font-size: 15px; + padding: 4px; +} + +.upcoming-details p:hover { + cursor: pointer; + text-decoration: underline; +} + +.upcoming-special-day { + font-size: 20px +} + +.upcoming-blank { + display: flex; + border-bottom: 2px solid #bebebe; + margin: 5px 50px; + height: 2em; + padding: 0px; +} + +.upcoming-blank p { + padding: 0; + margin: 0; +} + +.upcoming-title { + display: flex; + align-content: space-between; +} + +.upcoming-title h2 { + width: 25%; +} + +.upcoming-filters { + display: flex; + height: 26px; + width: 65%; + align-self: center; + align-items: center; + color: var(--text-color); + padding: 5px; + overflow-x: scroll; + overflow-y: hidden; +} + + +.upcoming-checkbox-container { + display: block; + position: relative; + padding: none !important; + padding-left: 25px !important; + padding-right: 10px !important; + cursor: pointer; + font-size: 12px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + height: 20px; + align-items: center; + display: flex; + + +} + +/* Hide the browser's default checkbox */ +.upcoming-checkbox-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; + padding: 0; +} + +/* Create a custom checkbox */ +.upcoming-checkmark { + position: absolute; + top: 0; + left: 0; + height: 15px; + width: 15px; + border: 3px solid var(--item-colour); + border-radius: 5px; + color: var(--text-color); +} + +/* On mouse-over, add a grey background color */ +.upcoming-checkbox-container:hover input~.upcoming-checkmark { + filter: brightness(0.8); +} + +/* When the checkbox is checked, add a blue background */ +.upcoming-checkbox-container input:checked~.upcoming-checkmark { + background-color: var(--item-colour); +} + +/* Create the checkmark/indicator (hidden when not checked) */ +.upcoming-checkmark:after { + content: ""; + position: absolute; + display: none; +} + +/* Show the checkmark when checked */ +.upcoming-checkbox-container input:checked~.upcoming-checkmark:after { + display: block; +} + +/* Style the checkmark/indicator */ +.upcoming-checkbox-container .upcoming-checkmark:after { + left: 3.5px; + top: 0px; + width: 5px; + height: 10px; + border: solid white; + border-width: 0 3px 3px 0; + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} + +.upcoming-hiddenassessment { + color: #797979; +} + +.titlebar { + align-items: center; + transition: 200ms; + color: var(--text-primary); + display: flex; + min-height: 32px; + height: 100px; + justify-content: space-between; + z-index: 10; + position: absolute; + right: 250px; +} + +.pagename { + align-items: center; + display: flex; + font-size: 20px; +} + +.pagename svg { + width: 50px; + height: 50px; + margin-left: 12px; + margin-right: 8px; +} + +.shadow { + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +.userInfo { + display: flex; + align-items: center; +} + +.userInfoText { + text-align: end; +} + +.userInfoName { + margin: 0 !important; + font-size: 20px; + font-weight: 500; +} + +.userInfoCode { + margin: 0 !important; +} + +.userInfosvg { + width: 50px; + height: 50px; + color: var(--better-main); + z-index: 3; + position: absolute; +} + +.userInfosvgdiv { + width: 50px !important; + height: 50px !important; + color: var(--better-main); + margin: 10px; + z-index: 3; + position: absolute !important; + right: -70px !important; + top: 14px !important; +} + +.userInfosvg::after { + width: 35px; + height: 35px; + background: antiquewhite; + position: absolute; +} + +.userInfohouse { + padding: 0px 10px; + font-size: 15px; + margin: 0 8px !important; + border-radius: 5px; + color: var(--text-primary); + background: var(--background-secondary); + outline: solid 1px black; +} + +.tooltip svg { + fill: var(--background-primary); +} + +.tooltip { + display: inline-block; + width: 28px; + background: none; + box-shadow: none; + padding: 2px; + position: absolute; +} + +.tooltip .tooltiptext { + width: 120px; + transform: scale(0); + transition: transform 0.2s; + transform-origin: top; + background-color: var(--background-primary); + color: var(--text-primary); + text-align: center; + border-radius: 6px; + padding: 2px; + position: absolute; + z-index: 1; + top: 105%; + left: 50%; + margin-left: -62px; +} + +.tooltip .tooltiptext::after { + content: ""; + position: absolute; + bottom: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent var(--text-primary) transparent; +} + +.tooltiptext p:hover { + cursor: pointer; + background: rgba(0, 0, 0, 0.3) !important; + transition: 200ms; +} + +.tooltiptext p { + border-radius: 8px !important; + padding-top: 2px; + padding-bottom: 2px; + margin: 2px; +} + +.tooltip:hover .tooltiptext { + transform: scale(1); + transform-origin: top; + transition: transform 0.2s; +} + +.assessmenttooltip svg { + fill: var(--text-primary); +} + +.assessmenttooltip { + bottom: 0px; + left: 5px; +} + +.DarkLightButton { + right: 145px !important; + fill: var(--text-primary); + height: 35px; + width: 35px; + top: 31px; +} + +.topmenutooltip { + top: 115% !important; + background: var(--text-primary) !important; + color: var(--background-primary) !important; +} + +.whatsnewContainer { + position: absolute; + width: 38em; + height: 95%; + max-height: 60em; + background: var(--better-sub); + z-index: 50; + left: 50%; + top: 50%; + transform: translate(-50%, -50%) scale(0.8); + border-radius: 20px; + display: flex; + flex-direction: column; + color: white; + animation: zoomin 0.5s; + animation-fill-mode: forwards; + transform-origin: center center; + +} + +@keyframes zoomin { + 75% { + transform: translate(-50%, -50%) scale(1.05); + } + + 100% { + transform: translate(-50%, -50%) scale(1); + } +} + +@keyframes zoomout { + 0% { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } + + 100% { + opacity: 0; + transform: translate(-50%, -50%) scale(0.8); + } +} + +.whatsnewHeader { + margin: 20px; + width: 100%; + height: 3em; + display: flex; + flex-direction: column; +} + +.whatsnewHeader h1 { + font-size: 2em; +} + +.whatsnewHeader p { + font-size: 1em; + color: #c9c9c9; +} + +.whatsnewBackground { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 49; + opacity: 0; + animation: fadein 0.2s; + animation-fill-mode: forwards; +} + +@keyframes fadein { + 100% { + opacity: 1; + } +} + +@keyframes fadeout { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.whatsnewImgContainer { + width: 96%; + display: flex; + padding: 2em 0; + margin: 0 auto; + background: #141414; + border-radius: 10px; + margin-bottom: 20px; +} + +.whatsnewImg { + margin: 0 auto; + width: 30%; +} + +.whatsnewTextContainer { + display: flex; + flex-direction: column; + width: 90%; + margin: 5px auto; +} + +.whatsnewTextContainer li { + margin: 2px 0; + list-style-type: disc; + list-style-position: inside; + text-indent: -1em; + padding-left: 1em; +} + +.whatsnewTextHeader { + font-size: 1.4em !important; + color: #4dd868; + font-weight: 600; + width: fit-content; + position: relative; +} + +.whatsnewTextHeader::after { + content: ''; + width: 160%; + height: 2px; + background: #4dd868; + margin-left: 10px; + position: absolute; + top: 50%; +} + +.whatsnewFooter { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 3em; + border-radius: 0 0px 20px 20px; + background: #0e0e0e; + display: flex; + justify-content: space-between; + align-items: center; +} + +.whatsnewFooter div { + margin: 0 15px; + display: flex; + align-items: center; +} + +#whatsnewclosebutton { + position: absolute; + top: 10px; + right: 20px; + font-size: 2em; + padding: 5px; + cursor: pointer; +} + +.whatsnewfadeout { + animation: fadeout 0.6s; +} + +.whatsnewzoomout { + animation: zoomout 0.7s; +} \ No newline at end of file diff --git a/src/inject/preview/customshortcut.png b/src/inject/preview/customshortcut.png new file mode 100644 index 00000000..5ce45243 Binary files /dev/null and b/src/inject/preview/customshortcut.png differ diff --git a/src/inject/preview/lightdarkmode.png b/src/inject/preview/lightdarkmode.png new file mode 100644 index 00000000..55542406 Binary files /dev/null and b/src/inject/preview/lightdarkmode.png differ diff --git a/src/manifest.json b/src/manifest.json new file mode 100644 index 00000000..8050b45a --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,49 @@ +{ + "manifest_version": 2, + "name": "BestSEQTA", + "version": "3.0.2", + "description": "Making SEQTA Learn better.", + "icons": { + "48": "icons/icon-48.png" + }, + "browser_action": { + "browser_style": true, + "default_popup": "popup/info.html", + "default_icon": { + "32": "icons/icon-32.png", + "64": "icons/icon-64.png" + } + }, + "permissions": [ + "tabs", + "notifications", + "storage", + "https://newsapi.org/" + ], + "background": { + "scripts": [ + "background.js" + ] + }, + "optional_permissions": [ + "*://*/*", + "declarativeContent" + ], + "content_scripts": [ + { + "matches": [ + "https://*.edu.au/*" + ], + "js": [ + "SEQTA.js" + ], + "run_at": "document_start" + } + ], + "web_accessible_resources": [ + "icons/*", + "images/*", + "inject/*", + "popup/*" + ] +} \ No newline at end of file diff --git a/src/popup/coloris.css b/src/popup/coloris.css new file mode 100644 index 00000000..018eebb1 --- /dev/null +++ b/src/popup/coloris.css @@ -0,0 +1,504 @@ +.clr-picker { + display: none; + flex-wrap: wrap; + position: absolute; + width: 200px; + z-index: 1000; + border-radius: 10px; + background-color: #fff; + justify-content: space-between; + box-shadow: 0 0 5px rgba(0,0,0,.05), 0 5px 20px rgba(0,0,0,.1); + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +.clr-picker.clr-open { + display: flex; +} + +.clr-gradient { + position: relative; + width: 100%; + height: 100px; + margin-bottom: 15px; + border-radius: 3px 3px 0 0; + background-image: linear-gradient(rgba(0,0,0,0), #000), linear-gradient(90deg, #fff, currentColor); + cursor: pointer; +} + +.clr-marker { + position: absolute; + width: 12px; + height: 12px; + margin: -6px 0 0 -6px; + border: 1px solid #fff; + border-radius: 50%; + background-color: currentColor; + cursor: pointer; +} + +.clr-picker input[type="range"]::-webkit-slider-runnable-track { + width: 100%; + height: 8px; +} + +.clr-picker input[type="range"]::-webkit-slider-thumb { + width: 8px; + height: 8px; + -webkit-appearance: none; +} + +.clr-picker input[type="range"]::-moz-range-track { + width: 100%; + height: 8px; + border: 0; +} + +.clr-picker input[type="range"]::-moz-range-thumb { + width: 8px; + height: 8px; + border: 0; +} + +.clr-hue { + background-image: linear-gradient(to right, #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%); +} + +.clr-hue, +.clr-alpha { + position: relative; + width: calc(100% - 40px); + height: 8px; + margin: 5px 20px; + border-radius: 4px; +} + +.clr-alpha span { + display: block; + height: 100%; + width: 100%; + border-radius: inherit; + background-image: linear-gradient(90deg, rgba(0,0,0,0), currentColor); +} + +.clr-hue input, +.clr-alpha input { + position: absolute; + width: calc(100% + 16px); + height: 16px; + left: -8px; + top: -4px; + margin: 0; + background-color: transparent; + opacity: 0; + cursor: pointer; + appearance: none; + -webkit-appearance: none; +} + +.clr-hue div, +.clr-alpha div { + position: absolute; + width: 16px; + height: 16px; + left: 0; + top: 50%; + margin-left: -8px; + transform: translateY(-50%); + border: 2px solid #fff; + border-radius: 50%; + background-color: currentColor; + box-shadow: 0 0 1px #888; + pointer-events: none; +} + +.clr-alpha div:before { + content: ''; + position: absolute; + height: 100%; + width: 100%; + left: 0; + top: 0; + border-radius: 50%; + background-color: currentColor; +} + +.clr-format { + display: none; + order: 1; + width: calc(100% - 40px); + margin: 0 20px 20px; +} + +.clr-segmented { + display: flex; + position: relative; + width: 100%; + margin: 0; + padding: 0; + border: 1px solid #ddd; + border-radius: 15px; + box-sizing: border-box; + color: #999; + font-size: 12px; +} + +.clr-segmented input, +.clr-segmented legend { + position: absolute; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: 0; + left: 0; + top: 0; + opacity: 0; + pointer-events: none; +} + +.clr-segmented label { + flex-grow: 1; + padding: 4px 0; + text-align: center; + cursor: pointer; +} + +.clr-segmented label:first-of-type { + border-radius: 10px 0 0 10px; +} + +.clr-segmented label:last-of-type { + border-radius: 0 10px 10px 0; +} + +.clr-segmented input:checked + label { + color: #fff; + background-color: #666; +} + +.clr-swatches { + order: 2; + width: calc(100% - 32px); + margin: 0 16px; +} + +.clr-swatches div { + display: flex; + flex-wrap: wrap; + padding-bottom: 12px; + justify-content: center; +} + +.clr-swatches button { + position: relative; + width: 20px; + height: 20px; + margin: 0 4px 6px 4px; + border: 0; + border-radius: 50%; + color: inherit; + text-indent: -1000px; + white-space: nowrap; + overflow: hidden; + cursor: pointer; +} + +.clr-swatches button:after { + content: ''; + display: block; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + border-radius: inherit; + background-color: currentColor; + box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); +} + +input.clr-color { + order: 1; + width: calc(100% - 80px); + height: 32px; + margin: 15px 20px 20px 0; + padding: 0 10px; + border: 1px solid #ddd; + border-radius: 16px; + color: #444; + background-color: #fff; + font-family: sans-serif; + font-size: 14px; + text-align: center; + box-shadow: none; +} + +input.clr-color:focus { + outline: none; + border: 1px solid #1e90ff; +} + +.clr-clear { + display: none; + order: 2; + height: 24px; + margin: 0 20px 20px auto; + padding: 0 20px; + border: 0; + border-radius: 12px; + color: #fff; + background-color: #666; + font-family: inherit; + font-size: 12px; + font-weight: 400; + cursor: pointer; +} + +.clr-preview { + position: relative; + width: 32px; + height: 32px; + margin: 15px 0 20px 20px; + border: 0; + border-radius: 50%; + overflow: hidden; + cursor: pointer; +} + +.clr-preview:before, +.clr-preview:after { + content: ''; + position: absolute; + height: 100%; + width: 100%; + left: 0; + top: 0; + border: 1px solid #fff; + border-radius: 50%; +} + +.clr-preview:after { + border: 0; + background-color: currentColor; + box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); +} + +.clr-marker, +.clr-hue div, +.clr-alpha div, +.clr-color { + box-sizing: border-box; +} + +.clr-field { + display: inline-block; + position: relative; + color: transparent; +} + +.clr-field button { + position: absolute; + width: 30px; + height: 100%; + right: 0; + top: 50%; + transform: translateY(-50%); + border: 0; + color: inherit; + text-indent: -1000px; + white-space: nowrap; + overflow: hidden; + pointer-events: none; +} + +.clr-field button:after { + content: ''; + display: block; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + border-radius: inherit; + background-color: currentColor; + box-shadow: inset 0 0 1px rgba(0,0,0,.5); +} + +.clr-alpha, +.clr-alpha div, +.clr-swatches button, +.clr-preview:before, +.clr-field button { + background-image: repeating-linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa), repeating-linear-gradient(45deg, #aaa 25%, #fff 25%, #fff 75%, #aaa 75%, #aaa); + background-position: 0 0, 4px 4px; + background-size: 8px 8px; +} + +.clr-marker:focus { + outline: none; +} + +.clr-keyboard-nav .clr-marker:focus, +.clr-keyboard-nav .clr-hue input:focus + div, +.clr-keyboard-nav .clr-alpha input:focus + div, +.clr-keyboard-nav .clr-segmented input:focus + label { + outline: none; + box-shadow: 0 0 0 2px #1e90ff, 0 0 2px 2px #fff; +} + +.clr-picker[data-alpha="false"] .clr-alpha { + display: none; +} + +.clr-picker[data-minimal="true"] { + padding-top: 16px; +} + +.clr-picker[data-minimal="true"] .clr-gradient, +.clr-picker[data-minimal="true"] .clr-hue, +.clr-picker[data-minimal="true"] .clr-alpha, +.clr-picker[data-minimal="true"] .clr-color, +.clr-picker[data-minimal="true"] .clr-preview { + display: none; +} + +/** Dark theme **/ + +.clr-dark { + background-color: #444; +} + +.clr-dark .clr-segmented { + border-color: #777; +} + +.clr-dark .clr-swatches button:after { + box-shadow: inset 0 0 0 1px rgba(255,255,255,.3); +} + +.clr-dark input.clr-color { + color: #fff; + border-color: #777; + background-color: #555; +} + +.clr-dark input.clr-color:focus { + border-color: #1e90ff; +} + +.clr-dark .clr-preview:after { + box-shadow: inset 0 0 0 1px rgba(255,255,255,.5); +} + +.clr-dark .clr-alpha, +.clr-dark .clr-alpha div, +.clr-dark .clr-swatches button, +.clr-dark .clr-preview:before { + background-image: repeating-linear-gradient(45deg, #666 25%, transparent 25%, transparent 75%, #888 75%, #888), repeating-linear-gradient(45deg, #888 25%, #444 25%, #444 75%, #888 75%, #888); +} + +/** Polaroid theme **/ + +.clr-picker.clr-polaroid { + border-radius: 6px; + box-shadow: 0 0 5px rgba(0,0,0,.1), 0 5px 30px rgba(0,0,0,.2); +} + +.clr-picker.clr-polaroid:before { + content: ''; + display: block; + position: absolute; + width: 16px; + height: 10px; + left: 20px; + top: -10px; + border: solid transparent; + border-width: 0 8px 10px 8px; + border-bottom-color: currentColor; + box-sizing: border-box; + color: #fff; + filter: drop-shadow(0 -4px 3px rgba(0,0,0,.1)); + pointer-events: none; +} + +.clr-picker.clr-polaroid.clr-dark:before { + color: #444; +} + +.clr-picker.clr-polaroid.clr-left:before { + left: auto; + right: 20px; +} + +.clr-picker.clr-polaroid.clr-top:before { + top: auto; + bottom: -10px; + transform: rotateZ(180deg); +} + +.clr-polaroid .clr-gradient { + width: calc(100% - 20px); + height: 120px; + margin: 10px; + border-radius: 3px; +} + +.clr-polaroid .clr-hue, +.clr-polaroid .clr-alpha { + width: calc(100% - 30px); + height: 10px; + margin: 6px 15px; + border-radius: 5px; +} + +.clr-polaroid .clr-hue div, +.clr-polaroid .clr-alpha div { + box-shadow: 0 0 5px rgba(0,0,0,.2); +} + +.clr-polaroid .clr-format { + width: calc(100% - 20px); + margin: 0 10px 15px; +} + +.clr-polaroid .clr-swatches { + width: calc(100% - 12px); + margin: 0 6px; +} +.clr-polaroid .clr-swatches div { + padding-bottom: 10px; +} + +.clr-polaroid .clr-swatches button { + width: 22px; + height: 22px; +} + +.clr-polaroid input.clr-color { + width: calc(100% - 60px); + margin: 10px 10px 15px 0; +} + +.clr-polaroid .clr-clear { + margin: 0 10px 15px auto; +} + +.clr-polaroid .clr-preview { + margin: 10px 0 15px 10px; +} + +/** Large theme **/ + +.clr-picker.clr-large { + width: 275px; +} + +.clr-large .clr-gradient { + height: 150px; +} + +.clr-large .clr-swatches button { + width: 22px; + height: 22px; +} diff --git a/src/popup/coloris.js b/src/popup/coloris.js new file mode 100644 index 00000000..e9c31c2d --- /dev/null +++ b/src/popup/coloris.js @@ -0,0 +1,961 @@ +/*! + * Copyright (c) 2021 Momo Bassit. + * Licensed under the MIT License (MIT) + * https://github.com/mdbassit/Coloris + */ + +((window, document, Math) => { + const ctx = document.createElement('canvas').getContext('2d'); + const currentColor = { r: 0, g: 0, b: 0, h: 0, s: 0, v: 0, a: 1 }; + let picker, colorArea, colorAreaDims, colorMarker, colorPreview, colorValue, clearButton, + hueSlider, hueMarker, alphaSlider, alphaMarker, currentEl, currentFormat, oldColor; + + // Default settings + const settings = { + el: '.coloris', + parent: null, + theme: 'default', + themeMode: 'light', + wrap: true, + margin: 2, + format: 'hex', + formatToggle: false, + swatches: [], + swatchesOnly: false, + alpha: true, + focusInput: true, + autoClose: false, + clearButton: { + show: false, + label: 'Clear' + }, + a11y: { + open: 'Open color picker', + close: 'Close color picker', + marker: 'Saturation: {s}. Brightness: {v}.', + hueSlider: 'Hue slider', + alphaSlider: 'Opacity slider', + input: 'Color value field', + format: 'Color format', + swatch: 'Color swatch', + instruction: 'Saturation and brightness selector. Use up, down, left and right arrow keys to select.' + } + }; + + /** + * Configure the color picker. + * @param {object} options Configuration options. + */ + function configure(options) { + if (typeof options !== 'object') { + return; + } + + for (const key in options) { + switch (key) { + case 'el': + bindFields(options.el); + if (options.wrap !== false) { + wrapFields(options.el); + } + break; + case 'parent': + settings.parent = document.querySelector(options.parent); + if (settings.parent) { + settings.parent.appendChild(picker); + } + break; + case 'themeMode': + settings.themeMode = options.themeMode; + if (options.themeMode === 'auto' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + settings.themeMode = 'dark'; + } + // The lack of a break statement is intentional + case 'theme': + if (options.theme) { + settings.theme = options.theme; + } + picker.className = `clr-picker clr-${settings.theme} clr-${settings.themeMode}`; + break; + case 'margin': + options.margin *= 1; + settings.margin = !isNaN(options.margin) ? options.margin : settings.margin; + break; + case 'wrap': + if (options.el && options.wrap) { + wrapFields(options.el); + } + break; + case 'formatToggle': + getEl('clr-format').style.display = options.formatToggle ? 'block' : 'none'; + if (options.formatToggle) { + settings.format = 'auto'; + } + break; + case 'swatches': + if (Array.isArray(options.swatches)) { + const swatches = []; + + options.swatches.forEach((swatch, i) => { + swatches.push(``); + }); + + if (swatches.length) { + getEl('clr-swatches').innerHTML = `
    ${swatches.join('')}
    `; + } + } + break; + case 'swatchesOnly': + settings.swatchesOnly = !!options.swatchesOnly; + picker.setAttribute('data-minimal', settings.swatchesOnly); + + if (settings.swatchesOnly) { + settings.autoClose = true; + } + break; + case 'alpha': + settings.alpha = !!options.alpha; + picker.setAttribute('data-alpha', settings.alpha); + break; + case 'clearButton': + let display = 'none'; + + if (options.clearButton.show) { + display = 'block'; + } + + if (options.clearButton.label) { + clearButton.innerHTML = options.clearButton.label; + } + + clearButton.style.display = display; + break; + case 'a11y': + const labels = options.a11y; + let update = false; + + if (typeof labels === 'object') { + for (const label in labels) { + if (labels[label] && settings.a11y[label]) { + settings.a11y[label] = labels[label]; + update = true; + } + } + } + + if (update) { + const openLabel = getEl('clr-open-label'); + const swatchLabel = getEl('clr-swatch-label'); + + openLabel.innerHTML = settings.a11y.open; + swatchLabel.innerHTML = settings.a11y.swatch; + colorPreview.setAttribute('aria-label', settings.a11y.close); + hueSlider.setAttribute('aria-label', settings.a11y.hueSlider); + alphaSlider.setAttribute('aria-label', settings.a11y.alphaSlider); + colorValue.setAttribute('aria-label', settings.a11y.input); + colorArea.setAttribute('aria-label', settings.a11y.instruction); + } + default: + settings[key] = options[key]; + } + } + } + + /** + * Bind the color picker to input fields that match the selector. + * @param {string} selector One or more selectors pointing to input fields. + */ + function bindFields(selector) { + // Show the color picker on click on the input fields that match the selector + addListener(document, 'click', selector, event => { + const parent = settings.parent; + const coords = event.target.getBoundingClientRect(); + const scrollY = window.scrollY; + let reposition = { left: false, top: false }; + let offset = { x: 0, y: 0 }; + let left = coords.x; + let top = scrollY + coords.y + coords.height + settings.margin; + + currentEl = event.target; + oldColor = currentEl.value; + currentFormat = getColorFormatFromStr(oldColor); + picker.classList.add('clr-open'); + + const pickerWidth = picker.offsetWidth; + const pickerHeight = picker.offsetHeight; + + // If the color picker is inside a custom container + // set the position relative to it + if (parent) { + const style = window.getComputedStyle(parent); + const marginTop = parseFloat(style.marginTop); + const borderTop = parseFloat(style.borderTopWidth); + + offset = parent.getBoundingClientRect(); + offset.y += borderTop + scrollY; + left -= offset.x; + top -= offset.y; + + if (left + pickerWidth > parent.clientWidth) { + left += coords.width - pickerWidth; + reposition.left = true; + } + + if (top + pickerHeight > parent.clientHeight - marginTop) { + top -= coords.height + pickerHeight + settings.margin * 2; + reposition.top = true; + } + + top += parent.scrollTop; + + // Otherwise set the position relative to the whole document + } else { + if (left + pickerWidth > document.documentElement.clientWidth) { + left += coords.width - pickerWidth; + reposition.left = true; + } + + if (top + pickerHeight - scrollY > document.documentElement.clientHeight) { + top = scrollY + coords.y - pickerHeight - settings.margin; + reposition.top = true; + } + } + + picker.classList.toggle('clr-left', reposition.left); + picker.classList.toggle('clr-top', reposition.top); + picker.style.left = `${left}px`; + picker.style.top = `${top}px`; + colorAreaDims = { + width: colorArea.offsetWidth, + height: colorArea.offsetHeight, + x: picker.offsetLeft + colorArea.offsetLeft + offset.x, + y: picker.offsetTop + colorArea.offsetTop + offset.y + }; + + setColorFromStr(oldColor); + + if (settings.focusInput) { + colorValue.focus({ preventScroll: true }); + } + }); + + // Update the color preview of the input fields that match the selector + addListener(document, 'input', selector, event => { + const parent = event.target.parentNode; + + // Only update the preview if the field has been previously wrapped + if (parent.classList.contains('clr-field')) { + parent.style.color = event.target.value; + } + }); + } + + /** + * Wrap the linked input fields in a div that adds a color preview. + * @param {string} selector One or more selectors pointing to input fields. + */ + function wrapFields(selector) { + document.querySelectorAll(selector).forEach(field => { + const parentNode = field.parentNode; + + if (!parentNode.classList.contains('clr-field')) { + const wrapper = document.createElement('div'); + + wrapper.innerHTML = ``; + parentNode.insertBefore(wrapper, field); + wrapper.setAttribute('class', 'clr-field'); + wrapper.style.color = field.value; + wrapper.appendChild(field); + } + }); + } + + /** + * Close the color picker. + * @param {boolean} [revert] If true, revert the color to the original value. + */ + function closePicker(revert) { + if (currentEl) { + // Revert the color to the original value if needed + if (revert && oldColor !== currentEl.value) { + currentEl.value = oldColor; + + // Trigger an "input" event to force update the thumbnail next to the input field + currentEl.dispatchEvent(new Event('input', { bubbles: true })); + } + + if (oldColor !== currentEl.value) { + currentEl.dispatchEvent(new Event('change', { bubbles: true })); + } + + picker.classList.remove('clr-open'); + + if (settings.focusInput) { + currentEl.focus({ preventScroll: true }); + } + + currentEl = null; + } + } + + /** + * Set the active color from a string. + * @param {string} str String representing a color. + */ + function setColorFromStr(str) { + const rgba = strToRGBA(str); + const hsva = RGBAtoHSVA(rgba); + + updateMarkerA11yLabel(hsva.s, hsva.v); + updateColor(rgba, hsva); + + // Update the UI + hueSlider.value = hsva.h; + picker.style.color = `hsl(${hsva.h}, 100%, 50%)`; + hueMarker.style.left = `${hsva.h / 360 * 100}%`; + + colorMarker.style.left = `${colorAreaDims.width * hsva.s / 100}px`; + colorMarker.style.top = `${colorAreaDims.height - (colorAreaDims.height * hsva.v / 100)}px`; + + alphaSlider.value = hsva.a * 100; + alphaMarker.style.left = `${hsva.a * 100}%`; + } + + /** + * Guess the color format from a string. + * @param {string} str String representing a color. + * @return {string} The color format. + */ + function getColorFormatFromStr(str) { + const format = str.substring(0, 3).toLowerCase(); + + if (format === 'rgb' || format === 'hsl') { + return format; + } + + return 'hex'; + } + + /** + * Copy the active color to the linked input field. + * @param {number} [color] Color value to override the active color. + */ + function pickColor(color) { + if (currentEl) { + currentEl.value = color !== undefined ? color : colorValue.value; + currentEl.dispatchEvent(new Event('input', { bubbles: true })); + } + } + + /** + * Set the active color based on a specific point in the color gradient. + * @param {number} x Left position. + * @param {number} y Top position. + */ + function setColorAtPosition(x, y) { + const hsva = { + h: hueSlider.value * 1, + s: x / colorAreaDims.width * 100, + v: 100 - (y / colorAreaDims.height * 100), + a: alphaSlider.value / 100 + }; + const rgba = HSVAtoRGBA(hsva); + + updateMarkerA11yLabel(hsva.s, hsva.v); + updateColor(rgba, hsva); + pickColor(); + } + + /** + * Update the color marker's accessibility label. + * @param {number} saturation + * @param {number} value + */ + function updateMarkerA11yLabel(saturation, value) { + let label = settings.a11y.marker; + + saturation = saturation.toFixed(1) * 1; + value = value.toFixed(1) * 1; + label = label.replace('{s}', saturation); + label = label.replace('{v}', value); + colorMarker.setAttribute('aria-label', label); + } + + // + /** + * Get the pageX and pageY positions of the pointer. + * @param {object} event The MouseEvent or TouchEvent object. + * @return {object} The pageX and pageY positions. + */ + function getPointerPosition(event) { + return { + pageX: event.changedTouches ? event.changedTouches[0].pageX : event.pageX, + pageY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY + }; + } + + /** + * Move the color marker when dragged. + * @param {object} event The MouseEvent object. + */ + function moveMarker(event) { + const pointer = getPointerPosition(event); + let x = pointer.pageX - colorAreaDims.x; + let y = pointer.pageY - colorAreaDims.y; + + if (settings.parent) { + y += settings.parent.scrollTop; + } + + x = (x < 0) ? 0 : (x > colorAreaDims.width) ? colorAreaDims.width : x; + y = (y < 0) ? 0 : (y > colorAreaDims.height) ? colorAreaDims.height : y; + + colorMarker.style.left = `${x}px`; + colorMarker.style.top = `${y}px`; + + setColorAtPosition(x, y); + + // Prevent scrolling while dragging the marker + event.preventDefault(); + event.stopPropagation(); + } + + /** + * Move the color marker when the arrow keys are pressed. + * @param {number} offsetX The horizontal amount to move. + * * @param {number} offsetY The vertical amount to move. + */ + function moveMarkerOnKeydown(offsetX, offsetY) { + const x = colorMarker.style.left.replace('px', '') * 1 + offsetX; + const y = colorMarker.style.top.replace('px', '') * 1 + offsetY; + + colorMarker.style.left = `${x}px`; + colorMarker.style.top = `${y}px`; + + setColorAtPosition(x, y); + } + + /** + * Update the color picker's input field and preview thumb. + * @param {Object} rgba Red, green, blue and alpha values. + * @param {Object} [hsva] Hue, saturation, value and alpha values. + */ + function updateColor(rgba = {}, hsva = {}) { + let format = settings.format; + + for (const key in rgba) { + currentColor[key] = rgba[key]; + } + + for (const key in hsva) { + currentColor[key] = hsva[key]; + } + + const hex = RGBAToHex(currentColor); + const opaqueHex = hex.substring(0, 7); + + colorMarker.style.color = opaqueHex; + alphaMarker.parentNode.style.color = opaqueHex; + alphaMarker.style.color = hex; + colorPreview.style.color = hex; + + // Force repaint the color and alpha gradients as a workaround for a Google Chrome bug + colorArea.style.display = 'none'; + colorArea.offsetHeight; + colorArea.style.display = ''; + alphaMarker.nextElementSibling.style.display = 'none'; + alphaMarker.nextElementSibling.offsetHeight; + alphaMarker.nextElementSibling.style.display = ''; + + if (format === 'mixed') { + format = currentColor.a === 1 ? 'hex' : 'rgb'; + } else if (format === 'auto') { + format = currentFormat; + } + + switch (format) { + case 'hex': + colorValue.value = hex; + break; + case 'rgb': + colorValue.value = RGBAToStr(currentColor); + break; + case 'hsl': + colorValue.value = HSLAToStr(HSVAtoHSLA(currentColor)); + break; + } + + // Select the current format in the format switcher + document.querySelector(`.clr-format [value="${format}"]`).checked = true; + } + + /** + * Set the hue when its slider is moved. + */ + function setHue() { + const hue = hueSlider.value * 1; + const x = colorMarker.style.left.replace('px', '') * 1; + const y = colorMarker.style.top.replace('px', '') * 1; + + picker.style.color = `hsl(${hue}, 100%, 50%)`; + hueMarker.style.left = `${hue / 360 * 100}%`; + + setColorAtPosition(x, y); + } + + /** + * Set the alpha when its slider is moved. + */ + function setAlpha() { + const alpha = alphaSlider.value / 100; + + alphaMarker.style.left = `${alpha * 100}%`; + updateColor({ a: alpha }); + pickColor(); + } + + /** + * Convert HSVA to RGBA. + * @param {object} hsva Hue, saturation, value and alpha values. + * @return {object} Red, green, blue and alpha values. + */ + function HSVAtoRGBA(hsva) { + const saturation = hsva.s / 100; + const value = hsva.v / 100; + let chroma = saturation * value; + let hueBy60 = hsva.h / 60; + let x = chroma * (1 - Math.abs(hueBy60 % 2 - 1)); + let m = value - chroma; + + chroma = (chroma + m); + x = (x + m); + + const index = Math.floor(hueBy60) % 6; + const red = [chroma, x, m, m, x, chroma][index]; + const green = [x, chroma, chroma, x, m, m][index]; + const blue = [m, m, x, chroma, chroma, x][index]; + + return { + r: Math.round(red * 255), + g: Math.round(green * 255), + b: Math.round(blue * 255), + a: hsva.a + }; + } + + /** + * Convert HSVA to HSLA. + * @param {object} hsva Hue, saturation, value and alpha values. + * @return {object} Hue, saturation, lightness and alpha values. + */ + function HSVAtoHSLA(hsva) { + const value = hsva.v / 100; + const lightness = value * (1 - (hsva.s / 100) / 2); + let saturation; + + if (lightness > 0 && lightness < 1) { + saturation = Math.round((value - lightness) / Math.min(lightness, 1 - lightness) * 100); + } + + return { + h: hsva.h, + s: saturation || 0, + l: Math.round(lightness * 100), + a: hsva.a + }; + } + + /** + * Convert RGBA to HSVA. + * @param {object} rgba Red, green, blue and alpha values. + * @return {object} Hue, saturation, value and alpha values. + */ + function RGBAtoHSVA(rgba) { + const red = rgba.r / 255; + const green = rgba.g / 255; + const blue = rgba.b / 255; + const xmax = Math.max(red, green, blue); + const xmin = Math.min(red, green, blue); + const chroma = xmax - xmin; + const value = xmax; + let hue = 0; + let saturation = 0; + + if (chroma) { + if (xmax === red) { hue = ((green - blue) / chroma); } + if (xmax === green) { hue = 2 + (blue - red) / chroma; } + if (xmax === blue) { hue = 4 + (red - green) / chroma; } + if (xmax) { saturation = chroma / xmax; } + } + + hue = Math.floor(hue * 60); + + return { + h: hue < 0 ? hue + 360 : hue, + s: Math.round(saturation * 100), + v: Math.round(value * 100), + a: rgba.a + }; + } + + /** + * Parse a string to RGBA. + * @param {string} str String representing a color. + * @return {object} Red, green, blue and alpha values. + */ + function strToRGBA(str) { + const regex = /^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i; + let match, rgba; + + // Default to black for invalid color strings + ctx.fillStyle = '#000'; + + // Use canvas to convert the string to a valid color string + ctx.fillStyle = str; + match = regex.exec(ctx.fillStyle); + + if (match) { + rgba = { + r: match[3] * 1, + g: match[4] * 1, + b: match[5] * 1, + a: match[6] * 1 + }; + + } else { + match = ctx.fillStyle.replace('#', '').match(/.{2}/g).map(h => parseInt(h, 16)); + rgba = { + r: match[0], + g: match[1], + b: match[2], + a: 1 + }; + } + + return rgba; + } + + /** + * Convert RGBA to Hex. + * @param {object} rgba Red, green, blue and alpha values. + * @return {string} Hex color string. + */ + function RGBAToHex(rgba) { + let R = rgba.r.toString(16); + let G = rgba.g.toString(16); + let B = rgba.b.toString(16); + let A = ''; + + if (rgba.r < 16) { + R = '0' + R; + } + + if (rgba.g < 16) { + G = '0' + G; + } + + if (rgba.b < 16) { + B = '0' + B; + } + + if (settings.alpha && rgba.a < 1) { + const alpha = rgba.a * 255 | 0; + A = alpha.toString(16); + + if (alpha < 16) { + A = '0' + A; + } + } + + return '#' + R + G + B + A; + } + + /** + * Convert RGBA values to a CSS rgb/rgba string. + * @param {object} rgba Red, green, blue and alpha values. + * @return {string} CSS color string. + */ + function RGBAToStr(rgba) { + if (!settings.alpha || rgba.a === 1) { + return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`; + } else { + return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; + } + } + + /** + * Convert HSLA values to a CSS hsl/hsla string. + * @param {object} hsla Hue, saturation, lightness and alpha values. + * @return {string} CSS color string. + */ + function HSLAToStr(hsla) { + if (!settings.alpha || hsla.a === 1) { + return `hsl(${hsla.h}, ${hsla.s}%, ${hsla.l}%)`; + } else { + return `hsla(${hsla.h}, ${hsla.s}%, ${hsla.l}%, ${hsla.a})`; + } + } + + /** + * Init the color picker. + */ + function init() { + // Render the UI + picker = document.createElement('div'); + picker.setAttribute('id', 'clr-picker'); + picker.className = 'clr-picker'; + picker.innerHTML = + `` + + `
    ` + + '
    ' + + '
    ' + + '
    ' + + `` + + '
    ' + + '
    ' + + '
    ' + + `` + + '
    ' + + '' + + '
    ' + + '
    ' + + '
    ' + + `${settings.a11y.format}` + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    ' + + '
    ' + + '
    ' + + `` + + `` + + `` + + ``; + + // Append the color picker to the DOM + document.body.appendChild(picker); + + // Reference the UI elements + colorArea = getEl('clr-color-area'); + colorMarker = getEl('clr-color-marker'); + clearButton = getEl('clr-clear'); + colorPreview = getEl('clr-color-preview'); + colorValue = getEl('clr-color-value'); + hueSlider = getEl('clr-hue-slider'); + hueMarker = getEl('clr-hue-marker'); + alphaSlider = getEl('clr-alpha-slider'); + alphaMarker = getEl('clr-alpha-marker'); + + // Bind the picker to the default selector + bindFields(settings.el); + wrapFields(settings.el); + + addListener(picker, 'mousedown', event => { + picker.classList.remove('clr-keyboard-nav'); + event.stopPropagation(); + }); + + addListener(colorArea, 'mousedown', event => { + addListener(document, 'mousemove', moveMarker); + }); + + addListener(colorArea, 'touchstart', event => { + document.addEventListener('touchmove', moveMarker, { passive: false }); + }); + + addListener(colorMarker, 'mousedown', event => { + addListener(document, 'mousemove', moveMarker); + }); + + addListener(colorMarker, 'touchstart', event => { + document.addEventListener('touchmove', moveMarker, { passive: false }); + }); + + addListener(colorValue, 'change', event => { + setColorFromStr(colorValue.value); + pickColor(); + }); + + addListener(clearButton, 'click', event => { + pickColor(''); + closePicker(); + }); + + addListener(colorPreview, 'click', event => { + pickColor(); + closePicker(); + }); + + addListener(document, 'click', '.clr-format input', event => { + currentFormat = event.target.value; + updateColor(); + pickColor(); + }); + + addListener(picker, 'click', '.clr-swatches button', event => { + setColorFromStr(event.target.textContent); + pickColor(); + + if (settings.autoClose) { + closePicker(); + } + }); + + addListener(document, 'mouseup', event => { + document.removeEventListener('mousemove', moveMarker); + }); + + addListener(document, 'touchend', event => { + document.removeEventListener('touchmove', moveMarker); + }); + + addListener(document, 'mousedown', event => { + picker.classList.remove('clr-keyboard-nav'); + closePicker(); + }); + + addListener(document, 'keydown', event => { + if (event.key === 'Escape') { + closePicker(true); + } else if (event.key === 'Tab') { + picker.classList.add('clr-keyboard-nav'); + } + }); + + addListener(document, 'click', '.clr-field button', event => { + event.target.nextElementSibling.dispatchEvent(new Event('click', { bubbles: true })); + }); + + addListener(colorMarker, 'keydown', event => { + const movements = { + ArrowUp: [0, -1], + ArrowDown: [0, 1], + ArrowLeft: [-1, 0], + ArrowRight: [1, 0] + }; + + if (Object.keys(movements).indexOf(event.key) !== -1) { + moveMarkerOnKeydown(...movements[event.key]); + event.preventDefault(); + } + }); + + addListener(colorArea, 'click', moveMarker); + addListener(hueSlider, 'input', setHue); + addListener(alphaSlider, 'input', setAlpha); + } + + /** + * Shortcut for getElementById to optimize the minified JS. + * @param {string} id The element id. + * @return {object} The DOM element with the provided id. + */ + function getEl(id) { + return document.getElementById(id); + } + + /** + * Shortcut for addEventListener to optimize the minified JS. + * @param {object} context The context to which the listener is attached. + * @param {string} type Event type. + * @param {(string|function)} selector Event target if delegation is used, event handler if not. + * @param {function} [fn] Event handler if delegation is used. + */ + function addListener(context, type, selector, fn) { + const matches = Element.prototype.matches || Element.prototype.msMatchesSelector; + + // Delegate event to the target of the selector + if (typeof selector === 'string') { + context.addEventListener(type, event => { + if (matches.call(event.target, selector)) { + fn.call(event.target, event); + } + }); + + // If the selector is not a string then it's a function + // in which case we need regular event listener + } else { + fn = selector; + context.addEventListener(type, fn); + } + } + + /** + * Call a function only when the DOM is ready. + * @param {function} fn The function to call. + * @param {array} [args] Arguments to pass to the function. + */ + function DOMReady(fn, args) { + args = args !== undefined ? args : []; + + if (document.readyState !== 'loading') { + fn(...args); + } else { + document.addEventListener('DOMContentLoaded', () => { + fn(...args); + }); + } + } + + // Polyfill for Nodelist.forEach + if (NodeList !== undefined && NodeList.prototype && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = Array.prototype.forEach; + } + + // Expose the color picker to the global scope + window.Coloris = (() => { + const methods = { + set: configure, + wrap: wrapFields, + close: closePicker + }; + + function Coloris(options) { + DOMReady(() => { + if (options) { + if (typeof options === 'string') { + bindFields(options); + } else { + configure(options); + } + } + }); + } + + for (const key in methods) { + Coloris[key] = (...args) => { + DOMReady(methods[key], args); + }; + } + + return Coloris; + })(); + + // Init the color picker when the DOM is ready + DOMReady(init); + +})(window, document, Math); + +Coloris({ + el: '.coloris', + theme: 'large', + themeMode: 'dark', + format: 'hex', + alpha: false, + swatches: [ + '#471616', + '#1e4716', + '#16473f', + '#161c47', + '#371647', + '#47163f', + '#471627', + '#3a3a3a', + '#ffffff', + '#1a1a1a' + ] +}); \ No newline at end of file diff --git a/src/popup/github.svg b/src/popup/github.svg new file mode 100644 index 00000000..bf0cf267 --- /dev/null +++ b/src/popup/github.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/popup/info.css b/src/popup/info.css new file mode 100644 index 00000000..ecedbc6f --- /dev/null +++ b/src/popup/info.css @@ -0,0 +1,491 @@ +/* // This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . */ +/* cyrillic-ext */ +@import url('https://fonts.googleapis.com/css?family=Rubik:300,400,500,600'); + +.outside-container { + width: 350px; + margin: 0; + background-color: #131313; + overflow: hidden; + position: absolute; + right: 10px; + top: 80px; + z-index: 20; +} + +.selector-container { + font-family: Rubik, sans-serif; + background-color: #131313; + color: white; + padding: 4px; + font-size: 1.5em !important; + text-align: center; + width: 90%; + display: flex; + flex-direction: column; + margin: 0px auto; +} +.main-page { + position: relative; + left: 0px; + transition: 0.4s; +} +.menu-page { + transition: 0.4s; + width: 100%; + height: 26em; +} +.menu-container { + display: flex; + justify-content: center; + align-content: center; + height: 2em !important; +} +.apply-changes { + margin-top: 10px; + margin-left: 5px; + padding: 8px; + background-color: #4cd964; + width: 40%; + font-size: 14px !important; + justify-self: right; + cursor: pointer; + height: fit-content; + text-align: center; + text-shadow: 0px 0px 15px rgb(22, 22, 22); +} +.apply-changes h3, h5 { + margin: 0; +} +.apply-changes h3 { + font-size: 10px; +} +.apply-changes h5 { + font-size: 13px; +} + +.logo-container { + margin-top: 10px; + width: 100%; + height: 6em; + text-align: center; +} +.checkbox-container { + width: 30%; + justify-content: end; + display: flex; +} +.logo-container img { + width: 70%; +} +.addonitem { + font-size: 14px !important; + margin: 0; + /* margin-left: 5px; */ + font-weight: 700; +} +p { + margin: 0 0 1ex; +} +.main { + font-size: 20px !important; + margin-left: 5px; + width: 70%; + font-weight: 700; +} +.menumain { + width: 100%; + margin-left: 0; + font-weight: 700; + font-size: 20px !important; +} +.menu-item-selection { + max-height: 17em; + overflow-y: auto; + overflow-x: hidden; +} +.subitem { + font-size: 12px !important; + font-weight: 300; +} +.bottom-container { + padding: 10px; + background-color: #0d0d0d; + color: rgb(209, 209, 209); + z-index: 3; + display: flex; + flex-direction: row; + justify-content: space-between; + margin-top: 10px; + font-size: 13px !important; + position:relative; +} +.clr-field input:hover { + cursor: pointer; +} +.text-container { + width: 70%; +} +.item-container { + justify-content: space-between; + width: 96%; + margin: 0px auto; + height: 3em; + margin-top: 5px; + border-bottom: 1px solid rgb(90, 90, 90); + display: flex; + flex-direction: row; + text-align: left; + align-items: center; +} +.aboutcontainer { + justify-content: space-between; + width: 96%; + margin: 0px auto; + margin-top: 0px; + display: flex; + flex-direction: row; + text-align: left; + align-items: center; +} +.aboutlinks { + display: flex; + margin: 6px 0 !important; + padding: 5px 18px !important; + font-size: 12px; + background: #3d3d3d !important; + align-items: center; + border-radius: 20px !important; + color: white !important; + border: none !important; + text-decoration: none; +} +.aboutlinks svg { + margin: 0 !important; + margin-right: 5px !important; +} + +.onoffswitch { + margin: 0 0 1ex; + position: relative; width: 42px; +} +.onoffswitch-checkbox { + position: absolute; + opacity: 0; + pointer-events: none; +} + +#github { + width: 25px; + height: 25px; + filter: invert(99%) sepia(0%) saturate(627%) hue-rotate(255deg) + brightness(122%) contrast(100%); + cursor: pointer; +} + +.onoffswitch-label { + display: block; overflow: hidden; cursor: pointer; + height: 16px; padding: 0; line-height: 16px; + border: 0px solid #FFFFFF; border-radius: 24px; + background-color: #9E9E9E; +} +.onoffswitch-label:before { + content: ""; + display: block; width: 24px; margin: -4px; height: 24px; + background: #FFFFFF; + position: absolute; top: 0; bottom: 0; + right: 22px; + border-radius: 24px; + transition: 0.3s; +} +.onoffswitch-checkbox:checked + .onoffswitch-label { + background-color: #20E060; +} +.onoffswitch-checkbox:checked + .onoffswitch-label, .onoffswitch-checkbox:checked + .onoffswitch-label:before { + border-color: #20E060; +} +.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner { + margin-left: 0; +} +.onoffswitch-checkbox:checked + .onoffswitch-label:before { + transition: 0.3s; + right: 0px; + background-color: #86F078; + box-shadow: 3px 6px 18px 0px rgba(0, 0, 0, 0.2); +} + +.notification { + width: 50px; + height: 20px; +} +.notification::before { + width: 16px; + height: 16px; + font: 10px/16px Helvetica; + word-spacing: 26px; +} +.notification:checked:before { + left: 32px; +} +.next-page { + position: absolute; + top: 280px; + left: 270px; + color: white; + font-size: 15px; + font-family: Rubik, sans-serif; +} +.item-container img { + opacity: 0.6; +} +.clickable { + cursor: pointer; +} +.back-button { + width: 30%; + font-size: 20px !important; + color: white; + display: flex; + align-content: center; + padding: 12px; + cursor: pointer; +} +.back-button img { + transform: scaleX(-1); + margin: 5px; + margin-left: 0; +} +.menushortcuts { + height: 2em; +} +::-webkit-scrollbar { + width: 10px; + height: 10px; + transition: 1.0s; +} + +::-webkit-scrollbar-thumb { + background-color: rgba(127, 127, 127, 0.6); + background-clip: padding-box; + border: 2px solid transparent; + transition: 1.0s; +} + +::-webkit-scrollbar-thumb:vertical:hover, +::-webkit-scrollbar-thumb:horizontal:hover { + background-color: rgb(110, 110, 110); +} + +::-webkit-scrollbar-track { + background-color: transparent; +} + + + +::-webkit-scrollbar-thumb:vertical:active, +::-webkit-scrollbar-thumb:horizontal:active { + background: rgba(95, 91, 91, 1); + +} + +::-webkit-scrollbar-corner { + background: none; +} +:root, html, body, div, ol { + scrollbar-width: thin !important; + scrollbar-color: #5e5e5f #161616 !important; +} + + +.topmenu { + display: flex; + width: 100%; + margin: 0 auto; + color: white; + margin-top: 20px; + margin-bottom: 20px; + +} +.navitem { + width: 33.34%; + padding: 15px 0; + position: relative; + font-weight: 400; + text-align: center; + cursor: pointer; + text-transform: uppercase; + overflow: hidden; + border-bottom: 2px solid #a5a5a5; + color: #a5a5a5; + transition: 0.3s; + +} +.activenav { + border-bottom: 2px solid #ff5f5f; + color: #ff5f5f; +} +.hiddenmenu { + display: none; +} +.applychanges { + color: #fcdfb5; + border: 2px solid #ffb64c; + background-color: #131313; + width: 35%; + position: absolute; + padding: 6px; + cursor: pointer; + bottom: 4px; + left: -150px; + z-index: 2; + transition: 0.6s; + border-radius: 5px; +} +.applychanges:hover { + background-color: #202020; +} +#applychanges { + margin-top: 0px; +} +.applychanges h5, h6 { + margin: 0; + font-weight: 400; +} +.draggable { + list-style: none; + position: relative; + margin-left: 10px; + cursor:grab; +} +.draggable:active { + cursor:-moz-grabbing; + cursor: -webkit-grabbing; +} +.draggable::before { + position: absolute; + z-index: 20; + left: -14px; + top: 10px; + content: url('data:image/svg+xml;charset=UTF-8, '); +} +.custom-shortcuts-button { + width: 60%; + height: 2em; + background: #1a1a1a; + color: white; + font-size: 15px; + padding: 0.4em; + display: flex; + align-items: center; + justify-content: center; + transition: 300ms; +} +.custom-shortcuts-buttons:hover { + background: #161616; + transition: 300ms; + cursor: pointer; +} +.custom-shortcuts-buttons:active { + background: #191919; + transition: 300ms; +} + +.customshortcut-submit-valid { + background: #20de5f !important; + transition: 300ms; +} + +.customshortcut-submit-valid:hover { + background: #1cc956 !important; + transition: 300ms; + cursor: pointer; +} + +.customshortcut-submit-valid:active { + background: #17aa48 !important; + transition: 300ms; +} + +.custom-shortcuts-container { + width: 93%; + display: flex; + flex-direction: column; + background: #1a1a1a; + padding: 0; + margin: 0; + height: 0; + overflow: hidden; + transition: 250ms; +} +.custom-shortcuts-container-shown { + padding: 10px; + margin: 10px 0; + height: auto; + transition: 250ms; +} + +.custom-shortcuts-label { + padding: 5px; + text-align: initial; + font-size: 15px; +} +.custom-shortcuts-field { + background: #161616 !important; + color: #b9b9b9 !important; + font-size: 16px !important; + padding: 10px !important; + border-radius: 10px !important; + border: 0 !important; + box-shadow: 0 0 15px 4px rgb(0 0 0 / 6%) !important; + transition: 100ms; +} +.custom-shortcuts-submit { + width: 30%; + font-size: 15px; + margin-top: 0.5em; + background: #161616; + padding: 0.5em; +} + +.custom-shortcuts-field:focus { + outline: none; + outline: 1px solid rgb(60, 60, 60); + transition: 100ms; +} +.domain-container { + font-size: 9px; + margin-top: 2px; + color: white; + margin-left: 10px; + text-align: initial; +} +.domain-container-button { + margin-top: 2px; + font-size: 11px; + padding: 5px 2px; + width: 70%; + border-radius: 10px; + background: #1cc956; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + margin-left: 0; +} +.domain-container-button:hover { + background: #1ed25a; +} +.domain-container-button:active { + background: #19b34d; +} \ No newline at end of file diff --git a/src/popup/info.html b/src/popup/info.html new file mode 100644 index 00000000..f03eec41 --- /dev/null +++ b/src/popup/info.html @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + +
    +
    +
    + + + +
    +
    + + + + + + + + + + + +
    +
    +
    +
    Unsaved Changes
    +
    Click to apply.
    +
    +
    + +
    + +
    +

    Created by RTC

    +

    +
    +
    + + + + + \ No newline at end of file diff --git a/src/popup/info.js b/src/popup/info.js new file mode 100644 index 00000000..16fc1d9b --- /dev/null +++ b/src/popup/info.js @@ -0,0 +1,342 @@ +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +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"); + +const github = document.getElementById("github"); + +const version = document.getElementById('version'); +const domainbutton = document.getElementById('domain-button'); + +var validURL = false; +var validName = false; + +function openGithub() { + chrome.tabs.create({ url: "https://github.com/OG-RandomTechChannel/BestSEQTA" }); +} + + +function openPage(page) { + mainpage.style.left = "-350px"; + page.style.right = '0px'; +} + +function backToMainMenu() { + mainpage.style.left = "0px"; + + menupage.style.right = "-350px"; + shortcutpage.style.right = "-350px"; + miscpage.style.right = "-350px"; +} + +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.tabs.query({}, function (tabs) { + for (let tab of tabs) { + if (tab.title.includes("SEQTA Learn")) { + chrome.tabs.reload(tab.id); + } + } + }); +} +/* +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 }); + }); + } +} + +var stringtoHTML = function (str) { + var parser = new DOMParser(); + var doc = parser.parseFromString(str, "text/html"); + return doc.body; +}; + +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 + ); + +} + +function onError(e) { + console.error(e); +} +/* +On opening the options page, fetch stored settings and update the UI with them. +*/ +chrome.storage.local.get(null, function (result) { + document.getElementsByClassName('clr-field')[0].style.color = result.selectedColor; + colorpicker.value = result.selectedColor; + console.log(result); + updateUI(result); +}); + +/* +On blur, save the currently selected settings. +*/ +document.addEventListener("DOMContentLoaded", function () { + version.innerHTML = `v${chrome.runtime.getManifest().version}`; + github.addEventListener("click", openGithub); + + domainbutton.addEventListener('click', function (event) { + chrome.runtime.sendMessage({ type: "addPermissions" }); + }) + + 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 }) + } + + +}) \ No newline at end of file diff --git a/src/popup/page.png b/src/popup/page.png new file mode 100644 index 00000000..c10efd67 Binary files /dev/null and b/src/popup/page.png differ