// ==UserScript==
// @name WaniKani Open Framework Statistics Filters
// @namespace https://www.wanikani.com
// @description Additional statistics filters for the WaniKani Open Framework
// @author prouleau
// @version 1.5.0
// @match https://www.wanikani.com/*
// @license MIT; http://opensource.org/licenses/MIT
// @grant none
// ==/UserScript==
(function(wkof) {
'use strict';
var wkofMinimumVersion = '1.0.52';
if (!wkof) {
var response = confirm('WaniKani Open Framework Date Filters 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;
}
var settingsDialog;
var settingsScriptId = 'statsFilters';
var settingsTitle = 'Statistics Filters';
var needToRegisterFilters = true;
var filterNamePrefix = 'statsFilters_';
var leechLteqFilterName = filterNamePrefix + 'LeechLteq';
var meaningCorAnsLteqFilterName = filterNamePrefix + 'meaningCorAnsLteq';
var meaningCorAnsGteqFilterName = filterNamePrefix + 'meaningCorAnsGteq';
var readingCorAnsLteqFilterName = filterNamePrefix + 'readingCorAnsLteq';
var readingCorAnsGteqFilterName = filterNamePrefix + 'readingCorAnsGteq';
var meaningIncorAnsLteqFilterName = filterNamePrefix + 'meaningIncorAnsLteq';
var meaningIncorAnsGteqFilterName = filterNamePrefix + 'meaningIncorAnsGteq';
var readingIncorAnsLteqFilterName = filterNamePrefix + 'readingIncorAnsLteq';
var readingIncorAnsGteqFilterName = filterNamePrefix + 'readingIncorAnsGteq';
var totalCorAnsLteqFilterName = filterNamePrefix + 'totalCorAnsLteq';
var totalCorAnsGteqFilterName = filterNamePrefix + 'totalCorAnsGteq';
var totalIncorAnsLteqFilterName = filterNamePrefix + 'totalIncorAnsLteq';
var totalIncorAnsGteqFilterName = filterNamePrefix + 'totalIncorAnsGteq';
var percentageTotalCorLteqFilterName = filterNamePrefix + 'percentageTotalCorLteq';
var percentageTotalCorGteqFilterName = filterNamePrefix + 'percentageTotalCorGteq';
var percentageMeaningCorLteqFilterName = filterNamePrefix + 'pecentagerMeaningCorLteq';
var percentageMeaningCorGteqFilterName = filterNamePrefix + 'percentageMeaningCorGteq';
var percentageReadingCorLteqFilterName = filterNamePrefix + 'percentageReadingCorLteq';
var percentageReadingCorGteqFilterName = filterNamePrefix + 'percentageReadingCorGteq';
var meaningCurStrLteqFilterName = filterNamePrefix + 'meaningCurStrLteq';
var meaningCurStrGteqFilterName = filterNamePrefix + 'meaningCurStrGteq';
var meaningMaxStrLteqFilterName = filterNamePrefix + 'meaningMaxStrLteq';
var meaningMaxStrGteqFilterName = filterNamePrefix + 'meaningMaxStrGteq';
var readingCurStrLteqFilterName = filterNamePrefix + 'readingCurStrLteq';
var readingCurStrGteqFilterName = filterNamePrefix + 'readingCurStrGteq';
var readingMaxStrLteqFilterName = filterNamePrefix + 'readingMaxStrLteq';
var readingMaxStrGteqFilterName = filterNamePrefix + 'readingMaxStrGteq';
var bothCurStrLteqFilterName = filterNamePrefix + 'bothCurStrLteq';
var bothCurStrGteqFilterName = filterNamePrefix + 'bothCurStrGteq';
var minCurStrLteqFilterName = filterNamePrefix + 'minCurStrLteq';
var minCurStrGteqFilterName = filterNamePrefix + 'minCurStrGteq';
var numReviewsLteqFilterName = filterNamePrefix + 'numReviewsLteq';
var numReviewGteqFilterName = filterNamePrefix + 'numReviewsGteq';
var supportedFilters = [leechLteqFilterName, meaningCorAnsLteqFilterName, meaningCorAnsGteqFilterName, readingCorAnsLteqFilterName, readingCorAnsGteqFilterName,
meaningIncorAnsLteqFilterName, meaningIncorAnsGteqFilterName, readingIncorAnsLteqFilterName, readingIncorAnsGteqFilterName,
totalCorAnsLteqFilterName, totalCorAnsGteqFilterName, totalIncorAnsLteqFilterName, totalIncorAnsGteqFilterName,
percentageTotalCorLteqFilterName, percentageTotalCorGteqFilterName, percentageMeaningCorLteqFilterName, percentageMeaningCorGteqFilterName,
percentageReadingCorLteqFilterName, percentageReadingCorGteqFilterName, meaningCurStrLteqFilterName, meaningCurStrGteqFilterName,
meaningMaxStrLteqFilterName, meaningMaxStrGteqFilterName, readingCurStrLteqFilterName, readingCurStrGteqFilterName,
readingMaxStrLteqFilterName, readingMaxStrGteqFilterName, bothCurStrLteqFilterName, bothCurStrGteqFilterName,
minCurStrLteqFilterName, minCurStrGteqFilterName, numReviewsLteqFilterName, numReviewGteqFilterName];
function updateFiltersWhenReady() {
wkof.set_state(settingsScriptId, 'loading');
needToRegisterFilters = true;
waitForItemDataRegistry().then(registerFilters);
}
function waitForItemDataRegistry() {
return wkof.wait_state('wkof.ItemData.registry', 'ready');
}
function registerFilters() {
if (!needToRegisterFilters) {
return;
}
supportedFilters.forEach(function(filterName) {
delete wkof.ItemData.registry.sources.wk_items.filters[filterName];
});
registerLeechLteqFilter();
registerMeaningCorAnsGteqFilter();
registerMeaningCorAnsLteqFilter();
registerReadingCorAnsGteqFilter();
registerReadingCorAnsLteqFilter();
registerMeaningIncorAnsGteqFilter();
registerMeaningIncorAnsLteqFilter();
registerReadingIncorAnsGteqFilter();
registerReadingIncorAnsLteqFilter();
registerTotalCorAnsGteqFilter();
registerTotalCorAnsLteqFilter();
registerTotalIncorAnsGteqFilter();
registerTotalIncorAnsLteqFilter();
registerPercentageTotalCorGteqFilter();
registerPercentageTotalCorLteqFilter();
registerPercentageMeaningCorGteqFilter();
registerPercentageMeaningCorLteqFilter();
registerPercentageReadingCorGteqFilter();
registerPercentageReadingCorLteqFilter();
registerMeaningCurStrGteqFilter();
registerMeaningCurStrLteqFilter();
registerMeaningMaxStrGteqFilter();
registerMeaningMaxStrLteqFilter();
registerReadingCurStrGteqFilter();
registerReadingCurStrLteqFilter();
registerReadingMaxStrGteqFilter();
registerReadingMaxStrLteqFilter();
registerBothCurStrGteqFilter();
registerBothCurStrLteqFilter();
registerMinCurStrGteqFilter();
registerMinCurStrLteqFilter();
registerNumberReviewsGteqFilter();
registerNumberReviewsLteqFilter();
needToRegisterFilters = false;
wkof.set_state(settingsScriptId, 'ready');
}
// BEGIN Leech
let leechLteqHover_tip = 'Select items that have a leech value less than or equal to the stated value.';
function registerLeechLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[leechLteqFilterName] = {
type: 'number',
label: 'Leech value <=',
default: 10,
filter_func: leechLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: leechLteqHover_tip,
};
}
function leechLteqFilter(filterValue, item) {
if (item.review_statistics === undefined) {
return false;
}
var reviewStats = item.review_statistics;
var meaningScore = getLeechScore(reviewStats.meaning_incorrect, reviewStats.meaning_current_streak);
var readingScore = getLeechScore(reviewStats.reading_incorrect, reviewStats.reading_current_streak);
return meaningScore <= filterValue && readingScore <= filterValue;
}
// Leech scores a rounded because otherwise the behavior of the filter is not consistent with rounded values presented to users in scripts.
// In other words, data would be not filtered when based on user facing data it appears that it should be.
function getLeechScore(incorrect, currentStreak) {
return Math.round((incorrect / Math.pow((currentStreak || 0.5), 1.5)) * 100) / 100;
}
// END Leech
// BEGIN Meaning correct answers
let meaningCorAnsGteqFilterHover_tip = 'Selects items where the number of correct\nanswers for Meaning is >= this value.';
let meaningCorAnsLteqFilterHover_tip = 'Selects items where the number of correct\nanswers for Meaning is <= this value.';
function registerMeaningCorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningCorAnsGteqFilterName] = {
type: 'number',
label: 'Meaning Cor. Ans. >=',
default: 0,
filter_func: meaningCorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningCorAnsGteqFilterHover_tip,
};
}
function meaningCorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_correct >= filterValue;
}
function registerMeaningCorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningCorAnsLteqFilterName] = {
type: 'number',
label: 'Meaning Cor. Ans. <=',
default: 100,
filter_func: meaningCorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningCorAnsLteqFilterHover_tip,
};
}
function meaningCorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
};
return review_statistics.meaning_correct <= filterValue;
};
// END Meaning correct answers
// BEGIN Reading correct answers
let readingCorAnsGteqFilterHover_tip = 'Selects items where the number of correct\nanswers for Reading is >= this value.';
let readingCorAnsLteqFilterHover_tip = 'Selects items where the number of correct\nanswers for Reading is <= this value.';
function registerReadingCorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingCorAnsGteqFilterName] = {
type: 'number',
label: 'Reading Cor. Ans. >=',
default: 0,
filter_func: readingCorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingCorAnsGteqFilterHover_tip,
};
};
function readingCorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
};
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
};
return review_statistics.reading_correct >= filterValue;
};
function registerReadingCorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingCorAnsLteqFilterName] = {
type: 'number',
label: 'Reading Cor. Ans. <=',
default: 100,
filter_func: readingCorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingCorAnsLteqFilterHover_tip,
};
}
function readingCorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_correct <= filterValue;
}
// END Reading correct answers
// BEGIN Meaning incorrect answers
let meaningIncorAnsGteqFilterHover_tip = 'Selects items where the number of incorrect\nanswers for Meaning is >= this value.';
let meaningIncorAnsLteqFilterHover_tip = 'Selects items where the number of incorrect\nanswers for Meaning is <= this value.';
function registerMeaningIncorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningIncorAnsGteqFilterName] = {
type: 'number',
label: 'Meaning Incor. Ans. >=',
default: 0,
filter_func: meaningIncorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningIncorAnsGteqFilterHover_tip,
};
}
function meaningIncorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_incorrect >= filterValue;
}
function registerMeaningIncorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningIncorAnsLteqFilterName] = {
type: 'number',
label: 'Meaning Incor. Ans. <=',
default: 100,
filter_func: meaningIncorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningIncorAnsLteqFilterHover_tip,
};
}
function meaningIncorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_incorrect <= filterValue;
}
// END Meaning incorrect answers
// BEGIN Reading incorrect answers
let readingIncorAnsGteqFilterHover_tip = 'Selects items where the number of incorrect\nanswers for Reading is >= this value.';
let readingIncorAnsLteqFilterHover_tip = 'Selects items where the number of incorrect\nanswers for Reading is <= this value.';
function registerReadingIncorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingIncorAnsGteqFilterName] = {
type: 'number',
label: 'Reading Incor. Ans. >=',
default: 0,
filter_func: readingIncorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingIncorAnsGteqFilterHover_tip,
};
}
function readingIncorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_incorrect >= filterValue;
}
function registerReadingIncorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingIncorAnsLteqFilterName] = {
type: 'number',
label: 'Reading Incor. Ans. <=',
default: 100,
filter_func: readingIncorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingIncorAnsLteqFilterHover_tip,
};
}
function readingIncorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_incorrect <= filterValue;
}
// END Reading incorrect answers
// BEGIN Total correct answers
let totalCorAnsGteqFilterHover_tip = 'Selects items where the total number\nof correct answers is >= this value.';
let totalCorAnsLteqFilterHover_tip = 'Selects items where the total number\nof correct answers is <= this value.';
function registerTotalCorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[totalCorAnsGteqFilterName] = {
type: 'number',
label: 'Total Cor. Ans. >=',
default: 0,
filter_func: totalCorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: totalCorAnsGteqFilterHover_tip,
};
}
function totalCorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_correct >= filterValue;
}
return review_statistics.meaning_correct + review_statistics.reading_correct >= filterValue;
}
function registerTotalCorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[totalCorAnsLteqFilterName] = {
type: 'number',
label: 'Total Cor. Ans. <=',
default: 100,
filter_func: totalCorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: totalCorAnsLteqFilterHover_tip,
};
}
function totalCorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_correct <= filterValue;
}
return review_statistics.meaning_correct + review_statistics.reading_correct <= filterValue;
}
// END Total correct answers
// BEGIN Number of reviews
// The number of reviews is always equal to the total correct answers because
// you need to answer correctly exactly once to terminate a review
// Therefore this is the same filters as Total correct answer with a different user
// interface to inform the user of what they are doing
let numberReviewsGteqFilterHover_tip = 'Selects items where the total number\nof reviews is >= this value.';
let numberReviewsLteqFilterHover_tip = 'Selects items where the total number\nof reviews is <= this value.';
function registerNumberReviewsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[numReviewGteqFilterName] = {
type: 'number',
label: 'Number of Reviews >=',
default: 0,
filter_func: totalCorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: numberReviewsGteqFilterHover_tip,
};
}
function registerNumberReviewsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[numReviewsLteqFilterName] = {
type: 'number',
label: 'Number of Reviews <=',
default: 100,
filter_func: totalCorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: numberReviewsLteqFilterHover_tip,
};
}
// END Number of reviews
// BEGIN Total incorrect answers
let totalIncorAnsGteqFilterHover_tip = 'Selects items where the total number\nof incorrect answers is >= this value.';
let totalIncorAnsLteqFilterHover_tip = 'Selects items where the total number\nof incorrect answers is <= this value.';
function registerTotalIncorAnsGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[totalIncorAnsGteqFilterName] = {
type: 'number',
label: 'Total Incor. Ans. >=',
default: 0,
filter_func: totalIncorAnsGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: totalIncorAnsGteqFilterHover_tip,
};
}
function totalIncorAnsGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_incorrect >= filterValue;
}
return review_statistics.meaning_incorrect + review_statistics.reading_incorrect >= filterValue;
}
function registerTotalIncorAnsLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[totalIncorAnsLteqFilterName] = {
type: 'number',
label: 'Total Incor. Ans. <=',
default: 100,
filter_func: totalIncorAnsLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: totalIncorAnsLteqFilterHover_tip,
};
}
function totalIncorAnsLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_incorrect <= filterValue;
}
return review_statistics.meaning_incorrect + review_statistics.reading_incorrect <= filterValue;
}
// END Total incorrect answers
//==============================================
// Percentages filters
//
// Needs rounding because otherwise user facing data is usually floored and inconsistencies in displayed data will occur
// Flooring is used instead of rounding because otherwise we could have 100% correct while missing some answers due to rounding
function percentageRounding(value){return Math.floor(value * 100)};
// BEGIN Percentage Total Correct
let percentageTotalCorGteqFilterHover_tip = 'Selects items where % of correct answers\non Total is >= this value.';
let percentageTotalCorLteqFilterHover_tip = 'Selects items where % of correct answers\non Total is <= this value.';
function registerPercentageTotalCorGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageTotalCorGteqFilterName] = {
type: 'number',
label: '%Total Correct >=',
default: 0,
filter_func: percentageTotalCorGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageTotalCorGteqFilterHover_tip,
};
}
function percentageTotalCorGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.percentage_correct >= filterValue;
}
function registerPercentageTotalCorLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageTotalCorLteqFilterName] = {
type: 'number',
label: '%Total Correct <=',
default: 100,
filter_func: percentageTotalCorLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageTotalCorLteqFilterHover_tip,
};
}
function percentageTotalCorLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.percentage_correct <= filterValue;
}
// END Percentage Total Correct
// BEGIN Percentage Meaning Correct
let percentageMeaningCorGteqFilterHover_tip = 'Selects items where % of correct answers\non Meaning is >= this value.';
let percentageMeaningCorLteqFilterHover_tip = 'Selects items where % of correct answers\non Meaning is <= this value.';
function registerPercentageMeaningCorGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageMeaningCorGteqFilterName] = {
type: 'number',
label: '%Meaning Correct >=',
default: 0,
filter_func: percentageMeaningCorGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageMeaningCorGteqFilterHover_tip,
};
}
function percentageMeaningCorGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return percentageRounding(review_statistics.meaning_correct / (review_statistics.meaning_correct + review_statistics.meaning_incorrect)) >= filterValue;
}
function registerPercentageMeaningCorLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageMeaningCorLteqFilterName] = {
type: 'number',
label: '%Meaning Correct <=',
default: 100,
filter_func: percentageMeaningCorLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageMeaningCorLteqFilterHover_tip,
};
}
function percentageMeaningCorLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return percentageRounding(review_statistics.meaning_correct / (review_statistics.meaning_correct + review_statistics.meaning_incorrect)) <= filterValue;
}
// END Percentage Meaning Correct
// BEGIN Percentage Reading Correct
let percentageReadingCorGteqFilterHover_tip = 'Selects items where % of correct answers\non Reading is >= this value.';
let percentageReadingCorLteqFilterHover_tip = 'Selects items where % of correct answers\non Reading is <= this value.';
function registerPercentageReadingCorGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageReadingCorGteqFilterName] = {
type: 'number',
label: '%Reading Correct >=',
default: 0,
filter_func: percentageReadingCorGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageReadingCorGteqFilterHover_tip,
};
}
function percentageReadingCorGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return percentageRounding(review_statistics.reading_correct / (review_statistics.reading_correct + review_statistics.reading_incorrect)) >= filterValue;
}
function registerPercentageReadingCorLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[percentageReadingCorLteqFilterName] = {
type: 'number',
label: '%Reading Correct <=',
default: 100,
filter_func: percentageReadingCorLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: percentageReadingCorLteqFilterHover_tip,
};
}
function percentageReadingCorLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return percentageRounding(review_statistics.reading_correct / (review_statistics.reading_correct + review_statistics.reading_incorrect)) <= filterValue;
}
// END Percentage Reading Correct
//======================================================
// Streak Filters
//
// Wanikani starts the streak count at 1, that is when the last review is failed, the streak is 1, not 0.
// User facing data is adjusted in Item Inspector to start the streak count at 0 because starting at 1 is not intuitive.
// The filters do so too because the filter value in the settings panel is also user facing data that may be correlated with Item Inspector data.
// This is done by adjusting the filter value through passing streakValueAdjustment to the filter_value_map: registering option.
// This adjustment is not made in leech calculations because a- this use of streaks is not user facing data - and b- there is an history of
// calculating leech values this way and it would be disruptive to change it.
function streakValueAdjustment(param){return param + 1};
// BEGIN Meaning Current Streak
let meaningCurStrGteqFilterHover_tip = 'Selects items where current Meaning streak is >= this value.';
let meaningCurStrLteqFilterHover_tip = 'Selects items where current Meaning streak is <= this value.';
function registerMeaningCurStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningCurStrGteqFilterName] = {
type: 'number',
label: 'Meaning Cur. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: meaningCurStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningCurStrGteqFilterHover_tip,
};
}
function meaningCurStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_current_streak >= filterValue;
}
function registerMeaningCurStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningCurStrLteqFilterName] = {
type: 'number',
label: 'Meaning Cur. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: meaningCurStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningCurStrLteqFilterHover_tip,
};
}
function meaningCurStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_current_streak <= filterValue;
}
// END Meaning Current Streak
// BEGIN Meaning Maximum Streak
let meaningMaxStrGteqFilterHover_tip = 'Selects items where maximum Meaning streak is >= this value.';
let meaningMaxStrLteqFilterHover_tip = 'Selects items where maximum Meaning streak is <= this value.';
function registerMeaningMaxStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningMaxStrGteqFilterName] = {
type: 'number',
label: 'Meaning Max. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: meaningMaxStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningMaxStrGteqFilterHover_tip,
};
}
function meaningMaxStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_max_streak >= filterValue;
}
function registerMeaningMaxStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[meaningMaxStrLteqFilterName] = {
type: 'number',
label: 'Meaning Max. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: meaningMaxStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: meaningMaxStrLteqFilterHover_tip,
};
}
function meaningMaxStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
return review_statistics.meaning_max_streak <= filterValue;
}
// END Meaning Maximum Streak
// BEGIN Reading Current Streak
let readingCurStrGteqFilterHover_tip = 'Selects items where current Reading streak is >= this value.';
let readingCurStrLteqFilterHover_tip = 'Selects items where current Reading streak is <= this value.';
function registerReadingCurStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingCurStrGteqFilterName] = {
type: 'number',
label: 'Reading Cur. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: readingCurStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingCurStrGteqFilterHover_tip,
};
}
function readingCurStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_current_streak >= filterValue;
}
function registerReadingCurStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingCurStrLteqFilterName] = {
type: 'number',
label: 'Reading Cur. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: readingCurStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingCurStrLteqFilterHover_tip,
};
}
function readingCurStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_current_streak <= filterValue;
}
// END Reading Current Streak
// BEGIN Reading Maximum Streak
let readingMaxStrGteqFilterHover_tip = 'Selects items where maximum Reading streak is >= this value.';
let readingMaxStrLteqFilterHover_tip = 'Selects items where maximum Reading streak is <= this value.';
function registerReadingMaxStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingMaxStrGteqFilterName] = {
type: 'number',
label: 'Reading Max. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: readingMaxStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingMaxStrGteqFilterHover_tip,
};
}
function readingMaxStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_max_streak >= filterValue;
}
function registerReadingMaxStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[readingMaxStrLteqFilterName] = {
type: 'number',
label: 'Reading Max. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: readingMaxStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: readingMaxStrLteqFilterHover_tip,
};
}
function readingMaxStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return true;
}
return review_statistics.reading_max_streak <= filterValue;
}
// END Reading Maximum Streak
// BEGIN Both Current Streaks
let bothCurStrGteqFilterHover_tip = 'Selects items where both current Meaning streak\nand current Reading streak are >= this value.';
let bothCurStrLteqFilterHover_tip = 'Selects items where both current Meaning streak\nand current Reading streak are <= this value.';
function registerBothCurStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[bothCurStrGteqFilterName] = {
type: 'number',
label: 'Both Cur. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: bothCurStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: bothCurStrGteqFilterHover_tip,
};
}
function bothCurStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_current_streak >= filterValue;
} else {
return review_statistics.meaning_current_streak >= filterValue && review_statistics.reading_current_streak >= filterValue;
}
}
function registerBothCurStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[bothCurStrLteqFilterName] = {
type: 'number',
label: 'Both Cur. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: bothCurStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: bothCurStrLteqFilterHover_tip,
};
}
function bothCurStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_current_streak <= filterValue;
} else {
return review_statistics.meaning_current_streak <= filterValue && review_statistics.reading_current_streak <= filterValue;
}
}
// END Both Current Streaks
// BEGIN Minimum Current Streaks
let minCurStrGteqFilterHover_tip = 'Selects items where the minimum of current Meaning streak\nand current Reading streak is >= this value.';
let minCurStrLteqFilterHover_tip = 'Selects items where the minimum of current Meaning streak\nand current Reading streak is <= this value.';
function registerMinCurStrGteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[minCurStrGteqFilterName] = {
type: 'number',
label: 'Minimum Cur. Str. >=',
default: 0,
filter_value_map: streakValueAdjustment,
filter_func: minCurStrGteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: minCurStrGteqFilterHover_tip,
};
}
function minCurStrGteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_current_streak >= filterValue;
} else {
return review_statistics.meaning_current_streak >= filterValue && review_statistics.reading_current_streak >= filterValue;
};
}
function registerMinCurStrLteqFilter() {
wkof.ItemData.registry.sources.wk_items.filters[minCurStrLteqFilterName] = {
type: 'number',
label: 'Minimum Cur. Str. <=',
default: 100,
filter_value_map: streakValueAdjustment,
filter_func: minCurStrLteqFilter,
set_options: function(options) { options.review_statistics = true; },
hover_tip: minCurStrLteqFilterHover_tip,
};
}
function minCurStrLteqFilter(filterValue, item) {
let review_statistics = item.review_statistics;
if (review_statistics === undefined) {
return false;
}
if (item.object === 'radical' || item.object === 'kana_vocabulary'){
return review_statistics.meaning_current_streak <= filterValue;
} else {
return review_statistics.meaning_current_streak <= filterValue || review_statistics.reading_current_streak <= filterValue;
}
}
// END Minimum Current Streaks
updateFiltersWhenReady();
})(window.wkof);