您需要先安装一个扩展,例如 篡改猴、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 3.1.4 // @date 13.08.2018 // @author Halibut // @namespace https://greasyfork.org/en/users/145947-halibut // @homepageURL https://greasyfork.org/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]), listener = { options: { // <--- ОПЦИИ СКРИПТА ---> showAlerts: false // Показывать алерты по окончании поиска , scrollToSearchResults: true // Автоматически прокручивать страницу к результатам поиска // (если showAlerts == true, то, при подтверждении, все-равно прокрутит к результатам) , hideSearchButton: false // Показывпть кнопку поиска только при наведении курсора на пост , autoOpenSpoilerWithResult: false // Раскрывать спойлер с результатами поиска автоматически , reversPostSorting: true // обратить сортировку по дате для найденных постов (от новых к старым) , headToResult: false // Включать шапку темы (если она создана выбранным пользоватем) в результаты поиска , createCnMenu: true // Добавить в контекстное меню пункт запускающий поиск (только для FF) , searchOnProfileLinksByRMB: true // Поиск при клике по ссылкам ведущим на профиль пользователя // (только если нет выделенного текста и не нажаты клавиши модификаторы) , fillSearchFormWithNames: true // Заполнять в диалоговом окне поиска по тексту поле именем(-ами) // Список имен которые можно будет выбрать из выпадающего меню в форме поиска ---> , namesToSearch: ['Name1', 'Name2', 'Name3', 'etc...'] } , names: [] , txt: '' , sort: null , ttlShow: '\u25BA Показать результаты поиска' , ttlHide: '\u25BC Скрыть результаты поиска' , ttlLdng: '\u23F3 Поиск...' , ttlNotFnd: '\u26A0 Постов не найдено!' , get name() { return this.name = this.getName() } , set name(str) { return this.setName(str) } , get text() { const text = this.txt; delete this.txt; return text; } , set text(str) { if (str) return this.txt = 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() || "" } , spawn(gen) { const continuer = (verb, arg) => { let result; try { result = generator[verb](arg); } catch (err) { return Promise.reject(err); } if (result.done) { return result.value; } else { return Promise.resolve(result.value).then(onFulfilled, onRejected); }; }, generator = gen(), onFulfilled = continuer.bind(continuer, 'next'), onRejected = continuer.bind(continuer, 'throw'); return onFulfilled(); } , prompt(name, txt) { return new Promise((res, rej) => { delete this.sort; body.appendChild(document.createElement('div')).outerHTML = html; const mdlOverlay = document.getElementById('spu-modal'), clsBtn = document.getElementById('spu-close'), regChkbx = document.getElementById('spu-regexp'), csChkbx = document.getElementById('spu-case'), sntChkbx = document.getElementById('spu-sentence'), flgsFrm = document.getElementById('spu-flags'), txtFrm = document.getElementById('spu-txtarea'), nmsFrm = document.getElementById('spu-names'), nmsBtn = document.getElementById('spu-names-list'), srchBtn = document.getElementById('spu-srch-strt'), fromOld= document.getElementById('spu-fromold'), fromNew= document.getElementById('spu-fromnew'), nmsMenu = document.getElementById('spu-nms-menu'); name && (nmsFrm.value = name); txt && (txtFrm.value = txt); txtFrm.focus(); for (const nm of this.options.namesToSearch) { const menuitem = nmsMenu.appendChild(document.createElement('li')); menuitem.textContent = nm; menuitem.onclick = () => nmsFrm.value += (nmsFrm.value ? ',' + nm : nm); } if (this.options.reversPostSorting) fromNew.checked = true; else fromOld.checked = true; txt && txt.startsWith('"') && txt.endsWith('"') && (sntChkbx.checked = true); for (const el of [...mdlOverlay.getElementsByClassName('clear-form')]) el && (el.onclick = () => el.nextElementSibling.value = ''); clsBtn.onclick = () => {mdlOverlay.remove(); body.onwheel = null; listener.names.length = 0; res(null)}; mdlOverlay.onclick = mdlOverlay.oncontextmenu = mdlOverlay.onwheel = e => { if (e.target != mdlOverlay) return; e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); }; body.onwheel = e => { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); }; nmsBtn.onclick = () => nmsMenu.hidden = !nmsMenu.hidden; sntChkbx.onclick = () => { let val = txtFrm.value.trim(), quoted = val && val.startsWith('"') && val.endsWith('"'); sntChkbx.checked ? !quoted && (val = '"' + val + '"') : quoted && (val = val.slice(val.indexOf('"') + 1, val.lastIndexOf('"'))); return txtFrm.value = val; } fromOld.onclick = fromNew.onclick = e => { this.sort = fromNew.checked ? true : false; } regChkbx.onclick = e => { flgsFrm.disabled = !regChkbx.checked; sntChkbx.disabled = csChkbx.disabled = regChkbx.checked; !regChkbx.checked && (flgsFrm.value = ''); } srchBtn.onclick = () => { const val = {n: nmsFrm.value, t: txtFrm.value, rgxp: regChkbx.checked, flags: flgsFrm.value, cs: csChkbx.checked}; body.onwheel = null; mdlOverlay.remove(); res(val); } }) } , getPosts([url, page], name, txt) { return new Promise((res, rej) => { let posts; if (url == this.loc) { posts = document.getElementsByClassName('tb'); if (posts && !!posts.length) { posts = this.filterPosts(posts, name, txt, 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, txt, 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).filter(post => !!post); if (posts && !!posts.length) { if (typeof this.sort == "boolean") this.sort && (posts = posts.reverse()); else if (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, txt, page) { return [...posts].filter(post => { const isUser = name && name.includes(post.querySelector("td.dats b").textContent.toLowerCase().replace(/\s/g, '_')), chkHead = this.options.headToResult && page == 1 || !post.querySelector('a.tpc[href$="&postno=1"]'), isText = () => { let pstEl = post.getElementsByClassName('post')[0], pstTxt = pstEl.textContent, txtToSearch = txt.val; if (!(pstTxt && !!pstTxt.length)) return false; if (txt.type != 'rgxp') { pstTxt = pstTxt.replace(/\s+/g, ' '); txtToSearch = txtToSearch.map(sntnc => sntnc.replace(/\s+/g, ' ')); if (txt.cx) { pstTxt = pstTxt.toLowerCase(); txtToSearch = txtToSearch.map(sntnc => sntnc.toLowerCase()) } }; switch (txt.type) { case 'all': { return txtToSearch.every(sntnc => pstTxt.indexOf(sntnc) != -1) }; break; case 'any': { return txtToSearch.some(sntnc => pstTxt.indexOf(sntnc) != -1) }; break; case 'rgxp': { return txtToSearch.test(pstTxt) }; break; case 'snt': { return pstTxt.indexOf(txtToSearch) != -1 }; break; case 'some': { return txtToSearch.some(sntnc => pstTxt.indexOf(sntnc) != -1) }; break; } }; if (name) { if (chkHead && isUser) { return txt ? isText() : true } } else { return chkHead && isText() } }); } , 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 = [...new Set(this.flatPosts(this.names))].map(nm => nm && nm.replace(/(?:\s+)?,(?:\s+)?/).replace(/\s/g, "_").toLowerCase()).filter(nm => !!nm); if (name && !!name.length) return name } , setName(str) { if (str) return this.names.push(str); } , getSearchQuery(str, cs) { const query = {type: null, val: null, cs: cs}; if (Array.isArray(str)){ query.type = 'rgxp'; try {query.val = new RegExp(str[0], str[1])} catch(err) {listener.names.length = 0; return this.win.alert(err)} return query } if (str.includes('OR')){ query.type = 'some'; query.val = str.split(/(?:\s+)?OR(?:\s+)?/); return query } if (str.includes('AND')){ query.type = 'all'; query.val = str.split(/(?:\s+)?AND(?:\s+)?/); return query } if (str.startsWith('"') && str.endsWith('"')) { query.type = 'snt'; query.val = [str.slice(str.indexOf('"') + 1, str.lastIndexOf('"'))]; return query } else { query.type = 'any'; query.val = str.trim().split(/\s+/) return query } return null } , getPages() { const paginator = [...document.getElementsByTagName("p")].find(el => el.textContent && el.textContent.startsWith("Страницы: ")); if (paginator) return [...paginator.getElementsByTagName("td")[0].children].filter(el => !el.title).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(); let cs, txt, sel = listener.getSel(); // spawn function by Jake Archibald https://gist.github.com/jakearchibald/31b89cba627924972ad6 this.spawn(function*() { if (sel && !prmpt && !e.ctrlKey) { const confirm = listener.win.prompt('На странице был выделен текст.\nЗапустить поиск с именем пользователя из выделенного текста (нажать "Да"),\nили по тексту, с открытием диалога для редактирования (нажать "Отмена")?', sel); confirm ? (name = confirm) : (prmpt = true); } if (name && !prmpt) { listener.name = name; if (e.ctrlKey) return; } if (prmpt) { listener.name = name; sel && (txt = sel); const rVal = yield listener.prompt(listener.options.fillSearchFormWithNames && listener.name, txt); listener.names.length = 0; if (!rVal) return; cs = rVal.cs; listener.name = rVal.n; listener.text = rVal.rgxp ? [rVal.t, rVal.flags] : rVal.t; } const nmsToSearch = listener.name, txtToSearch = listener.text, isNames = nmsToSearch && !!nmsToSearch.length, isTexxt = txtToSearch && !!txtToSearch.length, txtQuery = isTexxt && listener.getSearchQuery(txtToSearch, cs); if (!isNames && !isTexxt || isTexxt && !txtQuery) return; const pageLinks = listener.getPages(), spoilerHead = listener.spHd, spoilerBody = listener.spBd, spoilerTitle = listener.spTTl, errsLbl = document.getElementById("spu-errs"), findedLbl = document.getElementById("spu-fndd"); spoilerHead.hidden = false; spoilerTitle.textContent = listener.ttlLdng; spoilerHead.setAttribute("notready", "true"); spoilerBody.hidden = true; listener.options.scrollToSearchResults && !listener.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 listener.getPosts(link, isNames && nmsToSearch, isTexxt && txtQuery).catch(err => { errorsCntr += 1; errsLbl.textContent = errorsCntr }) })).then( posts => { return listener.procesPosts(posts) } ).then( founded => { findedLbl.textContent = founded; spoilerTitle.textContent = listener.ttlShow; spoilerHead.removeAttribute("notready"); if (listener.options.showAlerts) listener.endNotify(founded, errorsCntr); else if (listener.options.autoOpenSpoilerWithResult) { spoilerBody.hidden = false spoilerTitle.textContent = listener.ttlHide; }; return } ).catch(err => { if (err == "not found") { spoilerTitle.textContent = listener.ttlNotFnd; listener.options.showAlerts && listener.endNotify(null, errorsCntr, notfound); return } errorsCntr += 1; errsLbl.textContent = errorsCntr }); listener.names.length = 0; }); } }, prmptTxt = 'На странице был выделен текст.\nЗапустить поиск с именем пользователя из выделенного текста (нажать "Да"),\nили по тексту, с открытием диалога для редактирования (нажать "Отмена")?', hlpNms = 'Чтобы искать посты для всех пользователей, по тексту, - оставьте поле имени пустым.\nИмена в форму поиска вводить без учета регистра, разделяя запятой (без пробела).\nИмена с пробелами - ищутся и с пробелом и с _.', hlpTxt = [ 'Чтобы искать только посты по именам пользователей - оставьте поле текста пустым.', '', 'Регулярные выражения вводить включив чекбокс.', 'Без начального и закрывающего слеша.', 'Для ввода флагов - отдельное поле,', 'Регулярки не проверяются на валидность.', '', 'Поиск без регулярок:', '\tраз два три - искать любое из слов', '\tраз два OR три OR пять - искать любую из фраз: "раз два", "три", "пять"', '\tраз два AND три AND пять - искать все фразы', '\t"раз два три" - (в двойных кавычках) искать фразу целиком', 'Комбинировать операторы пока нельзя.', '', 'Поиск с учетом регистра по умолчанию. Для поиска без учета - включить чекбокс.', 'При поиске без регулярок все пробелы, переносы, табуляции - заменяются на единичный пробел,', 'как в задании для поиска, так и в тексте постов.', 'Слово "поле" - найдется и в "Наполеон".', ].join('\n'), clsImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDoAABSCAABFVgAADqXAAAXb9daH5AAAAEhSURBVHja1FMxS8NgEH1XxCUuri24VKmLY6qDPyDoIF0k0Dmj4GBoQZBWBLEVOnaI0LEiXTIo/gAHO7sIOjm4SsEu4nfPJQGNIRk6iA/ecI/jeHePE5KYBQXMiL8fMJcUVja2VwG4ALrP45spACyvb1kAfACXT/fXj5kOSHVJBal+uepY5apjkepHmpu7wklj74JGEdGPCBrF6eF+kOyXlBjlKrwtNo7PvYKIAoCShbOjg2B3x3kFwEwHIsJefzBR84nv7PUHExFhroOltc34YGnovjzcTTMdqDG+GgM1Bp12M+i0m0FcqzG/B5P8wVrds4sVuzUchSWSQlKGo7BUrNitWt2zk/1pR5wHsADgLd6ZpABYBPAO4CMvhX/2C18DAHuyrpoNc5ujAAAAAElFTkSuQmCC', questionMark = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAn1BMVEUAAAAAbfMAbfEAbe8AbfAAbfAAbfEAbu8AcO8AAP8Abu8AbfAAbfAAbfEAgP8AbPAAbfAAbPIAa/IAbvAAbfAAbPEAbe0AcO8AbPAAbfAAceMAbfAAbfAAbfAAbPAAbfAAbfAAZv8AafAAbfEAavQAVf8AbPEAcfEAbf8AbfAAbfAAbe8Abe8AbfAAbfAAbfAAa/IAbfAAbfAAbfAAAADuFkhRAAAAM3RSTlMAKn606eKxgCABcvj0bgK19ztMl+1cDhA0+gnw4fnI09sFEcMYA6ASB77xcJOvzc4T8kSdjffTAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+IIDBMlMtO6eB4AAAChSURBVBjTTY/pDoMgEIQHAVHE2lNr7/uyt+//bl3Ypun8YL5dks0MQBKRVDo2CVipzdogl3f83Cnan4qUFjlB1/T6gyGBBRJHPkJZYUyQCRiyelJOXYUZYYSY3vli2a7Wm5pQQvO57W5/8K6geHE8nYNryOCX5sofMSKG253dQISYDzw5LMW3Hl7vJixyX+U/OpfJHY+ZTb99ExNrJSPh+QOxnx6dvxBTegAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0wOC0xMlQxOTozNzo1MCswMjowMEnQ2mMAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMDgtMTJUMTk6Mzc6NTArMDI6MDA4jWLfAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAABJRU5ErkJggg==', html = [ '<div id="spu-modal">', ' <div>', ' <button class="spu" id="spu-close" title="Закрыть">X</button><br>', ' <fieldset>', ' <legend>Сортировать найденное</legend>', ' <label for="spu-fromnew">От новых к старым</label>', ' <input id="spu-fromnew" name="sort" type="radio">', ' <label for="spu-fromold">От старых к новым</label>', ' <input id="spu-fromold" name="sort" type="radio">', ' </fieldset>', ' <fieldset>', ' <legend>Введите имя(-ена)', ' <img src="' + questionMark + '" title="' + hlpNms + '">', ' </legend>', ' <li>', ' <button class="spu" id="spu-names-list" title="">Добавить имена</button>', ' <div>', ' <ul id="spu-nms-menu" hidden="true">', ' </ul>', ' </div>', ' </li>', ' <img class="spu clear-form" src="' + clsImg + '" title="Очистить форму">', ' <input id="spu-names">', ' </fieldset>', ' <fieldset id="spu-col">', ' <legend>Введите текст', ' <img src="' + questionMark + '" title="' + hlpTxt + '">', ' </legend>', ' <fieldset>', ' <legend>Опции поиска</legend> ', ' <input id="spu-sentence" type="checkbox">', ' <label for="spu-sentence">Фразу целиком</label>', ' <input id="spu-case" type="checkbox">', ' <label for="spu-case">Без учета регистра</label>', ' <input id="spu-regexp" type="checkbox">', ' <label for="spu-regexp">RegExp</label>', ' <label for="spu-flags">Флаги: </label>', ' <input id="spu-flags" size="6" disabled="" type="text">', ' </fieldset>', ' <div>', ' <img class="spu clear-form" src="' + clsImg + '" title="Очистить форму">', ' <textarea id="spu-txtarea"></textarea>', ' </div>', ' </fieldset><br>', ' <div></div>', ' <div id="spu-sticky">', ' <button id="spu-srch-strt" class="spu">Начать поиск</button>', ' </div>', ' </div>', '</div>' ].join('\n'), 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.spu' + (listener.options.hideSearchButton ? ', .tb:not(:hover) button.spu' : '') + '{', ' visibility: hidden !important;', '}', '.spu {', ' 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;', '}', '.spu:hover {', ' background: rgb(235,235,235) !important;', '}', '.spu:active {', ' background: rgb(225,225,225) !important;', '}', '#spu-modal {', ' position: fixed !important;', ' top: 0 !important;', ' right: 0 !important;', ' bottom: 0 !important;', ' left: 0 !important;', ' background: rgba(0,0,0,0.8) !important;', ' z-index: 2147483647 !important;', '}', '#spu-modal > div {', ' position: relative !important;', ' width: 45vw;', ' max-height: 80vh !important;', ' display: flex !important;', ' flex-flow: column !important;', ' margin: 10vh auto !important;', ' padding: 20px !important;', ' border-radius: 3px !important;', ' background: rgb(251, 251, 251) !important;', ' resize: both !important;', ' overflow: auto !important;', '}', '#spu-modal fieldset,', '#spu-modal fieldset div {', ' display: flex !important;', ' position: relative !important;', ' flex-flow: column !important;', ' font-weight: 600 !important;', '}', '#spu-modal legend img {', ' cursor: help !important;', ' padding: 0 5px !important;', ' vertical-align: bottom !important;', '}', '#spu-modal .clear-form {', ' position: absolute !important;', ' padding: 0 !important;', ' border-radius: 100% !important;', '}', '#spu-modal fieldset > .clear-form {', ' top: -5px !important;', ' right: 0 !important;', '}', '#spu-modal div > .clear-form {', ' top: 0 !important;', ' right: -7px !important;', '}', '#spu-modal fieldset:not([id]) {', ' display: flex;', ' flex-flow: wrap !important;', ' align-items: center !important;', ' justify-content: space-evenly !important;', '}', '#spu-modal fieldset:nth-of-type(3),', '#spu-modal fieldset > div,', '#spu-modal input:not([type]) {', ' flex-grow: 1 !important;', '}', '#spu-modal label {', ' font-weight: 400 !important;', '}', '#spu-modal input:not([type]),', '#spu-modal #spu-names-list {', ' height: 2.5em !important;', '}', '#spu-modal textarea {', ' resize: none !important;', ' flex-basis: 30vh !important;', ' flex-grow: 1 !important;', ' margin: 10px 2px 0 !important;', '}', '#spu-modal button {', ' font-weight: 600 !important;', '}', '#spu-modal #spu-close {', ' position: absolute !important;', ' top: 0 !important;', ' right: 0 !important;', ' padding: 0 15px !important;', '}', '#spu-modal #spu-srch-strt {', ' padding: 5px 0 !important;', ' flex-grow: 1 !important;', '}', '#spu-modal div:empty {', ' min-height: 20px;', '}', '#spu-modal #spu-sticky {', ' display: flex !important;', ' position: sticky !important;', ' bottom: -20px;', '}', '#spu-modal fieldset > li {', ' display: inline-block !important;', ' position: relative !important;', '}', '#spu-modal #spu-nms-menu li:not(:last-child) {', ' border-bottom: solid .5px lightgrey !important;', '}', '#spu-modal #spu-nms-menu li {', ' padding: .25em !important;', ' padding-left: 1em !important;', ' cursor: default !important;', ' text-align: start !important;', ' font-weight: 400 !important;', '}', '#spu-modal #spu-nms-menu li:hover {', ' color: #fff !important;', ' background: linear-gradient(to bottom, #6f81f5, #3f51f2) repeat-x !important;', '}', '#spu-modal li {', ' list-style-type: none !important;', '}', '#spu-modal li > div {', ' position: absolute !important;', ' top: 100% !important;', ' left: 0 !important;', ' right: 0 !important;', ' z-index: 999', '}', '#spu-modal #spu-nms-menu {', ' margin-top: 0 !important;', ' padding: 0 !important;', ' background: #fff !important;', ' border: 1px solid rgba(66,78,90,0.2) !important;', '}', '@media screen and (-webkit-min-device-pixel-ratio:0) {', ' #spu-modal fieldset:not([id]) {', ' display: inline !important;', ' text-align: center !important;', ' }', ' #spu-modal input:not([type]) {', ' width: calc(100% - 121px) !important;', ' }', ' #spu-modal fieldset > .clear-form {', ' top: 8px !important;', ' right: 2px !important;', ' }', ' #spu-modal #spu-sticky {', ' bottom: 0px !important;', ' }', ' #spu-modal div:empty {', ' min-height: 0 !important;', ' }', ' #spu-modal #spu-srch-strt {', ' height: max-content !important;', ' }', '}' ].join('\n'); style.type = "text/css"; 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"; button.textContent = "Найти посты"; button.title = "Ctrl + ЛКМ: Добавить этого пользователя в задание для поиска\nЛКМ:\n\tПоиск постов для пользователя(-ей)\n\tПри наличии выделенного текста - поиск по тексту и/или по имени\n\tс диалогом выбора и редактирования\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()); }; });