Greasy Fork

来自缓存

Greasy Fork is available in English.

Duolingo Wide

Make Duolingo wider and more minimalist, and add useful keyboard shortcuts for the main features of the site.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Duolingo Wide
// @namespace    http://tampermonkey.net/
// @version      2.0.3
// @description  Make Duolingo wider and more minimalist, and add useful keyboard shortcuts for the main features of the site.
// @author       Nekosuki
// @match        https://www.duolingo.com/*
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==


GM_addStyle("div.a5SW0,div._2_lzu{display:none}div._3MT-S{width:100%}div.kHldG{width:20%}");
GM_addStyle("div[data-test='player-end-carousel'] > div > div:first-child{width:100%} div._2Q3-3 {display:none}");
GM_addStyle(".__duowide_langs > :last-child {column-count:3} .__duowide_langs > :last-child > ul {max-height:none} .__duowide_friends a+div {position:absolute}");
GM_addStyle(".__duowide_achievs div._3jMdg {column-count:2} .__duowide_achievs li.f4TL7 {border:none; padding: 0 10px 25px 0} .__duowide_achievs h1._1Cjfg {margin-bottom: 30px !important}");

(function() {
    "use strict";
    let addStrengthenButton = function() {
        let c = document.querySelector("div.mAsUf");
        if(c === null || c.firstElementChild.dataset.test != "lingot-store-button") return;
        let a = document.querySelector("a[data-test='global-practice']");
        a.className = "_3FQrh _1uzK0 _3f25b _2arQ0 _3skMI _2ESN4";
        a.style.float = "right";
        a.innerHTML = "Practice";
        let p = a.cloneNode(true);
        p.onclick = function() { a.click(); return false; };
        c.replaceChild(p, c.firstChild);
    };
    let improveProfile = function() {
        if(document.querySelector("h1[data-test='profile-username']") == null) return;
        let d = document.querySelector("div.a5SW0");
        if(d === null || d.firstChild.textContent != "Languages") return;
        let e = d.nextElementSibling;
        let c = document.querySelector("div._3MT-S").firstChild;
        c.firstChild.classList.add("__duowide_achievs");
        d.className = "_2hEQd _1E3L7 __duowide_langs";
        e.className = "_2hEQd _1E3L7 __duowide_friends";
        let info = c.firstChild.firstChild.firstChild.firstChild;
        info.removeChild(info.lastChild);
        let a = document.createElement("div");
        a.className = "_2hEQd _1E3L7";
        a.innerHTML = "<div class=\"_2RO1n\"></div>";
        a.firstChild.appendChild(info);
        c.insertBefore(a, c.firstChild);
        c.insertBefore(d, c.lastChild);
        c.insertBefore(e, c.lastChild);
        let h = c.querySelector("h1._1Cjfg");
        if(h === null || h.textContent !== "Achievements") {
            info.parentNode.appendChild(c.children[1].firstChild);
            c.removeChild(c.children[1]);
        }
    };
    let keyEventListener = function(event) {
        if(['input', 'select', 'textarea'].indexOf(document.activeElement.tagName.toLowerCase()) !== -1) return;
        if(window.location.pathname === "/practice" || window.location.pathname.match(/^\/skill\/[^/]+\/[^/]+\//)) {
            switch(event.keyCode) {
                case 68:
                    let discussSentence = document.querySelector("div.PYCF5 > button:last-child");
                    if(discussSentence !== null) discussSentence.click();
                    return;
                case 81:
                    let quitButton = document.querySelector("div.Mlxjr > a._38taa._2Zfkq.cCL9P");
                    if(quitButton !== null) quitButton.click();
                    return;
            }
        }
        let tag = null;
        switch(event.keyCode) {
            case 78: /* N */ newLearningSession(); return;
            case 72: /* H */ tag = "home-nav"; break;
            case 87: /* W */ tag = "vocab-nav"; break;
            case 68: /* D */ tag = "discussion-nav"; break;
            case 76: /* L */ tag = "labs-nav"; break;
            case 80: /* P */ tag = "global-practice"; break;
            case 89: /* Y */ tag = "user-profile"; break;
            case 83: /* S */ tag = "sound-settings"; break;
        }
        let elem = document.querySelector("a[data-test='" + tag + "']");
        if(elem !== null) elem.click();
        else if(window.location.pathname === "/practice") {
            let practiceButton = document.querySelector("button[data-test='secondary-button']");
            let timedPracticeButton = document.querySelector("button[data-test='player-next']");
            if(event.keyCode == 80) practiceButton.click();
            else if(event.keyCode == 84) timedPracticeButton.click();
        }
    };
    let widenCommentSection = function() {
        if(window.location.pathname.startsWith("/comment/")) {
            document.querySelector("section.page-main.main-right").style.width = "initial";
        }
    };
    let checkForSettings = function() {
        let m = document.querySelector("div._3MT-S");
        if(m === null) return;
        let s = document.querySelector("div._2_lzu");
        if(window.location.pathname.startsWith("/settings")) {
            m.style.width = "auto";
            s.style.display = "block";
        } else {
            m.style.width = "100%";
            s.style.display = "none";
        }
    };
    let init = function() {
        document.addEventListener("keyup", keyEventListener);
    };
    let check = function() {
        widenCommentSection();
        improveProfile();
        addStrengthenButton();
        checkForSettings();
    };
    let newLearningSession = function() {
        if(window.location.pathname.startsWith("/skill/")) {
            let next = document.querySelector("a[data-test=begin-session-button]");
            if(next !== null) next.click();
            return;
        }
        let skills = Array.prototype.slice.call(document.querySelectorAll("a[data-test~=skill-tree-link]"));
        let toLearn = skills.filter(a => !a.dataset.test.includes("gold") && !a.dataset.test.includes("purple") && a.firstElementChild.childElementCount == 1);
        if(toLearn.length === 0) return;
        toLearn[0].click();
    };
    new MutationObserver(check).observe(document, {childList: true, subtree: true});
    init();
})();