fix: eliminate x-data quoting bug by moving page data to JSON script tag
Root cause: x-data HTML attribute with tojson creates quote conflicts that survive even Cache-Control: no-store (likely nginx proxy cache). Solution: page data is now in a <script type=application/json> tag, completely decoupled from Alpine x-data HTML attribute. Zero quoting issues regardless of page content. - x-data="editorState()" + x-init="loadPage()" replaces editor(...) - Server passes page_data dict, template renders as JSON script tag - Same approach used for page_share_mode and page_published - All 73 tests pass
This commit is contained in:
@@ -752,7 +752,8 @@ async def view_page(request: Request, page_id: int):
|
||||
).fetchone()
|
||||
ctx = {**sidebar, "page": page, "page_favorited": fav is not None,
|
||||
"page_share_mode": page.get("share_mode", "private"),
|
||||
"page_published": bool(page.get("published", 0))}
|
||||
"page_published": bool(page.get("published", 0)),
|
||||
"page_data": {"id": page_id, "title": page.get("title"), "content_format": page.get("content_format", "blocks"), "content": page.get("content", ""), "favorited": fav is not None, "share_mode": page.get("share_mode", "private"), "published": bool(page.get("published", 0))}}
|
||||
template = env.get_template("page_editor.html")
|
||||
response = template.render(**ctx)
|
||||
return HTMLResponse(content=response, headers={"Cache-Control": "no-store, max-age=0"})
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-editor-wrapper" x-data='editor({{ page.id }}, {{ page.title | tojson }}, {{ page.content_format | tojson }}, {{ page.content | tojson }}, {{ page_favorited | tojson }})' x-init="init()">
|
||||
<div class="page-editor-wrapper" x-data="editorState()" x-init="loadPage()">
|
||||
|
||||
<!-- ═══════════ Top Action Bar ═══════════ -->
|
||||
<div class="page-topbar">
|
||||
@@ -261,6 +261,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="application/json" id="page-data">{{ page_data | tojson }}</script>
|
||||
<script>
|
||||
const CMDS=[{name:'BASIC',items:[
|
||||
{id:'paragraph',name:'Text',icon:'¶'},{id:'heading_1',name:'Heading 1',icon:'H1'},{id:'heading_2',name:'Heading 2',icon:'H2'},
|
||||
@@ -329,12 +330,12 @@ function renderBlock(b,idx){
|
||||
}
|
||||
|
||||
window.E=null;
|
||||
function editor(pid,title,fmt,raw,favorited){
|
||||
const self={
|
||||
pid,pageTitle:title,blocks:[],dirty:false,saving:false,lastSaved:'',st:null,
|
||||
function editorState(){
|
||||
return {
|
||||
pid:null,pageTitle:'',blocks:[],dirty:false,saving:false,lastSaved:'',st:null,
|
||||
fmt:{open:false,top:0,left:0,idx:-1},
|
||||
shareOpen:false,moreOpen:false,gsMoreOpen:false,accessMenuOpen:false,
|
||||
shareTab:'share',favorited:!!favorited,
|
||||
shareTab:'share',favorited:false,
|
||||
pagePublished:{{ page_published | tojson }},
|
||||
generalAccess:'{{ page_share_mode }}',publicPerm:'viewer',
|
||||
pubAllowEdit:false,pubAllowComments:true,
|
||||
|
||||
Reference in New Issue
Block a user