Wanikani: Skip to Quiz

Enables the quiz button without having to go through any of the lessons.

当前为 2021-10-22 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Wanikani: Skip to Quiz
// @namespace    http://tampermonkey.net/
// @version      1.1.1
// @description  Enables the quiz button without having to go through any of the lessons.
// @author       Kumirei
// @match        https://www.wanikani.com/lesson/session
// @match        https://preview.wanikani.com/lesson/session
// @grant        none
// ==/UserScript==
/*global $, wkof */
/*jshint esversion: 9 */

(function() {
  // Make quiz button look clickable
  add_css(
    '#lesson #batch-items ul li[data-index="quiz"] span {background-color: #004fdd; cursor: pointer !important;}',
    "skip-to-quiz-css"
  );

  // Enable clicking quiz button by adding class that the existing
  // click handler / keyup handler checks for before it fires
  onEachElementReady('li[data-index="quiz"]', null, function(e) {
    e = $(e);
    bindFirst(e, "click", function() {
      e.addClass("active-quiz");
    });
    bindFirst($("body"), "keyup", function(evt) {
      if (evt.key == "q") e.addClass("active-quiz");
    });
  });

  // Library Functions

  // Adds CSS to document
  // Does not escape its input
  function add_css(css, id = "") {
    document
      .getElementsByTagName("head")[0]
      .insertAdjacentHTML("beforeend", `<style id="${id}">${css}</style>`);
  }

  // Calls callback once on each element matching selector that is added
  // to the DOM, including existing elements at the time the function is first called.
  // options is options for the MutationObserver (optional, is merged with default options  {childList: true, subtree: true})
  function onEachElementReady(selector, options, callback) {
    if (!options) options = {};

    let els_found = new Set();
    function check_available() {
      for (const el of document.querySelectorAll(selector)) {
        if (!els_found.has(el)) {
          els_found.add(el);
          callback(el);
        }
      }
    }

    queueMicrotask(check_available);

    let mo = new MutationObserver(check_available);
    mo.observe(document.documentElement, {
      childList: true,
      subtree: true,
      ...options
    });
  }

  // Adds a jQuery event listener that runs before all ones added so far
  // Based on https://stackoverflow.com/questions/2360655/jquery-event-handlers-always-execute-in-order-they-were-bound-any-way-around-t
  // [name] is the name of the event "click", "mouseover", ..
  // same as you'd pass it to bind()
  // [fn] is the handler function
  let bindFirst = function(jqel, name, fn) {
    // bind as you normally would
    // don't want to miss out on any jQuery magic
    jqel.on(name, fn);

    // Thanks to a comment by @Martin, adding support for
    // namespaced events too.
    jqel.each(function() {
      var handlers = $._data(this, "events")[name.split(".")[0]];
      // take out the handler we just inserted from the end
      var handler = handlers.pop();
      // move it at the beginning
      handlers.splice(0, 0, handler);
    });
  };
})();