fix: PPI + button replaces text immediately; add auto-sync folder
PPI + button fix: - After adding a mapping, the real PPI value is now immediately replaced with the fake value in the input/contenteditable element via the new replaceInInput() helper (handles both <textarea>/<input> and contenteditable divs by walking text nodes). - Triggers a re-scan 150ms later so the pre-send warning updates or dismisses itself if no more PPI remains. Auto-sync folder (File System Access API): - User picks a folder once per browser via "Choose Sync Folder". Any settings/mappings/identity change writes silent-send-sync.json to that folder automatically (via api.storage.onChanged listener). - On options page open and every time the page regains focus, the file is read back; if its lastModified is newer than local data, settings are imported immediately and the UI refreshes. - File handle is stored in IndexedDB (ss_sync_handles) so it persists across browser sessions without repeated permission prompts. - Pick the SAME folder in each browser (or a synced cloud folder for cross-computer sync) — fully automatic after that, no copy-paste. - sync.js gains saveSyncDirHandle / loadSyncDirHandle / clearSyncDirHandle helpers backed by IndexedDB. https://claude.ai/code/session_01TKpSR9M8JgHLXCp5CeDsQP
This commit is contained in:
+30
-1
@@ -1134,9 +1134,17 @@
|
||||
});
|
||||
await setStorageData('ss_mappings', currentMappings);
|
||||
|
||||
// Update local mappings
|
||||
// Update local mappings so the fetch interceptor uses them immediately
|
||||
mappings = currentMappings;
|
||||
|
||||
// Replace the PPI value in the current input right now
|
||||
if (inputEl) {
|
||||
replaceInInput(inputEl, real, fake);
|
||||
// Re-scan — will dismiss warning if no more PPI remains
|
||||
if (inputScanTimer) clearTimeout(inputScanTimer);
|
||||
inputScanTimer = setTimeout(() => scanInputForPPI(inputEl), 150);
|
||||
}
|
||||
|
||||
// Visual feedback
|
||||
btn.textContent = '\u2714';
|
||||
btn.style.color = '#4ade80';
|
||||
@@ -1145,6 +1153,27 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Replace all occurrences of `real` with `fake` in an input or contenteditable element
|
||||
function replaceInInput(el, real, fake) {
|
||||
if (!el) return;
|
||||
const re = new RegExp(real.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
|
||||
if (el.value !== undefined) {
|
||||
// <textarea> or <input>
|
||||
el.value = el.value.replace(re, fake);
|
||||
} else if (el.isContentEditable) {
|
||||
// contenteditable div — walk text nodes to avoid breaking inner HTML
|
||||
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
|
||||
let node;
|
||||
while ((node = walker.nextNode())) {
|
||||
re.lastIndex = 0;
|
||||
if (re.test(node.textContent)) {
|
||||
re.lastIndex = 0;
|
||||
node.textContent = node.textContent.replace(re, fake);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Storage helpers for page world (uses postMessage to injector)
|
||||
function getStorageData(key) {
|
||||
return new Promise(resolve => {
|
||||
|
||||
Reference in New Issue
Block a user