Skip to content

Commit cc1d612

Browse files
committed
clean up our script
remove tabs and windows API listeners, added error handling, fixed migration race condition and empty catch blocks
1 parent bee7e70 commit cc1d612

1 file changed

Lines changed: 137 additions & 41 deletions

File tree

src/script.js

Lines changed: 137 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,74 @@ const els = {
1010
status: document.getElementById("save-status"),
1111
};
1212

13-
// Storage Wrapper
13+
// Detect browser API (browser vs chrome)
14+
const browserAPI = typeof browser !== "undefined" ? browser : chrome;
15+
16+
// Storage Wrapper - now uses browser.storage.sync with proper error handling
1417
const store = {
18+
get: (key, callback) => {
19+
const handleError = (error) => {
20+
if (error) {
21+
console.error("Storage get error:", error);
22+
els.status.textContent = "Error loading";
23+
}
24+
};
25+
26+
if (typeof callback === "function") {
27+
// Chrome-style callback with error handling
28+
browserAPI.storage.sync.get([key], (result) => {
29+
if (browserAPI.runtime.lastError) {
30+
handleError(browserAPI.runtime.lastError);
31+
return;
32+
}
33+
callback(result);
34+
});
35+
} else {
36+
// Promise-style (Firefox) with error handling
37+
return browserAPI.storage.sync.get([key]).catch(handleError);
38+
}
39+
},
40+
set: (key, value, callback) => {
41+
const data = {};
42+
data[key] = value;
43+
44+
const handleError = (error) => {
45+
if (error) {
46+
console.error("Storage set error:", error);
47+
els.status.textContent = "Error saving";
48+
els.status.classList.remove("saved");
49+
}
50+
};
51+
52+
if (typeof callback === "function") {
53+
browserAPI.storage.sync.set(data, () => {
54+
if (browserAPI.runtime.lastError) {
55+
handleError(browserAPI.runtime.lastError);
56+
return;
57+
}
58+
callback();
59+
});
60+
} else {
61+
browserAPI.storage.sync.set(data).catch(handleError);
62+
}
63+
},
64+
};
65+
66+
// LocalStorage fallback (for theme/font settings that don't need sync)
67+
const localStore = {
1568
get: (k) => {
1669
try {
1770
return localStorage.getItem(k);
18-
} catch (e) {}
71+
} catch (e) {
72+
console.error("LocalStorage get error:", e);
73+
}
1974
},
2075
set: (k, v) => {
2176
try {
2277
localStorage.setItem(k, v);
23-
} catch (e) {}
78+
} catch (e) {
79+
console.error("LocalStorage set error:", e);
80+
}
2481
},
2582
};
2683

