source: Klonkt/src/views/partials/msg-item.ejs@ 3e7dde2

main
Last change on this file since 3e7dde2 was 34e63f0, checked in by roboburr <roboburr@…>, 5 weeks ago

De antwoordpoort ook in Klonkts eigen web-UI (shaer-r4c, vervolg)

De poort weigert nu in deliverReply, dus het antwoord komt er niet doorheen --
maar de webinterface toonde het veld gewoon nog. Precies de knop-die-niet-werkt
waar ik in de app-code tegen waarschuwde: een kind duwt tegen een deur die op
slot zit en krijgt geen uitleg.

res.locals.mayReply staat er nu een keer, naast res.locals.site, zodat geen route
hem apart hoeft door te geven.

NIET IN DE PARTIAL ZELF, en dat scheelde een fout. reply-editor.ejs leek het
knooppunt -- vier includes, een plek -- maar hij wordt ook voor BEWERKEN gebruikt
(msg-edit, /fediverse/:id/edit). Een guard daarbinnen had het bewerken van een
eigen bericht meegesloopt.

Dus per include, en in Berichten precies de tak die de server ook kiest:
/messages/reply gaat naar deliverReply als er een interaction+post is (een
antwoord, valt onder de poort) en anders naar deliverDirectNote (een bericht,
andere poort). Alleen de eerste verdwijnt.

De vier gewijzigde templates compileren; de suite (686) blijft groen.

  • Property mode set to 100644
