Wanikani Override

Adds an "Ignore Answer" button during reviews that makes WaniKani ignore the current answer (useful if, for example, you made a stupid typo)

目前為 2016-10-03 提交的版本,檢視 最新版本

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

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

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Wanikani Override
// @namespace   wkoverride
// @description Adds an "Ignore Answer" button during reviews that makes WaniKani ignore the current answer (useful if, for example, you made a stupid typo)
// @include     http://www.wanikani.com/review/session*
// @include     https://www.wanikani.com/review/session*
// @version     1.1.3
// @author      Rui Pinheiro
// @grant       GM_addStyle
// @grant       unsafeWindow
// @require     http://code.jquery.com/jquery-1.11.2.min.js
// @license     GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// ==/UserScript==

// ESC shortcut

/*
 * Debug Settings
 */
var debugLogEnabled = true;
var scriptShortName = 'WKO';
scriptLog = debugLogEnabled ? function (msg) {
  if (typeof msg === 'string') {
    console.log(scriptShortName + ': ' + msg);
  } else {
    console.log(msg);
  }
}
 : function () {
};
/*
 * Other settings
 */
var prefAllowUnignore = true;
/*
 * "Ignore Answer" Button Click
 */
var ActionEnum = Object.freeze({
  ignore: 0,
  unignore: 1
});
function WKO_ignoreAnswer()
{
  try
  {
    /* Check if the current item was answered incorrectly */
    var elmnts = document.getElementsByClassName('incorrect');
    var elmnts2 = document.getElementsByClassName('WKO_ignored');
    
    var curAction;
    if (!isEmpty(elmnts[0])) // Current answer is wrong
    curAction = ActionEnum.ignore;
     else if (prefAllowUnignore && !isEmpty(elmnts2[0])) // Current answer is ignored
    curAction = ActionEnum.unignore;
     else
    // Either there is no current answer, or it's correct
    {
      alert('WKO: Current item wasn\'t answered incorrectly, nor ignored previously!');
      return false;
    }
 
    /* Grab information about current question */
 
    var curItem = $.jStorage.get('currentItem');
    var questionType = $.jStorage.get('questionType');
 
    /* Build item name */
    var itemName;
    if (curItem.rad)
    itemName = 'r';
     else if (curItem.kan)
    itemName = 'k';
     else
    itemName = 'v';
    itemName += curItem.id;
    scriptLog(itemName);
    /* Grab item from jStorage.
         * 
         * item.rc and item.mc => Reading/Meaning Completed (if answered the item correctly)
         * item.ri and item.mi => Reading/Meaning Invalid (number of mistakes before answering correctly)
         */
    var item = $.jStorage.get(itemName) || {
    };
    /* Update the item data */
    if (questionType === 'meaning')
    {
      if (!('mi' in item) || isEmpty(item.mi))
      {
        throw Error('item.mi undefined');
        return false;
      } 
      else if (item.mi < 0 || (item.mi == 0 && curAction == ActionEnum.ignore))
      {
        throw Error('item.mi too small');
        return false;
      }
      if (curAction == ActionEnum.ignore)
      item.mi -= 1;
       else
      item.mi += 1;
      delete item.mc;
    } 
    else
    {
      if (!('ri' in item) || isEmpty(item.ri))
      {
        throw Error('item.ri undefined');
        return false;
      } 
      else if (item.ri < 0 || (item.ri == 0 && curAction == ActionEnum.ignore))
      {
        throw Error('i.ri too small');
        return false;
      }
      if (curAction == ActionEnum.ignore)
      item.ri -= 1;
       else
      item.ri += 1;
      delete item.rc;
    }
    /* Save the new state back into jStorage */
 
    $.jStorage.set(itemName, item);
    /* Modify the questions counter and wrong counter and change the style of the answer field */
    var wrongCount = $.jStorage.get('wrongCount');
    var questionCount = $.jStorage.get('questionCount');
    if (curAction == ActionEnum.ignore)
    {
      $.jStorage.set('wrongCount', wrongCount - 1);
      $.jStorage.set('questionCount', questionCount - 1);
      $('#answer-form fieldset').removeClass('incorrect');
      $('#answer-form fieldset').addClass('WKO_ignored');
    } 
    else
    {
      $.jStorage.set('wrongCount', wrongCount + 1);
      $.jStorage.set('questionCount', questionCount + 1);
      $('#answer-form fieldset').removeClass('WKO_ignored');
      $('#answer-form fieldset').addClass('incorrect');
    }
    return true;
  } 
  catch (err) {
    logError(err);
  }
}
/*
 * Bind '~' as a hotkey 
 */
 
function bindHotkey()
{
  jQuery(document).on('keydown.reviewScreen', function (event)
  {
    if ($('#reviews').is(':visible') && !$('*:focus').is('textarea, input'))
    {
      //alert('keycode: ' + event.keyCode);
      switch (event.keyCode) {
        //case 176: //Firefox '~'
        //case 192: //Chrome '~'
        case 27: // ESC Button
          event.stopPropagation();
          event.preventDefault();
          if ($('#user-response').is(':disabled'))
           WKO_ignoreAnswer();
          return false;
          break;
      }
    }
  });
}
/*
 * Inject Ignore Button
 */
 
function addIgnoreAnswerBtn()
{
  var footer = document.getElementsByTagName('footer'),
      $btn = jQuery('<div id="WKO_button" title="Ignore Answer">Ignore Answer</div>').on('click', WKO_ignoreAnswer);
  jQuery(footer[0]).prepend($btn);
}
/*
 * Prepares the script
 */
 
function scriptInit()
{
  // Add global CSS styles
  GM_addStyle('#WKO_button {background-color: #CC0000; color: #FFFFFF; cursor: pointer; display: inline-block; font-size: 0.8125em; padding: 10px; vertical-align: bottom;}');
  GM_addStyle('#answer-form fieldset.WKO_ignored input[type="text"]:-moz-placeholder, #answer-form fieldset.WKO_ignored input[type="text"]:-moz-placeholder {color: #FFFFFF; font-family: "Source Sans Pro",sans-serif; font-weight: 300; text-shadow: none; transition: color 0.15s linear 0s; } #answer-form fieldset.WKO_ignored button, #answer-form fieldset.WKO_ignored input[type="text"], #answer-form fieldset.WKO_ignored input[type="text"]:disabled { background-color: #FFCC00 !important; }');
  scriptLog('loaded');
  // Set up hooks
  try
  {
    addIgnoreAnswerBtn();
    bindHotkey();
  } 
  catch (err) {
    logError(err);
  }
}
/*
 * Helper Functions/Variables
 */
 
//use 'jQuery' for greasemonkey's version, $ is WK's jQuery
 
$ = unsafeWindow.$;
function isEmpty(value) {
  return (typeof value === 'undefined' || value === null);
}
/*
 * Error handling
 * Can use 'error.stack', not cross-browser (though it should work on Firefox and Chrome)
 */
 
function logError(error)
{
  var stackMessage = '';
  if ('stack' in error)
  stackMessage = '\n\tStack: ' + error.stack;
  console.error(scriptShortName + ' Error: ' + error.name + '\n\tMessage: ' + error.message + stackMessage);
}
/*
 * Start the script
 */
 
scriptInit();