// This file contains all methods related to rendering UI elements. Rendering // is done by simple string manipulations & templates. If you need to write // loops simply write it in code and return strings. /*function render_timeline_event(damus, view, ev) { const root_id = get_thread_root_id(damus, ev.id) const max_depth = root_id ? get_thread_max_depth(damus, view, root_id) : get_default_max_depth(damus, view) if (ev.refs && ev.refs.root && view.expanded.has(ev.refs.root)) max_depth = null return render_event(damus, view, ev, {max_depth}) } function render_events(damus, view) { return view.events .filter((ev, i) => i < 140) .map((ev) => render_timeline_event(damus, view, ev)).join("\n") }*/ function render_reply_line_top(has_top_line) { const classes = has_top_line ? "" : "invisible" return `
` } function render_reply_line_bot() { return `
` } function render_thread_collapsed(model, ev, opts) { if (opts.is_composing) return "" return `
Read More
` } function render_replied_events(damus, view, ev, opts) { if (!(ev.refs && ev.refs.reply)) return "" const reply_ev = damus.all_events[ev.refs.reply] if (!reply_ev) return "" opts.replies = opts.replies == null ? 1 : opts.replies + 1 if (!(opts.max_depth == null || opts.replies < opts.max_depth)) return render_thread_collapsed(damus, ev, opts) opts.is_reply = true return render_event(damus, view, reply_ev, opts) } function render_replying_to_chat(damus, ev) { const chatroom = (ev.refs.root && damus.chatrooms[ev.refs.root]) || {} const roomname = chatroom.name || ev.refs.root || "??" const pks = ev.refs.pubkeys || [] const names = pks.map(pk => render_mentioned_name(pk, damus.profiles[pk])).join(", ") const to_users = pks.length === 0 ? "" : ` to ${names}` return `
replying${to_users} in ${roomname}
` } function render_replying_to(model, ev) { if (!(ev.refs && ev.refs.reply)) return "" if (ev.kind === 42) return render_replying_to_chat(model, ev) let pubkeys = ev.refs.pubkeys || [] if (pubkeys.length === 0 && ev.refs.reply) { const replying_to = model.all_events[ev.refs.reply] if (!replying_to) return `
reply to ${ev.refs.reply}
` pubkeys = [replying_to.pubkey] } const names = ev.refs.pubkeys.map(pk => render_mentioned_name(pk, model.profiles[pk])).join(", ") return ` replying to ${names} ` } function render_unknown_event(damus, ev) { return "Unknown event " + ev.kind } function render_share(damus, view, ev, opts) { // TODO validate content const shared_ev = damus.all_events[ev.refs && ev.refs.root] // share isn't resolved yet. that's ok, we can render this when we have // the event if (!shared_ev) return "" opts.shared = { pubkey: ev.pubkey, profile: damus.profiles[ev.pubkey] } return render_event(damus, view, shared_ev, opts) } function render_comment_body(damus, ev, opts) { const can_delete = damus.pubkey === ev.pubkey; const bar = !can_reply(ev) || opts.nobar ? "" : render_action_bar(damus, ev, {can_delete}) const show_media = !opts.is_composing return `
${render_replying_to(damus, ev)} ${render_shared_by(ev, opts)}

${format_content(ev, show_media)}

