Greasy Fork 支持简体中文。

IgnitiaPlus

Enhance your study experience with IgnitiaPlus

// ==UserScript==
// @name         IgnitiaPlus
// @namespace    http://tampermonkey.net/
// @version      2.0.1
// @license      Apache-2.0
// @description  Enhance your study experience with IgnitiaPlus
// @author       Minemetero
// @match        *://*.ignitiaschools.com/*
// @icon         https://raw.githubusercontent.com/Minemetero/Minemetero/refs/heads/master/favicon.png
// @grant        GM.getValue
// @grant        GM.setValue
// @require      https://unpkg.com/darkreader@latest/darkreader.js
// @require      https://cdn.jsdelivr.net/npm/mathjs@14/lib/browser/math.min.js
// ==/UserScript==

(function () {
    'use strict';

    let clockWidget, timetableWidget, todoWidget;

    /*** CSS Injection ***/
    function injectCSS() {
        const style = document.createElement('style');
        style.textContent = `
            /* ======================================================
            General Widget Styles
            ====================================================== */
            #clockWidget,
            #timetableWidget,
            #todoWidget,
            #minimalist-toolbar-popup,
            #StopWatchWidget {
                position: fixed;
                background-color: rgba(0, 0, 0, 0.7);
                color: white;
                border-radius: 5px;
                font-family: Arial, sans-serif;
                font-size: 14px;
                z-index: 1000;
                user-select: none;
                overflow: hidden;
            }

            #clockWidget,
            #timetableWidget,
            #todoWidget,
            #StopWatchWidget {
                max-width: 90vw;
                max-height: 90vh;
            }

            /* ======================================================
            Clock Widget and Stop Watch Widget
            ====================================================== */
            #clockWidget,
            #StopWatchWidget {
                bottom: 10px;
                right: 10px;
                background-color: rgba(0, 0, 0, 0.5);
                padding: 5px 10px;
                cursor: move;
            }

            /* ======================================================
            Stop Watch Widget
            ====================================================== */

            .incompleted {
                color: #00b3ff !important;
            }

            .completed {
                color: #07f007 !important;
            }

            /* ======================================================
            Timetable Widget
            ====================================================== */
            #timetableWidget {
                bottom: 60px;
                left: 10px;
                padding: 10px;
                overflow-y: auto;
            }

            #timetableWidget textarea {
                width: 100%;
                height: calc(100% - 40px);
                background: transparent;
                color: white;
                border: none;
                outline: none;
                resize: none;
                margin-top: 5px;
            }

            /* ======================================================
            Todo Widget
            ====================================================== */
            #todoWidget {
                bottom: 0;
                left: 10px;
                padding: 10px;
                overflow: auto;
            }

            #todoWidget ul {
                list-style-type: none;
                padding: 0;
                margin-top: 10px;
            }

            #todoWidget ul li {
                margin: 0;
                cursor: pointer;
                padding: 5px;
                border-radius: 3px;
                background-color: rgba(255, 255, 255, 0.1);
            }

            /* ======================================================
            Resize Handles
            ====================================================== */
            .resize-handle {
                width: 10px;
                height: 10px;
                background-color: rgba(255, 255, 255, 0.5);
                position: absolute;
                bottom: 0;
                right: 0;
                cursor: nwse-resize;
            }

            #todoWidget .resize-handle {
                width: 15px;
                height: 15px;
                background-color: rgba(255, 255, 255, 0.7);
                border-bottom-right-radius: 5px;
            }

            /* ======================================================
            Minimalist Toolbar Popup
            ====================================================== */
            #minimalist-toolbar-popup {
                top: 50px;
                left: 10px;
                width: 250px;
                background: #f9f9f9;
                color: #333;
                padding: 15px;
                border: 1px solid #ddd;
                box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                display: none;
                flex-direction: column;
                align-items: center;
                border-radius: 10px;
                z-index: 1000;
            }

            #minimalist-toolbar-popup textarea {
                width: 100%;
                background: #fff;
                color: #333;
                border: 1px solid #ddd;
                border-radius: 5px;
                padding: 10px;
                outline: none;
                resize: none;
            }

            #minimalist-calculator {
                height: 50px;
                margin-bottom: 15px;
            }

            #minimalist-notes {
                height: 100px;
            }

            /* ======================================================
            Toggle Menu Dropdown (from Cog)
            ====================================================== */
            .toggle-widgets {
                z-index: 9999;
                background-color: #333;
                color: #fff;
                padding: 10px;
                border-radius: 8px;
                display: flex;
                flex-direction: column;
                gap: 8px; 
                min-width: 150px;
                max-height: 200px;
                overflow-y: auto;
            }

            .widget-container {
                display: flex;
                flex-direction: row;
                align-items: center;
                background-color: transparent;
                border-radius: 4px;
            }

            .widget-container span {
                flex: 1;            /* occupy remaining horizontal space */
                white-space: nowrap;/* prevent wrapping onto a second line */
                font-size: 16px;    /* adjust as desired */
            }

            /* The Reset button */
            #resetButton {
                margin-left: 8px;
                background-color: #007BFF;
                color: white;
                border: none;
                border-radius: 5px;
                padding: 4px 8px;
                cursor: pointer;
                transition: background-color 0.3s;
                font-size: 12px;
            }

            /* ======================================================
            Dark Mode Toggle
            ====================================================== */
            #dark-reader-toggle {
                position: fixed;
                bottom: 10px;
                left: 70px;
                z-index: 10000;
                padding: 10px;
                background-color: transparent;
                color: white;
                border-radius: 50%;
                cursor: pointer;
                font-size: 20px;
                text-align: center;
            }

            /* ======================================================
            Toolbar Toggle (if used)
            ====================================================== */
            #minimalist-toolbar-toggle {
                position: fixed;
                top: 10px;
                left: 10px;
                width: 50px;
                height: 50px;
                background: linear-gradient(135deg, #007BFF, #0056b3);
                color: #fff;
                text-align: center;
                line-height: 50px;
                border-radius: 50%;
                font-size: 20px;
                box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
                z-index: 1001;
                cursor: pointer;
                transition: background 0.3s, transform 0.2s;
                }

                #minimalist-toolbar-toggle:hover {
                background: linear-gradient(135deg, #0056b3, #007BFF);
                transform: scale(1.1);
            }

            /* ======================================================
            Container for Widget Toggle Rows (if needed)
            ====================================================== */
            #container {
                display: flex;
                align-items: center;
                justify-content: space-between;
                margin-bottom: 2px;
            }

            /* ======================================================
            FadeIn Animation (for Quote)
            ====================================================== */
            @keyframes fadeIn {
                to {
                    opacity: 1;
                }
            }
        `;
        document.head.appendChild(style);
    }

    /*** Utility Functions ***/
    function injectFavicon(href) {
        const existingFavicon = document.querySelector('link[rel="shortcut icon"]');
        if (existingFavicon) existingFavicon.remove();
        const faviconLink = document.createElement('link');
        faviconLink.rel = 'shortcut icon';
        faviconLink.href = href;
        faviconLink.type = 'image/x-icon';
        document.head.appendChild(faviconLink);
    }

    function adjustElementPosition(element, storageKey) {
        if (!element) return;
        let rect = element.getBoundingClientRect();
        let adjustedLeft = rect.left;
        let adjustedTop = rect.top;
        if (rect.right > window.innerWidth) adjustedLeft = window.innerWidth - rect.width;
        if (rect.bottom > window.innerHeight) adjustedTop = window.innerHeight - rect.height;
        if (rect.left < 0) adjustedLeft = 0;
        if (rect.top < 0) adjustedTop = 0;
        element.style.left = `${adjustedLeft}px`;
        element.style.top = `${adjustedTop}px`;
        localStorage.setItem(storageKey, JSON.stringify({ left: element.style.left, top: element.style.top }));
    }

    function loadSavedPositionAndSize(element, posKey, sizeKey) {
        const savedPos = JSON.parse(localStorage.getItem(posKey));
        if (savedPos) {
            let left = parseInt(savedPos.left, 10);
            let top = parseInt(savedPos.top, 10);
            left = Math.max(0, Math.min(left, window.innerWidth - element.offsetWidth));
            top = Math.max(0, Math.min(top, window.innerHeight - element.offsetHeight));
            element.style.left = `${left}px`;
            element.style.top = `${top}px`;
            element.style.bottom = 'auto'; element.style.right = 'auto';
        }
        const savedSize = JSON.parse(localStorage.getItem(sizeKey));
        if (savedSize) {
            element.style.width = savedSize.width;
            element.style.height = savedSize.height;
        }
    }

    /*** Page Modifiers ***/
    function modifyPageHead() {
        const titleElement = document.querySelector('title');
        if (!titleElement) return;
        const titleText = titleElement.textContent.trim();
        if (titleText === 'Ignitia') {
            titleElement.textContent = 'IgnitiaPlus';
            injectFavicon('https://raw.githubusercontent.com/Minemetero/Minemetero/refs/heads/master/favicon.png');
        } else if (titleText === 'switchedonuk') {
            titleElement.textContent = 'SwitchedOnPlus';
            injectFavicon('https://raw.githubusercontent.com/Minemetero/Minemetero/refs/heads/master/SwitchedOn.png');
        }
    }

    function removeUnwantedElements() {
        const signOutElement = document.getElementById('logout');
        const bannerTabDividers = document.querySelectorAll('.bannerTabDivider');
        if (signOutElement) signOutElement.remove();
        bannerTabDividers.forEach(divider => divider.remove());
    }

    function removeLoginError() {
        const loginError = document.querySelector('.login-error.alert.alert-error');
        if (loginError) {
            loginError.remove();
        }
    }

    function logOut() { /***(Credit:BurdenOwl)***/
        const passwordResetForm = document.getElementById("passwordResetFormWrapper");
        if (!passwordResetForm) return;

        const signOutButton = document.createElement('button');
        signOutButton.id = 'signOut';
        signOutButton.className = 'btn btn-default btn-block';
        signOutButton.textContent = 'Sign Out';

        passwordResetForm.appendChild(signOutButton);

        signOutButton.addEventListener('click', () => {
            const logoutUrl = `${window.location.origin}/owsoo/j_spring_security_logout`;
            window.location.href = logoutUrl;
        });
    }

    function addRefreshWarning() {
        if (window.location.href.includes('/owsoo/home')) return;
        let warningActive = false;
        window.addEventListener('beforeunload', (event) => {
            if (!warningActive) {
                warningActive = true;
                event.preventDefault();
                event.returnValue = '';
                setTimeout(() => { warningActive = false; }, 5000);
            }
        });
    }

    function addContributorTab() {
        const navTabs = document.querySelector('ul.nav.nav-tabs[data-tabs="tabs"]');
        if (!navTabs) return;

        const contributorTab = document.createElement('li');
        contributorTab.className = 'contributor';

        // Create tooltip element with updated positioning
        const tooltip = document.createElement('div');
        tooltip.style.cssText = `
            display: none;
            position: absolute;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 14px;
            z-index: 1000;
            white-space: nowrap;
            pointer-events: none;
            transform: translateX(-100%) translateY(-50%);  /* Changed to move left and center vertically */
            margin-right: 10px;  /* Added margin to separate from the tab */
        `;
        tooltip.textContent = 'IgnitiaPlus contributors: Minemetero, BurdenOwl';

        // Updated tooltip positioning on hover
        contributorTab.addEventListener('mouseenter', () => {
            tooltip.style.display = 'block';
            const rect = contributorTab.getBoundingClientRect();
            tooltip.style.left = `${rect.left}px`;  // Position at left edge of tab
            tooltip.style.top = `${rect.top + (rect.height / 2)}px`;  // Center vertically
        });

        contributorTab.addEventListener('mouseleave', () => {
            tooltip.style.display = 'none';
        });

        const contributorLink = document.createElement('a');
        contributorLink.href = '#';
        contributorLink.className = 'clickable-icon';
        contributorLink.style.cssText = `
            display: block;
            padding: 14.5px 0;
            text-align: center;
            color: #666666;
            font-size: 24px;
            width: 52px;
            background: #fbfbfb;
            border: 1px solid #ccc;
            border-radius: 2px;
            margin-bottom: 5px;
            cursor: pointer;
        `;

        contributorLink.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();

        });

        contributorLink.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg"
                 viewBox="0 -960 960 960"
                 style="width: 24px; height: 24px; display: block; margin: 0 auto;">
              <path d="M680-119q-8 0-16-2t-15-7l-120-70q-14-8-21.5-21.5T500-249v-141q0-16 7.5-29.5T529-441l120-70q7-5 15-7t16-2q8 0 15.5 2.5T710-511l120 70q14 8 22 21.5t8 29.5v141q0 16-8 29.5T830-198l-120 70q-7 4-14.5 6.5T680-119ZM400-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM80-160v-112q0-33 17-62t47-44q51-26 115-44t141-18h14q6 0 12 2-8 18-13.5 37.5T404-360h-4q-71 0-127.5 18T180-306q-9 5-14.5 14t-5.5 20v32h252q6 21 16 41.5t22 38.5H80Zm320-400q33 0 56.5-23.5T480-640q0-33-23.5-56.5T400-720q-33 0-56.5 23.5T320-640q0 33 23.5 56.5T400-560Zm0-80Zm12 400Zm174-166 94 55 94-55-94-54-94 54Zm124 208 90-52v-110l-90 53v109Zm-150-52 90 53v-109l-90-53v109Z"></path>
            </svg>`;

        contributorTab.appendChild(contributorLink);
        document.body.appendChild(tooltip);
        navTabs.appendChild(contributorTab);
    }

    /** Functions for Footer ***/
    function createFooterModeSelector() {
        // Container
        const container = document.createElement('div');
        container.className = 'widget-container';

        // Label
        const label = document.createElement('span');
        label.textContent = 'Footer Mode';
        label.style.flex = "1";
        label.style.fontSize = "16px";

        // Dropdown
        const select = document.createElement('select');
        select.style.width = "120px";
        select.style.padding = "3px";
        select.style.borderRadius = "3px";
        select.style.border = "1px solid #ddd";
        select.style.fontSize = "14px";

        const modes = [
            { value: 'none', label: 'Do Nothing' },
            { value: 'remove', label: 'Remove Footer' },
            { value: 'modified', label: 'Modified Footer' },
        ];

        // Load saved mode (default "none")
        let savedMode = localStorage.getItem('footerMode') || 'none';

        modes.forEach(m => {
            const option = document.createElement('option');
            option.value = m.value;
            option.textContent = m.label;
            select.appendChild(option);
        });
        select.value = savedMode;

        select.addEventListener('change', () => {
            const newMode = select.value;
            localStorage.setItem('footerMode', newMode);
            applyFooterMode(newMode);
        });

        container.appendChild(label);
        container.appendChild(select);
        return container;
    }

    function applyFooterMode(mode) {
        const footerElement = document.getElementById('footer');
        if (!footerElement) return;

        switch (mode) {
            case 'remove':
                footerElement.style.display = 'none';
                break;

            case 'modified':
                footerElement.style.display = '';
                adjustFooter();
                break;

            default:
                footerElement.style.display = '';
                footerElement.style.position = '';
                footerElement.style.bottom = '';
                footerElement.style.left = '';
                footerElement.style.right = '';
                break;
        }
    }

    function adjustFooter() {
        const footerElement = document.getElementById('footer');
        if (!footerElement) return;

        function updateFooterPosition() {
            // If the content's height is less than or equal to the viewport height, fix the footer at the bottom.
            if (document.body.scrollHeight <= window.innerHeight) {
                footerElement.style.position = 'fixed';
                footerElement.style.bottom = '0';
                footerElement.style.left = '0';
                footerElement.style.right = '0';
            } else {
                // Otherwise, let the site's own CSS take over.
                footerElement.style.position = '';
                footerElement.style.bottom = '';
                footerElement.style.left = '';
                footerElement.style.right = '';
            }
        }

        updateFooterPosition();

        window.addEventListener('resize', updateFooterPosition);

        const observer = new MutationObserver(updateFooterPosition);
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: true
        });

        // Check on dynamic content load
        window.addEventListener('load', updateFooterPosition);
        document.addEventListener('DOMContentLoaded', updateFooterPosition);
    }

    /*** Widgets Manager ***/
    function createWidgetToggleCog() {
        const cogContainer = document.createElement('div');
        cogContainer.id = 'widget-toggle-cog-container';
        Object.assign(cogContainer.style, {
            position: 'fixed',
            bottom: '10px',
            left: '10px',
            zIndex: '10000'
        });

        // Create the cog icon
        const cogIcon = document.createElement('div');
        cogIcon.id = 'widget-toggle-cog';
        Object.assign(cogIcon.style, {
            padding: '10px',
            backgroundColor: 'transparent',
            color: 'white',
            borderRadius: '50%',
            cursor: 'pointer',
            fontSize: '20px',
            textAlign: 'center'
        });
        cogIcon.textContent = '⚙️';

        // Build the dropdown container with checkboxes
        const toggleMenu = createToggleMenu();
        Object.assign(toggleMenu.style, {
            position: 'absolute',
            bottom: '100%',
            left: '0',
            marginBottom: '5px',
            display: 'none'
        });

        cogContainer.appendChild(cogIcon);
        cogContainer.appendChild(toggleMenu);

        cogIcon.addEventListener('click', () => {
            toggleMenu.style.display =
                (toggleMenu.style.display === 'none') ? 'flex' : 'none';
        });

        document.body.appendChild(cogContainer);
    }

    function createToggleMenu() {
        const toggleMenu = document.createElement('div');
        toggleMenu.className = 'toggle-widgets';

        const widgets = [
            { name: 'Clock', id: 'clockWidget', init: addClock },
            { name: 'Class Timetable', id: 'timetableWidget', init: addClassTimetable },
            { name: 'Todo List', id: 'todoWidget', init: addTodoList },
            { name: 'Quote', id: 'quoteWidget', init: addInspirationalQuoteWidget }
        ];

        widgets.forEach(widget => {
            const container = createWidgetContainer(widget);
            toggleMenu.appendChild(container);
        });

        const footerModeSelector = createFooterModeSelector();
        toggleMenu.appendChild(footerModeSelector);

        toggleMenu.style.marginBottom = '2px';
        return toggleMenu;
    }

    function createWidgetContainer(widget) {
        let isEnabled = JSON.parse(localStorage.getItem(widget.id) || 'true');

        const label = document.createElement('span');
        label.textContent = widget.name;
        label.style.marginBottom = '5px';
        label.style.cursor = 'pointer';

        label.addEventListener('click', () => {
            isEnabled = !isEnabled;
            localStorage.setItem(widget.id, isEnabled);
            if (isEnabled) {
                widget.init();
            } else {
                document.getElementById(widget.id)?.remove();
            }
        });

        const resetButton = createResetButton(widget);
        const container = document.createElement('div');
        container.className = 'widget-container';
        container.appendChild(label);
        container.appendChild(resetButton);
        return container;
    }

    function createResetButton(widget) {
        const resetButton = document.createElement('button');
        resetButton.textContent = 'Reset';
        resetButton.id = 'resetButton';

        resetButton.addEventListener('click', () => {
            localStorage.removeItem(`${widget.id}Position`);
            localStorage.removeItem(`${widget.id}Size`);
            location.reload();
        });

        resetButton.addEventListener('mouseover', () => {
            resetButton.style.backgroundColor = '#0056b3';
        });
        resetButton.addEventListener('mouseout', () => {
            resetButton.style.backgroundColor = '#007BFF';
        });

        return resetButton;
    }

    /*** Widgets ***/
    function testAndQuizStopWatch() { /***(Credit:BurdenOwl)***/
        if (!window.location.href.includes('/owsoo/studentAssignment')) return;

        const assignmentTab = document.querySelector('.assignmentTitle.assignment-title-text');
        if (!assignmentTab) return;

        const assignmentLabel = assignmentTab.querySelector("label");
        if (!assignmentLabel) return;

        const assignmentType = assignmentLabel.textContent.trim();
        if (assignmentType === "Quiz" || assignmentType === "Test") {
            const stopwatchWidget = document.createElement('div');
            stopwatchWidget.id = 'StopWatchWidget';
            stopwatchWidget.classList.add('incompleted');
            stopwatchWidget.style.resize = "none";
            stopwatchWidget.style.position = 'fixed';
            stopwatchWidget.style.cursor = 'move';

            const displaySpan = document.createElement("span");
            displaySpan.id = "displayOfWatch";
            displaySpan.textContent = "0.00";
            stopwatchWidget.appendChild(displaySpan);

            let timer = null;
            let elapsedTime = 0;

            function startTimer() {
                if (timer) return;
                timer = setInterval(() => {
                    elapsedTime += 0.01;

                    const hours = Math.floor(elapsedTime / 3600);
                    const minutes = Math.floor((elapsedTime % 3600) / 60);
                    const seconds = (elapsedTime % 60).toFixed(2);
                    const formattedTime =
                        `${String(hours).padStart(2, '0')}:` +
                        `${String(minutes).padStart(2, '0')}:` +
                        `${String(seconds).padStart(5, '0')}`;

                    const questionsNumberElement = document.querySelector(".totalProblemCount");
                    if (questionsNumberElement) {
                        const totalProblems = parseInt(questionsNumberElement.textContent.trim(), 10);
                        const minutesConverted = minutes + (seconds / 60);
                        const totalTimeInMinutes = hours * 60 + minutesConverted;

                        if (!isNaN(totalProblems)) {
                            const expectedTime = 1.1 * (totalProblems - 5) + 10;
                            if (totalTimeInMinutes >= expectedTime) {
                                stopwatchWidget.classList.remove("incompleted");
                                stopwatchWidget.classList.add("completed");
                            }
                        }
                    }

                    displaySpan.textContent = formattedTime;
                }, 10);
            }

            // Drag functionality
            let isDragging = false;
            let offsetX = 0;
            let offsetY = 0;

            stopwatchWidget.addEventListener('mousedown', (e) => {
                isDragging = true;
                offsetX = e.clientX - stopwatchWidget.offsetLeft;
                offsetY = e.clientY - stopwatchWidget.offsetTop;
            });

            document.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                let newX = e.clientX - offsetX;
                let newY = e.clientY - offsetY;
                newX = Math.max(0, Math.min(newX, window.innerWidth - stopwatchWidget.offsetWidth));
                newY = Math.max(0, Math.min(newY, window.innerHeight - stopwatchWidget.offsetHeight));
                stopwatchWidget.style.left = `${newX}px`;
                stopwatchWidget.style.top = `${newY}px`;
            });

            document.addEventListener('mouseup', () => {
                if (isDragging) {
                    isDragging = false;
                    localStorage.setItem('StopWatchWidgetPosition', JSON.stringify({
                        left: stopwatchWidget.style.left,
                        top: stopwatchWidget.style.top
                    }));
                }
            });

            document.body.appendChild(stopwatchWidget);
            startTimer();
            loadSavedPositionAndSize(stopwatchWidget, 'StopWatchWidgetPosition', null);
        } else {
            return; // Exit if not a Quiz/Test
        }
    }

    function addClock() {
        clockWidget = document.createElement('div');
        clockWidget.id = 'clockWidget';
        clockWidget.style.resize = "none";

        function updateClock() {
            const now = new Date();
            const h = now.getHours().toString().padStart(2, '0');
            const m = now.getMinutes().toString().padStart(2, '0');
            const s = now.getSeconds().toString().padStart(2, '0');
            clockWidget.textContent = `${h}:${m}:${s}`;
        }

        let isDragging = false, offsetX, offsetY;
        clockWidget.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - clockWidget.offsetLeft;
            offsetY = e.clientY - clockWidget.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                let newX = e.clientX - offsetX;
                let newY = e.clientY - offsetY;
                newX = Math.max(0, Math.min(newX, window.innerWidth - clockWidget.offsetWidth));
                newY = Math.max(0, Math.min(newY, window.innerHeight - clockWidget.offsetHeight));
                clockWidget.style.left = `${newX}px`;
                clockWidget.style.top = `${newY}px`;
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                localStorage.setItem('clockWidgetPosition', JSON.stringify({ left: clockWidget.style.left, top: clockWidget.style.top }));
            }
        });

        updateClock();
        setInterval(updateClock, 1000);
        document.body.appendChild(clockWidget);
        loadSavedPositionAndSize(clockWidget, 'clockWidgetPosition', null);
    }

    function addClassTimetable() {
        timetableWidget = document.createElement('div');
        timetableWidget.id = 'timetableWidget';

        const timetableHeader = document.createElement('div');
        timetableHeader.textContent = '📅 Class Timetable';
        timetableHeader.style.fontWeight = 'bold';
        timetableHeader.style.cursor = 'move';

        const timetableBody = document.createElement('textarea');
        timetableBody.placeholder = 'Enter your class schedule here...';
        timetableBody.value = localStorage.getItem('timetable') || '';
        timetableBody.addEventListener('input', () => localStorage.setItem('timetable', timetableBody.value));

        const resizeHandle = document.createElement('div');
        resizeHandle.className = 'resize-handle';

        timetableWidget.appendChild(timetableHeader);
        timetableWidget.appendChild(timetableBody);
        timetableWidget.appendChild(resizeHandle);
        document.body.appendChild(timetableWidget);

        let isDragging = false, isResizing = false, offsetX, offsetY;
        timetableHeader.addEventListener('mousedown', (e) => {
            if (e.target === resizeHandle) return;
            isDragging = true;
            offsetX = e.clientX - timetableWidget.offsetLeft;
            offsetY = e.clientY - timetableWidget.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                let newX = e.clientX - offsetX;
                let newY = e.clientY - offsetY;
                newX = Math.max(0, Math.min(newX, window.innerWidth - timetableWidget.offsetWidth));
                newY = Math.max(0, Math.min(newY, window.innerHeight - timetableWidget.offsetHeight));
                timetableWidget.style.left = `${newX}px`;
                timetableWidget.style.top = `${newY}px`;
            } else if (isResizing) {
                const newWidth = e.clientX - timetableWidget.getBoundingClientRect().left;
                const newHeight = e.clientY - timetableWidget.getBoundingClientRect().top;
                timetableWidget.style.width = `${newWidth}px`;
                timetableWidget.style.height = `${newHeight}px`;
                timetableBody.style.height = 'calc(100% - 40px)';
                localStorage.setItem('timetableWidgetSize', JSON.stringify({ width: timetableWidget.style.width, height: timetableWidget.style.height }));
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                localStorage.setItem('timetableWidgetPosition', JSON.stringify({ left: timetableWidget.style.left, top: timetableWidget.style.top }));
            }
            if (isResizing) isResizing = false;
        });

        resizeHandle.addEventListener('mousedown', (e) => {
            isResizing = true;
            e.preventDefault();
            e.stopPropagation();
        });

        loadSavedPositionAndSize(timetableWidget, 'timetableWidgetPosition', 'timetableWidgetSize');
    }

    function addTodoList() {
        todoWidget = document.createElement('div');
        todoWidget.id = 'todoWidget';

        const todoHeader = document.createElement('div');
        todoHeader.textContent = '📝 Todo List';
        todoHeader.style.fontWeight = 'bold';
        todoHeader.style.marginBottom = '5px';
        todoHeader.style.cursor = 'move';

        const todoInput = document.createElement('input');
        todoInput.placeholder = 'Add a new task...';
        Object.assign(todoInput.style, { width: '90%', padding: '5px', borderRadius: '3px', border: '1px solid #ddd' });

        const todoList = document.createElement('ul');
        const resizeHandle = document.createElement('div');
        resizeHandle.className = 'resize-handle';

        todoWidget.appendChild(todoHeader);
        todoWidget.appendChild(todoInput);
        todoWidget.appendChild(todoList);
        todoWidget.appendChild(resizeHandle);
        document.body.appendChild(todoWidget);

        const savedTodos = JSON.parse(localStorage.getItem('todoItems')) || [];
        savedTodos.forEach(addTodoItem);

        todoInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && todoInput.value.trim() !== '') {
                addTodoItem(todoInput.value.trim());
                todoInput.value = '';
            }
        });

        let isDragging = false, isResizing = false, offsetX, offsetY;
        let startX, startY, startWidth, startHeight;

        todoHeader.addEventListener('mousedown', (e) => {
            if (isResizing) return;
            isDragging = true;
            offsetX = e.clientX - todoWidget.offsetLeft;
            offsetY = e.clientY - todoWidget.offsetTop;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                let newX = e.clientX - offsetX;
                let newY = e.clientY - offsetY;
                newX = Math.max(0, Math.min(newX, window.innerWidth - todoWidget.offsetWidth));
                newY = Math.max(0, Math.min(newY, window.innerHeight - todoWidget.offsetHeight));
                todoWidget.style.left = `${newX}px`;
                todoWidget.style.top = `${newY}px`;
            } else if (isResizing) {
                const deltaX = e.clientX - startX;
                const deltaY = e.clientY - startY;
                const newWidth = Math.max(startWidth + deltaX, 50);
                const newHeight = Math.max(startHeight + deltaY, 50);
                todoWidget.style.width = `${newWidth}px`;
                todoWidget.style.height = `${newHeight}px`;
                localStorage.setItem('todoWidgetSize', JSON.stringify({ width: todoWidget.style.width, height: todoWidget.style.height }));
            }
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                localStorage.setItem('todoWidgetPosition', JSON.stringify({ left: todoWidget.style.left, top: todoWidget.style.top }));
            }
            if (isResizing) isResizing = false;
        });

        resizeHandle.addEventListener('mousedown', (e) => {
            isResizing = true;
            e.preventDefault();
            e.stopPropagation();
            startX = e.clientX;
            startY = e.clientY;
            startWidth = parseInt(document.defaultView.getComputedStyle(todoWidget).width, 10);
            startHeight = parseInt(document.defaultView.getComputedStyle(todoWidget).height, 10);
        });

        loadSavedPositionAndSize(todoWidget, 'todoWidgetPosition', 'todoWidgetSize');
        if (!localStorage.getItem('todoWidgetSize')) {
            todoWidget.style.width = '150px';
            todoWidget.style.height = '200px';
        }

        function addTodoItem(todoText) {
            const todoItem = document.createElement('li');
            const index = todoList.children.length + 1;
            todoItem.textContent = `${index}. ${todoText}`;
            todoItem.addEventListener('click', () => {
                todoItem.style.textDecoration = (todoItem.style.textDecoration === 'line-through') ? 'none' : 'line-through';
            });
            todoItem.addEventListener('dblclick', () => {
                todoItem.remove();
                saveTodos();
                updateTodoIndices();
            });
            todoList.appendChild(todoItem);
            saveTodos();
        }

        function saveTodos() {
            const todos = Array.from(todoList.children).map(item => item.textContent.split('. ')[1]);
            localStorage.setItem('todoItems', JSON.stringify(todos));
        }

        function updateTodoIndices() {
            Array.from(todoList.children).forEach((item, index) => {
                const text = item.textContent.split('. ')[1];
                item.textContent = `${index + 1}. ${text}`;
            });
        }
    }

    /*** Dark Mode Toggle ***/
    async function createDarkReaderToggle() {
        const btn = document.createElement('div');
        btn.id = 'dark-reader-toggle';
        btn.textContent = '🔆';
        btn.addEventListener('click', async () => {
            if (await GM.getValue('darkMode', false)) {
                await GM.setValue('darkMode', false);
                disableDarkMode();
            } else {
                await GM.setValue('darkMode', true);
                enableDarkMode();
            }
        });
        document.body.appendChild(btn);

        if (await GM.getValue('darkMode', false)) enableDarkMode();
        else disableDarkMode();
    }

    function enableDarkMode() {
        DarkReader.setFetchMethod(window.fetch);
        DarkReader.enable({ brightness: 105, contrast: 105, sepia: 0 });
        const btn = document.getElementById('dark-reader-toggle');
        if (btn) btn.textContent = '🔅';
        const logoElement = document.querySelector('#gl_logo img');
        if (logoElement) logoElement.src = 'https://raw.githubusercontent.com/BurdenOwl/burdenowl/refs/heads/main/failureswebsite.png';
    }

    function disableDarkMode() {
        DarkReader.disable();
        const btn = document.getElementById('dark-reader-toggle');
        if (btn) btn.textContent = '🔆';
        const logoElement = document.querySelector('#gl_logo img');
        if (logoElement) logoElement.src = 'https://media-release.glynlyon.com/branding/images/ignitia/logo.png';
    }

    /*** Minimalist Toolbar ***/
    function addMinibar() {
        const toolbar = createToolbar();
        const toggleButton = createToggleButton(toolbar);
        const developerName = createDeveloperName();
        const calculator = createCalculator();
        const notes = createNotes();

        toolbar.appendChild(developerName);
        toolbar.appendChild(calculator);
        toolbar.appendChild(notes);

        document.body.appendChild(toggleButton);
        document.body.appendChild(toolbar);
    }

    function createToolbar() {
        const toolbar = document.createElement('div');
        toolbar.id = 'minimalist-toolbar-popup';
        return toolbar;
    }

    function createToggleButton(toolbar) {
        const toggleButton = document.createElement('div');
        toggleButton.id = 'minimalist-toolbar-toggle';

        toggleButton.style.display = "flex";
        toggleButton.style.justifyContent = "center";
        toggleButton.style.alignItems = "center";
        toggleButton.innerHTML = `
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" width="24" height="24" style="display: block; margin: auto;">
              <path fill="white" d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z"></path>
            </svg>`;

        toggleButton.addEventListener('click', () => {
            toolbar.style.display = (toolbar.style.display === 'none') ? 'flex' : 'none';
        });

        return toggleButton;
    }

    function createDeveloperName() {
        const developerName = document.createElement('div');
        developerName.textContent = 'By Minemetero';
        developerName.style.fontWeight = 'bold';
        developerName.style.marginBottom = '15px';
        return developerName;
    }

    function createCalculator() {
        const calculator = document.createElement('textarea');
        calculator.id = 'minimalist-calculator';
        calculator.placeholder = 'Calculator (press Enter to evaluate)';

        calculator.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                try {
                    const input = calculator.value.trim();
                    let result;

                    if (input.startsWith('sqrt(') && input.endsWith(')')) {
                        const number = input.slice(5, -1);
                        result = math.sqrt(math.evaluate(number));
                    } else if (input.startsWith('simplify(') && input.endsWith(')')) {
                        const expr = input.slice(10, -1);
                        result = math.simplify(expr).toString();
                    } else {
                        result = math.evaluate(input);
                    }

                    calculator.value = `${result}`;
                } catch {
                    calculator.value = 'Error!';
                }
            }
        });

        return calculator;
    }

    function createNotes() {
        const notes = document.createElement('textarea');
        notes.id = 'minimalist-notes';
        notes.placeholder = 'Your Notes...';
        notes.value = localStorage.getItem('minimalistNotes') || '';

        notes.addEventListener('input', () => {
            localStorage.setItem('minimalistNotes', notes.value);
        });

        return notes;
    }

    /*** Inspirational Quote ***/
    async function addInspirationalQuoteWidget() {
        if (!window.location.pathname.startsWith('/owsoo/login/auth')) {
            return;
        }
        if (document.getElementById('quoteWidget')) return;

        const quotesURL = "https://raw.githubusercontent.com/Minemetero/IgnitiaPlus/refs/heads/main/qutoes.json";
        try {
            const response = await fetch(quotesURL, { cache: "no-store" });
            if (!response.ok) {
                console.error("Failed to load quotes:", response.statusText);
                return;
            }

            const quotes = await response.json();
            if (!Array.isArray(quotes) || quotes.length === 0) {
                console.error("Quotes file is empty or not an array.");
                return;
            }

            const today = new Date();
            const dayOfYear = Math.floor((today - new Date(today.getFullYear(), 0, 0)) / 86400000);
            const quote = quotes[dayOfYear % quotes.length];
            displayQuote(quote);
        } catch (error) {
            console.error("Error fetching quotes:", error);
        }
    }

    function displayQuote(quote) {
        const link = document.createElement('link');
        link.href = 'https://fonts.googleapis.com/css2?family=Merriweather&display=swap';
        link.rel = 'stylesheet';
        document.head.appendChild(link);

        // Create the quote container
        const quoteContainer = document.createElement('div');
        quoteContainer.id = 'quoteWidget';
        Object.assign(quoteContainer.style, {
            position: 'fixed', top: '50%', right: '200px',
            transform: 'translateY(-50%)',
            background: 'linear-gradient(135deg, #f6d365 0%, #fda085 100%)',
            color: 'white', padding: '20px', borderRadius: '15px',
            fontFamily: '"Merriweather", serif', fontSize: '22px',
            lineHeight: '1.5', zIndex: '1000', maxWidth: '350px', textAlign: 'center',
            boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)', opacity: '0', animation: 'fadeIn 1s forwards'
        });

        // The quote text
        const quoteText = document.createElement('div');
        quoteText.textContent = quote;

        quoteContainer.appendChild(quoteText);
        document.body.appendChild(quoteContainer);
    }

    /*** Initialization ***/
    async function init() {
        injectCSS();
        if (window.location.pathname.startsWith('/owsoo/login/auth')) {
            if (JSON.parse(localStorage.getItem('quoteWidget') || 'true')) addInspirationalQuoteWidget();
            removeLoginError();
        } else {
            modifyPageHead();
            removeUnwantedElements();
            addRefreshWarning();
            await createDarkReaderToggle();
            createWidgetToggleCog()
            addMinibar();
            logOut();
            testAndQuizStopWatch()
            //addContributorTab();
            const savedMode = localStorage.getItem('footerMode') || 'none';
            applyFooterMode(savedMode);

            if (JSON.parse(localStorage.getItem('clockWidget') || 'true')) addClock();
            if (JSON.parse(localStorage.getItem('timetableWidget') || 'true')) addClassTimetable();
            if (JSON.parse(localStorage.getItem('todoWidget') || 'true')) addTodoList();
        }
    }

    window.addEventListener('load', init);
    window.addEventListener('resize', () => {
        adjustElementPosition(clockWidget, 'clockWidgetPosition');
        adjustElementPosition(timetableWidget, 'timetableWidgetPosition');
        adjustElementPosition(todoWidget, 'todoWidgetPosition');
    });
})();