Files
weval-l99/v129_url_state.py
2026-04-24 04:38:58 +02:00

117 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""V129 - Persist sort + active filter in URL hash (bookmarkable full state)"""
path = "/var/www/html/all-ia-hub.html"
with open(path, "r", encoding="utf-8") as f:
c = f.read()
if "V129-URL-STATE" in c:
print("ALREADY")
exit(0)
# Add URL state helpers next to __dashPins
marker = "function __dashTogglePin(name){"
addition = '''// V129-URL-STATE: persist sort + active filter (category) in URL hash
function __dashHashGet(key){
return new URLSearchParams(window.location.hash.slice(1)).get(key) || '';
}
function __dashHashSet(key, val){
const params = new URLSearchParams(window.location.hash.slice(1));
if (val) params.set(key, val);
else params.delete(key);
const h = params.toString();
window.history.replaceState(null, '', window.location.pathname + window.location.search + (h ? '#'+h : ''));
}
''' + marker
assert marker in c, "marker missing"
c = c.replace(marker, addition, 1)
# Hook sort change to save in URL
sort_listener = "if (sort) sort.addEventListener('change', rerender);"
new_sort_listener = """if (sort) {
// V129: restore sort from URL on init
const savedSort = __dashHashGet('sort');
if (savedSort && ['name','size','mtime','category'].includes(savedSort)) sort.value = savedSort;
sort.addEventListener('change', () => { __dashHashSet('sort', sort.value === 'name' ? '' : sort.value); rerender(); });
}"""
if sort_listener in c:
c = c.replace(sort_listener, new_sort_listener, 1)
# Hook filter click to save active cat
filter_click = """b.addEventListener('click', () => {
box.querySelectorAll('.dash-filter').forEach(x => x.classList.remove('on'));
b.classList.add('on');
renderDashGrid(__dashData.dashboards, b.getAttribute('data-cat'));
});"""
new_filter_click = """b.addEventListener('click', () => {
box.querySelectorAll('.dash-filter').forEach(x => x.classList.remove('on'));
b.classList.add('on');
const cat = b.getAttribute('data-cat');
__dashHashSet('cat', cat === 'all' ? '' : cat); /* V129: persist */
renderDashGrid(__dashData.dashboards, cat);
});"""
if filter_click in c:
c = c.replace(filter_click, new_filter_click, 1)
# Restore filter on load (in renderDashFilters, after initial render)
# Inside renderDashFilters, add restoration logic at the end of the forEach
old_finish = """ box.querySelectorAll('.dash-filter').forEach(b => {
b.addEventListener('click', () => {
box.querySelectorAll('.dash-filter').forEach(x => x.classList.remove('on'));
b.classList.add('on');
const cat = b.getAttribute('data-cat');
__dashHashSet('cat', cat === 'all' ? '' : cat); /* V129: persist */
renderDashGrid(__dashData.dashboards, cat);
});
});
}"""
new_finish = """ box.querySelectorAll('.dash-filter').forEach(b => {
b.addEventListener('click', () => {
box.querySelectorAll('.dash-filter').forEach(x => x.classList.remove('on'));
b.classList.add('on');
const cat = b.getAttribute('data-cat');
__dashHashSet('cat', cat === 'all' ? '' : cat); /* V129: persist */
renderDashGrid(__dashData.dashboards, cat);
});
});
/* V129: restore active filter from URL */
const savedCat = __dashHashGet('cat');
if (savedCat) {
const target = box.querySelector('button[data-cat="' + savedCat + '"]');
if (target) {
box.querySelectorAll('.dash-filter').forEach(x => x.classList.remove('on'));
target.classList.add('on');
}
}
}"""
if old_finish in c:
c = c.replace(old_finish, new_finish, 1)
# Also: loadDashboards should pass saved cat to renderDashGrid
old_load = """ renderDashStats(d);
renderDashFilters(d);
renderDashGrid(d.dashboards, 'all');"""
new_load = """ renderDashStats(d);
renderDashFilters(d);
/* V129: restore active filter */
const savedCat = __dashHashGet('cat') || 'all';
renderDashGrid(d.dashboards, savedCat);"""
if old_load in c:
c = c.replace(old_load, new_load, 1)
# Same for loadDashboardsStatus
old_load2 = "renderDashGrid(d.dashboards, document.querySelector('.dash-filter.on')?.getAttribute('data-cat') || 'all');"
# already uses active filter - OK
with open(path, "w", encoding="utf-8") as f:
f.write(c)
print(f"PATCHED size={len(c)}")