
I am no longer going to support all the features and every NIP. It's too hard. Thus I am reducing what I support in YoSup. From now on it will only be a simple client with simple needs that serve me. I will continue to use Damus on iOS or other clients for sending Zaps or using other functionality. I do not feel I need to support these features and it has me competing with other clients such as Snort or Iris, I don't want to be a clone of them - I want a simple client for my needs: viewing what's up from people I follow. Thus I have started removing features and optimizing. Especially for the very poor internet connection here in Costa Rica, reducing load of images, content, etc. makes the client much faster and easier to use. If you feel you are missing features please use the other clients that have put in a LOT of hard work.
231 lines
6.4 KiB
JavaScript
231 lines
6.4 KiB
JavaScript
/* This file contains utility functions related to UI manipulation. Some code
|
|
* may be specific to areas of the UI and others are more utility based. As
|
|
* this file grows specific UI area code should be migrated to its own file.
|
|
*/
|
|
|
|
/* toggle_gnav hides or shows the global navigation's additional buttons based
|
|
* on its opened state.
|
|
*/
|
|
function toggle_gnav(el) {
|
|
el.parentElement.classList.toggle("open");
|
|
}
|
|
|
|
function close_gnav() {
|
|
find_node("#gnav").classList.remove("open");
|
|
}
|
|
|
|
/* init_message_textareas finds all message textareas and updates their initial
|
|
* height based on their content (0). This is so there is no jaring affect when
|
|
* the page loads.
|
|
*/
|
|
function init_message_textareas() {
|
|
const els = document.querySelectorAll(".post-input");
|
|
for (const el of els) {
|
|
trigger_postbox_assess(el);
|
|
}
|
|
}
|
|
|
|
// update_notification_markers will find all markers and hide or show them
|
|
// based on the passed in state of 'active'. This applies to the navigation
|
|
// icons.
|
|
function update_notification_markers(active, type) {
|
|
let els = document.querySelectorAll(`.new-notifications[role='${type}']`)
|
|
for (const el of els) {
|
|
el.classList.toggle("hide", !active)
|
|
}
|
|
}
|
|
|
|
/* newlines_to_br takes a string and converts all newlines to HTML 'br' tags.
|
|
*/
|
|
function newlines_to_br(str="") {
|
|
return str.split("\n").reduce((acc, part, index) => {
|
|
return acc + part + "<br/>";
|
|
}, "");
|
|
}
|
|
|
|
function show_new() {
|
|
view_timeline_show_new(DAMUS);
|
|
}
|
|
|
|
function click_share(el) {
|
|
share(el.dataset.evid);
|
|
}
|
|
|
|
function click_toggle_like(el) {
|
|
// Disable the button to prevent multiple presses
|
|
el.disabled = true;
|
|
if (el.dataset.liked == "yes") {
|
|
delete_post(el.dataset.reactionId);
|
|
return;
|
|
}
|
|
send_reply(R_SHAKA, el.dataset.reactingTo);
|
|
}
|
|
|
|
/* open_media_preview presents a modal to display an image via "url".
|
|
*/
|
|
function open_media_preview(url, type) {
|
|
const el = find_node("#media-preview");
|
|
el.showModal();
|
|
find_node("img", el).src = url;
|
|
// TODO handle different medias such as audio and video
|
|
// TODO add loading state & error checking
|
|
}
|
|
|
|
/* close_media_preview closes any present media modal.
|
|
*/
|
|
function close_media_preview() {
|
|
find_node("#media-preview").close();
|
|
}
|
|
|
|
function delete_post_confirm(evid) {
|
|
if (!confirm("Are you sure you want to delete this post?"))
|
|
return;
|
|
const reason = (prompt("Why you are deleting this? Leave empty to not specify. Type CANCEL to cancel.") || "").trim()
|
|
if (reason.toLowerCase() === "cancel")
|
|
return;
|
|
delete_post(evid, reason)
|
|
}
|
|
|
|
async function do_send_reply(all=false) {
|
|
const modal = document.querySelector("#reply-modal");
|
|
const replying_to = modal.querySelector("#replying-to");
|
|
const evid = replying_to.dataset.evid;
|
|
const reply_content_el = document.querySelector("#reply-content");
|
|
const content = reply_content_el.value;
|
|
await send_reply(content, evid, all);
|
|
reply_content_el.value = "";
|
|
close_modal(modal);
|
|
}
|
|
|
|
function update_reply_box(state="new") {
|
|
const isnew = state == "new";
|
|
const modal = document.querySelector("#reply-modal");
|
|
modal.querySelector("#replying-to").classList.toggle("hide", isnew);
|
|
modal.querySelector("header label").textContent = isnew ? "New Note" : "Replying To";
|
|
modal.querySelector(".post-tools.new").classList.toggle("hide", !isnew);
|
|
modal.querySelector(".post-tools.reply").classList.toggle("hide", isnew);
|
|
}
|
|
|
|
function new_note() {
|
|
const modal = document.querySelector("#reply-modal");
|
|
const inputbox = modal.querySelector("#reply-content");
|
|
update_reply_box("new");
|
|
inputbox.placeholder = "What's up?";
|
|
modal.showModal();
|
|
inputbox.focus();
|
|
}
|
|
|
|
function reply(evid) {
|
|
const ev = DAMUS.all_events[evid]
|
|
const modal = document.querySelector("#reply-modal")
|
|
const replybox = modal.querySelector("#reply-content")
|
|
const replying_to = modal.querySelector("#replying-to")
|
|
update_reply_box("reply");
|
|
replying_to.dataset.evid = evid
|
|
replying_to.classList.remove("hide");
|
|
replying_to.innerHTML = render_event_nointeract(DAMUS, ev, {
|
|
is_composing: true,
|
|
nobar: true
|
|
});
|
|
replybox.placeholder = "Reply...";
|
|
modal.showModal();
|
|
replybox.focus();
|
|
}
|
|
|
|
function update_favicon(path) {
|
|
let link = document.querySelector("link[rel~='icon']");
|
|
const head = document.getElementsByTagName('head')[0]
|
|
|
|
if (!link) {
|
|
link = document.createElement('link');
|
|
link.rel = 'icon';
|
|
head.appendChild(link);
|
|
}
|
|
|
|
link.href = path;
|
|
}
|
|
|
|
// update_notifications updates the document title & visual indicators based on if the
|
|
// number of notifications that are unseen by the user.
|
|
function update_notifications(model) {
|
|
let dm_count = 0;
|
|
for (const item of model.dms) {
|
|
if (item[1].new_count)
|
|
dm_count += item[1].new_count;
|
|
}
|
|
|
|
const { count } = model.notifications;
|
|
const suffix = "Yo Sup";
|
|
const total = count + dm_count;
|
|
document.title = total ? `(${total}) ${suffix}` : suffix;
|
|
// TODO I broke the favicons; I will fix with later.
|
|
//update_favicon(has_notes ? "img/damus_notif.svg" : "img/damus.svg");
|
|
update_notification_markers(count, "activity");
|
|
update_notification_markers(dm_count, "dm");
|
|
// slight hack :)
|
|
find_node("#header-tools button[action='mark-all-read']")
|
|
.disabled = dm_count == 0;
|
|
}
|
|
|
|
async function get_pubkey(use_prompt=true) {
|
|
let pubkey = get_local_state('pubkey')
|
|
if (pubkey)
|
|
return pubkey
|
|
if (window.nostr && window.nostr.getPublicKey) {
|
|
log_debug("calling window.nostr.getPublicKey()...")
|
|
try {
|
|
pubkey = await window.nostr.getPublicKey()
|
|
return await handle_pubkey(pubkey)
|
|
} catch (err) {
|
|
return;
|
|
}
|
|
log_debug("got %s pubkey from nos2x", pubkey)
|
|
}
|
|
if (!use_prompt)
|
|
return;
|
|
pubkey = prompt("Enter Nostr ID (eg: jb55@jb55.com) or public key (hex or npub).")
|
|
if (!pubkey.trim())
|
|
return;
|
|
return await handle_pubkey(pubkey)
|
|
}
|
|
|
|
function get_privkey() {
|
|
let privkey = get_local_state('privkey')
|
|
if (privkey)
|
|
return privkey
|
|
if (!privkey)
|
|
privkey = prompt("Enter private key")
|
|
if (!privkey)
|
|
throw new Error("can't get privkey")
|
|
if (privkey[0] === "n") {
|
|
privkey = bech32_decode(privkey)
|
|
}
|
|
set_local_state('privkey', privkey)
|
|
return privkey
|
|
}
|
|
|
|
function open_thread(thread_id) {
|
|
view_timeline_apply_mode(DAMUS, VM_THREAD, { thread_id });
|
|
}
|
|
|
|
function close_modal(el) {
|
|
find_parent(el, "dialog").close();
|
|
}
|
|
|
|
function on_click_show_event_details(evid) {
|
|
const model = DAMUS;
|
|
const ev = model.all_events[evid];
|
|
if (!ev)
|
|
return;
|
|
const el = find_node("#event-details");
|
|
el.showModal();
|
|
find_node("code", el).innerText = JSON.stringify(ev, null, "\t");
|
|
}
|
|
|
|
function onclick_pfp(ev) {
|
|
open_profile(ev.target.dataset.pubkey);
|
|
}
|
|
|
|
function onerror_pfp(ev) {
|
|
ev.target.src = IMG_NO_USER;
|
|
}
|