// ==UserScript==
// @name WaniKani Vocab Beyond
// @author Norman Sue
// @description Shows WWWJDIC vocab with Forvo audio for each kanji in lessons, reviews, and kanji pages. A paid Forvo API key is required for audio.
// @version 0.6.0
// @update 4/28/2019, 7:24:38 PM
// @grant GM_xmlhttpRequest
// @include https://www.wanikani.com/*
// @run-at document-start
// @namespace https://greasyfork.org/en/users/56591-normful
// @connect nihongo.monash.edu
// @connect apifree.forvo.com
// @license The MIT License (MIT); http://opensource.org/licenses/MIT
// ==/UserScript==
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var gm_http_1 = __webpack_require__(1);
var app_1 = __webpack_require__(2);
// Set `debug: true` to enable GM.xmlHttpRequest logging
gm_http_1.default.setConfig({ debug: true });
var app = new app_1.App();
app.init();
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory();
else {}
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Created by axetroy on 17-6-23.
*/
/// <reference path="./index.d.ts" />
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
function isFunction(func) {
return typeof func === 'function';
}
var Http = (function () {
function Http(config) {
if (config === void 0) { config = {}; }
this.config = config;
}
Http.prototype.setConfig = function (config) {
if (config === void 0) { config = {}; }
this.config = __assign({}, this.config, config);
};
Http.prototype.create = function (config) {
return new Http(config);
};
Http.prototype.request = function (method, url, data, header, config) {
var _this = this;
if (data === void 0) { data = ''; }
if (header === void 0) { header = {}; }
if (config === void 0) { config = {}; }
return new Promise(function (resolve, reject) {
var commonRequestConfig = {
method: method,
url: url,
data: data,
header: header
};
var GM_xmlhttpRequestConfig = __assign({}, commonRequestConfig, config, _this.config);
var onreadystatechange = GM_xmlhttpRequestConfig.onreadystatechange, onerror = GM_xmlhttpRequestConfig.onerror, onabort = GM_xmlhttpRequestConfig.onabort, ontimeout = GM_xmlhttpRequestConfig.ontimeout;
GM_xmlhttpRequestConfig.synchronous = true; // async
GM_xmlhttpRequestConfig.onreadystatechange = function (response) {
try {
isFunction(onreadystatechange) &&
onreadystatechange.call(this, response);
}
catch (err) {
reject(err);
}
if (response.readyState !== 4)
return;
response.status >= 200 && response.status < 400
? resolve(response)
: reject(response);
};
GM_xmlhttpRequestConfig.onerror = function (response) {
try {
isFunction(onerror) && onerror.call(this, response);
reject(response);
}
catch (err) {
reject(err);
}
};
GM_xmlhttpRequestConfig.onabort = function (response) {
try {
isFunction(onabort) && onabort.call(this, response);
reject(response);
}
catch (err) {
reject(err);
}
};
GM_xmlhttpRequestConfig.ontimeout = function (response) {
try {
isFunction(ontimeout) && ontimeout.call(this, response);
reject(response);
}
catch (err) {
reject(err);
}
};
if (_this.config.debug) {
console.log("%c[" + commonRequestConfig.method.toUpperCase() + "]%c: " + commonRequestConfig.url, 'color: green', 'color: #000;text-style: under-line');
}
GM_xmlhttpRequest(__assign({}, GM_xmlhttpRequestConfig));
});
};
Http.prototype.get = function (url, data, header, config) {
return this.request('GET', url, data, header, config);
};
Http.prototype.post = function (url, data, header, config) {
return this.request('POST', url, data, header, config);
};
Http.prototype.put = function (url, data, header, config) {
return this.request('PUT', url, data, header, config);
};
Http.prototype['delete'] = function (url, data, header, config) {
return this.request('DELETE', url, data, header, config);
};
Http.prototype.head = function (url, data, header, config) {
return this.request('HEAD', url, data, header, config);
};
return Http;
}());
exports.Http = Http;
var timeout = 5000;
exports.timeout = timeout;
var http = new Http({ timeout: timeout });
exports.http = http;
exports.default = http;
/***/ })
/******/ ]);
});
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var runAllWkofDependentCode_1 = __webpack_require__(3);
var App = /** @class */ (function () {
function App() {
}
App.prototype.init = function () {
addEventListener("DOMContentLoaded", this.onDomContentLoaded.bind(this));
};
App.prototype.onDomContentLoaded = function () {
runAllWkofDependentCode_1.runAllWkofDependentCode();
};
return App;
}());
exports.App = App;
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var logger_1 = __webpack_require__(4);
var appConstants_1 = __webpack_require__(5);
var insertInitialDOMElements_1 = __webpack_require__(6);
var waitForWkof_1 = __webpack_require__(21);
var wkofConstants_1 = __webpack_require__(24);
var Log = new logger_1.Logger();
function runAllWkofDependentCode() {
waitForWkof_1.waitForWkof(appConstants_1.prettyScriptName, function (wkof) {
wkof.include("Menu,Settings");
wkof.ready("Menu,Settings").then(function () {
wkof.Menu.insert_script_link({
name: wkofConstants_1.MenuScriptLinkId,
submenu: "Settings",
title: "Vocab Beyond",
on_click: onSettingsMenuLinkClick.bind(null, wkof)
});
wkof.Settings.load(wkofConstants_1.SettingsScriptId).then(function (settings) {
insertInitialDOMElements_1.insertInitialDOMElements(settings);
});
});
});
}
exports.runAllWkofDependentCode = runAllWkofDependentCode;
function onSettingsMenuLinkClick(wkof) {
var dialog = new wkof.Settings(__assign({}, wkofConstants_1.WkofSettingsMenuConfig, { on_save: onSettingsSave.bind(null, wkof) }));
dialog.open();
}
function onSettingsSave(wkof) {
window.location.reload(false);
}
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* tslint:disable:no-console */
Object.defineProperty(exports, "__esModule", { value: true });
var logPrefix = "[WKVB] ";
var Logger = /** @class */ (function () {
function Logger() {
this.prefix = logPrefix;
this.disableLogging = false; // Set to false for development
}
Logger.prototype.debug = function (msg) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.disableLogging) {
return;
}
console.debug.apply(console, [this.prefix + msg].concat(args));
};
Logger.prototype.info = function (msg) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.disableLogging) {
return;
}
console.log.apply(console, [this.prefix + msg].concat(args));
};
Logger.prototype.warn = function (msg) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.disableLogging) {
return;
}
console.warn.apply(console, [this.prefix + msg].concat(args));
};
Logger.prototype.error = function (msg) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.disableLogging) {
return;
}
console.error.apply(console, [this.prefix + msg].concat(args));
};
return Logger;
}());
exports.Logger = Logger;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.prettyScriptName = "WaniKani Vocab Beyond";
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var logger_1 = __webpack_require__(4);
var determinePageType_1 = __webpack_require__(7);
var domConstants_1 = __webpack_require__(8);
var queryWwwjdicThenInsertParsedResults_1 = __webpack_require__(9);
var Log = new logger_1.Logger();
function insertInitialDOMElements(settings) {
Log.debug("insertInitialDOMElements called");
var pageType = determinePageType_1.determinePageType(document.URL);
if (pageType === determinePageType_1.PageType.kanji && !settings.show_vocab_beyond_first) {
insertPageListHeaderLink();
}
maybeLoadVocabDependingOnPage(pageType, settings);
}
exports.insertInitialDOMElements = insertInitialDOMElements;
var insertedPageListHeaderLink = false;
function insertPageListHeaderLink() {
Log.debug("insertPageListHeaderLink called");
if (insertedPageListHeaderLink) {
return;
}
var header = $(".page-list-header");
var listItem = $("<li>");
var link = $("<a href='#" + domConstants_1.sectionHeaderID + "''>Vocab Beyond</a>");
listItem.append(link);
// Other scripts may have altered this list, so just insert this link at the end
listItem.insertAfter(header.siblings().last());
insertedPageListHeaderLink = true;
}
function maybeLoadVocabDependingOnPage(pageType, settings) {
Log.debug("maybeLoadVocabDependingOnPage called");
if (pageType === determinePageType_1.PageType.other) {
Log.debug("maybeLoadVocabDependingOnPage returning early. PageType.other");
return;
}
var optAttrs = { attributes: true };
var optChildList = { childList: true };
if (pageType === determinePageType_1.PageType.kanji) {
Log.debug("maybeLoadVocabDependingOnPage PageType.kanji");
createSectionAndRunQuery(settings);
}
else if (pageType === determinePageType_1.PageType.reviews) {
Log.debug("maybeLoadVocabDependingOnPage PageType.reviews");
var ob = new MutationObserver(function (mutationRecords) {
mutationRecords.forEach(checkReviewMut.bind(null, settings));
});
// Observe the element that is mutated after clicking the
// Item Info icon with the eye on it
ob.observe(document.getElementById("item-info-col2"), optChildList);
}
else if (pageType === determinePageType_1.PageType.lessons) {
Log.debug("maybeLoadVocabDependingOnPage PageType.lessons");
var obs = new MutationObserver(function (mutationRecords) {
if (isKanjiLesson()) {
createSectionAndRunQuery(settings);
}
else {
Log.debug("not doing anything because not kanji lesson");
}
});
// Observe the 3 elements for the 3 lesson types, that are modified
// when switching to each new lesson item
obs.observe(document.getElementById("supplement-rad"), optAttrs);
obs.observe(document.getElementById("supplement-kan"), optAttrs);
obs.observe(document.getElementById("supplement-voc"), optAttrs);
}
}
function createSectionAndRunQuery(settings) {
var emptySection = maybeInsertEmptyVocabSectionOnce(settings);
queryWwwjdicThenInsertParsedResults_1.queryWwwjdicThenInsertParsedResults(settings, emptySection);
}
function isKanjiLesson() {
var mainInfo = document.getElementById("main-info");
return mainInfo && mainInfo.className === "kanji";
}
var createdSectionForKanjiReview = false;
function checkReviewMut(settings, mutationRecord) {
var isKanjiReview = $("#question-type")
.text()
.toLowerCase()
.includes("kanji");
if (mutationRecord.target.id.includes("item-info") &&
isKanjiReview &&
!createdSectionForKanjiReview) {
createdSectionForKanjiReview = true;
createSectionAndRunQuery(settings);
}
}
function maybeInsertEmptyVocabSectionOnce(settings) {
var pageType = determinePageType_1.determinePageType(document.URL);
Log.debug("maybeInsertEmptyVocabSectionOnce pageType", pageType);
if ($("#" + domConstants_1.sectionID).length === 0) {
var sectionHTML = "<section>" +
'<h2 id="' +
domConstants_1.sectionHeaderID +
'">Vocab Beyond</h2>' +
'<div id="' +
domConstants_1.sectionID +
'"></div>' +
"</section>";
if (pageType === determinePageType_1.PageType.kanji) {
Log.debug("maybeInsertEmptyVocabSectionOnce inserting for kanji page");
var informationSection = $("#information");
if (settings.show_vocab_beyond_first) {
$(sectionHTML).insertAfter(informationSection);
}
else {
var lastSection = informationSection.siblings().last();
$(sectionHTML).insertAfter(lastSection);
}
}
else if (pageType === determinePageType_1.PageType.reviews) {
Log.debug("maybeInsertEmptyVocabSectionOnce inserting for reviews page");
if (settings.show_vocab_beyond_first) {
$("#item-info-col2").prepend(sectionHTML);
}
else {
$("#item-info-col2").append(sectionHTML);
}
}
else if (pageType === determinePageType_1.PageType.lessons) {
Log.debug("maybeInsertEmptyVocabSectionOnce inserting for lessons page");
if (settings.show_vocab_beyond_first) {
$("#supplement-kan-breakdown .col1").append(sectionHTML);
}
else {
$("#supplement-kan-related-vocabulary .col1").append(sectionHTML);
}
}
else {
Log.debug("maybeInsertEmptyVocabSectionOnce not inserting because page type does not match");
}
}
return $("#" + domConstants_1.sectionID);
}
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var PageType;
(function (PageType) {
PageType[PageType["other"] = 0] = "other";
PageType[PageType["radicals"] = 1] = "radicals";
PageType[PageType["kanji"] = 2] = "kanji";
PageType[PageType["vocabulary"] = 3] = "vocabulary";
PageType[PageType["reviews"] = 4] = "reviews";
PageType[PageType["reviewsSummary"] = 5] = "reviewsSummary";
PageType[PageType["lessons"] = 6] = "lessons";
PageType[PageType["lessonsReviews"] = 7] = "lessonsReviews";
})(PageType = exports.PageType || (exports.PageType = {}));
function determinePageType(url) {
if (/\/radicals\/./.test(url)) {
return PageType.radicals;
}
else if (/com\/kanji\/./.test(url)) {
return PageType.kanji;
}
else if (/com\/vocabulary\/./.test(url)) {
return PageType.vocabulary;
}
else if (/com\/review\/session/.test(url)) {
return PageType.reviews;
}
else if (/com\/review/.test(url)) {
return PageType.reviewsSummary;
}
else if (/com\/lesson\/./.test(url)) {
return PageType.lessons;
}
// TODO: Figure out what URL lessonsReviews is for
return PageType.other;
}
exports.determinePageType = determinePageType;
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sectionHeaderID = "wanikani_vocab_beyond_section_header";
exports.sectionID = "wanikani_vocab_beyond_section";
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var gm_http_1 = __webpack_require__(1);
var logger_1 = __webpack_require__(4);
var determinePageType_1 = __webpack_require__(7);
var getKanji_1 = __webpack_require__(10);
var makeWwwjdicUrl_1 = __webpack_require__(11);
var parsing_1 = __webpack_require__(12);
var insertForvoAudioForWord_1 = __webpack_require__(19);
var Log = new logger_1.Logger();
var cachedSections = {};
var DISABLE_FORVO_DEFAULT = false;
function shouldDisableForvo(settings) {
var retVal = DISABLE_FORVO_DEFAULT;
if (!settings.forvo_api_key || settings.forvo_api_key === "") {
retVal = true;
}
Log.debug("shouldDisableForvo", retVal);
return retVal;
}
function queryWwwjdicThenInsertParsedResults(settings, emptySection) {
Log.debug("queryWwwjdic");
if (!emptySection.length) {
Log.debug("queryWwwjdicThenInsertParsedResults returning early because emptySection has no elements");
return;
}
var pageType = determinePageType_1.determinePageType(document.URL);
var kanji = getKanji_1.getKanji(pageType);
if (!kanji) {
Log.error("queryWwwjdicThenInsertParsedResults could not get kanji");
return;
}
if (cachedSections[kanji]) {
Log.debug("queryWwwjdicThenInsertParsedResults reusing cachedSection and returning early");
emptySection.replaceWith(cachedSections[kanji]);
return;
}
var showMessage = function (message) {
emptySection.html(message);
};
showMessage("Loading...");
Log.debug("Querying WWWJDIC for ", kanji);
var wwwJdicUrl = makeWwwjdicUrl_1.makeWwwjdicUrl(kanji, settings);
gm_http_1.default
.get(wwwJdicUrl)
.then(function (res) {
onWwwJdicResponse(res.responseText, emptySection, showMessage, settings, kanji);
})
.catch(function (err) {
Log.error("WWWJDIC error: ", err);
showMessage("Error contacting WWWJDIC server");
});
}
exports.queryWwwjdicThenInsertParsedResults = queryWwwjdicThenInsertParsedResults;
var appendedForvoAttribution = false;
function onWwwJdicResponse(res, section, showMessage, settings, kanji) {
Log.debug("onWwwJdicResponse raw res", res);
var lines = parsing_1.extractLines(res);
if (lines.length === 0) {
showMessage(settings.show_all_wwwjdic_vocab
? "No vocabulary found."
: "No common vocabulary found.");
return;
}
// Clear loading text
showMessage("");
var renderables = parsing_1.parseLines(lines);
var maybeOnlyCommonRenderables = renderables.filter(function (renderable) {
if (settings.show_all_wwwjdic_vocab) {
return true;
}
var isCommon = renderable.cm;
return isCommon;
});
Log.debug("WWWJDIC maybeOnlyCommonRenderables.length", maybeOnlyCommonRenderables.length);
var sliceEnd = maybeOnlyCommonRenderables.length;
var limit = settings.max_wwwjdic_vocab_shown;
if (limit > 0) {
sliceEnd = limit;
}
var renderablesWithinLimit = maybeOnlyCommonRenderables.slice(0, sliceEnd);
Log.debug("WWWJDIC renderablesWithinLimit.length", renderablesWithinLimit.length);
Log.debug("WWWJDIC renderablesWithinLimit", renderablesWithinLimit);
var disableForvo = shouldDisableForvo(settings);
if (!disableForvo) {
insertForvoAudioForWord_1.populateForvoUserWhitelist(settings);
}
var promises = renderablesWithinLimit.map(function (renderable) {
var jpText = renderable.jp;
var enPOSText = renderable.pos;
var isCommon = renderable.cm;
var definitions = renderable.en;
var vocabForQueryingForvo = renderable.q;
var listItem = $("<div>");
listItem.css({ marginBottom: "35px" });
var jpEl = $("<h3>");
var _loop_1 = function (codePoint) {
var span = $("<span>");
span.text(codePoint);
var codePointInt = codePoint.codePointAt(0);
span.css("font-size", shouldRenderBig(codePointInt) ? "45px" : "11px");
// Clicking on kanji opens page for it
if (isKanjiCodePoint(codePointInt)) {
span.on("click", function () {
window.open("https://www.wanikani.com/kanji/" + encodeURIComponent(codePoint), "_blank");
});
span.hover(function () {
$(this).css("cursor", "pointer");
});
}
span.css({
fontWeight: "normal",
lineHeight: "45px"
});
jpEl.append(span);
};
// for...of iterates over Unicode code points
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/@@iterator
for (var _i = 0, jpText_1 = jpText; _i < jpText_1.length; _i++) {
var codePoint = jpText_1[_i];
_loop_1(codePoint);
}
if (!isCommon && !settings.hide_uncommon_indicator) {
// uncommon vocab indicator
var uc = $("<span>");
uc.text("稀");
uc.css({
position: "absolute",
display: "block",
fontSize: "12px",
height: "22px",
width: "22px",
top: "0",
left: "-25px",
margin: "0",
padding: "0",
boxSizing: "border-box",
borderRadius: "50%",
textAlign: "center",
lineHeight: "22px",
textShadow: "0.7px 0.2px 4.1px #FFF9DE",
backgroundColor: "#E38B32",
boxShadow: "0 -3px 0 rgba(0,0,0,0.2) inset, 0 0 10px rgba(255,255,255,0.5)",
color: "#F41300",
zIndex: "999"
});
jpEl.append(uc);
}
jpEl.css({
position: "relative",
marginTop: "20px",
marginRight: "0",
marginBottom: "15px",
marginLeft: "0",
padding: "0"
});
listItem.append(jpEl);
var enPOSEl = $("<h3>");
enPOSEl.text(enPOSText);
enPOSEl.css({
fontSize: "20px",
fontWeight: "normal",
lineHeight: "20px",
padding: "0"
});
listItem.append(enPOSEl);
definitions.forEach(function (definition) {
var enDefnEl = $("<p>");
enDefnEl.text(definition);
enDefnEl.css({
margin: "0",
padding: "0"
});
listItem.append(enDefnEl);
});
section.append(listItem);
if (!disableForvo) {
return insertForvoAudioForWord_1.insertForvoAudioForWord(vocabForQueryingForvo, settings, listItem);
}
return Promise.resolve();
});
Promise.all(promises).then(function () {
if (!disableForvo && !appendedForvoAttribution) {
var forvoAttribution = $('<p><a href="https://forvo.com/" target="_blank">Pronunciations by Forvo</a></p>');
section.append(forvoAttribution);
appendedForvoAttribution = true;
}
var sectionDeepClone = section.clone(true, true);
cachedSections[kanji] = sectionDeepClone;
});
}
function isKanjiCodePoint(codePointInt) {
return codePointInt >= 19968 && codePointInt <= 40879;
}
function shouldRenderBig(codePointInt) {
// Determined from "\u3040".codePointAt(0)
// All other hiragana, katakana, kanji have higher code points
var firstHiraganaCodePointInt = 12352;
if (codePointInt > firstHiraganaCodePointInt) {
return true;
}
var punctuationToRenderBig = [
11816,
11817,
12289,
12293 // repeater
];
if (punctuationToRenderBig.includes(codePointInt)) {
return true;
}
return false;
}
exports.shouldRenderBig = shouldRenderBig;
/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var determinePageType_1 = __webpack_require__(7);
function getKanji(pageType) {
switch (pageType) {
case determinePageType_1.PageType.kanji:
return document.title[document.title.length - 1];
case determinePageType_1.PageType.reviews:
var curItem = $.jStorage.get("currentItem");
if ("kan" in curItem) {
return curItem.kan.trim();
}
else {
return null;
}
case determinePageType_1.PageType.lessons:
var kanjiNode = $("#character");
if (kanjiNode === undefined || kanjiNode === null) {
return null;
}
return kanjiNode.text().trim();
}
return null;
}
exports.getKanji = getKanji;
/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// API Docs: http://www.edrdg.org/wwwjdic/wwwjdicinf.html#backdoor_tag
function makeWwwjdicUrl(kanji, settings) {
var encodedKanji = encodeURIComponent(kanji);
var useEDICT = "1";
var useBackdoorEntryRawOutput = "Z";
var searchType;
var dictionaryLookupWithUTF8LookupText = "U";
searchType = dictionaryLookupWithUTF8LookupText;
var keyType;
var lookupKanjiInAnyPosition = "L";
keyType = lookupKanjiInAnyPosition;
var queryCode = useEDICT + useBackdoorEntryRawOutput + searchType + keyType;
return ("http://nihongo.monash.edu/cgi-bin/wwwjdic?" + queryCode + encodedKanji);
}
exports.makeWwwjdicUrl = makeWwwjdicUrl;
/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vocab_header_1 = __webpack_require__(13);
var part_of_speech_1 = __webpack_require__(17);
var definition_line_1 = __webpack_require__(18);
function extractLines(rawResponseText) {
if (rawResponseText.indexOf("No matches were found for this key") > -1) {
return [];
}
var noHeader = rawResponseText.slice(rawResponseText.indexOf("<pre>") + 6);
var preBody = noHeader.slice(0, noHeader.indexOf("</pre>") - 1);
return preBody.split(/\r?\n/);
}
exports.extractLines = extractLines;
var commonP = /(.*)\/\(P\)$/;
function parseLines(lines) {
return lines.map(function (untrimmed) {
var line = untrimmed.trim();
// Extract vocab header
var sepIdx = line.indexOf(" /");
var vocabHeader = line.substring(0, sepIdx);
var rest = line.substring(sepIdx + 2);
// Extract part of speech
var firstRightParen = rest.indexOf(")");
var partOfSpeech = rest.substring(1, firstRightParen);
var englishAndMaybeCommonP = rest.substring(firstRightParen + 2, rest.length - 1);
// Extract common indicator from end of line
var commonMatches = englishAndMaybeCommonP.match(commonP);
var isCommon;
var english;
if (commonMatches) {
isCommon = true;
english = commonMatches[1].replace(/\//g, "; ");
}
else {
isCommon = false;
english = englishAndMaybeCommonP.replace(/\//g, "; ");
}
var definitions = [];
var thisDefn;
if (english.indexOf("(1) ") === 0) {
var nextDefNum = 2;
var cur = 0; // index of start of current definition text
var next = 0; // index of start of next definition text
while (true) {
next = english.indexOf("(" + nextDefNum + ")", cur);
if (next > -1) {
thisDefn = english.substring(cur, next - 1);
definitions.push(definition_line_1.formatDefinitionLine(dottedListItem(thisDefn)));
nextDefNum++;
cur = next;
}
else {
thisDefn = english.substring(cur);
definitions.push(definition_line_1.formatDefinitionLine(dottedListItem(thisDefn)));
break;
}
}
}
else {
definitions.push(definition_line_1.formatDefinitionLine(english));
}
return {
jp: vocab_header_1.formatVocabHeader(vocabHeader),
pos: part_of_speech_1.formatPartOfSpeech(partOfSpeech),
cm: isCommon,
en: definitions,
q: extractVocab(vocabHeader)
};
});
}
exports.parseLines = parseLines;
var parenListItemRegExp = /\((\d+)\)(.*)/;
function dottedListItem(text) {
var matches = text.match(parenListItemRegExp);
if (!matches) {
return text;
}
return matches[1] + "." + matches[2].replace(/;$/, "");
}
// 3040-309F: hiragana
// 30A0-30FF: katakana
// 4E00-9FAF: common and uncommon kanji
var jpRegex = /([\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FAF])+/;
function extractVocab(jpText) {
var matches = jpText.match(jpRegex);
return matches ? matches[0] : jpText;
}
/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vocab_1 = __webpack_require__(14);
var pronunciation_1 = __webpack_require__(16);
var pronunciationSplitter = /(.*)\[(.+)\]$/;
function formatVocabHeader(text) {
var m = text.match(pronunciationSplitter);
if (!m) {
return text;
}
return vocab_1.formatVocab(m[1].trim()) + pronunciation_1.formatPronunciation(m[2]);
}
exports.formatVocabHeader = formatVocabHeader;
/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var dict_codes_1 = __webpack_require__(15);
var dictCodeSplitter = /(.*)\(([a-z,A-Z-,0-9]+)\)$/;
function formatVocab(words) {
return words
.replace(/\(P\)/g, "(common)")
.split(";")
.map(function (word) {
var trimmed = word.trim();
var m = trimmed.trim().match(dictCodeSplitter);
if (!m) {
return trimmed;
}
return m[1] + "(" + (dict_codes_1.DICT_CODES[m[2]] || m[2]) + ")";
})
.join("、");
}
exports.formatVocab = formatVocab;
/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DICT_CODES = {
abbr: "abbreviation",
"adj-f": "noun or verb acting prenominally",
"adj-i": "i-adjective",
"adj-kari": "'kari' adjective (archaic)",
"adj-ku": "'ku' adjective (archaic)",
"adj-na": "na-adjective",
"adj-nari": "archaic/formal form of na-adjective",
"adj-no": "no-adjective",
"adj-pn": "pre-noun adjectival (rentaishi)",
"adj-s": "special adjective",
"adj-shiku": "'shiku' adjective (archaic)",
"adj-t": "'taru' adjective",
adv: "adverb",
"adv-n": "adverbial noun",
"adv-to": "adverb taking the と particle",
an: "adjectival noun (keiyoudoushi)",
anat: "anatomical term",
arch: "archaism",
archit: "architecture term",
astron: "astronomy term",
ateji: "ateji reading",
aux: "auxiliary",
"aux-adj": "auxiliary adjective",
"aux-v": "auxiliary verb",
baseb: "baseball term",
biol: "biology term",
bot: "botany term",
Buddh: "Buddhist term",
bus: "business term",
c: "company name",
chem: "chemistry term",
chn: "children's language",
col: "colloquialism",
comp: "computer terminology",
conj: "conjunction",
ctr: "counter",
derog: "derogatory word or expression",
econ: "economics term",
eK: "exclusively written in kanji",
engr: "engineering term",
exp: "expression",
f: "female given name",
fam: "familiar language",
fem: "female term or language",
finc: "finance term",
food: "food term",
g: "given name, as-yet not classified by sex",
geol: "geology term",
geom: "geometry term",
gikun: "gikun (meaning) reading",
gram: "grammatical term",
h: "full (family plus given) name of a person",
hob: "Hokkaido-ben",
hon: "honorific language (sonkeigo)",
hum: "humble language (kenjougo)",
id: "idiomatic expression",
ik: "irregular kana",
iK: "irregular kanji",
int: "interjection",
io: "irregular okurigana",
iv: "irregular verb",
joc: "jocular, humorous term",
ksb: "Kansai-ben",
ktb: "Kantou-ben",
kyb: "Kyoto-ben",
kyu: "Kyuushuu-ben",
law: "law term",
ling: "linguistics terminology",
m: "male given name",
"m-sl": "manga slang",
MA: "martial arts term",
male: "male term or language",
"male-sl": "male slang",
math: "mathematics",
med: "medical term",
mil: "military",
music: "music term",
n: "noun",
"n-adv": "adverbial noun",
"n-pr": "proper noun",
"n-pref": "prefix noun",
"n-suf": "suffix noun",
"n-t": "temporal noun",
nab: "Nagano-ben",
neg: "negative (in a negative sentence, or with negative verb)",
"neg-v": "negative verb (when used with)",
num: "numeral",
o: "organization name",
obs: "obsolete term",
obsc: "obscure term",
ok: "outdated kana",
oK: "outdated kanji",
"on-mim": "onomatopoeic or mimetic word",
osb: "Osaka-ben",
p: "place-name",
physics: "physics terminology",
pn: "pronoun",
poet: "poetical term",
pol: "polite language",
pr: "product name",
pref: "prefix",
proverb: "proverb",
prt: "particle",
qv: "quod vide (see another entry)",
rare: "rare",
rkb: "Ryukyuan language",
s: "surname",
sens: "sensitive",
Shinto: "Shinto term",
sl: "slang",
sports: "sports term",
st: "station name",
suf: "suffix",
sumo: "sumo term",
thb: "Touhoku-ben",
tsb: "Tosa-ben",
tsug: "Tsugaru-ben",
u: "unclassified name",
uk: "usually written using kana alone",
uK: "usually written using kanji alone",
"v-unspec": "verb unspecified",
v1: "ichidan verb",
"v2a-s": "nidan verb (archaic)",
"v2b-k": "nidan verb (archaic)",
"v2b-s": "nidan verb (archaic)",
"v2d-k": "nidan verb (archaic)",
"v2d-s": "nidan verb (archaic)",
"v2g-k": "nidan verb (archaic)",
"v2g-s": "nidan verb (archaic)",
"v2h-k": "nidan verb (archaic)",
"v2h-s": "nidan verb (archaic)",
"v2k-k": "nidan verb (archaic)",
"v2k-s": "nidan verb (archaic)",
"v2m-k": "nidan verb (archaic)",
"v2m-s": "nidan verb (archaic)",
"v2n-s": "nidan verb (archaic)",
"v2r-k": "nidan verb (archaic)",
"v2r-s": "nidan verb (archaic)",
"v2s-s": "nidan verb (archaic)",
"v2t-k": "nidan verb (archaic)",
"v2t-s": "nidan verb (archaic)",
"v2w-s": "nidan verb (archaic)",
"v2y-k": "nidan verb (archaic)",
"v2y-s": "nidan verb (archaic)",
"v2z-s": "nidan verb (archaic)",
v4b: "yodan verb (archaic)",
v4g: "yodan verb (archaic)",
v4h: "yondan verb (archaic)",
v4k: "yodan verb (archaic)",
v4m: "yodan verb (archaic)",
v4n: "yodan verb (archaic)",
v4r: "yondan verb (archaic)",
v4s: "yodan verb (archaic)",
v4t: "yodan verb (archaic)",
v5aru: "godan verb",
v5b: "godan verb",
v5g: "godan verb",
v5k: "godan verb",
"v5k-s": "godan verb",
v5m: "godan verb",
v5n: "godan verb",
v5r: "godan verb",
"v5r-i": "godan verb",
v5s: "godan verb",
v5t: "godan verb",
v5u: "godan verb",
"v5u-s": "godan verb",
v5uru: "godan verb",
v5z: "godan verb",
vi: "intransitive verb",
vk: "kuru verb",
vn: "irregular nu verb",
vr: "irregular ru verb, plain form ends with -ri",
vs: "suru verb",
"vs-c": "su verb - precursor to the modern suru",
"vs-i": "suru verb - irregular",
"vs-s": "suru verb - special class",
vt: "transitive verb",
vulg: "vulgar expression or word",
vz: "ichidan verb - -zuru special class (alternative form of -jiru verbs)",
X: "rude or X-rated term",
zool: "zoology term"
};
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* tslint:disable:no-console */
Object.defineProperty(exports, "__esModule", { value: true });
var dict_codes_1 = __webpack_require__(15);
// 3040-309F: hiragana
// 30A0-30FF: katakana
// 4E00-9FAF: common and uncommon kanji
var kanjiAndCodeSplitter = /^(.*)\(([\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]+)\)\(([a-zA-Z0-9,]+)\)$/;
var codeSplitter = /^(.*)\(([a-zA-Z0-9,]+)\)$/;
var kanjiSplitter = /^(.*)\(([\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]+)\)$/;
var kanjiAndParenthesizedCsvSplitter = /^([\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]+)\(([\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF,]+)\)/;
function formatPronunciation(pronunciation) {
var parts = pronunciation.split(";");
var mapped = parts
.map(function (part) {
var kcm = part.match(kanjiAndCodeSplitter);
if (kcm) {
return (kcm[1] +
"⸨" +
kcm[2] +
"⸩" +
"(" +
(dict_codes_1.DICT_CODES[kcm[3]] || kcm[3]) +
")");
}
var kp = part.match(kanjiAndParenthesizedCsvSplitter);
if (kp) {
return kp[1] + "⸨" + kp[2].replace(",", "、") + "⸩";
}
var cm = part.match(codeSplitter);
if (cm) {
var code = cm[2];
var expandedCode = code;
if (code === "P") {
expandedCode = "common";
}
else if (dict_codes_1.DICT_CODES[code]) {
expandedCode = dict_codes_1.DICT_CODES[code];
}
return cm[1] + "(" + expandedCode + ")";
}
var km = part.match(kanjiSplitter);
if (km) {
return km[1] + "⸨" + km[2] + "⸩";
}
return part;
})
.join("、");
return "(" + mapped + ")";
}
exports.formatPronunciation = formatPronunciation;
/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var dict_codes_1 = __webpack_require__(15);
function capitalize(text) {
return text.charAt(0).toUpperCase() + text.slice(1);
}
function formatPartOfSpeech(commaDelimitedPos) {
if (!commaDelimitedPos) {
return "";
}
return (commaDelimitedPos.split(",") || [])
.map(function (part) {
var expandedPos = dict_codes_1.DICT_CODES[part];
return expandedPos ? capitalize(expandedPos) : capitalize(part);
})
.join(", ");
}
exports.formatPartOfSpeech = formatPartOfSpeech;
/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var dict_codes_1 = __webpack_require__(15);
function formatDefinitionLine(line) {
return replaceAbbreviations(replaceDictCodesAtEnd(replaceDictCodesAtStart(line)));
}
exports.formatDefinitionLine = formatDefinitionLine;
function replaceDictCodesAtStart(text) {
// Both regexes account for an optional numbered list prefix (e.g. "1. ")
var dictCodeInParens = /^([0-9]\.\s)?\(([a-z,A-Z,-,0-9]+)\)(.*)/;
var dictCodeInBraces = /^([0-9]\.\s)?\{([a-z,A-Z,-,0-9]+)\}(.*)/;
var parenMatches = text.match(dictCodeInParens);
var braceMatches = text.match(dictCodeInBraces);
if (parenMatches) {
var listPrefix = parenMatches[1] ? parenMatches[1] : "";
return listPrefix + replaceDictCode(parenMatches[2]) + parenMatches[3];
}
if (braceMatches) {
var listPrefix = braceMatches[1] ? braceMatches[1] : "";
return listPrefix + replaceDictCode(braceMatches[2]) + braceMatches[3];
}
return text;
}
function replaceDictCode(maybeDictCode) {
var longForm = dict_codes_1.DICT_CODES[maybeDictCode];
if (!longForm) {
return "(" + maybeDictCode + ")";
}
return "[" + longForm + "]";
}
function replaceDictCodesAtEnd(text) {
var dictCodesInParens = /(.*)\(([a-z,A-Z,0-9\,\-]+)\)$/;
var m = text.match(dictCodesInParens);
if (!m) {
return text;
}
var longFormCodes = m[2]
.split(",")
.map(function (maybeDictCode) {
var longForm = dict_codes_1.DICT_CODES[maybeDictCode];
return longForm ? longForm : maybeDictCode;
})
.join(", ");
return m[1] + "(" + longFormCodes + ")";
}
function replaceAbbreviations(text) {
return text.replace(/usu\./g, "usually").replace(/esp\./g, "especially");
}
/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var logger_1 = __webpack_require__(4);
var getWordPronunciations_1 = __webpack_require__(20);
var Log = new logger_1.Logger();
var forvoUserWhitelist = [""];
var EMPTY_FORVO_USER_WHITELIST = JSON.stringify(forvoUserWhitelist);
function populateForvoUserWhitelist(settings) {
if (typeof settings.forvo_username_whitelist_csv === "string") {
forvoUserWhitelist = settings.forvo_username_whitelist_csv
.trim()
.replace(/ /g, "")
.split(",");
}
}
exports.populateForvoUserWhitelist = populateForvoUserWhitelist;
function insertForvoAudioForWord(jpVocabText, settings, destAppendee) {
if (!destAppendee) {
Log.error("destAppendee missing");
return Promise.reject(new Error());
}
Log.debug("Querying Forvo for ", jpVocabText);
return getWordPronunciations_1.getWordPronunciations(jpVocabText, settings)
.then(function (responseText) {
if (!responseText) {
Log.warn("no Forvo responseText");
return Promise.resolve();
}
return handleForvoSuccess(responseText, settings, destAppendee);
})
.catch(function (res) {
Log.error("Forvo API error: ", res.statusText);
});
}
exports.insertForvoAudioForWord = insertForvoAudioForWord;
function handleForvoSuccess(responseText, settings, destAppendee) {
var parsedForvoJson;
try {
parsedForvoJson = JSON.parse(responseText);
}
catch (parseErr) {
Log.error("JSON parseErr", parseErr);
}
var forvoItems = parsedForvoJson.items;
if (!forvoItems || forvoItems.length === 0) {
Log.warn("no forvoItems");
return Promise.resolve();
}
var audioSection = $("<div>");
audioSection.css("margin-top", "10px");
forvoItems.forEach(function (forvoItem) {
if (!forvoItem.pathmp3) {
Log.error("!forvoItem.pathmp3");
return;
}
if (!forvoItem.username) {
Log.error("!forvoItem.username");
return;
}
if (JSON.stringify(forvoUserWhitelist) !== EMPTY_FORVO_USER_WHITELIST &&
!forvoUserWhitelist.includes(forvoItem.username)) {
Log.debug("skipping pronunciation from " + forvoItem.username);
return;
}
var audioContainer = $("<div>");
audioContainer.css({
fontSize: "12px",
display: "inline-block",
boxSizing: "border-box",
width: "250px",
marginTop: "0",
marginRight: "5px",
marginBottom: "5px",
marginLeft: "0",
padding: "0"
});
var audioEl = document.createElement("audio");
audioEl.src = forvoItem.pathmp3;
audioEl.controls = true;
audioEl.preload = "none";
audioEl.style.width = "250px";
if (settings.show_forvo_usernames) {
var usernameEl = $("<span>");
usernameEl.text(forvoItem.username);
usernameEl.css({
fontSize: "12px",
color: "#888888",
margin: "0",
padding: "0"
});
audioContainer.prepend(usernameEl);
}
audioContainer.append(audioEl);
audioSection.append(audioContainer);
});
destAppendee.append(audioSection);
return Promise.resolve();
}
/***/ }),
/* 20 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var gm_http_1 = __webpack_require__(1);
var logger_1 = __webpack_require__(4);
var Log = new logger_1.Logger();
function getWordPronunciations(jpWord, settings) {
if (!jpWord) {
return Promise.reject(new Error("jpWord missing"));
}
var forvoApiKey = settings ? settings.forvo_api_key : null;
if (!forvoApiKey) {
return Promise.reject(new Error("Forvo api key missing"));
}
var forvoUrl = "https://apifree.forvo.com/key/" +
forvoApiKey +
"/format/json" +
"/action/word-pronunciations" +
"/word/" +
encodeURIComponent(jpWord) +
"/language/ja" +
"/rate/" +
String(settings.forvo_min_rating || 0) +
"/country/JPN" +
"/order/rate-desc";
return gm_http_1.default
.get(forvoUrl)
.then(function (res) {
return Promise.resolve(res.responseText);
})
.catch(function (err) {
Log.error("Forvo error: ", err);
});
}
exports.getWordPronunciations = getWordPronunciations;
/***/ }),
/* 21 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var windowHelpers_1 = __webpack_require__(22);
var WKOF_POLL_INTERVAL_MS = 10;
var WKOF_WAIT_TIMEOUT_MS = 10000;
var WKOF_INSTALL_PAGE = "https://community.wanikani.com/t/instructions-installing-wanikani-open-framework/28549";
var prompted = false;
function promptInstall(scriptName, overridingGetWindowFunc) {
if (prompted) {
return;
}
var win = (overridingGetWindowFunc || windowHelpers_1.getWindow)();
prompted = true;
if (win.confirm(scriptName +
" requires the Wanikani Open Framework.\nDo you want to be forwarded to the installation instructions?")) {
win.location.href = WKOF_INSTALL_PAGE;
}
}
// waitForWkof calls onLoad with the global wkof object after wkof is loaded
function waitForWkof(scriptName, onLoad) {
windowHelpers_1.waitUntilWindowPropLoads(windowHelpers_1.getWindow, "wkof", WKOF_POLL_INTERVAL_MS, WKOF_WAIT_TIMEOUT_MS, onLoad, promptInstall.bind(null, scriptName));
}
exports.waitForWkof = waitForWkof;
/***/ }),
/* 22 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
Object.defineProperty(exports, "__esModule", { value: true });
function getWindow() {
return global;
}
exports.getWindow = getWindow;
function waitUntilWindowPropLoads(getWindowFunc, windowProp, pollingIntervalMs, maxWaitMs, onLoad, onTimeout) {
var startMs = new Date().getTime();
var intervalID = setInterval(function () {
if (getWindowFunc()[windowProp]) {
clearInterval(intervalID);
onLoad(getWindowFunc()[windowProp]);
return;
}
if (new Date().getTime() - startMs > maxWaitMs) {
clearInterval(intervalID);
onTimeout();
}
}, pollingIntervalMs);
}
exports.waitUntilWindowPropLoads = waitUntilWindowPropLoads;
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(23)))
/***/ }),
/* 23 */
/***/ (function(module, exports) {
var g;
// This works in non-strict mode
g = (function() {
return this;
})();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1, eval)("this");
} catch (e) {
// This works if the window reference is available
if (typeof window === "object") g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
/***/ }),
/* 24 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SettingsScriptId = "wanikani_vocab_beyond_settings";
exports.MenuScriptLinkId = "wanikani_vocab_beyond_settings_link";
exports.WkofSettingsMenuConfig = {
script_id: exports.SettingsScriptId,
title: "WaniKani Vocab Beyond",
autosave: true,
background: false,
content: {
forvo_page_id: {
type: "page",
label: "Audio",
hover_tip: "Settings for Forvo.com audio pronunciations",
content: {
forvo_instructions: {
type: "html",
html: "<p><a href='https://forvo.com' target='_blank'>Forvo.com</a> has an audio collection of words pronounced by native Japanese speakers.</p>" +
"<p>To enable Forvo pronunciations of vocabulary words:</p>" +
"<p>1. <a href='https://forvo.com/signup/' target='_blank'>Sign up for a Forvo.com account</a></p>" +
"<p>2. <a href='https://api.forvo.com/plans-and-pricing' target='_blank'>Purchase an API key here</a></p>" +
"<p>3. Enter your key below</p>"
},
forvo_api_key: {
type: "text",
default: "",
label: "Forvo API key",
full_width: true,
hover_tip: "Your API key from https://api.forvo.com/"
},
forvo_caveat: {
type: "html",
html: "<p>(WaniKani Vocab Beyond will work without a Forvo API key, but audio for vocabulary won't be shown.)</p>"
},
forvo_divider_id: {
type: "divider"
},
forvo_rating_instructions: {
type: "html",
html: "<p>Forvo pronunciations are voted on by users. Limit displayed audio to at least this overall rating. Zero is the default and recommended value.</p>"
},
forvo_min_rating: {
type: "number",
label: "Minimum Forvo rating",
hover_tip: "Only show Forvo pronunciations with at least this rating",
placeholder: "0",
default: 0,
full_width: false
},
forvo_divider_id_2: {
type: "divider"
},
forvo_whitelist_instructions: {
type: "html",
html: "<p>Comma-separated list of Forvo users whose pronunciations should be shown. If blank, pronunciations from all users are shown.</p>"
},
forvo_username_whitelist_csv: {
type: "text",
label: "Favorite Forvo users",
full_width: true,
placeholder: "Example: skent, usako_usagiclub, strawberrybrown",
default: "",
hover_tip: "A comma-separated list of Forvo usernames whose pronunciations should be shown"
}
}
},
vocab_page_id: {
type: "page",
label: "Vocab",
hover_tip: "Settings for WWWJDIC vocabulary words",
content: {
vocab_instructions_1: {
type: "html",
html: "<p>By default, only common words are retrieved and displayed from <a href='http://nihongo.monash.edu/cgi-bin/wwwjdic' target='_blank'>WWWJDIC</a>. You can also retrieve uncommon words and phrases by checking the box below.</p>"
},
show_all_wwwjdic_vocab: {
type: "checkbox",
label: "Show uncommon vocab",
hover_tip: "Show both common and uncommon WWWJDIC vocab",
default: false,
full_width: false
},
vocab_instructions_2: {
type: "html",
html: "<p>Set the maximum number of WWWJDIC vocab to display per kanji below. 0 means unlimited. (Warning: showing WWWJDIC unlimited results may quickly exhaust your Forvo API key's daily request limits.)</p>"
},
max_wwwjdic_vocab_shown: {
type: "number",
label: "Maximum number of WWWJDIC vocab to display per kanji",
hover_tip: "Maximum number of WWWJDIC vocabulary to display per kanji",
full_width: true,
placeholder: "15",
default: 15,
min: 0
}
}
},
appearance_page_id: {
type: "page",
label: "Appearance",
hover_tip: "Appearance settings",
content: {
appearance_instructions_1: {
type: "html",
html: "<p>Check to show Vocab Beyond at top of kanji pages and in the first tab of kanji reviews and lessons.</p>"
},
show_vocab_beyond_first: {
type: "checkbox",
label: "Show Vocab Beyond first",
hover_tip: "Show the Vocab Beyond section at the top of kanji pages and in the first tab of kanji reviews and kanji lessons",
default: false,
full_width: false
},
appearance_instructions_2: {
type: "html",
html: "<p>Check to show Forvo usernames above audio clips.</p>"
},
show_forvo_usernames: {
type: "checkbox",
label: "Show Forvo usernames",
hover_tip: "Show Forvo usernames above each audio clip",
default: false,
full_width: false
},
appearance_instructions_3: {
type: "html",
html: "<p>Check below to hide icon beside uncommon vocab.</p>"
},
hide_uncommon_indicator: {
type: "checkbox",
label: "Hide uncommon icon",
hover_tip: "Hide uncommon vocabulary icon",
default: false,
full_width: false
}
}
}
}
};
/***/ })
/******/ ]);