Add SX editor to post edit page, prevent sx_content clearing on save

- Add sx_content to _post_to_edit_dict so edit page receives existing content
- Add SX/Koenig editor tabs, sx-editor mount point, and SxEditor.mount init
- Only pass sx_content to writer_update when form field is present (prevents
  accidental clearing when editing via Koenig-only path)
- Add csrf_exempt to example API POST/DELETE/PUT demo endpoints
- Add defpage infrastructure (pages.py, layouts.py) and sx docs page definitions
- Add defhandler definitions for example API handlers (examples.sx)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 10:23:33 +00:00
parent 0af07f9f2e
commit a8c0741f54
8 changed files with 1194 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ from datetime import datetime
from uuid import uuid4
from quart import Blueprint, Response, make_response, request
from shared.browser.app.csrf import csrf_exempt
def register(url_prefix: str = "/") -> Blueprint:
@@ -145,6 +146,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("click-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.post("/examples/api/form")
async def api_form():
from shared.sx.helpers import sx_response
@@ -175,6 +177,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("poll-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.delete("/examples/api/delete/<item_id>")
async def api_delete(item_id: str):
from shared.sx.helpers import sx_response
@@ -200,6 +203,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("edit-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.post("/examples/api/edit")
async def api_edit_save():
from shared.sx.helpers import sx_response
@@ -295,6 +299,7 @@ def register(url_prefix: str = "/") -> Blueprint:
_jobs: dict[str, int] = {}
@csrf_exempt
@bp.post("/examples/api/progress/start")
async def api_progress_start():
from shared.sx.helpers import sx_response
@@ -373,6 +378,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("validate-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.post("/examples/api/validate/submit")
async def api_validate_submit():
from shared.sx.helpers import sx_response
@@ -402,6 +408,7 @@ def register(url_prefix: str = "/") -> Blueprint:
# --- Reset on Submit ---
@csrf_exempt
@bp.post("/examples/api/reset-submit")
async def api_reset_submit():
from shared.sx.helpers import sx_response
@@ -442,6 +449,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("editrow-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.post("/examples/api/editrow/<row_id>")
async def api_editrow_save(row_id: str):
from shared.sx.helpers import sx_response
@@ -488,6 +496,7 @@ def register(url_prefix: str = "/") -> Blueprint:
_bulk_users[u["id"]] = dict(u)
return _bulk_users
@csrf_exempt
@bp.post("/examples/api/bulk")
async def api_bulk():
from shared.sx.helpers import sx_response
@@ -517,6 +526,7 @@ def register(url_prefix: str = "/") -> Blueprint:
_swap_count = {"n": 0}
@csrf_exempt
@bp.post("/examples/api/swap-log")
async def api_swap_log():
from shared.sx.helpers import sx_response
@@ -682,6 +692,7 @@ def register(url_prefix: str = "/") -> Blueprint:
oob_comp = _oob_code("pp-comp", comp_text)
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
@csrf_exempt
@bp.put("/examples/api/putpatch")
async def api_pp_put():
from shared.sx.helpers import sx_response
@@ -712,6 +723,7 @@ def register(url_prefix: str = "/") -> Blueprint:
# --- JSON Encoding ---
@csrf_exempt
@bp.post("/examples/api/json-echo")
async def api_json_echo():
from shared.sx.helpers import sx_response