Skip to content

Commit 811b030

Browse files
committed
fix: debounce source toggle searches
1 parent 6fa7156 commit 811b030

4 files changed

Lines changed: 34 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ All notable changes to ScriptHunt will be documented in this file.
1414
- Propagated each search AbortSignal through direct, proxy, GitHub code, and custom-source requests so replacement searches cancel network work instead of only ignoring late results.
1515
- Removed Google Fonts runtime requests by vendoring OFL-licensed Outfit and JetBrains Mono WOFF2 assets and adding them to the offline shell cache.
1616
- Stale-while-revalidate assets now compare ETags, modification metadata, or SHA-256 body fingerprints and show one actionable reload notice when cached content changes.
17+
- Rapid source-toggle changes now coalesce into one replacement search while checkbox state and preferences update immediately.
1718

1819
### Added
1920
- Added versioned source result envelopes and visible per-source provenance for partiality, pagination, latency, cache use, privacy route, HTTP status, and normalized failures.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ npm run qa
6666
| **Source Health** | Persists failing source cooldowns with retry controls and versioned per-source provenance for partiality, route, latency, HTTP status, and cache use |
6767
| **Offline Recent Searches** | Versioned records preserve source route, status, partiality, errors, and scan age/hash evidence; legacy IndexedDB/localStorage records reconcile by newest valid copy |
6868
| **Cache Diagnostics** | Shows offline/scan cache counts, schema and eviction state, browser quota estimates, and independent cache-clear recovery controls |
69-
| **Source Toggles** | Enable/disable sources with preferences persisted across sessions |
69+
| **Source Toggles** | Enable/disable sources with preferences persisted across sessions; rapid changes coalesce into one replacement search |
7070
| **Live Status Chips** | Real-time per-source indicators with partial-result reasons, search mode, privacy route, latency, cache use, and suspension status |
7171
| **Sort Controls** | Sort by relevance, trust score, total/daily installs, rating, last updated, or name |
7272
| **Infinite Scroll** | Automatic pagination fetches next page from all active sources |

index.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4002,6 +4002,15 @@ <h3>Search userscripts everywhere</h3>
40024002
panel.innerHTML = '';
40034003
}
40044004

4005+
var sourceToggleDebounce = null;
4006+
function scheduleSourceToggleSearch() {
4007+
clearTimeout(sourceToggleDebounce);
4008+
sourceToggleDebounce = setTimeout(function() {
4009+
sourceToggleDebounce = null;
4010+
if (state.rawQuery) executeSearch(state.rawQuery);
4011+
}, 300);
4012+
}
4013+
40054014
function renderSourceToggles() {
40064015
var bar = document.getElementById('sourcesBar'); bar.innerHTML = '';
40074016
Object.values(SOURCES).forEach(function(src) {
@@ -4015,7 +4024,7 @@ <h3>Search userscripts everywhere</h3>
40154024
src.enabled = !src.enabled; el.classList.toggle('active', src.enabled);
40164025
el.setAttribute('aria-checked', String(src.enabled));
40174026
var sp = {}; Object.keys(SOURCES).forEach(function(k) { sp[k] = SOURCES[k].enabled; }); _prefSet('sources', sp);
4018-
if (state.rawQuery) executeSearch(state.rawQuery);
4027+
if (state.rawQuery) scheduleSourceToggleSearch();
40194028
}
40204029
el.addEventListener('click', toggle);
40214030
el.addEventListener('keydown', function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); } });

tests/smoke.spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,28 @@ test('source toggles are keyboard accessible', async ({ page }) => {
277277
await expect(toggle).toHaveAttribute('aria-checked', 'false');
278278
});
279279

280+
test('rapid source toggles coalesce into one replacement search', async ({ page }) => {
281+
await page.goto('/');
282+
await runSearch(page, 'youtube');
283+
await page.evaluate(() => {
284+
window.__sourceToggleSearches = 0;
285+
const original = executeSearch;
286+
executeSearch = function(...args) {
287+
window.__sourceToggleSearches += 1;
288+
return original.apply(this, args);
289+
};
290+
});
291+
292+
const toggle = page.getByLabel('Greasy Fork source');
293+
await toggle.click();
294+
await toggle.click();
295+
await toggle.click();
296+
await toggle.click();
297+
await expect(toggle).toHaveAttribute('aria-checked', 'true');
298+
expect(await page.evaluate(() => window.__sourceToggleSearches)).toBe(0);
299+
await expect.poll(() => page.evaluate(() => window.__sourceToggleSearches)).toBe(1);
300+
});
301+
280302
test('theme toggle cycles through modes', async ({ page }) => {
281303
await page.goto('/');
282304
const btn = page.locator('#themeToggle');

0 commit comments

Comments
 (0)