您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hides thread titles you don't want to see immediately
// ==UserScript== // @name TF.TV Thread Title Hider // @namespace sheybey // @description Hides thread titles you don't want to see immediately // @include https://www.teamfortress.tv/* // @version 1.3 // @grant none // ==/UserScript== // I don't agree with some of jslint's whitespace rules /*jslint browser, for, multivar, this, white*/ /*global NodeList*/ /*property add, addEventListener, appendChild, backgroundColor, border, call, classList, clear, color, contains, createElement, currentTarget, dataset, display, float, fontSize, fontStyle, forEach, getAttribute, getElementById, getItem, height, insertBefore, join, keys, length, lineHeight, marginTop, oldHref, oldTitle, overflow, padding, parentNode, parse, position, preventDefault, prototype, push, querySelector, querySelectorAll, remove, removeChild, removeEventListener, replace, setAttribute, setItem, slice, split, stopPropagation, stringify, style, test, textContent, toLowerCase, top, trim, value, width, zIndex */ (function () { "use strict"; var hidden = localStorage.getItem("user-hidden"), def = [ "esea", "etf2l", "ozf", "lan" ], // these elements are explained where they are first used navbar = document.querySelector("nav"), spoiler = document.createElement("a"), spoilerdiv = document.createElement("div"), spoilericon = document.createElement("i"), container = document.createElement("div"), add = document.createElement("span"), savetext = document.createElement("span"), firstrow = document.createElement("div"), shown = false, before, threads, articles, news; if (hidden === null) { hidden = def; } else { hidden = JSON.parse(hidden); } hidden = (function () { var o = {}; hidden.forEach(function (keyword) { o[keyword] = new RegExp("\\b" + // this replace call escapes regex characters keyword.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + "\\b", "i"); }); return o; }()); // remove the title of a thread from a link, while preserving the effective target function sanitize(link, title) { link.classList.add("user-hidden"); link.dataset.oldTitle = title; // <a title="..."> is not always set link.dataset.oldHref = link.getAttribute("href"); // this slice and join removes the last component of the url, which is the slug, from href link.setAttribute("href", link.dataset.oldHref.split("/").slice(0, -1).join("/")); link.setAttribute("title", "Click to reveal"); } // restore the information removed by sanitize() function restore(link) { link.classList.remove("user-hidden"); link.setAttribute("title", link.dataset.oldTitle); link.setAttribute("href", link.dataset.oldHref); } // these functions find link and title elements given a click event and restore information as necessary function revealsidebar(event) { var link = event.currentTarget, span = link.querySelector(".module-item-title"); event.preventDefault(); event.stopPropagation(); restore(link); link.removeEventListener("click", revealsidebar); span.textContent = link.dataset.oldTitle; span.style.fontStyle = ""; } function revealthread(event) { var link = event.currentTarget; event.preventDefault(); event.stopPropagation(); restore(link); link.removeEventListener("click", revealthread); link.textContent = link.dataset.oldTitle; link.style.fontStyle = ""; } function revealarticle(event) { var link = event.currentTarget, span = link.querySelector(".news-item-title"); event.preventDefault(); event.stopPropagation(); restore(link); link.removeEventListener("click", revealarticle); span.textContent = link.dataset.oldTitle; span.style.fontStyle = ""; } // basically Array.prototype.forEach, but safer than using it directly if (typeof NodeList.prototype.forEach !== "function") { NodeList.prototype.forEach = function (f) { var i; for (i = 0; i < this.length; i += 1) { f.call(this[i], this[i], i, this); } }; } // look for links to sanitize // the sidebar exists on all pages document.getElementById("sidebar-left").querySelectorAll(".module").forEach(function (module) { module.querySelectorAll(".module-item").forEach(function (link) { var span = link.querySelector(".module-item-title"), title; if (span.classList.contains("mod-event")) { return; // event posts generally do not have spoilers } title = span.textContent.trim(); // Object.keys is usually faster than querySelector[All], so it is on the inside of the loop Object.keys(hidden).forEach(function (keyword) { var newtitle = "[" + keyword + " thread]"; if (link.classList.contains("user-hidden")) { return; } if (hidden[keyword].test(title)) { sanitize(link, title); link.addEventListener("click", revealsidebar); span.textContent = newtitle; span.style.fontStyle = "italic"; } }); }); }); // this element only exists on /forum... and /threads threads = document.getElementById("thread-list"); if (threads !== null) { threads.querySelectorAll(".thread-inner").forEach(function (thread) { // this element only exists on /threads var category = thread.querySelector(".description a"), link, title; if (category !== null && category.textContent.trim() === "Events") { return; } link = thread.querySelector("a.title"); title = link.textContent.trim(); Object.keys(hidden).forEach(function (keyword) { var newtitle = "[" + keyword + " thread]"; if (link.classList.contains("user-hidden")) { return; } if (hidden[keyword].test(title)) { sanitize(link, title); link.addEventListener("click", revealthread); link.textContent = newtitle; link.style.fontStyle = "italic"; } }); }); } // this element only exists on the front page articles = document.getElementById("article-list"); if (articles !== null) { articles.querySelectorAll("a").forEach(function (link) { var span = link.querySelector(".news-item-title"), title = span.textContent.trim(); Object.keys(hidden).forEach(function (keyword) { var newtitle = "[" + keyword + " article]"; if (link.classList.contains("user-hidden")) { return; } if (hidden[keyword].test(title)) { sanitize(link, title); link.addEventListener("click", revealarticle); span.textContent = newtitle; span.style.fontStyle = "italic"; } }); }); } // this element only exists on /news news = document.querySelector("#content > .list-table:not(#schedule-table)"); if (news !== null) { news.querySelectorAll("a").forEach(function (link) { var title = link.textContent.trim(); Object.keys(hidden).forEach(function (keyword) { var newtitle = "[" + keyword + " article]"; if (link.classList.contains("user-hidden")) { return; } if (hidden[keyword].test(title)) { sanitize(link, title); link.addEventListener("click", revealthread); link.textContent = newtitle; link.style.fontStyle = "italic"; } }); }); } // this function creates an <input> and remove button for the config div function createrow(word) { var row = document.createElement("div"), input = document.createElement("input"), remove = document.createElement("span"); if (word === undefined) { word = ""; } // the <input> input.style.height = "30px"; input.style.marginTop = "5px"; input.style.fontSize = "11px"; input.style.lineHeight = "30px"; input.style.width = "100px"; input.value = word; // remove button remove.style.float = "right"; remove.classList.add("btn"); remove.textContent = "Remove"; remove.addEventListener("click", function () { row.parentNode.removeChild(row); }); // containing row row.style.height = "40px"; row.style.padding = "5px 0"; row.style.clear = "both"; row.appendChild(input); row.appendChild(remove); return row; } // the spoiler <a> in the navbar spoiler.classList.add("header-nav-item-wrapper"); spoiler.classList.add("mod-last"); spoiler.setAttribute("href", "#"); spoiler.style.overflow = "visible"; spoiler.addEventListener("click", function (event) { event.preventDefault(); // # causes "scroll jump" to top otherwise var newhidden = []; if (shown) { container.style.display = "none"; container.querySelectorAll("input").forEach(function (input) { newhidden.push(input.value.toLowerCase()); }); localStorage.setItem("user-hidden", JSON.stringify(newhidden)); spoilericon.classList.remove("fa-caret-up"); spoilericon.classList.add("fa-caret-down"); shown = false; } else { container.style.display = ""; spoilericon.classList.remove("fa-caret-down"); spoilericon.classList.add("fa-caret-up"); shown = true; } }); // each navbar button has a <div> child that contains its label spoilerdiv.classList.add("header-nav-item"); spoilerdiv.classList.add("mod-solo"); spoilerdiv.textContent = "Spoilers "; // font awesome icon that reflects whether the config <div> is shown or not spoilericon.classList.add("fa"); spoilericon.classList.add("fa-caret-down"); // this <div> is shown and hidden when the spoiler button is clicked container.style.backgroundColor = "#f5f5f5"; container.style.position = "absolute"; container.style.top = "40px"; container.style.display = "none"; container.style.zIndex = "99"; container.style.width = "200px"; container.style.padding = "5px"; container.style.border = "1px solid #b4b4b4"; // this is necessary to prevent clicks on the config <div> from propagating to the spoiler button container.addEventListener("click", function (event) { event.preventDefault(); event.stopPropagation(); }); // this row contains the help text and add button firstrow.style.height = "40px"; firstrow.style.padding = "5px 0"; firstrow.style.clear = "both"; // help text for config <div> savetext.style.fontSize = "11px"; savetext.style.color = "#555555"; savetext.style.lineHeight = "40px"; savetext.textContent = "Close to save"; // the add button add.classList.add("btn"); add.textContent = "Add"; add.style.float = "right"; add.addEventListener("click", function () { container.appendChild(createrow()); }); firstrow.appendChild(savetext); firstrow.appendChild(add); container.appendChild(firstrow); Object.keys(hidden).forEach(function (keyword) { container.appendChild(createrow(keyword)); }); spoilerdiv.appendChild(spoilericon); spoiler.appendChild(spoilerdiv); spoiler.appendChild(container); // spoiler button is inserted before this element before = navbar.querySelector("#user-actions"); // logged in if (before === null) { before = navbar.querySelector("a:last-child"); // not logged in } navbar.insertBefore(spoiler, before); }());
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址