File size: 16.0 KB
Line 
1<% if (n.type === 'thread') { %>
2<%
3 var _tseen = (typeof seen !== 'undefined' && seen) ? seen : 0;
4 // Een draad is nieuw zodra EEN bericht erin nieuw is.
5 var _tnew = !!_tseen && (n.messages || []).some(function (m) {
6 return m.created_at && Date.parse(m.created_at) > _tseen;
7 });
8 var _tpeople = (n.people || []).map(function (p) { return p.name || p.handle || '?'; });
9 // Alleen jij aan het woord: dan is de tegenpartij het adres waaraan
10 // je schreef, niet een lege naam.
11 var _tto = ((n.messages || []).find(function (m) { return m.to_handle; }) || {}).to_handle;
12 var _tlabel = _tpeople.length ? _tpeople.join(', ') : (_tto || t('msg.you'));
13 %>
14 <li class="msg-item msg-thread<%= _tnew ? ' is-new' : '' %>" data-kind="conv" data-who="<%= (_tpeople.join(' ') + ' ' + (_tto || '')).toLowerCase() %>">
15 <div class="msg-thread-head">
16 <%# Tegenpartij en aantal in EEN uitsparing: het is een label bij het
17 gesprek, geen kop erboven. Zo houdt de inhoud de ruimte.
18
19 Deze uitsparing is ook de knop die het gesprek in- en uitklapt
20 (Barts aanwijzing): tikken op de tegenpartij is waar je van
21 nature naar wijst als je "dit gesprek" bedoelt. Een BUTTON en
22 geen span met een klikhandler, want dan werkt hij ook met het
23 toetsenbord en leest een schermlezer de stand voor.
24
25 Zonder JavaScript doet hij niets, en dan staat het gesprek
26 gewoon open -- dat is ook de stand waar we mee beginnen. %>
27 <button type="button" class="msg-thread-who" aria-expanded="true">
28 <span class="msg-thread-name"><%= _tlabel %></span>
29 <% if (n.count > 1) { %><span class="msg-thread-count"><%= n.count %></span><% } %>
30 <svg class="msg-thread-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
31 </button>
32 <% if (_tnew) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
33 <%# De context bij de draad: waar gaat dit gesprek over? Zonder deze
34 link is een antwoord in een lijst niet te plaatsen. %>
35 <% if (n.post) { %>
36 <a class="msg-thread-post" href="/<%= n.post.slug %>">
37 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
38 <%= n.post.title || n.post.slug %>
39 </a>
40 <% } %>
41 </div>
42 <ul class="msg-thread-msgs">
43 <% (n.messages || []).forEach(function (m) { %><%- include('msg-item', { n: m, seen: _tseen, inThread: true }) %><% }); %>
44 </ul>
45 <%# Antwoorden vanuit de draad zelf. Ingeklapt, want een open editor
46 onder elk gesprek maakt de lijst onleesbaar -- juist het probleem
47 dat deze weergave moest oplossen. De route kiest het pad: een
48 draad aan een post krijgt een reply, een draad aan een persoon een
49 direct bericht. %>
50 <%# shaer-r4c: precies de tak die de server ook kiest. /messages/reply
51 gaat naar deliverReply als er een interaction+post is (dat is een
52 ANTWOORD en valt onder de poort), en anders naar deliverDirectNote
53 (dat is een bericht, andere poort). Alleen de eerste verbergen. %>
54 <% var _rt = n.replyTo || {}; var _thread = _rt.interactionId && _rt.postSlug; %>
55 <% var _kan = canMutate && ((_thread && locals.mayReply !== false) || (!_thread && _rt.actorUri)); %>
56 <% if (_kan) { %>
57 <div class="msg-thread-foot">
58 <details class="msg-reply">
59 <summary><%= t('fedi.reply') %></summary>
60 <div class="msg-reply-form">
61 <%- include('../partials/reply-editor', {
62 action: (typeof siteUrlBase !== 'undefined' ? siteUrlBase : '') + '/messages/reply',
63 hiddenFields: [
64 { name: 'interaction_id', value: _rt.interactionId || '' },
65 { name: 'post_slug', value: _rt.postSlug || '' },
66 { name: 'to', value: _rt.actorUri || '' },
67 ],
68 placeholder: t('fedi.reply_ph'),
69 submitLabel: t('fedi.reply'),
70 rows: 2,
71 }) %>
72 </div>
73 </details>
74 <%# De zwaai blijft een eigen knop: het is geen antwoord maar een
75 seintje (FEP-633c), en die twee horen niet op een hoop. %>
76 <% if (_rt.actorUri) { %>
77 <form method="post" action="<%= (typeof siteUrlBase !== 'undefined' ? siteUrlBase : '') %>/messages/quick-reply" class="msg-wave" data-sent="<%= t('msg.wave_sent') %>">
78 <input type="hidden" name="to" value="<%= _rt.actorUri %>">
79 <button class="btn small" name="text" value="&#128075;" title="<%= t('msg.wave_back') %>">&#128075;</button>
80 </form>
81 <% } %>
82 </div>
83 <% } %>
84 </li>
85<% } else { %>
86<%
87 var _seen = (typeof seen !== 'undefined' && seen) ? seen : 0;
88 var _t = n.type === 'announce' ? 'boost' : n.type; // reply|mention|report|like|boost|follow|sent
89 var _new = _seen && n.created_at ? (Date.parse(n.created_at) > _seen) : false;
90 var _who = n.name || n.handle || '';
91 var _priv0 = (n.visibility === 'followers' || n.visibility === 'direct');
92 // Emmers: Activiteit = likes/boosts/follows/polls, Moderatie =
93 // reports, en al het overige is gesprek. De oude emmers 'msgs' en
94 // 'sent' bestaan niet meer sinds Berichten, Gesprekken en Verzonden
95 // samenvielen -- en dat is geen cosmetische hernoeming: een
96 // gespreksregel die om wat voor reden dan ook geen draad werd (geen
97 // post, geen herkenbare tegenpartij) hield anders een data-kind
98 // waarvoor geen chip meer bestond, en was daarmee onder ELKE chip
99 // behalve Alles onzichtbaar.
100 var _kind = (_t === 'like' || _t === 'boost' || _t === 'follow' || _t === 'poll_done') ? 'act'
101 : _t === 'report' ? 'mod'
102 : 'conv';
103 // Binnen een draad is dit geen zelfstandige regel: de chip filtert op
104 // de draad, niet op de losse zinnen erin.
105 var _sub = (typeof inThread !== 'undefined' && inThread);
106 var _init = String(_who || '?').replace(/^@/, '').charAt(0).toUpperCase();
107 var _priv = (n.visibility === 'followers' || n.visibility === 'direct');
108 %>
109 <li class="<%= _sub ? 'msg-sub' : 'msg-item' %> msg-<%= _t %><%= _new ? ' is-new' : '' %>"<% if (!_sub) { %> data-kind="<%= _kind %>"<% } %> data-who="<%= String(_who).toLowerCase() %>">
110 <span class="msg-av<%= _t === 'sent' ? ' msg-av-sent' : '' %>" aria-hidden="true">
111 <% if (_t === 'sent') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
112 <% } else if (_t === 'poll_done') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
113 <% } else if (n.icon) { %><img src="<%= avatar(n.icon, 96) %>" alt="" loading="lazy">
114 <% } else { %><%= _init %><% } %>
115 <span class="msg-dot msg-dot-<%= _t %>">
116 <% if (_t === 'like') { %><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.6l2.9 5.88 6.49.95-4.7 4.58 1.11 6.46L12 17.96l-5.8 3.06 1.1-6.46-4.69-4.58 6.49-.95z"/></svg>
117 <% } else if (_t === 'boost') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
118 <% } else if (_t === 'follow') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>
119 <% } else if (_t === 'report') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" y1="22" x2="4" y2="15"/></svg>
120 <% } else if (_t === 'mention') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"/></svg>
121 <% } else if (_t === 'sent') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
122 <% } else if (_t === 'poll_done') { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>
123 <% } else { %><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><% } %>
124 </span>
125 </span>
126
127 <div class="msg-body">
128 <div class="msg-line">
129 <% if (_t === 'sent') { %>
130 <span class="msg-who"><%= t('msg.you') %></span>
131 <% if (n.to_handle && !_sub) { %><span class="msg-handle">→ <%= n.to_handle %></span><% } %>
132 <% } else { %>
133 <a class="msg-who" href="<%= n.url %>" target="_blank" rel="nofollow noopener"><%- emojiName(_who, n.actor_emoji_json) %></a>
134 <% /* De naam blijft: binnen een draad moet je zien WIE wat zei.
135 De handle erachter niet -- die staat in de kop. */ %>
136 <% if (n.handle && n.name && !_sub) { %><span class="msg-handle"><%= n.handle %></span><% } %>
137 <% } %>
138 <% if (_new) { %><span class="msg-new" title="<%= t('msg.new') %>"></span><% } %>
139 <% /* When the post was written, like de Krant and de Guardian PWA
140 show it. created_at (when it reached us) stays the sort key
141 and drives the "new since your last visit" dot above. */ %>
142 <% if (n.published || n.created_at) { %><span class="msg-time"><%= formatDateTime(n.published || n.created_at) %></span><% } %>
143 </div>
144
145 <% var _hasWhat = !_sub || _priv
146 || (_t === 'mention' && (n.help_request || n.wave || n.note_url))
147 || (_t === 'sent' && n.in_reply_to); %>
148 <% if (_hasWhat) { %>
149 <div class="msg-what">
150 <% if (n.count && n.count > 1) { %>
151 <strong><%= t('msg.and_more', { n: n.count - 1 }) %></strong>
152 <%= _t === 'like' ? t('msg.liked_many') : t('msg.boosted_many') %>
153 <% } else if (_t === 'follow') { %><%= t('notif.followed') %>
154 <% } else if (_t === 'like') { %><%= t('notif.liked') %>
155 <% } else if (_t === 'boost') { %><%= t('notif.boosted') %>
156 <% } else if (_t === 'report') { %><%= t('notif.reported') %>
157 <% } else if (_t === 'mention' && n.help_request) { %>🛟 <%= t('msg.help_request') %>
158 <% } else if (_t === 'mention' && n.wave) { %>👋 <%= t('msg.waved_at_you') %>
159 <% } else if (_sub) { %><%# binnen een draad zegt de kop al dat dit een gesprek is %>
160 <% } else if (_t === 'mention') { %><%= t('notif.mentioned') %>
161 <% } else if (_t === 'sent') { %><%= t('msg.sent_reply') %>
162 <% } else if (_t === 'poll_done') { %><strong><%= t('msg.poll_done') %></strong>
163 <% } else { %><%= t('notif.replied') %><% } %>
164 <% if (_priv) { %><span class="msg-priv" title="<%= t('msg.private_hint') %>">🔒 <%= t('msg.private') %></span><% } %>
165 <% if (n.post_slug && !_sub) { %><a class="msg-post" href="/<%= n.post_slug %>"><%= n.post_title || n.post_slug %></a><% } %>
166 <% if (_t === 'mention' && n.note_url) { %><a class="msg-post" href="<%= n.note_url %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
167 <% if (_t === 'sent' && n.in_reply_to) { %><a class="msg-post" href="<%= n.in_reply_to %>" target="_blank" rel="nofollow noopener"><%= t('tl.view_original') %></a><% } %>
168 </div>
169 <% } %>
170
171 <% if (_t === 'report' && n.content) { %><div class="msg-content"><%= n.content %></div>
172 <% } else if ((_t === 'reply' || _t === 'mention' || _t === 'sent') && n.content) { %><div class="msg-content msg-note"><%- include('../partials/note-body', { nb: n }) %></div>
173 <% if (_t === 'mention' && n.wave && n.actorUri && canMutate) { %>
174 <form class="msg-quickreply" method="post" action="<%= (typeof siteUrlBase !== 'undefined' ? siteUrlBase : '') %>/messages/quick-reply" data-sent="<%= t('msg.wave_sent') %>" style="display:flex;gap:6px;flex-wrap:wrap;margin-top:6px">
175 <input type="hidden" name="to" value="<%= n.actorUri %>">
176 <button class="btn small" name="text" value="<%= t('msg.wave_r1') %>"><%= t('msg.wave_r1') %></button>
177 <button class="btn small" name="text" value="<%= t('msg.wave_r2') %>"><%= t('msg.wave_r2') %></button>
178 <button class="btn small" name="text" value="👋"><%= t('msg.wave_back') %></button>
179 </form>
180 <% } %>
181 <% } else if (_t === 'poll_done' && n.poll) { %>
182 <div class="msg-poll" role="group">
183 <% n.poll.options.forEach(function (o) { %>
184 <div class="msg-poll-opt">
185 <div class="msg-poll-top"><span class="msg-poll-name"><%= o.name %></span><span class="msg-poll-pct"><%= o.pct %>%</span></div>
186 <div class="msg-poll-bar"><span style="width:<%= o.pct %>%"></span></div>
187 </div>
188 <% }); %>
189 <div class="msg-poll-total"><%= t('msg.poll_total', { n: n.poll.voters }) %></div>
190 </div>
191 <% } %>
192
193 <% if (_t === 'sent' && n.outboxId) { %>
194 <div class="msg-actions">
195 <details class="msg-edit">
196 <summary><%= t('fedi.edit') %></summary>
197 <div class="msg-edit-form">
198 <%- include('../partials/reply-editor', {
199 action: '/fediverse/' + n.outboxId + '/edit',
200 placeholder: t('fedi.reply_ph'),
201 submitLabel: t('fedi.save_edit'),
202 rows: 2,
203 initialHtml: n.content,
204 initialText: n.editable,
205 defaultLang: n.language,
206 noAttach: true,
207 }) %>
208 </div>
209 </details>
210 <form method="post" action="/fediverse/<%= n.outboxId %>/delete" data-confirm="<%= t('fedi.delete_confirm') %>">
211 <button type="submit" class="msg-del"><%= t('comments.delete') %></button>
212 </form>
213 </div>
214 <% } %>
215 </div>
216 </li>
217<% } %>
Note: See TracBrowser for help on using the repository browser.