@@ -29,7 +86,7 @@ const toggleTheme = () => {
2986
const next =
3087
els.html.getAttribute("data-theme") === "dark" ? "light" : "dark";
3188
els.html.setAttribute("data-theme", next);
32-
store.set("theme", next);
89+
localStore.set("theme", next);
3390
els.toggleTheme.setAttribute(
3491
"aria-label",
3592
`Switch to ${next === "dark" ? "light" : "dark"}`
@@ -50,7 +107,7 @@ const updateFontSize = (val) => {
50107
const size = `${val}px`;
51108
els.html.style.setProperty("--note-size", size);
52109
els.fontDisplay.textContent = size;
53-
store.set("fontsize", size);
110+
localStore.set("fontsize", size);
54111
};
55112

56113
// Menu Listeners
@@ -85,54 +142,93 @@ const save = (text) => {
85142
els.status.classList.remove("saved");
86143
clearTimeout(timeout);
87144
timeout = setTimeout(() => {
88-
store.set("notekeeper_content", text);
89-
els.status.textContent = "Saved";
90-
els.status.classList.add("saved");
145+
store.set("notekeeper_content", text, () => {
146+
// Only update UI on success (error handling is in store.set)
147+
els.status.textContent = "Saved";
148+
els.status.classList.add("saved");
149+
});
91150
}, 500);
92151
};
93152

94-
// Migration Logic (Legacy Chrome Storage -> LocalStorage)
95-
const migrateFromExtension = () => {
96-
// If we already have data in the new system, do not overwrite
97-
if (store.get("notekeeper_content")) return;
98-
99-
// Detect extension environment
100-
const ext =
101-
typeof browser !== "undefined"
102-
? browser
103-
: typeof chrome !== "undefined"
104-
? chrome
105-
: null;
106-
107-
if (ext && ext.storage && ext.storage.sync) {
108-
ext.storage.sync.get(["tab_note"], (result) => {
109-
// Check if legacy data exists
110-
if (result && result.tab_note) {
111-
// Save to new storage
112-
store.set("notekeeper_content", result.tab_note);
113-
114-
// Update UI immediately
115-
els.note.value = result.tab_note;
116-
updateStats(result.tab_note);
153+
// Listen for storage changes from other tabs/extensions
154+
// This keeps notes in sync across multiple tabs
155+
browserAPI.storage.onChanged.addListener((changes, area) => {
156+
if (area === "sync" && changes.notekeeper_content) {
157+
const newValue = changes.notekeeper_content.newValue;
158+
if (newValue !== undefined && newValue !== els.note.value) {
159+
els.note.value = newValue;
160+
updateStats(newValue);
161+
els.status.textContent = "Synced";
162+
els.status.classList.add("saved");
163+
}
164+
}
165+
});
166+
167+
// Refresh when the page gains visibility (e.g., switching back to tab)
168+
// This handles tab switching without requiring tabs permission
169+
document.addEventListener("visibilitychange", () => {
170+
if (!document.hidden) {
171+
store.get("notekeeper_content", (result) => {
172+
if (result && result.notekeeper_content) {
173+
els.note.value = result.notekeeper_content;
174+
updateStats(result.notekeeper_content);
117175
els.status.textContent = "Restored";
118176
els.status.classList.add("saved");
119177
}
120178
});
121179
}
180+
});
181+
182+
// Initialize - load from sync storage and run migration if needed
183+
// Combined into single operation to avoid race condition
184+
const initializeNotes = () => {
185+
store.get("notekeeper_content", (syncResult) => {
186+
if (syncResult && syncResult.notekeeper_content) {
187+
// We have data in sync storage, load it
188+
els.note.value = syncResult.notekeeper_content;
189+
updateStats(syncResult.notekeeper_content);
190+
els.status.textContent = "Restored";
191+
els.status.classList.add("saved");
192+
return;
193+
}
194+
195+
// No sync data, check for localStorage migration
196+
const localContent = localStore.get("notekeeper_content");
197+
if (localContent) {
198+
console.log("Migrating notes from localStorage to sync storage...");
199+
store.set("notekeeper_content", localContent, () => {
200+
els.note.value = localContent;
201+
updateStats(localContent);
202+
els.status.textContent = "Migrated";
203+
els.status.classList.add("saved");
204+
});
205+
return;
206+
}
207+
208+
// Check for legacy tab_note (from original extension)
209+
browserAPI.storage.sync.get(["tab_note"], (legacyResult) => {
210+
if (browserAPI.runtime.lastError) {
211+
console.error("Legacy storage check error:", browserAPI.runtime.lastError);
212+
return;
213+
}
214+
215+
if (legacyResult && legacyResult.tab_note) {
216+
console.log("Migrating notes from legacy tab_note to notekeeper_content...");
217+
store.set("notekeeper_content", legacyResult.tab_note, () => {
218+
els.note.value = legacyResult.tab_note;
219+
updateStats(legacyResult.tab_note);
220+
els.status.textContent = "Restored";
221+
els.status.classList.add("saved");
222+
});
223+
}
224+
});
225+
});
122226
};
123227

124-
// Init Content
125-
const content = store.get("notekeeper_content");
126-
if (content) {
127-
els.note.value = content;
128-
updateStats(content);
129-
} else {
130-
// Only attempt migration if new storage is empty
131-
migrateFromExtension();
132-
}
228+
initializeNotes();
133229

134230
// Init Font Size
135-
const storedFontSize = store.get("fontsize");
231+
const storedFontSize = localStore.get("fontsize");
136232
if (storedFontSize) {
137233
const val = parseInt(storedFontSize);
138234
els.slider.value = val;

0 commit comments

Comments
 (0)