Wanikani: Lesson Lock

Displays 0 lessons available when you have too much on your plate already

// ==UserScript==
// @name         Wanikani: Lesson Lock
// @namespace    http://tampermonkey.net/
// @version      1.2.2
// @description  Displays 0 lessons available when you have too much on your plate already
// @author       Kumirei
// @include      /^https://(www|preview).wanikani.com/(dashboard)?/
// @grant        none
// ==/UserScript==

;(function (wkof, $) {
    // Check that the Wanikani Framework is installed
    const script_name = 'Lesson Lock'
    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 it's installed then do the stuffs
    else {
        wkof.include('Menu,Settings,ItemData')
        wkof.ready('Menu,Settings,ItemData').then(load_settings).then(install_menu).then(get_counts).then(lock)
    }

    // Fetches the subjects
    function get_counts() {
        const [promise, resolve] = new_promise()
        wkof.ItemData.get_items('subjects,assignments').then(function (items) {
            const srs_counts = {}
            const by_srs = wkof.ItemData.get_index(items, 'srs_stage')
            Object.keys(by_srs).forEach(function (srs_name) {
                srs_counts[srs_name] = by_srs[srs_name].length
            })
            resolve(srs_counts)
        })
        return promise
    }

    // Lock Lessons if score is above the threshold
    function lock(counts) {
        // Calculate score
        const s = wkof.settings.lesson_lock
        const scores = [
            0,
            s.apprentice1,
            s.apprentice2,
            s.apprentice3,
            s.apprentice4,
            s.guru1,
            s.guru2,
            s.master,
            s.enlightened,
        ]
        let score = 0
        for (let i = 1; i < 9; i++) if (counts[i]) score += counts[i] * scores[i]
        const headerButton = $('.lesson-and-review-count__item:first-child')
        const headerCount = $('.lesson-and-review-count__item:first-child .lesson-and-review-count__count')
        const dashboardPanel = $('.todays-lessons')
        const dashboardCount = $('.todays-lessons__count-text .count-bubble')
        const dashboardPanelButtons = $('.todays-lessons__buttons')
        const dashboardPanelText = $('.todays-lessons__text .wk-text')
        const lessons = Number(headerCount.text()) || 0
        // Lock lessons
        if (score >= s.lock) {
            headerCount.addClass('lesson-and-review-count__count--zero')
            headerCount.text(lessons === 0 ? '0' : 'locked')
            headerButton.removeAttr('href')
            dashboardCount.text('Locked')
            dashboardPanel.addClass('todays-lessons--complete')
            dashboardPanelButtons.remove()
            dashboardPanelText.text('Do more reviews to reduce your score and unlock lessons')
        } else if (s.display_lessons_left) {
            const left = Math.ceil((s.lock - score) / s.apprentice1)
            if (lessons > left) headerCount.text(left)
            if (lessons > left) dashboardCount.text(left)
        }
        // Display score
        if (s.display_as != 'none') {
            let score_text
            switch (s.display_as) {
                case 'score':
                    score_text = Math.round(score)
                    break
                case 'score_and_max':
                    score_text = Math.round(score) + ' of ' + s.lock
                    break
                case 'percent':
                    score_text = Math.round((score / s.lock) * 100) + '%'
                    break
            }
            headerButton.append(
                '<div id="lock_score" style="text-align: center; font-size: 12px; position: absolute; bottom: 1px;">Score: ' +
                    score_text +
                    '</div>',
            )
            dashboardPanel.append(
                '<div id="big_lock_score" style="padding-top: 0.5em;color: white;font-weight: bold;">Score: ' +
                    score_text +
                    '</div>',
            )
        }
    }

    // Load stored settings or set defaults
    function load_settings() {
        const defaults = {
            lock: 100,
            display_as: 'score',
            display_lessons_left: false,
            apprentice1: 1,
            apprentice2: 1,
            apprentice3: 1,
            apprentice4: 1,
            guru1: 0,
            guru2: 0,
            master: 0,
            enlightened: 0,
        }
        return wkof.Settings.load('lesson_lock', defaults)
    }

    // Installs the options button in the menu
    function install_menu() {
        const config = {
            name: 'lesson_lock',
            submenu: 'Settings',
            title: 'Lesson Lock',
            on_click: open_settings,
        }
        wkof.Menu.insert_script_link(config)
    }

    // Create the options
    function open_settings(items) {
        const config = {
            script_id: 'lesson_lock',
            title: 'Lesson Lock',
            content: {
                general: {
                    type: 'group',
                    label: 'General',
                    content: {
                        lock: {
                            type: 'number',
                            label: 'Lock when score reaches',
                            hover_tip: 'Locks lessons when your total score is above this number',
                            default: 100,
                        },
                        display_as: {
                            type: 'dropdown',
                            label: 'Display',
                            hover_tip: 'Choose how you want the score to be displayed',
                            content: {
                                none: 'None',
                                score: 'Current score',
                                score_and_max: 'Current score & lock score',
                                percent: 'Percentage of lock score',
                            },
                            default: 'score',
                        },
                        display_lessons_left: {
                            type: 'checkbox',
                            label: 'Display lessons left',
                            hover_tip: 'Display how many more lessons you can do before lessons are locked',
                            default: false,
                        },
                    },
                },
                scores: {
                    type: 'group',
                    label: 'Score Per Item',
                    content: {
                        apprentice1: {
                            type: 'number',
                            label: 'Apprentice 1',
                            hover_tip: 'The score attributed to each apprentice 1 item',
                            default: 1,
                        },
                        apprentice2: {
                            type: 'number',
                            label: 'Apprentice 2',
                            hover_tip: 'The score attributed to each apprentice 2 item',
                            default: 1,
                        },
                        apprentice3: {
                            type: 'number',
                            label: 'Apprentice 3',
                            hover_tip: 'The score attributed to each apprentice 3 item',
                            default: 1,
                        },
                        apprentice4: {
                            type: 'number',
                            label: 'Apprentice 4',
                            hover_tip: 'The score attributed to each apprentice 4 item',
                            default: 1,
                        },
                        guru1: {
                            type: 'number',
                            label: 'Guru 1',
                            hover_tip: 'The score attributed to each guru 1 item',
                            default: 0,
                        },
                        guru2: {
                            type: 'number',
                            label: 'Guru 2',
                            hover_tip: 'The score attributed to each guru 2 item',
                            default: 0,
                        },
                        master: {
                            type: 'number',
                            label: 'Master',
                            hover_tip: 'The score attributed to each master item',
                            default: 0,
                        },
                        enlightened: {
                            type: 'number',
                            label: 'Enlightened',
                            hover_tip: 'The score attributed to each enlightened item',
                            default: 0,
                        },
                    },
                },
            },
        }
        const dialog = new wkof.Settings(config)
        dialog.open()
    }

    // Returns a promise and a resolve function
    function new_promise() {
        let resolve,
            promise = new Promise((res, rej) => {
                resolve = res
            })
        return [promise, resolve]
    }
})(window.wkof, window.jQuery)