auto-save: settings save on change via /style/field, noscript fallback button

This commit is contained in:
blankie 2026-06-14 08:46:21 +00:00
parent 076390cbee
commit a72de2bb10
2 changed files with 50 additions and 4 deletions

View file

@ -32,7 +32,7 @@ from .subscriptions import (
handle_subscription_delete, handle_subscription_syncall, handle_subscription_delete, handle_subscription_syncall,
_sync_threads, _sync_threads,
) )
from .customize import handle_style_form, handle_style_submit, handle_style_template_submit, handle_about from .customize import handle_style_form, handle_style_submit, handle_style_template_submit, handle_field_save, handle_about
from .tags import handle_tags, handle_tag_browse from .tags import handle_tags, handle_tag_browse
from .data import ( from .data import (
handle_export, handle_import_form, handle_import_submit, handle_export, handle_import_form, handle_import_submit,
@ -125,6 +125,8 @@ def _dispatch_inner(data):
return handle_style_submit(body, gateway_host=gateway_host, scheme=scheme) return handle_style_submit(body, gateway_host=gateway_host, scheme=scheme)
elif path == "/style/template": elif path == "/style/template":
return handle_style_template_submit(body, gateway_host=gateway_host, scheme=scheme) return handle_style_template_submit(body, gateway_host=gateway_host, scheme=scheme)
elif path == "/style/field":
return handle_field_save(body)
elif path == "/style/reset": elif path == "/style/reset":
set_setting("custom_template", "") set_setting("custom_template", "")
return handle_style_form("Template reset to default.", gateway_host=gateway_host, scheme=scheme) return handle_style_form("Template reset to default.", gateway_host=gateway_host, scheme=scheme)

View file

@ -1,7 +1,7 @@
from db import get_db, return_db, get_setting, set_setting, get_site_name from db import get_db, return_db, get_setting, set_setting, get_site_name
import templates as templates_mod import templates as templates_mod
from templates import esc, DEFAULT_TEMPLATE from templates import esc, DEFAULT_TEMPLATE
from ._helpers import _respond, _csrf_field, _get_bookmark_token from ._helpers import _respond, _json_response, _csrf_field, _get_bookmark_token
from .subscriptions import _count_shared_pages from .subscriptions import _count_shared_pages
@ -54,7 +54,7 @@ def handle_style_form(msg="", gateway_host="", scheme="http"):
return _respond( return _respond(
f"<h1>customize</h1>" f"<h1>customize</h1>"
f"<h2>name your search engine</h2>" f"<h2>name your search engine</h2>"
f'<form method="post" action="/style">' f'<form method="post" action="/style" id="settings">'
f'{_csrf_field()}' f'{_csrf_field()}'
f'<input name="site_name" value="{esc(name)}" placeholder="tinyweb" size="30"><br><br>' f'<input name="site_name" value="{esc(name)}" placeholder="tinyweb" size="30"><br><br>'
f"<h2>sharing</h2>" f"<h2>sharing</h2>"
@ -127,8 +127,26 @@ def handle_style_form(msg="", gateway_host="", scheme="http"):
f'<a href="/reindex">manage semantic index</a><br><br>' f'<a href="/reindex">manage semantic index</a><br><br>'
f"</div>" f"</div>"
f"{forum_section}" f"{forum_section}"
f'<button type="submit">save settings</button>' f'<p id="settings-status" style="font-size:0.85rem;color:#888;min-height:1.2em"></p>'
f'<noscript><button type="submit">save settings</button></noscript>'
f"</form>" f"</form>"
'<script>'
'(function(){'
"var f=document.getElementById('settings');"
"var csrf=f.querySelector('input[name=_csrf]').value;"
"var st=document.getElementById('settings-status');"
"f.querySelectorAll('input:not([type=hidden]):not([type=submit]),select').forEach(function(el){"
"el.addEventListener('change',function(){"
"var key=el.name,val=el.type=='checkbox'?(el.checked?'1':'0'):el.value;"
"st.textContent='saving...';"
"fetch('/style/field',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},"
"body:'_csrf='+encodeURIComponent(csrf)+'&key='+encodeURIComponent(key)+'&value='+encodeURIComponent(val)})"
".then(function(r){return r.json()})"
".then(function(d){st.textContent=d.status=='ok'?'saved \\u2713':d.message||'error';setTimeout(function(){st.textContent=''},3000)})"
".catch(function(){st.textContent='save failed';setTimeout(function(){st.textContent=''},3000)});"
"},false);});"
'})();'
'</script>'
f"<h2>custom html</h2>" f"<h2>custom html</h2>"
f"<p>Edit the full page template. Use <code>{esc('{{content}}')}</code> " f"<p>Edit the full page template. Use <code>{esc('{{content}}')}</code> "
f"where page content should appear.</p>" f"where page content should appear.</p>"
@ -223,6 +241,32 @@ def handle_style_template_submit(body, gateway_host="", scheme="http"):
return handle_style_form("Template saved.", gateway_host=gateway_host, scheme=scheme) return handle_style_form("Template saved.", gateway_host=gateway_host, scheme=scheme)
def handle_field_save(body):
key = body.get("key", [""])[0].strip()
value = body.get("value", [""])[0].strip()
if not key:
return _json_response({"status": "error", "message": "No key provided."}, 400)
if key == "forum_enabled":
from handlers import forum_plugin
if value == "1" and forum_plugin is None:
return _json_response({"status": "error", "message": "Forum plugin not installed."}, 400)
if value == "1":
forum_plugin.enable()
try:
forum_plugin.fdb.set_setting("forum_enabled", "1")
except Exception:
pass
else:
forum_plugin.disable()
try:
forum_plugin.fdb.set_setting("forum_enabled", "0")
except Exception:
pass
templates_mod.FORUM_ENABLED = (value == "1")
set_setting(key, value)
return _json_response({"status": "ok", "message": ""})
def handle_about(): def handle_about():
name = get_site_name() name = get_site_name()
dest_hash = get_setting("dest_hash") dest_hash = get_setting("dest_hash")