您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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); } }