您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Display detailed level progress.
当前为
// ==UserScript== // @name WaniKani Dashboard Progress Plus // @namespace rfindley // @description Display detailed level progress. // @version 1.0.0 // @author Robin Findley // @copyright 2015+, Robin Findley // @license MIT; http://opensource.org/licenses/MIT // @include https://www.wanikani.com/ // @include https://www.wanikani.com/dashboard // @run-at document-end // @grant none // ==/UserScript== //==[ History ]====================================================== // 1.0.0 - Initial release. //=================================================================== var dlog_level = 1; function dlog(level) { if (level > dlog_level) return; if (!console || typeof console.log !== 'function') return; var args = Array.prototype.slice.call(arguments); args.shift(); console.log.apply(console,args); } //=================================================================== window.wkdpp = {}; window.wkdpp.radical_data = []; window.wkdpp.kanji_data = []; var progress_png = '.wkdpp-progress {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJwAAAAnCAYAAAD6tSH7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoyNjY0MTY4NzY1RUFFNDExOUE4OERFMDQ5OThDNEVFNiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo4RDU0MjUxQUVENzAxMUU0QTFFMDhGNEI3QzRCMUM2NSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4RDU0MjUxOUVENzAxMUU0QTFFMDhGNEI3QzRCMUM2NSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkVEQkNDNzgxNzBFREU0MTE5QjJFQzRERDc3QUZGN0I5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjI2NjQxNjg3NjVFQUU0MTE5QTg4REUwNDk5OEM0RUU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+NKKUkQAAAjtJREFUeNrsXLFOAkEU3CPGHilpiMSEji8wgYrGa/X3bKXF/kz8AjoTIqGxVHub8714JIbIAedmd97tTDIUl91k8D3OG/YNWVmWziMK5xdTavOms0C41nFEmwHVbPrChmOzBb3GhmOzBb125vmNzoRdYV84FI6EY2EPoAipaSsQGzDzbBr+wqXwWjgRDiI+mKekDfZuF6LhtrgS3ghzbXSQorZVG+y/1pANt8Wt8E54AVTUtmmjafiFufBe+AH4sN0WbbCmIZZLXQgfhCVgYduiDdI0dCJ/YhegXytY1wbZbA7gpOFRuAEtbBu08aRhByvhE2hRrWujadiDZ+E7aGGtaqNpqMFauAQtqmVtNA01eHG4sKiNpuEAXoGLalkbTcMevAEX1ao2moYafAIX1aK2ZMaTmuLLhT+b/C92x8Jn1ftA1EfTYAhdz+tCaKNpMIy+53UhtdE0GMTQ87pQ2mgajGLkeV0IbTxpMAod8x4fuXZcrUfRRtNgEJopODbI0qvWI2ijaTAIzRJMTtwzqfahaKNpMAQNrgxO3DOo9iFoo2kwBA2s5A335tX+mNpoGgxBi6npqKzh/qzan0fWlmwQ2tqd7ZQoXh00XaWBl3lkbckGodENQtOwcR30j6uBF80grCJoYxAaDL5+TuEQNu4ng6Bj4etA2iCf41JquHMX/8dsNIOgY+E6qavDkzrPth0x8qkN1jSk1HCFSwdTx5MGItKHiycNRNA7HVQDsuHYbDxpINrZbPryLcAAR3upHUQO964AAAAASUVORK5CYII=");background-position-x:39px;background-repeat:no-repeat;}'+ '.wkdpp-progress[data-srs-lvl="10"] {background-position-x:-117px;}'+ '.wkdpp-progress[data-srs-lvl="1"] {background-position-x:39px;}'+ '.wkdpp-progress[data-srs-lvl="2"] {background-position-x:0px;}'+ '.wkdpp-progress[data-srs-lvl="3"] {background-position-x:-39px;}'+ '.wkdpp-progress[data-srs-lvl="4"] {background-position-x:-78px;}'+ '.wkdpp-progress[data-srs-lvl="5"] {background-position-x:39px;background-color:#a035ba !important;}'+ '.wkdpp-progress[data-srs-lvl="6"] {background-position-x:-39px;background-color:#a035ba !important;}'+ '.wkdpp-progress[data-srs-lvl="7"] {background-position-x:39px;background-color:#4866e0 !important;}'+ '.wkdpp-progress[data-srs-lvl="8"] {background-position-x:39px;background-color:#00a3f5 !important;}'+ '.wkdpp-progress[data-srs-lvl="9"] {background-position-x:39px;background-color:#505050 !important;}'; //------------------------------------------------------------------- // Add a <style> section to the document. //------------------------------------------------------------------- function addStyle(aCss) { var head, style; head = document.getElementsByTagName('head')[0]; if (head) { style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.textContent = aCss; head.appendChild(style); return style; } return null; } //------------------------------------------------------------------- // Get the user's API Key. //------------------------------------------------------------------- function get_api_key() { var done = $.Deferred(); // First check if the API key is in local storage. var api_key = localStorage.getItem('apiKey'); if (api_key && api_key.length == 32) return done.resolve(); // We don't have the API key. Fetch it from the /account page. dlog(1,'wkdpp: Fetching api_key'); $.get('/account') .done(function(page){ // Make sure what we got is a web page. if (typeof page !== 'string') {return done.reject()} // Extract the API key. var api_key = $(page).find('#api-button').parent().find('input').attr('value'); if (typeof api_key !== 'string' || api_key.length !== 32) {return done.reject()} // Store the updated user info. localStorage.setItem('apiKey', apiKey); // Return success. done.resolve(); }) .fail(function(){ // Failed to get web page. done.reject(); }); return done.promise(); } //------------------------------------------------------------------- // Populate level info from API. //------------------------------------------------------------------- function populate_level_info() { // Grab the user's current level. var user_level = parseInt($('.dropdown.levels>a>span').text()); // Request kanji information. $.getJSON('/api/user/'+window.wkdata.user.api_key+'/kanji/'+user_level) .done(function(data){ // Check if we got an API error. if (data.hasOwnProperty('error')) { dlog(1,'wkdpp: API Error - '+data.error.message); return; } $.each(data.requested_information, function(i, e) { window.wkdpp.kanji_data.push(e); }); update_progress('kanji'); }); // Request radicals information. $.getJSON('/api/user/'+window.wkdata.user.api_key+'/radicals/'+user_level) .done(function(data){ // Check if we got an API error. if (data.hasOwnProperty('error')) { dlog(1,'wkdpp: API Error - '+data.error.message); return; } $.each(data.requested_information, function(i, e) { window.wkdpp.radical_data.push(e); }); update_progress('radicals'); }); } //------------------------------------------------------------------- // Print date in pretty format. //------------------------------------------------------------------- function formatDate(d){ var s = ''; var now = new Date(); var YY = d.getFullYear(), MM = d.getMonth(), DD = d.getDate(), hh = d.getHours(), mm = d.getMinutes(), one_day = 24*60*60*1000; var same_day = ((YY == now.getFullYear()) && (MM == now.getMonth()) && (DD == now.getDate()) ? 1 : 0); // If today: "Today 8:15pm" // otherwise: "Wed, Apr 15, 8:15pm" if (same_day) { s += 'Today '; } else { s += ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][d.getDay()]+', '+ ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][MM]+' '+DD+', '; } s += (((hh+11)%12)+1)+':'+('0'+mm).slice(-2)+['am','pm'][Math.floor(d.getHours()/12)]; // Append "(X days)". if (!same_day) s += ' ('+(Math.floor(d.getTime()/one_day)-Math.floor(now.getTime()/one_day))+' days)'; return s; } //------------------------------------------------------------------- // Capitalize all words in a string. //------------------------------------------------------------------- function capitalize_words(string) { return string.replace(/\b\w+\b/g,function(w){return w.charAt(0).toUpperCase()+w.slice(1);}); } //------------------------------------------------------------------- // Update the dashboard info. //------------------------------------------------------------------- function update_progress(type) { var ul; var arr; // Fetch container element, remove existing elements, and select data source. if (type==='radicals') { ul = $('.radicals-progress .lattice-single-character>ul'); arr = window.wkdpp.radical_data; } else { ul = $('.kanji-progress .lattice-single-character>ul'); arr = window.wkdpp.kanji_data; } var li_proto = ul.children().first().clone(); ul.children().remove(); // Sort items by srs level, then by character or meaning. arr.sort(function(a,b){ var a_srs = (a.user_specific ? a.user_specific.srs_numeric : 10); var b_srs = (b.user_specific ? b.user_specific.srs_numeric : 10); if (a_srs < b_srs) return -1; if (a_srs > b_srs) return 1; if (a.meaning < b.meaning) return -1; if (a.meaning > b.meaning) return 1; return 0; }); // Populate item data. var renum = 0; $.each(arr, function(idx, data){ var li; var a; var span; // Populate id, class, href, and text. li = li_proto.clone(); a = li.find('>a'); a.addClass('wkdpp-progress'); if (type==='radicals') { li.attr('id', 'radical-x'+renum); a.attr('href','/radicals/'+data.meaning); if (data.character) { a.text(data.character); } else { a.text('<i class="radical-'+data.meaning.replace(' ','-')+'"></i>'); } } else { li.attr('id', 'kanji-x'+renum); a.attr('href','/kanji/'+encodeURIComponent(data.character)); a.text(data.character); } // Populate 'data-srs-lvl', which is a styling selector. var srs = (data.user_specific ? data.user_specific.srs_numeric : 10); a.attr('data-srs-lvl', srs); // Populate the next review date. var next = ''; if (data.user_specific && data.user_specific.available_date) { var date = formatDate(new Date(data.user_specific.available_date*1000)); next = '<br><span style="font-size:75%;font-weight:bold;">Next: '+date+'</span>'; } // Populate remaining data for popup window. var percent = 0; var correct; var total; if (type==='radicals') { a.attr('data-original-title', capitalize_words(data.meaning)+next); if (data.user_specific) { correct = data.user_specific.meaning_correct; total = correct+data.user_specific.meaning_incorrect; if (total > 0) percent = 100.0*correct/total; } } else { a.attr('data-original-title', capitalize_words(data.meaning)+'<br><span lang="ja">'+data[data.important_reading]+'</span>'+next); if (data.user_specific) { correct = data.user_specific.meaning_correct+data.user_specific.reading_correct; total = correct+data.user_specific.meaning_incorrect+data.user_specific.reading_incorrect; if (total > 0) percent = 100.0*correct/total; } } a.attr('data-content', '<div class="progress"><div class="bar full" style="width: '+Math.max(percent,15)+'%;">'+percent+'%</div></div>'); ul.append(li); }); // WaniKani function to add popover. // InfoTip.popoverLattice(); if (type==='radicals') { arr = $(".radicals-progress [rel=auto-popover]"); } else { arr = $(".kanji-progress [rel=auto-popover]"); } arr.popover({ html:!0, animation:!1, trigger:"hover", placement:function(e,t){var n,r;return r=window.innerWidth,n=$(t).offset().left,r<500?"bottom":r-n>400?"right":"left"}, template:'<div class="popover lattice"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>' }); } //------------------------------------------------------------------- // main() - Runs after page is done loading. //------------------------------------------------------------------- function main() { addStyle(progress_png); // Set up a sequence of deferred actions, so we can // control asynchronous flow in a more readable manner. $.Deferred() .resolve() .then(get_api_key) .then(populate_level_info); } //------------------------------------------------------------------- // Run main() upon load. //------------------------------------------------------------------- window.addEventListener("load", main, false);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址