WaniKani Lesson Hover Details

Show lesson breakdown by type on hover

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name          WaniKani Lesson Hover Details
// @namespace     https://www.wanikani.com
// @description   Show lesson breakdown by type on hover
// @author        seanblue
// @version       1.2.1
// @include       https://www.wanikani.com/*
// @grant         none
// ==/UserScript==

(function(wkof, $) {
	'use strict';

	if (!wkof) {
		var response = confirm('WaniKani Lesson Hover Details script 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;
	}

	const levelSettingOptions = {
		None: 0,
		CurrentLevel: 1,
		PriorLevels: 2
	};

	// USER SETTING: Change this to display current level data, prior level data, or no level data in parentheses. Use one of the options from "levelSettingOptions".
	const levelSetting = levelSettingOptions.CurrentLevel;

	const lessonMenuItemSelector = '.navigation .navigation-shortcut--lessons a';
	const lessonDashboardItemSelector = 'a.lessons-and-reviews__lessons-button';

    const popoverTemplate = '<div class="popover review-time"><div class="arrow"></div><div class="popover-inner"><div class="popover-content"><p></p></div></div></div>';

    const popoverConfig = {
        html: true,
        animation: false,
        placement: 'bottom',
        trigger: 'hover',
        template: popoverTemplate
    };

	const style = `<style>
	.popover { width: auto; }
	.lhd-table { display: table; margin: 0; padding: 0; }
	.lhd-row { display: table-row; margin: 0; padding: 0; }
	.lhd-cell { display: table-cell; margin: 0; font-size: 0.875rem; }
	.lhd-cell-title { font-weight: bold; padding: 0 5px 0 0; text-align: right; }
	.lhd-cell-value { padding: 0 0 0 5px; text-align: left; }
</style>`;

	$('head').append(style);

	wkof.include('Apiv2');
	wkof.ready('Apiv2').then(fetchData);

	function fetchData() {
		let promises = [];
		promises.push(wkof.Apiv2.get_endpoint('user'));
		promises.push(wkof.Apiv2.get_endpoint('summary'));
		promises.push(wkof.Apiv2.get_endpoint('subjects'));

		Promise.all(promises).then(processData);
	}

	function processData(results) {
		let lessonCounts = getLessonCount(results);
		setupMenuPopover(lessonCounts);
		setupDashboardPopover(lessonCounts);
	}

	function getLessonCount(results) {
		let currentLevel = results[0].level;
		let summary = results[1];
		let subjects = results[2];

		let lessonCounts = {
			radical: 0,
			kanji: 0,
			vocabulary: 0,
			kana_vocabulary: 0,
			currentLevel : {
				radical: 0,
				kanji: 0,
				vocabulary: 0,
				kana_vocabulary: 0
			}
		};

		// Pull the list of subject_ids from the lesson list in 'summary'.
		let lessonSubjectIds = summary.lessons[0].subject_ids;
		lessonSubjectIds.forEach(function(subjectId) {
			let item = subjects[subjectId];
			lessonCounts[item.object]++;

			if (item.data.level === currentLevel) {
				lessonCounts.currentLevel[item.object]++;
			}
		});

		return lessonCounts;
	}

	function setupMenuPopover(lessonCounts) {
		let lessonMenuItem = $(lessonMenuItemSelector);
		if (lessonMenuItem.length === 0) {
			return;
        }

		lessonMenuItem.attr('data-content', getPopoverHtml(lessonCounts)).popover(popoverConfig);
	}

	function setupDashboardPopover(lessonCounts) {
		let lessonDashboardItem = $(lessonDashboardItemSelector);
		if (lessonDashboardItem.length === 0) {
			return;
        }

		lessonDashboardItem.attr('data-content', getPopoverHtml(lessonCounts)).popover(popoverConfig);
	}

	function getPopoverHtml(lessonCounts) {
		return `<div class="lhd-table">
	${getPopoverSectionHtml(lessonCounts, 'Radicals', 'radical')}
	${getPopoverSectionHtml(lessonCounts, 'Kanji', 'kanji')}
	${getPopoverSectionHtml(lessonCounts, 'Vocab', 'vocabulary')}
	${getPopoverSectionHtml(lessonCounts, 'Kana Vocab', 'kana_vocabulary')}
</div>`;
	}

	function getPopoverSectionHtml(lessonCounts, sectionHeader, sectionKey) {
		let rowOpen = '<div class="lhd-row">';

		let headerCell = `<div class="lhd-cell lhd-cell-title">${sectionHeader}</div>`;
		let lessonCountCell = `<div class="lhd-cell lhd-cell-value">${lessonCounts[sectionKey]}</div>`;

		let lessonLevelCountCell = '';

		if (levelSetting === levelSettingOptions.CurrentLevel) {
			lessonLevelCountCell = `<div class="lhd-cell lhd-cell-value">(${lessonCounts.currentLevel[sectionKey]} current level)</div>`;
		}
		else if (levelSetting === levelSettingOptions.PriorLevels) {
			lessonLevelCountCell = `<div class="lhd-cell lhd-cell-value">(${lessonCounts[sectionKey] - lessonCounts.currentLevel[sectionKey]} prior levels)</div>`;
		}

		let rowClose = '</div>';

		return `${rowOpen}${headerCell}${lessonCountCell}${lessonLevelCountCell}${rowClose}`;
	}
})(window.wkof, window.jQuery);