您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a space on the main page that reviews random burned items. This is a maintained fork of the original script by Samuel Harbord
当前为
// ==UserScript== // @name Wanikani Burn Reviews // @namespace wkburnreviewnew // @description Adds a space on the main page that reviews random burned items. This is a maintained fork of the original script by Samuel Harbord // @version 2.2.6 // @author Jonny Dark // @license Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0); http://creativecommons.org/licenses/by-nc/4.0/ // @include http://www.wanikani.com/ // @include https://www.wanikani.com/ // @include http://www.wanikani.com/dashboard // @include https://www.wanikani.com/dashboard // @require https://greasyfork.org/scripts/19781-wanakana/code/WanaKana.js?version=126349 // @grant none // @require http://code.jquery.com/jquery-1.12.4.min.js // Use site jquery and other variables // Todo fix this properly to work with Greasmonkey try { localStorage = unsafeWindow.localStorage; window = unsafeWindow; } catch {} // CONSTANTS var RADICAL = 0; var KANJI = 1; var VOCAB = 2; var UNDEFINED = -1; var MEANING = 0; var READING = 1; var DEBUG = 7; var WARNING = 8; var ERROR = 9; var LITEBLUE = "#00a0f1"; var PINK = "#f100a0"; var PURPLE = "#a000f1"; // Globals....ewww var BRLoggingEnabled = (localStorage.getItem("BRLoggingEnabled") == "true"); BRData = { Radicals: [], Kanji: [], Vocab: [] }; BRConfig = { RadicalsEnabled: true, KanjiEnabled: true, VocabEnabled: true }; BRQuestion = { Item : {}, askingFor : UNDEFINED, itemType : UNDEFINED, progress : 0, answered : false, IsRadical : function() { return this.itemType === RADICAL; }, IsKanji : function() { return this.itemType === KANJI; }, IsVocab : function() { return this.itemType === VOCAB; }, IsAskingForMeaning: function() { return this.askingFor === MEANING || this.IsRadical(); }, IsAskingForReading: function() { return this.askingFor === READING; }, IsAnswered : function() { return this.answered; }, SetAnswered: function(answered) { this.answered = answered; }, GetAnswers : function() { if (this.IsAskingForMeaning()) { return this.Item.meaning; } else { if (BRQuestion.IsKanji()) { var importantReading = BRQuestion.Item.important_reading; return BRQuestion.Item[importantReading]; } else { return BRQuestion.Item.kana; } } }, Started : function() { return this.progress > 0; }, IsComplete : function() { return (this.IsRadical() && this.Started()) || this.progress >= 2; }, Restart : function() { this.progress = 0; }, Skip : function() { this.progress = 2; }, NextPart : function() { this.progress++; this.askingFor = this.IsAskingForMeaning() ? READING : MEANING; }, DependingOnTypeUse : function (ifRadical, ifKanji, ifVocab) { return this.IsRadical() ? ifRadical : this.IsKanji() ? ifKanji : ifVocab; }, Reset : function() { this.askingFor = UNDEFINED; this.itemType = UNDEFINED; this.Item = {}; this.progress = 0; this.answered = false; } }; function BRLog(logdata, level) { level = (typeof level == "undefined") ? DEBUG : level; if (!BRLoggingEnabled && level < WARNING) return; if (!console) return; var logmethod = console.log.bind(console); if (typeof level !== "undefined" && level !== DEBUG) { logmethod = (level == WARNING ? console.warn.bind(console) : level == ERROR ? console.error.bind(console) : logmethod); } logmethod("WKBurnReview: " + logdata); if (typeof logdata != "string") { logmethod(logdata); } } window.BREnableLogging = function() { BRLoggingEnabled = true; localStorage.setItem("BRLoggingEnabled", true); }; window.BRDisableLogging = function() { BRLoggingEnabled = false; localStorage.removeItem("BRLoggingEnabled"); }; function getApiKeyThen(callback) { // First check if the API key is in local storage. var api_key = localStorage.getItem('apiKey'); if (typeof api_key === 'string' && api_key.length === 32) { return callback(api_key); } else { // We don't have the API key. Fetch it from the /settings/personal_access_tokens page. $.get('https://www.wanikani.com/settings/personal_access_tokens') .done(function(page) { if (typeof page !== 'string') return callback(null); // Extract the API key. api_key = $(page).find('#user_api_key').val(); if (typeof api_key == 'string' && api_key.length == 32) { // Store the updated user info. localStorage.setItem('apiKey', api_key); } else { BRLog("Failed to get API key :( instead got: '" + api_key + "'", ERROR); } return callback(api_key); }); } } function addBurnReviewStylesThen(callback) { if (stylesAlreadyAdded()) { BRLog("Styles already added, don't need to add again"); return callback(); } BRLog("Getting the review page stylesheet..."); $.ajax({url:"https://www.wanikani.com/review", dataType:"html"}).done( function(data) { BRLog("Got the review page document. Extracting styles"); var parser = new DOMParser(); var reviewsdoc = parser.parseFromString(data, "text/html"); var links = reviewsdoc.head.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { var link = links[i]; if (link.href.endsWith(".css")) { BRLog("Adding " + link.outerHTML + " to document head"); $("head").append(link); } } appendExternalBurnReviewStylesheetThen(callback); }); } function stylesAlreadyAdded() { return $('#burnReviewStyles').length > 0; } function appendExternalBurnReviewStylesheetThen(callback) { BRLog("Adding additional CSS"); // TODO - tie query string to release version var cssFile = "https://cdn.rawgit.com/jonnydark/wanikani-burn/master/BurnReviews.css?v=2.2"; $.get(cssFile, function(content) { $('head').append('<style id="burnReviewStyles"></style>'); $('#burnReviewStyles').text(content); callback(); }); } // This is for dumping CSS that must be present before loading main stylesheet function appendPriorityCSS() { var priorityStyles = '<style type="text/css">' + '.burn-review-container { float:left;}' + '#loadingBR { position: relative; background-color: #d4d4d4; margin-top: 0px; padding-top: 42px; height: 99px; }' + '#dim-overlay { position: fixed; background-color: black; opacity: 0.75; width: 100%; height: 100%; z-index: 1; margin-top: -122px; padding-bottom: 122px; display: none; }' + '</style>'; $(priorityStyles).appendTo($("head")); } function injectWidgetHtmlWrapper() { $(".low-percentage.kotoba-table-list.dashboard-sub-section").parent().wrap('<div class="col burn-review-container"></div>'); $("<br />" + wrapperHTML() + "<!-- span4 -->").insertAfter($(".low-percentage.kotoba-table-list.dashboard-sub-section")); setLanguage(); } function wrapperHTML() { var html = '<div class="">' + '<section class="burn-reviews kotoba-table-list dashboard-sub-section one-second-transition" style="z-index: 2; position: relative">' + '<h3 class="small-caps">' + '<span class="br-en">BURN REVIEWS</span>' + '<span class="br-jp">焦げた復習</span>' + '</h3>' + '<div id="loadingBR" align="center" style=""></div>' + '<div class="see-more" style="margin-top: -1px">' + '<a href="javascript:void(0)" id="new-item" class="small-caps">' + '<span class="br-en">NEW ITEM</span>' + '<span class="br-jp">新しい項目</span>' + '</a>' + '</div>' + '</section>' + '</div>'; return html; } function constructBurnReviewHtml() { BRLog("Constructing Burn Review HTML"); $("#user-response").attr("disabled", false).val("").focus(); $("body").prepend('<div id="dim-overlay"></div>'); BRLog("Overlay applied"); var strReview = '<div class="answer-exception-form" id="answer-exception" align="center">' + '<span>Answer goes here</span>' + '</div>' + '<div id="question" class="br-question">' + '<div class="item-toggle-buttons">' + '<div class="radicals-toggle' + ((BRConfig.RadicalsEnabled) ? ' on' : '') +'">' + '<span lang="ja">部</span>' + '</div>' + '<div class="kanji-toggle' + ((BRConfig.KanjiEnabled) ? ' on' : '') +'" style="padding-top: 1px">' + '<span lang="ja">漢</span>' + '</div>' + '<div class="vocab-toggle' + ((BRConfig.VocabEnabled) ? ' on' : '') +'">' + '<span lang="ja">語</span>' + '</div>' + '</div>' + '<div class="left-side-action-buttons">' + '<div class="load-button">' + '<span class="br-en" lang="ja">Load</span>' + '<span class="br-jp" lang="ja">ロード</span>' + '</div>' + '<div class="start-button-toggle' + ((localStorage.getItem('BRStartButton') !== null) ? ' on' : '') +'">' + '<span lang="ja" class="br-en">Start Button</span>' + '<span lang="ja" class="br-jp">開始<br />ボタン</span>' + '</div>' + '</div>' + '<div class="right-side-toggle-buttons">' + '<div class="toggle-language-button">' + '<span lang="ja" class="br-en">日本語</span>' + '<span lang="ja" class="br-jp">English</span>' + '</div>' + '<div class="resize-button">' + '<span lang="ja" class="br-en">Resize</span>' + '<span lang="ja" class="br-jp">拡大する</span>' + '</div>' + '</div>' + '<div class="review-item-container">' + '<span class="review-item" lang="ja">' + BRQuestion.Item.character +'</span>' + '</div>' + '<div id="question-type"><h1 id="question-type-text" align="center">' + getReviewTypeText() +'</h1></div>' + '<div id="answer-form" tabindex="10">' + '<form onSubmit="return false">' + '<fieldset>' + '<input autocapitalize="off" autocomplete="off" autocorrect="off" id="user-response" name="user-response" placeholder="Your Response" type="text"></input>' + '<button id="answer-button" type="button"><i class="icon-chevron-right"></i></button>' + '</fieldset>' + '</form>' + '</div>' + '</div>' + '</div>'; BRLog(strReview); $(strReview).insertAfter($(".burn-reviews.kotoba-table-list.dashboard-sub-section h3")); setLanguage(); } function rand(low, high) { return Math.floor(Math.random()*(high + 1)) + low; } function enableKanaInput() { wanakana.bind(document.getElementById('user-response')); } function disableKanaInput() { wanakana.unbind(document.getElementById('user-response')); } function nextQuestion() { BRLog("Getting burn review"); BRQuestion.NextPart(); BRQuestion.SetAnswered(false); $("#user-response").attr("disabled", false).val("").focus(); $(".answer-exception-form").css("display", "none"); if (BRQuestion.IsComplete()) { newBRItem(); updateBRItem(true); } configureInputForEnglishOrJapanese(); $("#question-type-text").html(getReviewTypeText()); setLanguage(); //TODO See if there's a way to bind this to jquery.html(); document.getElementById('user-response').value = ""; $("#answer-form fieldset").removeClass("correct").removeClass("incorrect"); } function getReviewTypeText() { var reviewTypeTextEng; var reviewTypeTextJp; if (BRQuestion.IsAskingForMeaning()) { reviewTypeTextEng = "Meaning"; reviewTypeTextJp = "意味"; } else { if (BRQuestion.Item.important_reading == "onyomi") { reviewTypeTextEng = "onyomi"; reviewTypeTextJp = "音"; } else { reviewTypeTextEng = "kunyomi"; reviewTypeTextJp = "訓"; } reviewTypeTextEng += " Reading"; reviewTypeTextJp += "読み"; } return '<span class="br-en">' + reviewTypeTextEng + '</span><span class="br-jp">' + reviewTypeTextJp + '</span>'; } function setLanguage() { var langToHide = BRLangJP ? ".br-en" : ".br-jp"; $(langToHide).addClass("br-hide"); } function newBRItem() { BRLog("Getting new burn item"); // Need to get a weighted Random var itemTypeArray = []; if (BRConfig.RadicalsEnabled) { itemTypeArray = itemTypeArray.concat(new Array(BRData.Radicals.length).fill(RADICAL)); } if (BRConfig.KanjiEnabled) { itemTypeArray = itemTypeArray.concat(new Array(BRData.Kanji.length).fill(KANJI)); } if (BRConfig.VocabEnabled) { itemTypeArray = itemTypeArray.concat(new Array(BRData.Vocab.length).fill(VOCAB)); } BRQuestion.itemType = itemTypeArray[rand(0, itemTypeArray.length)]; var dataBank = [BRData.Radicals, BRData.Kanji, BRData.Vocab][BRQuestion.itemType]; BRQuestion.ItemIndex = rand(0, dataBank.length - 1); BRQuestion.Item = dataBank[BRQuestion.ItemIndex]; BRQuestion.askingFor = BRQuestion.IsRadical() ? MEANING : rand(MEANING, READING); BRQuestion.Restart(); BRLog("Burn item type: " + BRQuestion.itemType); BRLog("Burn item: " + BRQuestion.Item); } function updateBRItem(updateText) { BRLog("Updating Burn review item"); if (updateText) { $(".review-item").html(BRQuestion.Item.character); setItemFontSize(); } var bg = BRQuestion.DependingOnTypeUse(LITEBLUE, PINK, PURPLE); var bgi = "linear-gradient(to bottom, "; bgi += BRQuestion.DependingOnTypeUse("#0af, #0093dd", "#f0a, #dd0093", "#a0f, #9300dd"); $(".review-item-container").css({"background-color": bg, "background-image": bgi }); } function setItemFontSize() { var itemLength = BRQuestion.Item.character.length; var fontSize = 48; switch(itemLength) { case 1: case 2: case 3: fontSize = 48; break; case 4: fontSize = 38; break; case 5: fontSize = 28; break; default: fontSize = 24; break; } $(".review-item").css("font-size", fontSize + "px"); } function skipItem() { BRQuestion.Skip(); nextQuestion(); return false; } function displayStartMessage() { var text = BRLangJP ? "開始" : "Start"; $("#loadingBR").html('<a lang="ja" href="javascript:void(0)" style="font-size: 52px; color: #434343; text-decoration: none">' + text + '</a>'); } function bindStartButtonClickEvent() { $("#loadingBR a").click(function() { startWaniKaniBurnReviews(); }); } function displayLoadingMessage(color, english, japanese) { $("#loadingBR").html('<h3 style="color:' + color + '">' + (BRLangJP ? japanese : english) + '</h3>'); } function displayRadicalLoadingMessage() { displayLoadingMessage(LITEBLUE, "Retrieving radical data...", "部首データを検索中…"); } function displayKanjiLoadingMessage() { displayLoadingMessage(PINK,"Retrieving kanji data...", "漢字データを検索中…"); } function displayVocabLoadingMessage() { displayLoadingMessage(PURPLE,"Retrieving vocabulary data...", "単語データを検索中…"); } function getRadicalCharacter(radical) { return radical.character ? radical.character : "<img class=\"radical-question\" src=\"" + radical.image + "\" />"; } function itemIsBurned(item) { return item.user_specific ? item.user_specific.burned : false; } function getMeaning(item) { var usyn = item.user_specific ? item.user_specific.user_synonyms : null; var meaning = item.meaning.split(', '); return usyn !== null ? meaning.concat(usyn) : meaning; } function fetchAndCacheBurnedRadicalsThen(callback) { fetchAndCacheBurnedItemsThen(callback, "radicals", "Radicals", "burnedRadicals", function(radical) { return { character : getRadicalCharacter(radical), meaning : getMeaning(radical) }; }); } function fetchAndCacheBurnedKanjiThen(callback) { fetchAndCacheBurnedItemsThen(callback, "kanji", "Kanji", "burnedKanji", function(kanji) { return { character : kanji.character, meaning : getMeaning(kanji), onyomi : kanji.onyomi ? kanji.onyomi.split(", ") : null, kunyomi : kanji.kunyomi ? kanji.kunyomi.split(", ") : null, important_reading : kanji.important_reading, }; }); } function fetchAndCacheBurnedVocabThen(callback) { fetchAndCacheBurnedItemsThen(callback, "vocabulary", "Vocab", "burnedVocab", function(vocab) { return { character : vocab.character, meaning : getMeaning(vocab), kana : vocab.kana.split(", "), }; }); } function fetchAndCacheBurnedItemsThen(callback, requestedResource, type, storageKey, mapFunction) { $.ajax({url:"https://www.wanikani.com/api/user/" + apiKey + "/" + requestedResource, dataType:"json"}) .done(function(response) { // vocabulary for some reason has everything in a child called general, kanji and radicals do not var requestData = response.requested_information.general ? response.requested_information.general : response.requested_information; var burnedItems = requestData.filter(itemIsBurned); BRData[type] = burnedItems.map(mapFunction); localStorage.setItem(storageKey, JSON.stringify(BRData[type])); callback(); }) .fail(function() { BRLog("Request to WaniKani API failed. Catastrophic failure ermagerd D:", ERROR); }); } function maybeGetBurnedItemsThen(callback, storageKey, type, fetchFunction) { var RawBRData = localStorage.getItem(storageKey); if (RawBRData !== null) { try { BRData[type] = JSON.parse(RawBRData); if (BRData[type].length > 0) { return callback(); } BRLog("No burned " + type + " in cache. Refectching...", WARNING); } catch(e) { BRLog("Could not parse cached radical data. Refetching...", WARNING); } } return fetchFunction(callback); } function maybeGetBurnedRadicalsThen(callback) { displayRadicalLoadingMessage(); maybeGetBurnedItemsThen(callback, "burnedRadicals", "Radicals", fetchAndCacheBurnedRadicalsThen); } function maybeGetBurnedKanjiThen(callback) { displayKanjiLoadingMessage(); maybeGetBurnedItemsThen(callback, "burnedKanji", "Kanji", fetchAndCacheBurnedKanjiThen); } function maybeGetBurnedVocabThen(callback) { displayVocabLoadingMessage(); maybeGetBurnedItemsThen(callback, "burnedVocab", "Vocab", fetchAndCacheBurnedVocabThen); } function getBurnReviewDataThen(callback) { BRLog("Getting WaniKana data"); maybeGetBurnedRadicalsThen(function() { maybeGetBurnedKanjiThen(function() { maybeGetBurnedVocabThen(function() { BRLog("Data items { RadicalData: " + BRData.Radicals.length + "; KanjiData: " + BRData.Kanji.length + "; VocabData: " + BRData.Vocab.length + "}"); callback(); }); }); }); } function clearBurnedItemData() { localStorage.removeItem("burnedRadicals"); localStorage.removeItem("burnedKanji"); localStorage.removeItem("burnedVocab"); BRData.Radicals = []; BRData.Kanji = []; BRData.Vocab = []; } function confirmResurrection() { $(".answer-exception-form").css({"display": "block", "opacity": "0", "-webkit-transform": "translateY(20px)", "-moz-transform": "translateY(20px)"}).removeClass("animated fadeInUp"); $(".answer-exception-form").addClass("animated fadeInUp"); var itemTypeForUrl = BRQuestion.DependingOnTypeUse("radicals/", "kanji/", "vocabulary/"); var resurrectionUrl = "https://www.wanikani.com/retired/" + itemTypeForUrl + BRQuestion.Item.character + "?resurrect=true"; var resurrectionLink = '<a href="' + resurrectionUrl + '" target="_blank" class="btn btn-mini resurrect-btn" data-method="put" rel="nofollow">'; var resurrectEng = '<div class="br-en">Are you sure you want to ' + resurrectionLink + 'Resurrect</a> the ' + BRQuestion.DependingOnTypeUse("radical", "kanji item", "vocabulary item") + ' "' + BRQuestion.Item.character + '"?</div>'; var resurrectJp = '<div class="br-jp">' + BRQuestion.DependingOnTypeUse("部首", "漢字", "単語") + "「" + BRQuestion.Item.character + "」を" + resurrectionLink + '復活</a>する<br />本当によろしいですか?</div>'; $(".answer-exception-form span").html(resurrectEng + resurrectJp); setLanguage(); document.getElementById("answer-exception").onclick = "return false"; return false; } function initBurnReviews() { BRLog("Initialising the Burn Review widget"); var loadStylesAndConstructWidget = function() { useCache = false; $("#loadingBR").remove(); addBurnReviewStylesThen(constructBurnReviewWidget); }; getBurnReviewDataThen(loadStylesAndConstructWidget); } function constructBurnReviewWidget() { BRLog("Getting new burn review item"); newBRItem(); BRLog("Adding burn review section"); constructBurnReviewHtml(); $("#answer-button").click(function() { submitBRAnswer(); }); updateBRItem(false); configureInputForEnglishOrJapanese(); bindMouseClickEvents(); } function configureInputForEnglishOrJapanese() { if (BRQuestion.IsAskingForMeaning()) { disableKanaInput(); $("#user-response").removeAttr("lang").attr("placeholder","Your Response"); $("#question-type").addClass("meaning"); $("#question-type").removeClass("reading"); } else { enableKanaInput(); $("#user-response").attr({lang:"ja",placeholder:"答え"}); $("#question-type").addClass("reading"); $("#question-type").removeClass("meaning"); } } function bindMouseClickEvents() { bindQuestionTypeToggleButtonClickEvents(); bindLoadButtonClickEvent(); bindStartButtonToggleButtonClickEvent(); bindLanguageToggleButtonClickEvent(); bindResizeButtonClickEvent(); bindDimOverlayClickEvent(); bindNewItemButtonClickEvent(); } function bindNewItemButtonClickEvent() { document.getElementById("new-item").onclick = skipItem; } function bindLanguageToggleButtonClickEvent() { $('.toggle-language-button').click(function() { switchBRLang(); }); } function resizeWidget() { if (!resizeWidget.complete) return; resizeWidget.complete = false; $('.resize-button').toggleClass("on"); $(".burn-reviews.kotoba-table-list.dashboard-sub-section").toggleClass("scale-up"); $("#dim-overlay").fadeToggle({ duration: 1000, complete: function() { resizeWidget.complete = true; } }); } resizeWidget.complete = true; function bindResizeButtonClickEvent() { $('.resize-button').click(function() { resizeWidget(); }); } function bindDimOverlayClickEvent() { $("#dim-overlay").click(function () { $('.resize-button').trigger("click"); }); } function bindLoadButtonClickEvent() { $(".load-button").click(function() { $("#dim-overlay").remove(); $(".burn-reviews").parent().remove(); BRQuestion.Reset(); queueBRAnim = false; allowQueueBRAnim = true; $(wrapperHTML()).insertAfter($(".low-percentage.kotoba-table-list.dashboard-sub-section").parent().next()); displayStartMessage(); clearBurnedItemData(); initBurnReviews(); }); } function bindStartButtonToggleButtonClickEvent() { $(".start-button-toggle").click(function() { $(this).toggleClass("on"); if ($(this).hasClass("on")) { localStorage.setItem("BRStartButton", true); } else { localStorage.removeItem("BRStartButton"); } }); } function bindQuestionTypeToggleButtonClickEvents() { bindRadicalsToggleButtonClickEvent(); bindKanjiToggleButtonClickEvent(); bindVocabToggleButtonClickEvent(); } function bindVocabToggleButtonClickEvent() { bindItemToggleButtonClickEvent('.vocab-toggle', "BRVocabEnabled", "VocabEnabled", BRQuestion.IsVocab.bind(BRQuestion)); } function bindKanjiToggleButtonClickEvent() { bindItemToggleButtonClickEvent('.kanji-toggle', "BRKanjiEnabled", "KanjiEnabled", BRQuestion.IsKanji.bind(BRQuestion)); } function bindRadicalsToggleButtonClickEvent() { bindItemToggleButtonClickEvent('.radicals-toggle', "BRRadicalsEnabled", "RadicalsEnabled", BRQuestion.IsRadical.bind(BRQuestion)); } function bindItemToggleButtonClickEvent(cssClass, storageKey, configKey, currentQuestionIsType) { $('.item-toggle-buttons ' + cssClass).click(function() { if ($(this).hasClass("on")) { // Don't let last button be disabled if ($('.item-toggle-buttons .on').length == 1) return; localStorage.setItem(storageKey, false); BRConfig[configKey] = false; if (currentQuestionIsType()) { skipItem(); } } else { localStorage.removeItem(storageKey); BRConfig[configKey] = true; } $(this).toggleClass("on"); }); } function switchBRLang() { if (!BRLangJP) { localStorage.setItem("BRLangJP", true); } else { localStorage.removeItem("BRLangJP"); } BRLangJP = !BRLangJP; $('.br-en,.br-jp').toggleClass('br-hide'); } function checkBurnReviewAnswer() { BRLog("Checking answer"); var response = $("#user-response").val().toLowerCase().trim(); response = BRQuestion.IsAskingForReading() ? addTerminalN(response) : response; var answers = BRQuestion.GetAnswers(); var answerIsCorrect = isAnswerCorrect(response, answers); $("#answer-form").focus(); // fix for FF to stop focus being trapped $("#user-response").attr("disabled", true); if (responseIsValid(response)) { if (isIncorrectReading(response, answerIsCorrect)) { shakeAnswerForm(); displayIncorrectReadingMessage(); $("#user-response").attr("disabled", false).focus(); } else { if (answerIsCorrect) { onCorrectAnswer(response); } else { onIncorrectAnswer(response); } BRQuestion.SetAnswered(true); } } else { shakeAnswerForm(); $("#user-response").attr("disabled", false).focus(); } } function addTerminalN(str = '') { return /n/i.test(str.slice(-1)) ? `${str.slice(0, -1)}ん` : str; } function isAnswerCorrect(response, answers) { for (var a = 0; a < answers.length; a++) { if (response == answers[a]) { return true; } } return false; } function shakeAnswerForm() { $('#answer-form').addClass('shake') .delay(1000) .queue(function(next) { $(this).removeClass('shake'); next(); }); } function setInputValue(text) { $("#user-response").val(text); } function onCorrectAnswer(answer) { $("#answer-form fieldset").removeClass("incorrect").addClass("correct"); setInputValue(answer); } function onIncorrectAnswer(answer) { $("#answer-form fieldset").removeClass("correct").addClass("incorrect"); setInputValue(answer); displayIncorrectAnswerMessage(); } function responseIsValid(response) { return ((BRQuestion.IsAskingForMeaning() && isAsciiPresent(response)) || (!isAsciiPresent(response) && BRQuestion.IsAskingForReading())) && response !== ""; } function displayIncorrectAnswerMessage() { // concat in to string of comma-separated answers var answerList = BRQuestion.GetAnswers().join(", "); var resurrectButton = '<a href="#" class="btn btn-mini resurrect-btn">'; var answerTextEng = '<div class="br-en">The answer was:<br />"' + answerList + '"<br />' + resurrectButton + 'Resurrect</a> this item?</div>'; var answerTextJp = '<div class="br-jp">解答は<br />「' + answerList + '」であった。<br />この項目を' + resurrectButton + '復活</a>したいか?</div>'; $('.answer-exception-form span').html(answerTextEng + answerTextJp); setLanguage(); $(".answer-exception-form").css({"display": "block"}).addClass("animated fadeInUp"); $('.resurrect-btn').on('click', confirmResurrection); } function isIncorrectReading(response, answerIsCorrect) { return (!answerIsCorrect && BRQuestion.IsKanji() && BRQuestion.IsAskingForReading() && ((BRQuestion.Item.important_reading == "onyomi" && compareKunyomiReading(response, BRQuestion.Item.kunyomi)) || (BRQuestion.Item.important_reading == "kunyomi" && response == BRQuestion.Item.onyomi))); } function displayIncorrectReadingMessage() { var incorrectReadingText = '<div class="br-en">Oops! You entered the wrong reading.</div>' + '<div class="br-jp">おっと、異なる読みを入力してしまった。</div>'; $(".answer-exception-form span").html(incorrectReadingText); setLanguage(); $(".answer-exception-form").css({"display": "block"}).addClass("animated fadeInUp").delay(5000).queue(function(){ $(this).addClass("fadeOut").dequeue().delay(800).queue(function(){ $(this).removeClass("fadeOut").css("display", "none").dequeue(); }); }); } function compareKunyomiReading(input, reading) { return (input == reading || input == reading.toString().substring(0, reading.indexOf(".")) || input == reading.toString().replace("*", input.substring(reading.indexOf(".") + 1)).replace(".", "")); } function submitBRAnswer() { if (!BRQuestion.IsAnswered()) { checkBurnReviewAnswer(); } else { nextQuestion(); } } function isAsciiPresent(e){ return (BRQuestion.IsAskingForMeaning()) ? !/[^a-z \-0-9]/i.test(e) : /[^ぁ-ー0-9 ]/.test(e); } function startWaniKaniBurnReviews() { if (!useCache) { clearBurnedItemData(); } BRLog("Loading..."); var checkReady = setInterval(function() { BRLog("Checking for wanakana..."); if (wanakana !== undefined) { clearInterval(checkReady); initBurnReviews(); } }, 250); } function pageIsDashboard() { return $('title').text().search("Dashboard") > 0; } function main() { if (!pageIsDashboard()) { BRLog("Script not running on dashboard, exiting..."); return; } getApiKeyThen(function(key) { if (key === null) { BRLog("Couldn't fetch API key. It's all gone Pete Tong. Cannot continue ;__;", ERROR); return; } apiKey = key; //global BRLog("Running!"); useCache = !(localStorage.getItem("burnedRadicals") === null || localStorage.getItem("burnedKanji") === null || localStorage.getItem("burnedVocab") === null); BRIsChrome = (navigator.userAgent.toLowerCase().indexOf('chrome') > -1); BRQuestion.Reset(); queueBRAnim = false; allowQueueBRAnim = true; BRLangJP = (localStorage.getItem("BRLangJP") == "true"); BRConfig.RadicalsEnabled = (localStorage.getItem("BRRadicalsEnabled") != "false"); BRConfig.KanjiEnabled = (localStorage.getItem("BRKanjiEnabled") != "false"); BRConfig.VocabEnabled = (localStorage.getItem("BRVocabEnabled") != "false"); String.prototype.trim = function() { return(this.replace(/^ +/,'').replace(/ +$/,'')); }; appendPriorityCSS(); injectWidgetHtmlWrapper(); displayStartMessage(); bindStartButtonClickEvent(); function submitOnEnterPress(event) { const isEnterKey = event.keyCode == 13; const isNotWkSearchInput = !event.target.matches('#query.search-query'); if(isNotWkSearchInput && isEnterKey) { BRLog("User pressed Enter"); submitBRAnswer(); } } $(document).unbind('keypress', submitOnEnterPress).bind('keypress', submitOnEnterPress); if (localStorage.getItem("BRStartButton") === null) { startWaniKaniBurnReviews(); } }); } if (document.readyState === 'complete') main(); else window.addEventListener("load", main, false); // ==/UserScript==