Guest User

Dashboard Level Progress Indicator 1.0+ / Improvement

a guest
Dec 22nd, 2021
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         WaniKani Dashboard Level Progress Detail
  3. // @version      1.1.2
  4. // @description  Show detailed progress bars.
  5. // @author       UInt2048
  6. // @include      /^https://(www|preview).wanikani.com/(dashboard)?$/
  7. // @run-at       document-end
  8. // @grant        none
  9. // @namespace https://greasyfork.org/users/149329
  10. // ==/UserScript==
  11.  
  12. (function() {
  13.     'use strict';
  14.  
  15.     if (!window.wkof) {
  16.         alert('WK Dashboard Level Progress Detail requires Wanikani Open Framework.\nYou will now be forwarded to installation instructions.');
  17.         window.location.href = 'https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549';
  18.         return;
  19.     }
  20.     window.wkof.include('ItemData, Apiv2, Menu, Settings');
  21.  
  22.     var locked_data_url = "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAABlBMVEX////p6emlmyooAAAAAnRSTlMAgJsrThgAAAA1SURBVDjLY3huea54DpQ4wIBgnyuewDAHSdKAAUnhuQIGJIVzHjCMmjJqyqgpo6aMmkKkKQC2XQWeSEU1BQAAAABJRU5ErkJggg==')";
  23.  
  24.     function render(json) {
  25.         const burnStage = 9;
  26.         const enlightenedStage = 8;
  27.         const masterStage = 7;
  28.         const guruStage = 5;
  29.         const apprenticeStage = 1;
  30.         const stageNames = ['', 'Apprentice I', 'Apprentice II', 'Apprentice III', 'Apprentice IV', 'Guru I', 'Guru II', 'Master', 'Enlightened', 'Burned'];
  31.  
  32.         function getDesiredLevel() {
  33.             switch (settings.progress_hidden) {
  34.                 case '3':
  35.                 case '4':
  36.                     return masterStage;
  37.                 case '5':
  38.                 case '6':
  39.                     return enlightenedStage;
  40.                 case '7':
  41.                     return burnStage;
  42.                 default:
  43.                     return guruStage;
  44.             }
  45.         }
  46.  
  47.         const settings = window.wkof.settings.level_progress_detail;
  48.         const usePassed = settings.progress_hidden % 2 == 0;
  49.         console.log(settings.progress_hidden);
  50.         const desiredLevel = getDesiredLevel();
  51.         console.log(desiredLevel);
  52.         const percentageRequired = settings.progress_hidden_percentage;
  53.  
  54.         const burnedOpacity = 1;
  55.         const enlightenedOpacity = 1;
  56.         const masterOpacity = 0.9;
  57.         const initialGuruOpacity = 1;
  58.         const guruOpacityChange = settings.opacity_multiplier_guru / 100.;
  59.         const initialApprenticeOpacity = 1;
  60.         const apprenticeOpacityChange = settings.opacity_multiplier_apprentice / 100.;
  61.  
  62.         function getColorCode(stage) {
  63.             if (stage >= burnStage) return settings.colorcode_burned;
  64.             else if (stage >= enlightenedStage) return settings.colorcode_enlightened;
  65.             else if (stage >= masterStage) return settings.colorcode_master;
  66.             else if (stage >= guruStage) return settings.colorcode_guru;
  67.             else if (stage >= apprenticeStage) return settings.colorcode_apprentice;
  68.         }
  69.  
  70.         function totalAtLeast(progress, stage) {
  71.             return progress.srs_level_totals.slice(stage).reduce((a, b) => a + b, 0);
  72.         }
  73.  
  74.         window.$(".progress-component").children().slice(0, -2).remove();
  75.         if (settings.hide_current_level) { window.$(".progress-component").empty(); }
  76.  
  77.         console.log(json.progresses);
  78.         var progresses = [];
  79.         while (json.progresses.length > settings.unconditional_progressions) {
  80.             var progress = json.progresses[0];
  81.             var total_learned = totalAtLeast(progress, apprenticeStage);
  82.             var desired_level_plus_total = totalAtLeast(progress, desiredLevel);
  83.             console.log(desired_level_plus_total)
  84.  
  85.             var learnedRequired = settings.require_learned ? progress.max : 0;
  86.             var percentageTotal = usePassed ? progress.passed_total : desired_level_plus_total;
  87.  
  88.             if (!(percentageTotal * 100.0 / progress.max >= percentageRequired && total_learned >= learnedRequired) && progress.max !== 0) {
  89.                 progresses.push(progress);
  90.             }
  91.             json.progresses = json.progresses.slice(1);
  92.         }
  93.  
  94.         json.progresses = progresses.concat(json.progresses);
  95.  
  96.         var runningHTML = "";
  97.         json.progresses.forEach(function(progress, j) {
  98.             var html =
  99.                 '<div id="progress-' + progress.level + '-' + progress.type + '" class="vocab-progress">' +
  100.                 '  <h3>Level ' + progress.level + ' ' + progress.type.charAt(0).toUpperCase() + progress.type.slice(1) + ' Progression</h3>' +
  101.                 '<div class="chart" style="position:relative;">' +
  102.                 (progress.max < 10 ? "" :
  103.                  '<div class="threshold" style="width: ' + Math.ceil(progress.max * 0.9) * 100 / progress.max + '% !important;height:100% !important;position:absolute !important;padding-right:0.5em !important;color:#a6a6a6 !important;font-family:Helvetica, Arial, sans-serif;text-align:right;border-right:1px solid rgba(0,0,0,0.1);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:1px 0 0 #eee;-moz-box-shadow:1px 0 0 #eee;box-shadow:1px 0 0 #eee;text-shadow:0 1px 0 rgba(255,255,255,0.5)"><div style="position:absolute;bottom:0;right:0;">' +
  104.                  Math.ceil(progress.max * 0.9) +
  105.                  '&nbsp</div></div>') + // 90% marker
  106.                 (progress.max < 2 || !settings.show_halfway_marker ? "" :
  107.                  '<div class="threshold" style="width: ' + Math.ceil(progress.max * 0.5) * 100 / progress.max + '% !important;height:100% !important;position:absolute !important;padding-right:0.5em !important;color:#a6a6a6 !important;font-family:Helvetica, Arial, sans-serif;text-align:right;border-right:1px solid rgba(0,0,0,0.1);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:1px 0 0 #eee;-moz-box-shadow:1px 0 0 #eee;box-shadow:1px 0 0 #eee;text-shadow:0 1px 0 rgba(255,255,255,0.5)"><div style="position:absolute;bottom:0;right:0;">' +
  108.                  Math.ceil(progress.max * 0.5) +
  109.                  '&nbsp</div></div>'); // 50% marker
  110.  
  111.             let opacity = settings.distinguish_beyond_guru ? burnedOpacity : initialGuruOpacity;
  112.             let gurued_plus_total = totalAtLeast(progress, guruStage);
  113.  
  114.             html += '    <div class="progress" title="Unstarted (' + progress.srs_level_totals[0] + '/' + progress.max + ')" style="border-radius:' + settings.border_radius + 'px !important;">';
  115.             for (let i = settings.distinguish_beyond_guru ? stageNames.length - 1 : guruStage; i >= apprenticeStage; i--) {
  116.                 let name = (!settings.distinguish_beyond_guru && i == guruStage) ? "Guru+" : stageNames[i];
  117.                 let total = (!settings.distinguish_beyond_guru && i == guruStage) ? gurued_plus_total : progress.srs_level_totals[i];
  118.                 let percentage = total * 100.0 / progress.max;
  119.                 let gradient = "linear-gradient(to bottom, " + getColorCode(i) + ", " + (settings.shadow ? "#222" : getColorCode(i)) + ")";
  120.  
  121.                 html +=
  122.                     '      <div class="bar bar-supplemental"  title="' + name + ' (' + total + '/' + progress.max + ')" style="float: left !important; opacity: ' + opacity + ' !important; background-color: #a100f1 !important; background-image: ' + gradient + ' !important; width: ' + (percentage) + '% !important; height: 100% !important; margin:0px !important; border-radius:' + settings.border_radius + 'px !important;">' +
  123.                     '        <span class="dark" style="display: none;"></span>' +
  124.                     '      </div>';
  125.  
  126.                 if (i == burnStage) opacity = enlightenedOpacity;
  127.                 else if (i == enlightenedStage) opacity = masterOpacity;
  128.                 else if (i == masterStage) opacity = initialGuruOpacity;
  129.                 else if (i > guruStage) opacity *= guruOpacityChange;
  130.                 else if (i == guruStage) opacity = initialApprenticeOpacity;
  131.                 else opacity *= apprenticeOpacityChange;
  132.             }
  133.  
  134.             var unlockedCount = 0;
  135.             progress.srs_level_totals.forEach(function(srs_level_total) {
  136.                 unlockedCount += srs_level_total;
  137.             });
  138.             var lockedCount = progress.max - unlockedCount;
  139.             var notStartedWidth = progress.srs_level_totals[0] * 100.0 / progress.max;
  140.             var lockedWidth = lockedCount * 100.0 / progress.max;
  141.  
  142.             html +=
  143.                 '      <div class="bar bar-supplemental" title="Locked (' + lockedCount + '/' + progress.max + ')" style="float:left !important; background-color: #a8a8a8 !important; background-image: ' + locked_data_url + ' !important; width: ' + lockedWidth + '% !important; height: 100% !important; margin:0px !important; margin-left: ' + notStartedWidth + '% !important; border-radius:' + settings.border_radius + 'px !important;">' +
  144.                 '        <span class="dark" style="display: none;"></span>' +
  145.                 '      </div>';
  146.  
  147.             var total = gurued_plus_total == progress.max ? 0 : gurued_plus_total;
  148.             html +=
  149.                 '    </div>' + total + '<span class="pull-right total">' + progress.max + '</span>' +
  150.                 '  </div>' +
  151.                 '</div>';
  152.  
  153.             runningHTML += html;
  154.         });
  155.         window.$('.progress-component').prepend(runningHTML);
  156.     }
  157.  
  158.     function prepareForRender() {
  159.         var cached_json = localStorage.getItem('level-progress-cache');
  160.         var didRender = false;
  161.         if (cached_json) {
  162.             render(JSON.parse(cached_json));
  163.             didRender = true;
  164.         }
  165.  
  166.         window.wkof.ready('ItemData, Apiv2').then(() => {
  167.             window.wkof.Apiv2.get_endpoint('level_progressions').then(levels => {
  168.                 var level_list = [];
  169.                 for (var id in levels) {
  170.                     level_list.push(levels[id]);
  171.                 }
  172.                 var top_level = (level_list.find(l => l.data.abandoned_at == null && l.data.passed_at == null && l.data.unlocked_at != null) || level_list.slice(-1)[0]).data.level;
  173.                 window.wkof.ItemData.get_items('assignments').then(items => {
  174.                     var collection = [];
  175.                     items.forEach(item => {
  176.                         prog = collection.find(p => p.level == item.data.level && p.type == item.object);
  177.                         if (prog == undefined) {
  178.                             var prog = {
  179.                                 level: item.data.level,
  180.                                 type: item.object,
  181.                                 srs_level_totals: Array(10).fill(0),
  182.                                 passed_total: 0,
  183.                                 max: 0
  184.                             };
  185.                             collection.push(prog);
  186.                         }
  187.                         if (item.assignments != undefined && item.assignments.unlocked_at != null) {
  188.                             prog.srs_level_totals[item.assignments.srs_stage]++;
  189.                             if (item.assignments.passed_at != null) {
  190.                                 prog.passed_total++;
  191.                             }
  192.                         }
  193.                         prog.max++;
  194.                     });
  195.                     collection = collection.filter(p => {
  196.                         return p.level <= top_level
  197.                     }).sort((a, b) => {
  198.                         var order = ['radical', 'kanji', 'vocabulary'];
  199.                         return a.level - b.level + (order.indexOf(a.type) - order.indexOf(b.type)) / 10;
  200.                     });
  201.                     var json = {
  202.                         progresses: collection
  203.                     };
  204.                     localStorage.setItem('level-progress-cache', JSON.stringify(json));
  205.                     if (cached_json != json) { render(json); }
  206.                 }); // assignments
  207.             }); // level progressions
  208.         }); // Item Data, APIv2
  209.     }
  210.  
  211.     window.wkof.ready('Menu,Settings').then(load_settings).then(install_menu).then(prepareForRender);
  212.  
  213.     // Load settings and set defaults
  214.     function load_settings() {
  215.         var defaults = {
  216.             progress_hidden: '2',
  217.             progress_hidden_percentage: 90,
  218.             unconditional_progressions: 0,
  219.             border_radius: 10,
  220.             hide_current_level: true,
  221.             require_learned: true,
  222.             show_halfway_marker: true,
  223.             distinguish_beyond_guru: false,
  224.             colorcode_apprentice: '#f300a2',
  225.             colorcode_guru: '#9d34b7',
  226.             colorcode_master: '#4867e0',
  227.             colorcode_enlightened: '#00a5f7',
  228.             colorcode_burned: '#fbb41c',
  229.             shadow: false,
  230.             opacity_multiplier_apprentice: '70',
  231.             opacity_multiplier_guru: '70'
  232.         };
  233.         return window.wkof.Settings.load('level_progress_detail', defaults);
  234.     }
  235.  
  236.     // Installs the options button in the menu
  237.     function install_menu() {
  238.         var config = {
  239.             name: 'level_progress_detail_settings',
  240.             submenu: 'Settings',
  241.             title: 'Dashboard Level Progress Detail',
  242.             on_click: open_settings
  243.         };
  244.         window.wkof.Menu.insert_script_link(config);
  245.     }
  246.  
  247.     // Create the options
  248.     function open_settings(items) {
  249.         var config = {
  250.             script_id: 'level_progress_detail',
  251.             title: 'Dashboard Level Progress Detail',
  252.             content: {
  253.                 tabs: {type:'tabset', content: {
  254.                     pgFilter: {type:'page', label:'Filters', content: {
  255.                         progress_hidden: {
  256.                             type: 'dropdown',
  257.                             label: 'Progress hidden criteria',
  258.                             hover_tip: 'Choose criteria for what progress to hide',
  259.                             default: '2',
  260.                             content: {
  261.                                 1: 'Guru or higher right now',
  262.                                 2: 'Has been guru or higher at any point',
  263.                                 3: 'Master or higher right now',
  264.                                 5: 'Enlightened or higher right now',
  265.                                 7: 'Burnt right now'
  266.                             }
  267.                         },
  268.                         progress_hidden_percentage: {
  269.                             type: 'number',
  270.                             label: 'Progress hidden percentage',
  271.                             hover_tip: 'Determines the percentage of progress necessary to hide',
  272.                             min: 0,
  273.                             max: 100,
  274.                             step: '1',
  275.                             default: '90'
  276.                         },
  277.                         unconditional_progressions: {
  278.                             type: 'number',
  279.                             label: 'Progressions shown unconditionally',
  280.                             hover_tip: 'For example, 3 will always show current level radical, kanji, and vocab progressions',
  281.                             min: 0,
  282.                             default: 3
  283.                         },
  284.                         border_radius: {
  285.                             type: 'number',
  286.                             label: 'Roundedness of progression (in pixels)',
  287.                             hover_tip: 'Choose zero for no roundedness, and 10 for maximum roundedness.',
  288.                             min: 0,
  289.                             default: 10
  290.                         },
  291.                         hide_current_level: {
  292.                             type: 'checkbox',
  293.                             label: 'Hide current level items',
  294.                             hover_tip: 'Check this box to hide the list of radicals and kanji.',
  295.                             default: false
  296.                         },
  297.                         require_learned: {
  298.                             type: 'checkbox',
  299.                             label: 'Require all items to be learned to hide',
  300.                             hover_tip: 'Check this box to require every item to have completed its lesson in a category before hiding it.',
  301.                             default: true
  302.                         },
  303.                         show_halfway_marker: {
  304.                             type: 'checkbox',
  305.                             label: 'Show halfway marker',
  306.                             hover_tip: 'Show 50% marker in addition to 90% marker.',
  307.                             default: true
  308.                         },
  309.                         distinguish_beyond_guru: {
  310.                             type: 'checkbox',
  311.                             label: 'Distinguish beyond Guru',
  312.                             hover_tip: 'Show different colored bars for Guru, Master, Enlightened and Burned',
  313.                             default: false
  314.                         }}},
  315.                     pgColor: {type:'page', label:'Colors', content: {
  316.                         colorcode_apprentice:{
  317.                             type: 'color',
  318.                             label: 'Color Apprentice',
  319.                             hover_tip: 'Color for your Apprentice Progression bar',
  320.                             default: '#f300a2'
  321.                         },
  322.                         colorcode_guru:{
  323.                             type: 'color',
  324.                             label: 'Color Guru',
  325.                             hover_tip: 'Color for your Guru Progression bar',
  326.                             default: '#9d34b7'
  327.                         },
  328.                         colorcode_master:{
  329.                             type: 'color',
  330.                             label: 'Color Master',
  331.                             hover_tip: 'Color for your Master Progression bar',
  332.                             default: '#4867e0'
  333.                         },
  334.                         colorcode_enlightened:{
  335.                             type: 'color',
  336.                             label: 'Color Enlightened',
  337.                             hover_tip: 'Color for your Enlightend Progression Bar',
  338.                             default: '#00a5f7'
  339.                         },
  340.                         colorcode_burned:{
  341.                             type: 'color',
  342.                             label: 'Color Burned',
  343.                             hover_tip: 'Color for your Burned Progression Bar',
  344.                             default: '#fbb41c'
  345.                         },
  346.                         shadow:{
  347.                             type: 'checkbox',
  348.                             label: 'Shadow',
  349.                             hover_tip: 'Display shadow for each progress bar. Works best in dark mode.',
  350.                             default: false
  351.                         },
  352.                         opacity_multiplier_apprentice:{
  353.                             type: 'number',
  354.                             label: 'Fading multiplier Apprentice',
  355.                             hover_tip: 'Determines how quickly the color fades when the Apprentice rank decreases. Should be a number between 1 and 100',
  356.                             min: 1,
  357.                             max: 100,
  358.                             step: '1',
  359.                             default: 70
  360.                         },
  361.                         opacity_multiplier_guru:{
  362.                             type: 'number',
  363.                             label: 'Fading multiplier Guru',
  364.                             hover_tip: 'Determines how quickly the color fades when the Guru rank decreases. Should be a number between 1 and 100',
  365.                             min: 1,
  366.                             max: 100,
  367.                             step: '1',
  368.                             default: 70
  369.                         }
  370.                     }}
  371.                 }
  372.                       }}
  373.         }
  374.         var dialog = new window.wkof.Settings(config);
  375.         dialog.open();
  376.     }
  377. })();
Add Comment
Please, Sign In to add comment