From 7ccb07ffc3c419adab4a080bdbab03396603dfa0 Mon Sep 17 00:00:00 2001 From: Thomas Mathews Date: Mon, 16 Jan 2023 19:52:41 -0800 Subject: [PATCH] Added support for rendering mentions. --- js/event.js | 10 ++++++++-- js/main.js | 1 + js/ui/fmt.js | 45 +++++++++++++++++++++++++++++++++++++++++++-- js/ui/render.js | 15 +++++++-------- js/ui/state.js | 10 ++++++++++ 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/js/event.js b/js/event.js index 386edc5..e682630 100644 --- a/js/event.js +++ b/js/event.js @@ -25,8 +25,8 @@ function event_tags_pubkey(ev, pubkey) { return false } -function event_get_pubkeys(ev) { - const keys = [ev.pubkey]; +function event_get_tagged_pubkeys(ev) { + const keys = []; for (const tag of ev.tags) { if (tag.length >= 2 && tag[0] == "p") keys.push(tag[1]); @@ -34,6 +34,12 @@ function event_get_pubkeys(ev) { return keys; } +function event_get_pubkeys(ev) { + const keys = event_get_tagged_pubkeys(ev); + keys.splice(0, 0, ev.pubkey); + return keys; +} + function event_calculate_pow(ev) { const id_bits = leading_zero_bits(ev.id) for (const tag of ev.tags) { diff --git a/js/main.js b/js/main.js index bdc1bc9..e197f31 100644 --- a/js/main.js +++ b/js/main.js @@ -72,6 +72,7 @@ async function webapp_init() { // WARNING Order Matters! init_message_textareas(); + init_timeline(model); init_my_pfp(model); init_postbox(model); init_profile(); diff --git a/js/ui/fmt.js b/js/ui/fmt.js index 4928e1e..9689400 100644 --- a/js/ui/fmt.js +++ b/js/ui/fmt.js @@ -24,7 +24,7 @@ function linkify(text="", show_media=false) { }) } -function format_content(ev, show_media) { +function format_content(model, ev, show_media) { if (ev.kind === KIND_REACTION) { if (ev.content === "" || ev.content === "+") return "❤️" @@ -32,7 +32,8 @@ function format_content(ev, show_media) { } const content = (ev.kind == KIND_DM ? ev.decrypted || ev.content : ev.content) .trim(); - const body = fmt_body(content, show_media); + const body = fmt_mentions(model, fmt_body(content, show_media), + event_get_tagged_pubkeys(ev)); let cw = get_content_warning(ev.tags) if (cw !== null) { let cwHTML = "Content Warning" @@ -50,6 +51,46 @@ function format_content(ev, show_media) { return body; } +function fmt_mentions(model, str, pubkeys) { + var buf = ""; + for (var i = 0; i < str.length; i++) { + let c = str.charAt(i); + let peek = str.charAt(i+1); + if (!(c == "#" && peek == "[")) { + buf += c; + continue; + } + const start = i; + i += 2; + let x = ""; + for(;;) { + c = str.charAt(i); + if (c >= '0' && c <= '9') { + x += c; + i++; + } else if (c == ']') { + break; + } else { + buf += x; + x = ""; + break; + } + } + if (x == "") + continue; + // Specification says it's 0-based, but everyone is doing 1-base + let pubkey = pubkeys[parseInt(x)]; + if (!pubkey) { + buf += "(Invalid User Mentioned)" + continue; + } + let profile = model_get_profile(model, pubkey); + buf += ` + ${fmt_name(profile)}`; + } + return buf; +} + /* fmt_body will parse images, blockquotes, and sanitize the content. */ function fmt_body(content, show_media) { diff --git a/js/ui/render.js b/js/ui/render.js index 2e73c58..169749d 100644 --- a/js/ui/render.js +++ b/js/ui/render.js @@ -94,7 +94,7 @@ function render_dm(model, ev, opts) { return html`
-

$${format_content(ev, show_media)}

+

$${format_content(model, ev, show_media)}

${delta}
@@ -109,7 +109,7 @@ function event_shows_media(model, ev, mode) { function rerender_dm(model, ev, el) { let show_media = event_shows_media(model, ev, model.embeds); - find_node(".body > p", el).innerHTML = format_content(ev, show_media); + find_node(".body > p", el).innerHTML = format_content(model, ev, show_media); } function render_event_nointeract(model, ev, opts={}) { @@ -145,7 +145,7 @@ function render_event_body(model, ev, opts) { let str = "
"; str += shared ? render_shared_by(ev, opts) : render_replying_to(model, ev); str += `

- ${format_content(ev, show_media)} + ${format_content(model, ev, show_media)}

`; str += render_reactions(model, ev); str += opts.nobar || ev.kind == KIND_DM ? "" : @@ -258,8 +258,7 @@ function render_pubkey(pk) { return fmt_pubkey(pk); } -function render_username(pk, profile) -{ +function render_username(pk, profile) { return (profile && profile.name) || render_pubkey(pk) } @@ -269,9 +268,9 @@ function render_mentioned_name(pk, profile) { function render_name(pk, profile, prefix="") { // Beware of whitespace. - return html`${prefix} ${fmt_profile_name(profile, fmt_pubkey(pk))}` + return html`${prefix} + ${fmt_profile_name(profile, fmt_pubkey(pk))}` } function render_profile_img(profile, noclick=false) { diff --git a/js/ui/state.js b/js/ui/state.js index f2c5d99..d8f79af 100644 --- a/js/ui/state.js +++ b/js/ui/state.js @@ -468,6 +468,16 @@ function html2el(html) { return div.firstChild; } +function init_timeline(model) { + const el = view_get_timeline_el(); + el.addEventListener("click", onclick_timeline); +} +function onclick_timeline(ev) { + if (ev.target.matches(".username[data-pubkey]")) { + open_profile(ev.target.dataset.pubkey); + } +} + function init_my_pfp(model) { find_nodes(`img[role='my-pfp']`).forEach((el)=> { el.dataset.pubkey = model.pubkey;