Changeset e00c0e9 in Klonkt for src/services/ActivityPubService.js
- Timestamp:
- 07/01/2026 10:06:57 PM (2 months ago)
- Branches:
- main
- Children:
- 254939c
- Parents:
- d11e308
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
rd11e308 re00c0e9 343 343 body = body.replace(/\r?\n/g, '<br>'); 344 344 body = linkHashtags(base, body); // link inline #hashtags in the post body too 345 body = linkUrls(body); // bare URLs → clickable links on the federated copy 345 346 // Append the tags-field hashtags to the content so Mastodon renders them as clickable 346 347 // hashtags (a Hashtag that's only in the `tag` array isn't shown inline). CamelCase … … 1371 1372 `${pre}<a href="${base}/tag/${encodeURIComponent(tag.toLowerCase())}" class="mention hashtag" rel="tag">#${tag}</a>`); 1372 1373 } 1374 // Auto-link bare http(s) URLs in already-safe HTML (federated copies). Splits on existing 1375 // <a>…</a> so a linked URL is never wrapped twice; requires start/whitespace/'>' before the 1376 // URL so attribute values (src="https://…") never match. Trailing sentence punctuation stays 1377 // outside the link (Mastodon-style). 1378 function linkUrls(html) { 1379 const parts = String(html || '').split(/(<a\b[^>]*>[\s\S]*?<\/a>)/gi); 1380 for (let i = 0; i < parts.length; i++) { 1381 if (/^<a\b/i.test(parts[i])) continue; // already a link → leave as-is 1382 parts[i] = parts[i].replace(/(^|[\s>])(https?:\/\/[^\s<]+?)([.,;:!?)\]»]*)(?=$|[\s<])/g, 1383 (m, pre, url, trail) => `${pre}<a href="${url.replace(/"/g, '%22')}" rel="nofollow noopener" target="_blank">${url}</a>${trail}`); 1384 } 1385 return parts.join(''); 1386 } 1373 1387 // Extract the AP Hashtag tag objects from already-linked reply content. 1374 1388 function hashtagTags(base, content) { … … 1497 1511 const mention = parent.actor_uri 1498 1512 ? `<a href="${escHtml(parent.actor_url || parent.actor_uri)}" class="u-url mention" data-actor="${escHtml(parent.actor_uri)}">${escHtml(dispHandle)}</a> ` : ''; 1499 const content = `<p>${mention}${link Hashtags(base, mres.html)}</p>`;1513 const content = `<p>${mention}${linkUrls(linkHashtags(base, mres.html))}</p>`; 1500 1514 // Dedup: skip if the exact same reply was already sent (double-submit guard). 1501 1515 const dup = db.prepare('SELECT 1 FROM ap_outbox WHERE site_slug = ? AND IFNULL(in_reply_to, \'\') = ? AND content = ? LIMIT 1') … … 1657 1671 ? `<a href="${escHtml(toProfile)}" class="u-url mention" data-actor="${escHtml(row.to_actor)}">${escHtml(toHandle)}</a> ` : ''; 1658 1672 const mres = await resolveMentionsInText(base, escHtml(text).replace(/\r?\n/g, '<br>')); 1659 const content = `<p>${mention}${link Hashtags(base, mres.html)}</p>`;1673 const content = `<p>${mention}${linkUrls(linkHashtags(base, mres.html))}</p>`; 1660 1674 db.prepare('UPDATE ap_outbox SET content = ? WHERE id = ?').run(content, outboxId); 1661 1675 const note = buildReplyNote(base, site, iStmts().getO.get(outboxId));
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)