summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data-viewer/data-viewer.css402
-rw-r--r--data-viewer/data-viewer.html69
-rw-r--r--data-viewer/data-viewer.js405
-rw-r--r--manifest.json5
-rw-r--r--popup/popup.html6
-rw-r--r--popup/popup.js7
6 files changed, 894 insertions, 0 deletions
diff --git a/data-viewer/data-viewer.css b/data-viewer/data-viewer.css
new file mode 100644
index 0000000..7e4d8b3
--- /dev/null
+++ b/data-viewer/data-viewer.css
@@ -0,0 +1,402 @@
+/* Data Viewer specific styles */
+
+/* General layout adjustments */
+.app-content {
+ max-width: 960px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+body {
+ width: auto;
+ min-width: 600px;
+}
+
+/* Data section styling */
+.data-section {
+ margin-bottom: 24px;
+ background-color: var(--secondary-bg);
+ border-radius: var(--radius-md);
+ padding: 16px;
+}
+
+.data-container {
+ border-radius: var(--radius-sm);
+ overflow: hidden;
+}
+
+/* Table styling */
+.data-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 14px;
+ background-color: var(--bg-color);
+}
+
+.data-table th,
+.data-table td {
+ padding: 10px 12px;
+ text-align: left;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.data-table th {
+ background-color: var(--bg-color);
+ font-weight: 600;
+ color: var(--accent-color);
+ position: sticky;
+ top: 0;
+}
+
+.data-table tr:hover {
+ background-color: rgba(255, 255, 255, 0.05);
+}
+
+/* Status badges */
+.badge {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.badge.enabled {
+ background-color: var(--success-color);
+ color: white;
+}
+
+.badge.disabled {
+ background-color: var(--border-color);
+ color: var(--text-secondary);
+}
+
+/* No data message */
+.no-data {
+ padding: 16px;
+ text-align: center;
+ color: var(--text-secondary);
+ font-style: italic;
+ background-color: var(--bg-color);
+ border-radius: var(--radius-sm);
+}
+
+/* Website list styling */
+.websites-container {
+ margin-top: 16px;
+}
+
+.website-panel {
+ margin-bottom: 8px;
+ background-color: var(--bg-color);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+}
+
+.website-header {
+ cursor: pointer;
+ padding: 12px 16px;
+ font-weight: 500;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.website-header::after {
+ content: "\f078"; /* chevron-down icon */
+ font-family: "Font Awesome 5 Free";
+ font-weight: 900;
+ transition: transform 0.3s ease;
+}
+
+.website-header.active::after {
+ transform: rotate(180deg);
+}
+
+.website-header-content {
+ display: flex;
+ align-items: center;
+ flex: 1;
+}
+
+.website-name {
+ font-weight: 600;
+ color: var(--text-primary);
+}
+
+.feature-count {
+ font-size: 12px;
+ color: var(--text-secondary);
+ margin-left: 12px;
+}
+
+.settings-badge {
+ background-color: var(--accent-color);
+ color: white;
+ font-size: 11px;
+ padding: 2px 6px;
+ border-radius: 4px;
+ margin-left: 8px;
+}
+
+.website-content {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease;
+ background-color: var(--secondary-bg);
+}
+
+/* Search functionality */
+.search-container {
+ position: relative;
+ margin-bottom: 16px;
+}
+
+.search-input {
+ width: 100%;
+ padding: 10px 16px 10px 36px;
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ background-color: var(--bg-color);
+ color: var(--text-primary);
+ font-size: 14px;
+}
+
+.search-input:focus {
+ outline: none;
+ border-color: var(--accent-color);
+}
+
+.search-icon {
+ position: absolute;
+ left: 12px;
+ top: 12px;
+ color: var(--text-secondary);
+}
+
+/* Tab system */
+.tabs-container {
+ display: flex;
+ background-color: var(--bg-color);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.tab {
+ padding: 10px 16px;
+ cursor: pointer;
+ font-weight: 500;
+ border-bottom: 2px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.tab.active {
+ border-bottom-color: var(--accent-color);
+ color: var(--accent-color);
+}
+
+.tab-contents {
+ padding: 16px;
+}
+
+.tab-content {
+ display: none;
+}
+
+.tab-content.active {
+ display: block;
+}
+
+/* Features list */
+.features-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 8px;
+}
+
+.feature-item {
+ padding: 8px 12px;
+ background-color: var(--bg-color);
+ border-radius: var(--radius-sm);
+ font-size: 13px;
+}
+
+/* CSS blocks */
+.css-block {
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+.css-block:last-child {
+ border-bottom: none;
+}
+
+.css-block-header {
+ padding: 12px 16px;
+ cursor: pointer;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.2);
+ position: relative;
+}
+
+.css-block-header::after {
+ content: "\f078"; /* chevron-down icon */
+ font-family: "Font Awesome 5 Free";
+ font-weight: 900;
+ transition: transform 0.3s ease;
+}
+
+.css-block-header.active::after {
+ transform: rotate(180deg);
+}
+
+.feature-name {
+ font-weight: 500;
+}
+
+.feature-status {
+ padding: 2px 8px;
+ border-radius: 12px;
+ font-size: 12px;
+ margin-right: 24px;
+}
+
+.feature-status.enabled {
+ background-color: var(--success-color);
+ color: white;
+}
+
+.feature-status.disabled {
+ background-color: var(--border-color);
+ color: var(--text-secondary);
+}
+
+.css-content {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.3s ease;
+}
+
+/* CSS code display */
+.css-code {
+ background-color: rgba(0, 0, 0, 0.2);
+ padding: 16px;
+ margin: 0;
+ overflow-x: auto;
+ font-family: "Monaco", "Courier New", monospace;
+ font-size: 12px;
+ line-height: 1.5;
+ color: var(--text-primary);
+ max-height: 400px;
+ overflow-y: auto;
+ white-space: pre-wrap;
+}
+
+.show-more {
+ background: none;
+ border: none;
+ color: var(--accent-color);
+ cursor: pointer;
+ font-size: 12px;
+ padding: 0;
+ margin-top: 8px;
+ text-decoration: underline;
+}
+
+.show-more:hover {
+ color: var(--hover-color);
+}
+
+/* Mode info box */
+.mode-info {
+ padding: 12px;
+ margin-bottom: 16px;
+ background-color: var(--bg-color);
+ border-radius: var(--radius-sm);
+ border-left: 3px solid var(--accent-color);
+}
+
+/* Expand/collapse all button */
+.view-all-button {
+ margin: 8px 0;
+}
+
+/* Clear list button styling */
+.clear-list-button {
+ margin-top: 8px;
+ margin-bottom: 16px;
+ background-color: var(--secondary-bg);
+ border-color: var(--border-color);
+ font-size: 12px;
+ padding: 6px 12px;
+}
+
+.clear-list-button:hover {
+ background-color: rgba(220, 53, 69, 0.1);
+ border-color: var(--danger-color);
+ color: var(--danger-color);
+}
+
+/* Null and object value styling */
+.null-value {
+ color: #999;
+ font-style: italic;
+}
+
+.object-value {
+ color: var(--accent-color);
+ font-style: italic;
+}
+
+/* Danger zone styling */
+.danger-zone {
+ margin-top: 24px;
+ padding: 16px;
+ background-color: rgba(220, 53, 69, 0.1);
+ border: 1px solid rgba(220, 53, 69, 0.3);
+ border-radius: var(--radius-md);
+}
+
+.danger-title {
+ color: var(--danger-color);
+ font-size: 16px;
+ font-weight: 600;
+ margin-top: 0;
+ margin-bottom: 12px;
+}
+
+.danger-actions {
+ display: flex;
+ justify-content: center;
+}
+
+.action-button.danger {
+ background-color: var(--danger-color);
+ color: white;
+}
+
+.action-button.danger:hover {
+ background-color: #e03444;
+ box-shadow: 0 0 8px rgba(220, 53, 69, 0.5);
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .app-content {
+ padding: 15px;
+ }
+
+ body {
+ min-width: 320px;
+ }
+
+ .data-table th,
+ .data-table td {
+ padding: 8px 10px;
+ }
+
+ .features-list {
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+ }
+}
diff --git a/data-viewer/data-viewer.html b/data-viewer/data-viewer.html
new file mode 100644
index 0000000..12af92c
--- /dev/null
+++ b/data-viewer/data-viewer.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>ZenInternet - Data Viewer</title>
+ <link rel="stylesheet" href="../popup/popup.css">
+ <link rel="stylesheet" href="data-viewer.css">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+</head>
+
+<body>
+ <div class="container">
+ <header class="app-header">
+ <div class="logo-container">
+ <img src="../assets/images/logo_48.png" alt="ZenInternet Logo" class="logo-img">
+ <h1 class="app-title">ZenInternet Data Viewer</h1>
+ </div>
+ <div class="author">by <a href="https://www.sameerasw.com/" target="_blank">@sameerasw</a></div>
+ <div id="addon-version" class="addon-version"></div>
+ </header>
+
+ <main class="app-content">
+ <div class="data-section">
+ <h2 class="section-title">Global Settings</h2>
+ <div id="global-settings-data" class="data-container"></div>
+ </div>
+
+ <div class="data-section">
+ <h2 class="section-title">Skip/Enable List</h2>
+ <div id="skip-list-data" class="data-container"></div>
+ </div>
+
+ <div class="data-section">
+ <h2 class="section-title">Websites and CSS</h2>
+ <div id="combined-websites-data" class="data-container"></div>
+ </div>
+
+ <div class="actions">
+ <button id="back-button" class="action-button secondary">
+ <i class="fas fa-arrow-left"></i> Back to Extension
+ </button>
+ </div>
+
+ <div class="danger-zone">
+ <h3 class="danger-title">Danger Zone</h3>
+ <div class="danger-actions">
+ <button id="delete-all-data" class="action-button danger">
+ <i class="fas fa-trash"></i> Delete All Data
+ </button>
+ </div>
+ </div>
+ </main>
+
+ <footer class="app-footer">
+ <a href="https://sameerasw.github.io/my-internet/" class="footer-link" target="_blank">
+ <i class="fas fa-book"></i> Styles Repository
+ </a>
+ <div class="footer-divider"></div>
+ <a href="https://github.com/sameerasw/zeninternet" class="footer-link" target="_blank">
+ <i class="fa-brands fa-github"></i> Project Repository
+ </a>
+ </footer>
+ </div>
+ <script src="data-viewer.js"></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/data-viewer/data-viewer.js b/data-viewer/data-viewer.js
new file mode 100644
index 0000000..f7a7043
--- /dev/null
+++ b/data-viewer/data-viewer.js
@@ -0,0 +1,405 @@
+document.addEventListener("DOMContentLoaded", function () {
+ const BROWSER_STORAGE_KEY = "transparentZenSettings";
+ const SKIP_FORCE_THEMING_KEY = "skipForceThemingList";
+
+ const globalSettingsElement = document.getElementById("global-settings-data");
+ const skipListElement = document.getElementById("skip-list-data");
+ const combinedWebsitesElement = document.getElementById(
+ "combined-websites-data"
+ );
+ const backButton = document.getElementById("back-button");
+ const refreshButton = document.getElementById("refresh-data");
+ const deleteAllButton = document.getElementById("delete-all-data");
+ const versionElement = document.getElementById("addon-version");
+
+ // Load and display the data
+ loadAllData();
+
+ // Display addon version
+ displayAddonVersion();
+
+ // Event listener for the back button
+ backButton.addEventListener("click", function () {
+ window.close();
+ });
+
+ // Event listener for refresh button
+ refreshButton.addEventListener("click", function () {
+ loadAllData();
+ });
+
+ // Event listener for delete all data button
+ deleteAllButton.addEventListener("click", function() {
+ if (confirm("WARNING: This will delete ALL extension data including settings, website styles, and preferences. This action cannot be undone!\n\nAre you sure you want to proceed?")) {
+ deleteAllData();
+ }
+ });
+
+ async function deleteAllData() {
+ try {
+ // Clear all storage data
+ await browser.storage.local.clear();
+
+ // Show confirmation message
+ alert("All data has been deleted successfully. The page will now reload.");
+
+ // Reload the page to show empty state
+ window.location.reload();
+ } catch (error) {
+ console.error("Error deleting data:", error);
+ alert("An error occurred while trying to delete data: " + error.message);
+ }
+ }
+
+ async function displayAddonVersion() {
+ const manifest = browser.runtime.getManifest();
+ versionElement.textContent = `Version: ${manifest.version}`;
+ }
+
+ async function loadAllData() {
+ try {
+ // Load all data from storage
+ const data = await browser.storage.local.get(null);
+
+ // Display global settings
+ const globalSettings = data[BROWSER_STORAGE_KEY] || {};
+ displayGlobalSettings(globalSettings);
+
+ // Display skip/enable list
+ const skipList = data[SKIP_FORCE_THEMING_KEY] || [];
+ displaySkipList(skipList, globalSettings.whitelistMode);
+
+ // Display combined websites and settings
+ displayCombinedWebsiteData(data);
+
+ console.info("Data loaded successfully");
+ } catch (error) {
+ console.error("Error loading data:", error);
+ }
+ }
+
+ function displayGlobalSettings(settings) {
+ globalSettingsElement.innerHTML = "";
+
+ const table = document.createElement("table");
+ table.classList.add("data-table");
+
+ // Table header
+ const thead = document.createElement("thead");
+ const headerRow = document.createElement("tr");
+ headerRow.innerHTML = `<th>Setting</th><th>Value</th>`;
+ thead.appendChild(headerRow);
+ table.appendChild(thead);
+
+ // Table body
+ const tbody = document.createElement("tbody");
+
+ for (const [key, value] of Object.entries(settings)) {
+ // Skip lastFetchedTime as it will be formatted differently
+ if (key === "lastFetchedTime") continue;
+
+ const row = document.createElement("tr");
+ row.innerHTML = `
+ <td>${formatSettingName(key)}</td>
+ <td>${formatSettingValue(value)}</td>
+ `;
+ tbody.appendChild(row);
+ }
+
+ // Add last fetched time with formatted date if available
+ if (settings.lastFetchedTime) {
+ const row = document.createElement("tr");
+ row.innerHTML = `
+ <td>${formatSettingName("lastFetchedTime")}</td>
+ <td>${new Date(settings.lastFetchedTime).toLocaleString()}</td>
+ `;
+ tbody.appendChild(row);
+ }
+
+ table.appendChild(tbody);
+ globalSettingsElement.appendChild(table);
+ }
+
+ function displaySkipList(skipList, isWhitelistMode) {
+ skipListElement.innerHTML = "";
+
+ const modeType = isWhitelistMode ? "Whitelist" : "Blacklist";
+ const actionType = isWhitelistMode ? "Enabled" : "Skipped";
+
+ const modeInfo = document.createElement("div");
+ modeInfo.classList.add("mode-info");
+ modeInfo.innerHTML = `<strong>Current Mode:</strong> ${modeType} Mode - ${
+ isWhitelistMode
+ ? "Only apply forced styling to sites in the list"
+ : "Apply forced styling to all sites except those in the list"
+ }`;
+ skipListElement.appendChild(modeInfo);
+
+ // Add Clear List button
+ if (skipList.length > 0) {
+ const clearListButton = document.createElement("button");
+ clearListButton.classList.add("action-button", "secondary", "clear-list-button");
+ clearListButton.innerHTML = '<i class="fas fa-trash"></i> Clear List';
+ clearListButton.addEventListener("click", function() {
+ if (confirm(`Are you sure you want to clear the entire ${modeType} list? This will affect how styling is applied to websites.`)) {
+ clearSkipList();
+ }
+ });
+ skipListElement.appendChild(clearListButton);
+ }
+
+ if (skipList.length === 0) {
+ skipListElement.innerHTML +=
+ '<div class="no-data">No websites in the list.</div>';
+ return;
+ }
+
+ const table = document.createElement("table");
+ table.classList.add("data-table");
+
+ // Table header
+ const thead = document.createElement("thead");
+ const headerRow = document.createElement("tr");
+ headerRow.innerHTML = `<th>${actionType} Websites</th>`;
+ thead.appendChild(headerRow);
+ table.appendChild(thead);
+
+ // Table body
+ const tbody = document.createElement("tbody");
+
+ for (const site of skipList) {
+ const row = document.createElement("tr");
+ row.innerHTML = `<td>${site}</td>`;
+ tbody.appendChild(row);
+ }
+
+ table.appendChild(tbody);
+ skipListElement.appendChild(table);
+ }
+
+ async function clearSkipList() {
+ try {
+ await browser.storage.local.remove(SKIP_FORCE_THEMING_KEY);
+ alert(`${SKIP_FORCE_THEMING_KEY} has been cleared successfully.`);
+ loadAllData(); // Reload data to reflect changes
+ } catch (error) {
+ console.error("Error clearing skip list:", error);
+ alert("An error occurred while trying to clear the list: " + error.message);
+ }
+ }
+
+ function displayCombinedWebsiteData(data) {
+ combinedWebsitesElement.innerHTML = "";
+
+ const styles = data.styles || {};
+ const websites = styles.website || {};
+ const websiteKeys = Object.keys(websites);
+
+ // Find all site-specific settings
+ const siteSettings = {};
+ for (const [key, value] of Object.entries(data)) {
+ if (key.startsWith(BROWSER_STORAGE_KEY + ".")) {
+ const siteName = key.substring(BROWSER_STORAGE_KEY.length + 1);
+ siteSettings[siteName] = value;
+ }
+ }
+
+ if (websiteKeys.length === 0) {
+ combinedWebsitesElement.innerHTML =
+ '<div class="no-data">No websites found. Try fetching styles first.</div>';
+ return;
+ }
+
+ // Create search filter
+ const searchContainer = document.createElement("div");
+ searchContainer.classList.add("search-container");
+
+ const searchInput = document.createElement("input");
+ searchInput.type = "text";
+ searchInput.placeholder = "Search websites...";
+ searchInput.classList.add("search-input");
+ searchInput.addEventListener("input", function () {
+ filterWebsites(this.value.toLowerCase());
+ });
+
+ const searchIcon = document.createElement("i");
+ searchIcon.className = "fas fa-search search-icon";
+
+ searchContainer.appendChild(searchIcon);
+ searchContainer.appendChild(searchInput);
+
+ combinedWebsitesElement.appendChild(searchContainer);
+
+ // Create expand all button
+ const expandAllButton = document.createElement("button");
+ expandAllButton.classList.add(
+ "action-button",
+ "secondary",
+ "view-all-button"
+ );
+ expandAllButton.textContent = "Expand All";
+ expandAllButton.addEventListener("click", function () {
+ const expanded = this.textContent === "Collapse All";
+ const panels = document.querySelectorAll(".website-panel");
+
+ panels.forEach((panel) => {
+ const header = panel.querySelector(".website-header");
+ const content = panel.querySelector(".website-content");
+
+ if (expanded) {
+ header.classList.remove("active");
+ content.style.maxHeight = null;
+
+ // Also collapse all CSS blocks
+ content.querySelectorAll(".css-block-header").forEach((cssHeader) => {
+ cssHeader.classList.remove("active");
+ const cssContent = cssHeader.nextElementSibling;
+ if (cssContent) cssContent.style.maxHeight = null;
+ });
+ } else {
+ header.classList.add("active");
+ content.style.maxHeight = content.scrollHeight + "px";
+ }
+ });
+
+ this.textContent = expanded ? "Expand All" : "Collapse All";
+ });
+
+ combinedWebsitesElement.appendChild(expandAllButton);
+
+ const websitesContainer = document.createElement("div");
+ websitesContainer.classList.add("websites-container");
+ combinedWebsitesElement.appendChild(websitesContainer);
+
+ // Sort websites alphabetically
+ websiteKeys.sort();
+
+ // Create panels for each website
+ for (const website of websiteKeys) {
+ const websitePanel = document.createElement("div");
+ websitePanel.classList.add("website-panel");
+ websitePanel.dataset.website = website.toLowerCase();
+
+ const header = document.createElement("div");
+ header.classList.add("website-header");
+
+ // Create website name with feature count
+ const features = websites[website];
+ const featureCount = Object.keys(features).length;
+
+ // Get site settings if available
+ const siteName = website.replace(".css", "");
+ const domainName = siteName.startsWith("+")
+ ? siteName.slice(1)
+ : siteName;
+ const settingsData =
+ siteSettings[domainName] || siteSettings[`www.${domainName}`] || {};
+
+ header.innerHTML = `
+ <div class="website-header-content">
+ <span class="website-name">${website}</span>
+ <span class="feature-count">${featureCount} features</span>
+ </div>
+ `;
+
+ header.addEventListener("click", function () {
+ this.classList.toggle("active");
+ const content = this.nextElementSibling;
+ if (content.style.maxHeight) {
+ content.style.maxHeight = null;
+ } else {
+ content.style.maxHeight = content.scrollHeight + "px";
+ }
+ });
+
+ const content = document.createElement("div");
+ content.classList.add("website-content");
+
+ // Create CSS blocks for each feature
+ for (const [feature, css] of Object.entries(features)) {
+ const cssBlock = document.createElement("div");
+ cssBlock.classList.add("css-block");
+
+ // Get the feature's enabled status from site settings
+ const isEnabled = settingsData[feature] !== false; // true by default
+
+ // Create the block header with feature name and status
+ const cssBlockHeader = document.createElement("div");
+ cssBlockHeader.classList.add("css-block-header");
+ cssBlockHeader.innerHTML = `
+ <span class="feature-name">${feature}</span>
+ <span class="feature-status ${isEnabled ? "enabled" : "disabled"}">${
+ isEnabled ? "Enabled" : "Disabled"
+ }</span>
+ `;
+
+ // Make the CSS block header toggleable
+ cssBlockHeader.addEventListener("click", function (e) {
+ // Don't expand if clicking on status badge
+ if (e.target.classList.contains("feature-status")) return;
+
+ this.classList.toggle("active");
+ const cssContent = this.nextElementSibling;
+ if (cssContent.style.maxHeight) {
+ cssContent.style.maxHeight = null;
+ } else {
+ cssContent.style.maxHeight = cssContent.scrollHeight + "px";
+ }
+ });
+
+ // Create the CSS content area
+ const cssContent = document.createElement("div");
+ cssContent.classList.add("css-content");
+
+ const cssCode = document.createElement("pre");
+ cssCode.classList.add("css-code");
+ cssCode.textContent = css;
+ cssContent.appendChild(cssCode);
+
+ cssBlock.appendChild(cssBlockHeader);
+ cssBlock.appendChild(cssContent);
+ content.appendChild(cssBlock);
+ }
+
+ websitePanel.appendChild(header);
+ websitePanel.appendChild(content);
+ websitesContainer.appendChild(websitePanel);
+ }
+
+ // Filter function for search
+ function filterWebsites(query) {
+ const panels = websitesContainer.querySelectorAll(".website-panel");
+
+ panels.forEach((panel) => {
+ const website = panel.dataset.website;
+ if (website.includes(query)) {
+ panel.style.display = "";
+ } else {
+ panel.style.display = "none";
+ }
+ });
+ }
+ }
+
+ // Helper Functions
+ function formatSettingName(name) {
+ // Convert camelCase to Title Case with spaces
+ return name
+ .replace(/([A-Z])/g, " $1")
+ .replace(/^./, (str) => str.toUpperCase());
+ }
+
+ function formatSettingValue(value) {
+ if (typeof value === "boolean") {
+ return value
+ ? '<span class="badge enabled">Enabled</span>'
+ : '<span class="badge disabled">Disabled</span>';
+ } else if (value === null) {
+ return '<span class="null-value">null</span>';
+ } else if (typeof value === "object") {
+ return '<span class="object-value">{Object}</span>';
+ } else {
+ return value;
+ }
+ }
+});
diff --git a/manifest.json b/manifest.json
index 356ff24..92a8578 100644
--- a/manifest.json
+++ b/manifest.json
@@ -33,5 +33,10 @@
"js": ["inject-css.js"],
"run_at": "document_start"
}
+ ],
+ "web_accessible_resources": [
+ "data-viewer/data-viewer.html",
+ "data-viewer/data-viewer.js",
+ "data-viewer/data-viewer.css"
]
}
diff --git a/popup/popup.html b/popup/popup.html
index 8ffa03d..1c5c84c 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -87,6 +87,12 @@
</div>
</div>
+ <div class="actions">
+ <button id="view-data" class="action-button secondary">
+ <i class="fas fa-database"></i> View All Stored Data
+ </button>
+ </div>
+
</main>
diff --git a/popup/popup.js b/popup/popup.js
index d81ed7d..82fc942 100644
--- a/popup/popup.js
+++ b/popup/popup.js
@@ -54,6 +54,13 @@ new (class ExtensionPopup {
this.handleWhitelistModeChange.bind(this)
);
+ // Add event listener for the data viewer button
+ document.getElementById("view-data")?.addEventListener("click", () => {
+ browser.tabs.create({
+ url: browser.runtime.getURL("data-viewer/data-viewer.html"),
+ });
+ });
+
// Setup auto-update and display last fetched time
this.setupAutoUpdate();
this.displayLastFetchedTime();