Wanikani: Dashboard Apprentice

Displays all your apprentice items on the dashboard

Устаревшая версия за 02.08.2019. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         Wanikani: Dashboard Apprentice
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Displays all your apprentice items on the dashboard
// @author       Kumirei
// @match        https://www.wanikani.com/
// @match        https://www.wanikani.com/dashboard
// @grant        none
// ==/UserScript==

(function() {
    // Make sure WKOF is installed
    if (!wkof) {
        var script_name = 'Wanikani: Dashboard Apprentice';
        var response = confirm(script_name + ' 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;
    }
    // Ready to go
    else {
        wkof.include('ItemData');
        wkof.ready('ItemData')
            .then(fetch_items)
            .then(get_apprentice)
            .then(display);
        add_css();
    }

    // Fetches the items
    function fetch_items() {
        var [promise, resolve] = new_promise();
        wkof.ItemData.get_items('assignments')
            .then(data=>resolve(data))
        return promise;
    }

    // Returns the apprentice items divided by SRS level
    function get_apprentice(data) {
        var apprentice = {1: [], 2: [], 3: [], 4: []};
        for (var i=0; i<data.length; i++) {
            var item = data[i];
            if (item.assignments) {
                var srs_level = item.assignments.srs_stage;
                if (srs_level < 5 && srs_level > 0) {
                    apprentice[srs_level].push(item);
                }
            }
        }
        return apprentice;
    }

    // Puts the information on the dashboard
    function display(data) {
        var elem = $('<div id="wkda_items"></div>')[0];
        if (is_dark_theme()) elem.className = 'dark';
        for (var i=1; i<5; i++) {
            var srs_elem = $('<div class="apprentice_'+i+'"></div>')[0];
            var title = $('<span>Apprentice '+i+'</span>')[0];
            var items = $('<div class="items"></div>')[0];
            srs_elem.appendChild(title);
            srs_elem.appendChild(items);
            for (var j=0; j<data[i].length; j++) {
                var item = data[i][j];
                var info = {type: item.object, characters: item.data.characters, meanings: [], readings: [], level: item.data.level, available: 0, url: item.data.document_url};
                info.available = ((Date.parse(item.assignments.available_at) < Date.now() ? 'Now' : s_to_dhm((Date.parse(item.assignments.available_at)-Date.now())/1000)));
                for (var k=0; k<item.data.meanings.length; k++) {
                    info.meanings.push(item.data.meanings[k].meaning);
                }
                if (item.data.readings) {
                    for (var k=0; k<item.data.readings.length; k++) {
                        info.readings.push(item.data.readings[k].reading);
                    }
                }
                var adjust_left = false;
                if (event.pageX > window.innerWidth/2) adjust_left = true;
                var item_elem = $('<div class="item '+info.type+'"'+(adjust_left ? ' style"transform: translateX(-100%);"' : '')+'>'+
                    '<div class="hover_elem">'+
                        '<div class="left">'+
                            '<a class="'+info.type+'" href="'+info.url+'">'+info.characters+'</a>'+
                        '</div>'+
                        '<div class="right">'+
                            '<table>'+
                                '<tr><td>Meanings</td><td>'+info.meanings.join(', ')+'</td></tr>'+
                                '<tr><td>Readings</td><td>'+info.readings.join('、')+'</td></tr>'+
                                '<tr><td>Level</td><td>'+info.level+'</td></tr>'+
                                '<tr><td>Available</td><td>'+info.available+'</td></tr>'+
                            '</table>'+
                        '</div>'+
                    '</div>'+
                    '<a class="'+info.type+'" href="'+info.url+'">'+info.characters+'</a>'+
                '</div>')[0];
                items.appendChild(item_elem);
            }
            elem.appendChild(srs_elem);
        }
        document.getElementsByClassName('progression')[0].appendChild(elem)

    }

    // Adds the CSS to the page
    function add_css() {
        $('head').append('<style id="wkda_css">'+
                            '#wkda_items > div {'+
                            '    margin-bottom: 10px;'+
                            '}'+
                            '#wkda_items > div > span {'+
                            '    font-size: 16px;'+
                            '}'+
                            '#wkda_items .items {'+
                            '    position: relative;'+
                            '    display: flex;'+
                            '    flex-direction: row;'+
                            '    flex-wrap: wrap;'+
                            '    justify-content: flex-start;'+
                            '    margin-left: -2px;'+
                            '}'+
                            '#wkda_items .items .item {'+
                            '    display: inline-block;'+
                            '    padding: 0 5px;'+
                            '    margin: 2px;'+
                            '    border-radius: 3px;'+
                            '    position: relative;'+
                            '}'+
                            '#wkda_items .items .radical {'+
                            '    background: #0096e7;'+
                            '    order: 0;'+
                            '}'+
                            '#wkda_items .items .kanji {'+
                            '    background: #ff00aa;'+
                            '    order: 1;'+
                            '}'+
                            '#wkda_items .items .vocabulary {'+
                            '    background: #9800e8;'+
                            '    order: 2;'+
                            '}'+
                            '#wkda_items.dark .items .radical {'+
                            '    background: #3daee9;'+
                            '}'+
                            '#wkda_items.dark .items .kanji {'+
                            '    background: #fdbc4b;'+
                            '}'+
                            '#wkda_items.dark .items .vocabulary {'+
                            '    background: #2ecc71;'+
                            '}'+
                            '#wkda_items .hover_elem {'+
                            '    visibility: hidden;'+
                            '    position: absolute;'+
                            '    background-color: rgba(0, 0, 0, 0.9);'+
                            '    z-index: 2;'+
                            '    padding: 5px;'+
                            '    border-radius: 3px;'+
                            '    width: max-content;'+
                            '    transform: translate(-50%, calc(0px - 100% - 5px));'+
                            '    left: 50%;'+
                            '}'+
                            '#wkda_items .item:hover .hover_elem {'+
                            '    visibility: visible; '+
                            '}'+
                            '#wkda_items .hover_elem::after {'+
                            '    visibility: hidden;'+
                            '    position: absolute;'+
                            '    width: 0;'+
                            '    border-top: 5px solid rgba(0, 0, 0, 0.9);'+
                            '    border-right: 5px solid transparent;'+
                            '    border-left: 5px solid transparent;'+
                            '    content: " ";'+
                            '    font-size: 0;'+
                            '    line-height: 0;'+
                            '    left: 50%;'+
                            '    bottom: -5px;'+
                            '    transform: translateX(-50%);'+
                            '}'+
                            '#wkda_items .item:hover .hover_elem::after {'+
                            '    visibility: visible;'+
                            '}'+
                            '#wkda_items .hover_elem > div {'+
                            '    display: inline-block;'+
                            '}'+
                            '#wkda_items .item.vocabulary .hover_elem > div {'+
                            '    display: block;'+
                            '}'+
                            '#wkda_items .left {'+
                            '    vertical-align: top;'+
                            '}'+
                            '#wkda_items .item.vocabulary .hover_elem .left {'+
                            '    margin-bottom: 5px;'+
                            '}'+
                            '#wkda_items .left a {'+
                            '    font-size: 74px;'+
                            '    line-height: 73px;'+
                            '    display: block;'+
                            '    padding: 5px;'+
                            '    border-radius: 3px;'+
                            '    margin: 3px 10px 0 3px;'+
                            '}'+
                            '#wkda_items .item.vocabulary .left a {'+
                            '    margin-right: 3px;'+
                            '    text-align: center;'+
                            '}'+
                            '#wkda_items .right table td:first-child {'+
                            '    padding-right: 10px;'+
                            '    font-weight: bold;'+
                            '}'+
                            '#wkda_items .items table td,'+
                            '#wkda_items .items > div a {'+
                            '    color: rgb(240, 240, 240) !important;'+
                            '}'+
                            '#wkda_items.dark .items > div a {'+
                            '    color: black !important;'+
                            '}'+
                        '</style>');
    }

    // 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');
    }

   // Returns a promise and a resolve function
   function new_promise() {
       var resolve, promise = new Promise((res, rej)=>{resolve = res;});
       return [promise, resolve];
   }

  // Handy little function that rfindley wrote. Checks whether the theme is dark.
  function is_dark_theme() {
      // Grab the <html> background color, average the RGB.  If less than 50% bright, it's dark theme.
      return $('body').css('background-color').match(/\((.*)\)/)[1].split(',').slice(0,3).map(str => Number(str)).reduce((a, i) => a+i)/(255*3) < 0.5;
  }
})();