${render_reactions(damus, ev)} ${bar} ` } function render_shared_by(ev, opts) { const b = opts.shared if (!b) { return "" } return `
Shared by ${render_name(b.pubkey, b.profile)}
` } function render_deleted_comment_body(ev, deleted) { if (deleted.content) { return `
This content was deleted with reason:
${format_content(deleted, false)}
` } return `
This content was deleted.
` } /*function render_event(damus, view, ev, opts={}) { if (ev.kind === 6) return render_share(damus, view, ev, opts) if (shouldnt_render_event(damus.pubkey, view, ev, opts)) return "" view.rendered.add(ev.id) const has_bot_line = opts.is_reply const reply_line_bot = (has_bot_line && render_reply_line_bot()) || "" if (opts.is_composing) has_bot_line = true; const deleted = is_deleted(damus, ev.id) if (deleted && !opts.is_reply) return "" const replied_events = render_replied_events(damus, view, ev, opts) let name = "" if (!deleted) { name = render_name_plain(profile) } const has_top_line = replied_events !== "" return ` ${replied_events} ` + render_event2(damus, ev, { deleted, has_top_line, has_bot_line, reply_line_bot, }); }*/ function render_event(model, ev, opts={}) { let { has_bot_line, has_top_line, reply_line_bot, } = opts const thread_root = (ev.refs && ev.refs.root) || ev.id; const profile = model.profiles[ev.pubkey]; const delta = fmt_since_str(new Date().getTime(), ev.created_at*1000) const border_bottom = opts.is_composing || has_bot_line ? "" : "bottom-border"; let thread_btn = ""; if (!reply_line_bot) reply_line_bot = ''; return `
${render_reply_line_top(has_top_line)} ${render_pfp(ev.pubkey, profile)} ${reply_line_bot}
${render_name(ev.pubkey, profile)} ${delta}
${render_comment_body(model, ev, opts)}
` } function render_event_nointeract(model, ev, opts={}) { const profile = model.profiles[ev.pubkey]; const delta = fmt_since_str(new Date().getTime(), ev.created_at*1000) return `
${render_pfp(ev.pubkey, profile)}
${render_name(ev.pubkey, profile)} ${delta}
${render_comment_body(model, ev, opts)}
` } function render_react_onclick(our_pubkey, reacting_to, emoji, reactions) { const reaction = reactions[our_pubkey] if (!reaction) { return `onclick="send_reply('${emoji}', '${reacting_to}')"` } else { return `onclick="delete_post('${reaction.id}')"` } } function render_reaction_group(model, emoji, reactions, reacting_to) { const pfps = Object.keys(reactions).map((pk) => render_reaction(model, reactions[pk])) let onclick = render_react_onclick(model.pubkey, reacting_to.id, emoji, reactions) return ` ${emoji} ${pfps.join("\n")} ` } function render_reaction(model, reaction) { const profile = model.profiles[reaction.pubkey] let emoji = reaction.content[0] if (reaction.content === "+" || reaction.content === "") emoji = "❤️" return render_pfp(reaction.pubkey, profile) } function render_action_bar(model, ev, opts={}) { let { can_delete } = opts; let delete_html = "" if (can_delete) delete_html = ` ` const groups = get_reactions(model, ev.id) const react_onclick = render_react_onclick(model.pubkey, ev.id, "❤️", groups["❤️"] || {}) return `
${delete_html}
` } function render_reactions(model, ev) { const groups = get_reactions(model, ev.id) let str = "" for (const emoji of Object.keys(groups)) { str += render_reaction_group(model, emoji, groups[emoji], ev) } return `
${str}
` } // Utility Methods /* render_name_plain takes in a profile and tries it's best to return a string * that is best suited for the profile. */ function render_name_plain(profile=DEFAULT_PROFILE) { if (profile.sanitized_name) return profile.sanitized_name const display_name = profile.display_name || profile.user const username = profile.name || "anon" const name = display_name || username profile.sanitized_name = sanitize(name) return profile.sanitized_name } function render_pubkey(pk) { return pk.slice(-8) } function render_username(pk, profile) { return (profile && profile.name) || render_pubkey(pk) } function render_mentioned_name(pk, profile) { return render_name(pk, profile, "@"); //return `@${render_username(pk, profile)}` } function render_name(pk, profile, prefix="") { return ` ${prefix} ${render_name_plain(profile)} ` } function render_deleted_name() { return "" } function render_pfp(pk, profile) { const name = render_name_plain(profile) return `` } function render_deleted_pfp() { return `
` } function render_loading_spinner() { return `
` }