Changeset 5190152 in Klonkt for src/views


Ignore:
Timestamp:
07/19/2026 05:38:25 PM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
e9c9ae1
Parents:
feced2c
git-author:
Robin <roboburr@…> (07/19/2026 05:38:00 PM)
git-committer:
Robin <roboburr@…> (07/19/2026 05:38:25 PM)
Message:

Feature: rich editor on the edit forms too (klonkt-demo-c7f, last slice)

Editing a sent reply (Messages + the interact page's manage list) now opens the
same shared editor as new replies, instead of a bare textarea. Prutter stays
plain on purpose (Robin: not part of this).

  • reply-editor partial: initialHtml/initialText prefill for edit mode, and a noAttach flag that omits the media UI (an edit never touches attachments). JS grew canAttach guards so the component runs without the attach elements; pasted files are still swallowed there rather than becoming base64 blobs.
  • deliverOutboxUpdate(site, id, text, {html, language}): rich path with the same sanitize + enrichment + mention-first-paragraph logic as deliverReply; language updated via COALESCE (bogus codes keep the old one); attachments survive untouched. Plain path unchanged.
  • /fediverse/:id/edit passes content + language; listOutbox and the Messages sent-projection carry language so the select preselects correctly.
  • The interact page's edit-toggle focuses the rich editor when present.

2 new tests (93 green). Browser-verified on /messages: prefilled editor
(mention-stripped HTML + plain fallback + language preselected, no paperclip),
edit saved -> content replaced with markup, mention re-attached inline,
language nl->en, no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@…>

Location:
src/views
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/views/pages/authorize-interaction.ejs

    rfeced2c r5190152  
    4141              </form>
    4242            </div>
    43             <form method="post" action="/fediverse/<%= m.id %>/edit" class="fedi-edit-form">
    44               <textarea name="text" rows="3" maxlength="2000" class="fedi-edit-ta"><%= m.editable %></textarea>
    45               <div class="fedi-edit-actions"><button type="submit" class="fedi-edit-save"><%= t('fedi.save_edit') %></button></div>
    46             </form>
     43            <div class="fedi-edit-form">
     44              <%- include('../partials/reply-editor', {
     45                action: '/fediverse/' + m.id + '/edit',
     46                placeholder: t('fedi.reply_ph'),
     47                submitLabel: t('fedi.save_edit'),
     48                rows: 3,
     49                initialHtml: m.content,
     50                initialText: m.editable,
     51                defaultLang: m.language,
     52                noAttach: true,
     53              }) %>
     54            </div>
    4755          </li>
    4856        <% }); %>
     
    5967          b.classList.toggle('is-open', open);
    6068          b.setAttribute('aria-expanded', open ? 'true' : 'false');
    61           if (open) { var ta = form.querySelector('textarea'); if (ta) ta.focus(); }
     69          if (open) { var ed = form.querySelector('.re-editor') || form.querySelector('textarea'); if (ed) ed.focus(); }
    6270        });
    6371      })();
  • src/views/pages/messages.ejs

    rfeced2c r5190152  
    7878                <details class="msg-edit">
    7979                  <summary><%= t('fedi.edit') %></summary>
    80                   <form method="post" action="/fediverse/<%= n.outboxId %>/edit" class="msg-edit-form">
    81                     <textarea name="text" rows="2" required><%= n.editable %></textarea>
    82                     <button type="submit" class="btn"><%= t('fedi.save_edit') %></button>
    83                   </form>
     80                  <div class="msg-edit-form">
     81                    <%- include('../partials/reply-editor', {
     82                      action: '/fediverse/' + n.outboxId + '/edit',
     83                      placeholder: t('fedi.reply_ph'),
     84                      submitLabel: t('fedi.save_edit'),
     85                      rows: 2,
     86                      initialHtml: n.content,
     87                      initialText: n.editable,
     88                      defaultLang: n.language,
     89                      noAttach: true,
     90                    }) %>
     91                  </div>
    8492                </details>
    8593                <form method="post" action="/fediverse/<%= n.outboxId %>/delete" data-confirm="<%= t('fedi.delete_confirm') %>">
  • src/views/partials/reply-editor.ejs

    rfeced2c r5190152  
    1616    rows          textarea rows for the no-JS fallback (default 3)
    1717    defaultLang   preselected reply language (default: UI lang)
     18    initialHtml   prefill for EDIT mode (our own sanitized HTML) (optional)
     19    initialText   plain-text prefill for the no-JS textarea (optional)
     20    noAttach      true hides the media button (edits do not touch attachments)
    1821%>
     22<% var _reInitHtml = (typeof initialHtml !== 'undefined' && initialHtml) || ''; %>
     23<% var _reInitText = (typeof initialText !== 'undefined' && initialText) || ''; %>
     24<% var _reNoAttach = (typeof noAttach !== 'undefined' && noAttach); %>
    1925<% var _reLang = (typeof defaultLang !== 'undefined' && defaultLang) || (typeof lang !== 'undefined' ? lang : 'en'); %>
    2026<form method="post" action="<%= action %>" class="re-form" data-re
     
    3642    <button type="button" data-cmd="list" title="<%= t('re.list') %>" aria-label="<%= t('re.list') %>">•≡</button>
    3743    <button type="button" data-cmd="quote" title="<%= t('re.quote') %>" aria-label="<%= t('re.quote') %>">❝</button>
    38     <button type="button" data-cmd="attach" title="<%= t('re.attach') %>" aria-label="<%= t('re.attach') %>">📎</button>
    39     <input type="file" class="re-file" accept="image/*,audio/*,video/*" multiple hidden>
     44    <% if (!_reNoAttach) { %>
     45      <button type="button" data-cmd="attach" title="<%= t('re.attach') %>" aria-label="<%= t('re.attach') %>">📎</button>
     46      <input type="file" class="re-file" accept="image/*,audio/*,video/*" multiple hidden>
     47    <% } %>
    4048  </div>
    41   <input type="hidden" name="attachments" value="">
    42   <div class="re-attachments" hidden></div>
    43   <textarea name="text" rows="<%= typeof rows !== 'undefined' ? rows : 3 %>" required placeholder="<%= placeholder %>"></textarea>
     49  <% if (!_reNoAttach) { %>
     50    <input type="hidden" name="attachments" value="">
     51    <div class="re-attachments" hidden></div>
     52  <% } %>
     53  <textarea name="text" rows="<%= typeof rows !== 'undefined' ? rows : 3 %>" required placeholder="<%= placeholder %>"><%= _reInitText %></textarea>
    4454  <div class="re-editor" contenteditable="true" role="textbox" aria-multiline="true"
    45        data-ph="<%= placeholder %>" aria-label="<%= placeholder %>" hidden></div>
     55       data-ph="<%= placeholder %>" aria-label="<%= placeholder %>" hidden><%- _reInitHtml %></div>
    4656  <div class="re-foot">
    4757    <select name="language" class="re-lang" aria-label="<%= t('re.lang') %>" hidden>
Note: See TracChangeset for help on using the changeset viewer.