A rewrite of Poly+, my quality-of-life browser extension for Polytoria. Built entirely fresh using the WXT extension framework, Typescript, and with added better overall code quality.
extension
1import config from "@/utils/config.json";
2
3/**
4 * Detects any username mentions in a forum post and turns them into clickable links.
5 */
6export function forumMentions() {
7 const textBlocks = document.querySelectorAll("p:not(.text-muted):not(.mb-0)");
8 const regex = /@([\w.]+)/g;
9
10 textBlocks.forEach((text) => {
11 const walker = document.createTreeWalker(text, NodeFilter.SHOW_TEXT, null);
12 let node;
13
14 while ((node = walker.nextNode())) {
15 const fragment = document.createDocumentFragment();
16 let lastIndex = 0;
17 let match;
18
19 while ((match = regex.exec(node.nodeValue!)) !== null) {
20 const username = match[1];
21 const link = document.createElement("a");
22 link.href = `/u/${username}`;
23 link.className = "polyplus-mention";
24 link.textContent = match[0];
25
26 fragment.appendChild(
27 document.createTextNode(
28 node.nodeValue!.substring(lastIndex, match.index),
29 ),
30 );
31 fragment.appendChild(link);
32 lastIndex = match.index + match[0].length;
33 }
34
35 fragment.appendChild(
36 document.createTextNode(node.nodeValue!.substring(lastIndex)),
37 );
38 node.parentNode!.replaceChild(fragment, node);
39 }
40 });
41}
42
43export function generativeAI() {
44 for (const userID of config.users.generativeAI) {
45 const cards = document.querySelectorAll(".card");
46
47 cards.forEach((card) => {
48 const user = card.querySelector(".forum-user-container");
49
50 if (user) {
51 const link = user.querySelector(`[href^="/users/${userID}"]`);
52
53 if (link) {
54 const textBlock = card.querySelector(".user-forum-content");
55
56 if (textBlock) {
57 const tag = document.createElement("span");
58 tag.classList.add("badge", "bg-secondary");
59 tag.innerText =
60 "This content may have been generated using AI. This information may not be factual.";
61 textBlock.appendChild(tag);
62 }
63 }
64 }
65 });
66 }
67}