WaniKani Hint Button

Button that shows a part of the answer when hovered and shows more when clicked.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         WaniKani Hint Button
// @namespace    wk-showhint
// @version      1.0
// @description  Button that shows a part of the answer when hovered and shows more when clicked.
// @author       Jiftoo
// @include      http://www.wanikani.com/review/session*
// @include      https://www.wanikani.com/review/session*
// @grant        GM_addStyle
// @grant        unsafeWindow
// ==/UserScript==

/* jshint esversion: 6 */
(function () {
	"use strict";

	const $ = unsafeWindow.$;
	if (!$) {
		throw new Error("jquеry's $ is not defined. Hint button is disabled.");
	}
	if (!CSS.supports("display", "flex")) {
		throw new Error("Flexbox is not supported. Hint button is disabled.");
	}

	const buttonList = document.querySelector("#additional-content > ul");

	const textSpan = document.createElement("span");
	textSpan.id = "hint-option-span";
	textSpan.innerText = "Hover for hint";
	textSpan.title = "pog";
	const setHint = (str) => {
		textSpan.title = str;
	};

	const templateItem = buttonList.children[0].cloneNode();
	templateItem.id = "option-hint";
	templateItem.appendChild(textSpan);
	const hintCallback = (ev) => {
		// 'text-span' doesn't work; currentTarget only works when called as callback.
		const hintEl = textSpan; //document.getElementById("hint-option-span");

		const advanceHint = (hint) => {
			// Increment hint advance by one or set it to one
			// Attribute converted to number using +(...)
			// 'data-adv' can't be null because it's set to '0' in 'resetHintSpan'
			console.assert(hintEl.getAttribute("data-adv") !== null);
			const nextAdv = +hintEl.getAttribute("data-adv") + 1;
			hintEl.setAttribute("data-adv", nextAdv);

			const hintSlice = hint.slice(0, nextAdv);
			setHint(`${hintSlice}${hintSlice.length !== hint.length ? "..." : ""}`);
		};
		// Wanikani uses it internally.
		const {rad, kan, voc, en, kana, emph, on, kun} = $.jStorage.get("currentItem");
		const firstEn = en[0];
		const type = $.jStorage.get("questionType");
		if (type === "reading") {
			if (rad) {
				advanceHint(rad);
			} else if (kan) {
				if (emph === "onyomi") {
					advanceHint(on[0]);
				} else {
					// kunyomi
					advanceHint(kun[0]);
				}
			} else if (voc) {
				advanceHint(kana[0]);
			}
		} else {
			// It must be 'meaning'
			advanceHint(firstEn);
		}
	};
	const resetHintSpan = () => {
		textSpan.setAttribute("data-adv", 0);
		hintCallback();
	};

	templateItem.onclick = hintCallback;
	buttonList.appendChild(templateItem);

	// Reset hint when submitting
	// Set a small timeout to let the old item update before getting values for hint
	const resetCallback = (ev) => {
		if (ev === undefined || ev.key === "Enter") {
			setTimeout(() => resetHintSpan(), 50);
		}
	};
	const keyListenerFix = ({code}) => {
		if (code === "Enter") {
			resetCallback();
		}
	};
	document.querySelector("#user-response ~ button").addEventListener(
		"click",
		() => {
			resetCallback();
		},
		true
	);
	$(document).on("keydown.reviewScreen", resetCallback);

	GM_addStyle(`#additional-content ul {display: flex; justify-content: space-around;}`);
	GM_addStyle(`#additional-content ul li {width: 0 !important; flex-grow: 1;}`);

	// Observe loading screen style to detect loading
	let loadingScreen = document.getElementById("loading");
	let observer = new MutationObserver((mutations) => {
		for (let mutation of mutations) {
			if (mutation.type == "attributes" && mutation.target.style.display === "none") {
				console.log("finished loading!");

				// Initialise first hint.
				resetHintSpan();

				observer.disconnect();
				observer = undefined;
				break;
			}
		}
	});
	observer.observe(loadingScreen, {
		attributes: true,
	});
})();