Move blog composition from Python to .sx defcomps (Phase 7)
Convert all 8 blog page helpers from returning sx_call() strings to returning data dicts. Defpages now use :data + :content pattern: helpers load data, SX composes markup. Newsletter options and footer badges composed inline with map/fn in defpage expressions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
; Blog app defpage declarations
|
; Blog app defpage declarations
|
||||||
; Pages kept as Python: home, index, post-detail (cache_page / complex branching)
|
; Pages kept as Python: home, index, post-detail (cache_page / complex branching)
|
||||||
|
; All helpers return data dicts — markup composition in SX.
|
||||||
|
|
||||||
; --- New post/page editors ---
|
; --- New post/page editors ---
|
||||||
|
|
||||||
@@ -7,13 +8,23 @@
|
|||||||
:path "/new/"
|
:path "/new/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout :blog
|
:layout :blog
|
||||||
:content (editor-content))
|
:data (editor-data)
|
||||||
|
:content (~blog-editor-content
|
||||||
|
:csrf csrf :title-placeholder title-placeholder
|
||||||
|
:create-label create-label :css-href css-href
|
||||||
|
:js-src js-src :sx-editor-js-src sx-editor-js-src
|
||||||
|
:init-js init-js))
|
||||||
|
|
||||||
(defpage new-page
|
(defpage new-page
|
||||||
:path "/new-page/"
|
:path "/new-page/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout :blog
|
:layout :blog
|
||||||
:content (editor-page-content))
|
:data (editor-page-data)
|
||||||
|
:content (~blog-editor-content
|
||||||
|
:csrf csrf :title-placeholder title-placeholder
|
||||||
|
:create-label create-label :css-href css-href
|
||||||
|
:js-src js-src :sx-editor-js-src sx-editor-js-src
|
||||||
|
:init-js init-js))
|
||||||
|
|
||||||
; --- Post admin pages (absolute paths under /<slug>/admin/) ---
|
; --- Post admin pages (absolute paths under /<slug>/admin/) ---
|
||||||
|
|
||||||
@@ -21,37 +32,71 @@
|
|||||||
:path "/<slug>/admin/"
|
:path "/<slug>/admin/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout (:post-admin :selected "admin")
|
:layout (:post-admin :selected "admin")
|
||||||
:content (post-admin-content slug))
|
:data (post-admin-data slug)
|
||||||
|
:content (~blog-admin-placeholder))
|
||||||
|
|
||||||
(defpage post-data
|
(defpage post-data
|
||||||
:path "/<slug>/admin/data/"
|
:path "/<slug>/admin/data/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout (:post-admin :selected "data")
|
:layout (:post-admin :selected "data")
|
||||||
:content (post-data-content slug))
|
:data (post-data-data slug)
|
||||||
|
:content (~blog-data-table-content :tablename tablename :model-data model-data))
|
||||||
|
|
||||||
(defpage post-preview
|
(defpage post-preview
|
||||||
:path "/<slug>/admin/preview/"
|
:path "/<slug>/admin/preview/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout (:post-admin :selected "preview")
|
:layout (:post-admin :selected "preview")
|
||||||
:content (post-preview-content slug))
|
:data (post-preview-data slug)
|
||||||
|
:content (~blog-preview-content
|
||||||
|
:sx-pretty sx-pretty :json-pretty json-pretty
|
||||||
|
:sx-rendered sx-rendered :lex-rendered lex-rendered))
|
||||||
|
|
||||||
(defpage post-entries
|
(defpage post-entries
|
||||||
:path "/<slug>/admin/entries/"
|
:path "/<slug>/admin/entries/"
|
||||||
:auth :admin
|
:auth :admin
|
||||||
:layout (:post-admin :selected "entries")
|
:layout (:post-admin :selected "entries")
|
||||||
:content (post-entries-content slug))
|
:data (post-entries-data slug)
|
||||||
|
:content (~blog-entries-browser-content
|
||||||
|
:entries-panel (~blog-associated-entries-from-data :entries entries :csrf csrf)
|
||||||
|
:calendars calendars))
|
||||||
|
|
||||||
(defpage post-settings
|
(defpage post-settings
|
||||||
:path "/<slug>/admin/settings/"
|
:path "/<slug>/admin/settings/"
|
||||||
:auth :post_author
|
:auth :post_author
|
||||||
:layout (:post-admin :selected "settings")
|
:layout (:post-admin :selected "settings")
|
||||||
:content (post-settings-content slug))
|
:data (post-settings-data slug)
|
||||||
|
:content (~blog-settings-form-content
|
||||||
|
:csrf csrf :updated-at updated-at :is-page is-page
|
||||||
|
:save-success save-success :slug settings-slug
|
||||||
|
:published-at published-at :featured featured
|
||||||
|
:visibility visibility :email-only email-only
|
||||||
|
:tags tags :feature-image-alt feature-image-alt
|
||||||
|
:meta-title meta-title :meta-description meta-description
|
||||||
|
:canonical-url canonical-url :og-title og-title
|
||||||
|
:og-description og-description :og-image og-image
|
||||||
|
:twitter-title twitter-title :twitter-description twitter-description
|
||||||
|
:twitter-image twitter-image :custom-template custom-template))
|
||||||
|
|
||||||
(defpage post-edit
|
(defpage post-edit
|
||||||
:path "/<slug>/admin/edit/"
|
:path "/<slug>/admin/edit/"
|
||||||
:auth :post_author
|
:auth :post_author
|
||||||
:layout (:post-admin :selected "edit")
|
:layout (:post-admin :selected "edit")
|
||||||
:content (post-edit-content slug))
|
:data (post-edit-data slug)
|
||||||
|
:content (~blog-edit-content
|
||||||
|
:csrf csrf :updated-at updated-at
|
||||||
|
:title-val title-val :excerpt-val excerpt-val
|
||||||
|
:feature-image feature-image :feature-image-caption feature-image-caption
|
||||||
|
:sx-content-val sx-content-val :lexical-json lexical-json
|
||||||
|
:has-sx has-sx :title-placeholder title-placeholder
|
||||||
|
:status status :already-emailed already-emailed
|
||||||
|
:newsletter-options (<>
|
||||||
|
(option :value "" "Select newsletter\u2026")
|
||||||
|
(map (fn (nl) (option :value (get nl "slug") (get nl "name"))) newsletters))
|
||||||
|
:footer-extra (when badges
|
||||||
|
(<> (map (fn (b) (span :class (get b "cls") (get b "text"))) badges)))
|
||||||
|
:css-href css-href :js-src js-src
|
||||||
|
:sx-editor-js-src sx-editor-js-src
|
||||||
|
:init-js init-js :save-error save-error))
|
||||||
|
|
||||||
; --- Settings pages (absolute paths) ---
|
; --- Settings pages (absolute paths) ---
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
"""Blog page helpers — async functions available in .sx defpage expressions."""
|
"""Blog page helpers — async functions available in .sx defpage expressions.
|
||||||
|
|
||||||
|
All helpers return data values (dicts, lists) — no sx_call().
|
||||||
|
Markup composition lives entirely in .sx defpage and .sx defcomp files.
|
||||||
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Shared hydration helpers
|
# Shared hydration helpers (kept for auth/g._defpage_ctx side effects)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _add_to_defpage_ctx(**kwargs: Any) -> None:
|
def _add_to_defpage_ctx(**kwargs: Any) -> None:
|
||||||
@@ -95,20 +99,20 @@ async def _inject_post_context(p_data: dict) -> None:
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Page helpers (async functions available in .sx defpage expressions)
|
# Registration
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _register_blog_helpers() -> None:
|
def _register_blog_helpers() -> None:
|
||||||
from shared.sx.pages import register_page_helpers
|
from shared.sx.pages import register_page_helpers
|
||||||
register_page_helpers("blog", {
|
register_page_helpers("blog", {
|
||||||
"editor-content": _h_editor_content,
|
"editor-data": _h_editor_data,
|
||||||
"editor-page-content": _h_editor_page_content,
|
"editor-page-data": _h_editor_page_data,
|
||||||
"post-admin-content": _h_post_admin_content,
|
"post-admin-data": _h_post_admin_data,
|
||||||
"post-data-content": _h_post_data_content,
|
"post-data-data": _h_post_data_data,
|
||||||
"post-preview-content": _h_post_preview_content,
|
"post-preview-data": _h_post_preview_data,
|
||||||
"post-entries-content": _h_post_entries_content,
|
"post-entries-data": _h_post_entries_data,
|
||||||
"post-settings-content": _h_post_settings_content,
|
"post-settings-data": _h_post_settings_data,
|
||||||
"post-edit-content": _h_post_edit_content,
|
"post-edit-data": _h_post_edit_data,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -264,52 +268,51 @@ def _editor_urls() -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _h_editor_content(**kw):
|
def _h_editor_data(**kw) -> dict:
|
||||||
"""New post editor panel."""
|
"""New post editor — return data for ~blog-editor-content."""
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
|
|
||||||
urls = _editor_urls()
|
urls = _editor_urls()
|
||||||
csrf = generate_csrf_token()
|
csrf = generate_csrf_token()
|
||||||
init_js = _editor_init_js(urls, form_id="post-new-form", has_initial_json=False)
|
init_js = _editor_init_js(urls, form_id="post-new-form", has_initial_json=False)
|
||||||
|
|
||||||
return sx_call("blog-editor-content",
|
return {
|
||||||
csrf=csrf,
|
"csrf": csrf,
|
||||||
title_placeholder="Post title...",
|
"title-placeholder": "Post title...",
|
||||||
create_label="Create Post",
|
"create-label": "Create Post",
|
||||||
css_href=urls["css_href"],
|
"css-href": urls["css_href"],
|
||||||
js_src=urls["js_src"],
|
"js-src": urls["js_src"],
|
||||||
sx_editor_js_src=urls["sx_editor_js_src"],
|
"sx-editor-js-src": urls["sx_editor_js_src"],
|
||||||
init_js=init_js)
|
"init-js": init_js,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _h_editor_page_content(**kw):
|
def _h_editor_page_data(**kw) -> dict:
|
||||||
"""New page editor panel."""
|
"""New page editor — return data for ~blog-editor-content."""
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
|
|
||||||
urls = _editor_urls()
|
urls = _editor_urls()
|
||||||
csrf = generate_csrf_token()
|
csrf = generate_csrf_token()
|
||||||
init_js = _editor_init_js(urls, form_id="post-new-form", has_initial_json=False)
|
init_js = _editor_init_js(urls, form_id="post-new-form", has_initial_json=False)
|
||||||
|
|
||||||
return sx_call("blog-editor-content",
|
return {
|
||||||
csrf=csrf,
|
"csrf": csrf,
|
||||||
title_placeholder="Page title...",
|
"title-placeholder": "Page title...",
|
||||||
create_label="Create Page",
|
"create-label": "Create Page",
|
||||||
css_href=urls["css_href"],
|
"css-href": urls["css_href"],
|
||||||
js_src=urls["js_src"],
|
"js-src": urls["js_src"],
|
||||||
sx_editor_js_src=urls["sx_editor_js_src"],
|
"sx-editor-js-src": urls["sx_editor_js_src"],
|
||||||
init_js=init_js)
|
"init-js": init_js,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Post admin helpers
|
# Post admin helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async def _h_post_admin_content(slug=None, **kw):
|
async def _h_post_admin_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from shared.sx.helpers import sx_call
|
return {}
|
||||||
return sx_call("blog-admin-placeholder")
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -388,40 +391,38 @@ def _obj_summary(obj) -> str:
|
|||||||
return str(esc(" \u2022 ".join(ident_parts) if ident_parts else str(obj)))
|
return str(esc(" \u2022 ".join(ident_parts) if ident_parts else str(obj)))
|
||||||
|
|
||||||
|
|
||||||
async def _h_post_data_content(slug=None, **kw):
|
async def _h_post_data_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
|
|
||||||
original_post = getattr(g, "post_data", {}).get("original_post")
|
original_post = getattr(g, "post_data", {}).get("original_post")
|
||||||
if original_post is None:
|
if original_post is None:
|
||||||
return sx_call("blog-data-table-content")
|
return {"tablename": None, "model-data": None}
|
||||||
|
|
||||||
tablename = getattr(original_post, "__tablename__", "?")
|
tablename = getattr(original_post, "__tablename__", "?")
|
||||||
model_data = _extract_model_data(original_post, 0, 2)
|
model_data = _extract_model_data(original_post, 0, 2)
|
||||||
|
|
||||||
return sx_call("blog-data-table-content",
|
return {"tablename": tablename, "model-data": model_data}
|
||||||
tablename=tablename, model_data=model_data)
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Preview content
|
# Preview content
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async def _h_post_preview_content(slug=None, **kw):
|
async def _h_post_preview_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call
|
from shared.sx.helpers import SxExpr
|
||||||
from shared.sx.parser import SxExpr
|
|
||||||
|
|
||||||
preview = await services.blog_page.preview_data(g.s)
|
preview = await services.blog_page.preview_data(g.s)
|
||||||
|
|
||||||
return sx_call("blog-preview-content",
|
return {
|
||||||
sx_pretty=SxExpr(preview["sx_pretty"]) if preview.get("sx_pretty") else None,
|
"sx-pretty": SxExpr(preview["sx_pretty"]) if preview.get("sx_pretty") else None,
|
||||||
json_pretty=SxExpr(preview["json_pretty"]) if preview.get("json_pretty") else None,
|
"json-pretty": SxExpr(preview["json_pretty"]) if preview.get("json_pretty") else None,
|
||||||
sx_rendered=preview.get("sx_rendered") or None,
|
"sx-rendered": preview.get("sx_rendered") or None,
|
||||||
lex_rendered=preview.get("lex_rendered") or None)
|
"lex-rendered": preview.get("lex_rendered") or None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -493,13 +494,11 @@ def _extract_calendar_browser_data(all_calendars, post_slug: str) -> list:
|
|||||||
return calendars
|
return calendars
|
||||||
|
|
||||||
|
|
||||||
async def _h_post_entries_content(slug=None, **kw):
|
async def _h_post_entries_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from quart import g
|
from quart import g
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from shared.models.calendars import Calendar
|
from shared.models.calendars import Calendar
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
from shared.sx.parser import SxExpr
|
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
from bp.post.services.entry_associations import get_post_entry_ids
|
from bp.post.services.entry_associations import get_post_entry_ids
|
||||||
|
|
||||||
@@ -516,30 +515,24 @@ async def _h_post_entries_content(slug=None, **kw):
|
|||||||
await g.s.refresh(calendar, ["entries", "post"])
|
await g.s.refresh(calendar, ["entries", "post"])
|
||||||
|
|
||||||
csrf = generate_csrf_token()
|
csrf = generate_csrf_token()
|
||||||
entry_data = _extract_associated_entries_data(
|
entries = _extract_associated_entries_data(
|
||||||
all_calendars, associated_entry_ids, post_slug)
|
all_calendars, associated_entry_ids, post_slug)
|
||||||
calendar_data = _extract_calendar_browser_data(all_calendars, post_slug)
|
calendars = _extract_calendar_browser_data(all_calendars, post_slug)
|
||||||
|
|
||||||
entries_panel = sx_call("blog-associated-entries-from-data",
|
return {"entries": entries, "calendars": calendars, "csrf": csrf}
|
||||||
entries=entry_data, csrf=csrf)
|
|
||||||
|
|
||||||
return sx_call("blog-entries-browser-content",
|
|
||||||
entries_panel=SxExpr(entries_panel),
|
|
||||||
calendars=calendar_data)
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Settings form
|
# Settings form
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async def _h_post_settings_content(slug=None, **kw):
|
async def _h_post_settings_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from quart import g, request
|
from quart import g, request
|
||||||
from models.ghost_content import Post
|
from models.ghost_content import Post
|
||||||
from sqlalchemy import select as sa_select
|
from sqlalchemy import select as sa_select
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
from bp.post.admin.routes import _post_to_edit_dict
|
from bp.post.admin.routes import _post_to_edit_dict
|
||||||
|
|
||||||
post_id = g.post_data["post"]["id"]
|
post_id = g.post_data["post"]["id"]
|
||||||
@@ -570,28 +563,29 @@ async def _h_post_settings_content(slug=None, **kw):
|
|||||||
pub_at = gp.get("published_at") or ""
|
pub_at = gp.get("published_at") or ""
|
||||||
pub_at_val = pub_at[:16] if pub_at else ""
|
pub_at_val = pub_at[:16] if pub_at else ""
|
||||||
|
|
||||||
return sx_call("blog-settings-form-content",
|
return {
|
||||||
csrf=csrf,
|
"csrf": csrf,
|
||||||
updated_at=gp.get("updated_at") or "",
|
"updated-at": gp.get("updated_at") or "",
|
||||||
is_page=is_page,
|
"is-page": is_page,
|
||||||
save_success=save_success,
|
"save-success": save_success,
|
||||||
slug=gp.get("slug") or "",
|
"settings-slug": gp.get("slug") or "",
|
||||||
published_at=pub_at_val,
|
"published-at": pub_at_val,
|
||||||
featured=bool(gp.get("featured")),
|
"featured": bool(gp.get("featured")),
|
||||||
visibility=gp.get("visibility") or "public",
|
"visibility": gp.get("visibility") or "public",
|
||||||
email_only=bool(gp.get("email_only")),
|
"email-only": bool(gp.get("email_only")),
|
||||||
tags=tag_names,
|
"tags": tag_names,
|
||||||
feature_image_alt=gp.get("feature_image_alt") or "",
|
"feature-image-alt": gp.get("feature_image_alt") or "",
|
||||||
meta_title=gp.get("meta_title") or "",
|
"meta-title": gp.get("meta_title") or "",
|
||||||
meta_description=gp.get("meta_description") or "",
|
"meta-description": gp.get("meta_description") or "",
|
||||||
canonical_url=gp.get("canonical_url") or "",
|
"canonical-url": gp.get("canonical_url") or "",
|
||||||
og_title=gp.get("og_title") or "",
|
"og-title": gp.get("og_title") or "",
|
||||||
og_description=gp.get("og_description") or "",
|
"og-description": gp.get("og_description") or "",
|
||||||
og_image=gp.get("og_image") or "",
|
"og-image": gp.get("og_image") or "",
|
||||||
twitter_title=gp.get("twitter_title") or "",
|
"twitter-title": gp.get("twitter_title") or "",
|
||||||
twitter_description=gp.get("twitter_description") or "",
|
"twitter-description": gp.get("twitter_description") or "",
|
||||||
twitter_image=gp.get("twitter_image") or "",
|
"twitter-image": gp.get("twitter_image") or "",
|
||||||
custom_template=gp.get("custom_template") or "")
|
"custom-template": gp.get("custom_template") or "",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -629,7 +623,7 @@ def _extract_footer_badges(ghost_post: dict, post: dict, save_success: bool,
|
|||||||
return badges
|
return badges
|
||||||
|
|
||||||
|
|
||||||
async def _h_post_edit_content(slug=None, **kw):
|
async def _h_post_edit_data(slug=None, **kw) -> dict:
|
||||||
await _ensure_post_data(slug)
|
await _ensure_post_data(slug)
|
||||||
from quart import g, request as qrequest
|
from quart import g, request as qrequest
|
||||||
from models.ghost_content import Post
|
from models.ghost_content import Post
|
||||||
@@ -637,8 +631,6 @@ async def _h_post_edit_content(slug=None, **kw):
|
|||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
from shared.infrastructure.data_client import fetch_data
|
from shared.infrastructure.data_client import fetch_data
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
from shared.sx.helpers import sx_call
|
|
||||||
from shared.sx.parser import SxExpr, serialize as sx_serialize
|
|
||||||
from bp.post.admin.routes import _post_to_edit_dict
|
from bp.post.admin.routes import _post_to_edit_dict
|
||||||
|
|
||||||
post_id = g.post_data["post"]["id"]
|
post_id = g.post_data["post"]["id"]
|
||||||
@@ -678,36 +670,34 @@ async def _h_post_edit_content(slug=None, **kw):
|
|||||||
|
|
||||||
title_placeholder = "Page title..." if is_page else "Post title..."
|
title_placeholder = "Page title..." if is_page else "Post title..."
|
||||||
|
|
||||||
# Newsletter options as SX fragment
|
# Return newsletter data as list of dicts (composed in SX)
|
||||||
nl_parts = ['(option :value "" "Select newsletter\u2026")']
|
nl_options = _extract_newsletter_options(newsletters)
|
||||||
for nl in newsletters:
|
|
||||||
nl_slug = sx_serialize(getattr(nl, "slug", ""))
|
|
||||||
nl_name = sx_serialize(getattr(nl, "name", ""))
|
|
||||||
nl_parts.append(f"(option :value {nl_slug} {nl_name})")
|
|
||||||
nl_opts_sx = SxExpr("(<> " + " ".join(nl_parts) + ")")
|
|
||||||
|
|
||||||
# Footer extra badges as SX fragment
|
# Return footer badge data as list of dicts (composed in SX)
|
||||||
publish_requested = bool(qrequest.args.get("publish_requested")) if hasattr(qrequest, 'args') else False
|
publish_requested = bool(qrequest.args.get("publish_requested")) if hasattr(qrequest, 'args') else False
|
||||||
badges = _extract_footer_badges(ghost_post, post, save_success,
|
badges = _extract_footer_badges(ghost_post, post, save_success,
|
||||||
publish_requested, already_emailed)
|
publish_requested, already_emailed)
|
||||||
if badges:
|
|
||||||
badge_parts = [f'(span :class "{b["cls"]}" {sx_serialize(b["text"])})'
|
|
||||||
for b in badges]
|
|
||||||
footer_extra_sx = SxExpr("(<> " + " ".join(badge_parts) + ")")
|
|
||||||
else:
|
|
||||||
footer_extra_sx = None
|
|
||||||
|
|
||||||
init_js = _editor_init_js(urls, form_id="post-edit-form", has_initial_json=True)
|
init_js = _editor_init_js(urls, form_id="post-edit-form", has_initial_json=True)
|
||||||
|
|
||||||
return sx_call("blog-edit-content",
|
return {
|
||||||
csrf=csrf, updated_at=str(updated_at),
|
"csrf": csrf,
|
||||||
title_val=title_val, excerpt_val=excerpt_val,
|
"updated-at": str(updated_at),
|
||||||
feature_image=feature_image,
|
"title-val": title_val,
|
||||||
feature_image_caption=feature_image_caption,
|
"excerpt-val": excerpt_val,
|
||||||
sx_content_val=sx_content, lexical_json=lexical_json,
|
"feature-image": feature_image,
|
||||||
has_sx=has_sx, title_placeholder=title_placeholder,
|
"feature-image-caption": feature_image_caption,
|
||||||
status=status, already_emailed=already_emailed,
|
"sx-content-val": sx_content,
|
||||||
newsletter_options=nl_opts_sx, footer_extra=footer_extra_sx,
|
"lexical-json": lexical_json,
|
||||||
css_href=urls["css_href"], js_src=urls["js_src"],
|
"has-sx": has_sx,
|
||||||
sx_editor_js_src=urls["sx_editor_js_src"],
|
"title-placeholder": title_placeholder,
|
||||||
init_js=init_js, save_error=save_error or None)
|
"status": status,
|
||||||
|
"already-emailed": already_emailed,
|
||||||
|
"newsletters": nl_options,
|
||||||
|
"badges": badges,
|
||||||
|
"css-href": urls["css_href"],
|
||||||
|
"js-src": urls["js_src"],
|
||||||
|
"sx-editor-js-src": urls["sx_editor_js_src"],
|
||||||
|
"init-js": init_js,
|
||||||
|
"save-error": save_error or None,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user