// ==UserScript==
// @name WaniKani Item Inspector
// @namespace wk-dashboard-item-inspector
// @description Inspect Items in Tabular Format
// @author prouleau
// @version 1.4.0
// @include https://www.wanikani.com/dashboard
// @include https://www.wanikani.com/
// @grant none
// ==/UserScript==
(function() {
'use strict';
//------------------------------
// Wanikani Framework
//------------------------------
if (!window.wkof) {
let response = confirm('WaniKani Dashboard Leech List 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 config = {
wk_items: {
options: {
review_statistics: true
},
filters: {
level: '1..+0', //only retrieve items from lv 1 up to and including current level
srs: {value: 'lock, init, burn', invert: true} //exlude locked, initial and burned items
}
}
};
var quiz_setup_state = 'init';
function open_settings_dialog() {
wkof.Settings.load('Item_Inspector')
.then(function(){
quiz_setup_state = 'ready';
init_settings();
})
open_quiz_settings();
}
//------------------------------
// Styling
//------------------------------
var leechTableCss = `
.noLeeches {
margin: 0 0 20px 0;
}
.radicalCharacterImgSize {
font-size: 12px;
}
/* Control Bar */
.WkitControlBar {
margin: 7px 0.6% 7px 2.6%;
}
/* to prevent rendering problems */
.WkitTopBar {
display: inline-block;
width: 103%;
margin-left: -29px;
}
.WkitClipBoard {
display: inline-block;
width: 96%;
height: 420px;
margin-left: 29px;
}
.WkitHeader {
background-color: LightGray;
height: 40px;
border-radius: 5px;
}
.WkitTitle {
font-size: 150%;
padding-right: 320px;
text-align: center;
}
.WkitButton {
display: inline;
float: left;
border-width: 1px;
border-radius: 3px;
margin: 5px;
margin-top: 8px;
}
.WkitSelector {
display: inline;
float: left;
margin-right: 5px;
margin-left: 5px;
margin-top: 5px;
border-width: 1px;
border-color: Black;
color: Black;
background-color: LightGray;
}
.emptyMessage {
margin: 7px 0.6% 7px 2.6%;
padding: 5px;
padding-left: 15px;
padding-top: 10px;
background-color: Azure;
border-radius: 8px;
}
/* TOOL TIPS */
.WkisTooltip {
position: relative;
display: inline-block;
}
.WkisTooltip .WkisTooltipContent {
display: none;
visibility: hidden;
background-color: black;
color: #fff;
font-size: 100%;
width: max-content;
text-align: left;
margin: 5px;
padding: 5px;
border-radius: 3px;
position: absolute;
bottom: 30px;
left: 0%;
z-index: 1;
}
.WkisTooltip:hover div.WkisTooltipContent {
visibility: visible;
display: inline-block;
z-index: 50;
}
.WkisTooltip .WkisTooltipContent::after {
content: " ";
position: absolute;
top: 100%; /* At the bottom of the tooltip */
left: 1em;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: black transparent transparent transparent;
}
.WkisLabel, {
width: max-content;
padding: 4px;
}
.WkisTipValue {
width: max-content;
padding: 4px;
}
/* END TOOL TIPS
/*makes space*/
#leech-table:after{
clear: none;
}
#leaderboard:after{
clear: none;
}`;
var leechStyling = document.createElement('style');
leechStyling.type='text/css';
if(leechStyling.styleSheet){
leechStyling.styleSheet.cssText = leechTableCss;
}else{
leechStyling.appendChild(document.createTextNode(leechTableCss));
}
document.getElementsByTagName('head')[0].appendChild(leechStyling);
//------------------------------
// Menu
//------------------------------
var settings_dialog;
function install_menu() {
wkof.Menu.insert_script_link({
script_id: 'Item_Inspector',
name: 'Item_Inspector',
submenu: 'Settings',
title: 'Item Inspector',
on_click: open_settings_dialog
});
}
//------------------------------
// Settings - new version
//------------------------------
//########################################################################
// QUIZ DATA
//########################################################################
var quiz = {
// Dialogs
dialog: null,
settings_dialog: null,
// Item Lists
items: [],
group_list: [],
serial_list: [],
index: null,
// Status
showing_help: false,
mode: 'loading',
// Question Info
qinfo: {
load: null,
prep: null,
cache: {},
},
// Stats
stats: {
round: 1,
total: 0,
correct: 0,
incorrect: 0,
},
// Functions
start: null,
shuffle: null,
requiz: null,
ask: null,
submit: null,
prev: null,
next: null,
close: null,
};
//########################################################################
// QUIZ SETTINGS DIALOG
//########################################################################
//========================================================================
// setup_quiz_settings()
//------------------------------------------------------------------------
var quiz_settings_state = 'init';
function setup_quiz_settings() {
if (quiz_settings_state === 'init') {
quiz_settings_state = 'loading';
return wkof.ready('Settings')
.then(function(){
quiz_settings_state = 'setup';
setup_quiz_settings();
});
}
if (quiz_settings_state !== 'setup') return;
let tableElementContents = {'Meaning_Brief':'Meaning Brief', 'Meaning_Full':'Meaning Full',
'Reading_Brief':'Reading Brief', 'Reading_Full':'Reading Full', 'Leech':'Leach Value',
'Meaning_Correct_Answers': 'Meaning Correct Answers', 'Meaning_Incorrect_Answers': 'Meaning Incorrect Answers',
'Reading_Correct_Answers': 'Reading Correct Answers', 'Reading_Incorrect_Answers': 'Reading Incorrect Answers',
'Total_Correct_Answers': 'Total Correct Answers','Total_Incorrect_Answers': 'Total Incorrect Answers',
'Percentage_Correct': 'Percentage Correct Total','Meaning_Correct': 'Percentage Correct Meaning','Reading_Correct': 'Percentage Correct Reading',
'Meaning_Current_Streak' : 'Meaning Current Streak', 'Reading_Current_Streak': 'Reading Current Streak',
'Meaning_Max_Streak' : 'Meaning Maximum Streak', 'Reading_Max_Streak': 'Reading Maximum Streak',
'Level':'Level',
'Srs':'SRS Stage', 'Review_Date':'Review Date', 'Review_Wait':'Review Wait Time',
'Passed_Date':'Passed Guru Date', 'Burned_Date':'Burned Date', 'Resurrected_Date': 'Resurrected Date',
'Lesson_Date':'Lesson Date', 'Unlock_Date': 'Unlock Date'};
let dataElementContents = {'None':'None', 'Meaning_Brief':'Meaning Brief', 'Meaning_Full':'Meaning Full',
'Reading_Brief':'Reading Brief', 'Reading_Full':'Reading Full', 'Leech':'Leach Value',
'Meaning_Correct_Answers': 'Meaning Correct Answers', 'Reading_Correct_Answers': 'Reading Correct Answers',
'Meaning_Incorrect_Answers': 'Meaning Incorrect Answers', 'Reading_Incorrect_Answers': 'Reading Incorrect Answers',
'Total_Correct_Answers': 'Total Correct Answers','Total_Incorrect_Answers': 'Total Incorrect Answers',
'Percentage_Correct': 'Percentage Correct Total','Meaning_Correct': 'Percentage Correct Meaning','Reading_Correct': 'Percentage Correct Reading',
'Meaning_Current_Streak' : 'Meaning Current Streak', 'Reading_Current_Streak': 'Reading Current Streak',
'Meaning_Max_Streak' : 'Meaning Maximum Streak', 'Reading_Max_Streak': 'Reading Maximum Streak',
'Level':'Level',
'Srs':'SRS Stage', 'Review_Date':'Review Date', 'Review_Wait':'Review Wait Time',
'Passed_Date':'Passed Guru Date', 'Burned_Date':'Burned Date', 'Resurrected_Date': 'Resurrected Date',
'Lesson_Date':'Lesson Date', 'Unlock_Date': 'Unlock Date'};
let sortElementContents = {'Default':'Default', 'Meaning_Brief':'Meaning Brief', 'Meaning_Full':'Meaning Full',
'Reading_Brief':'Reading Brief', 'Reading_Full':'Reading Full', 'Leech':'Leach Value',
'Meaning_Correct_Answers': 'Meaning Correct Answers', 'Reading_Correct_Answers': 'Reading Correct Answers',
'Meaning_Incorrect_Answers': 'Meaning Incorrect Answers', 'Reading_Incorrect_Answers': 'Reading Incorrect Answers',
'Total_Correct_Answers': 'Total Correct Answers','Total_Incorrect_Answers': 'Total Incorrect Answers',
'Percentage_Correct': 'Percentage Correct Total','Meaning_Correct': 'Percentage Correct Meaning','Reading_Correct': 'Percentage Correct Reading',
'Meaning_Current_Streak' : 'Meaning Current Streak', 'Reading_Current_Streak': 'Reading Current Streak',
'Meaning_Max_Streak' : 'Meaning Maximum Streak', 'Reading_Max_Streak': 'Reading Maximum Streak',
'Level':'Level',
'Srs':'SRS Stage', 'Review_Date':'Review Date', 'Review_Wait':'Review Wait Time',
'Passed_Date':'Passed Guru Date', 'Burned_Date':'Burned Date', 'Resurrected_Date': 'Resurrected Date',
'Lesson_Date':'Lesson Date', 'Unlock_Date': 'Unlock Date'};
var config = {
script_id: 'Item_Inspector',
title: 'Item Inspector',
pre_open: preopen_quiz_settings,
on_save: save_quiz_settings,
on_close: close_quiz_settings,
on_refresh: refresh_quiz_settings,
no_bkgd: true,
settings: {
pgSettings: {type:'page',label:'Settings',content:{
hoursFormat: {type:'dropdown',label:'Hours Format',hover_tip:'Choose the format for displaying hours',content:{'12hours':'12h', '24hours':'24h',}
},
position: {type: 'dropdown', label: 'Position', default: 2, hover_tip: 'Where on the dashboard to install Item Inspector',
content: {0: "Top", 1: "Below forecast", 2: "Below SRS", 3: "Below panels", 4: "Bottom"},
},
sect_tbl_cnts:{type:'section',label:'Word Export'},
noLatin: {type: 'checkbox', label:'No Latin Characters', default: false, hover_tip:'Radicals with latin characters not exported if set',},
oneItemPerLine: {type: 'checkbox', label:'One item per line', default: false, hover_tip: 'One item per line if set\nAll items in one paragraph otherwise',},
}},
pg_items: {type:'page',label:'Tables',hover_tip:'Choose the table for which you want to define the settings',content:{
grp_ipre_list: {type:'group',label:'Table List',content:{
active_ipreset: {type:'list',refresh_on_change:true,on_change:refresh_table_on_preset_click,hover_tip:'Choose a table to edit',content:{}},
}},
grp_ipre: {type:'group',label:'Selected Table',content:{
sect_ipre_name: {type:'section',label:'Table Name'},
ipre_name: {type:'text',label:'Edit Table Name',on_change:refresh_ipresets,path:'@ipresets[@active_ipreset].name',hover_tip:'Enter a name for the selected table'},
sect_ipre_srcs: {type:'section',label:'Table Settings'},
ipre_srcs: {type:'tabset',content:{
table_contents:{type:'page',label:'Contents',hover_tip:'Define the contents of your table',content:{
sect_tbl_cnts:{type:'section',label:'Table Entry'},
table_data: {type:'dropdown',label:'Table Data Element',hover_tip:'The data that will be displayed on the table.',
on_change:update_table_presets,
content:tableElementContents,
},
sort1: {type:'dropdown',label:'Primary Sort Criterion',hover_tip:'Items will be sorted by this criterion.',
on_change:update_table_presets,
content:sortElementContents,
},
sortOrder1: {type:'dropdown',label:'Primary Sort Order',hover_tip:'Items will be sorted in this order.',
on_change:update_table_presets,
content:{'Default': 'Default', 'Ascending': 'Ascending', 'Descending': 'Descending',},
},
sort2: {type:'dropdown',label:'Secondary Sort Criterion',hover_tip:'Items will be sorted by this criterion when the primary criterion is of equal values.',
on_change:update_table_presets,
content:sortElementContents,
},
sortOrder2: {type:'dropdown',label:'Secondary Sort Order',hover_tip:'Items will be sorted in this order when the primary criterion is of equal values.',
on_change:update_table_presets,
content:{'Default': 'Default', 'Ascending': 'Ascending', 'Descending': 'Descending',},
},
sect_tbl_tooltips:{type:'section',label:'Table Tooltips'},
tooltip1: {type:'dropdown',label:'First Tooltip Element',hover_tip:'The first line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
tooltip2: {type:'dropdown',label:'Second Tooltip Element',hover_tip:'The second line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
tooltip3: {type:'dropdown',label:'Third Tooltip Element',hover_tip:'The third line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
tooltip4: {type:'dropdown',label:'Fourth Tooltip Element',hover_tip:'The fourth line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
tooltip5: {type:'dropdown',label:'Fifth Tooltip Element',hover_tip:'The fifth line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
tooltip6: {type:'dropdown',label:'Sixth Tooltip Element',hover_tip:'The sixth line of data that will be displayed on the tooltip.',
on_change:update_table_presets,
content:dataElementContents,
},
sect_tbl_settings:{type:'section',label:'Other Settings'},
randomSelection: {type:'number',label:'Random Selection',hover_tip:'A non zero value returns a random selection of the stated number of items.\n0 returns all items.',
on_change:update_table_presets,default:0
},
leechStreakLimit: {type:'number',label:'Leech Streak Limit',hover_tip:'Do not display an item when current streak for both meaning and reading is equal or greater to this limit.\nA value of 0 disable this feature',
on_change:update_table_presets,default:0
},
},
}},
}},
}},
},
}};
populate_items_config(config);
quiz.settings_dialog = new wkof.Settings(config);
}
//========================================================================
// preopen_quiz_settings()
//------------------------------------------------------------------------
function preopen_quiz_settings(dialog) {
var btn_grp =
'<div class="pre_list_btn_grp">'+
'<button type="button" ref="###" action="new" class="ui-button ui-corner-all ui-widget" title="Create a new table">New</button>'+
'<button type="button" ref="###" action="up" class="ui-button ui-corner-all ui-widget" title="Move the selected table up in the list"><span class="icon-arrow-up"></span></button>'+
'<button type="button" ref="###" action="down" class="ui-button ui-corner-all ui-widget" title="Move the selected table down in the list"><span class="icon-arrow-down"></span></button>'+
'<button type="button" ref="###" action="delete" class="ui-button ui-corner-all ui-widget" title="Delete the selected table">Delete</button>'+
'</div>';
var wrap = dialog.find('#Item_Inspector_active_ipreset').closest('.row');
wrap.addClass('pre_list_wrap');
wrap.prepend(btn_grp.replace(/###/g, 'ipreset'));
wrap.find('.pre_list_btn_grp').on('click', 'button', preset_button_pressed);
$('#Item_Inspector_ipre_srcs .row:first-child').each(function(i,e){
var row = $(e);
var right = row.find('>.right');
row.prepend(right);
row.addClass('src_enable');
});
// Customize the item source filters.
var srcs = $('#Item_Inspector_ipre_srcs');
var flt_grps = srcs.find('.wkof_group');
flt_grps.addClass('filters');
var filters = flt_grps.find('.row');
filters.prepend('<div class="enable"><input type="checkbox"></div>');
filters.on('change', '.enable input[type="checkbox"]', toggle_filter);
init_settings();
refresh_ipresets();
}
//========================================================================
// open_quiz_settings()
//------------------------------------------------------------------------
var old_position;
function open_quiz_settings() {
if (quiz_settings_state !== 'ready') return call_setup_quiz_settings();
quiz_settings_state = 'open';
var backup = {};
quiz.backup = backup;
//backup.max_quiz_size = quiz.settings.max_quiz_size;
backup.ipre = JSON.stringify(quiz.settings.ipresets[quiz.settings.active_ipreset].content);
old_position = quiz.settings.position;
quiz.settings_dialog.open();
function call_setup_quiz_settings(){
setup_quiz_settings();
wkof.Settings.load('Item_Inspector')
.then(function(){
quiz_settings_state = 'ready';
open_quiz_settings();
});
};
}
//========================================================================
// save_quiz_settings()
//------------------------------------------------------------------------
function save_quiz_settings(settings) {
quiz.settings = settings;
populate_presets($('#Item_Inspector_source'), settings.ipresets, settings.active_ipreset);
quiz.settings.tablePresets[quiz.settings.active_ipreset].currentItem = 0;
// check if the table list is empty
if (!quiz.settings.ipresets.length){
init_settings(); // restore defaults
};
fetch_items()
.then(function(){
initCurrentItem();
populateDropdown();
if (old_position != quiz.settings.position){
if (document.getElementById("WkitTopBar")){
$('#WkitTopBar').empty();
$('#WkitTopBar').remove();
};
insertContainer();
eventHandlers();
};
updatePage();
})
}
//========================================================================
// close_quiz_settings()
//------------------------------------------------------------------------
function close_quiz_settings(settings) {
quiz_settings_state = 'setup';
}
//========================================================================
// refresh_quiz_settings()
//------------------------------------------------------------------------
function refresh_quiz_settings(settings) {
$('#Item_Inspector_ipre_srcs .wkof_group .row').each(function(i,e){
var row = $(e);
var panel = row.closest('[role="tabpanel"]');
var source = panel.attr('id').match(/^Item_Inspector_pg_(.*)$/)[1];
var filter_name = row.find('.setting').attr('name').slice((source+'_flt_').length);
var preset = quiz.settings.ipresets[quiz.settings.active_ipreset].content;
var enabled = false;
try {
enabled = preset[source].filters[filter_name].enabled;
} catch(e) {}
if (enabled) {
row.addClass('checked');
} else {
row.removeClass('checked');
}
row.find('.enable input[type="checkbox"]').prop('checked', enabled);
});
}
//========================================================================
// refresh_ipresets()
//------------------------------------------------------------------------
function refresh_ipresets() {
var settings = quiz.settings;
populate_presets($('#Item_Inspector_active_ipreset'), settings.ipresets, settings.active_ipreset);
}
//========================================================================
// preset_button_pressed()
//------------------------------------------------------------------------
function preset_button_pressed(e) {
var settings = quiz.settings;
var tablePresets = settings.tablePresets;
var ref = e.currentTarget.attributes.ref.value;
var action = e.currentTarget.attributes.action.value;
var selected = Number(settings['active_'+ref]);
var presets = settings[ref+'s'];
var elem = $('#Item_Inspector_active_'+ref);
var dflt;
dflt = {name:'<untitled>', content:$.extend(true, {}, ipre_defaults)};
switch (action) {
case 'new':
presets.push(dflt);
tablePresets.push(table_defaults);
selected = presets.length - 1;
settings[ref+'s'] = presets;
settings['active_'+ref] = selected;
settings.tablePresets = tablePresets;
populate_presets(elem, presets, selected);
refresh_table_presets(selected)
quiz.settings_dialog.refresh();
$('#Item_Inspector_'+ref.slice(0,4)+'_name').focus().select();
break;
case 'up':
if (selected <= 0) break;
presets = [].concat(presets.slice(0, selected-1), presets[selected], presets[selected-1], presets.slice(selected+1));
tablePresets = [].concat(tablePresets.slice(0, selected-1), tablePresets[selected], tablePresets[selected-1], tablePresets.slice(selected+1));
selected--;
settings[ref+'s'] = presets;
settings['active_'+ref] = selected;
settings.tablePresets = tablePresets;
populate_presets(elem, presets, selected);
break;
case 'down':
if (selected >= presets.length-1) break;
presets = [].concat(presets.slice(0, selected), presets[selected+1], presets[selected], presets.slice(selected+2));
tablePresets = [].concat(tablePresets.slice(0, selected), tablePresets[selected+1], tablePresets[selected], tablePresets.slice(selected+2));
selected++;
settings[ref+'s'] = presets;
settings['active_'+ref] = selected;
settings.tablePresets = tablePresets;
populate_presets(elem, presets, selected);
break;
case 'delete':
presets = presets.slice(0, selected).concat(presets.slice(selected+1));
tablePresets = tablePresets.slice(0, selected).concat(tablePresets.slice(selected+1));
selected = Math.max(0, selected-1);
settings[ref+'s'] = presets;
settings['active_'+ref] = selected;
settings.tablePresets = tablePresets;
populate_presets(elem, presets, selected);
quiz.settings_dialog.refresh();
break;
}
}
//========================================================================
// init_settings()
//------------------------------------------------------------------------
var table_defaults;
function init_settings() {
var idx;
// Merge some defaults
var defaults = {
};
var settings = $.extend(true, {}, defaults, wkof.settings.Item_Inspector);
wkof.settings.Item_Inspector = quiz.settings = settings;
let ipresets_defaults = [
{name:'Leeches', content:{wk_items:{enabled:true,filters:{srs:{enabled:true,value:{appr1:true,appr2:true,appr3:true,appr4:true,guru1:true,guru2:true,mast:true}}
,additionalFilters_leechTraining:{enabled:true,value:1}}},
tableContents:{currentItem:0,table_data:"Leech",sort1:"Default",sortOrder1:'Default',sort2:"Default",sortOrder2:'Default',
tooltip1:"Meaning_Full",tooltip2:"Reading_Full",tooltip3:"None",tooltip4:"None",tooltip5:"None",
tooltip6:"None",randomSelection:0,leechStreakLimit:0}}},
{name:'Failed Last Review', content:{wk_items:{enabled:true,filters:{additionalFilters_failedLastReview:{enabled:true,value:24}}},
tableContents:{currentItem:0,table_data:"Leech",sort1:"Default",sortOrder1:'Default',sort2:"Default",sortOrder2:'Default',
tooltip1:"Meaning_Full",tooltip2:"Reading_Full",tooltip3:"None",tooltip4:"None",tooltip5:"None",
tooltip6:"None",randomSelection:0,leechStreakLimit:0}}},
{name:'Current Level SRS', content:{wk_items:{enabled:true,filters:{level:{enabled:true,value:"+0"},srs:{enabled:true,value:{appr1:true,appr2:true,appr3:true,appr4:true,guru1:true,guru2:true,mast:true,enli:true}}}},
tableContents:{currentItem:0,table_data:"Srs",sort1:"Default",sortOrder1:'Default',sort2:"Default",sortOrder2:'Default',
tooltip1:"Review_Date",tooltip2:"Review_Wait",tooltip3:"None",tooltip4:"None",tooltip5:"None",
tooltip6:"None",randomSelection:0,leechStreakLimit:0}}},
{name:'Previous Level SRS', content:{wk_items:{enabled:true,filters:{level:{enabled:true,value:"-1"},srs:{enabled:true,value:{appr1:true,appr2:true,appr3:true,appr4:true,guru1:true,guru2:true,mast:true,enli:true}}}},
tableContents:{currentItem:0,table_data:"Srs",sort1:"Default",sortOrder1:'Default',sort2:"Default",sortOrder2:'Default',
tooltip1:"Review_Date",tooltip2:"Review_Wait",tooltip3:"None",tooltip4:"None",tooltip5:"None",
tooltip6:"None",randomSelection:0,leechStreakLimit:0}}},
];
table_defaults = {currentItem:0,table_data:"Leech",sort1:"Default",sortOrder1:'Default',sort2:"Default",sortOrder2:'Default',
tooltip1:"Meaning_Full",tooltip2:"Reading_Full",tooltip3:"None",tooltip4:"None",tooltip5:"None",tooltip6:"None",
randomSelection:0,leechStreakLimit:0,};
// define defaults if presets not yet defined
if (settings.ipresets === undefined) {
settings.ipresets = ipresets_defaults;
settings.active_ipreset = 0;
settings.tablePresets = init_table_presets(ipresets_defaults);
};
// restore defaults when ipresets list is empty
if (!settings.ipresets.length) {
settings.ipresets = ipresets_defaults;
settings.active_ipreset = 0;
settings.tablePresets = init_table_presets(ipresets_defaults);
};
if (ipre_defaults) {
for (idx in settings.ipresets) {
settings.ipresets[idx].content = $.extend(true, {}, ipre_defaults, settings.ipresets[idx].content);
}
}
if (settings.table_data) {refresh_table_presets(settings.active_ipreset)};
function init_table_presets(ipresets_defaults){
var x = [];
for (var y of ipresets_defaults){x.push(y.content.tableContents)};
return x;
}
}
//========================================================================
// populate_items_config()
//------------------------------------------------------------------------
var ipre_defaults;
function populate_items_config(config) {
var ipre_srcs = config.settings.pg_items.content.grp_ipre.content.ipre_srcs.content;
var srcs = wkof.ItemData.registry.sources;
ipre_defaults = {};
let src_name = 'wk_items';
var src = srcs[src_name];
var pg_content = {};
ipre_srcs['pg_'+src_name] = {type:'page',label:'Filters',content:pg_content};
var settings = {};
ipre_defaults[src_name] = settings;
// Add 'Filters' section.
if (src.filters && Object.keys(src.filters).length > 0) {
settings.filters = {};
var flt_content = {};
pg_content['grp_'+src_name+'_filters'] = {type:'group',label:'',content:flt_content};
for (var flt_name in src.filters) {
var flt = src.filters[flt_name];
settings.filters[flt_name] = {enabled:false, value:flt.default};
switch (flt.type) {
case 'checkbox':
flt_content[src_name+'_flt_'+flt_name] = {
type:'checkbox',
label:flt.label,
default:flt.default,
path:'@ipresets[@active_ipreset].content["'+src_name+'"].filters["'+flt_name+'"].value',
hover_tip:flt.hover_tip
}
break;
case 'multi':
var dflt = flt.default;
if (typeof flt.filter_value_map === 'function') dflt = flt.filter_value_map(dflt);
flt_content[src_name+'_flt_'+flt_name] = {
type:'list',
multi:true,
size:Math.min(4,Object.keys(flt.content).length),
label:flt.label,
content:flt.content,
default:dflt,
path:'@ipresets[@active_ipreset].content["'+src_name+'"].filters["'+flt_name+'"].value',
hover_tip:flt.hover_tip
}
settings.filters[flt_name].value = dflt;
break;
case 'text':
case 'number':
case 'input':
flt_content[src_name+'_flt_'+flt_name] = {
type:flt.type,
label:flt.label,
placeholder:flt.placeholder,
default:flt.default,
path:'@ipresets[@active_ipreset].content["'+src_name+'"].filters["'+flt_name+'"].value',
hover_tip:flt.hover_tip
}
break;
case 'button':
flt_content[src_name+'_flt_'+flt_name] = {
type:flt.type,
label:flt.label,
on_click:flt.on_click,
hover_tip:flt.hover_tip
}
break;
}
}
}
}
//========================================================================
// toggle_filter()
//------------------------------------------------------------------------
function toggle_filter(e) {
var row = $(e.delegateTarget);
var panel = row.closest('[role="tabpanel"]');
var source = panel.attr('id').match(/^Item_Inspector_pg_(.*)$/)[1];
var enabled = row.find('.enable input[type="checkbox"]').prop('checked');
var preset = quiz.settings.ipresets[quiz.settings.active_ipreset].content;
var filter_name = row.find('.setting').attr('name').slice((source+'_flt_').length);
if (enabled) {
row.addClass('checked');
} else {
row.removeClass('checked');
}
try {
preset[source].filters[filter_name].enabled = enabled;
} catch(e) {}
}
//========================================================================
// populate_presets()
//------------------------------------------------------------------------
function populate_presets(elem, presets, active_preset) {
var html = '';
for (var idx in presets) {
var preset = presets[idx];
var name = preset.name.replace(/</g,'<').replace(/>/g,'>');
html += '<option name="'+idx+'">'+name+'</option>';
}
var elem_name = elem.attr('id')
if (elem_name === 'Item_Inspector_source' && quiz.custom.has_ipreset) {
html += '<option name="custom">('+quiz.custom.ipreset.name+')</option>';
if (quiz.custom.using_ipreset) active_preset = presets.length;
}
elem.html(html);
elem.children().eq(active_preset).prop('selected', true);
refresh_table_presets(active_preset);
}
//========================================================================
// refresh_table_presets()
//------------------------------------------------------------------------
function refresh_table_presets(active_preset){
// Convert tablePresets to add the settings that were added in new versions
let tablePresets = quiz.settings.tablePresets;
for (var i = 0; i < tablePresets.length; i++){
for (var settingName in tablePresets[i]){
var setting = tablePresets[i][settingName];
if (setting == 'Review_Date12' || setting == 'Review_Date24' ) {tablePresets[i][settingName] = 'Review_Date'};
};
if (tablePresets[i].sort1 == undefined){tablePresets[i].sort1 = 'Default'};
if (tablePresets[i].sortOrder1 == undefined){tablePresets[i].sortOrder1 = 'Default'};
if (tablePresets[i].sort2 == undefined){tablePresets[i].sort2 = 'Default'};
if (tablePresets[i].sortOrder2 == undefined){tablePresets[i].sortOrder2 = 'Default'};
if (tablePresets[i].tooltip4 == undefined){tablePresets[i].tooltip4 = 'None'};
if (tablePresets[i].tooltip5 == undefined){tablePresets[i].tooltip5 = 'None'};
if (tablePresets[i].tooltip6 == undefined){tablePresets[i].tooltip6 = 'None'};
if (tablePresets[i].randomSelection == undefined){tablePresets[i].randomSelection = 0};
if (tablePresets[i].leechStreakLimit == undefined){tablePresets[i].leechStreakLimit = 0};
if (tablePresets[i].currentItem == undefined){tablePresets[i].currentItem = 0};
}
// change the settings the framework wants to use and let the framework
// update the UI.
let presets = quiz.settings.tablePresets[active_preset];
quiz.settings.table_data = presets.table_data;
quiz.settings.sort1 = presets.sort1;
quiz.settings.sortOrder1 = presets.sortOrder1;
quiz.settings.sort2 = presets.sort2;
quiz.settings.sortOrder2 = presets.sortOrder2;
quiz.settings.tooltip1 = presets.tooltip1;
quiz.settings.tooltip2 = presets.tooltip2;
quiz.settings.tooltip3 = presets.tooltip3;
quiz.settings.tooltip4 = presets.tooltip4;
quiz.settings.tooltip5 = presets.tooltip5;
quiz.settings.tooltip6 = presets.tooltip6;
quiz.settings.randomSelection = presets.randomSelection;
quiz.settings.leechStreakLimit = presets.leechStreakLimit;
}
//========================================================================
// refresh_table_on_preset_click()
//------------------------------------------------------------------------
function refresh_table_on_preset_click(){
// change the settings the framework wants to use and let the framework
// update the UI.
let active_preset = $('#Item_Inspector_active_ipreset').prop('selectedIndex');
let presets = quiz.settings.tablePresets[active_preset];
quiz.settings.table_data = presets.table_data;
quiz.settings.sort1 = presets.sort1;
quiz.settings.sortOrder1 = presets.sortOrder1;
quiz.settings.sort2 = presets.sort2;
quiz.settings.sortOrder2 = presets.sortOrder2;
quiz.settings.tooltip1 = presets.tooltip1;
quiz.settings.tooltip2 = presets.tooltip2;
quiz.settings.tooltip3 = presets.tooltip3;
quiz.settings.tooltip4 = presets.tooltip4;
quiz.settings.tooltip5 = presets.tooltip5;
quiz.settings.tooltip6 = presets.tooltip6;
quiz.settings.randomSelection = presets.randomSelection;
quiz.settings.leechStreakLimit = presets.leechStreakLimit;
}
//========================================================================
// update_table_presets()
//------------------------------------------------------------------------
function update_table_presets(){
// copy the settings the framework wants to use and let the framework
// manage the UI.
let active_preset = $('#Item_Inspector_active_ipreset').prop('selectedIndex');
let presets = quiz.settings.tablePresets[active_preset];
presets.table_data = quiz.settings.table_data;
presets.sort1 = quiz.settings.sort1;
presets.sortOrder1 = quiz.settings.sortOrder1;
presets.sort2 = quiz.settings.sort2;
presets.sortOrder2 = quiz.settings.sortOrder2;
presets.tooltip1 = quiz.settings.tooltip1;
presets.tooltip2 = quiz.settings.tooltip2;
presets.tooltip3 = quiz.settings.tooltip3;
presets.tooltip4 = quiz.settings.tooltip4;
presets.tooltip5 = quiz.settings.tooltip5;
presets.tooltip6 = quiz.settings.tooltip6;
presets.randomSelection = quiz.settings.randomSelection;
presets.leechStreakLimit = quiz.settings.leechStreakLimit;
}
//########################################################################
// QUIZ DIALOG
//########################################################################
//========================================================================
// install_css()
//------------------------------------------------------------------------
function install_css() {
$('head').append(
'<style id="Item_Inspector_css" type="text/css">'+
//--[ Settings dialog ]-------------------------------------------
'#wkof_ds div[role="dialog"][aria-describedby="wkofs_Item_Inspector"] {z-index:12002;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_btn_grp {width:60px;float:left;margin-right:2px;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_btn_grp button {width:100%; padding:2px 0;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_btn_grp button:not(:last-child) {margin-bottom:2px;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_wrap {display:flex;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_wrap .right {flex:1;}'+
'#wkofs_Item_Inspector.wkof_settings .pre_list_wrap .list {overflow:auto;height:100%;}'+
'#wkofs_Item_Inspector.wkof_settings .filters .row {border-top:1px solid #ccc; padding:6px 4px; margin-bottom:0;}'+
'#wkofs_Item_Inspector.wkof_settings .filters .row:not(.checked) {padding-top:0px;padding-bottom:0px;}'+
'#wkofs_Item_Inspector .filters .row .enable input[type="checkbox"] {margin:0;}'+
'#wkofs_Item_Inspector.narrow .filters .row.checked .right input[type="checkbox"]:after {content:"⇐yes?";margin-left:28px;line-height:30px;}'+
'#wkofs_Item_Inspector .filters .row.checked {background-color:#f7f7f7;}'+
'#wkofs_Item_Inspector .filters .row:not(.checked) {opacity:0.5;}'+
'#wkofs_Item_Inspector .filters .row .enable {display:inline; margin:0; float:left;}'+
'#wkofs_Item_Inspector:not(.narrow) .filters .left {width:170px;}'+
'#wkofs_Item_Inspector .filters .row .enable input[type="checkbox"] {margin:0 4px 0 0;}'+
'#wkofs_Item_Inspector .filters .row:not(.checked) .right {display:none;}'+
'#wkofs_Item_Inspector .filters .row:not(.checked) .left label {text-align:left;}'+
'#wkofs_Item_Inspector.narrow .filters .row .left {width:initial;}'+
'#wkofs_Item_Inspector.narrow .filters .row .left label {line-height:30px;}'+
'#wkofs_Item_Inspector #Item_Inspector_ipre_srcs .src_enable .left {width:initial;}'+
'#wkofs_Item_Inspector #Item_Inspector_ipre_srcs .src_enable .left label {text-align:left;width:initial;line-height:30px;}'+
'#wkofs_Item_Inspector #Item_Inspector_ipre_srcs .src_enable .right {float:left; margin:0 4px;width:initial;}'+
//----------------------------------------------------------------
'</style>'
);
}
//========================================================================
// fetch_items()
//------------------------------------------------------------------------
function fetch_items() {
var settings = quiz.settings;
var ipreset = settings.ipresets[settings.active_ipreset].content;
//set_mode('loading');
var config = {};
for (var src_name in ipreset) {
var src_preset = ipreset[src_name];
//if (!src_preset.enabled) continue;
if (!wkof.ItemData.registry.sources[src_name]) continue;
var src_cfg = {};
config[src_name] = src_cfg;
src_cfg.filters = {};
//if (src_name === 'wk_items') src_cfg.options = {study_materials: true};
if (src_name === 'wk_items') src_cfg.options = {};
var ipre_filters = src_preset.filters;
for (var flt_name in ipre_filters) {
var ipre_flt = ipre_filters[flt_name];
if (!ipre_flt.enabled) continue;
if (!wkof.ItemData.registry.sources[src_name].filters[flt_name]) continue;
src_cfg.filters[flt_name] = {value: ipre_flt.value};
if (ipre_flt.invert === true) src_cfg.filters[flt_name].invert = true;
}
}
let presets = quiz.settings.tablePresets[settings.active_ipreset];
for (var settingName in presets){
var setting = presets[settingName];
if ((settingName != 'randomSelection') && (settingName != 'leechStreakLimit') && (setting != 'None') &&
(setting != 'Default') && (settingName != 'currentItem') && (settingName != 'sortOrder1') && (settingName != 'sortOrder2')) {
src_cfg.options[metadata[setting].endPoint] = true;
};
}
if (presets.leechStreakLimit != 0) {src_cfg.options.review_statistics = true}
return wkof.ItemData.get_items(config)
.then(function(items){
quiz.items = items;
});
}
//------------------------------
// Calculating displayed data
//------------------------------
var theFuture = Date.parse("01 Jan 2090 00:00:00 GMT");
var srsName = ["Initiate","Apprentice I","Apprentice II","Apprentice III","Apprentice IV","Guru I","Guru II","Master","Enlightened","Burned"];
var metadata = {'Meaning_Brief': {'exists': ((item) => {return true}), 'label': 'EN: ',
'tableEntry': meaningsBrief,
'tooltipEntry': meaningsBrief,
'sortkey': ((item) => {return 0}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return 0}),
'sortOrder2': 'Ascending',
'endPoint' : 'subjects',
},
'Meaning_Full': {'exists': ((item) => {return true}), 'label': 'EN: ',
'tableEntry': meaningsFullTable,
'tooltipEntry': meaningsFull,
'sortkey': ((item) => {return 0}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return 0}),
'sortOrder2': 'Ascending',
'endPoint' : 'subjects',
},
'Reading_Brief': {'exists': ((item) => {return item.data.readings}), 'label': 'JP: ',
'tableEntry': readingsBrief,
'tooltipEntry': readingsBrief,
'sortkey': ((item) => {return 0}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return 0}),
'sortOrder2': 'Ascending',
'endPoint' : 'subjects',
},
'Reading_Full': {'exists': ((item) => {return item.data.readings}), 'label': 'JP: ',
'tableEntry': readingsFull,
'tooltipEntry': readingsFull,
'sortkey': ((item) => {return 0}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return 0}),
'sortOrder2': 'Ascending',
'endPoint' : 'subjects',
},
'Leech': {'exists': ((item) => {return true}), 'label': 'Leech: ',
'tableEntry': leechScore,
'tooltipEntry': leechScore,
'sortkey': leechScore,
'sortOrder': 'Descending',
'sortkey2': ((item) => {return (item.review_statistics ? item.review_statistics.percentage_correct : 101)}),
'sortOrder2': 'Ascending',
'endPoint' : 'review_statistics',
},
'Total_Incorrect_Answers': {'exists': ((item) => {return true}), 'label': 'Total Incorrect: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_incorrect + item.review_statistics.reading_incorrect)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_incorrect + item.review_statistics.reading_incorrect)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_incorrect + item.review_statistics.reading_incorrect)}),
'sortOrder': 'Descending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Total_Correct_Answers': {'exists': ((item) => {return true}), 'label': 'Total Correct: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_correct + item.review_statistics.reading_correct)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_correct + item.review_statistics.reading_correct)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_correct + item.review_statistics.reading_correct)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Percentage_Correct': {'exists': ((item) => {return true}), 'label': '%Total: ',
'tableEntry': ((item) => {return (item.review_statistics ? item.review_statistics.percentage_correct+'%' : 'None')}),
'tooltipEntry': ((item) => {return (item.review_statistics ? item.review_statistics.percentage_correct+'%' : 'None')}),
'sortkey': ((item) => {return (item.review_statistics ? item.review_statistics.percentage_correct : 101)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Meaning_Correct': {'exists': ((item) => {return true}), 'label': '%Meaning: ',
'tableEntry': ((item) => {return (item.review_statistics ? MeaningCorrect(item)+'%' : 'None')}),
'tooltipEntry': ((item) => {return (item.review_statistics ? MeaningCorrect(item)+'%' : 'None')}),
'sortkey': ((item) => {return (item.review_statistics ? MeaningCorrect(item) : 101)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Reading_Correct': {'exists': ((item) => {return item.data.readings}), 'label': '%Reading: ',
'tableEntry': ((item) => {return (item.review_statistics ? ReadingCorrect(item)+'%' : 'None')}),
'tooltipEntry': ((item) => {return (item.review_statistics ? ReadingCorrect(item)+'%' : 'None')}),
'sortkey': ((item) => {return (item.review_statistics ? ReadingCorrect(item) : 101)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Meaning_Incorrect_Answers': {'exists': ((item) => {return true}), 'label': 'Meaning Incorrect Answers: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_incorrect)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_incorrect)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_incorrect)}),
'sortOrder': 'Descending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Meaning_Correct_Answers': {'exists': ((item) => {return true}), 'label': 'Meaning Correct Answers: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_correct)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_correct)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_correct)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Meaning_Current_Streak': {'exists': ((item) => {return true}), 'label': 'Meaning Current Streak: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_current_streak - 1)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_current_streak -1)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_current_streak)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Meaning_Max_Streak': {'exists': ((item) => {return true}), 'label': 'Meaning Max. Streak: ',
'tableEntry': ((item) => {return (item.review_statistics.meaning_max_streak - 1)}),
'tooltipEntry': ((item) => {return (item.review_statistics.meaning_max_streak -1)}),
'sortkey': ((item) => {return (item.review_statistics.meaning_max_streak)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Reading_Incorrect_Answers': {'exists': ((item) => {return true}), 'label': 'Reading Incorrect: ',
'tableEntry': ((item) => {return (item.review_statistics.reading_incorrect)}),
'tooltipEntry': ((item) => {return (item.review_statistics.reading_incorrect)}),
'sortkey': ((item) => {return (item.review_statistics.reading_incorrect)}),
'sortOrder': 'Descending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Reading_Correct_Answers': {'exists': ((item) => {return true}), 'label': 'Reading Correct: ',
'tableEntry': ((item) => {return (item.review_statistics.reading_correct)}),
'tooltipEntry': ((item) => {return (item.review_statistics.reading_correct)}),
'sortkey': ((item) => {return (item.review_statistics.reading_correct)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Reading_Current_Streak': {'exists': ((item) => {return true}), 'label': 'Reading Current Streak: ',
'tableEntry': ((item) => {return (item.review_statistics.reading_current_streak - 1)}),
'tooltipEntry': ((item) => {return (item.review_statistics.reading_current_streak - 1)}),
'sortkey': ((item) => {return (item.review_statistics.reading_current_streak)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Reading_Max_Streak': {'exists': ((item) => {return true}), 'label': 'Reading Max. Streak: ',
'tableEntry': ((item) => {return (item.review_statistics.reading_max_streak - 1)}),
'tooltipEntry': ((item) => {return (item.review_statistics.reading_max_streak - 1)}),
'sortkey': ((item) => {return (item.review_statistics.reading_max_streak)}),
'sortOrder': 'Ascending',
'sortkey2': leechScore,
'sortOrder2': 'Descending',
'endPoint' : 'review_statistics',
},
'Level': {'exists': ((item) => {return true}), 'label': 'Level: ',
'tableEntry': ((item) => {return item.data.level}),
'tooltipEntry': ((item) => {return item.data.level}),
'sortkey': ((item) => {return item.data.level}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return 0}),
'sortOrder2': 'Ascending',
'endPoint' : 'subjects',
},
'Srs': {'exists': ((item) => {return true}), 'label': 'SRS: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined ? srsName[item.assignments.srs_stage] : 'Locked') : 'Locked')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined ? srsName[item.assignments.srs_stage] : 'Locked') : 'Locked')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined ? item.assignments.srs_stage : 10) : 10)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? Date.parse(item.assignments.available_at) : theFuture) : theFuture)}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Review_Date': {'exists': ((item) => {return true}), 'label': 'Review: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? makeDate(item) : 'Unscheduled') : 'Unscheduled')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? makeDate(item) : 'Unscheduled') : 'Unscheduled')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? trimDate(Date.parse(item.assignments.available_at)) : theFuture) : theFuture)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined? item.assignments.srs_stage : 10) : 10)}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Review_Wait': {'exists': ((item) => {return true}), 'label': 'Wait: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? reviewWait(item) : 'Unscheduled') : 'Unscheduled')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? reviewWait(item) : 'Unscheduled') : 'Unscheduled')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.available_at != undefined ? trimDate(Date.parse(item.assignments.available_at)) : theFuture) : theFuture)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined? item.assignments.srs_stage : 10) : 10)}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Passed_Date': {'exists': ((item) => {return true}), 'label': 'Passed: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.passed_at != undefined ? makePassedDate(item) : 'Not yet') : 'Not yet')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.passed_at != undefined ? makePassedDate(item) : 'Not yet') : 'Not yet')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.passed_at != undefined ? trimDate(Date.parse(item.assignments.passed_at)) : 0) : 0)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return (item.assignments ? (item.assignments.srs_stage != undefined ? item.assignments.srs_stage : 10) : 10)}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Burned_Date': {'exists': ((item) => {return true}), 'label': 'Burned: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.burned_at != undefined ? makeBurnedDate(item) : 'Not yet') : 'Not yet')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.burned_at != undefined ? makeBurnedDate(item) : 'Not yet') : 'Not yet')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.burned_at != undefined ? trimDate(Date.parse(item.assignments.burned_at)) : 0) : 0)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return item.data.level}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Resurrected_Date': {'exists': ((item) => {return true}), 'label': 'Resurrected: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.resurrected_at != undefined ? makeResurrectedDate(item) : 'Not yet') : 'Not yet')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.resurrected_at != undefined ? makeResurrectedDate(item) : 'Not yet') : 'Not yet')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.resurrected_at != undefined ? trimDate(Date.parse(item.assignments.resurrected_at)) : 0) : 0)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return item.data.level}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Lesson_Date': {'exists': ((item) => {return true}), 'label': 'Lesson: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.started_at != undefined ? makeLessonDate(item) : 'Not yet') : 'Not yet')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.started_at != undefined ? makeLessonDate(item) : 'Not yet') : 'Not yet')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.started_at ? trimDate(Date.parse(item.assignments.started_at)) : theFuture) : theFuture)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return item.data.level}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
'Unlock_Date': {'exists': ((item) => {return true}), 'label': 'Unlock: ',
'tableEntry': ((item) => {return (item.assignments ? (item.assignments.unlocked_at != undefined ? makeUnlockDate(item) : 'Not yet') : 'Not yet')}),
'tooltipEntry': ((item) => {return (item.assignments ? (item.assignments.unlocked_at != undefined ? makeUnlockDate(item) : 'Not yet') : 'Not yet')}),
'sortkey': ((item) => {return (item.assignments ? (item.assignments.unlocked_at ? trimDate(Date.parse(item.assignments.unlocked_at)) : theFuture) : theFuture)}),
'sortOrder': 'Ascending',
'sortkey2': ((item) => {return item.data.level}),
'sortOrder2': 'Ascending',
'endPoint' : 'assignments',
},
}
function MeaningCorrect(item){
let stats = item.review_statistics;
let denominator = stats.meaning_correct + stats.meaning_incorrect;
if (denominator == 0){
return 100
} else {
return Math.floor(100 * stats.meaning_correct / denominator)
}
}
function ReadingCorrect(item){
let stats = item.review_statistics;
let denominator = stats.reading_correct + stats.reading_incorrect;
if (denominator == 0){
return 100
} else {
return Math.floor(100 * stats.reading_correct / denominator)
}
}
function leechScore(item){
let reviewStats = item.review_statistics;
if (reviewStats){
let meaningScore = getLeechScore(reviewStats.meaning_incorrect, reviewStats.meaning_current_streak);
let readingScore = getLeechScore(reviewStats.reading_incorrect, reviewStats.reading_current_streak);
return Math.max(meaningScore, readingScore);
} else {return 0}
}
function getLeechScore(incorrect, currentStreak) {
//get incorrect number than lessen it using the user's correctStreak
let leechScore = incorrect / Math.pow((currentStreak || 0.5), 1.5); // '||' => if currentstreak zero make 0.5 instead (prevents dividing by zero)
leechScore = Math.round(leechScore * 100) / 100; //round to two decimals
return leechScore;
}
function reviewWait(item){
return (Date.parse(item.assignments.available_at) < Date.now() ? 'Now' : s_to_dhm((Date.parse(item.assignments.available_at)-Date.now())/1000))
}
// Converts seconds to days, hours, and minutes
function s_to_dhm(s) {
var d = Math.floor(s/60/60/24);
var h = Math.floor(s%(60*60*24)/60/60);
var m = Math.ceil(s%(60*60*24)%(60*60)/60);
return (d>0?d+'d ':'')+(h>0?h+'h ':'')+(m>0?m+'m':'1m');
}
function makeDate(item){
return formatDate(new Date(item.assignments.available_at), true, /* is_next_date */);
}
function makePassedDate(item){
return formatDate(new Date(item.assignments.passed_at), false, /* is_next_date */);
}
function makeBurnedDate(item){
return formatDate(new Date(item.assignments.burned_at), false, /* is_next_date */);
}
function makeResurrectedDate(item){
return formatDate(new Date(item.assignments.resurrected_at), false, /* is_next_date */);
}
function makeLessonDate(item){
return formatDate(new Date(item.assignments.started_at), false, /* is_next_date */);
}
function makeUnlockDate(item){
return formatDate(new Date(item.assignments.unlocked_at), false, /* is_next_date */);
}
//========================================================================
// Print date in pretty format.
//-------------------------------------------------------------------
function formatDate(d, is_next_date){
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;
if (is_next_date && d < now) return "Available Now";
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+', ';
}
if (quiz.settings.hoursFormat === '24hours') {
s += ('0'+hh).slice(-2)+':'+('0'+mm).slice(-2);
} else {
s += (((hh+11)%12)+1)+':'+('0'+mm).slice(-2)+['am','pm'][Math.floor(d.getHours()/12)];
}
return s;
}
//========================================================================
// Reduce date in milliseconds to minutes boundary
// This makes secondary sorting match the primary sort data seen by the user
//------------------------------------------------------------------------
function trimDate(d){
return Math.floor((d/1000)/60)*1000*60;
}
function meaningsFullTable(item){
var meanings = meaningsFull(item);
if (meanings.length > 20){meanings = meanings.slice(0, 20) + '...'}
return meanings;
}
function meaningsFull(item){
// make sure meanings are returned in the order WK provides them, but primary comes first
var meanings = "";
var meaningsPrimary = "";
for (var k = 0; k < item.data.meanings.length; k++){
if(item.data.meanings[k].primary){
if (meaningsPrimary.length != 0){
meaningsPrimary += ', ' + item.data.meanings[k].meaning;
} else {
meaningsPrimary = item.data.meanings[k].meaning;
}
} else {
if (meanings.length != 0){
meanings += ', ' + item.data.meanings[k].meaning;
} else {
meanings = item.data.meanings[k].meaning;
}
}
}
if (meanings.length != 0){meaningsPrimary = meaningsPrimary + ', ' + meanings}
return meaningsPrimary;
}
function meaningsBrief(item){
var meanings = item.data.meanings[0].meaning;
for (var k = 0; k < item.data.meanings.length; k++){if (item.data.meanings[k].primary){return item.data.meanings[k].meaning}};
return meanings;
}
function readingsFull(item){
// make sure readings are returned in the order WK provides them, but primary comes first
var readings = "";
var readingsPrimary = "";
for (var k = 0; k < item.data.readings.length; k++){
if(item.data.readings[k].primary){
if (readingsPrimary.length != 0){
readingsPrimary += ', ' + item.data.readings[k].reading;
} else {
readingsPrimary = item.data.readings[k].reading;
}
} else {
if (readings.length != 0){
readings += ', ' + item.data.readings[k].reading;
} else {
readings = item.data.readings[k].reading;
}
}
}
if (readings.length != 0){readingsPrimary = readingsPrimary + ', ' + readings}
return readingsPrimary;
}
function readingsBrief(item){
var readings = item.data.readings[0].reading;
for (var k = 0; k < item.data.readings.length; k++){if (item.data.readings[k].primary){return item.data.readings[k].reading}};
return readings;
}
function shuffle(items){
for(let i = items.length - 1; i > 0; i--){
const j = Math.floor(Math.random() * i);
const temp = items[i];
items[i] = items[j];
items[j] = temp;
}
return items
}
function updatePage() {
let leechStreakLimit = quiz.settings.tablePresets[quiz.settings.active_ipreset].leechStreakLimit;
if (leechStreakLimit != 0) {
quiz.items = quiz.items.filter((item => {return (item.review_statistics.meaning_current_streak < (leechStreakLimit+1)) || (item.review_statistics.reading_current_streak < (leechStreakLimit+1))}));
};
let randomSelection = quiz.settings.tablePresets[quiz.settings.active_ipreset].randomSelection;
if (randomSelection != 0){
quiz.items = shuffle(quiz.items).slice(0, randomSelection);
};
let tableKey = quiz.settings.tablePresets[quiz.settings.active_ipreset].table_data;
let settings = quiz.settings.tablePresets[quiz.settings.active_ipreset];
let sort1 = settings.sort1;
let sort2 = settings.sort2;
let sortKey, sortKey2;
let sortOrder = settings.sortOrder1;
let sortOrder2 = settings.sortOrder2;
if ((sort1 == "Default") && (sort2 == 'Default')){
sortKey = metadata[tableKey].sortkey;
if (sortOrder === 'Default'){sortOrder = metadata[tableKey].sortOrder};
sortKey2 = metadata[tableKey].sortkey2;
if (sortOrder2 === 'Default'){sortOrder2 = metadata[tableKey].sortOrder2};
} else if ((sort1 == "Default") && (sort2 != "Default")){
sortKey = metadata[tableKey].sortkey;
if (sortOrder === 'Default'){sortOrder = metadata[tableKey].sortOrder};
sortKey2 = metadata[sort2].sortkey;
if (sortOrder2 === 'Default'){sortOrder2 = metadata[sort2].sortOrder};
} else if ((sort1 != "Default") && (sort2 == "Default")){
sortKey = metadata[sort1].sortkey;
if (sortOrder === 'Default'){sortOrder = metadata[sort1].sortOrder};
sortKey2 = metadata[sort1].sortkey2;
if (sortOrder2 === 'Default'){sortOrder2 = metadata[sort1].sortOrder2};
} else {
sortKey = metadata[sort1].sortkey;
if (sortOrder === 'Default'){sortOrder = metadata[sort1].sortOrder};
sortKey2 = metadata[sort2].sortkey;
if (sortOrder === 'Default'){sortOrder2 = metadata[sort2].sortOrder};
}
quiz.items.forEach(((item) => {item.sortKey = sortKey(item); item.sortKey2 = sortKey2(item)}));
if ((sortOrder == 'Descending') && (sortOrder2 == 'Descending')){
quiz.items = quiz.items.sort(function(a, b){return b.sortKey == a.sortKey ? b.sortKey2 - a.sortKey2 : b.sortKey - a.sortKey });
} else if ((sortOrder == 'Descending') && (sortOrder2 == 'Ascending')){
quiz.items = quiz.items.sort(function(a, b){return b.sortKey == a.sortKey ? a.sortKey2 - b.sortKey2 : b.sortKey - a.sortKey });
} else if ((sortOrder == 'Ascending') && (sortOrder2 == 'Descending')){
quiz.items = quiz.items.sort(function(a, b){return a.sortKey == b.sortKey ? b.sortKey2 - a.sortKey2 : a.sortKey - b.sortKey });
} else {
quiz.items = quiz.items.sort(function(a, b){return(a.sortKey == b.sortKey ? a.sortKey2 - b.sortKey2 : a.sortKey - b.sortKey)});
};
createTopLeechTables(quiz.items);
}
function itemsCharacterCallback (itemsData){
//check if an item has characters. Kanji and vocabulary will always have these but wk-specific radicals (e.g. gun, leaf, stick) use images instead
if(itemsData.characters!= null) {
return itemsData.characters;
} else if (itemsData.character_images!= null){
let imgUrl = '';
for (let i = 0; i < itemsData.character_images.length; i++) {
if (itemsData.character_images[i].content_type == "image/png"){
imgUrl = itemsData.character_images[i].url;
}
}
return '<img class="radical-'+itemsData.slug+' radicalCharacterImgSize" src="'+imgUrl+'"></img>';
} else {
//if both characters and character_images are somehow absent try using slug instead
return itemsData.slug;
}
}
function makeTableEntry(item, selectedTable){
let tableData = metadata[quiz.settings.tablePresets[selectedTable].table_data];
return (tableData.exists(item) ? tableData.tableEntry(item) : '')
}
function makeTooltipEntry(item, tableName){
let html = '';
if (tableName != "None") {
let tableData = metadata[tableName];
if (tableData.exists(item)) {
html += '<tr><td class="WkisLabel">'+tableData.label+'</td><td class="WkisTipValue">'+tableData.tooltipEntry(item)+'</td></tr>'
};
};
return html;
};
function makeTooltips(item, selectedTable){
let html = '';
let presets = quiz.settings.tablePresets[selectedTable]
html += makeTooltipEntry(item, presets.tooltip1);
html += makeTooltipEntry(item, presets.tooltip2);
html += makeTooltipEntry(item, presets.tooltip3);
html += makeTooltipEntry(item, presets.tooltip4);
html += makeTooltipEntry(item, presets.tooltip5);
html += makeTooltipEntry(item, presets.tooltip6);
if (html != '') {
html = '<div class="WkisTooltipContent"><table><tbody>'+html+'</tbody></table></div>';
};
return html;
}
/* control variables for the currently displayed tables*/
var currentItem = 0;
var nbItems = 0;
function initCurrentItem(){
currentItem = quiz.settings.tablePresets[quiz.settings.active_ipreset].currentItem;
}
/* Callbacks for buttons */
function clickedBackward(event) {
//test prevents multiple clicks
if (!event.detail || event.detail == 1) {
if ((currentItem - nbDisplayedItems) >= 0) {
currentItem -= nbDisplayedItems;
quiz.settings.tablePresets[quiz.settings.active_ipreset].currentItem = currentItem;
quiz.settings_dialog.save();
};
/* refresh the page */
createTopLeechTables(quiz.items);
};
}
function clickedForward(event) {
//test prevents multiple clicks
if (!event.detail || event.detail == 1) {
if ((currentItem + nbDisplayedItems) < nbItems) {
currentItem += nbDisplayedItems;
quiz.settings.tablePresets[quiz.settings.active_ipreset].currentItem = currentItem;
quiz.settings_dialog.save();
};
/* refresh the page */
createTopLeechTables(quiz.items);
};
}
function selectTable(event) {
quiz.settings.active_ipreset = $('#WkitTableSelector').prop('selectedIndex');
currentItem = 0;
quiz.settings.tablePresets[quiz.settings.active_ipreset].currentItem = currentItem;
quiz.settings_dialog.save();
fetch_items()
.then(function(){
updatePage()
})
}
const numberOfTables = 3;
const leechesPerTable = 11;
const nbDisplayedItems = numberOfTables * leechesPerTable;
function createTopLeechTables(items) {
let sectionContents = "";
//let sectionContainer = "";
//let topBlock = "";
let numberPerTable = leechesPerTable;
let startnumberTable = currentItem;
let endNumberTable = currentItem + numberPerTable;
let itemsLength = items.length;
let nrOfTables = numberOfTables;
let totalNumberOfLeeches = numberPerTable * nrOfTables;
let meanings = "";
let readings = "";
nbItems = items.length;
let activeTable = quiz.settings.active_ipreset;
//make sure we don't create empty tables if there are too few leeches
if(items.length == 0){ //if no leeches
nrOfTables = 0;
sectionContents += `<div class="emptyMessage"><p><b>No items match your criteria. You may try relaxing them if possible.</b></p></div>`;
} else if(items.length < totalNumberOfLeeches) { //if less leeches available then user requested
var ratio = items.length / (numberPerTable*3);
if(ratio <= 0.34){
nrOfTables = 1;
} else if(ratio <= 0.67){
nrOfTables = 2;
}
} else if (numberPerTable >= totalNumberOfLeeches){ //if table capacity greater than user's requested amount of leeches
nrOfTables = 1;
}
//Create leech tables
for (var i = 0; i < nrOfTables; i++){
//In case there are less than the requested amount of leeches
if(items.length <= endNumberTable){
endNumberTable = items.length;
nrOfTables = i - 1;
}
sectionContents += `
<div class="span4" style="width=290px;">
<section class="kotoba-table-list dashboard-sub-section" style="position: relative;">
<h3 class="small-caps">Items ${startnumberTable+1}-${endNumberTable} of ${itemsLength}</h3>
<table>
<tbody>`;
for (var j = startnumberTable; j < endNumberTable; j++){
let tableEntry = makeTableEntry(items[j], activeTable);
let tooltip = makeTooltips(items[j], activeTable);
sectionContents += `<tr class="${items[j].object}">` +
'<td>' +
`<div class="WkisTooltip"><a target="_blank" href="${items[j].data.document_url}"><span lang="ja">${itemsCharacterCallback(items[j].data)}</span></a>` +
tooltip +
'</div>' +
'</td>' +
'<td>' +
'<div style="text-align: right"><a><span style="color: Gainsboro">'+tableEntry+'</span></a>' +
'</div>' +
'</td>' +
'</tr>';
}
//preparing for next table
startnumberTable += numberPerTable;
endNumberTable += numberPerTable;
sectionContents += '</tbody>' +
'</table>' +
'</section>' +
'</div>';
}
//check if a leech table is already there, insert container and topBlock if not already there and then update the contents
$('#leech_table').html(sectionContents);//replace existing table
// Populate the dropdown with the configured tables
/* var tableList = '';
var ipresets = quiz.settings.ipresets;
for (var table of ipresets) {
tableList += '<option>' + table.name.replace(/</g,'<').replace(/>/g,'>') +'</option>'
};
var dropdown = $('#WkitTableSelector');
dropdown.html(tableList);
$('#WkitTableSelector').prop('selectedIndex',activeTable);*/
}
function fillClipboard(){
let textarea = '<textarea id="WkitTextArea" class="WkitClipBoard">';
$('#leech_table').html(textarea);//replace existing table
let items = quiz.items;
let text = '';
let noLatin = quiz.settings.noLatin;
if (noLatin === undefined){noLatin = false; quiz.settings.noLatin = false}
let oneItemPerLine = quiz.settings.oneItemPerLine;
if (oneItemPerLine === undefined){oneItemPerLine = false; quiz.settings.oneItemPerLine = false}
for (var i = 0; i < items.length; i++){
let itemsData = items[i].data;
if(itemsData.characters!= null) {
text += itemsData.characters+' ';
if (oneItemPerLine){text += '\n'};
} else if (!noLatin){
text += itemsData.slug+' ';
if (oneItemPerLine){text += '\n'};
};
};
$('#WkitTextArea').val(text);
$('#WkitTextArea').select();
document.execCommand('copy');
alert('The items have been copied in the clipboard.');
fetch_items()
.then(function(){
updatePage();
})
};
function insertContainer(){
/* build containers for the table elements */
let sectionContainer = `<section id="WkitTopBar" class="WkitTopBar"></section> `;
let topBlock = '<div id="WkitControlBar" class="WkitControlBar">' +
'<div class="WkitHeader">' +
'<button id="WkitBackwardButton" type="button" class="WkitButton">◄</button>' +
'<button id="WkitForwardButton" type="button" class="WkitButton">►</button>' +
'<select id="WkitTableSelector" class="WkitSelector" title="Choose the table you want to display"></select>'+
'<button id="WkitWordExport" type="button" class="WkitButton" title="Place table items in clipboard\nPaste in your software of choice">☁</button>' +
'<p class="WkitTitle"><b>Wanikani Item Inspector</b></p>' +
'</div>' +
'</div>' +
'<div id="leech_table"><p>The table goes here</p></div>';
if (quiz.settings.position === undefined) {quiz.settings.position = 2};
let position = [".progress-and-forecast", '.progress-and-forecast', '.srs-progress', '.span12 .row', '.span12 .row:last-of-type',][quiz.settings.position];
if (quiz.settings.position == 0){
$(position).before(sectionContainer);
} else {
$(position).after(sectionContainer);
}
// insert the top block - must be separate from the sectionContainer to work around a bug
$('#WkitTopBar').append(topBlock); // must be appended - someone else may be there due to the bug
populateDropdown();
};
function populateDropdown(){
// Populate the dropdown with the configured tables
let activeTable = quiz.settings.active_ipreset;
var tableList = '';
var ipresets = quiz.settings.ipresets;
for (var table of ipresets) {
tableList += '<option>' + table.name.replace(/</g,'<').replace(/>/g,'>') +'</option>'
};
var dropdown = $('#WkitTableSelector');
dropdown.html(tableList);
$('#WkitTableSelector').prop('selectedIndex',activeTable);
};
function eventHandlers() {
/* Define the button actions. Must be done when the DOC is completed */
$("#WkitBackwardButton").click(clickedBackward);
$("#WkitForwardButton").click(clickedForward);
$('#WkitTableSelector').change(selectTable);
$("#WkitWordExport").click(fillClipboard);
};
//------------------------------------------
// Starting the program
// at the end to ensure the global variables are defined
//------------------------------------------
wkof.include('ItemData, Menu, Settings');
wkof.ready('ItemData, Menu, Settings')
.then(install_css)
.then(install_menu)
.then(init_settings)
.then(setup_quiz_settings)
.then(function(){return wkof.Settings.load('Item_Inspector')})
.then(function(){
quiz_setup_state = 'ready';
var defaults = {};
var settings = $.extend(true, {}, defaults, wkof.settings.Item_Inspector);
wkof.settings.Item_Inspector = quiz.settings = settings;
if (settings.table_data) {refresh_table_presets(settings.active_ipreset)};
})
.then(fetch_items)
.then(function(){
initCurrentItem();
insertContainer();
updatePage()
})
.then(eventHandlers);
})();