I’ve been sitting with this problem for days, and I can’t quite figure out what’s wrong with my code.
My problem is that whenever my data gets re-ordered or change position, like changing the tabs position, the values don’t properly reflect. I’m so burnt out with this problem and I can’t really think straight anymore.
I regretted using index as my identifier, but in this case, which I’m really sure, doesn’t have any affect on how my data is being displayed. Please help! Thank you.
My popup.js
let data_placeholder = {};
initialize_data();
// Update the storage after the popup is closed
document.addEventListener("visibilitychange", () => {
chrome.runtime.sendMessage({ message: "set_data", data: data_placeholder });
});
// Update data_placeholder everytime the checkbox is toggled
function update_data(checkbox, type, index, method) {
if (checkbox.nodeName == "INPUT" && checkbox.type == "checkbox") {
checkbox.addEventListener("change", () => {
data_placeholder[type][index][method] = checkbox.checked;
});
} else {
console.warn("This shouldn't be happening: Error(Incompatible type)");
}
}
// Execute script
document.getElementById("execute-script").addEventListener("click", (e) => {
chrome.runtime.sendMessage({
message: "execute_methods",
data: data_placeholder,
});
});
// some code
function initialize_data() {
chrome.runtime.sendMessage({ message: "get_data" }, (data) => {
// Update data_placeholder with the latest data
data_placeholder = structuredClone(data);
console.log("Popup data: ", data_placeholder);
if (data.extensions.length > 0) {
let frag_ext = document.createDocumentFragment();
data.extensions.sort((a, b) => a.ext_name.localeCompare(b.ext_name));
data.extensions.forEach((extension, i) => {
// Don't show self
if (extension.ext_name == "Chroxt") {
return;
}
// Setting up the elements
let container = document.createElement("div");
let name = document.createElement("p");
let reload = document.createElement("input");
let uninstall = document.createElement("input");
let disable = document.createElement("input");
name.title = `Name: ${extension.ext_name}nID: ${extension.ext_id}nVersion: ${extension.version}nMatches: nt${extension.matches.join(",nt")}nPermissions: nt${extension.permissions.join(",nt")}`;
name.textContent = extension.ext_name;
frag_ext.appendChild(batch_append(container, [name, reload, uninstall, disable]));
batch_set_attr([reload, uninstall, disable], "type", "checkbox");
container.setAttribute("class", "ext-list-body");
// Modifying the properties
reload.checked = extension.reload;
disable.checked = extension.disable;
uninstall.checked = extension.uninstall;
// Adding listeners for checkboxes
update_data(reload, "extensions", i, "reload");
update_data(uninstall, "extensions", i, "uninstall");
update_data(disable, "extensions", i, "disable");
// Stylization
if (extension.enabled) {
name.style.opacity = "100%";
} else {
name.style.opacity = "30%";
}
});
document.getElementById("list-ext").appendChild(frag_ext);
} else {
// Add such empty
}
if (data.websites.length > 0) {
let frag_site = document.createDocumentFragment();
data.websites.forEach((website, i) => {
// Setting up the elements
let container = document.createElement("div");
let name = document.createElement("p");
let reload = document.createElement("input");
name.title = `Title: ${website.site_name}nID: ${website.site_id}nURL: ${website.url}`;
name.textContent = website.site_name;
frag_site.appendChild(batch_append(container, [name, reload]));
reload.type = "checkbox";
container.setAttribute("class", "site-list-body");
// Modifying the properties
reload.checked = website.reload;
// Adding listeners for checkbox
update_data(reload, "websites", i, "reload");
});
document.getElementById("list-site").appendChild(frag_site);
} else {
// Add such empty
}
});
}
background.js
let storage = chrome.storage.local;
// Purpose: Get new extensions & tabs data, default if new, otherwise copy methods data from original
// Return: Return an object, not merged with old data, but with old data essential properties
// Nutshell: Returns new & updated data
function get_new_data(callback = null) {
let data_placeholder = {
extensions: [],
websites: [],
enabled: false,
"show-popup": true,
};
return new Promise((resolve, reject) => {
// Get the current strorage
storage.get(null, (data) => {
// Get new extensions and new extension properties
chrome.management.getAll((extensions) => {
extensions.sort((a, b) => a.name.localeCompare(b.name));
extensions.forEach((ext, i) => {
// Since PWA is included, only allow extensions
if (ext.type == "extension") {
// Create an object inside an array of this object for every extension
data_placeholder.extensions[i] = {
// Brand new data
ext_name: ext.name,
ext_id: ext.id,
version: ext.version,
enabled: ext.enabled,
matches: ext.hostPermissions,
permissions: ext.permissions,
icon: ext.icons?.[0].url,
// Keep settings the same, if not initialized, set to default
reload: data.extensions?.[i]?.reload ?? false,
disable: data.extensions?.[i]?.disable ?? false,
uninstall: data.extensions?.[i]?.uninstall ?? false,
};
}
});
// After extension operation, get all open tabs
chrome.tabs.query({}, (tabs) => {
tabs.forEach((tab, k) => {
// For each tab, add this object
data_placeholder.websites[k] = {
site_name: tab.title,
site_id: tab.id,
icon: tab.favIconUrl,
url: tab.url,
// Keep settings the same, if not initialized, set to default
reload: data.websites?.[k]?.reload ?? false,
};
});
// Finally, return the merged data through Promises or callback
if (typeof callback == "function") {
callback(data_placeholder);
} else {
resolve(data_placeholder);
}
});
});
});
});
}
chrome.runtime.onMessage.addListener((receive, _, send) => {
switch (receive.message) {
case "get_data":
get_new_data().then((data) => {
send(data);
console.log("Background: ", data);
});
break;
case "set_data":
storage.set(receive.data);
break;
case "execute_methods":
receive.data.extensions.forEach((extension) => {
if (extension.reload) {
chrome.management.setEnabled(extension.ext_id, false);
chrome.management.setEnabled(extension.ext_id, true);
}
if (extension.disable) {
chrome.management.setEnabled(extension.ext_id, !extension.enabled);
}
if (extension.uninstall) {
chrome.management.uninstall(extension.ext_id);
}
});
receive.data.websites.forEach((website) => {
if (website.reload) {
chrome.tabs.reload(website.site_id);
}
});
break;
default:
console.warn("UNHANDLED MESSAGE: ONMESSAGE");
break;
}
return true;
});
I tried using ID as identifier using find(), but it produces the same result. I’m new with JS object concepts, and I’ve been trying to find a course or study materials on how to make data consistent everywhere and I couldn’t find any materials.