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 { bricksToCurrency, pullCache } from "@/utils/utilities";
2import * as api from "@/utils/api";
3
4/**
5 * Adds the locale real-life dollar value next to the amount of bricks an item costs on the /store/ page item grid.
6 */
7export function irlBrickPrice() {
8 const grid = document.getElementById("assets")!;
9
10 const addPrice = (item: HTMLElement) => {
11 const brickCount = item.getElementsByClassName("text-success")[0]
12 .textContent!;
13 const currency = bricksToCurrency(parseInt(brickCount), "USD");
14
15 if (currency) {
16 const spanTag = document.createElement("span");
17 spanTag.classList.add("text-muted");
18 spanTag.style.fontSize = "0.7rem";
19 spanTag.style.fontWeight = "lighter";
20 spanTag.innerText = ` (${currency})`;
21 item.getElementsByClassName("text-success")[0].appendChild(spanTag);
22 }
23 };
24
25 for (const item of document.getElementsByClassName("itemCardCont")) {
26 addPrice(item as HTMLElement);
27 }
28
29 const mutations = new MutationObserver((mutations) => {
30 for (const record of mutations) {
31 for (const node of record.addedNodes) {
32 const item = node as HTMLElement;
33 if ((item as HTMLElement).classList.contains("itemCardCont")) {
34 addPrice(item);
35 }
36 }
37 }
38 });
39
40 mutations.observe(grid, { childList: true });
41}
42
43/**
44 * Adds a star in the corner of items the user owns on the /store/ page item grid.
45 * @param userId The ID of the authenticated user.
46 */
47export async function ownedTags(userId: number) {
48 const grid = document.getElementById("assets")!;
49 const inventory = await pullCache(
50 "inventory",
51 async () =>
52 await api.iterate(
53 "public",
54 "users/" + userId + "/inventory?limit=100&page=",
55 {
56 data: "inventory",
57 metadata: "meta",
58 },
59 1,
60 5,
61 ),
62 300000,
63 false,
64 );
65
66 if (inventory == "disabled") {
67 throw new Error(
68 "[Poly+] API is disabled, cancelling item owned tags loading..",
69 );
70 }
71
72 const owns = (item: HTMLElement) => {
73 const itemId = parseInt(item.getAttribute("href")!.split("/")[2]);
74
75 if (
76 inventory.find((item: {
77 asset: {
78 id: number;
79 };
80 }) => item.asset.id == itemId)
81 ) {
82 return true;
83 }
84
85 return false;
86 };
87
88 const addTag = (item: HTMLElement) => {
89 const tag = document.createElement("span");
90 tag.classList.add("badge", "bg-primary");
91 tag.setAttribute(
92 "style",
93 `
94 position: absolute;
95 font-size: 0.9rem;
96 top: 0px;
97 left: 0px;
98 padding: 5.5px;
99 border-top-left-radius: var(--bs-border-radius-lg) !important;
100 border-top-right-radius: 0px;
101 border-bottom-left-radius: 0px;
102 font-size: 0.65rem;
103 `,
104 );
105 tag.innerHTML = "<i class='fas fa-star'></i>";
106
107 const image = item.getElementsByTagName("img")[0]!;
108 image.parentElement!.appendChild(tag);
109 };
110
111 for (const item of document.getElementsByClassName("itemCardCont")) {
112 const link: HTMLElement = item.getElementsByTagName("a")[0]!;
113 if (owns(link)) {
114 addTag(item as HTMLElement);
115 }
116 }
117
118 const mutations = new MutationObserver((mutations) => {
119 for (const record of mutations) {
120 for (const node of record.addedNodes) {
121 const item = node as HTMLElement;
122 if ((item as HTMLElement).classList.contains("itemCardCont")) {
123 const link: HTMLElement = item.getElementsByTagName("a")[0]!;
124 if (owns(link)) {
125 addTag(item as HTMLElement);
126 }
127 }
128 }
129 }
130 });
131
132 mutations.observe(grid, { childList: true });
133}