2025-02-15 13:11:38 -07:00

128 lines
3.7 KiB
JavaScript

const port = browser.runtime.connect({ name: "devtools" });
port.onMessage.addListener((message) => {
if (message.type === "PAGE_LOADED") {
loadContextStack(); // Refresh your context stack here.
}
});
const tabId = browser.devtools.inspectedWindow.tabId;
document.getElementById("refresh").addEventListener("click", loadContextStack);
function loadContextStack() {
const container = document.getElementById("contextContainer");
container.innerHTML = "";
browser.runtime.sendMessage({ type: "GET_CONTEXT_STACK", tabId }).then(
(response) => {
if (response.error) {
container.innerHTML = `<p>Error: ${response.error}</p>`;
return;
}
if (!response || !response.contextStack) {
container.innerHTML = "<p>No context stack found.</p>";
return;
}
const contextStack = coalesceContextStack(response.contextStack);
const form = generateObjectForm(contextStack);
container.appendChild(form);
},
);
}
function generateObjectForm(obj, path = "") {
const detail = document.createElement("details");
detail.open = path === "";
const summary = document.createElement("summary");
summary.textContent = path.split(".").at(-1);
detail.appendChild(summary);
const form = document.createElement("form");
let count = 0;
for (const [key, value] of Object.entries(obj)) {
if (value == undefined || value === "[Circular]") continue;
const isObject = value.constructor === Object;
const isArray = Array.isArray(value);
if (isObject || isArray) {
const nestedForm = generateObjectForm(
value,
path ? path + "." + key : key,
);
if (!nestedForm) {
continue;
}
const div = document.createElement("div");
div.appendChild(nestedForm);
form.appendChild(div);
count++;
continue;
}
const div = document.createElement("div");
const label = document.createElement("label");
label.textContent = key;
div.appendChild(label);
const input = document.createElement("input");
input.name = key;
const isBoolean = typeof value === "boolean";
if (isBoolean) {
input.type = "checkbox";
input.checked = value;
input.addEventListener("change", () => {
browser.runtime.sendMessage({
type: "UPDATE_CONTEXT_VALUE",
key: path ? path + "." + key : key,
value: input.checked,
tabId,
}).then((updateResponse) => {
if (updateResponse && updateResponse.success) {
console.log(`Updated ${key} to ${input.checked}`);
} else {
console.error(`Failed to update ${key}:`, updateResponse.error);
}
});
});
} else {
input.type = "text";
input.value = value;
input.addEventListener("change", () => {
browser.runtime.sendMessage({
type: "UPDATE_CONTEXT_VALUE",
key: path ? path + "." + key : key,
value: input.value,
tabId,
}).then((updateResponse) => {
if (updateResponse && updateResponse.success) {
console.log(`Updated ${key} to ${input.value}`);
} else {
console.error(`Failed to update ${key}:`, updateResponse.error);
}
});
});
}
div.appendChild(input);
form.appendChild(div);
count++;
}
if (count === 0) {
const pre = document.createElement("pre");
pre.textContent = JSON.stringify(obj, null, 2);
detail.appendChild(pre);
} else {
detail.appendChild(form);
}
return detail;
}
function coalesceContextStack(contextStack) {
const obj = {};
for (const ctx of contextStack) {
Object.assign(obj, ctx);
}
return obj;
}
document.addEventListener("DOMContentLoaded", () => {
loadContextStack();
});