// ==UserScript==
// @name Pronote Dark Mode
// @namespace http://tampermonkey.net/
// @version 0.3.5
// @description Un thème sombre pour Pronote avec quelques petites améliorations
// @author Dood Corp.
// @match https://*/pronote/*.html
// @match https://*.pronote.toutatice.fr/pronote/eleve.html
// @run-at document-idle
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
if (localStorage.getItem("badConnection") == null) {
localStorage.setItem("badConnection", false);
}
var tryLimit = 50 //Change this line to the number of attempts before stopping the homepage/loginpage detecting. Lower is better for good and reliable connections (you can see the number of tries before load in the console). A higher one will spam the console with errors if you fail your login.
var tryTiming = 100 //Change this line to the amount of time between two attempts. A low number will spam the console with errors (if you use a low one and the page is not detected, up the tryLimit), a high one will cause a delay between the load of the page and the detectiong (it's in ms).
function isInViewport(element) { //Check if element is visible
var rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
function checkLoadHome() { //Check if home page is visible (loaded)
var tries = 0
var counter = setInterval( function() {
tries++ //add one to the number of tries
console.log("Home page not detected at try " + (tries - 1) + ", retrying..."); //had to put it here since the if (isInViewport [...]) causes an error
if (tries >= tryLimit) { //stop the attempts after a number of failed tries
clearInterval(counter); //stop the counter
console.log("failed to load homepage, retrying stopped")
} else {
if (isInViewport(document.querySelector("#GInterface\\.Instances\\[2\\]"))) { //detect if homepage is visible
console.log("home page loaded successfully after " + (tries * tryTiming) / 1000 + " s (try " + tries + ")");
launchJS();
clearInterval(counter); //stop both counters
clearInterval(counterBis);
}
}
}, tryTiming);
}
checkLoadHome(); //since checkLoadHome is a defined function (unlike the login one), this is needed to fire it at launch
var loginTries = 0
var counterBis = setInterval(function () {
loginTries++
console.log("Login page not detected at try " + (loginTries - 1) + " , retrying ...");
if (loginTries >= tryLimit) {
console.log("failed to detect login page, retrying stopped");
clearInterval(counterBis);
} else {
if (isInViewport(document.querySelector("#id_42 > div.InlineBlock.Texte10"))) { //detect if homepage is fully loaded (when using autologin)
console.log("Login page loaded successfully after " + (loginTries * tryTiming) / 1000 + " s (try " + (loginTries + 1) + ")")
clearInterval(counter);
clearInterval(counterBis);
document.querySelector("#id_39").addEventListener('click', function a() { clearInterval(counter); checkLoadHome()}, false); //fire checkLoadHome at click on the "connect" button
document.querySelector("#id_50").addEventListener('keyup', function a() { if (event.keyCode === 13) { clearInterval(counter); checkLoadHome() }; }, false); //fire checkLoadHome when hitting Enter
}
}
}, tryTiming);
function launchJS() {
document.getElementById('GInterface.Instances[0].Instances[3]_Combo0').addEventListener('click', function a() { checkLoadHome(); }, false);
if (document.getElementById('customBtn') == null) {
var customInput = document.createElement("DIV"); //create the main custom div
customInput.id = "customInput"; // give an id to the div
customInput.style = "display: none; position: relative;top: -1.1rem; left: 38rem;"; // hide the div
customInput.innerHTML = '<input type="text" id="url" placeholder="Entrez une URL" style="border-radius: 4px; margin-left: 0.5rem;"><input type="text" id="name" placeholder="Entrez votre nom" style="border-radius: 4px; margin-left: 0.5rem;"><input type="checkbox" id="keepCheck"style="margin-left: 0.5rem;"><input type="checkbox" id="badConnection" style="margin-left: 0.5rem;">';
//<input type="text" id="backgroundURL" placeholder ="background URL" style="border-radius: 4px; margin-left: 0.5rem"> (this line is for a future update)
document.getElementById("GInterface.Instances[0].Instances[0]").firstElementChild.appendChild(customInput); //makes the div a children of the navbar
document.getElementById('keepCheck').addEventListener('click', function a() { store("keep", document.getElementById('keepCheck').checked) }, false); //changes if the name/url is kept
document.getElementById('badConnection').addEventListener('click', function a() { store("badConnection", document.getElementById('badConnection').checked); }, false);
//document.getElementById('backgroundURL').onchange = changeBackground
document.getElementById('url').addEventListener('change', function a() { store("profilePic", document.getElementById("url").value); changeImage(); }, false); //changes image on url input
document.getElementById('name').addEventListener('change', function b() { store("name", document.getElementById("name").value); changeName(); }, false);
var mainDiv = document.getElementsByClassName("ibe_util").item(0); //get the buttons div
var customButton = document.createElement("DIV"); //create div
customButton.class = "ibe_iconebtn ibe_actif"; //set class, title etc
customButton.tabindex = "0";
customButton.title = "Cacher les options de customisation";
customButton.innerHTML = '<button id="customBtn" style="height: 22px; width: 22px; margin-left: 0.5rem; cursor: pointer; outline: none; background-color: #232325; border: none;"><img src="https://cdn.onlinewebfonts.com/svg/img_142231.png" style="width: 22px; height: 22px; transform: translateX(-5px) translateY(-3px);"></button>'; //add the button
var customBtn = document.getElementById('customBtn');
mainDiv.appendChild(customButton); //append div to buttons
document.getElementById('customBtn').onclick = showCustom; //detect click on the button, an attribute in the button won't work cauz the button search the function in the website
}
function store(name, value) {
localStorage.setItem(name, value);
console.log('"' + value + '" successfully stored in "' + name + '"');
}
var strTheme = document.querySelector("#div").className;
var theme = strTheme.substr(33);
function changeImage() {
var urls = localStorage.getItem("profilePic");
document.getElementsByClassName("ibe_util_photo ibe_actif").item(0).firstElementChild.src = urls
}
changeNameStartup(); //set the image/name stored in localStorage at the launch of the page
function changeNameStartup() {
if (localStorage.getItem("keep") == "true") { //only change the image/name if the "keep" var is set to true
document.getElementsByClassName("ibe_util_texte ibe_actif").item(0).innerText = localStorage.getItem("name");
document.getElementsByClassName("ibe_util_photo ibe_actif").item(0).firstElementChild.src = localStorage.getItem("profilePic");
document.getElementById("keepCheck").checked = true; //tick the checkbox
}
if (localStorage.getItem("badConnection") == "true") {
document.getElementById("badConnection").checked = true;
}
}
function changeName() {
var names = localStorage.getItem("name");
document.getElementsByClassName("ibe_util_texte ibe_actif").item(0).innerText = names
}
/*function changeBackground() {
var bckgrnd = document.getElementById("backgroundURL").value
localStorage.setItem("bckgrnd", bckgrnd);
}*/ //this will maybe be added in next update
function showCustom() { //show the input div
var c = document.getElementById("customInput")
if (c.style.display === "none") {
c.style.display = "block";
console.log("Customisation options displayed");
} else {
c.style.display = "none";
console.log("Customisation options hidden");
}
}
//So I tried to use IndexedDB but I'm too dumb to do it, the following code doesn't work (the JS is loading indefinitly)... If someone knows how to use it, post a comment or email me at whitebowoo@gmail.com
/*var openRequest = indexedDB.open("store", 1);
console.log(openRequest);
var db
openRequest.onupdateneeded = function(event) {
db = event.target.result;
console.log(db);
var objectStore
if (!db.objectStoreNames.contains('note')) {
objectStore = db.createObjectStore('note', { keyPath: 'id' });
objectStore.createIndex('content', 'content', { unique: true });
}
}
function storeNotepadDB() {
var request = db.transaction(['note'], 'readwrite')
.objectStore('note')
.add({ id: 1, content: 'yeet' });
request.onsuccess = function (event) {
console.log('The data has been written successfully');
};
request.onerror = function (event) {
console.log('The data has been written failed');
}
db = openRequest.result;
var notes = document.getElementById("noteInput").value
var transactions = indexedDB.open("store", 1).transaction('store', 'readwrite');
var noteObject = transactions.objectStore("store");
var note = {
id: 'note',
content: notes,
};
request = noteObject.add(note);
request.onsuccess = function() {
console.log('note succesfully stored !' + request.result);
}
request.onerror = function() {
console.log("Error", request.error);
}
}
storeNotepadDB();
function addNotepad() {
function autoGrow(element) {
element.style.height = 'auto';
element.style.height = (element.scrollHeight) + "px";
}
if (document.getElementById('notepad') == null) {
var column = document.getElementById('GInterface.Instances[2]_colonne_0');
var notepad = document.createElement("article");
notepad.id = "notepad";
notepad.class = "widget notepad collapsible"
notepad.style = "heigth: auto;"
notepad.innerHTML = "<button id='saveNote' style='margin-bottom: 5px;'>Save</button><textarea id='noteInput' style='width: 100%; resize: none; min-height: 40px; max-height: 500px; overflow: hidden;'></textarea>"
column.appendChild(notepad);
notepad.addEventListener('keyup', function a() { autoGrow(document.getElementById('noteInput')); }, false);
document.getElementById('saveNote').addEventListener('click', function a() {storeNotepadDB();}, false);
}
}
addNotepad();
function read() {
db = openRequest.result;
var transactions = db.transaction('store', 'readwrite');
var noteObject = transactions.objectStore("store");
var request = noteObject.get("note");
if (request.result) {
console.log(request.result.content);
} else {
console.log("couldn't find data !");
}
}*/
console.log("JS was successfully loaded");
}
var cssLoad = 0
function addGlobalStyle(css) { //Apply the CSS
cssLoad++
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
console.log("-CSS line number " + cssLoad + " : " + css + " was successfully loaded")
}
localStorage.setItem("etatAffichageFooter_3", true); //Get rid of the useless footer
console.log("footer removed successfully");
//Good luck to read the css bro
if (localStorage.getItem("badConnection") == 'true') {
addGlobalStyle('#div { background-image : linear-gradient(#4e4e4e, #212121) !important;}'); //change the loading & login background image
addGlobalStyle('.dotty, .interface_affV_client {background-image : radial-gradient(circle, #4e4e4e 5%, transparent 10%), radial-gradient(circle, #6d6d6e 5%, transparent 10%); width:100%; height: 100%; user-select: text; background-color: #121212 !important;}'); //change main background
console.log('mauvaise co');
} if (localStorage.getItem("badConnection") == 'false') {
addGlobalStyle('#div { background-image : url("https://s3-eu-west-1.amazonaws.com/sales-i-wordpress/wp-content/uploads/2015/12/17112848/black-background.jpg") !important; }'); //change the loading & login background image
console.log('bonne co');
addGlobalStyle('.dotty, .interface_affV_client { background-image: url("https://wallpaperaccess.com/full/1811424.png"); background-size: auto; width:100%; height: 100%; background-color: #121212 !important; user-select: text; }'); //change main background
}
addGlobalStyle('.liste-nested > li > h4 {color: #a478d4 !important;}');
addGlobalStyle('h4, fieldset, td.AlignementMilieu, a > span:not(.InlineBlock), legend.Texte10.Legende, td.AlignementDroit.AlignementHaut { color: #fff !important; }');
addGlobalStyle('legend > div > div.jiehint.ie-ellipsis { background-color: #fff; }');
addGlobalStyle('::-webkit-scrollbar { display: none; } !important; }'); //get rid of the useless scrollbar
addGlobalStyle('.widget, fieldset, legend.Texte10.Legende, td.AlignementDroit.AlignementHaut { background-color: #303030 !important; }');
addGlobalStyle('.widget.travailafaire h3, .widget.ressourcepedagogique h3 { background-color: #ebdbff; border-radius: 0.5rem 0.5rem 0.5rem 0.5rem; padding: 0.3rem !important; }');
addGlobalStyle('.widget .content-container > div[id^=id_] .liste-nested h5, .widget .content-container > div[id^=id_] .liste-groups h5, .widget .content-container > div[id^=id_] .liste-ressources h5, .widget .content-container > div[id^=id_] h4, { color: #9ca0a0 !important; }');
addGlobalStyle('.widget, .AlignementDroit.PetitEspaceDroit, #id_114 > ul > li:nth-child(1) > ul > li:nth-child(2) > div > div.descriptif.done, .objetBandeauEntete_secondmenu .objetBandeauEntete_fullsize .precedenteConnexion { color: #f0f0f0 !important; }');
addGlobalStyle('.widget.travailafaire .content-container > div[id^=id_] .liste-nested .sub-liste li .liste-docs a, .widget.travailafaire .content-container > div[id^=id_] .liste-groups .sub-liste li .liste-docs a, .widget.travailafaire .content-container > div[id^=id_] .liste-ressources .sub-liste li .liste-docs a { color: #ebdbff !important; }');
addGlobalStyle('.widget.ressourcepedagogique .content-container > div[id^=id_] li .file-name, .widget.ressourcepedagogique .content-container > div[id^=id_] li .file-contain.icon::before { color: #ebdbff !important; }');
addGlobalStyle('.as-input.actif.ie-ellipsis {color: #303030 !important; }');
addGlobalStyle('.as-button { background-color: #b5bbbb !important; }');
addGlobalStyle('.EspaceIndex #div > .interface_affV > div.interface_affV_client.no-tactile { overflow: auto !important; }');
addGlobalStyle('.ibp-bloc-left, .host-france-container, .knowledge-container, .footer-toggler, .ibe_gauche, .Image_Logo_PronoteBarreHaut, .icon_uniF2C3 { display:none !important; }'); //get rid of the useless images
addGlobalStyle('.ObjetBandeauPied { transform: translateY(-5px) !important; }'); //set the footer a little bit higher because there is a gab between the main background and the end of the page
addGlobalStyle('.ObjetBandeauEspace, .item-menu_niveau0:hover, .item-menu_niveau0.focused-in, .item-menu_niveau0.item-selected { background-color: #232325 !important; color: #eef0f5 !important; }');
addGlobalStyle('.ibe_centre { position: fixed !important; }'); //set the name in the navbar fixed so it doesn't change place when showing the custom div
addGlobalStyle('.item-menu_niveau0, .label-submenu { color: #b7b7b7 !important;}');
addGlobalStyle('.objetBandeauEntete_secondmenu { background-color: #757575 !important;}');
addGlobalStyle('.objetBandeauEntete_secondmenu, .menu-principal_niveau1, .EtiquetteCours { background-color : #626469 !important }');
addGlobalStyle('.objetbandeauentete_global, .objetBandeauEntete_thirdmenu { background-color: #a2a0a0 !important;}');
addGlobalStyle('.item-menu_niveau1.selected, .ObjetMenuContexutel { background-color: #46484d !important}');
addGlobalStyle('::placeholder { color: #5d5e61 !important }');
addGlobalStyle('#id_137fond { background-color: #707070 !important; }');
addGlobalStyle('.widget .content-container > div[id^=id_] .liste-nested h5, .widget .content-container > div[id^=id_] .liste-groups h5, .widget .content-container > div[id^=id_] .liste-ressources h5, .underline { color:#a6b5b5 !important }');
addGlobalStyle('.Texte10:not(.c_7):not(.ieBoutonDefautSansImage):not(.Calendrier_Jour):not(.Calendrier_Mois):not(#breadcrumbBandeauPerso):not(.EspaceGauche.EspaceDroit) { color: #d2d2d2 !important }');
addGlobalStyle('.Fenetre_Cadre { background-color: #cccccc !important}');
addGlobalStyle('.Calendrier_Jour_Selection { background-color: #626262 !important}');
addGlobalStyle('.liste_contenu_cellule_contenu, .divCellule, .liste_gridTitre_cel { background-color: #5c5c5c; color: #cdcdd8 !important}');
addGlobalStyle('.MaClasseBordure, .CarteCompteZoneGenerique { border-radius: 0 4px 0 4px !important;}');
addGlobalStyle('#id_95 { user-select:none !important}');
addGlobalStyle('#conteneur-page > div > div.jspPane > div > div:nth-child(1), #conteneur-page > div > div.jspPane > div > div:nth-child(2), #conteneur-page > div > div.jspPane > div > div:nth-child(3), #conteneur-page > div > div.jspPane > div > div:nth-child(4), #conteneur-page > div > div.jspPane > div > div:nth-child(5) { background-color: #7f7f7f !important;}');
addGlobalStyle('.ObjetTimeline_classScrollPanel { border-left: 1px solid #1E1414 !important; border-right: 1px solid #1E1414; border-bottom: 1px solid #1E1414 !important; }');
//addGlobalStyle('.PetitEspaceHaut { border-left: 1px solid #1E1414 !important; border-top: 1px solid #1E1414 !important; border-right: 1px solid #1E1414 !important; }');
addGlobalStyle('#conteneur-page > div > div.jspPane > div > div:nth-child(1) > div.PetitEspaceHaut { border-top: 1px solid #1E1414 !important; }');
addGlobalStyle('#id_174 { background-color: #a2a0a0 !important }');
addGlobalStyle('.EtiquetteCours, .AlignementMilieu.Insecable { color: #f0f0f0 !important; }');
addGlobalStyle('.liste_zoneFils { border-top: 4px solid #C5C5C5 !important; border-bottom: 4px solid #C5C5C5 !important; border-left: 4px solid #C5C5C5 !important; border-right: 4px solid #C5C5C5 !important; backdrop-filter: blur(7px); }');