diff --git a/source/ContentScript/element-factories/owns-column.ts b/source/ContentScript/element-factories/owns-column.ts
new file mode 100644
index 0000000..5b215fb
--- /dev/null
+++ b/source/ContentScript/element-factories/owns-column.ts
@@ -0,0 +1,26 @@
+import Trader from "../trader";
+
+export default class OwnsColumn {
+ static create(trader: Trader): HTMLTableCellElement {
+ let count = trader.ownsCount ?? 0;
+
+ let td = document.createElement("td");
+ td.style.textAlign = "center";
+
+ if (count === 0) {
+ td.innerText = "0";
+ td.style.color = "#cbd5e1";
+
+ return td;
+ }
+
+ let a = document.createElement("a");
+ a.target = "_blank";
+ a.href = trader.ownsList ?? "#";
+ a.innerHTML = `${count} `;
+
+ td.appendChild(a);
+
+ return td;
+ }
+}
diff --git a/source/ContentScript/element-factories/wants-column.ts b/source/ContentScript/element-factories/wants-column.ts
new file mode 100644
index 0000000..f499fae
--- /dev/null
+++ b/source/ContentScript/element-factories/wants-column.ts
@@ -0,0 +1,26 @@
+import Trader from "../trader";
+
+export default class WantsColumn {
+ static create(trader: Trader): HTMLTableCellElement {
+ let count = trader.wantsCount ?? 0;
+
+ let td = document.createElement("td");
+ td.style.textAlign = "center";
+
+ if (count === 0) {
+ td.innerText = "0";
+ td.style.color = "#cbd5e1";
+
+ return td;
+ }
+
+ let a = document.createElement("a");
+ a.target = "_blank";
+ a.href = trader.wantsList ?? "#";
+ a.innerHTML = `${count} `;
+
+ td.appendChild(a);
+
+ return td;
+ }
+}
diff --git a/source/ContentScript/index.ts b/source/ContentScript/index.ts
index 186104d..46a948e 100644
--- a/source/ContentScript/index.ts
+++ b/source/ContentScript/index.ts
@@ -1,3 +1,5 @@
+import TradeFinderEnhancer from "./page-enhancers/trade-finder-enhancer";
+import TradeFinderTheirsEnhancer from "./page-enhancers/trade-finder-theirs-enhancer";
import WhoOwnsEnhancer from "./page-enhancers/who-owns-enhancer";
import WhoWantsEnhancer from "./page-enhancers/who-wants-enhancer";
@@ -8,3 +10,11 @@ if (window.location.href.includes("who-owns.php")) {
if (window.location.href.includes("who-wants.php")) {
WhoWantsEnhancer.enhance(document);
}
+
+if (window.location.href.includes("profile/trade_finder.php")) {
+ TradeFinderEnhancer.enhance(document);
+}
+
+if (window.location.href.includes("profile/trade_finder_theirs.php")) {
+ TradeFinderTheirsEnhancer.enhance(document);
+}
diff --git a/source/ContentScript/page-elements/trade-finder-row.ts b/source/ContentScript/page-elements/trade-finder-row.ts
new file mode 100644
index 0000000..34972e2
--- /dev/null
+++ b/source/ContentScript/page-elements/trade-finder-row.ts
@@ -0,0 +1,88 @@
+import OwnsColumn from "../element-factories/owns-column";
+import WantsColumn from "../element-factories/wants-column";
+import Trader from "../trader";
+import TraderRepository from "../trader-repository";
+
+export default class TradeFinderRow {
+ constructor(
+ public row: HTMLTableRowElement,
+ public cells: NodeListOf,
+ public repository: TraderRepository | null
+ ) {}
+
+ static parse(
+ row: HTMLTableRowElement,
+ repository: TraderRepository | null = null
+ ): TradeFinderRow | null {
+ let cells = row.querySelectorAll("td");
+
+ if (cells.length < 2) {
+ return null;
+ }
+
+ return new TradeFinderRow(row, cells, repository);
+ }
+
+ get username(): string {
+ return this.cells[0]
+ .querySelector("a")!
+ .querySelector("strong")!
+ .innerText.trim();
+ }
+
+ get profile(): string {
+ return this.cells[0].querySelector("a")!.href;
+ }
+
+ get open(): boolean {
+ return this.cells[0]
+ .querySelector("span")!
+ .innerText.includes("Open to trades");
+ }
+
+ get count(): number {
+ let link = this.cells[1].querySelector("a");
+
+ return link ? parseInt(link.innerText.match(/\d+/)![0]) : 0;
+ }
+
+ get list(): string | null {
+ let link = this.cells[1].querySelector("a");
+
+ return link ? link.href : null;
+ }
+
+ get trader(): Trader | null {
+ if (this.repository === null) {
+ throw new Error(
+ "Cannot get trader from TradeFinderRow without a repository"
+ );
+ }
+
+ return this.repository.find(this.username);
+ }
+
+ addWantsColumn() {
+ if (this.trader === null) {
+ throw new Error(
+ "Cannot add wants column to a TradeFinderRow that has no trader data"
+ );
+ }
+
+ let td = WantsColumn.create(this.trader!);
+
+ this.row.appendChild(td);
+ }
+
+ addOwnsColumn() {
+ if (this.trader === null) {
+ throw new Error(
+ "Cannot add owns column to a TradeFinderRow that has no trader data"
+ );
+ }
+
+ let td = OwnsColumn.create(this.trader!);
+
+ this.row.appendChild(td);
+ }
+}
diff --git a/source/ContentScript/page-enhancers/trade-finder-enhancer.ts b/source/ContentScript/page-enhancers/trade-finder-enhancer.ts
new file mode 100644
index 0000000..43a9ecf
--- /dev/null
+++ b/source/ContentScript/page-enhancers/trade-finder-enhancer.ts
@@ -0,0 +1,30 @@
+import TradeFinderRow from "../page-elements/trade-finder-row";
+import TraderRepository from "../trader-repository";
+
+export default class TradeFinderEnhancer {
+ static addHeader(page: Document) {
+ let th = document.createElement("th");
+ th.innerText = "# of their wants that I own";
+ th.style.textAlign = "center";
+ th.scope = "col";
+
+ page.querySelector("table thead tr")?.appendChild(th);
+ }
+
+ static async enhance(page: Document) {
+ let repository = await TraderRepository.load();
+
+ this.addHeader(page);
+
+ let tbody = page.querySelector("table tbody")!;
+ let rows = tbody.querySelectorAll("tr");
+
+ Array.from(rows)
+ .map((row) =>
+ TradeFinderRow.parse(row as HTMLTableRowElement, repository)
+ )
+ .filter((row) => row !== null)
+ .filter((row) => row!.trader !== null)
+ .forEach((row) => row!.addWantsColumn());
+ }
+}
diff --git a/source/ContentScript/page-enhancers/trade-finder-theirs-enhancer.ts b/source/ContentScript/page-enhancers/trade-finder-theirs-enhancer.ts
new file mode 100644
index 0000000..b2a4e74
--- /dev/null
+++ b/source/ContentScript/page-enhancers/trade-finder-theirs-enhancer.ts
@@ -0,0 +1,30 @@
+import TradeFinderRow from "../page-elements/trade-finder-row";
+import TraderRepository from "../trader-repository";
+
+export default class TradeFinderTheirsEnhancer {
+ static addHeader(page: Document) {
+ let th = document.createElement("th");
+ th.innerText = "# of my wants that they own";
+ th.style.textAlign = "center";
+ th.scope = "col";
+
+ page.querySelector("table thead tr")?.appendChild(th);
+ }
+
+ static async enhance(page: Document) {
+ let repository = await TraderRepository.load();
+
+ this.addHeader(page);
+
+ let tbody = page.querySelector("table tbody")!;
+ let rows = tbody.querySelectorAll("tr");
+
+ Array.from(rows)
+ .map((row) =>
+ TradeFinderRow.parse(row as HTMLTableRowElement, repository)
+ )
+ .filter((row) => row !== null)
+ .filter((row) => row!.trader !== null)
+ .forEach((row) => row!.addOwnsColumn());
+ }
+}
diff --git a/source/ContentScript/trader-repository.ts b/source/ContentScript/trader-repository.ts
index 57069d8..322eead 100644
--- a/source/ContentScript/trader-repository.ts
+++ b/source/ContentScript/trader-repository.ts
@@ -29,8 +29,8 @@ export default class TraderRepository {
let text = await response.text();
let page = new DOMParser().parseFromString(text, "text/html");
- let table = page.querySelector("table")!;
- let rows = table.querySelectorAll("tr");
+ let tbody = page.querySelector("table tbody")!;
+ let rows = tbody.querySelectorAll("tr");
return Array.from(rows)
.map((row) => Trader.fromWantsRow(row as HTMLTableRowElement))
@@ -47,8 +47,8 @@ export default class TraderRepository {
let text = await response.text();
let page = new DOMParser().parseFromString(text, "text/html");
- let table = page.querySelector("table")!;
- let rows = table.querySelectorAll("tr");
+ let tbody = page.querySelector("table tbody")!;
+ let rows = tbody.querySelectorAll("tr");
return Array.from(rows)
.map((row) => Trader.fromOwnsRow(row as HTMLTableRowElement))
diff --git a/source/ContentScript/trader.ts b/source/ContentScript/trader.ts
index a092139..38a58d0 100644
--- a/source/ContentScript/trader.ts
+++ b/source/ContentScript/trader.ts
@@ -1,10 +1,4 @@
-interface RowData {
- username: string;
- profile: string;
- open: boolean;
- count: number;
- list: string | null;
-}
+import TradeFinderRow from "./page-elements/trade-finder-row";
export default class Trader {
constructor(
@@ -17,53 +11,11 @@ export default class Trader {
public wantsList: string | null = null
) {}
- /**
- * Get the underlying trader data from a row in a "Trade finder" table.
- */
- static parseRow(row: HTMLTableRowElement): RowData | null {
- let cells = row.querySelectorAll("td");
-
- if (cells.length < 2) {
- return null;
- }
-
- let profileLink = cells[0].querySelector("a");
-
- if (!profileLink) {
- return null;
- }
-
- let username =
- profileLink.querySelector("strong")?.innerText ??
- profileLink.innerText;
- let profile = profileLink.href;
-
- let open =
- cells[0]
- .querySelector("span")
- ?.innerText.includes("Open to trades") ?? false;
-
- let wantsLink = cells[1].querySelector("a");
-
- let count = wantsLink
- ? parseInt(wantsLink.innerText.match(/\d+/)![0])
- : 0;
- let list = wantsLink ? wantsLink.href : null;
-
- return {
- username,
- profile,
- open,
- count,
- list,
- };
- }
-
/**
* Create a Trader from a row in a "Trade finder wants" table.
*/
static fromWantsRow(row: HTMLTableRowElement): Trader | null {
- let data = Trader.parseRow(row);
+ let data = TradeFinderRow.parse(row);
if (data === null) {
return null;
@@ -84,7 +36,7 @@ export default class Trader {
* Create a Trader from a row in a "Trade finder owns" table.
*/
static fromOwnsRow(row: HTMLTableRowElement): Trader | null {
- let data = Trader.parseRow(row);
+ let data = TradeFinderRow.parse(row);
if (data === null) {
return null;