// ==UserScript==
// @name WaniKani Review Summary
// @namespace rwesterhof
// @version 0.9.5
// @description Adds a review summary tile to the dashboard
// @include /^https:\/\/(www|preview)\.wanikani\.com(\/(#)?dashboard)?(\/)?$/
// @match https://preview.wanikani.com/subjects/review*
// @match https://www.wanikani.com/subjects/review*
// @require https://greasyfork.org/scripts/410909-wanikani-review-cache/code/Wanikani:%20Review%20Cache.js?version=1183366
// @run-at document-end
// @grant none
// @license GPL-3.0-or-later
// ==/UserScript==
;(function() {
'use strict';
/* global wkof, review_cache */
var SCRIPT_ID = 'wk_reviewSummary';
var msInDay = 24 * 60 * 60 * 1000; // milliseconds in day
/*-------------------------------------------------------------------------------------------------------------------------------*/
// Temporary measure to allow the review cache script to load on the review page to track reviews while the /reviews endpoint is unavailable
if (/^https:\/\/(www|preview)\.wanikani\.com(\/(#)?dashboard)?(\/)?$/.test(window.location.href)) {
// Make sure WKOF is installed
if (!window.wkof) {
let response = confirm('WaniKani Review Summary 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;
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
wkof.include('Menu,Settings,ItemData');
wkof.ready('Menu,Settings')
.then(load_settings)
.then(install_menu)
.then(add_css)
.then(createPanel)
.then(wkof.ready('ItemData').then(fetch_and_update));
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
var CACHE_VERSION = '0.2';
var RS_CACHE_KEY = 'wk_rs_cache';
var LS_CACHE_KEY = 'wk_ls_cache'; // future expandable to lesson summary
function retrieveFromCache(cacheKey) {
var cached_json = localStorage.getItem(cacheKey);
if (cached_json) {
var cached = JSON.parse(cached_json);
if (cached.version == CACHE_VERSION) {
return cached;
}
}
return;
}
function storeInCache(cacheKey, itemBreakdown) {
// cache the results for next page load
var json = { version: CACHE_VERSION, itemBreakdown: itemBreakdown, currentTs: new Date().getTime() };
localStorage.setItem(cacheKey, JSON.stringify(json));
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
const STAGE_DIVS = [ '', 'Apprentice I', 'Apprentice II', 'Apprentice III', 'Apprentice IV', 'Apprentice',
'Guru I', 'Guru II', 'Guru',
'Master', 'Enlightened', 'Burned'
];
function createPanel() {
var reviewSummaryDiv = document.createElement("div");
reviewSummaryDiv.id="reviewSummaryDiv";
// first the access tile with the percentage
var reviewSummaryTile = document.createElement("div");
reviewSummaryTile.id="reviewSummaryTile";
reviewSummaryTile.innerHTML =
"<span id='rs_tile_span_header'>Review Summary</span><p></p>"
+ "<a id='rs_tile_windowlink' title='Open review summary' onclick='wk_rs_displayReviewSummary();'><span id='rs_tile_span_percentage'></span></a>"
+ "<a id='rs_tile_percentageToggle' title='Show/Hide percentage' onclick='wk_rs_togglePercentage(0);'>"
+ "<svg id='rs_tile_icon_percentage_down' class='wk-icon wk-icon--chevron-down hidden' viewBox='0 0 512 512' aria-hidden='true' style='color:var(--color-character-text);'><use href='#wk-icon__chevron-down'></use></svg>"
+ "<svg id='rs_tile_icon_percentage_up' class='wk-icon wk-icon--chevron-up hidden' viewBox='0 0 512 512' aria-hidden='true' style='color:var(--color-character-text);'><use href='#wk-icon__chevron-up'></use></svg>"
+ "</a>";
reviewSummaryDiv.append(reviewSummaryTile);
// then the detail window
var reviewSummaryWindow = document.createElement("div");
reviewSummaryWindow.id="reviewSummaryWindow";
reviewSummaryWindow.classList.add("reviewSummaryWindow");
reviewSummaryWindow.classList.add("hidden");
reviewSummaryWindow.setAttribute("onclick", "wk_rs_fireClickEvent();");
reviewSummaryWindow.innerHTML =
"<span id='rs_window_span_header'>Review Summary Details</span>"
+ "<button id='rs_window_button_close' onclick='wk_rs_hideReviewSummary();' title='Close window' class='rs_iconButton'>"
+ "<svg class='wk-icon wk-icon--cross' viewBox='0 0 384 512' aria-hidden='true'><use href='#wk-icon__cross'></use></svg>"
+ "</button><p></p>"
+ "<span id='rs_window_span_percentage'></span>"
+ "<div id='rs_window_div_tablist' class='rs_window_tablist'>"
+ "<button id='rs_window_button_tab_all' class='rs_window_button_tab' onclick='wk_rs_showTab([true, true]);'>All</button>"
+ "<button id='rs_window_button_tab_incorrect' class='rs_window_button_tab' onclick='wk_rs_showTab([true, false]);'>Incorrect</button>"
+ "<button id='rs_window_button_tab_correct' class='rs_window_button_tab' onclick='wk_rs_showTab([false, true]);'>Correct</button>"
+ "</div>";
reviewSummaryDiv.append(reviewSummaryWindow);
var reviewSummaryDivIncorrect = document.createElement("div");
reviewSummaryDivIncorrect.id=('rs_window_div_correct_0');
reviewSummaryDivIncorrect.classList.add('rs_window_div_items');
reviewSummaryDivIncorrect.innerHTML = "<span id='rs_window_span_count_incorrect'></span>";
reviewSummaryWindow.append(reviewSummaryDivIncorrect);
var reviewSummaryDivCorrect = document.createElement("div");
reviewSummaryDivCorrect.id=('rs_window_div_correct_1');
reviewSummaryDivCorrect.classList.add('rs_window_div_items');
reviewSummaryDivCorrect.innerHTML = "<span id='rs_window_span_count_correct'></span>";
reviewSummaryWindow.append(reviewSummaryDivCorrect);
for (var stage = 1; stage < STAGE_DIVS.length; stage++) {
var stageDiv = document.createElement("div");
stageDiv.id=('rs_window_div_correct_0_' + stage);
stageDiv.classList.add('rs_window_div_items_stage');
stageDiv.innerHTML = "<span class='rs_window_div_items_stage_span'>" + STAGE_DIVS[stage] + "</span>";
reviewSummaryDivIncorrect.append(stageDiv);
stageDiv = document.createElement("div");
stageDiv.id=('rs_window_div_correct_1_' + stage);
stageDiv.classList.add('rs_window_div_items_stage');
stageDiv.innerHTML = "<span class='rs_window_div_items_stage_span'>" + STAGE_DIVS[stage] + "</span>";
reviewSummaryDivCorrect.append(stageDiv);
}
document.getElementsByClassName('dashboard__content')[0].append(reviewSummaryDiv);
// position it over the review forecast
reviewSummaryDiv.style['grid-row'] = "1 / 2";
reviewSummaryDiv.style['grid-column'] = "5 / span 2";
// and make space
if (document.getElementsByClassName('dashboard__review-forecast')[0]) {
document.getElementsByClassName('dashboard__review-forecast')[0].style['grid-row'] = "2 / 5";
}
}
function applyVisibility(setting, panel) {
if (setting) {
panel.classList.remove('hidden');
}
else {
panel.classList.add('hidden');
}
}
window.wk_rs_displayReviewSummary=function() {
applyVisibility(true, document.getElementById("reviewSummaryWindow"));
var computedWidth = getComputedStyle(document.getElementById("reviewSummaryWindow")).width;
var nrOfCells = 25;
if (computedWidth.endsWith('px')) {
nrOfCells = Math.floor((computedWidth.slice(0, -2) - 24) / 28);
}
else if(computedWidth.endsWith('em')) {
// best effort guess
nrOfCells = Math.floor(((parseFloat(computedWidth.slice(0.-2)) * 16) - 24) / 28);
}
// else stick with default
[...document.querySelectorAll(".rs_window_div_items_stage_span")].forEach(span => { span.style["grid-column"]="1 / span " + nrOfCells });
}
window.wk_rs_hideReviewSummary=function() { applyVisibility(false, document.getElementById("reviewSummaryWindow")); }
window.wk_rs_displayDetails=function(div) { applyVisibility(true, div); listenForClicks(div); }
const DIV_ARRAY = [ 'incorrect', 'correct', 'all' ];
function showTab(divArray) {
var buttonClicked = 0;
for (var index = 0; index < divArray.length; index++) {
applyVisibility(divArray[index], document.getElementById("rs_window_div_correct_" + index));
if (divArray[index]) { buttonClicked += (index+1); }
}
for (var i = 0; i < DIV_ARRAY.length; i++) {
document.getElementById('rs_window_button_tab_' + DIV_ARRAY[i]).classList.remove("active");
}
document.getElementById('rs_window_button_tab_' + DIV_ARRAY[buttonClicked-1]).classList.add("active");
}
window.wk_rs_showTab=showTab;
function togglePercentage(mode) {
// mode can be 0 or 1 or it can be true or false, which we convert to 0 (false) and 1 (true) by forcing int conversion via calculations
var chevrons = [ document.getElementById('rs_tile_icon_percentage_down'),
document.getElementById('rs_tile_icon_percentage_up') ];
// remove all hiddens (prevent duplicate hidden classes)
applyVisibility(1, chevrons[0]);
applyVisibility(1, chevrons[1]);
// hide the one we don't need
applyVisibility(0, chevrons[((1-mode))]);
document.getElementById('rs_tile_percentageToggle').onclick=function() { wk_rs_togglePercentage(((1-mode))); };
applyVisibility(((0+mode)), document.getElementById('rs_tile_span_percentage'));
}
window.wk_rs_togglePercentage= togglePercentage;
function fireClickEvent() {
// fires a custom event to signal cockpit loaded
const event = document.createEvent('Event');
event.initEvent("review-summary-clicked", true, true);
document.getElementById("reviewSummaryWindow").dispatchEvent(event);
}
window.wk_rs_fireClickEvent=fireClickEvent;
function listenForClicks(div) {
document.getElementById("reviewSummaryWindow").addEventListener('review-summary-clicked', { div: div, handleEvent:function(event) { closeOnClick(event, div) } }, { once: true });
}
// eventlistener that moves the graph button to the heatmap once it is loaded
function closeOnClick(event, div) {
applyVisibility(false, div);
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
async function fetch_and_update() {
var cached = retrieveFromCache(RS_CACHE_KEY);
console.log("Found " + (cached ? cached.itemBreakdown.counts[2] : 0) + " reviews in cache");
var startAtTs = null;
if (cached) {
startAtTs = cached.currentTs;
}
// if no cache available, default to 24 hours
else {
startAtTs = new Date().getTime() - msInDay;
}
var data = await Promise.all([review_cache.get_reviews()]);
var filteredReviews = data[0].filter(item => item[0] > startAtTs);
var totalReviewCount = filteredReviews.length;
console.log("Found " + totalReviewCount + " new reviews since " + startAtTs);
if (totalReviewCount > 0) {
// we have reviews since last page load!
var errorReviews = filteredReviews.filter(item => (item[3]+item[4])>0);
var errorReviewCount = errorReviews.length;
var correctReviewCount = totalReviewCount - errorReviewCount;
var itemBreakdown = { filteredReviews: filteredReviews, percentage: (100 * correctReviewCount / totalReviewCount).toFixed(0) + '%', counts: [ errorReviewCount, correctReviewCount, totalReviewCount ] };
storeInCache(RS_CACHE_KEY, itemBreakdown);
togglePercentage((wkof.settings.wk_reviewSummary.showReviewPercentage > '0'));
display(itemBreakdown);
}
else {
// no reviews since last load, use cached summary
if (cached) {
document.getElementById('rs_tile_span_percentage').innerHTML=cached.itemBreakdown.percentage;
togglePercentage((wkof.settings.wk_reviewSummary.showReviewPercentage == '2'));
display(cached.itemBreakdown);
}
else {
console.log("No review summary to display");
}
}
// and show
applyVisibility(true, document.getElementById('reviewSummaryTile'));
}
const OBJECT_TYPE_ORDER = { 'radical': 1, 'kanji': 2, 'vocabulary': 3, 'kana_vocabulary': 3 };
async function display(itemBreakdown) {
document.getElementById('rs_tile_span_percentage').innerHTML=itemBreakdown.percentage;
document.getElementById('rs_window_span_percentage').innerHTML=itemBreakdown.percentage;
document.getElementById('rs_window_span_count_incorrect').innerHTML="Incorrect " + itemBreakdown.counts[0] + "/" + itemBreakdown.counts[2];
document.getElementById('rs_window_span_count_correct').innerHTML="Correct " + itemBreakdown.counts[1] + "/" + itemBreakdown.counts[2];
var reviewIds = itemBreakdown.filteredReviews.map(review => review[1]);
var itemList = await wkof.ItemData.get_index(await wkof.ItemData.get_items('include_hidden'), 'subject_id');
var svgs = await getSvgs(reviewIds, itemList);
let nextStage = (review) => {
let stageAfter = review[2] + (review[3] + review[4] == 0) - Math.ceil((review[3] + review[4]) / 2) * (review[2] < 5 ? 1 : 2);
return stageAfter < 1 ? 1 : stageAfter;
}
var displayItems = itemBreakdown.filteredReviews.map(review =>
{ return { id: review[1],
type: itemList[review[1]].object,
level: itemList[review[1]].data.level,
stage: nextStage(review),
correct: (review[3]+review[4]==0),
display: getDisplay(review[1], itemList, svgs)
}
});
displayItems.sort((a, b) => {
// level before type
if (wkof.settings.wk_reviewSummary.itemSort == '0') {
if (a.level != b.level) {
return 10000000 * (a.level - b.level);
}
}
if (a.type != b.type) {
return 1000000 * (OBJECT_TYPE_ORDER[a.type] - OBJECT_TYPE_ORDER[b.type]);
}
// level after type
if (wkof.settings.wk_reviewSummary.itemSort == '1') {
if (a.level != b.level) {
return 10000 * (a.level - b.level);
}
}
return (a.id - b.id);
});
// clear previous display
[...document.querySelectorAll('.rs_window_div_items_stage .rs_item_div')].forEach(node => node.remove());
[...document.querySelectorAll('.rs_window_div_items_stage')].forEach(div => { div.style.display = 'grid' });
// incorrect/correct split according to STAGE_DIVS (app1-4, App combined (5), Gur1-2, Gur combined (8), Mas,Enl,Bur)
for(var answer = 0; answer <= 1; answer++) {
const useAnswer = answer;
var answerSplit = displayItems.filter(item => (item.correct == useAnswer));
for (var stage = 1; stage <= 9; stage++) {
const useStage = stage;
var targetList = answerSplit.filter(item => item.stage == useStage);
if (targetList.length > 0) console.log("Processing " + targetList.length + " for stage " + useStage);
const targetDiv = document.getElementById('rs_window_div_correct_' + answer + '_' + (stage + Math.floor(stage/5) + Math.floor(stage/7)));
if ((targetList.length == 0) || (!wkof.settings.wk_reviewSummary.detailStages && (stage < 7))) {
targetDiv.style.display='none';
}
else {
var stageSpan = targetDiv.querySelector(".rs_window_div_items_stage_span");
stageSpan.textContent = STAGE_DIVS[(stage + Math.floor(stage/5) + Math.floor(stage/7))] + ' (' + targetList.length + ')';
targetList.forEach(item => targetDiv.append(item.display));
}
}
if (!wkof.settings.wk_reviewSummary.detailStages) {
for (var combinedStage = 5; combinedStage <= 8; combinedStage += 3) {
const useCombinedStage = combinedStage;
targetList = answerSplit.filter(item => (Math.floor(item.stage/7) + 3*Math.floor(item.stage/5) + 5) == useCombinedStage);
const targetDiv = document.getElementById('rs_window_div_correct_' + answer + '_' + combinedStage);
if (targetList.length == 0) {
targetDiv.style.display='none';
}
else {
console.log("Processing " + targetList.length + " for stage " + useCombinedStage);
stageSpan = targetDiv.querySelector(".rs_window_div_items_stage_span");
stageSpan.textContent = STAGE_DIVS[combinedStage] + ' (' + targetList.length + ')';
targetList.forEach(item => targetDiv.append(item.display));
}
}
}
else {
for (combinedStage = 5; combinedStage <= 8; combinedStage += 3) {
const targetDiv = document.getElementById('rs_window_div_correct_' + answer + '_' + combinedStage);
targetDiv.style.display='none';
}
}
}
if (itemBreakdown.counts[0] == 0) {
applyVisibility(false, document.getElementById('rs_window_button_tab_all'));
applyVisibility(false, document.getElementById('rs_window_button_tab_incorrect'));
showTab([false, true]);
}
else if (itemBreakdown.counts[1] == 0) {
applyVisibility(false, document.getElementById('rs_window_button_tab_all'));
applyVisibility(false, document.getElementById('rs_window_button_tab_correct'));
showTab([true, false]);
}
else {
showTab([wkof.settings.wk_reviewSummary.initialDisplay < 2, wkof.settings.wk_reviewSummary.initialDisplay != 1]);
}
}
const SUBJECT_TYPE_MAP = { 'radical': 'radical', 'kanji': 'kanji', 'vocabulary': 'vocabulary', 'kana_vocabulary': 'vocabulary' };
function getDisplay(reviewId, itemList, svgs) {
let item = itemList[reviewId];
var itemSize = (item.data.characters ? item.data.characters.length : 1);
var itemImgLink = document.createElement("div");
itemImgLink.classList.add("rs_item_div");
itemImgLink.style["grid-column"]="span " + ((itemSize+1));
var itemDetailDiv = document.createElement("div");
itemDetailDiv.id="rs_item_window_" + reviewId;
itemDetailDiv.classList.add("rs_item_window");
itemDetailDiv.classList.add("hidden");
var itemDetailTable = document.createElement("table");
itemDetailTable.classList.add("rs_item_table");
var itemDetailRow = document.createElement("tr");
var itemDetailCell = document.createElement("td");
itemDetailCell.setAttribute("colspan", "2");
var itemDetailImg = document.createElement("a");
itemDetailImg.classList.add("rs_item_table_character");
itemDetailImg.setAttribute("href", item.data.document_url);
itemDetailImg.setAttribute("target", "_blank");
var itemDetailSpan = document.createElement("span");
itemDetailSpan.classList.add("character-item--" + SUBJECT_TYPE_MAP[item.object]);
itemDetailSpan.append(item.data.characters || svgs[reviewId].cloneNode(true));
itemDetailImg.append(itemDetailSpan);
itemDetailCell.append(itemDetailImg);
itemDetailRow.append(itemDetailCell);
itemDetailTable.append(itemDetailRow);
itemDetailRow = document.createElement("tr");
itemDetailCell = document.createElement("th");
itemDetailCell.append('Meanings');
itemDetailRow.append(itemDetailCell);
itemDetailCell = document.createElement("td");
itemDetailCell.append(item.data.meanings.map((i) => i.meaning).join(', '));
itemDetailRow.append(itemDetailCell);
itemDetailTable.append(itemDetailRow);
itemDetailRow = document.createElement("tr");
itemDetailCell = document.createElement("th");
itemDetailCell.append('Readings');
itemDetailRow.append(itemDetailCell);
itemDetailCell = document.createElement("td");
itemDetailCell.append(item.data.readings ? item.data.readings.map((i) => i.reading).join('、 ') : '-');
itemDetailRow.append(itemDetailCell);
itemDetailTable.append(itemDetailRow);
itemDetailRow = document.createElement("tr");
itemDetailCell = document.createElement("th");
itemDetailCell.append('Level');
itemDetailRow.append(itemDetailCell);
itemDetailCell = document.createElement("td");
itemDetailCell.append(item.data.level);
itemDetailRow.append(itemDetailCell);
itemDetailTable.append(itemDetailRow);
itemDetailDiv.append(itemDetailTable);
itemImgLink.append(itemDetailDiv);
var itemImg = document.createElement("a");
itemImg.classList.add("rs_item_character");
itemImg.onclick=function() { wk_rs_fireClickEvent(); event.stopPropagation(); wk_rs_displayDetails(itemDetailDiv); };
var itemSpan = document.createElement("span");
itemSpan.classList.add("character-item--" + SUBJECT_TYPE_MAP[item.object]);
itemSpan.append(item.data.characters || svgs[reviewId].cloneNode(true));
itemImg.append(itemSpan);
itemImgLink.append(itemImg);
return itemImgLink;
}
// copied from the heatmap script
async function getSvgs(ids, items_id) {
const svgs = {};
const svgPromises = [];
for (var index in ids) {
const id = ids[index];
if (items_id[id].data.characters) { continue; }
svgPromises.push(
wkof.load_file(
items_id[id].data.character_images.find(
(a) => a.content_type == 'image/svg+xml' && a.metadata.inline_styles,
).url,
)
.then((svg) => {
let svgElem = document.createElement('span')
svgElem.innerHTML = svg.replace(/<svg /, `<svg class="radical-svg" `)
svgs[id] = svgElem.firstChild
}),
)
}
await Promise.allSettled(svgPromises);
return svgs;
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
// Adds the script's CSS to the page
function add_css() {
var userStyle = document.createElement('style');
userStyle.id = "wk_reviewSummary_CSS";
userStyle.append(
`#reviewSummaryTile {
grid-row: 1;
grid-column: 5 / span 2;
height: 100%;
background-color: #00aaff;
width: 150px;
text-align: center;
padding: 0;
border-radius: 5px;
}
#reviewSummaryTile i {
color: #fff;
position: relative;
float: right;
right: 6px;
top: 6px;
}
#reviewSummaryTile a {
cursor: pointer;
}
#reviewSummaryTile span {
position: relative;
color: #fff;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: bold;
}
#reviewSummaryTile span#rs_tile_span_header {
font-size: 18px;
top: 8px;
}
#reviewSummaryTile span#rs_tile_span_percentage {
font-size: 36px;
top: 28px;
}
.rs_iconButton {
cursor:pointer;
position: relative;
float: right;
right: 6px;
border: 0px;
width: 24px;
}
#reviewSummaryWindow {
position: absolute;
z-index: 1;
background: #434343;
border-radius: 5px;
padding: 6px;
top: 300px;
left: 150px;
width: 70%;
}
.reviewSummaryWindow span {
color: #fff;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 4px 6px 4px;
}
#reviewSummaryWindow span#rs_window_span_header {
font-size: 18px;
font-weight: bold;
}
#reviewSummaryWindow span#rs_window_span_percentage {
font-size: 36px;
position: relative;
top: 6px;
}
#rs_tile_windowlink:hover {
text-decoration:none;
}
.reviewSummaryWindow div {
position: relative;
top: 12px;
padding: 6px;
margin-bottom: 8px;
}
div.rs_window_div_items_stage {
display: grid;
grid-template-columns: min-content;
}
div.rs_window_div_items_stage span {
grid-column: 1 / span 10;
}
#rs_window_span_count_correct {
background: #00aa00;
}
#rs_window_span_count_incorrect {
background: #ff0000;
}
.rs_window_button_tab {
border-style: solid;
border-color: #666666;
background: #666666;
color: #fff;
}
.rs_window_button_tab:hover {
border-color: #888888;
color: #fff;
}
.rs_window_button_tab.active {
border-color: #888888;
background: #888888;
color: #fff;
}
.rs_iconButton {
background: #666666;
color: #fff;
}
.rs_item_div {
}
.rs_item_table_character {
color: #fff;
font-size: 32px;
}
.rs_item_table th {
padding-right: 20px;
}
.rs_item_character {
color: #fff;
font-size: 24px;
padding: 4px;
margin-right: 6px;
white-space: nowrap;
}
div.rs_item_window {
background: #666666;
color: #fff;
position: absolute;
width: 300px;
z-index:2;
padding: 12px;
left: 16px;
}
.rs_item_character:hover {
text-decoration:none;
color: #fff;
cursor: pointer;
}
.rs_item_table_character:hover {
text-decoration:none;
color: #fff;
}
a.rs_item_table_character span {
display: block;
text-align: center;
width: 92%;
padding: 12px;
}
.rs_item_character:visited {
text-decoration:none;
}
.rs_item_table_character:visited {
text-decoration:none;
}
.character-item--radical{background-color:#0af;background-image:linear-gradient(to bottom, #0af, #0093dd);border-color:#88d7ff transparent #069 #88d7ff}
.character-item--kanji{background-color:#f0a;background-image:linear-gradient(to bottom, #f0a, #dd0093);border-color:#f6c transparent #c08 #f6c}
.character-item--vocabulary{background-color:#a0f;background-image:linear-gradient(to bottom, #a0f, #9300dd);border-width:1px 0;border-color:#c655ff transparent #80c #c655ff}
.rs_item_character svg.radical-svg {
filter: invert(1);
width: 24px;
}
`);
document.getElementsByTagName('head')[0].append(userStyle);
}
/*-------------------------------------------------------------------------------------------------------------------------------*/
// Load settings and set defaults
function load_settings() {
var defaults = {
showLessonSummary: false,
showReviewPercentage: '1',
initialDisplay: '1',
itemSort: '1',
detailStages: false
};
return wkof.Settings.load(SCRIPT_ID, defaults);
}
// Installs the options button in the menu
function install_menu() {
var config = {
name: 'wk_reviewSummary_settings',
submenu: 'Settings',
title: 'Review Summary',
on_click: open_settings
};
wkof.Menu.insert_script_link(config);
}
// Create the options
function open_settings(items) {
var config = {
script_id: SCRIPT_ID,
title: 'Review Summary Settings',
on_save: fetch_and_update,
content: {
mainPage: {
type: 'page',
label: 'Settings',
hover_tip: 'Settings for the Review Summary',
content: {
display_group: {
type: 'group',
label: 'Display',
content: {
showReviewPercentage: {
type: 'dropdown',
label: 'Show accuracy of last review',
hover_tip: 'Display mode for the accuracy percentage',
default: '1',
content: {
0: 'Never',
1: 'Only when new',
2: 'Always'
}
},
initialDisplay: {
type: 'dropdown',
label: 'Information to initially display',
hover_tip: 'Only affects which items are initially displayed when opening the summary details. You can still toggle between the views later',
default: '1',
content: {
0: 'All',
1: 'Incorrect items',
2: 'Correct items'
}
},
itemSort: {
type: 'dropdown',
label: 'Order of displayed items',
hover_tip: 'Affects the order of display of the reviewed items',
default: '1',
content: {
0: 'Stage > Level > Type',
1: 'Stage > Type > Level'
}
},
detailStages: {
type: 'checkbox',
label: 'Use detailed stages',
hover_tip: 'Separate Guru I from Guru II, etc',
default: false
}
}
}
}
}
}
}
var dialog = new wkof.Settings(config);
dialog.open();
}
})();