import { addStyle, DOMUtils, log, pops, utils } from "@/env"; import { GreasyforkUrlUtils } from "@/utils/GreasyforkUrlUtils"; import { Panel } from "@components/setting/panel"; import type { PopsRightClickMenuDataConfig } from "@whitesev/pops/dist/types/src/components/rightClickMenu/types/index.js"; import i18next from "i18next"; import Qmsg from "qmsg"; import { type DiscuessionsFilterRule, GreasyforkDiscussionsFilter } from "./GreasyforkDiscussionsFilter"; export const GreasyforkForum = { init() { this.readBgColor(); DOMUtils.onReady(() => { Panel.execMenuOnce("greasyfork-discussions-filter-enable", () => { this.filterEnable(); }); addStyle(/*css*/ ` .discussion-meta-item[data-type="more"]{ display: none; } .discussion-meta-item[data-type="more"] button{ padding-left: 10px; padding-right: 10px; } @media screen and (max-width: 600px){ /* 移动端时隐藏过滤、举报按钮 */ .discussion-meta-item[data-type="filter"], .discussion-meta-item[data-type="report"]{ display: none; } /* 显示举报按钮 */ .discussion-meta-item[data-type="more"]{ display: block; } } `); const lockFn = new utils.LockFunction(() => { const addFilterButton = Panel.getValue("discussions-addShortcutOperationButton")!; const addReportButton = Panel.getValue("discussions-addReportButton")!; if (addFilterButton) { this.addFilterButton(); } if (addReportButton) { this.addReportButton(); } if (addFilterButton || addReportButton) { this.addMoreButton({ addFilterButton, addReportButton, }); } }); utils.mutationObserver(document.body, { config: { subtree: true, childList: true, }, immediate: true, callback: () => { lockFn.run(); }, }); }); }, /** * 启用Greasyfork论坛过滤器 */ filterEnable() { log.info("启用Greasyfork论坛过滤器"); GreasyforkDiscussionsFilter.init(); }, /** * 设置已读背景颜色 */ readBgColor() { log.info("设置已读背景颜色"); const color = Panel.getValue("discussions-readBgColor"); const colorConversion = new utils.ColorConversion(); const darkColor = colorConversion.getDarkColor(color, 0.8); return addStyle(/*css*/ ` .discussion-read{ background: ${color} !important; } @media (prefers-color-scheme: dark){ .discussion-read{ background: ${darkColor} !important; } } `); }, /** * 添加【过滤】按钮 */ addFilterButton() { const buttonClassName = "discussion-filter-button"; GreasyforkDiscussionsFilter.getElementList().forEach(($listContainer) => { if ($listContainer.querySelector(`.${buttonClassName}`)) { return; } const $listItem = $listContainer.querySelector(".discussion-list-item")!; const $meta = $listItem.querySelector(".discussion-meta")!; const $ownMetaItem = DOMUtils.createElement( "div", { className: "discussion-meta-item", innerHTML: ` `, }, { style: "flex: 0;", "data-type": "filter", } ); const $button = $ownMetaItem.querySelector(`.${buttonClassName}`)!; $meta.appendChild($ownMetaItem); DOMUtils.on($button, "click", (event) => { DOMUtils.preventEvent(event); const discussionInfo = GreasyforkDiscussionsFilter.parseDiscuessionListContainerInfo($listContainer); if (!discussionInfo) { return; } const attr_filter_key = "data-filter-key"; const attr_filter_value = "data-filter-value"; const $dialog = pops.alert({ title: { text: i18next.t("选择需要过滤的选项"), position: "center", html: false, }, content: { text: /*html*/ ` ${ discussionInfo.postUserId != null ? /*html*/ ` ` : "" } `, html: true, }, mask: { enable: true, clickEvent: { toClose: true, }, }, btn: { ok: { enable: false, }, }, drag: true, dragLimit: true, width: "350px", height: "300px", style: /*css*/ ` .pops-alert-content{ display: flex; flex-direction: column; gap: 20px; } .pops-alert-content button{ text-wrap: wrap; padding: 8px; height: auto; text-align: left; } `, }); const $content = $dialog.$shadowRoot.querySelector(".pops-alert-content")!; if (discussionInfo.scriptId == null) { $content.querySelector(`button[${attr_filter_key}="scriptId"]`)?.remove(); } if (discussionInfo.scriptName == null) { $content.querySelector(`button[${attr_filter_key}="scriptName"]`)?.remove(); } if (discussionInfo.postUserId == null) { $content.querySelector(`button[${attr_filter_key}="postUserId"]`)?.remove(); } if (discussionInfo.replyUserId != null) { const $replyUserIdButton = DOMUtils.createElement("button", { innerHTML: i18next.t("作者id:{{text}}", { text: discussionInfo.replyUserId, }), }); $replyUserIdButton.setAttribute(attr_filter_key, "scriptAuthorId"); $replyUserIdButton.setAttribute(attr_filter_value, "^" + discussionInfo.replyUserId + "$"); $content.appendChild($replyUserIdButton); } DOMUtils.on($dialog.$shadowRoot, "click", `button[${attr_filter_key}]`, (event) => { DOMUtils.preventEvent(event); const $click = event.target as HTMLButtonElement; const key = $click.getAttribute(attr_filter_key)! as keyof DiscuessionsFilterRule; const value = $click.getAttribute(attr_filter_value)!; GreasyforkDiscussionsFilter.addValue(key, value); $dialog.close(); GreasyforkDiscussionsFilter.filter(); Qmsg.success(i18next.t("添加成功")); }); }); }); }, /** * 添加【举报】按钮 */ addReportButton() { const buttonClassName = "discussion-report-button"; GreasyforkDiscussionsFilter.getElementList().forEach(($listContainer) => { if ($listContainer.querySelector(`.${buttonClassName}`)) { return; } let $listItem = $listContainer.querySelector(".discussion-list-item")!; let $meta = $listItem.querySelector(".discussion-meta")!; let $ownMetaItem = DOMUtils.createElement( "div", { className: "discussion-meta-item", innerHTML: ` `, }, { style: "flex: 0;", "data-type": "report", } ); let $button = $ownMetaItem.querySelector(`.${buttonClassName}`)!; $meta.appendChild($ownMetaItem); DOMUtils.on($button, "click", (event) => { DOMUtils.preventEvent(event); const discussionInfo = GreasyforkDiscussionsFilter.parseDiscuessionListContainerInfo($listContainer); if (!discussionInfo) { return; } let attr_filter_key = "data-filter-key"; let attr_filter_value = "data-filter-value"; let $dialog = pops.alert({ title: { text: i18next.t("举报"), position: "center", html: false, }, content: { text: /*html*/ `
${i18next.t("举报讨论:")} ${discussionInfo.snippet}
${ discussionInfo.scriptId ? /*html*/ `
${i18next.t("举报脚本:")} ${discussionInfo.scriptName}
` : "" }
${i18next.t("举报用户:")} ${discussionInfo.postUserName}
${ discussionInfo.replyUserId && discussionInfo.replyUserId != discussionInfo.postUserId ? /*html*/ `
${i18next.t("举报用户:")} ${discussionInfo.replyUserName}
` : "" } `, html: true, }, btn: { ok: { enable: false, }, }, mask: { enable: true, clickEvent: { toClose: true, }, }, drag: true, dragLimit: true, width: "350px", height: "300px", style: /*css*/ ` .pops-alert-content{ display: flex; flex-direction: column; gap: 20px; } .pops-alert-content .report-item{ text-wrap: wrap; padding: 8px; height: auto; text-align: left; margin: var(--button-margin-top) var(--button-margin-right) var(--button-margin-bottom) var(--button-margin-left); border-radius: var(--button-radius); color: var(--button-color); border-color: var(--button-bd-color); background-color: var(--button-bg-color); } `, }); }); }); }, /** * 添加【...】按钮 */ addMoreButton(config: { addFilterButton: boolean; addReportButton: boolean }) { const buttonClassName = "discussion-more-button"; GreasyforkDiscussionsFilter.getElementList().forEach(($listContainer) => { if ($listContainer.querySelector(`.${buttonClassName}`)) { return; } let $listItem = $listContainer.querySelector(".discussion-list-item")!; let $meta = $listItem.querySelector(".discussion-meta")!; let $ownMetaItem = DOMUtils.createElement( "div", { className: "discussion-meta-item", innerHTML: ` `, }, { style: "flex: 0;", "data-type": "more", } ); const $button = $ownMetaItem.querySelector(`.${buttonClassName}`)!; const data: PopsRightClickMenuDataConfig[] = []; if (config.addFilterButton) { data.push({ text: i18next.t("过滤"), callback: () => { const $parent = DOMUtils.parent($listItem); const $filter = $parent.querySelector('.discussion-meta-item[data-type="filter"] button'); if (!$filter) { Qmsg.error(i18next.t("未找到【过滤】按钮")); return; } $filter.click(); }, }); } if (config.addReportButton) { data.push({ text: i18next.t("举报"), callback: () => { const $parent = DOMUtils.parent($listItem); const $report = $parent.querySelector('.discussion-meta-item[data-type="report"] button'); if (!$report) { Qmsg.error(i18next.t("未找到【举报】按钮")); return; } $report.click(); }, }); } if (!data.length) { return; } const rightClickMenu = pops.rightClickMenu({ position: "absolute", limitPositionYInView: false, data: data, }); rightClickMenu.removeContextMenuEvent(document.documentElement); DOMUtils.on($button, "click", (event) => { DOMUtils.preventEvent(event); const rect = $button.getBoundingClientRect(); rightClickMenu.PopsContextMenu.contextMenuEvent( new PointerEvent("contextmenu", { clientX: rect.left + window.scrollX, clientY: rect.top + rect.height + window.scrollY, }), $button ); }); $meta.appendChild($ownMetaItem); }); }, };