Repository source: docs/plans/archive/forte_reply_step3_development_plan.md
Forte Reply — Step 3: Development Plan
Stage 1
Goal: Embed the reply composer markup into the Forte paned content pane, hidden by default, targeting the thread and default-selected (root) post.
Dependencies: none (Step 2 approved)
Expected changes: new partial (e.g.
templates/partials/paned_compose_panel.php) wrappingpartials/reply_form.phpwith ahiddenattribute and Forte-specific wrapper classes; included fromtemplates/pages/forte.phporpaned_content_pane.php;renderForte()passes whateverthread_id/board_tagsvalues the partial needs (already available via$thread)Verification approach: load a Forte thread page, inspect DOM for the hidden panel with correct
thread_id/parent_idhidden inputs; confirm classic thread pages are unaffectedRisks or open questions:
Confirm field names available on
$thread(e.g. tags) match whatreply_form.phpexpects forboard_tags
Canonical components/API contracts touched:
partials/reply_form.php(reused unchanged),templates/pages/forte.php/paned_content_pane.php(extended)
Stage 2
Goal: Enable the toolbar "Reply" button and wire it to toggle the compose panel's visibility.
Dependencies: Stage 1
Expected changes: remove
disabledfrom the Reply button inforte.php, add adata-paned-replyhook;paned_reader.jsgets a click handler toggling the panel'shiddenattribute (button stays enabled since Forte always has a selected post by default)Verification approach: load Forte, click Reply, confirm panel appears/disappears; confirm no console errors
Risks or open questions: none identified
Canonical components/API contracts touched:
public/assets/paned_reader.js(extended)
Stage 3
Goal: Keep the compose panel's target post in sync with the pane's current post selection.
Dependencies: Stage 2
Expected changes: existing post-selection handler in
paned_reader.jsupdates the compose form's hiddenparent_idinput whenever selection changesVerification approach: select different posts, open the composer, confirm
parent_idmatches the selected post each timeRisks or open questions:
Decide behavior when a draft is in progress and selection changes (reset vs. preserve draft) — default to resetting the field only, leaving typed body text untouched, unless testing shows confusion
Canonical components/API contracts touched:
public/assets/paned_reader.js(extended)
Stage 4
Goal: Style the compose panel to visually match Forte's paned chrome.
Dependencies: Stage 1
Expected changes: new scoped rules in
forte.cssfor the compose panel and its inner elements (textarea, buttons, labels), following the same.paned-window-scoped pattern used for the folder tree and post list; nosite.csschangesVerification approach: visual comparison of Forte vs. classic reply UI; rerun the
forte_css_isolationstatic-build fingerprint check to confirm no cross-contaminationRisks or open questions:
Visual fidelity is subjective; may need a review/iteration pass with the user
Canonical components/API contracts touched:
public/assets/forte.css(extended)
Stage 5
Goal: Verify and fix the end-to-end submit flow so replying from Forte returns the reader to Forte (not the classic thread view).
Dependencies: Stages 1-4
Expected changes:
handleComposeReplySubmit()currently redirects unconditionally to/threads/{id}; add a way to preserve "came from Forte" (e.g., a hiddenreturn_tofield on the composer read back on submit) so success and validation-error paths both return to the Forte view instead of the classic oneVerification approach: submit a reply (named and anonymous) from Forte and confirm redirect back into Forte with the new post visible; submit an invalid reply and confirm the error re-render also stays in Forte
Risks or open questions:
Need to confirm the validation-error path (
renderComposeReplyPage) can also honor a Forte return target, or whether it needs a Forte-specific error re-render instead
Canonical components/API contracts touched:
Application.php::handleComposeReplySubmit(extended),partials/reply_form.php(gains a hidden return-target field, reused by both surfaces)