From adf86104de89b0d710fbf64ff317ef455ab98df7 Mon Sep 17 00:00:00 2001
From: mdtaufiquekhan
Date: Tue, 20 May 2025 02:44:24 +0530
Subject: [PATCH] Add import/export feature for extension profiles
---
README.md | 4 ++
TODO.md | 6 ++-
js/importExport.js | 89 +++++++++++++++++++++++++++++++++++++++++
profiles.html | 12 ++++++
styles/importExport.css | 7 ++++
5 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 js/importExport.js
create mode 100644 styles/importExport.css
diff --git a/README.md b/README.md
index 193e1f8..8908a7a 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,10 @@ Follow us in Twitter: [@ExtensityChrome](https://twitter.com/ExtensityChrome)
### What's new:
+v1.15.0 (May 2025)
+- **New Feature**: Import/Export extension profiles as `.json` files.
+- Allows users to back up and restore profile settings.
+
v1.14.0 (Sep 2024)
- **New Feature**: Dark Mode (based on system settings)
- Migrated from CSSO to SASS
diff --git a/TODO.md b/TODO.md
index c18fa3f..34c101d 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,4 +1,8 @@
## Extensity TO-DOs
-- Allow import and export of profiles configuration
- Dark mode
+- [ ] Implement automatic sync with Chrome profile
+ - Keep manual import/export functionality for advanced users or backups
+ - Enable seamless syncing of profiles using `chrome.storage.sync`
+ - Profiles should automatically back up and restore across devices
+ - Add toggle option in settings to enable/disable auto-sync
\ No newline at end of file
diff --git a/js/importExport.js b/js/importExport.js
new file mode 100644
index 0000000..a102d6f
--- /dev/null
+++ b/js/importExport.js
@@ -0,0 +1,89 @@
+// Wait for the DOM to fully load before attaching event listeners
+document.addEventListener('DOMContentLoaded', () => {
+
+ // 🔹 EXPORT PROFILES FROM chrome.storage.sync
+ const exportBtn = document.getElementById('exportSettings');
+ if (exportBtn) {
+ exportBtn.addEventListener('click', () => {
+
+ // Fetch 'profiles' from Chrome's sync storage
+ chrome.storage.sync.get(['profiles'], (data) => {
+
+ // If no profiles exist, alert the user and exit
+ if (!data.profiles || Object.keys(data.profiles).length === 0) {
+ alert('!No profiles found to export.');
+ return;
+ }
+
+ // Convert profiles data to a JSON blob
+ const blob = new Blob(
+ [JSON.stringify(data.profiles, null, 2)],
+ { type: 'application/json' }
+ );
+
+ // Create a temporary download link for the JSON file
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ const dateStr = new Date().toISOString().split('T')[0];
+ a.href = url;
+ a.download = `extensity-profiles-${dateStr}.json`; // Dynamic filename
+ a.click(); // Trigger the download
+ URL.revokeObjectURL(url); // Clean up the URL
+ });
+ });
+ }
+
+ // 🔹 TRIGGER IMPORT FILE SELECTOR
+ const importBtn = document.getElementById('importSettings');
+ if (importBtn) {
+ importBtn.addEventListener('click', () => {
+ // Simulate a click on the hidden file input
+ document.getElementById('importFile').click();
+ });
+ }
+
+ // 🔹 HANDLE FILE INPUT CHANGE (IMPORT PROFILES)
+ const importFileInput = document.getElementById('importFile');
+ if (importFileInput) {
+ importFileInput.addEventListener('change', (event) => {
+ const file = event.target.files[0];
+ if (!file) return; // Exit if no file is selected
+
+ const reader = new FileReader();
+
+ // When file is successfully read
+ reader.onload = function (e) {
+ try {
+ const importedProfiles = JSON.parse(e.target.result);
+
+ // Validate the imported data
+ if (!importedProfiles || typeof importedProfiles !== 'object') {
+ alert('! Invalid or corrupt file.');
+ return;
+ }
+
+ // Save imported profiles into Chrome's sync storage
+ chrome.storage.sync.set({ profiles: importedProfiles }, () => {
+
+ // Show a success message in the UI, if available
+ const msg = document.getElementById('save-result');
+ if (msg) {
+ msg.classList.remove('hidden');
+ msg.textContent = '| Profiles imported!';
+ setTimeout(() => msg.classList.add('hidden'), 3000);
+ } else {
+ alert(':) Profiles imported! Please reload Extensity.');
+ }
+ });
+
+ } catch (err) {
+ // Handle JSON parsing errors
+ alert('! Failed to parse JSON file.');
+ }
+ };
+
+ // Start reading the file as text
+ reader.readAsText(file);
+ });
+ }
+});
diff --git a/profiles.html b/profiles.html
index fa7e31c..da6dac1 100644
--- a/profiles.html
+++ b/profiles.html
@@ -3,6 +3,9 @@
Extensity Profiles
+
+
+
@@ -10,6 +13,8 @@
+
+
+
+
+
+
+
+
+
diff --git a/styles/importExport.css b/styles/importExport.css
new file mode 100644
index 0000000..dd1b163
--- /dev/null
+++ b/styles/importExport.css
@@ -0,0 +1,7 @@
+#backup-tools{
+ margin-top: 10px;
+}
+
+#backup-tools button{
+margin-bottom: 5px;
+}
\ No newline at end of file