Edio Hotkeys

Adds shortcuts to get across the site faster

当前为 2025-01-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Edio Hotkeys
// @namespace    http://tampermonkey.net/
// @version      Alpha-v3
// @description  Adds shortcuts to get across the site faster
// @author       Crowned Studios
// @license      CC BY-NC
// @match        https://www.myedio.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_cookieSet
// @grant        GM_cookieDelete
// ==/UserScript==

/*
  _    _       _   _                        _____
 | |  | |     | | | |                     _|  __ \
 | |__| | ___ | |_| | _____ _   _ ___    (_) |  | |
 |  __  |/ _ \| __| |/ / _ \ | | / __|     | |  | |
 | |  | | (_) | |_|   <  __/ |_| \__ \    _| |__| |
 |_|  |_|\___/ \__|_|\_\___|\__, |___/   (_)_____/
                             __/ |
                            |___/
*/


    // === User Configurable Settings ===


// Set this to true to enable console logging, or false to disable it.
const isLoggingEnabled = true;

    // === End Of Configurable Settings ===

(function() {
    'use strict';

    function logMessage(message) {
        if (isLoggingEnabled) {
            console.log(message);
        }
    }

    function saveLinkIfMatches() {
        const link = window.location.href;
        const matchPatterns = [
            "https://www.myedio.com/learning/courses/",
            "/lessons/",
            "/summary/"
        ];

        if (matchPatterns.every(pattern => link.includes(pattern))) {
            try {
                GM_setValue('siteLink', link);
                logMessage(`Link saved using GM_setValue: ${link}`);
            } catch (e) {
                logMessage("Error saving with GM_setValue, falling back to cookies...");
                showErrorPopup(101, e.message);
                document.cookie = `siteLink=${link}; path=/; expires=${new Date(Date.now() + 86400000).toUTCString()}`;
                logMessage("Link saved to cookie: " + link);
            }
        } else {
            logMessage("Link does not match the pattern, not saved.");
        }
    }

    function getSavedLink() {
        return new Promise((resolve, reject) => {
            const gmLink = GM_getValue('siteLink', null);
            if (gmLink) {
                resolve(gmLink);
            } else {
                const cookieMatch = document.cookie.match(/siteLink=([^;]*)/);
                if (cookieMatch) {
                    resolve(cookieMatch[1]);
                } else {
                    showErrorPopup(102, "No site link found, or It was never saved.");
                    reject("No site link found, or It was never saved.");
                }
            }
        });
    }

    async function handleHotkeys(event) {
        if (event.altKey) {
            const key = event.key.toLowerCase();
            switch (key) {
                case 'r':
                    event.preventDefault();
                    try {
                        const savedLink = await getSavedLink();
                        logMessage(`Redirecting to saved link: ${savedLink}`);
                        window.location.href = savedLink;
                    } catch (e) {
                        logMessage(e);
                        showErrorPopup(103, "Error redirecting to saved link.");
                    }
                    break;
                case 'c':
                    event.preventDefault();
                    window.location.href = "https://www.myedio.com/calendar/day/";
                    break;
                case 'q':
                    event.preventDefault();
                    window.location.href = "https://www.myedio.com/login/?sessionExpired=true";
                    break;
                case 'd':
                    event.preventDefault();
                    window.location.href = "https://www.myedio.com/dashboard/";
                    break;
                case 'l':
                    event.preventDefault();
                    alert("Test successful!");
                    break;
                default:
                    handleCustomHotkeys(key);
                    break;
            }
        }
    }

    function handleCustomHotkeys(key) {
        const customHotkeys = GM_getValue('customHotkeys', {});
        if (customHotkeys[key]) {
            window.location.href = customHotkeys[key];
        }
    }

    function showErrorPopup(errorNumber, errorMessage) {
        if (document.querySelector('.error-overlay')) return;

        const overlay = document.createElement('div');
        overlay.classList.add('error-overlay');
        const overlayContent = document.createElement('div');
        overlayContent.classList.add('error-overlay-content');

        overlayContent.innerHTML = `
            <h2>Error ${errorNumber}</h2>
            <p>${errorMessage}</p>
        `;

        const closeButton = document.createElement('button');
        closeButton.innerHTML = 'Close';
        closeButton.addEventListener('click', () => {
            document.body.removeChild(overlay);
            document.body.removeChild(overlayBackground);
            document.body.style.overflow = '';
            document.body.style.userSelect = '';
        });

        overlayContent.appendChild(closeButton);
        overlay.appendChild(overlayContent);
        document.body.appendChild(overlay);

        const overlayBackground = document.createElement('div');
        overlayBackground.classList.add('error-overlay-background');
        document.body.appendChild(overlayBackground);

        document.body.style.overflow = 'hidden';
        document.body.style.userSelect = 'none';
    }

    function addHotkeysElement() {
        if (document.querySelector('.c-navigation__item.hotkeys-item')) return;

        const newElement = document.createElement('li');
        newElement.classList.add('c-navigation__item', 'hotkeys-item');
        newElement.innerHTML = `
            <a class="" target="" title="Hotkeys">
                <span>Hotkeys</span>
            </a>
        `;

        const navigationElement = document.querySelector('.c-navigation');
        if (navigationElement) navigationElement.appendChild(newElement);

        newElement.addEventListener('click', showHotkeysOverlay);

        observeSidebarToggle(newElement);
    }

    function observeSidebarToggle(hotkeysElement) {
        const toggleButton = document.querySelector('.c-button.-icon.c-sidebar__toggle');
        if (toggleButton) {
            const observer = new MutationObserver(() => {
                const isExpanded = toggleButton.getAttribute('aria-expanded') === 'true';
                const span = hotkeysElement.querySelector('span');
                span.textContent = isExpanded ? 'Hotkeys' : 'HK';
            });

            observer.observe(toggleButton, { attributes: true, attributeFilter: ['aria-expanded'] });
        }
    }

    function showHotkeysOverlay() {
        const overlay = document.createElement('div');
        overlay.classList.add('hotkeys-overlay');
        const overlayContent = document.createElement('div');
        overlayContent.classList.add('hotkeys-overlay-content');

        const userNameElement = document.querySelector('.c-avatar__name');
        let userName = userNameElement ? userNameElement.textContent.trim() : "User";

        function toTitleCase(str) {
            return str.replace(/\b\w/g, char => char.toUpperCase());
        }

        userName = toTitleCase(userName);

        overlayContent.innerHTML = `
            <h2>List of Hotkeys</h2>
            <p><strong>Logout:</strong> Alt + Q</p>
            <p><strong>Calendar:</strong> Alt + C</p>
            <p><strong>Dashboard:</strong> Alt + D</p>
            <p><strong>Return to Course Link:</strong> Alt + R</p>
            <p><strong>Test Key:</strong> Alt + L</p>
            <p><strong>Custom Hotkeys:</strong></p>
            <ul id="custom-hotkeys-list"></ul>
            <p>Hello ${userName}! You are running the Alpha version of <strong>Edio Hotkeys</strong>.
            There is still lots of development needed for this script, including one known error,
            but please enjoy what you currently have!</p>
            <button id="add-custom-hotkey">Add Custom Hotkey (Experimental)</button>
        `;

        const closeButton = document.createElement('button');
        closeButton.innerHTML = 'Close';
        closeButton.addEventListener('click', () => {
            document.body.removeChild(overlay);
            document.body.removeChild(overlayBackground);
            document.body.style.overflow = '';
            document.body.style.userSelect = '';
        });

        overlayContent.appendChild(closeButton);
        overlay.appendChild(overlayContent);
        document.body.appendChild(overlay);

        const overlayBackground = document.createElement('div');
        overlayBackground.classList.add('hotkeys-overlay-background');
        document.body.appendChild(overlayBackground);

        document.body.style.overflow = 'hidden';
        document.body.style.userSelect = 'none';

        displayCustomHotkeys();
        document.getElementById('add-custom-hotkey').addEventListener('click', addCustomHotkey);
    }

    function displayCustomHotkeys() {
        const customHotkeys = GM_getValue('customHotkeys', {});
        const customHotkeysList = document.getElementById('custom-hotkeys-list');
        customHotkeysList.innerHTML = '';
        for (const [key, url] of Object.entries(customHotkeys)) {
            const li = document.createElement('li');
            li.textContent = `Alt + ${key.toUpperCase()}: ${url}`;
            customHotkeysList.appendChild(li);
        }
    }

    function addCustomHotkey() {
        const key = prompt("Enter the key for the custom hotkey (e.g., 'n' for Alt+N):");
        const url = prompt("Enter the URL to be associated with this hotkey:");
        if (key && url) {
            const customHotkeys = GM_getValue('customHotkeys', {});
            customHotkeys[key.toLowerCase()] = url;
            GM_setValue('customHotkeys', customHotkeys);
            displayCustomHotkeys();
        }
    }

    const style = document.createElement('style');
    style.innerHTML = `
        .c-navigation__item.hotkeys-item a {
            display: flex;
            align-items: center;
            color: #333;
            font-size: 16px;
            text-decoration: none;
            padding: 10px;
            border-radius: 4px;
            transition: background-color 0.2s ease, transform 0.2s ease;
            cursor: pointer;
        }

        .c-navigation__item.hotkeys-item a:hover {
            background-color: #f4f4f4;
            transform: translateX(5px);
            cursor: pointer;
        }

        .hotkeys-overlay-background {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.8);
            z-index: 1000;
            pointer-events: none;
        }

        .hotkeys-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 1001;
            display: flex;
            justify-content: center;
            align-items: center;
            opacity: 0;
            animation: fadeIn 0.3s forwards;
        }

        .hotkeys-overlay-content {
            background: #ffffff;
            padding: 30px 25px;
            border-radius: 5px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
            max-width: 600px;
            text-align: center;
        }

        .hotkeys-overlay-content h2 {
            margin-bottom: 20px;
            font-size: 24px;
        }

        .hotkeys-overlay-content p {
            margin-bottom: 15px;
            font-size: 16px;
        }

        .hotkeys-overlay-content ul {
            list-style: none;
            padding: 0;
        }

        .hotkeys-overlay-content ul li {
            margin-bottom: 5px;
            font-size: 16px;
        }

        .hotkeys-overlay-content button {
            background-color: #007BFF;
            color: white;
            border: none;
            padding: 10px 20px;
            font-size: 14px;
            cursor: pointer;
            border-radius: 4px;
            margin-top: 20px;
        }

        .hotkeys-overlay-content button:hover {
            background-color: #0056b3;
        }

        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        .error-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 1001;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: rgba(0, 0, 0, 0.8);
        }

        .error-overlay-content {
            background: #ffebee;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
            max-width: 500px;
            text-align: center;
        }

        .error-overlay-content h2 {
            margin-bottom: 15px;
            font-size: 20px;
            color: #d32f2f;
        }

        .error-overlay-content p {
            margin-bottom: 15px;
            font-size: 16px;
            color: #333;
        }

        .error-overlay-content button {
            background-color: #d32f2f;
            color: white;
            border: none;
            padding: 10px 20px;
            font-size: 14px;
            cursor: pointer;
            border-radius: 4px;
            margin-top: 10px;
        }

        .error-overlay-content button:hover {
            background-color: #b71c1c;
        }
    `;
    document.head.appendChild(style);

    saveLinkIfMatches();
    window.addEventListener('keydown', handleHotkeys);
    setInterval(() => {
        addHotkeysElement();
    }, 10);
})();