+
+
+
+
diff --git a/js/core.js b/js/core.js
index 0934183..47bcef8 100644
--- a/js/core.js
+++ b/js/core.js
@@ -21,6 +21,12 @@ const STANDARD_KINDS = [
KIND_REACTION,
KIND_SHARE,
];
+const PUBLIC_KINDS = [
+ KIND_NOTE,
+ KIND_DELETE,
+ KIND_REACTION,
+ KIND_SHARE,
+];
function get_local_state(key) {
if (DAMUS[key] != null)
diff --git a/js/main.js b/js/main.js
index 3005d1f..1ac48c8 100644
--- a/js/main.js
+++ b/js/main.js
@@ -6,14 +6,13 @@ const IMG_EVENT_LIKE = "/icon/event-like.svg";
const IMG_NO_USER = "/icon/no-user.svg";
const SID_META = "meta";
-const SID_HISTORY = "history";
-const SID_NOTIFICATIONS = "notifications";
-const SID_DMS_OUT = "dms_out";
-const SID_DMS_IN = "dms_in";
-const SID_EXPLORE = "explore";
-const SID_PROFILES = "profiles";
-const SID_THREAD = "thread";
-const SID_FRIENDS = "friends";
+const SID_HISTORY = "hist";
+const SID_NOTIFICATIONS = "noti";
+const SID_DMS_OUT = "dout";
+const SID_DMS_IN = "din";
+const SID_PROFILES = "prof";
+const SID_THREAD = "thrd";
+const SID_FRIENDS = "frds";
// This is our main entry.
// https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event
@@ -69,6 +68,7 @@ async function signin() {
}
async function webapp_init() {
+ let err;
const model = DAMUS;
// WARNING Order Matters!
@@ -81,11 +81,10 @@ async function webapp_init() {
// Load data from storage
await model_load_settings(model);
- let err;
- err = await contacts_load(model);
+ /*err = await contacts_load(model);
if (err) {
window.alert("Unable to load contacts.");
- }
+ }*/
init_settings(model);
// Create our pool so that event processing functions can work
@@ -132,7 +131,7 @@ function parse_url_mode() {
}
switch (mode) {
case VM_FRIENDS:
- opts.hide_replys = true;
+ //opts.hide_replys = true;
break;
case VM_THREAD:
opts.thread_id = parts[1];
@@ -201,7 +200,7 @@ function on_pool_open(relay) {
// Get our notifications
relay.subscribe(SID_NOTIFICATIONS, [{
- kinds: STANDARD_KINDS,
+ kinds: PUBLIC_KINDS,
"#p": [pubkey],
limit: 5000,
}]);
@@ -215,19 +214,6 @@ function on_pool_open(relay) {
kinds: [KIND_DM],
authors: [pubkey],
}]);
-
- // Subscribe to the world as it will serve our friends, notifications, and
- // explore views
- relay.subscribe(SID_EXPLORE, [{
- kinds: STANDARD_KINDS,
- limit: 5000,
- }]);
-
- // Grab our friends history so our default timeline looks loaded
- if (model.contacts.friends.size > 0) {
- model_get_relay_que(model, relay).contacts_init = true;
- fetch_friends_history(Array.from(model.contacts.friends), model.pool, relay);
- }
}
function on_pool_notice(relay, notice) {
@@ -246,15 +232,19 @@ async function on_pool_eose(relay, sub_id) {
switch (sid) {
case SID_HISTORY:
case SID_THREAD:
- case SID_FRIENDS:
view_timeline_refresh(model);
pool.unsubscribe(sub_id, relay);
break
+ case SID_FRIENDS:
+ view_timeline_refresh(model);
+ //pool.unsubscribe(sub_id, relay);
+ break
case SID_META:
// if sid is ours and we did not init properly (must be login) then
// we will fetch our friends history now
- if (model.pubkey == identifier &&
- !model_get_relay_que(model, relay).contacts_init) {
+ //if (model.pubkey == identifier &&
+ // !model_get_relay_que(model, relay).contacts_init) {
+ if (model.pubkey == identifier) {
fetch_friends_history(Array.from(model.contacts.friends),
pool, relay);
log_debug("Got our friends after no init & fetching our friends");
@@ -296,7 +286,6 @@ function fetch_profile_info(pubkey, pool, relay) {
pool.subscribe(sid, [{
kinds: [KIND_METADATA, KIND_CONTACT, KIND_RELAY],
authors: [pubkey],
- limit: 1,
}], relay);
return sid;
}
@@ -304,7 +293,7 @@ function fetch_profile_info(pubkey, pool, relay) {
function fetch_profile(pubkey, pool, relay) {
fetch_profile_info(pubkey, pool, relay);
pool.subscribe(`${SID_HISTORY}:${pubkey}`, [{
- kinds: STANDARD_KINDS,
+ kinds: PUBLIC_KINDS,
authors: [pubkey],
limit: 1000,
}], relay);
@@ -313,17 +302,19 @@ function fetch_profile(pubkey, pool, relay) {
function fetch_thread_history(evid, pool) {
const sid = `${SID_THREAD}:${evid}`
pool.subscribe(sid, [{
- kinds: STANDARD_KINDS,
- limit: 1000,
+ kinds: PUBLIC_KINDS,
"#e": [evid],
}]);
log_debug(`fetching thread ${sid}`);
}
function fetch_friends_history(friends, pool, relay) {
+ // TODO only fetch friends history from their desired relay instead of
+ // pinging all of the relays
pool.subscribe(SID_FRIENDS, [{
- kinds: STANDARD_KINDS,
+ kinds: PUBLIC_KINDS,
authors: friends,
- limit: 500,
+ limit: 5000,
}], relay);
+ log_debug(`fetching friends history`);
}
diff --git a/js/model.js b/js/model.js
index abf1c5b..11e198a 100644
--- a/js/model.js
+++ b/js/model.js
@@ -7,6 +7,7 @@ function model_process_event(model, relay, ev) {
return;
}
+ let fetch_profile = false;
model.all_events[ev.id] = ev;
ev.refs = event_get_tag_refs(ev.tags);
ev.pow = event_calculate_pow(ev);
@@ -15,6 +16,10 @@ function model_process_event(model, relay, ev) {
// integers can't be used.
let fn;
switch(ev.kind) {
+ case KIND_NOTE:
+ case KIND_SHARE:
+ fetch_profile = true;
+ break;
case KIND_METADATA:
fn = model_process_event_metadata;
break;
@@ -43,11 +48,13 @@ function model_process_event(model, relay, ev) {
return;
// Request new profiles for unseen pubkeys of the event
- event_get_pubkeys(ev).forEach((pubkey) => {
- if (!model_has_profile(model, pubkey)) {
- model_que_profile(model, relay, pubkey);
- }
- });
+ if (fetch_profile) {
+ event_get_pubkeys(ev).forEach((pubkey) => {
+ if (!model_has_profile(model, pubkey)) {
+ model_que_profile(model, relay, pubkey);
+ }
+ });
+ }
}
function model_get_relay_que(model, relay) {
diff --git a/js/ui/fmt.js b/js/ui/fmt.js
index 160acd6..f36e2a8 100644
--- a/js/ui/fmt.js
+++ b/js/ui/fmt.js
@@ -1,4 +1,4 @@
-function linkify(text="", show_media=false) {
+function linkify(text="") {
return text.replace(URL_REGEX, function(match, p1, p2, p3) {
const url = p2+p3;
let parsed;
@@ -7,24 +7,17 @@ function linkify(text="", show_media=false) {
} catch (err) {
return match;
}
- let markup;
- if (show_media && is_img_url(parsed.pathname)) {
- markup = html`
-

`;
- } else if (show_media && is_video_url(parsed.pathname)) {
- markup = html`
-
-
- `;
- } else {
- markup = html`${url}`;
+ let markup = html`${url}`;
+ if (is_img_url(parsed.pathname)) {
+ //markup += ``;
+ } else if (is_video_url(parsed.pathname)) {
+ //markup += ``;
}
return p1+markup;
})
}
-function format_content(model, ev, show_media) {
+function format_content(model, ev) {
if (ev.kind === KIND_REACTION) {
if (ev.content === "" || ev.content === "+")
return "❤️"
@@ -32,7 +25,7 @@ function format_content(model, ev, show_media) {
}
const content = (ev.kind == KIND_DM ? ev.decrypted || ev.content : ev.content)
.trim();
- const body = fmt_mentions(model, fmt_body(content, show_media), ev.tags);
+ const body = fmt_mentions(model, fmt_body(content), ev.tags);
let cw = get_content_warning(ev.tags)
if (cw !== null) {
let cwHTML = "Content Warning"
@@ -97,25 +90,8 @@ function fmt_mentions(model, str, tags) {
/* fmt_body will parse images, blockquotes, and sanitize the content.
*/
-function fmt_body(content, show_media) {
- const split = content.split("\n")
- let blockin = false
- return split.reduce((str, line) => {
- if (line !== "" && line[0] === '>') {
- if (!blockin) {
- str += ""
- blockin = true
- }
- str += linkify(html`${line.slice(1)}`, show_media)
- } else {
- if (blockin) {
- blockin = false
- str += ""
- }
- str += linkify(html`${line}`, show_media)
- }
- return str + "
"
- }, "")
+function fmt_body(content) {
+ return newlines_to_br(linkify(content))
}
/* DEPRECATED: use fmt_name
diff --git a/js/ui/render.js b/js/ui/render.js
index 90b9f39..4c34542 100644
--- a/js/ui/render.js
+++ b/js/ui/render.js
@@ -169,17 +169,9 @@ function render_react_onclick(our_pubkey, reacting_to, emoji, reactions) {
function render_reaction_group(model, emoji, reactions, reacting_to) {
let count = 0;
- let str = "";
for (const k in reactions) {
count++;
- if (count > 5)
- continue;
- const pubkey = reactions[k].pubkey;
- str += render_profile_img(model_get_profile(model, pubkey),
- {noclick:true});
}
- if (count > 5)
- str = `${count}`;
let onclick = render_react_onclick(model.pubkey,
reacting_to.id, emoji, reactions);
return html`
@@ -187,7 +179,7 @@ function render_reaction_group(model, emoji, reactions, reacting_to) {
${emoji}
- $${str}
+ ${count}
`;
}
diff --git a/js/ui/state.js b/js/ui/state.js
index 375f13f..f85300d 100644
--- a/js/ui/state.js
+++ b/js/ui/state.js
@@ -1,5 +1,4 @@
const VM_FRIENDS = "friends"; // mine + only events that are from my contacts
-const VM_EXPLORE = "explore"; // all events
const VM_NOTIFICATIONS = "notifications"; // reactions & replys
const VM_DM = "dm"; // all events of KIND_DM aimmed at user
const VM_DM_THREAD = "dmthread"; // all events from a user of KIND_DM
@@ -9,7 +8,6 @@ const VM_SETTINGS = "settings";
const VIEW_NAMES= {};
VIEW_NAMES[VM_FRIENDS] = "Home";
-VIEW_NAMES[VM_EXPLORE] = "Explore";
VIEW_NAMES[VM_NOTIFICATIONS] = "Notifications";
VIEW_NAMES[VM_DM] = "Messages";
VIEW_NAMES[VM_DM_THREAD] = "DM";
@@ -120,7 +118,6 @@ function view_timeline_apply_mode(model, mode, opts={}, push_state=true) {
find_node("#view header > label").innerText = name;
find_node("#nav > div[data-active]").dataset.active = names[mode].toLowerCase();
find_node("#view [role='profile-info']").classList.toggle("hide", mode != VM_USER);
- find_node("#newpost").classList.toggle("hide", mode != VM_FRIENDS && mode != VM_DM_THREAD);
const timeline_el = find_node("#timeline");
timeline_el.classList.toggle("reverse", mode == VM_THREAD);
timeline_el.classList.toggle("hide", mode == VM_SETTINGS || mode == VM_DM);
@@ -131,8 +128,6 @@ function view_timeline_apply_mode(model, mode, opts={}, push_state=true) {
dms_available() : true);
find_node("#header-tools button[action='mark-all-read']")
.classList.toggle("hide", mode != VM_DM);
- find_node("#header-tools button[action='toggle-hide-replys']")
- .classList.toggle("hide", mode != VM_FRIENDS);
// Show/hide different profile image in header
const show_mypfp = mode != VM_DM_THREAD && mode != VM_USER;
@@ -219,8 +214,7 @@ function view_timeline_refresh(model, mode, opts={}) {
show_more = false;
// If we reached the limit there is "probably" more to show so show
// the more button
- const is_more_mode = mode == VM_FRIENDS || mode == VM_NOTIFICATIONS ||
- mode == VM_EXPLORE;
+ const is_more_mode = mode == VM_FRIENDS || mode == VM_NOTIFICATIONS;
if (is_more_mode && show_more) {
find_node("#show-more").classList.remove("hide");
}
@@ -426,10 +420,8 @@ function view_timeline_update_profiles(model, pubkey) {
const name = fmt_name(p);
const pic = get_profile_pic(p);
for (const evid in model.elements) {
- // Omitting this because we want to update profiles and names on all
- // reactions
- //if (!event_contains_pubkey(model.all_events[evid], pubkey))
- // continue;
+ // XXX if possible update profile pics in a smarter way
+ // this may be perhaps a micro optimization tho
update_el_profile(model.elements[evid], pubkey, name, pic);
}
// Update the profile view if it's active
@@ -446,7 +438,6 @@ function view_timeline_update_profiles(model, pubkey) {
// be caught by the process above.
update_el_profile(find_node("#dms"), pubkey, name, pic);
update_el_profile(find_node("#view header"), pubkey, name, pic);
- update_el_profile(find_node("#newpost"), pubkey, name, pic);
}
function update_el_profile(el, pubkey, name, pic) {
@@ -507,8 +498,6 @@ function view_mode_contains_event(model, ev, mode, opts={}) {
return false;
}
switch(mode) {
- case VM_EXPLORE:
- return ev.kind != KIND_REACTION;
case VM_USER:
return opts.pubkey && ev.pubkey == opts.pubkey;
case VM_FRIENDS:
@@ -603,35 +592,39 @@ function init_my_pfp(model) {
}
function init_postbox(model) {
- const el = find_node("#newpost");
- find_node("textarea", el).addEventListener("input", oninput_post);
- find_node("button[role='send']").addEventListener("click", onclick_send);
- find_node("button[role='toggle-cw']")
- .addEventListener("click", onclick_toggle_cw);
- // Do reply box
- // TODO refactor & cleanup reply modal init
find_node("#reply-content").addEventListener("input", oninput_post);
find_node("button[name='reply']")
.addEventListener("click", onclick_reply);
find_node("button[name='reply-all']")
.addEventListener("click", onclick_reply);
+ find_node("button[name='send']")
+ .addEventListener("click", onclick_send);
}
async function onclick_reply(ev) {
do_send_reply(ev.target.dataset.all == "1");
}
async function onclick_send(ev) {
- const el = view_get_timeline_el();
- const mode = el.dataset.mode;
+ const el = find_node("#reply-modal");
const pubkey = await get_pubkey();
- const el_input = document.querySelector("#post-input");
- const el_cw = document.querySelector("#content-warning-input");
+ const el_input = el.querySelector("#reply-content");
let post = {
pubkey,
kind: KIND_NOTE,
created_at: new_creation_time(),
content: el_input.value,
- tags: el_cw.value ? [["content-warning", el_cw.value]] : [],
- }
+ tags: [],
+ };
+ post.id = await nostrjs.calculate_id(post);
+ post = await sign_event(post);
+ broadcast_event(post);
+
+ // Reset UI
+ el_input.value = "";
+ trigger_postbox_assess(el_input);
+
+ /*
+ const el_cw = document.querySelector("#content-warning-input");
+ //tags: el_cw.value ? [["content-warning", el_cw.value]] : [],
// Handle DM type post
if (mode == VM_DM_THREAD) {
@@ -645,15 +638,7 @@ async function onclick_send(ev) {
post.content = await window.nostr.nip04.encrypt(target, post.content);
}
- // Send it
- post.id = await nostrjs.calculate_id(post)
- post = await sign_event(post)
- broadcast_event(post);
-
- // Reset UI
- el_input.value = "";
- el_cw.value = "";
- trigger_postbox_assess(el_input);
+ el_cw.value = "";*/
}
/* oninput_post checks the content of the textarea and updates the size
* of it's element. Additionally I will toggle the enabled state of the sending
@@ -752,6 +737,8 @@ function onclick_any(ev) {
case "toggle-hide-replys":
toggle_hide_replys(el);
break;
+ case "new-note":
+ new_note();
}
}
diff --git a/js/ui/util.js b/js/ui/util.js
index 2453862..1b2ba8c 100644
--- a/js/ui/util.js
+++ b/js/ui/util.js
@@ -97,18 +97,39 @@ async function do_send_reply(all=false) {
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()
+ replybox.focus();
}
function update_favicon(path) {