您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Injects verb conjugation tables from Verbix on dict.cc
// ==UserScript== // @name dict.cc-verbix // @namespace https://github.com/todeit02/dict.cc_verbix_userscript // @description Injects verb conjugation tables from Verbix on dict.cc // @grant GM.xmlHttpRequest // @grant GM_xmlhttpRequest // @include /^https:\/\/(?:(?:([a-z]){2}-?([a-z]){2})|(www))\.dict\.cc\/\?s=.*/ // @connect api.verbix.com // @connect raw.githubusercontent.com // @require https://code.jquery.com/jquery-3.3.1.js // @version 0.0.1.20190210183046 // ==/UserScript== // choose correct function for Greasemonkey/Tampermonkey if(typeof GM_xmlhttpRequest !== "function") GM_xmlhttpRequest = GM.xmlHttpRequest; const tenseNamesUrl = "https://raw.githubusercontent.com/todeit02/dict.cc_verbix_userscript/master/tense_names.json"; const verbixApiUrl = "https://api.verbix.com/conjugator/html"; const verbixTableTemplateUrl = "http://tools.verbix.com/webverbix/personal/template.htm"; const dictWordButtonTableClass = "td7cml"; const dictWordTextTableDataClass = "td7nl"; const dictItemTableLineIdSuffix = "tr"; const verbixLanguageCodes = { "de": "deu", "en": "eng", "da": "dan", "es": "spa", "fi": "fin", "fr": "fra", "hu": "hun", "is": "isl", "it": "ita", "la": "lat", "nl": "nld", "no": "nob", "pt": "por", "ro": "ron", "sv": "swe" }; const usingTemplateMoodTenses = [ ["Indicativo", "Presente"], ["Indicativo", "Perfecto"], ["Indicativo", "Imperfecto"], ["Subjuntivo", "Presente"], ["Imperativo", ""] ]; let languagePair = []; let templateHeadingsTranslations = {}; let hoveredWordLink; let openTooltips = []; let cursorOnWordLink = false; let cursorOnTooltip = false; $(function(){ languagePair = getLanguagePair(); loadTemplateHeadingsTranslations(); linkWordsToVerbix(); }); function linkWordsToVerbix() { let dictItemTableLines = $("div[id='maincontent']").find("tr" + "[id^='" + dictItemTableLineIdSuffix + "']"); let dictWordLinks = dictItemTableLines.find("a").filter(function(){ return $(this).text().length > 0; }); dictWordLinks.hover( (event) => { cursorOnWordLink = true; hoveredWordLink = $(event.target).closest("a"); createTooltipIfNoneOpen(); }, () => { cursorOnWordLink = false; removeTooltipIfNotHovered(); }); } function createTooltipIfNoneOpen() { if(openTooltips.length > 0) return; let wordText = $(hoveredWordLink).text(); let isLeftColumn = $(hoveredWordLink).parent().prev().attr("class") === dictWordButtonTableClass; let dictLanguage = isLeftColumn ? languagePair[0] : languagePair[1]; loadVerbixConjugationLists(dictLanguage, wordText); } function showTooltip(tenseTablesHtml) { let $tooltip = $("<br /><div></div>").appendTo(hoveredWordLink); openTooltips.push($tooltip); $tooltip.hover(() => { cursorOnTooltip = true; }, () => { cursorOnTooltip = false; removeTooltipIfNotHovered(); }); tenseTablesHtml.forEach(function(tenseTable, index){ if(index > 0) $tooltip.append("<br />"); $tooltip.append(tenseTable); }); $tooltip.parent().css("position", "relative"); $tooltip.css({ "display": "initial", "opacity": "0", "text-align": "center", "padding": "0.5em", "border-radius": "6px", "position": "absolute", "z-index": "1", "background-color": "#fff", "border": "1px solid black", "box-shadow": "0 0 0.5em", "height": "25em", "overflow": "scroll", "left": "99%" }); $tooltip.find("span").css("color", "black"); $tooltip.animate({"opacity": "1"}, 500); } function removeTooltipIfNotHovered() { if(cursorOnWordLink || cursorOnTooltip) return; openTooltips.forEach(function($tooltip){ $tooltip.parent().css("position", ""); $tooltip.remove(); }); openTooltips = []; } function loadVerbixConjugationLists(dictLanguage, verb) { if(verbixLanguageCodes[dictLanguage] == null) return; let getQuery = "language=" + verbixLanguageCodes[dictLanguage] + "&tableurl=" + verbixTableTemplateUrl + "&verb=" + verb; let verbixUrl = verbixApiUrl + '?' + getQuery; GM_xmlhttpRequest({ method: "GET", url: verbixUrl, onload: response => { let verbixContent = new DOMParser().parseFromString(response.responseText, "text/html"); let conjugationTables = []; usingTemplateMoodTenses.forEach(function(moodTensePair) { const mood = moodTensePair[0]; const translatedMood = translateTemplateWord(dictLanguage, "mood", mood); const tense = moodTensePair[1]; let moodTables = $(".verbtense", verbixContent).filter(isTableOfMood(mood)); if(moodTensePair[1] != null && moodTensePair[1].length > 0) { const translatedTense = translateTemplateWord(dictLanguage, "tense", tense); const $tenseTable = moodTables.filter(isTableOfTense(tense)); const $heading = $("<b>" + translatedTense + " (" + translatedMood + ")</b>"); conjugationTables.push($heading) conjugationTables.push($tenseTable); } else { const $heading = $("<b>" + translatedMood + "</b>"); conjugationTables.push($heading) conjugationTables.push(moodTables); } }); showTooltip(conjugationTables); } }); } function getLanguagePair() { let url = window.location.href; let subdomainRegex = /^https:\/\/(?:(?:([a-z]{2})-?([a-z]{2}))|(www))\.dict\.cc\/\?s=.*/; let subdomain = subdomainRegex.exec(url); if(subdomain[3]) return ["en", "de"]; if((subdomain[1] === "de" && subdomain[2] === "en") || (subdomain[2] === "de" && subdomain[1] === "en")) { return ["en", "de"]; } const isGermanWithoutEnglish = (subdomain[1] === "de" || subdomain[2] === "de"); const isEnglishWithoutGerman = (subdomain[1] === "en" || subdomain[2] === "en"); let languages = []; if(isGermanWithoutEnglish) { if(subdomain[1] === "de") languages.push(subdomain[2]); else languages.push(subdomain[1]); languages.push("de"); } if(isEnglishWithoutGerman) { if(subdomain[1] === "en") languages.push(subdomain[2]); else languages.push(subdomain[1]); languages.push("en"); } return languages; } function loadTemplateHeadingsTranslations() { $.getJSON(tenseNamesUrl, data => { templateHeadingsTranslations = data; }); } function translateTemplateWord(dictLanguage, verbAspect, word) { verbAspect += 's'; const fallbackTranslations = templateHeadingsTranslations["es"]; const usingTranslations = templateHeadingsTranslations[dictLanguage] || fallbackTranslations; const usingAspect = usingTranslations[verbAspect] || fallbackTranslations[verbAspect]; return usingAspect[word]; } function isTableOfMood(templateMoodName) { return function() { const $moodTableDataInMain = $(this).parents("td").eq(1); const $moodTableRowInMain = $moodTableDataInMain.parent(); const $mainTable = $moodTableRowInMain.parents("table").first(); const moodColIndexInMain = $moodTableDataInMain.index(); const moodRowIndexInMain = $moodTableRowInMain.index(); const heading = $("tr", $mainTable).eq(moodRowIndexInMain - 1).children().eq(moodColIndexInMain).text(); return (heading === templateMoodName); } } function isTableOfTense(templateTenseName) { return function() { let parentText = $(this).parent().text(); while(parentText.charAt(0) === '\r' || parentText.charAt(0) === '\n') { parentText = parentText.substr(1); } return parentText.substring(0, templateTenseName.length) === templateTenseName; }; }