您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Search for posts by user(-s) in current topic
当前为
// ==UserScript== // @name Search posts by user // @name:ru Поиск постов пользователя // @description Search for posts by user(-s) in current topic // @description:ru Найти посты пользователя(-ей) в текущей теме // @version 2.0.2 // @date 19.12.2017 // @author Halibut // @namespace https://gf.qytechs.cn/en/users/145947-halibut // @homepageURL https://gf.qytechs.cn/en/scripts/36319-search-posts-by-user // @supportURL https://forum.ru-board.com/topic.cgi?forum=2&topic=5673&glp // @license HUG-WARE // @include http*://forum.ru-board.com/topic.cgi?forum=*&topic=* // @noframes // @run-at document-start // @grant none // ==/UserScript== /****************************************************************************** * "THE HUG-WARE LICENSE" (Revision 2): As long as you retain this notice you * * can do whatever you want with this stuff. If we meet some day, and you * * think this stuff is worth it, you can give me/us a hug. * ******************************************************************************/ window.addEventListener("DOMContentLoaded", function f() { 'use strict'; this.removeEventListener("DOMContentLoaded", f); const body = document.body, style = document.head.appendChild(document.createElement("style")), dats = [...document.getElementsByClassName("tb")].map(el => el.getElementsByClassName("dats")[0]), css = [ '#spu-spoiler-head {', ' font-family: Segoe UI Emoji, bitstreamcyberbit, quivira, Verdana, Arial, Helvetica, sans-serif;', ' -moz-user-select: none !important;', ' -webkit-user-select: none !important;', ' -ms-user-select: none !important;', ' user-select: none !important;', ' cursor: pointer !important', '}', '#spu-spoiler-head[notready] {', ' cursor: not-allowed !important;', '}', '#spu-spoiler-body {', ' border: 1px solid black !important;', ' padding: 1em .5em !important;', '}', '#spu-spoiler-body button.cpu-search {', ' display: none !important;', '}', 'button.spu-search {', ' padding: .05em .5em .1em !important;', ' background: rgb(251,251,251) !important;', ' color: rgb(51, 51, 51) !important;', ' border: 1px solid rgba(66,78,90,0.2) !important;', ' border-radius: 2px !important;', ' box-shadow: none !important;', ' font-size: 1em !important;', '}', 'button.spu-search:hover {', ' background: rgb(235,235,235) !important;', '}', 'button.spu-search:active {', ' background: rgb(225,225,225) !important;', '}' ].join('\n'), listener = { options: { // !!!ОПЦИИ СКРИПТА!!! (пока неполные) showAlerts: false // Показывать алерты по окончании поиска , scrollToSearchResults: true // Автоматически прокручивать страницу к результатам поиска // (если showAlerts == true, то, при подтверждении, все-равно прокрутит к результатам) , autoOpenSpoilerWithResult: false // Раскрывать спойлер с результатами поиска автоматически , reversPostSorting: true // обратить сортировку по дате для найденных постов (от новых к старым) , headToResult: false // Включать шапку темы (если она создана выбранным пользоватем) в результаты поиска , createCnMenu: true // Добавить в контекстное меню пункт запускающий поиск (только для FF) , searchOnProfileLinksByRMB: true // Поиск при клике по ссылкам ведущим на профиль пользователя // (только если нет выделенного текста и не нажаты клавиши модификаторы) } , names: [] , ttlShow: '\u25BA Показать результаты поиска' , ttlHide: '\u25BC Скрыть результаты поиска' , ttlLdng: '\u23F3 Поиск...' , ttlNotFnd: '\u26A0 Постов не найдено!' , get name() { return this.name = this.getName() } , set name(str) { return this.setName(str) } , get win() { delete this.win; return this.win = window.top } , get loc() { delete this.loc; return this.loc = this.win.location.href } , get actnBox() { delete this.actnBox; return this.actnBox = [...document.getElementsByTagName("table")].find(el => el.querySelector("a[href^='post.cgi?action=new']") || !el.getElementsByTagName('td')[0].children.length) } , get isFF() { delete this.isFF; return this.isFF = this.win.navigator && this.win.navigator.userAgent && this.win.navigator.userAgent.toLowerCase().includes("firefox") } , get spHd() { delete this.spHd; return this.spHd = this.getSpHd() } , get spBd() { delete this.spBd; return this.spBd = this.getSpBd() } , get spTTl() { delete this.spTTl; return this.spTTl = this.spHd && this.spHd.getElementsByTagName('td')[0] } , getSel() { return this.win.getSelection && this.win.getSelection().toString() || "" } , prompt() { const prompt = this.win.prompt('Задайте имя(-ена) для поиска, разделяя запятой', '') return prompt } , getPosts([url, page], name) { return new Promise((res, rej) => { let posts; if (url == this.loc) { posts = document.getElementsByClassName('tb'); if (posts && !!posts.length) { posts = this.filterPosts(posts, name, page); return res(posts.map(el => el.cloneNode(true))); } }; const xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.onload = re => { if (!(xhr.readyState == 4 && xhr.status == 200)) return rej("error"); posts = xhr.responseXML.getElementsByClassName('tb'); if (posts && !!posts.length) { posts = this.filterPosts(posts, name, page); return res(posts); } }; xhr.onerror = xhr.onabort = xhr.ontimeout = () => rej("error"); xhr.responseType = "document"; xhr.send(); }) } , procesPosts(posts) { return new Promise((res, rej) => { posts = this.flatPosts(posts); if (posts && !!posts.length) { this.options.reversPostSorting && (posts = posts.reverse()); posts = this.stylePosts(posts); for (const post of posts) this.spBd.appendChild(post); res(posts.length) } else rej("not found"); }) } , filterPosts(posts, name, page) { return [...posts].filter(post => (this.options.headToResult && page == 1 || !post.querySelector('a.tpc[href$="&postno=1"]')) && name.includes(post.querySelector("td.dats b").textContent.toLowerCase().replace(/\s/g, '_'))); } , stylePosts(posts) { const color1 = "#EEEEEE", color2 = "#FFFFFF" return posts.map((post,indx) => { const tdEls = post.getElementsByTagName("td"); for (const td of tdEls) { td.bgColor && (td.bgColor = ((indx + 1) % 2) ? color1 : color2); } return post }) } , flatPosts(posts) { return posts.reduce((a, b) => a.concat(b), []) } , getName() { const name = this.getSel() || [...new Set(this.names)].join(","); if (name) return name.trim().toLowerCase().replace(/\s/g, "_").split(",") } , setName(str) { if (str) return this.names.push(str); } , getPages() { const paginator = [...document.getElementsByTagName("p")].find(el => el.textContent && el.textContent.startsWith("Страницы: ")); if (paginator) return [...paginator.getElementsByTagName("td")[0].children].map((el, indx) => [el.href || this.loc, indx + 1]); else return [[this.loc, 1]]; } , getSpHd() { let spoilerHead = document.getElementById("spu-spoiler-head"); if (!spoilerHead) { const dummyNode = this.actnBox.parentNode.insertBefore(document.createElement('div'), this.actnBox.nextElementSibling); dummyNode.outerHTML = '<table id="spu-spoiler-head" width="95%" cellspacing="1" cellpadding="3" bgcolor="#999999" align="center" border="0"><tbody><tr><td valign="middle" bgcolor="#dddddd" align="left"></td></tr><td class="small" bgcolor="#dddddd" align="center">Найдено: <span id="spu-fndd"></span> Ошибок: <span id="spu-errs"></span></td></tbody></table>'; spoilerHead = this.actnBox.nextElementSibling; spoilerHead.id = "spu-spoiler-head"; spoilerHead.hidden = true; const spTitle = spoilerHead.getElementsByTagName('td')[0]; spoilerHead.onclick = e => { e.preventDefault(); e.stopPropagation(); const spoilerBody = this.spBd; if (e.button != 0 || !spoilerBody || spoilerHead.hasAttribute("notready")) return; spTitle.textContent = spoilerBody.hidden ? this.ttlHide : this.ttlShow; spoilerBody.hidden = !spoilerBody.hidden; } } return spoilerHead; } , getSpBd() { let spoilerBody = document.getElementById("spu-spoiler-body"); if (!spoilerBody) { const spoilerHead = this.spHd; spoilerBody = spoilerHead.parentNode.insertBefore(document.createElement("table"), spoilerHead.nextElementSibling); spoilerBody.id = "spu-spoiler-body"; spoilerBody.align = "center"; spoilerBody.width = "95%"; spoilerBody.hidden = true } return spoilerBody; } , endNotify(fndd,errs,ntfnd) { if (fndd) { const spoilerHead = this.spHd, spoilerBody = this.spBd, confirm = this.win.confirm("Поиск окончен!\nНайдено: " + fndd + (errs ? "\nОшибок: " + errs : "") + "\nПерейти к резульататам?"); if (confirm) { spoilerHead.scrollIntoView({behavior:"smooth"}); if (this.options.autoOpenSpoilerWithResult) { this.spTTl.textContent = this.ttlHide; spoilerBody.hidden = false; } } } else this.win.alert("Постов не найдено!" + (errs ? "\nОшибок: " + errs : "")); } , handleEvent(e, name, prmpt) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); this.name = prmpt ? this.prompt() : name; if (name && e.ctrlKey) return; const nmsToSearch = this.name; if (!nmsToSearch || nmsToSearch && !nmsToSearch.length) return; const pageLinks = this.getPages(), spoilerHead = this.spHd, spoilerBody = this.spBd, spoilerTitle = this.spTTl, errsLbl = document.getElementById("spu-errs"), findedLbl = document.getElementById("spu-fndd"); spoilerHead.hidden = false; spoilerTitle.textContent = this.ttlLdng; spoilerHead.setAttribute("notready", "true"); spoilerBody.hidden = true; this.options.scrollToSearchResults && !this.options.showAlerts && spoilerHead.scrollIntoView({behavior:"smooth"}); let errorsCntr = 0; errsLbl.textContent = findedLbl.textContent = 0; if (spoilerBody.children && !!spoilerBody.children.length) for (const node of [...spoilerBody.children]) node.remove(); Promise.all(pageLinks.map(link => { return this.getPosts(link, nmsToSearch) })).then( posts => { return this.procesPosts(posts) } , error => { errorsCntr += 1; errsLbl.textContent = errorsCntr; } ).then( founded => { findedLbl.textContent = founded; spoilerTitle.textContent = this.ttlShow; spoilerHead.removeAttribute("notready"); if (this.options.showAlerts) this.endNotify(founded, errorsCntr) else if (this.options.autoOpenSpoilerWithResult) { spoilerBody.hidden = false spoilerTitle.textContent = this.ttlHide; }; return } , notfound => { spoilerTitle.textContent = this.ttlNotFnd; this.options.showAlerts && this.endNotify(null, errorsCntr, notfound); return } ).catch(err => { errorsCntr += 1; errsLbl.textContent = errorsCntr }) this.names.length = 0; } }; style.textContent = css; if (dats) for (const dat of dats) { const button = dat.appendChild(document.createElement("br")) && dat.appendChild(document.createElement("br")) && dat.appendChild(document.createElement("button")), name = dat.getElementsByTagName("b")[0].textContent; button.className = "spu-search"; button.textContent = "Найти посты"; button.title = "Ctrl + ЛКМ: Добавить этого пользователя в задание для поиска\nЛКМ: Поиск постов для пользователя(-ей)/для выделенного\nПКМ: Показать форму для ввода имен пользователей"; button.onclick = button.oncontextmenu = e => listener.handleEvent(e, name, e.button == 2); } if (listener.options.searchOnProfileLinksByRMB) body.addEventListener("contextmenu", e => { const target = e.target.closest("a[href*='?action=show&member=']"), name = target && target.search.split("&member=")[1]; if (!target || !name || e.altKey || e.shiftKey || e.ctrlKey || e.metaKey || !!listener.getSel() || target.closest("#spu-spoiler-body")) return; listener.handleEvent(e, name) }); if (listener.isFF && listener.options.createCnMenu) { const context = body.getAttribute("contextmenu"), menu = context ? document.getElementById(context) : body.appendChild(document.createElement("menu")), mitem = menu.appendChild(document.createElement("menuitem")); if (!context) { menu.id = "GM_page-actions"; menu.type = "context"; body.setAttribute("contextmenu", "GM_page-actions"); }; mitem.label = "Найти собщения пользователя(-ей)"; mitem.onclick = e => listener.handleEvent(e, null, !listener.getSel()); }; });
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址