Last active
February 6, 2023 01:38
-
-
Save dertuxmalwieder/5ad281037ed627de23f88f79629913cb to your computer and use it in GitHub Desktop.
WDE++: Das Forenhelferlein. https://www.whisky.de/forum/discussion/46331/wde-das-forenhelferlein/p1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Whisky.de-Forum ++ | |
// @author WithKeys | |
// @namespace tuxproject.de | |
// @description Zusätzliche Funktionen für das Whisky.de-Forum. | |
// @include /www.whisky.de\/forum\/.*/ | |
// @include /www.whisky.de\/tfg\/forum.html$/ | |
// @exclude /\.(jpe?g|png|gif)$/ | |
// @require https://raw.githubusercontent.com/franciscop/umbrella/master/umbrella.min.js | |
// @version 5.4 | |
// @license CDDL-1.1; https://spdx.org/licenses/CDDL-1.1.html#licenseText | |
// @downloadURL https://gist.github.com/dertuxmalwieder/5ad281037ed627de23f88f79629913cb/raw/WDE++.user.js | |
// @grant GM.addStyle | |
// @grant GM.getValue | |
// @grant GM.setValue | |
// @grant GM.info | |
// @run-at document-idle | |
// ==/UserScript== | |
// -------- WDE++-Button: | |
u("#header .navigation-realms ul").append('<li class="wde"><a href="#" onclick="return false;" id="wdeplus_btn"><span>WDE++</span></a></li>'); | |
// -------- Einstellungsdialog: | |
// Der Einstellungsdialog ist inzwischen so groß geworden, dass wir ihn auf mobilen | |
// (kleinen) Geräten nicht mehr vernünftig anzeigen können. Nutzer solcher Geräte | |
// sollten WDE++ aber natürlich trotzdem vernünftig nutzen können. | |
// Lösung: Wir brauchen einen zweiten, kleineren Einstellungsdialog, der nur die | |
// wesentlichen Optionen anzeigt - Kopfbereich und Seitenleisten und ähnliche UI- | |
// Spielereien sind hier nicht so entscheidend und können bei den Standardwerten | |
// belassen werden. | |
// Ein Gerät gilt als Mobilgerät, falls das bevorzugte Eingabegerät über Elementen | |
// schweben kann. Das können Mäuse ganz gut und Finger eher nicht. Bonusproblem: | |
// Tablets haben meist keine Maus, aber sind groß genug, um den Einstellungsdialog | |
// vernünftig anzuzeigen. Smartphones aber nicht. Wir brauchen also zusätzlich eine | |
// Erkennung der Bildschirmgröße. Außerdem gehen wir davon aus, dass im Querformat | |
// alles akzeptabel aussieht, weil wir ein bisschen naiv sind. ;-) | |
const isSmallMobileDevice = window.matchMedia("(max-width: 1024px) and (orientation: portrait) and (any-hover: none)").matches; | |
const dialogHtml = isSmallMobileDevice ? '\ | |
<div id="wdeplusSettingsCtr" class="wdeSmall"> \ | |
<form> \ | |
<div class="wdeplusHdr wdeSmall">WDE++ - mobile Version</div> \ | |
\ | |
<input type="checkbox" name="wdeChkConvertWID" id="wdeChkConvertWID" /> \ | |
<label for="wdeChkConvertWID">WIDs als Links darstellen</label> \ | |
\ | |
<div style="margin-left:16px"> \ | |
Anzeigestil: \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="1" id="wdeRdConvertWIDStyle1" /> \ | |
<label for="wdeRdConvertWIDStyle1" title="Zeigt [WB] an.">[WB]</label> \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="2" id="wdeRdConvertWIDStyle2" /> \ | |
<label for="wdeRdConvertWIDStyle2" title="Zeigt [Whisky-ID] an.">[123456]</label> \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="3" id="wdeRdConvertWIDStyle3" /> \ | |
<label for="wdeRdConvertWIDStyle3" title="Zeigt [WB: Whisky-ID] an.">[WB: 123456]</label> \ | |
</div> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkUncropQuotes" id="wdeChkUncropQuotes" /> \ | |
<label for="wdeChkUncropQuotes">Zitate kompakter anzeigen</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" style="display:none" name="wdeChkDontCollapseSignatures" id="wdeChkDontCollapseSignatures" /> \ | |
\ | |
<input type="checkbox" name="wdeChkHideCounter" id="wdeChkHideCounter" /> \ | |
<label for="wdeChkHideCounter">Beitragszähler ausblenden</label> \ | |
\ | |
<input type="checkbox" style="display:none" name="wdeChkPinHeader" id="wdeChkPinHeader" /> \ | |
<input type="checkbox" style="display:none" name="wdeChkLeftSidebar" id="wdeChkLeftSidebar" /> \ | |
<input type="checkbox" style="display:none" name="wdeChkRightSidebar" id="wdeChkRightSidebar" /> \ | |
\ | |
<br /><br /> \ | |
\ | |
<input type="text" name="wdeThreadIgnoreList" id="wdeThreadIgnoreList" placeholder="Die hier eingetragenen Themen werden ausgeblendet." /> \ | |
<label for="wdeThreadIgnoreList">Zu ignorierende Themen (IDs oder Titel, mit Semikolon getrennt)<br /><span class="wdeplusHint"><b>Achtung:</b> Unter "Neueste Beiträge" funktionieren nur die Titel!</span></label> \ | |
\ | |
<br /><br /> \ | |
\ | |
<input type="text" name="wdeUserIgnoreList" id="wdeUserIgnoreList" placeholder="Die hier eingetragenen Benutzer werden ausgeblendet." /> \ | |
<label for="wdeUserIgnoreList">Zu ignorierende Benutzer (mit Semikolon getrennt)</label><br /> \ | |
<input type="checkbox" name="wdeUserIgnoreCompletely" id="wdeUserIgnoreCompletely" /> \ | |
<label for="wdeUserIgnoreCompletely">Beiträge komplett entfernen</label> \ | |
\ | |
<br /><br /> \ | |
\ | |
<button id="wdeSaveBtn" type="button">speichern und neu laden</button> \ | |
<button id="wdeCloseBtn" type="button">abbrechen und schließen</button> \ | |
</form> \ | |
</div> \ | |
' | |
: | |
'\ | |
<div id="wdeplusSettingsCtr"> \ | |
<form> \ | |
<div class="wdeplusHdr">WDE++: Einstellungen fürs Whiskyforum</div> \ | |
\ | |
<input type="checkbox" name="wdeChkConvertWID" id="wdeChkConvertWID" /> \ | |
<label for="wdeChkConvertWID" title="Wandelt "WID: ..." automatisch in Links zum Whisky um.">WIDs als Links darstellen</label> \ | |
\ | |
<br /> \ | |
\ | |
<div style="margin-left:16px"> \ | |
Anzeigestil: \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="1" id="wdeRdConvertWIDStyle1" /> \ | |
<label for="wdeRdConvertWIDStyle1" title="Zeigt [WB] an.">[WB]</label> \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="2" id="wdeRdConvertWIDStyle2" /> \ | |
<label for="wdeRdConvertWIDStyle2" title="Zeigt [Whisky-ID] an.">[123456]</label> \ | |
\ | |
<input type="radio" name="wdeRdConvertWIDStyle" value="3" id="wdeRdConvertWIDStyle3" /> \ | |
<label for="wdeRdConvertWIDStyle3" title="Zeigt [WB: Whisky-ID] an.">[WB: 123456]</label> \ | |
</div> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkUncropQuotes" id="wdeChkUncropQuotes" /> \ | |
<label for="wdeChkUncropQuotes" title="Entfernt verschachtelte Zitate und klappt Zitate immer aus.">Zitate kompakter anzeigen</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkDontCollapseSignatures" id="wdeChkDontCollapseSignatures" /> \ | |
<label for="wdeChkDontCollapseSignatures" title="Deaktiviert das automatische Einklappen von Signaturen.">Signaturen immer komplett anzeigen</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkHideCounter" id="wdeChkHideCounter" /> \ | |
<label for="wdeChkHideCounter" title="Entfernt den Beitragszähler unter Benutzernamen.">Beitragszähler ausblenden</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkPinHeader" id="wdeChkPinHeader" /> \ | |
<label for="wdeChkPinHeader" title="Hält den Kopfbereich immer im sichtbaren Bereich.">Kopfbereich anheften</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkLeftSidebar" id="wdeChkLeftSidebar" /> \ | |
<label for="wdeChkLeftSidebar" title="Hinweis: Alle Elemente in der linken Leiste werden gelöscht!">Linke Seitenleiste ausblenden</label> \ | |
\ | |
<br /> \ | |
\ | |
<input type="checkbox" name="wdeChkRightSidebar" id="wdeChkRightSidebar" /> \ | |
<label for="wdeChkRightSidebar">Rechte Seitenleiste ausblenden</label> \ | |
\ | |
<br /><br /> \ | |
\ | |
<input type="text" name="wdeThreadIgnoreList" id="wdeThreadIgnoreList" placeholder="Die hier eingetragenen Themen werden ausgeblendet." /> \ | |
<label for="wdeThreadIgnoreList" title="Die hier eingetragenen Themen werden ausgeblendet.">Zu ignorierende Themen (IDs oder Titel, mit Semikolon getrennt)<br /><span class="wdeplusHint"><b>Achtung:</b> Unter "Neueste Beiträge" funktionieren nur die Titel!</span></label> \ | |
\ | |
<br /><br /> \ | |
\ | |
<input type="text" name="wdeUserIgnoreList" id="wdeUserIgnoreList" placeholder="Die hier eingetragenen Benutzer werden ausgeblendet." /> \ | |
<label for="wdeUserIgnoreList" title="Die hier eingetragenen Benutzer werden ausgeblendet.">Zu ignorierende Benutzer (mit Semikolon getrennt)</label><br /> \ | |
<input type="checkbox" name="wdeUserIgnoreCompletely" id="wdeUserIgnoreCompletely" /> \ | |
<label for="wdeUserIgnoreCompletely" title="An = Beiträge werden entfernt, aus = Beiträge werden durch Platzhalter ersetzt.">Beiträge komplett entfernen</label> \ | |
\ | |
<br /><br /> \ | |
\ | |
<button id="wdeSaveBtn" type="button">speichern und neu laden</button> \ | |
<button id="wdeCloseBtn" type="button" title="Tastenkürzel: <Esc>">abbrechen und schließen</button> \ | |
</form> \ | |
</div> \ | |
'; | |
u("body").append(dialogHtml); | |
u("#wdeplus_btn").on("click", function() { | |
u("#wdeplusSettingsCtr").addClass("visible"); | |
}, false); | |
u("#wdeCloseBtn").on("click", function() { | |
u("#wdeplusSettingsCtr").removeClass("visible"); | |
}, false); | |
u("#wdeChkConvertWID").on("click", function() { | |
document.getElementById("wdeRdConvertWIDStyle1").disabled = !u(this).is(":checked"); | |
document.getElementById("wdeRdConvertWIDStyle2").disabled = !u(this).is(":checked"); | |
document.getElementById("wdeRdConvertWIDStyle3").disabled = !u(this).is(":checked"); | |
}); | |
u("#wdeSaveBtn").on("click", function () { | |
// Speichern: | |
GM.setValue("convertWIDs", cbToBit("#wdeChkConvertWID")); | |
GM.setValue("pinHeader", cbToBit("#wdeChkPinHeader")); | |
GM.setValue("disableLeftSidebar", cbToBit("#wdeChkLeftSidebar")); | |
GM.setValue("disableRightSidebar", cbToBit("#wdeChkRightSidebar")); | |
GM.setValue("uncropQuotes", cbToBit("#wdeChkUncropQuotes")); | |
GM.setValue("dontCollapseSignatures", cbToBit("#wdeChkDontCollapseSignatures")); | |
GM.setValue("hideCounter", cbToBit("#wdeChkHideCounter")); | |
GM.setValue("userIgnoreList", document.getElementById("wdeUserIgnoreList").value); | |
GM.setValue("userIgnoreCompletely", cbToBit("#wdeUserIgnoreCompletely")); | |
GM.setValue("threadIgnoreList", document.getElementById("wdeThreadIgnoreList").value); | |
if (cbToBit("#wdeRdConvertWIDStyle1")) GM.setValue("convertWIDStyle", 1); | |
else if (cbToBit("#wdeRdConvertWIDStyle2")) GM.setValue("convertWIDStyle", 2); | |
else GM.setValue("convertWIDStyle", 3); | |
window.location.reload(true); | |
}, false); | |
// Versionsnummer im Einstellungsfenster anzeigen: | |
u(".wdeplusHdr").html(u(".wdeplusHdr").html() + " [Version " + GM.info.script.version + "]"); | |
// -------- Variablen (werden in den Einstellungen gesetzt): | |
let ConvertWIDs = await GM.getValue('convertWIDs', 0); | |
let ConvertWIDStyle = await GM.getValue('convertWIDStyle', 3); | |
let PinHeader = await GM.getValue('pinHeader', 0); | |
let DisableLeftSidebar = await GM.getValue('disableLeftSidebar', 0); | |
let DisableRightSidebar = await GM.getValue('disableRightSidebar', 1); | |
let UncropQuotes = await GM.getValue('uncropQuotes', 1); | |
let DontCollapseSignatures = await GM.getValue('dontCollapseSignatures', 0); | |
let HideCounter = await GM.getValue('hideCounter', 0); | |
let UserIgnoreList = await GM.getValue('userIgnoreList', ''); | |
let UserIgnoreDelete = await GM.getValue('userIgnoreCompletely', 0); | |
let ThreadIgnoreList = await GM.getValue('threadIgnoreList', ''); | |
// Dialogelemente vorbelegen: | |
if (ConvertWIDs == 1) { u("#wdeChkConvertWID").attr("checked", true); } | |
u("#wdeRdConvertWIDStyle" + ConvertWIDStyle).attr("checked", true); | |
if (PinHeader == 1) { u("#wdeChkPinHeader").attr("checked", true); } | |
if (DisableLeftSidebar == 1) { u("#wdeChkLeftSidebar").attr("checked", true); } | |
if (DisableRightSidebar == 1) { u("#wdeChkRightSidebar").attr("checked", true); } | |
if (UncropQuotes == 1) { u("#wdeChkUncropQuotes").attr("checked", true); } | |
if (DontCollapseSignatures == 1) { u("#wdeChkDontCollapseSignatures").attr("checked", true); } | |
if (HideCounter == 1) { u("#wdeChkHideCounter").attr("checked", true); } | |
if (UserIgnoreDelete == 1) { u("#wdeUserIgnoreCompletely").attr("checked", true); } | |
document.getElementById("wdeUserIgnoreList").value = UserIgnoreList; | |
document.getElementById("wdeThreadIgnoreList").value = ThreadIgnoreList; | |
document.getElementById("wdeRdConvertWIDStyle1").disabled = ConvertWIDs != 1; | |
document.getElementById("wdeRdConvertWIDStyle2").disabled = ConvertWIDs != 1; | |
document.getElementById("wdeRdConvertWIDStyle3").disabled = ConvertWIDs != 1; | |
// -------- Trigger für das Einstellungsmenü: | |
function cbToBit(node) { | |
// Checkboxselector rein, 1 oder 0 raus. | |
return u(node).is(":checked") ? 1 : 0; | |
} | |
document.addEventListener('keyup', function (event) { | |
// Einstellungen per <Esc> schließen: | |
if (event.defaultPrevented || !u("#wdeplusSettingsCtr").hasClass("visible")) { | |
return; | |
} | |
let key = event.key || event.keyCode; | |
if (key === 'Escape' || key === 'Esc' || key === 27) { | |
u("#wdeplusSettingsCtr").removeClass("visible"); | |
} | |
}); | |
// -------- Größenvariablen für Elemente, die wir später vielleicht | |
// entfernen, aber ihre Breite danach noch brauchen: | |
let sidebar_links = u("#sidebar-left").size().width; | |
let sidebar_rechts = u("#sidebar-right").size().width; | |
// -------- Tu' Dinge auf der Seite: | |
// Selektor für ganze Seite: | |
const pagewrapper = u(".page-content"); | |
const wdeObserver = new MutationObserver(function(mutations) { | |
// Wegen des blöden :-) AJAX-Krempels müssen wir aktiv gucken, | |
// ob sich die Seite ändert, und ggf. reagieren. | |
mutations.forEach(function(mutation) { | |
if (mutation.type == "childList" && mutation.addedNodes != null) { | |
// Beiträge wurden nachgeladen: | |
processPage(); | |
} | |
}); | |
}); | |
const obsConfig = { | |
attributes: true, | |
childList: true, | |
characterData: true, | |
subtree: true | |
}; | |
wdeObserver.observe(document.getElementById("content"), obsConfig); | |
function addWDEPlusSmileys() { | |
// Affen- und Schulternzuckemoji einfügbar machen: | |
const affensmiley = "<li class=\"wdePlusSmiley\" aria-label='<img class=\"emoji\" src=\"https://i.imgur.com/TenuIIZ.png\" title=\"Affe. (WDE++-Extra)\" alt=\"Affe. (WDE++-Extra)\" height=\"20\" />'><a href=\"#\" data-value='<img class=\"emoji\" src=\"https://i.imgur.com/TenuIIZ.png\" title=\"Affe. (WDE++-Extra)\" alt=\"Affe. (WDE++-Extra)\" height=\"20\" />'><img class=\"emoji\" src=\"https://i.imgur.com/TenuIIZ.png\" title=\"Affe. (WDE++-Extra)\" alt=\"Affe. (WDE++-Extra)\" height=\"20\" /></a></li>"; | |
const schulternzuck = "<li class=\"wdePlusSmiley\" aria-label='<img class=\"emoji\" src=\"https://i.imgur.com/89q8r3X.png\" title=\"Schulternzuck. (WDE++-Extra)\" alt=\"Schulternzuck. (WDE++-Extra)\" height=\"20\" />'><a href=\"#\" data-value='<img class=\"emoji\" src=\"https://i.imgur.com/89q8r3X.png\" title=\"Schulternzuck. (WDE++-Extra)\" alt=\"Schulternzuck. (WDE++-Extra)\" height=\"20\" />'><img class=\"emoji\" src=\"https://i.imgur.com/89q8r3X.png\" title=\"Schulternzuck. (WDE++-Extra)\" alt=\"Schulternzuck. (WDE++-Extra)\" height=\"20\" /></a></li>"; | |
u("ul.dropdown-smileys:not(.wdeProcessed)").each(function(node, i) { | |
u(node).append(affensmiley); | |
u(node).append(schulternzuck); | |
u(node).addClass("wdeProcessed"); | |
}); | |
} | |
function addThreadIgnoreMenu(force) { | |
// Fügt Menüpunkte zum Ignorieren/Entignorieren von Threads dem Zahnradmenü hinzu. | |
const menuUl = u("#Item_0.PageTitle .header-options .Options .OptionsMenu ul.Flyout"); | |
if (menuUl != null && (force || !u(".page-content").hasClass("wdeplusprocd"))) { | |
// Diese Funktion ist rekursiv. Beim initialen Aufruf sollte "force" auf "false" stehen, | |
// denn sonst wird sie in Endlosschleife aufgerufen und das ist nicht gut. | |
// Ist der Thread bereits ignoriert? | |
const numericThreadId = u("#Form_DiscussionID") != null ? u("#Form_DiscussionID").attr("value") : "0"; | |
const threadTitle = u("#Item_0.PageTitle h1").html(); | |
const ignoreThreadListArray = ThreadIgnoreList.split(";").map(s => s.trim()); | |
if (ignoreThreadListArray.length > 0) { | |
const isIgnore = ignoreThreadListArray.includes(numericThreadId) || ignoreThreadListArray.includes(threadTitle); | |
const ignoreMenu = '<li id="ThreadIgnoreMenu" data-threadtitle="'+ threadTitle +'" data-threadid="' + numericThreadId + '"><a href="#" onclick="return false;">' + (isIgnore ? "Entignorieren" : "Ignorieren") + '</a></li>'; | |
// Einmal reicht: | |
if (u("#ThreadIgnoreMenu") != null) u("#ThreadIgnoreMenu").remove(); | |
menuUl.append(ignoreMenu); | |
u("#ThreadIgnoreMenu").on("click", function() { | |
// (Ent-)Ignorieren: | |
const isIgnoreNum = ignoreThreadListArray.includes(u(this).attr("data-threadid")); | |
const isIgnoreTxt = ignoreThreadListArray.includes(u(this).attr("data-threadtitle")); | |
if (isIgnoreNum) { | |
let index = ignoreThreadListArray.indexOf(u(this).attr("data-threadid")); | |
if (index > -1) ignoreThreadListArray.splice(index, 1); | |
} | |
if (isIgnoreTxt) { | |
let index = ignoreThreadListArray.indexOf(u(this).attr("data-threadtitle")); | |
if (index > -1) ignoreThreadListArray.splice(index, 1); | |
} | |
if (!isIgnoreNum && !isIgnoreTxt) { | |
// Ist nicht ignoriert. Ignorieren. | |
// (Titel, falls ohne ";", sonst ID.) | |
ignoreThreadListArray.push(u(this).attr("data-threadtitle").includes(";") ? u(this).attr("data-threadid") : u(this).attr("data-threadtitle")); | |
} | |
ThreadIgnoreList = ignoreThreadListArray.join(";"); | |
GM.setValue("threadIgnoreList", ThreadIgnoreList); | |
// UI aktualisieren: | |
document.getElementById("wdeThreadIgnoreList").value = ThreadIgnoreList; | |
// (Ent-)Ignorieren-Menü neu aufbauen: | |
addThreadIgnoreMenu(true); | |
}); | |
} | |
} | |
} | |
function outputWIDStyle() { | |
// Gibt den Ausgabetext für die Regexersetzung von WIDs zurück. | |
let ersetzen = ''; | |
switch (ConvertWIDStyle) { | |
case 1: | |
// Nur "[WB]": | |
ersetzen = "[WB]"; | |
break; | |
case 2: | |
// Nur "[(WID)]": | |
ersetzen = "[$3]"; | |
break; | |
case 3: | |
// "[WB: (WID)]": | |
ersetzen = "[WB: $3]"; | |
break; | |
} | |
return ersetzen; | |
} | |
function processPage() { | |
// Hinweis: Firefox kann kein negatives Lookbehind und wird sich beklagen, wenn man es versucht. | |
// Wir müssen hier daher die einfachere Variante nehmen. Da die Forensoftware manchmal | |
// und/oder irgendwelche HTML-Tags einfügt, müssen wir das natürlich auch entfernen. | |
const widregex = /WB?ID([:\s]|( |<\S*?>|<span (?:data-sheets-formula-bar-text-)?style="[^"]*">))+(\d+)(?:<\/span>)?/g; | |
// Selektor für Themenliste (Forum): | |
const threadListNormal = u("ul.DataList.Discussions div li.ItemDiscussion"); | |
// Selektor für Themenliste (Neueste Beiträge): | |
const threadListRecent = u("div.vanilla-latest-comments ul.DataList.MessageList li.Item"); | |
// Selektor für Beitragsinhalte: | |
const allPostTexts = u(".MessageList .Item .clearfix .right-block .Item-BodyWrap .Item-Body"); | |
allPostTexts.each(function(node, i) { | |
if (u(node).hasClass("wdeplusprocd")) { | |
// Bereits verarbeitet. | |
return; | |
} | |
const beitragsDiv = u(node).parent().parent().parent(); | |
// Beiträge ignorierter Benutzer ausblenden: | |
const ignoreUserListArray = UserIgnoreList.split(";").map(s => s.trim()); | |
const postUser = u(beitragsDiv).find("a.Username").html(); | |
if (ignoreUserListArray.length > 0 && ignoreUserListArray.includes(postUser)) { | |
// Dieser Beitrag kann weg. | |
if (UserIgnoreDelete) { | |
u(beitragsDiv).parent().remove(); | |
} | |
else { | |
u(beitragsDiv).replace("<div>Ignorierter Beitrag von " + postUser + ".</div>"); | |
} | |
} | |
else if (postUser == "WithKeys") { | |
u(beitragsDiv).find("span.RoleTitle").html("Mäzen"); | |
} | |
// WIDs konvertieren: | |
if (ConvertWIDs) { | |
// Alle Links zu WIDs, die die Forensoftware bereits eingebaut hat, wieder entfernen: | |
const allLinksInNode = u(node).find("a"); | |
allLinksInNode.each(function(anchor, i) { | |
const href = u(anchor).attr("href"); | |
const innerText = u(anchor).html(); | |
if (href != null && href.match(/:WID:/) != null) { | |
u(anchor).replace(innerText); | |
} | |
}); | |
const origHtml = u(node).html(); | |
const ersetzen = outputWIDStyle(); | |
const newHtml = origHtml.replace(widregex, '<a href="https://www.whiskybase.com/whiskies/whisky/$3" target="_blank" title="Whisky $3 in der Base">' + ersetzen + '</a>'); | |
u(node).html(newHtml); | |
} | |
u(node).addClass("wdeplusprocd"); | |
}); | |
// Selektor für PN-Inhalte: | |
const allPMTexts = u(".MessageList .Item .ConversationMessage .Message .Wysiwyg-Content"); | |
allPMTexts.each(function(node, i) { | |
if (u(node).hasClass("wdeplusprocd")) { | |
// Bereits verarbeitet. | |
return; | |
} | |
// WIDs konvertieren: | |
if (ConvertWIDs) { | |
// Alle Links zu WIDs, die die Forensoftware bereits eingebaut hat, wieder entfernen: | |
const allLinksInNode = u(node).find("a"); | |
allLinksInNode.each(function(anchor, i) { | |
const href = u(anchor).attr("href"); | |
const innerText = u(anchor).html(); | |
if (href != null && href.match(/:WID:/) != null) { | |
u(anchor).replace(innerText); | |
} | |
}); | |
const origHtml = u(node).html(); | |
const ersetzen = outputWIDStyle(); | |
const newHtml = origHtml.replace(widregex, '<a href="https://www.whiskybase.com/whiskies/whisky/$3" target="_blank" title="Whisky $3 in der Base">' + ersetzen + '</a>'); | |
u(node).html(newHtml); | |
} | |
u(node).addClass("wdeplusprocd"); | |
}); | |
// Ignorierte Themen ausblenden: | |
const ignoreThreadListArray = ThreadIgnoreList.split(";").map(s => s.trim()); | |
if (ignoreThreadListArray.length > 0) { | |
if (threadListNormal != null) { | |
// Themenliste. Hier können IDs und Titel entfernt werden. | |
threadListNormal.each(function(node, i) { | |
// Nummerische IDs: | |
const discussionId = u(node).attr("id"); | |
const numericalId = discussionId.replace("Discussion_", ""); | |
if (ignoreThreadListArray.includes(numericalId)) { | |
// Gefunden. Ganzen Eintrag entfernen. | |
u(node).remove(); | |
return; | |
} | |
// Titel: | |
const titel = u(node).find("div.Title a").html(); | |
if (ignoreThreadListArray.includes(titel)) { | |
// Gefunden. Ganzen Eintrag entfernen. | |
u(node).remove(); | |
return; | |
} | |
}); | |
} | |
if (threadListRecent != null) { | |
// Beitragsliste. Hier funktionieren nur Titel. | |
threadListRecent.each(function(node, i) { | |
const titel = u(node).find(".MItem b a").html(); | |
if (ignoreThreadListArray.includes(titel)) { | |
// Gefunden. Ganzen Eintrag entfernen. | |
u(node).remove(); | |
return; | |
} | |
}); | |
} | |
} | |
if (UncropQuotes == 1) { | |
// "cropped" aus Zitaten entfernen (nervt nur unnötig): | |
u("blockquote").removeClass("cropped"); | |
// Zitate in Zitaten entfernen (braucht keiner): | |
u("blockquote div blockquote").remove(); | |
} | |
else { | |
// Bugfix: Dieses Script macht Ausklappen von Zitaten kaputt. | |
u("blockquote").on("click", function(e) { | |
e.preventDefault(); | |
u(this).removeClass("cropped"); | |
}); | |
} | |
if (HideCounter == 1) { | |
// Beitragszähler ausblenden: | |
u("span.AuthorInfo span.PostCount").remove(); | |
// Federn usw. auch: | |
u("span.AuthorInfo span.Rank:not(.TasteRatingIcon)").remove(); | |
} | |
// Extrasmileys einfügen. Das muss auch beim Hinzufügen neuer Nodes passieren, weil das | |
// Editierfenster von Beiträgen in diesen immer inline aufgeht. Blöd! | |
addWDEPlusSmileys(); | |
// Ignoriermenü einfügen. | |
addThreadIgnoreMenu(false); | |
// Signatureinklappung reparieren: | |
if (DontCollapseSignatures == 1) { | |
u(".UserSignature").removeClass("UserSignatureCollapsed"); | |
u(".userSignatureExpandCollapseButtons").remove(); | |
} | |
else { | |
u(".userSignatureExpandButton, .userSignatureCollapseButton").each(function(node, i) { | |
if (u(node).hasClass("wdeplusprocd")) { | |
// Bereits verarbeitet. | |
return; | |
} | |
u(node).off("click").on("click", function() { | |
let thisSignature = u(this).parent().parent().find(".UserSignature"); | |
// Funktionsweise des Ein- und Ausklappens wiederherstellen: | |
u(thisSignature).toggleClass("UserSignatureCollapsed"); | |
// Beschriftung reparieren: | |
u(node).html(u(thisSignature).hasClass("UserSignatureCollapsed") ? "Signatur ausklappen" : "Signatur einklappen"); | |
}); | |
// Rechtschreibung der Umschaltschaltfläche verbessern: | |
u(node).html("Signatur ausklappen"); | |
u(node).addClass("wdeplusprocd"); | |
}); | |
} | |
if (!u(pagewrapper).hasClass("wdeplusprocd")) { | |
// Die Seite wurde noch nicht angepasst. | |
// Dumme Reklame wegmachen: | |
u("#banners-top").remove(); | |
if (PinHeader == 1) { | |
// Kopfzeile anheften: | |
u(".container-fluid").attr("style", "position: fixed; z-index: 100; background-color: antiquewhite;"); | |
// Bei angehefteter Kopfzeile würden Popups verdeckt. Korrigieren: | |
u(".Popup").attr("style", "z-index: 200;"); | |
// Seitenauswahl und Foreninhalt müssen weiter unten beginnen: | |
u("#Body").attr("style", "margin-top: 170px"); | |
if (u(".datamints-infinite-scroll-pagination") != null) { | |
// "Unendliches" Scrollen ist aktiv. Da ohnehin angeheftet, können wir hier weniger | |
// "Platz" oben annehmen: | |
u(".datamints-infinite-scroll-pagination").attr("style", "margin-top: 110px"); | |
} | |
// Hochscrollen, da die Seite in schlechten Browsern (Firefox) jetzt | |
// automatisch runtergescrollt wurde, falls wir uns in einer Forenliste | |
// (/forum/categories/) befinden: | |
if (window.location.pathname.includes("/forum/categories/")) { | |
window.scrollTo(0, 0); | |
} | |
} | |
// Seitenleisten sind nur auf dem Desktop relevant. | |
if (!isSmallMobileDevice) { | |
// Seitenleiste(n) ausblenden: | |
if (DisableLeftSidebar == 1 && u("#sidebar-left") != null) { | |
u("#sidebar-left").remove(); | |
} | |
if (DisableRightSidebar == 1 && u("#sidebar-right") != null) { | |
u("#sidebar-right").remove(); | |
} | |
// Breite anpassen, falls Seitenleiste(n) ausgeblendet: | |
if (DisableRightSidebar == 1 || DisableLeftSidebar == 1) { | |
wdeResize(); | |
} | |
} | |
// Als "verarbeitet" kennzeichnen: | |
u(pagewrapper).addClass("wdeplusprocd"); | |
} | |
} | |
// Falls "Infinite Scroll" deaktiviert ist, greift der MutationObserver nicht. | |
// Initial muss processPage() daher wenigstens einmal aufgerufen werden. | |
processPage(); | |
// -------- Beim Größenändern des Fensters Elemente anpassen: | |
function wdeResize() { | |
// Beim Größenändern werden auch Seitenleisten u.U. unterschiedlich breit: | |
if (u("#sidebar-left").length > 0) { | |
sidebar_links = window.matchMedia("(max-width: 800px)").matches ? 0 : u("#sidebar-left").size().width; | |
} | |
if (u("#sidebar-right").length > 0) { | |
sidebar_rechts = window.matchMedia("(max-width: 800px)").matches ? 0 : u("#sidebar-right").size().width; | |
} | |
let breiteMitte = u("#Body .wrapper").size().width - sidebar_links - sidebar_rechts; | |
// Anpassen der Breite an die Existenz der Seitenleisten: | |
if (DisableLeftSidebar == 1 && u("#sidebar-left").length == 0) { | |
// Linke Seitenleiste weg - Mitte verbreitern: | |
breiteMitte += sidebar_links; | |
} | |
if (DisableRightSidebar == 1 && u("#sidebar-right").length == 0) { | |
// Rechte Seitenleiste weg - Mitte verbreitern: | |
breiteMitte += sidebar_rechts; | |
} | |
u(pagewrapper).attr("style", "width:" + breiteMitte + "px"); | |
// Auch das "antworten"-Element darf breiter sein: | |
const antwortenForm = u(".MessageForm.fixed").first(); | |
if (antwortenForm != null) { | |
let antwortenStyle = ""; | |
if (DisableLeftSidebar == 0) { | |
antwortenStyle += "margin-left:0px;"; | |
antwortenStyle += "left:" + sidebar_links + "px;"; | |
} | |
antwortenStyle += "max-width:" + breiteMitte + "px;"; | |
antwortenStyle += "width:" + breiteMitte + "px;"; | |
u(antwortenForm).attr("style", antwortenStyle); | |
} | |
} | |
if (!isSmallMobileDevice && (DisableRightSidebar == 1 || DisableLeftSidebar == 1)) { | |
// Eine Größenänderung ist nur bei Seitenleistenausblendung sinnvoll. | |
window.addEventListener("resize", wdeResize); | |
} | |
// -------- CSS: | |
GM.addStyle(" \ | |
.navigation-realms > ul > li.wde > a:before { \ | |
/* Stern fürs Einstellungsmenü */ \ | |
content: '\\f19a'; \ | |
} \ | |
\ | |
.MessageList.Comments .Pocket { \ | |
/* Keine Reklame zwischen den Beiträgen */ \ | |
display: none; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr { \ | |
position: fixed; \ | |
padding: 2em; \ | |
background: #FFF2E1; \ | |
border: 3px double black; \ | |
border-radius: 1ex; \ | |
z-index: 999; \ | |
width: 614px; \ | |
height: 600px; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr.wdeSmall { \ | |
padding: 12px; \ | |
width: 100%; \ | |
height: auto; \ | |
top: 100px; \ | |
left: 0px; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr:not(.wdeSmall) { \ | |
/* Zentrieren, wenn Bildschirm groß genug: */ \ | |
top: 50%; \ | |
left: 50%; \ | |
margin-top: -262px; \ | |
margin-left: -307px; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr:not(.visible) { \ | |
/* Der Dialog ist immer da, nur manchmal versteckt. */ \ | |
display: none; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr form label { \ | |
font-weight: normal; \ | |
padding-top: 4px; \ | |
} \ | |
\ | |
#wdeplusSettingsCtr form button { \ | |
border: 1px solid black; \ | |
} \ | |
\ | |
#wdeSaveBtn { \ | |
background-color: lightgreen; \ | |
} \ | |
\ | |
#wdeCloseBtn { \ | |
background-color: #fcaca4; \ | |
} \ | |
\ | |
.wdeplusHdr { \ | |
font-size: 18px; \ | |
font-weight: bold; \ | |
margin-bottom: 18px; \ | |
} \ | |
\ | |
.wdeplusHdr.wdeSmall { \ | |
margin-bottom: 8px; \ | |
} \ | |
\ | |
.wdeplusHint { \ | |
font-size: 12px; \ | |
margin-top: 20px; \ | |
} \ | |
\ | |
.FormWrapper-Condensed { \ | |
/* Antworten-Formular mit sichtbarem Rand. \ | |
Sieht sonst scheiße aus. */ \ | |
border: 1px solid #CF4D3B; \ | |
} \ | |
\ | |
div.consent { \ | |
/* Cookiezustimmungsnervbalken wegmachen. \ | |
Achtung: Euer Browser sollte natürlich trotzdem so \ | |
eingestellt sein, dass er nicht alle Werbecookies \ | |
ungefragt übernimmt. (Viele moderne Browser sind das \ | |
sowieso, geprüft in Safari und Vivaldi.) */ \ | |
display: none; \ | |
} \ | |
\ | |
@media (max-width: 799px) { \ | |
/* Korrektur: Mit dem zusätzlichen Button ist die Buttonleiste \ | |
oben auf kleinen Bildschirmen zu breit. Mach'se schmaler. */ \ | |
.navigation-realms > ul > li.current { \ | |
width: 20%; \ | |
} \ | |
\ | |
/* Auch die Buttonbeschriftung stört da eher. */ \ | |
.navigation-realms > ul > li.current > a > span { \ | |
display: none; \ | |
} \ | |
} \ | |
"); | |
if (PinHeader == 1) { | |
// Bei angehefteter Kopfzeile verschwinden sonst die Dialoge. | |
GM.addStyle(".modal { padding-top: 170px; }"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Version 1.0 2020-02-11 | |
* Erste Version. | |
Version 1.1 2020-02-11 | |
* Die Änderung der Fenstergröße wird jetzt behandelt. | |
* Das Ausklappen von Zitaten ging nicht mehr. | |
* Option eingebaut, um Zitate automatisch auszuklappen. | |
* Zitate in Zitaten werden jetzt auf Wunsch automatisch entfernt. | |
* Das manuelle Ausklappen geht wieder. | |
* Der WID-Umwandler funktioniert jetzt auch bei falscher Syntax etwas weniger schlecht. | |
Version 1.2 2020-02-11 | |
* Weitere Hilfetexte im Einstellungsdialog eingefügt. | |
* Blacklist für Threads eingefügt: Versteckt Themen anhand ihrer IDs. | |
* Vergessenen Debuglogeintrag entfernt. | |
Version 1.3 2020-02-11 | |
* Größenänderungen werden nur noch bei ausgeblendeten Seitenleisten vorgenommen. | |
Version 1.4 2020-02-12 | |
* Fehlerkorrektur für Firefox: Der reguläre Ausdruck für WIDs wurde vereinfacht. | |
Version 1.5 2020-02-13 | |
* Das Script läuft jetzt auch im "Treffpunkt". | |
* WDE++ kann sich bei Updates jetzt selbst aktualisieren. | |
* Unter "Neueste Beiträge" funktionierte das Ignorieren von Thread-IDs nicht. | |
* Alternativ können jetzt auch Threadtitel angegeben werden. | |
* Wenn ID und Titel desselben Threads angegeben werden, funktioniert es trotzdem. | |
* Verschönerung: Das Antworten-Formular hat nur noch in seiner Aufpoppvariante einen Rahmen. | |
Version 1.6 2020-02-13 | |
*** Testupdate für die automatische Aktualisierung, nicht separat veröffentlicht. | |
* Verschiedene Verbesserungen am Design des Einstellungsdialogs. | |
Version 1.7 2020-02-14 | |
* Verbesserungen für die WID-Erkennung. | |
* Automatisch eingefügte "denied:"-Links werden jetzt zuerst entfernt. | |
* Manchmal gab es in einer WID. Das wird jetzt korrekt weggefiltert. | |
* JPG, PNG und GIF werden nicht mehr fälschlich als Seite des Forums behandelt. | |
Version 1.8 2020-02-25 | |
*** Nicht separat veröffentlicht. | |
* Verlinkte WIDs werden jetzt auch als Nummer angezeigt. | |
* Code ein wenig aufgeräumt. | |
Version 1.9 2020-02-26 | |
* Der Anzeigestil von WIDs kann jetzt geändert werden. | |
* Mit Zahl, ohne Zahl oder nur die Zahl. | |
* Der Kopfbereich des Forums kann jetzt angeheftet werden. | |
* Der Einstellungsdialog wurde etwas farbenfroher gestaltet. | |
* Mehr reguläre Ausdrücke für weniger include-Regeln. | |
Version 2.0 2020-02-26 | |
* Der Einstellungsdialog wird jetzt in der Mitte des Bildschirms geöffnet. | |
Version 2.1 2020-02-27 | |
* Eventuell war der blöde Reklamebanner oben im Weg. Er wird jetzt ausgeblendet, sofern | |
die Kopfzeile angeheftet wird. | |
Version 2.2 2020-03-03 | |
*** Nicht separat veröffentlicht. | |
* Manchmal hat die Forensoftware HTML-Tags in WIDs reingemacht. Diese werden jetzt gefunden | |
und gelöscht. | |
Version 2.3 2020-03-31 | |
* WIDs in Dateinamen sollten jetzt kein Problem mehr darstellen. | |
* WB-Links jetzt mit "www". | |
Version 2.4 2020-04-09 | |
*** Nicht separat veröffentlicht. | |
* Das Antworten-Formular wurde manchmal nicht richtig angezeigt. Jetzt vielleicht doch. | |
Version 2.5 2020-04-14 | |
* Fehlerbehebungen für Firefox bei angeheftetem Kopfbereich: | |
* Firefox hat immer runtergescrollt. Es wird jetzt automatisch wieder hochgescrollt. | |
* Anpassung der Navigation bei ausgewähltem "unendlichem" Scrollen. | |
Version 2.6 2020-06-17 | |
* Das Hochscrollen (siehe Version 2.5) passiert jetzt nur noch in der Themenliste. | |
* Bei angeheftetem Kopfbereich wurden Popups verdeckt. Korrigiert. | |
* Der Einstellungsdialog kann jetzt mit "<Esc>" geschlossen werden. | |
Version 2.7 2020-06-19 | |
*** Nicht separat veröffentlicht. | |
* Der Einstellungsdialog zeigt jetzt auch die Versionsnummer des Scripts an. | |
Version 2.8 2020-06-24 | |
*** Das Veröffentlichen separater ZIP-Dateien wurde eingestellt. Es wird jetzt | |
nur noch die Installation über die Scriptdatei von GitHub unterstützt! | |
* Das Öffnen des Einstellungsdialogs springt nicht mehr auf der Seite umher. | |
* Der Einstellungsknopf benutzt jetzt das "Dauertiefpreis"- anstelle des Info-Symbols. | |
Version 2.9 2020-11-02 | |
* Reguläre Ausdrücke vereinfacht: Das Script wird nur noch auf der www-Subdomain | |
aktiviert. | |
* Zwischen Beiträgen tauchte manchmal ein Werbebanner auf. Der sollte jetzt nicht | |
mehr da sein. | |
Version 3.0 2020-11-09 | |
* Lizenzheader eingefügt (weil ich's kann). | |
* Layout der Buttonleiste auf kleinen Bildschirmen verbessert. | |
* Smartphonenutzer haben jetzt einen neuen, kleineren Einstellungsdialog. | |
* Der Einstellungsdialog wird erst freigegeben, wenn die Seite geladen ist. Das | |
sollte das "Flackern" beim Aufruf beheben. | |
* Bugfix: Breitenberechnung auf Smartphones deaktiviert. | |
Version 3.1 2020-11-09 | |
* Firefox ignorierte das "load"-Event manchmal. WDE++ wird daher nun per run-at- | |
Direktive nach dem Laden der Seite ausgeführt. | |
Version 3.2 2021-01-16 | |
* Die WID-Stilauswahl wird jetzt ausgegraut, wenn die Umwandlung nicht gewünscht | |
ist. | |
Version 3.3 2021-01-20 | |
* Code besser dokumentiert sowie im Forum angekündigtes Easter Egg platziert. | |
Version 3.4 2021-01-26 | |
* Die Ermittlung der WID-Anzeige wurde in eine eigene Funktion ausgelagert. | |
* WIDs werden jetzt auch in privaten Nachrichten umgewandelt. | |
Version 3.5 2021-01-27 | |
* Easter Egg wieder entfernt. | |
* Es gab eine unnötige Logmeldung beim Größeändern des Browserfensters. Jetzt | |
gibt es sie nicht mehr. | |
Version 3.6 2021-01-29 | |
* Die Ignorierlisten werden jetzt getrim()t, Leerzeichen vor/nach den trennenden | |
Semikola sollten somit weniger Probleme bereiten. | |
Version 3.7 2021-01-31 | |
* Die WID-Stileinstellungen sind jetzt auch auf mobilen Geräten sichtbar. | |
Version 3.8 2021-02-03 | |
* Fehler im regulären Ausdruck behoben: Das Wort WID konnte dazu führen, dass | |
ganze Absätze ersetzt (visuell gelöscht) wurden, wenn nach ihm eine neue Zeile | |
begonnen wurde. | |
* Die Reklame am oberen Bildrand sieht jetzt auch mit angeheftetem Kopfbereich | |
nicht mehr blöd aus, denn sie wird dann entfernt. | |
Version 3.9 2021-02-10 | |
* WIDs konnten noch nicht erkannte span-Tags enthalten. Korrigiert. | |
Version 4.0 2021-03-13 | |
* Es sind nun ein Affen- und ein Schulternzuck-Emoji als Bilder einfügbar. | |
Damit ist es theoretisch auch möglich, künftig beliebige Emojis hinzuzufügen, | |
sofern diese als Bilddateien online vorliegen. | |
Version 4.1 2021-03-26 | |
* Der Cookiebanner am unteren Bildrand wird automatisch weggemacht. | |
Version 4.2 2021-04-26 | |
* WID-Links funktionieren jetzt auch mit dem Präfix "WBID". | |
Version 4.3 2021-04-29 | |
* Code für die Ermittlung zu ignorierender Beiträge etwas vereinfacht. | |
* Es wurde eine Änderung an angezeigten Benutzertiteln vorgenommen. | |
Version 4.4 2021-05-04 | |
* Der Code für die Smartphoneerkennung war zwar funktional, aber nicht | |
ganz logisch. Korrigiert. | |
Version 4.5 2021-06-15 | |
* Die Änderung der Fenstergröße (horizontal und/oder vertikal) konnte | |
zu Darstellungsfehlern des "Antworten"-Formulars führen. Korrigiert. | |
* Ignorieren und Entignorieren von Threads ist jetzt über das Zahnrad- | |
menü oben rechts möglich. | |
Version 4.6 2021-06-16 | |
* Der Werbebanner oben wird jetzt auch ohne angehefteten Kopfbereich | |
entfernt. | |
* Eine Änderung am Forendesign hat WDE++ außer Gefecht gesetzt. Das | |
Gefecht wurde wieder aufgenommen. | |
* Die Suchleiste in der Seitenleiste existiert nicht mehr. Der Code, | |
um sie zu verschieben, wurde daher entfernt. | |
* Die Änderung der Fenstergröße (horizontal und/oder vertikal) konnte | |
immer noch zu Darstellungsfehlern führen. Korrigiert. | |
Version 4.7 2021-06-27 | |
* Beiträge ignorierter Benutzer können jetzt auch vollständig entfernt | |
werden. | |
Version 4.8 2021-09-03 | |
* Der Beitragszähler kann jetzt ausgeblendet werden. | |
Version 4.9 2021-10-28 | |
* Umstellung auf GM.*-APIs: Greasemonkey sollte jetzt zusätzlich zu den | |
bisher unterstützten Erweiterungen Tampermonkey und Violentmonkey | |
funktionieren. | |
Version 5.0 2021-11-24 | |
* Der kaputte Signatureinklapper vom Forum wurde erst mal rausoperiert. | |
Version 5.1 2021-11-26 | |
* Lizenz von CDDL 1.0 auf CDDL 1.1 umgestellt (vermeidet Unklarheiten in | |
der EU). | |
* Der kaputte Signatureinklapper vom Forum wurde repariert. | |
Version 5.2 2021-11-30 | |
* Der Signatureinklapper ist jetzt abschaltbar. | |
Version 5.3 2021-02-12 | |
* Anpassungen an die neue Version von Whisky.woff2. | |
Version 5.4 2023-02-06 | |
* Anpassungen an die neue Version von Whisky.woff2. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment