您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show when next review will become available on hover and automatically enable review button
当前为
// ==UserScript== // @name WaniKani Review Button Auto Enable and Hover Details // @description Show when next review will become available on hover and automatically enable review button // @author Nekosuki // @namespace https://www.wanikani.com/users/Nekosuki // @version 1.0.2 // @include /^https://(www|preview).wanikani.com/ // @grant none // ==/UserScript== (function(wkof, $) { "use strict"; if (!wkof) { const response = confirm("WaniKani Lesson Hover Details script requires WaniKani Open Framework.\n Click 'OK' to be forwarded to installation instructions."); if (response) { window.location.href = "https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549"; } return; } const menuReviewButtonSelector = ".navigation .navigation-shortcut--reviews"; const dashboardReviewButtonSelector = "a.lessons-and-reviews__reviews-button"; const dashboardClassPrefix = "lessons-and-reviews__reviews-button--"; const dashboardClassReviewCounts = [0, 1, 50, 100, 250, 500, 1000]; const dashboardButtonPopoverOffset = 12; const popoverConfig = { html: true, animation: false, placement: "bottom", trigger: "hover", template: "<div class='popover review-time' style='transform: translate(0, 100px)'><div class='arrow'></div><div class='popover-content'></div></div>", content: () => popoverText, }; let nextReviewCount; let nextReviewDate; let popoverText; let updateInterval; offsetDashboardButtonPopover(); fetchData(); function offsetDashboardButtonPopover() { const dashboardButton = $(dashboardReviewButtonSelector); if (dashboardButton.length === 0) { return; } const popoverParent = dashboardButton.parent().get(0); const dashboardReviewMutationObserver = new MutationObserver(mutations => { const popover = mutations[0].addedNodes[0]; if (popover !== undefined) { popover.style.top = `${popover.offsetTop + dashboardButtonPopoverOffset}px`; } }); dashboardReviewMutationObserver.observe(popoverParent, { childList: true }); } function fetchData() { wkof.include("Apiv2"); wkof.ready("Apiv2").then(() => { wkof.Apiv2.get_endpoint("summary").then(processData); }); } function processData(summary) { const { next_reviews_at, reviews } = summary; nextReviewCount = reviews.find(review => review.available_at === next_reviews_at).subject_ids.length; nextReviewDate = new Date(next_reviews_at); updateInterval = setInterval(updatePeriodically, 1000); setupPopovers(); } function setupPopovers() { const elements = $([menuReviewButtonSelector, dashboardReviewButtonSelector]); if (elements.length > 0) { elements.popover(popoverConfig); } else { clearInterval(updateInterval); } } function updatePeriodically() { const nextReviewAvailable = nextReviewDate < new Date(); updatePopover(nextReviewAvailable); updateButtons(nextReviewAvailable); if (nextReviewAvailable) { clearInterval(updateInterval); } } function updatePopover(reviewAvailable) { if (reviewAvailable) { popoverText = `<strong>${nextReviewCount}</strong> available now`; } else { popoverText = `+<strong>${nextReviewCount}</strong> ${relativeTimeToNextReview()}`; } } function updateButtons(reviewAvailable) { if (!reviewAvailable) { return; } const dashboardButton = $(dashboardReviewButtonSelector); if (dashboardButton.length > 0 && dashboardButton.hasClass(`${dashboardClassPrefix}0`)) { dashboardButton.removeClass(`${dashboardClassPrefix}0`); const dashboardClassReviewCount = dashboardClassReviewCounts.reverse().find(c => c <= nextReviewCount); dashboardButton.addClass(`${dashboardClassPrefix}${dashboardClassReviewCount}`); dashboardButton.find("span").text(nextReviewCount); } const menuButton = $(menuReviewButtonSelector); if (menuButton.length > 0 && +menuButton.attr("data-count") === 0) { menuButton.attr("data-count", nextReviewCount); menuButton.find("span").text(nextReviewCount); } } function relativeTimeToNextReview() { const seconds = Math.round((nextReviewDate - new Date()) / 1000); if (seconds < 45) { return "in a few seconds"; } const stages = [ { unit: "minute", factor: 60, threshold: 0.25 }, { unit: "hour", factor: 60, threshold: 0.25 }, { unit: "day", factor: 24, threshold: 0.1 }, { unit: "month", factor: 30, threshold: 0.15 }, { unit: "year", factor: 12, threshold: 0.1 }, ]; let measure = seconds; let unit; for (const stage of stages) { stage.measure = measure / stage.factor; stage.measure += stage.measure < 1 ? stage.threshold : 0.5; stage.measure = Math.floor(stage.measure); if (stage.measure === 0) { break; } measure = stage.measure; unit = stage.unit; } let time = "in "; if (measure === 1) { time += `a${unit.startsWith("h") ? "n" : ""} ${unit}`; } else { time += `${measure} ${unit}s`; } return time; } })(window.wkof, window.jQuery);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址