Jisho Mahou

12/28/2024, 12:50:00 PM

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name        Jisho Mahou
// @namespace   Violentmonkey Scripts
// @match       *://jisho.org/*
// @grant       GM_setClipboard
// @version     1.3
// @author      harrisonmg
// @description 12/28/2024, 12:50:00 PM
// @license     MIT
// ==/UserScript==

/// make entire search result list entries clickable ///

const selectedText = () => {
    var text = "";
    if (window.getSelection) {
        text = window.getSelection().toString();
    } else if (document.selection && document.selection.type != "Control") {
        text = document.selection.createRange().text;
    }
    return text;
}

for (const entry of document.querySelectorAll('.kanji_light, .concept_light, .sentence')) {
    const details = entry.querySelector('.light-details_link');
    if (details !== null) {
        entry.style.cursor = "pointer";

        entry.addEventListener("click", (event) => {
            // don't clobber clicks on existing links
            const anchor = event.target.tagName === "A";

            // don't trigger if the user is selecting text
            const selection = selectedText() !== "";

            if (!anchor && !selection) {
                entry.dataset.singleClicked = "true";

                // use a timeout to avoid triggering on double clicks
                // which might be for selecting text
                setTimeout(() => {
                    if (entry.dataset.singleClicked === "true") {
                        entry.dataset.singleClicked = "false";
                        details.click();
                    }
                }, 150);
            }
        });

        // use mousedown events to help detect double clicks
        entry.addEventListener("mousedown", () => {
            entry.dataset.singleClicked = "false";
        });
    }
}

/// click any kanji to go to that kanji's page ///

const isKanji = (char) => {
    const kanjiRegex = /[\u4E00-\u9FAF]/;
    return kanjiRegex.test(char);
}

let lastHighlighted = null;
let lastHighlightedBefore = null;
let lastHighlightedAfter = null;
let oldNode = null;

document.addEventListener('mousemove', (event) => {
    // remove highlighting from the last character
    if (lastHighlighted) {
        const parent = lastHighlighted.parentNode;

        parent.removeChild(lastHighlightedBefore);
        parent.removeChild(lastHighlightedAfter);
        parent.replaceChild(oldNode, lastHighlighted);

        lastHighlighted = null;
        lastHighlightedBefore = null;
        lastHighlightedAfter = null;
        oldNode = null;
    }

    // try to avoid activating while selecting text
    if (event.buttons > 0) return;

    // get char under cursor
    const caretPosition = document.caretPositionFromPoint(event.clientX, event.clientY);
    if (caretPosition && caretPosition.offsetNode.nodeType === Node.TEXT_NODE) {
        const textNode = caretPosition.offsetNode;

        // don't break radical search
        if (textNode.parentNode.classList.contains("radical")) return;

        const textContent = textNode.textContent;

        // don't clobber existing links
        const parent = textNode.parentNode;
        if (parent.tagName === 'A') return;

        let charIndex = caretPosition.offset;

        if (charIndex >= textContent.length) {
            charIndex = textContent.length - 1;
        }

        let char = textContent[charIndex];

        // not perfect the best for getting under cursor
        if (charIndex > 0 && (!isKanji(char) || char === "undefined")) {
            --charIndex;
        }

        char = textContent[charIndex];

        // only apply to kanji
        if (!isKanji(char)) return;

        oldNode = textNode.cloneNode(true);

        // make span for highlighted char
        const span = document.createElement('a');
        span.style.color = '#909dc0';
        span.href = `https://jisho.org/search/${encodeURIComponent(char)} %23kanji`;
        span.style.textDecoration = 'none';
        span.textContent = char;

        // split the text node around the char
        const beforeText = textContent.slice(0, charIndex);
        const afterText = textContent.slice(charIndex + 1);

        const beforeNode = document.createTextNode(beforeText)
        const afterNode = document.createTextNode(afterText)

        // replace with highlighted char
        parent.insertBefore(beforeNode, textNode);
        parent.insertBefore(span, textNode);
        parent.insertBefore(afterNode, textNode);
        parent.removeChild(textNode);

        lastHighlightedBefore = beforeNode;
        lastHighlighted = span;
        lastHighlightedAfter = afterNode;
    }
});

// ctrl+c copies kanji under cursor
document.addEventListener('keydown', (event) => {
    if (event.ctrlKey && event.key === 'c' && lastHighlighted) {
        GM_setClipboard(lastHighlighted.textContent);
    }
});