Wanikani: Skip to Quiz

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

目前為 2021-10-22 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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);
    });
  };
})();