您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Adds delay when you answered incorrectly so you have time to look at your answer again, and spot any typos
当前为
// ==UserScript== // @name WaniKani wrong answer delay // @namespace http://tampermonkey.net/ // @version 0.20 alpha // @description Adds delay when you answered incorrectly so you have time to look at your answer again, and spot any typos // @author cometzero // @include https://www.wanikani.com/review/session // @include http://www.wanikani.com/review/session // @grant none // ==/UserScript== /** * How long does user have to wait when he answered wrong */ var waitTime = 1000; /** * Speed of the animation in FPS */ var FPS = 100; var interval = 1000 / FPS; /** * Enables or disables log messages */ var DEBUG = false; (function() { 'use strict'; // init observer onSetUserResponseDisabled(); onIncorrectAnswerObserver(function(){ log("Wrong answer!"); disableNextOne(); // animate user wait time var timesRun = 0; var intervalId = setInterval(function(){ if(timesRun > waitTime / interval){ clearInterval(intervalId); enableNextOne(); setDelayProgress(1); }else{ var progress = timesRun / waitTime * interval; setDelayProgress(progress); } timesRun += 1; }, interval); }); // listens for option-item-info click and shortcut key 'F' and than calls showItemInfo // since it will not open by itself while in delay state $("#option-item-info").click(function() { showItemInfo(); }); $(document).on("keydown.reviewScreen", function(n) { if(n.keyCode == 70) { // letfter 'F' showItemInfo(); } }); })(); /** * Shows item info while the user waits * The problem is that show item info wont open by itself since disabled attribute is not set. * So in order to open it we need to set disabled attribute and than trigger click so that WaniKani js click * function is called again. * isDisabled must be set to false so that "onSetUserResponseDisabled" will not automatically set disabled attribute. */ function showItemInfo(){ if(isDisabled){ isDisabled = false; $("#user-response").prop("disabled", true); $("#option-item-info").trigger("click"); $("#user-response").prop("disabled", false); isDisabled = true; } } /** * Create div overlay that will be displayed when user is waiting to be able to go to the next letter */ function createOverlay(){ var overlay = $("<div></div>"); overlay.css("height", "100%"); overlay.css("width", "0%"); overlay.css("position", "absolute"); overlay.css("background-color", "rgba(255, 0, 51, 0.30)"); overlay.css("top", "0"); overlay.css("left", "0"); $("#user-response").parent().append(overlay); return overlay; } // overlay is created only once and than saved in this variable var overlay; /** * Show user how much time it has to wait * @param {progress} progress between 0 .. 1. 1 means it is completed */ function setDelayProgress(progress){ // if overlay doesn't exist creat it if(!overlay){ overlay = createOverlay(); } overlay.css("width", (100-progress*100) + "%"); overlay.css("left", (progress*50) + "%"); var trans = Math.min(0.40, 1-progress); overlay.css("background-color", "rgba(255, 0, 51, "+trans+")"); } /** * Enables user to proceed to next leter */ function enableNextOne(){ _enableNextOne(true); } /** * Disables user to proceed to next letter */ function disableNextOne(){ _enableNextOne(false); } var isDisabled = false; // is user currently able to go to the next letter? function _enableNextOne(enable){ log("Enable next one: " + enable); isDisabled = !enable; // if "user-response <input>" is not disabled than it will not go to the next letter // this is just how the wanikani works. // Since input is not disabled we have to set pointer-events to none so that user cannot input anything $("#user-response").prop("enabled", !enable); $("#user-response").prop("disabled", enable); $("#user-response").css("pointer-events", enable? "" : "none"); } /** * Set observer that is called every time user answered incorrectly * @param {function} function that is called user answered incorrectly */ function onIncorrectAnswerObserver(f){ MutationObserver = window.MutationObserver || window.WebKitMutationObserver; var observer = new MutationObserver(function(mutations, observer) { mutations.forEach(function(mutation) { // check if it has class name set as "incorrect" if(mutation.attributeName == "class" && mutation.target.className == "incorrect"){ f(); } }); }); // configuration of the observer: var config = {attributes: true, attributeOldValue: true }; // we have to select parent since it is the one that gets class changed var target = document.getElementById("user-response").parentElement; // pass in the target node, as well as the observer options observer.observe(target, config); } /** * When user response is not disabled and user presses enter wanikani will automatically disabled it * That means that user can proceed to the next letter. */ function onSetUserResponseDisabled(){ MutationObserver = window.MutationObserver || window.WebKitMutationObserver; var observer = new MutationObserver(function(mutations, observer) { mutations.forEach(function(mutation) { // check if it has class name set as "incorrect" if(isDisabled && mutation.attributeName == "disabled"){ $("#user-response").prop("disabled", false); } }); }); // configuration of the observer: var config = {attributes: true, attributeOldValue: true }; // we have to select parent since it is the one that gets class changed var target = document.getElementById("user-response"); // pass in the target node, as well as the observer options observer.observe(target, config); } function log(logMessage){ if(DEBUG){ console.log(logMessage); } }