Initial commit: AutoTrader Marker Firefox extension
Mark AutoTrader listings as 'not wanted' on both search results and detail pages. Includes the unlisted signing / auto-update pipeline (web-ext + dist/updates.json polled by Firefox). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
const api = typeof browser !== "undefined" ? browser : chrome;
|
||||
|
||||
const STORAGE_KEY = "dismissedListings";
|
||||
const SETTINGS_KEY = "settings";
|
||||
|
||||
const els = {
|
||||
count: document.getElementById("count"),
|
||||
hideToggle: document.getElementById("hideToggle"),
|
||||
exportBtn: document.getElementById("exportBtn"),
|
||||
importBtn: document.getElementById("importBtn"),
|
||||
importFile: document.getElementById("importFile"),
|
||||
clearBtn: document.getElementById("clearBtn"),
|
||||
status: document.getElementById("status"),
|
||||
};
|
||||
|
||||
function setStatus(msg) {
|
||||
els.status.textContent = msg;
|
||||
if (msg) setTimeout(() => (els.status.textContent = ""), 2500);
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
const res = await api.storage.local.get([STORAGE_KEY, SETTINGS_KEY]);
|
||||
const dismissed = res[STORAGE_KEY] || {};
|
||||
const settings = res[SETTINGS_KEY] || {};
|
||||
const n = Object.keys(dismissed).length;
|
||||
els.count.textContent = n === 1 ? "1 listing dismissed" : `${n} listings dismissed`;
|
||||
els.hideToggle.checked = !!settings.hideDismissed;
|
||||
}
|
||||
|
||||
els.hideToggle.addEventListener("change", async () => {
|
||||
const res = await api.storage.local.get(SETTINGS_KEY);
|
||||
const settings = res[SETTINGS_KEY] || {};
|
||||
settings.hideDismissed = els.hideToggle.checked;
|
||||
await api.storage.local.set({ [SETTINGS_KEY]: settings });
|
||||
});
|
||||
|
||||
els.clearBtn.addEventListener("click", async () => {
|
||||
const res = await api.storage.local.get(STORAGE_KEY);
|
||||
const n = Object.keys(res[STORAGE_KEY] || {}).length;
|
||||
if (n === 0) {
|
||||
setStatus("Nothing to clear.");
|
||||
return;
|
||||
}
|
||||
const ok = confirm(`Clear all ${n} dismissals? This can't be undone.`);
|
||||
if (!ok) return;
|
||||
await api.storage.local.set({ [STORAGE_KEY]: {} });
|
||||
await refresh();
|
||||
setStatus("Cleared.");
|
||||
});
|
||||
|
||||
els.exportBtn.addEventListener("click", async () => {
|
||||
const res = await api.storage.local.get(STORAGE_KEY);
|
||||
const data = res[STORAGE_KEY] || {};
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
const stamp = new Date().toISOString().slice(0, 10);
|
||||
a.href = url;
|
||||
a.download = `autotrader-marker-${stamp}.json`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
setStatus("Exported.");
|
||||
});
|
||||
|
||||
els.importBtn.addEventListener("click", () => els.importFile.click());
|
||||
els.importFile.addEventListener("change", async (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
try {
|
||||
const text = await file.text();
|
||||
const parsed = JSON.parse(text);
|
||||
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
||||
throw new Error("Expected an object keyed by listing id");
|
||||
}
|
||||
const res = await api.storage.local.get(STORAGE_KEY);
|
||||
const merged = { ...(res[STORAGE_KEY] || {}), ...parsed };
|
||||
await api.storage.local.set({ [STORAGE_KEY]: merged });
|
||||
await refresh();
|
||||
setStatus(`Imported ${Object.keys(parsed).length} entries.`);
|
||||
} catch (err) {
|
||||
setStatus(`Import failed: ${err.message}`);
|
||||
} finally {
|
||||
els.importFile.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
api.storage.onChanged.addListener((changes, area) => {
|
||||
if (area === "local" && (changes[STORAGE_KEY] || changes[SETTINGS_KEY])) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
refresh();
|
||||
Reference in New Issue
Block a user