您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Улучшение интерфейса
当前为
// ==UserScript== // @name Pikabu UI++ // @namespace pikabuUIPlusPlus // @version 1.4 // @description Улучшение интерфейса // @author Array // @license CC-BY-SA-4.0 // @match *://pikabu.ru/* // @grant unsafeWindow // @grant window.close // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== // simbols source http://myhomeinet.ru/smilegenerator/page-274.html // colors source https://www.w3schools.com/colors/colors_names.asp // special thanks: // @nazarpunk // @moretraher2020 (function() { `use strict`; const DATA_LIFETIME = 604800000; const DATABASE = `db`; const DATABASE_VERSION = `1`; const EXP_VALUES = [3, 5, 8]; const EXP_ICO = [`❊`, `•`, `︿`, `︽`, `⁂`, `★`]; const NOTE_VALUES = [`#добро`, `#интересно`, `#осторожно`, `#неприемлемо`], NOTE_ICO = [`❤`, `♞`, `⚠`, `✖`], NOTE_COLORS = [`LimeGreen`, `DodgerBlue`, `OrangeRed`, `Violet`]; const SUBS_VALUES = [40, 900, 4000, 9000], SUBS_ICO = [``, `◔`, `◑`, `◕`, `◉`]; const BAN_ICO = [``, `ϟ`, `†`]; const GENDER_ICO = [``, `♂`, `♀`]; // ************************ ENTRY POINT ************************* const SHOW_EXP = GM_getValue(`SHOW_EXP`, 1); const SHOW_NOTE = GM_getValue(`SHOW_NOTE`, 1); const SHOW_RATE = GM_getValue(`SHOW_RATE`, 1); const SHOW_SUBS = GM_getValue(`SHOW_SUBS`, 1); const SHOW_BAN = GM_getValue(`SHOW_BAN`, 1); const SHOW_GENDER = GM_getValue(`SHOW_GENDER`, 0); const SHOW_QUICK_NOTE = GM_getValue(`SHOW_QUICK_NOTE`, 1); const AUTOBAN = GM_getValue(`AUTOBAN`, 0); var database = new Map(); var loadingComments = new Map(); var loadingOrder = []; var updateOrder = []; var intersectionOrder = new Set(); var loadingComment = null; var enableLoadingNavigator = false; var loadingNavigator; var userpageRendered = false; // Intersections const intersector = new IntersectionObserver( entries => { for (const entry of entries) { if (entry.isIntersecting) { for (const userName of loadingOrder) { if(entry.target.dataset.name == userName) { intersectionOrder.add(userName); break; } } for (const userName of updateOrder) { if(entry.target.dataset.name == userName) { intersectionOrder.add(userName); break; } } } else { intersectionOrder.delete(entry.target.dataset.name); } } }, { threshold: 0 }); addCustomCSS(); renderNavigatorLoading(); loadDatabase(); findComments(); findUsernames(); checkUserPage(); checkSettingsPage(); // Ajax listener !function(send) { XMLHttpRequest.prototype.send = function(body) { send.call(this, body); if(body?.includes(`note`)) { checkUserPage(); } }; }(XMLHttpRequest.prototype.send); // Mutation listener var mutationObserverTimeout = false; new MutationObserver(mutations => { for (const mutation of mutations) { if(mutationObserverTimeout) break; for (const node of mutation.addedNodes) { if (!(node instanceof HTMLElement)) continue; if(mutationObserverTimeout) break; if (node.classList.contains(`comment`) || node.classList.contains(`story`)) { findComments(); findUsernames(); mutationObserverTimeout = true; setTimeout(() => {mutationObserverTimeout = false}, 200); break; } } } }).observe(document.body, {childList: true, subtree: true}); window.addEventListener('focus', function() { console.log('focused'); }); // ************************ DATABASE ************************* function loadDatabase() { let jobject = JSON.parse(GM_getValue(DATABASE, `{}`)); database = new Map(Object.entries(jobject)); let ver = GM_getValue(`version`, ``); if(ver != DATABASE_VERSION) { GM_setValue(`version`, DATABASE_VERSION); database = new Map(); } } function saveDatabase() { let json = JSON.stringify(Object.fromEntries(database.entries())); GM_setValue(DATABASE, json); } // ************************ BASEMENT ************************* function checkUserPage() { let url = window.location.href; let key = url.split(`@`)[1]; if(url.includes(`@`) && !userpageRendered) { userpageRendered = true; renderUserpageTools(); } if(database.has(key)) { database.get(key).timestamp = 0; saveDatabase(); findUsernames(key); } } function checkSettingsPage() { let url = window.location.href; if(url.includes(`settings`)) renderSettings(); } function findComments() { if(!SHOW_QUICK_NOTE) return; document.querySelectorAll(`.comment`).forEach((comment) => { let meta = comment.getAttribute(`data-meta`); if(!comment.hasAttribute(`data-quicknote`) && (meta != null) && !meta.includes(`ua`)) { comment.setAttribute(`data-quicknote`, 1); let uid = smartSlice(meta, `aid=`, `,`); let tools = comment.querySelector(`.comment__tools`); renderCommentTools(tools, uid); } }); } function findUsernames(requestedUser) { // comemet usernames document.querySelectorAll(`.comment__user`).forEach((commentBase) => { let comment = commentBase.querySelector(`.user__nick`); let userName = commentBase.getAttribute(`data-name`); let checkRequest = requestedUser != undefined && requestedUser == userName; // reg intersec events for new item if(comment?.textContent == userName) { intersector.observe(commentBase); } if(comment?.textContent == userName || checkRequest) { if(checkRequest) intersectionOrder.add(userName); addComment(comment, userName); } }); //post usernames document.querySelectorAll(`.story__user-link`).forEach((post) => { let userName = post.getAttribute(`data-name`); let checkRequest = requestedUser != undefined && requestedUser == userName; // reg intersec events for new item if(post?.textContent.trim() == userName) { intersector.observe(post); } if(post?.textContent.trim() == userName || checkRequest) { addComment(post, userName); } }); if(loadingComment == null) { nextLoading(); } } function addComment(comment, userName) { if(database.has(userName)) { let date = new Date(); let data = database.get(userName); renderUsername(userName, comment, data); // update data if(date.getTime() > (data.timestamp + DATA_LIFETIME)) { if(loadingComments.has(userName)) { loadingComments.get(userName).push(comment); } else { loadingComments.set(userName, [comment]); updateOrder.push(userName); } } } else { //request data if(loadingComments.has(userName)) { loadingComments.get(userName).push(comment); } else { loadingComments.set(userName, [comment]); loadingOrder.push(userName); nextLoading(); } } renderLoadingOrder(); } // ************************ LOADING ************************* function nextLoading() { if(loadingComment == null && intersectionOrder.size > 0) { while (intersectionOrder.size > 0) { let forcedUsername = intersectionOrder.values().next().value; intersectionOrder.delete(forcedUsername); if(loadingOrder.includes(forcedUsername)) { loadingOrder.splice(loadingOrder.indexOf(forcedUsername), 1); loadingComment = forcedUsername; loadData(loadingComment); break; } if(updateOrder.includes(forcedUsername)) { updateOrder.splice(updateOrder.indexOf(forcedUsername), 1); loadingComment = forcedUsername; loadData(loadingComment); break; } } // if all intersections check failed if(loadingComment == null) { nextLoading(); return; } } else if(loadingComment == null && loadingOrder.length > 0) { loadingComment = loadingOrder.shift(); loadData(loadingComment); } else if(loadingComment == null && updateOrder.length > 0) { // update expired data loadingComment = updateOrder.shift(); loadData(loadingComment); } renderLoadingOrder(); } function loadData(userName) { const body = new FormData(); body.set(`action`, `get_short_profile`); body.set(`user_name`, userName); fetch(`/ajax/user_info.php`, { method: `post`, body : body }) .then(r => r.json()) .then(result => { let data = parseData(result.data.html); database.set(userName, data); saveDatabase(); let comments = loadingComments.get(userName); loadingComments.delete(userName); for (let comment of comments) renderUsername(userName, comment, data); loadingComment = null; setTimeout(() => {nextLoading(); renderLoadingOrder();}, 100 + 400 * Math.random()); }); } // ************************ EVENTS ************************* var clickTimeout = false; function clickUserNote(e) { if(clickTimeout) return; clickTimeout = true; let note = e.target.getAttribute(`data-note`); let uid = e.target.getAttribute(`data-uid`); let url = window.location.href; let userName = url.split(`@`)[1]; let data = database.get(userName); let message = ``; let mtype = `-`; if(data.note != (parseInt(note)+1)) { message = NOTE_VALUES[note]; mtype = `+`; } let textarea = document.querySelector(`.page-profile`).querySelector(`.profile-note__textarea`).value = message; let textdiv = document.querySelector(`.page-profile`).querySelector(`.profile-note__text`).textContent = message; const body = new FormData(); body.set(`action`, `note`+mtype); body.set(`id`, uid); body.set(`message`, message); fetch(`/ajax/users_actions.php`, { method: `post`, body : body }) .then(result => { data.timestamp = 0; findUsernames(userName); clickTimeout = false; checkAutoban(uid, (parseInt(note) == 3)); }); } function clickQuicknote(e) { if(clickTimeout) return; let note = e.target.getAttribute(`data-note`); let uid = e.target.getAttribute(`data-uid`); let comment = e.target?.parentElement?.parentElement?.querySelector(`.comment__user`); let userName = comment?.getAttribute(`data-name`); if(!database.has(userName)) return; clickTimeout = true; let refTool = e.target.parentElement?.querySelector(`a`); let ref = refTool?.getAttribute(`href`); let data = database.get(userName); let message = ``; let mtype = `-`; if(data.note != (parseInt(note)+1)) { message = NOTE_VALUES[note]+` `+ref; mtype = `+`; } const body = new FormData(); body.set(`action`, `note`+mtype); body.set(`id`, uid); body.set(`message`, message); fetch(`/ajax/users_actions.php`, { method: `post`, body : body }) .then(result => { data.timestamp = 0; findUsernames(userName); clickTimeout = false; checkAutoban(uid, (parseInt(note) == 3)); }); } function checkAutoban(uid, isBan) { if(!AUTOBAN) return; const body = new FormData(); body.set(`action`, isBan ? `ignore_in_comments` : `unignore_in_comments`); body.set(`id`, uid); fetch(`/ajax/ignore_actions.php`, { method: `post`, body : body }); } // ************************ PARSING ************************* function smartSlice(text, start, end) { let strIndex = text.indexOf(start); let endIndex = text.indexOf(end, strIndex); return text.slice(strIndex+start.length, endIndex); } function parseData(html) { let data = new Object(); let regions = html.split(`information`); // ban let banStat = 0; if(regions[0].includes(`ban-status`)) { banStat = 1; if(regions[0].includes(`навсегда`)) banStat = 2; } // note let noteStat = 0; if(regions[1].includes(`profile__note`)) { let subRegions = regions[1].split(`profile__note-inner`); regions[1] = subRegions[0]; for (let i = 0; i < NOTE_VALUES.length; i++) { if(subRegions[1].includes(NOTE_VALUES[i])) { noteStat = i + 1; } } } // gender let genderStat = 0; if(regions[1].includes(`шник`)) genderStat = 1; if(regions[1].includes(`шница`)) genderStat = 2; //exp let expStat = 0; let expSource = smartSlice(regions[1], `<span>`, `</div>`); let y = expSource.includes(`лет`) || expSource.includes(`год`); let m = expSource.includes(`месяц`); if(y || m) { if(y) { let years = parseInt(expSource); expStat = 2 + EXP_VALUES.length; for (let i = EXP_VALUES.length - 1; i >= 0; i--) { if(years < EXP_VALUES[i]) { expStat = 2 + i; } } } else { expStat = 1; } } let digitalRegions = regions[1].split(`profile__digital`); //rate let rateStat = 0; let rateRaw = smartSlice(digitalRegions[1], `<b>`, `</b>`); if(rateRaw.includes(`К`)) { rateStat = rateRaw.replace(`-`, `▽`); } else { rateStat = (Math.round(rateRaw/1000) + `K`).replace(`-`, `▽`); } // subs let subsStat = 0; let rawSubs = smartSlice(digitalRegions[3], `<b>`, `</b>`); if(rawSubs.includes(`К`)) { subsStat = 4; } else if(rawSubs > SUBS_VALUES[0]) { subsStat = SUBS_VALUES.length; for (let i = SUBS_VALUES.length - 1; i > 0 ; i--) { if(rawSubs < SUBS_VALUES[i]) { subsStat = i; } } } // timestamp let date = new Date(); data.timestamp = date.getTime(); data.exp = expStat; data.note = noteStat; data.rate = rateStat; data.subs = subsStat; data.ban = banStat; data.gender = genderStat; return data; } // ************************ CSS ************************* function addCustomCSS() { var styles = ``; for (let i = 0; i < NOTE_COLORS.length; i++) { styles += `.`+NOTE_COLORS[i]+`_note {background-color: `+NOTE_COLORS[i]+`;}`; } styles += `.navigator__forced-on {opacity: 1 !important; visibility: visible !important;}`; styles += `.navigator__forced-off {opacity: 0 !important; visibility: hidden !important; max-width: 1px !important;}`; styles += `.navigator-loading-info {background-color: CornflowerBlue}`; styles += `.navigator-update-info {background-color: Gainsboro !important}`; styles += `.userpage-note-tools {margin-left: 15px !important; margin-top: 4px !important;}`; styles += `.userpage-note-tool {font-size: 18px !important; padding: 5px; padding-left: 8px; padding-right: 8px;}`; var styleSheet = document.createElement(`style`); styleSheet.type = `text/css`; styleSheet.innerText = styles; document.head.appendChild(styleSheet); } // ************************ RENDERING ************************* function renderUsername(userName, comment, data) { if(comment == null) return; let exp = ``; if(SHOW_EXP) { exp = EXP_ICO[data.exp] + ` `; } let note = ``; if(SHOW_NOTE && data.note > 0) { note = NOTE_ICO[data.note - 1] + ` `; let noteEl = comment?.parentElement?.parentElement?.querySelector(`.avatar__note`); if(noteEl == null || noteEl == undefined) { let avatar = comment?.parentElement?.parentElement?.querySelector(`.avatar`); noteEl = document.createElement(`span`); noteEl.classList.add(`avatar__note`); avatar.appendChild(noteEl); } // remove prev for (let i = 0; i < NOTE_COLORS.length; i++) { noteEl.classList.toggle(NOTE_COLORS[i]+`_note`, false); } noteEl.classList.add(NOTE_COLORS[data.note - 1]+`_note`); } if(SHOW_NOTE && data.note == 0) { let noteEl = comment?.parentElement?.parentElement?.querySelector(`.avatar__note`); if(noteEl != null && noteEl != undefined && noteEl.classList.length > 1) { noteEl.remove(); } } let rate = ``; if(SHOW_RATE) { rate = data.rate + ` `; } let subs = ``; if(SHOW_SUBS) { subs = SUBS_ICO[data.subs] + ` `; } let ban = ``; if(SHOW_BAN && data.ban > 0) { ban = ` `+BAN_ICO[data.ban]; } let gender = ``; if(SHOW_GENDER && data.gender > 0) { gender = ` `+GENDER_ICO[data.gender]; } if(comment.childNodes.length > 1) { comment.childNodes[2].textContent = exp + note + rate + subs + userName + ban + gender; } else { comment.textContent = exp + note + rate + subs + userName + ban + gender; } } function renderCommentTools(tools, uid) { if(!SHOW_QUICK_NOTE) return; for (let i = 0; i < NOTE_VALUES.length; i++) { let tool = document.createElement(`div`); tool.classList.add(`comment__tool`); tool.classList.add(`hint`); tool.setAttribute(`aria-label`, `Отметить как `+NOTE_VALUES[i]); tool.setAttribute(`data-note`, i); tool.setAttribute(`data-uid`, uid); tool.textContent = NOTE_ICO[i]; tool.addEventListener(`click`, clickQuicknote); tools.appendChild(tool); } } function renderUserpageTools() { if(!SHOW_QUICK_NOTE) return; let uid = document.querySelector(`.page-profile`).querySelector(`.section-group`).getAttribute(`data-user-id`); let root = document.querySelector(`.main__inner`); let panel = document.querySelector(`.feed-panel`); let tools = document.createElement(`div`); tools.classList.add(`comment__tools`); tools.classList.add(`navigator__forced-on`); tools.classList.add(`userpage-note-tools`); root.insertBefore(tools, panel); for (let i = 0; i < NOTE_VALUES.length; i++) { let tool = document.createElement(`div`); tool.classList.add(`comment__tool`); tool.classList.add(`hint`); tool.classList.add(`userpage-note-tool`); tool.setAttribute(`aria-label`, `Отметить как `+NOTE_VALUES[i]); tool.setAttribute(`data-note`, i); tool.setAttribute(`data-uid`, uid); tool.textContent = NOTE_ICO[i]; tool.addEventListener(`click`, clickUserNote); tools.appendChild(tool); } } function renderNavigatorLoading() { let navParent = document.querySelector(`.comments-navigator__scroll`); if(navParent == null) { setTimeout(() => renderNavigatorLoading(), 100); return; } let refresh = navParent.querySelector(`.comments-navigator__refresh`); let navBase = document.createElement(`div`); navBase.classList.add(`comments-navigator__controls`); navBase.classList.add(`navigator__forced-off`); let navContent = document.createElement(`div`); navContent.classList.add(`comments-navigator__count`); navContent.classList.add(`navigator__forced-off`); navContent.classList.add(`navigator-loading-info`); navContent.setAttribute(`title`, `Количество загружаемых комментариев`); navContent.textContent = `0`; navBase.appendChild(navContent); navParent?.insertBefore(navBase, refresh); loadingNavigator = navContent; renderLoadingOrder(); } function renderLoadingOrder() { if(loadingNavigator == null) { return; } if(loadingOrder.length > 0 || updateOrder.length > 0 || (loadingComment != null)) { if(!enableLoadingNavigator) { loadingNavigator.classList.add(`navigator__forced-on`); loadingNavigator.classList.remove(`navigator__forced-off`); loadingNavigator.parentElement.classList.add(`navigator__forced-on`); loadingNavigator.parentElement.classList.remove(`navigator__forced-off`); enableLoadingNavigator = true; } if(loadingOrder.length > 0 || updateOrder.length > 0) { loadingNavigator.classList.toggle(`navigator-update-info`, (loadingOrder.length == 0)); } loadingNavigator.textContent = loadingOrder.length + updateOrder.length + (loadingComment != null); } else { if(enableLoadingNavigator) { loadingNavigator.classList.remove(`navigator__forced-on`); loadingNavigator.classList.add(`navigator__forced-off`); loadingNavigator.parentElement.classList.remove(`navigator__forced-on`); loadingNavigator.parentElement.classList.add(`navigator__forced-off`); enableLoadingNavigator = false; } } } // ************************ SETTINGS ************************* function renderSettings() { var enableUISection = false; let header = document.querySelector(`.feed-panel`).querySelector(`.menu`); let items = []; header.querySelectorAll(`.menu__item`).forEach(item => { items.push(item); item.addEventListener(`click`, (e) => { if(enableUISection) { settingItem.classList.toggle(`menu__item_current`, false); settings?.remove(); if(settingsOld != null) { settingsContainer.appendChild(settingsOld); setTimeout(() => e.target.classList.toggle(`menu__item_current`, true), 100); } enableUISection= false; } }); }); var settingsContainer = document.querySelector(`.settings`); var settings; var settingsOld; let settingItem = document.createElement(`a`); settingItem.classList.add(`menu__item`); settingItem.classList.add(`menu__item_route`); settingItem.textContent = `UI++`; header.appendChild(settingItem); settingItem.addEventListener(`click`, () => { enableUISection = true; items.forEach(item => {item.classList.toggle(`menu__item_current`, false);}); settingItem.classList.toggle(`menu__item_current`, true); settingsOld = settingsContainer.querySelector(`.settings-main`) || settingsContainer.querySelector(`.settings-security`) || settingsContainer.querySelector(`.settings-save`) || settingsContainer.querySelector(`.settings-notifications`); settingsOld?.remove(); settings = document.createElement(`div`); settings.classList.add(`settings-main`); settingsContainer.appendChild(settings); let sectionGroup = document.createElement(`div`); sectionGroup.classList.add(`section-group`); settings.appendChild(sectionGroup); let sectionHeader = document.createElement(`section`); sectionHeader.classList.add(`section_gray`); sectionGroup.appendChild(sectionHeader); let h = document.createElement(`h4`); h.textContent = `Настройки сторонего скрипта Pikabu UI++`; sectionHeader.appendChild(h); let sectionBody = document.createElement(`section`); //sectionBody.classList.add(`section`); sectionBody.classList.add(`section_padding_none`); sectionGroup.appendChild(sectionBody); let options = document.createElement(`div`); options.classList.add(`settings-main__options`); sectionBody.appendChild(options); const addLine = tittle => { let line = document.createElement(`h4`); line.classList.add(`settings-main__sub-header`); line.textContent = tittle; options.appendChild(line); }; const addCheckbox = (tittle, current, name, desc) => { let op = document.createElement(`div`); op.classList.add(`settings-main__option`); options.appendChild(op); let l = document.createElement(`label`); op.appendChild(l); let checkbox = document.createElement(`span`); checkbox.classList.add(`checkbox`); checkbox.classList.add(`checkbox_switch`); checkbox.classList.toggle(`checkbox_checked`, current); checkbox.setAttribute(`tabindex`, `0`); checkbox.setAttribute(`unselectable`, `on`); l.appendChild(checkbox); var test = false; checkbox.addEventListener(`click`, () => { let value = !GM_getValue(name, 1); GM_setValue(name, value); checkbox.classList.toggle(`checkbox_checked`, value); }); l.insertAdjacentHTML(`beforeend`, tittle); if(desc != undefined) l.insertAdjacentHTML(`beforeend`,`<i class="fa fa-question-circle hint" aria-label="`+desc+`"></i>`); }; addLine(`Дополнительная информация о пользователе`); addCheckbox(`Показывать маркер даты регистрации `, SHOW_EXP, `SHOW_EXP`, `❊ - Менее месяца<br>• - 1 год<br>︿ - Более 1 года<br>︽ - Более `+EXP_VALUES[0]+` лет<br>⁂ - Более `+EXP_VALUES[1]+` лет<br>★ - Более `+EXP_VALUES[2]+` лет`); addCheckbox(`Показывать маркер умной заметки `, SHOW_NOTE, `SHOW_NOTE`, `Оставьте в заметке пользователя один из хэштегов (#добро, #интересно, #осторожно, #неприемлемый), чтобы показывать специальный маркер, а также изменить цвет заметки`); addCheckbox(`Показывать маркер рейтинга `, SHOW_RATE, `SHOW_RATE`); addCheckbox(`Показывать маркер подписчиков `, SHOW_SUBS, `SHOW_SUBS`, `◔ - Более `+SUBS_VALUES[0]+` подписчиков<br>◑ - Более `+SUBS_VALUES[1]+` подписчиков<br>◕ - Более `+SUBS_VALUES[2]+` подписчиков<br>◉ - Более `+SUBS_VALUES[3]+` подписчиков`); addCheckbox(`Показывать маркер бана `, SHOW_BAN, `SHOW_BAN`, `ϟ - Временныый бан<br>† - Вечный бан` ); addCheckbox(`Показывать маркер пола `, SHOW_GENDER, `SHOW_GENDER`, `♂ - Пикабушник<br>♀ - Пикабушница` ); addLine(`Умные заметки`); addCheckbox(`Показывать кнопки быстрого добавления умной заметки `, SHOW_QUICK_NOTE, `SHOW_QUICK_NOTE`, `Рядом с комментариями и на странице пользователя будут кнопки для быстрого добавления заметки с хэштегом. Кнопки рядом с комментариями также сохраняют ссылку на комментарий.<br>ОСТОРОЖНО: При добавлении хэтега через кнопку, предыдущая заметка полностью удаляется.` ); addLine(`Дополнительные функции`); addCheckbox(`Автоматический бан #неприемлемого `, AUTOBAN, `AUTOBAN`, `При добавлении хэштега #неприемлемый автоматически скрываются комментарии пользователя. Если убрать хэштег, то комментарии снова будут показываться. Работает только при добавлении хэштегов через кнопки быстрого добавления.` ); let sectionBottom = document.createElement(`section`); sectionBottom.classList.add(`section_gray`); sectionBottom.classList.add(`section_center`); sectionGroup.appendChild(sectionBottom); let buttonClear = document.createElement(`button`); buttonClear.classList.add(`button_danger`); buttonClear.textContent = `УДАЛИТЬ КЭШИРОВАННЫЕ ДАННЫЕ`; sectionBottom.appendChild(buttonClear); buttonClear.addEventListener(`click`, () => { GM_setValue(DATABASE, {}); }); }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址