Changeset 2e62848 in Klonkt
- Timestamp:
- 06/28/2026 10:07:38 AM (2 months ago)
- Branches:
- main
- Children:
- 37a297d
- Parents:
- 907a013
- File:
-
- 1 edited
-
src/services/ActivityPubService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/services/ActivityPubService.js
r907a013 r2e62848 229 229 body = body.replace(/\r?\n/g, '<br>'); 230 230 body = linkHashtags(base, body); // link inline #hashtags in the post body too 231 // Append the tags-field hashtags to the content so Mastodon renders them as clickable 232 // hashtags (a Hashtag that's only in the `tag` array isn't shown inline). CamelCase 233 // multi-word tags; skip any already present inline in the body. 234 { 235 const inlineTags = new Set(hashtagTags(base, body).map((h) => h.name.slice(1).toLowerCase())); 236 const addSeen = new Set(); 237 const tagLinks = normalizeTags(post.tags).map(tagParts).filter(Boolean) 238 .filter((p) => !inlineTags.has(p.slug) && !addSeen.has(p.slug) && addSeen.add(p.slug)) 239 .map((p) => `<a href="${base}/tag/${encodeURIComponent(p.slug)}" class="mention hashtag" rel="tag">#${p.label}</a>`); 240 if (tagLinks.length) body += `<p>${tagLinks.join(' ')}</p>`; 241 } 231 242 const seen = new Set(); 232 243 const attachment = urls.filter(Boolean) … … 915 926 } 916 927 928 // Normalise a post's tags field (array, JSON-string, or comma-string) to an array. 929 function normalizeTags(t) { 930 if (Array.isArray(t)) return t; 931 if (typeof t === 'string') { 932 const s = t.trim(); if (!s) return []; 933 if (s[0] === '[') { try { const a = JSON.parse(s); return Array.isArray(a) ? a : []; } catch { /* fall through */ } } 934 return s.split(',').map((x) => x.trim()).filter(Boolean); 935 } 936 return []; 937 } 938 // A tag → { label, slug }. Multi-word tags become CamelCase (#LiveMusic) for the display 939 // name (Mastodon hashtags can't contain spaces; CamelCase is the accessibility norm); the 940 // slug/href stays lowercase ("livemusic"). 941 function tagParts(raw) { 942 const words = String(raw || '').trim().split(/[\s_]+/).map((w) => w.replace(/[^A-Za-z0-9]/g, '')).filter(Boolean); 943 if (!words.length) return null; 944 const slug = words.join('').toLowerCase(); 945 if (!slug) return null; 946 const label = words.length > 1 ? words.map((w) => w[0].toUpperCase() + w.slice(1)).join('') : words[0]; 947 return { label, slug }; 948 } 917 949 // Merge a post's tags field + the #hashtags linked inline in its body into one deduped 918 950 // Hashtag tag list (with hrefs to our /tag page). 919 951 function buildHashtagList(base, tagsField, content) { 920 952 const out = [], seen = new Set(); 921 for (const t of (Array.isArray(tagsField) ? tagsField : [])) { 922 const name = String(t).replace(/\s+/g, ''); if (!name) continue; 923 const k = name.toLowerCase(); if (seen.has(k)) continue; seen.add(k); 924 out.push({ type: 'Hashtag', href: `${base}/tag/${encodeURIComponent(k)}`, name: '#' + name }); 953 for (const t of normalizeTags(tagsField)) { 954 const p = tagParts(t); if (!p || seen.has(p.slug)) continue; seen.add(p.slug); 955 out.push({ type: 'Hashtag', href: `${base}/tag/${encodeURIComponent(p.slug)}`, name: '#' + p.label }); 925 956 } 926 957 for (const h of hashtagTags(base, content)) {
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)