- // ==UserScript==
- // @name Wanikani Self-Study Hide Info
- // @namespace rfindley
- // @description Hide item info on the Level and Item screens for self-study.
- // @version 1.1.2
- // @match https://www.wanikani.com/level/*
- // @match https://www.wanikani.com/radicals*
- // @match https://www.wanikani.com/kanji*
- // @match https://www.wanikani.com/vocabulary*
- // @match https://preview.wanikani.com/level/*
- // @match https://preview.wanikani.com/radicals*
- // @match https://preview.wanikani.com/kanji*
- // @match https://preview.wanikani.com/vocabulary*
- // @copyright 2018-2023, Robin Findley
- // @license MIT; http://opensource.org/licenses/MIT
- // @run-at document-end
- // @grant none
- // ==/UserScript==
-
- window.ss_hideinfo = {};
-
- (function(gobj) {
-
- /* globals wkof, ss_quiz */
-
- //===================================================================
- // Initialization of the Wanikani Open Framework.
- //-------------------------------------------------------------------
- var script_name = 'Self-Study Quiz';
- var wkof_version_needed = '1.0.17';
- if (!window.wkof) {
- if (confirm(script_name+' requires Wanikani Open Framework.\nDo you want to be forwarded to the installation instructions?')) {
- window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
- }
- return;
- }
- if (wkof.version.compare_to(wkof_version_needed) === 'older') {
- if (confirm(script_name+' requires Wanikani Open Framework version '+wkof_version_needed+'.\nDo you want to be forwarded to the update page?')) {
- window.location.href = 'https://greasyfork.org/en/scripts/38582-wanikani-open-framework';
- }
- return;
- }
-
- wkof.include('Settings');
- wkof.ready('document, Settings')
- .then(load_settings)
- .then(install_interface);
-
- //========================================================================
- var btnbar, sections;
- function install_interface() {
- var html =
- '<div class="ss_hideinfo">'+
- ' <label>Self-study:</label>'+
- ' <div class="btn-group">'+
- ' <button class="btn enable" title="Enable/Disable self-study plugin"></button>'+
- ' <button class="btn ssquiz hidden" title="Open the quiz window">Quiz</button>'+
- ' <button class="btn shuffle" title="Shuffle the list of items below">Shuffle</button>'+
- ' <select class="btn mode" title="Select a self-study preset">'+
- ' <option value="jp2en">Japanese to English</option>'+
- ' <option value="en2jp">English to Japanese</option>'+
- ' </select>'+
- ' <select class="btn lockburn" title="Select a self-study preset">'+
- ' <option value="all">Show All Items</option>'+
- ' <option value="hideunlocked">Show Locked Only</option>'+
- ' <option value="hideunburned">Show Burned Only</option>'+
- ' <option value="hidelocked">Hide Locked</option>'+
- ' <option value="hideburned">Hide Burned</option>'+
- ' <option value="hidelockedburned">Hide Locked and Burned</option>'+
- ' </select>'+
- ' </div>'+
- '</div>';
-
- var css = `
- .ss_hideinfo {margin-left:20px; margin-bottom:10px; position:relative;}
- .ss_hideinfo label {display:inline; vertical-align:middle; padding-right:4px; color:#999; font-size:14px;font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif; text-shadow:0 1px 0 #fff;}
- .ss_hideinfo .btn-group {display:inline; vertical-align:middle; font-size:0px;}
- .ss_hideinfo select.btn {width:200px;}
- .ss_hideinfo .btn.enable {width:55px;}
- .ss_hideinfo .btn {
- display:inline-block;
- height:30px;
- padding: 4px 12px;
- margin-bottom: 0;
- font-size: 14px;
- line-height: 20px;
- text-align: center;
- vertical-align: middle;
- cursor: pointer;
- text-shadow: 0 1px 1px rgb(255 255 255 / 75%);
- font-family: "Ubuntu", Helvetica, Arial, sans-serif;
- background-color: #f0f0f0;
- background-image: linear-gradient(to bottom, #fff, #e6e6e6);
- background-repeat: repeat-x;
- border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
- border: 1px solid #ccc;
- border-left: 0;
- border-bottom-color: #b3b3b3;
- box-shadow: inset 0 1px 0 rgb(255 255 255 / 20%), 0 1px 2px rgb(0 0 0 / 5%);
- }
- .ss_hideinfo .btn:hover {
- color: #333;
- text-decoration: none;
- background-position: 0 -15px;
- transition: background-position 0.1s linear;
- }
- .ss_hideinfo .btn:first-child {
- border-left: 1px solid #ccc;
- border-radius: 4px 0 0 4px;
- }
- .ss_hideinfo .btn:last-child {border-radius: 0 4px 4px 0;}
-
- section.ss_active .ss_hideinfo button.enable {background-color:#b3e6b3; background-image:linear-gradient(to bottom, #ecf9ec, #b3e6b3);}
- section.ss_active .ss_hideinfo button.enable:after {content:"ON";}
- section:not(.ss_active) .ss_hideinfo button.enable:after {content:"OFF";}
-
- section.ss_active.ss_hidechar .subject-character .subject-character__characters {opacity:0; transition:opacity ease-in-out 0.15s}
- section.ss_active.ss_hideread .subject-character .subject-character__reading {opacity:0; transition:opacity ease-in-out 0.15s}
- section.ss_active.ss_hidemean .subject-character .subject-character__meaning {opacity:0; transition:opacity ease-in-out 0.15s}
- section.ss_active.ss_hideburned .ss_burned {display:none;}
- section.ss_active.ss_hidelocked .ss_locked {display:none;}
- section.ss_active.ss_hideunburned .subject-character-grid__item:not(.ss_burned) {display:none;}
- section.ss_active.ss_hideunlocked .subject-character-grid__item:not(.ss_locked) {display:none;}
-
- section.ss_active .subject-character:hover span.subject-character__characters {opacity: initial !important; transition:opacity ease-in-out 0.05s !important;}
- section.ss_active .subject-character:hover .subject-character__info span {opacity: initial !important; transition:opacity ease-in-out 0.05s !important;}
- `;
-
- let css_tag = document.createElement('style');
- css_tag.textContent = css;
- document.head.prepend(css_tag);
-
- sections = document.querySelectorAll('section.character-grid');
-
- sections.forEach((section) => {
- section.insertAdjacentHTML('afterbegin',html);
- btnbar = section.querySelector('.ss_hideinfo');
- btnbar.querySelector('button.enable').addEventListener('click', toggle_enable);
- btnbar.querySelector('button.ssquiz').addEventListener('click', open_quiz);
- btnbar.querySelector('button.shuffle').addEventListener('click', shuffle);
- btnbar.querySelector('select.mode').addEventListener('change', mode_changed);
- btnbar.querySelector('select.lockburn').addEventListener('change', lockburn_changed);
- });
-
- for (let item of document.querySelectorAll('section.character-grid .subject-character--locked')) {
- item.closest('.subject-character-grid__item').classList.add('ss_locked');
- }
- for (let item of document.querySelectorAll('section.character-grid .subject-character--burned')) {
- item.closest('.subject-character-grid__item').classList.add('ss_burned');
- }
-
- wkof.wait_state('ss_quiz', 'ready').then(function(){
- if (typeof ss_quiz.open === 'function') {
- for (let bar of document.querySelectorAll('.ss_hideinfo button.ssquiz')) {
- bar.classList.remove('hidden');
- };
- }
- });
-
- toggle_enable(null, true /* no_toggle */);
- mode_changed();
- lockburn_changed();
- if (settings.enabled) shuffle();
- }
-
- //========================================================================
- function deep_merge(...objects) {
- let merged = {};
- function recursive_merge(dest, src) {
- for (let prop in src) {
- if (typeof src[prop] === "object" && src[prop] !== null ) {
- if (Array.isArray(src[prop])) {
- dest[prop] = src[prop].slice();
- } else {
- dest[prop] = dest[prop] || {};
- recursive_merge(dest[prop], src[prop]);
- }
- } else {
- dest[prop] = src[prop];
- }
- }
- return dest;
- }
- for (let obj in objects) {
- recursive_merge(merged, objects[obj]);
- }
- return merged;
- }
-
- //========================================================================
- var settings;
- function load_settings() {
- var default_settings = {
- enabled: false,
- mode: 'jp2en',
- lockburn: 'all',
- };
- return wkof.Settings.load('ss_hideinfo')
- .then(function(){
- settings = deep_merge(default_settings, wkof.settings.ss_hideinfo);
- settings = wkof.settings.ss_hideinfo;
- });
- }
-
- //========================================================================
- function save_settings() {
- wkof.Settings.save('ss_hideinfo');
- }
-
- //========================================================================
- function toggle_enable(e, no_toggle) {
- var enabled = settings.enabled;
- if (no_toggle !== true) enabled = !enabled;
- if (enabled) {
- sections.forEach((section) => section.classList.add('ss_active'));
- } else {
- sections.forEach((section) => section.classList.remove('ss_active'));
- }
- if (enabled !== settings.enabled) {
- settings.enabled = enabled;
- save_settings();
- }
- }
-
- //========================================================================
- function fisher_yates_shuffle(arr) {
- var i = arr.length, j, temp;
- if (i===0) return arr;
- while (--i) {
- j = Math.floor(Math.random()*(i+1));
- temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;
- }
- return arr;
- }
-
- //========================================================================
- function shuffle(e) {
- if (e === undefined) {
- // Shuffle all
- for (let section of document.querySelectorAll('.subject-character-grid')) {
- let grid = section.querySelector('.subject-character-grid__items');
- let items = fisher_yates_shuffle(Array.from(grid.children));
- for (let item of items) grid.append(item);
- };
- } else {
- // Shuffle specific group
- let section = e.currentTarget.closest('section.character-grid');
- let grid = section.querySelector('.subject-character-grid__items');
- let items = fisher_yates_shuffle(Array.from(grid.children));
- for (let item of items) grid.append(item);
- }
- }
-
- //========================================================================
- function mode_changed(e) {
- let value;
- if (e !== undefined) {
- value = e.target.value;
- settings.mode = value;
- save_settings();
- } else {
- value = settings.mode;
- }
- for (let section of sections) {
- section.querySelector('select.mode').value = value;
- section.classList.remove('ss_hidechar', 'ss_hideread', 'ss_hidemean');
- switch (value) {
- case 'jp2en':
- section.classList.add('ss_hidemean', 'ss_hideread');
- break;
-
- case 'en2jp':
- section.classList.add('ss_hidechar', 'ss_hideread');
- break;
- }
- }
- }
-
- //========================================================================
- function lockburn_changed(e) {
- let value;
- if (e !== undefined) {
- value = e.target.value;
- settings.lockburn = value;
- save_settings();
- } else {
- value = settings.lockburn;
- }
- for (let section of sections) {
- section.querySelector('select.lockburn').value = value;
- section.classList.remove('ss_hidelocked', 'ss_hideburned', 'ss_hideunlocked', 'ss_hideunburned');
- switch (value) {
- case 'all':
- break;
-
- case 'hidelocked':
- section.classList.add('ss_hidelocked');
- break;
-
- case 'hideburned':
- section.classList.add('ss_hideburned');
- break;
-
- case 'hidelockedburned':
- section.classList.add('ss_hidelocked', 'ss_hideburned');
- break;
-
- case 'hideunlocked':
- section.classList.add('ss_hideunlocked');
- break;
-
- case 'hideunburned':
- section.classList.add('ss_hideunburned');
- break;
- }
- }
- }
-
- //========================================================================
- function open_quiz(e) {
- var btn = e.currentTarget;
- var sec = btn.closest('section.character-grid');
- var level, item_type;
- var path = window.location.pathname.split('/');
- var header = btn.closest('section').querySelector('header').textContent.trim();
- if (path[1] === 'level') {
- level = path[2];
- item_type = header.toLowerCase();
- } else {
- level = header.split(' ')[1];
- item_type = path[1];
- }
- var item_type_text = item_type;
- item_type_text[0] = item_type_text[0].toUpperCase();
- var title = 'Level '+level+' '+item_type_text;
- item_type = item_type.replace(/s$/g, '');
-
- var custom_options = {
- ipreset: {name: title, content: {
- wk_items: {enabled: true, filters: {
- level: {enabled: true, value: level},
- item_type: {enabled: true, value: item_type},
- }},
- }},
- };
- switch (settings.lockburn) {
- case 'all':
- break;
-
- case 'hidelocked':
- custom_options.ipreset.content.wk_items.filters.srs = {enabled:true,value:'1,2,3,4,5,6,7,8,9'};
- break;
-
- case 'hideburned':
- custom_options.ipreset.content.wk_items.filters.srs = {enabled:true,value:'-1,0,1,2,3,4,5,6,7,8'};
- break;
-
- case 'hidelockedburned':
- custom_options.ipreset.content.wk_items.filters.srs = {enabled:true,value:'1,2,3,4,5,6,7,8'};
- break;
-
- case 'hideunlocked':
- custom_options.ipreset.content.wk_items.filters.srs = {enabled:true,value:'-1,0'};
- break;
-
- case 'hideunburned':
- custom_options.ipreset.content.wk_items.filters.srs = {enabled:true,value:'9'};
- break;
- }
-
- if (settings.mode === 'en2jp' && item_type === 'vocabulary') {
- custom_options.qpreset = {
- name: 'English to Japanese',
- content: {
- mean2read:true,
- }
- };
- } else {
- custom_options.qpreset = {
- name: 'Japanese to English',
- content: {
- char2read:true,
- char2mean:true,
- }
- };
- }
- ss_quiz.open(custom_options);
- }
-
- })(window.ss_hideinfo);