work on reply jumping and fixed account fixer

This commit is contained in:
MathMan05 2024-07-28 14:53:39 -05:00
parent 7a745a5286
commit 6cea53dabd
12 changed files with 350 additions and 62 deletions

View file

@ -79,7 +79,7 @@ class Channel {
this.infinite = new InfiniteScroller(async function (id, offset) {
const snowflake = SnowFlake.getSnowFlakeFromID(id, Message);
if (offset === 1) {
if (this.idToPrev.get(snowflake)) {
if (this.idToPrev.has(snowflake)) {
return this.idToPrev.get(snowflake)?.id;
}
else {
@ -88,13 +88,25 @@ class Channel {
}
}
else {
if (this.idToNext.has(snowflake)) {
return this.idToNext.get(snowflake)?.id;
}
}.bind(this), function (id) {
else if (this.lastmessage.id !== id) {
await this.grabAfter(id);
return this.idToNext.get(snowflake)?.id;
}
else {
console.log("at bottom");
}
}
}.bind(this), async function (id) {
let res;
const promise = new Promise(_ => { res = _; });
const snowflake = SnowFlake.getSnowFlakeFromID(id, Message);
const html = this.messageids.get(snowflake).buildhtml(this.messageids.get(this.idToPrev.get(snowflake)), promise);
if (!snowflake.getObject()) {
await this.grabArround(id);
}
const html = snowflake.getObject().buildhtml(this.messageids.get(this.idToPrev.get(snowflake)), promise);
ids[id] = res;
return html;
}.bind(this), async function (id) {
@ -529,7 +541,7 @@ class Channel {
return;
}
this.makereplybox();
this.buildmessages();
await this.buildmessages();
history.pushState(null, null, "/channels/" + this.guild_id + "/" + this.snowflake);
document.getElementById("channelname").textContent = "#" + this.name;
console.log(this);
@ -573,6 +585,44 @@ class Channel {
}
this.children = build;
}
async grabAfter(id) {
if (id === this.lastmessage.id) {
return;
}
await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages?limit=100&after=" + id, {
headers: this.headers
}).then((j) => { return j.json(); }).then(response => {
let next;
let previd = undefined;
for (const i in response) {
let messager;
if (!next) {
messager = new Message(response[i], this);
}
else {
messager = next;
}
if (response[+i + 1] !== undefined) {
next = new Message(response[+i + 1], this);
}
else {
next = undefined;
console.log("ohno", +i + 1);
}
if (this.messageids.get(messager.snowflake) === undefined) {
this.idToNext.set(messager.snowflake, previd);
this.idToPrev.set(previd, messager.snowflake);
previd = messager.snowflake;
this.messageids.set(messager.snowflake, messager);
}
else {
console.log("How???");
}
}
//out.buildmessages();
});
return;
}
async grabBefore(id) {
if (this.allthewayup) {
return;
@ -614,22 +664,66 @@ class Channel {
});
return;
}
async grabArround(id) {
await fetch(this.info.api.toString() + "/channels/" + this.snowflake + "/messages?around=" + id + "&limit=100", {
headers: this.headers
}).then((j) => { return j.json(); }).then(response => {
let next;
if (response.length === 0) {
this.allthewayup = true;
}
let previd = SnowFlake.getSnowFlakeFromID(id, Message);
for (const i in response) {
let messager;
if (!next) {
messager = new Message(response[i], this);
}
else {
messager = next;
}
if (response[+i + 1] !== undefined) {
next = new Message(response[+i + 1], this);
}
else {
next = undefined;
console.log("ohno", +i + 1);
}
if (this.messageids.get(messager.snowflake) === undefined) {
this.idToNext.set(messager.snowflake, previd);
this.idToPrev.set(previd, messager.snowflake);
previd = messager.snowflake;
this.messageids.set(messager.snowflake, messager);
}
else {
console.log("How???");
}
}
//out.buildmessages();
});
return;
}
buildmessage(message, next) {
const built = message.buildhtml(next);
document.getElementById("messages").prepend(built);
}
buildmessages() {
async buildmessages() {
const messages = document.getElementById("channelw");
messages.innerHTML = "";
let id;
if (this.messageids.get(this.lastreadmessageid)) {
if (this.lastreadmessageid && this.lastreadmessageid.getObject()) {
id = this.lastreadmessageid;
}
else if (this.lastmessage.snowflake) {
id = this.goBackIds(this.lastmessage.snowflake, 50);
console.log("shouldn't");
}
messages.append(this.infinite.getDiv(id.id));
console.log(this.lastreadmessageid, id.id);
messages.append(await this.infinite.getDiv(id.id));
this.infinite.updatestuff();
this.infinite.watchForChange().then(async (_) => {
await new Promise(resolve => setTimeout(resolve, 100));
this.infinite.focus(id.id, false); //if someone could figure out how to make this work correctly without this, that's be great :P
});
}
goBackIds(id, back) {
while (back !== 0) {
@ -763,7 +857,9 @@ class Channel {
}
}
this.guild.unreads();
if (this === this.localuser.channelfocus) {
this.infinite.addedBottom();
}
if (messagez.author === this.localuser.user) {
return;
}

View file

@ -15,7 +15,7 @@ class InfiniteScroller {
this.reachesBottom = reachesBottom;
}
interval;
getDiv(initialId, bottom = true) {
async getDiv(initialId, bottom = true) {
const div = document.createElement("div");
div.classList.add("messagecontainer");
//div.classList.add("flexttb")
@ -28,10 +28,10 @@ class InfiniteScroller {
this.scroll.addEventListener("scroll", this.watchForChange.bind(this));
new ResizeObserver(this.watchForChange.bind(this)).observe(div);
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
this.firstElement(initialId);
await this.firstElement(initialId);
this.updatestuff();
await this.watchForChange().then(_ => {
this.updatestuff();
this.watchForChange().then(_ => {
this.scroll.scrollTop = this.scroll.scrollHeight;
});
return div;
}
@ -45,8 +45,8 @@ class InfiniteScroller {
}
//this.watchForChange();
}
firstElement(id) {
const html = this.getHTMLFromID(id);
async firstElement(id) {
const html = await this.getHTMLFromID(id);
this.scroll.append(html);
this.HTMLElements.push([html, id]);
}
@ -87,7 +87,7 @@ class InfiniteScroller {
}
else {
again = true;
const html = this.getHTMLFromID(nextid);
const html = await this.getHTMLFromID(nextid);
this.scroll.prepend(html);
this.HTMLElements.unshift([html, nextid]);
this.scrollTop += 60;
@ -108,7 +108,7 @@ class InfiniteScroller {
}
else {
again = true;
const html = this.getHTMLFromID(nextid);
const html = await this.getHTMLFromID(nextid);
this.scroll.append(html);
this.HTMLElements.push([html, nextid]);
this.scrollBottom += 60;
@ -130,6 +130,34 @@ class InfiniteScroller {
}
this.currrunning = false;
}
async focus(id, flash = true) {
let element;
for (const thing of this.HTMLElements) {
if (thing[1] === id) {
element = thing[0];
}
}
console.log(element, id, ":3");
if (element) {
element.scrollIntoView();
if (flash) {
element.classList.remove("jumped");
await new Promise(resolve => setTimeout(resolve, 100));
element.classList.add("jumped");
}
}
else {
for (const thing of this.HTMLElements) {
await this.destroyFromID(thing[1]);
}
this.HTMLElements = [];
await this.firstElement(id);
this.updatestuff();
await this.watchForChange();
await new Promise(resolve => setTimeout(resolve, 100));
await this.focus(id, true);
}
}
async delete() {
for (const thing of this.HTMLElements) {
await this.destroyFromID(thing[1]);

View file

@ -85,8 +85,8 @@ class Localuser {
this.typing = [];
}
outoffocus() {
document.getElementById("servers").textContent = "";
document.getElementById("channels").textContent = "";
document.getElementById("servers").innerHTML = "";
document.getElementById("channels").innerHTML = "";
if (this.channelfocus) {
this.channelfocus.infinite.delete();
}
@ -94,16 +94,18 @@ class Localuser {
this.channelfocus = null;
}
unload() {
console.log("please say this ran");
this.initialized = false;
clearInterval(this.wsinterval);
this.outoffocus();
this.guilds = [];
this.guildids = new Map();
this.ws.close(4000);
this.ws.close(4001);
}
async initwebsocket() {
let returny = null;
const promise = new Promise((res) => { returny = res; });
console.warn("info");
this.ws = new WebSocket(this.serverurls.gateway.toString());
this.ws.addEventListener('open', (event) => {
console.log('WebSocket connected');
@ -617,7 +619,7 @@ class Localuser {
]
], _ => { }, function () {
console.log(this);
hypouser = new User(this.user, this);
hypouser = this.user.clone();
regen();
file = null;
newprouns = null;

View file

@ -44,7 +44,7 @@ class Message {
this.channel.setReplying(this);
});
Message.contextmenu.addbutton("Copy message id", function () {
navigator.clipboard.writeText(this.id.id);
navigator.clipboard.writeText(this.id);
});
Message.contextmenu.addbutton("Edit", function () {
this.channel.editing = this;
@ -241,6 +241,10 @@ class Message {
username.textContent = author.username;
author.bind(username);
});
reply.onclick = _ => {
console.log("this got clicked :3");
this.channel.infinite.focus(this.message_reference.message_id);
};
div.appendChild(replyline);
}
build.classList.add("message");

View file

@ -15,9 +15,14 @@ class SnowFlake {
}
if (SnowFlake.SnowFlakes.get(obj.constructor).get(id)) {
const snowflake = SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref();
if (snowflake) {
snowflake.obj = obj;
return snowflake;
}
else {
SnowFlake.SnowFlakes.get(obj.constructor).delete(id);
}
}
this.id = id;
SnowFlake.SnowFlakes.get(obj.constructor).set(id, new WeakRef(this));
SnowFlake.FinalizationRegistry.register(this, [id, obj.constructor]);
@ -33,7 +38,13 @@ class SnowFlake {
}
const snowflake = SnowFlake.SnowFlakes.get(type).get(id);
if (snowflake) {
return snowflake.deref();
const obj = snowflake.deref();
if (obj) {
return obj;
}
else {
SnowFlake.SnowFlakes.get(type).delete(id);
}
}
{
const snowflake = new SnowFlake(id, undefined);

View file

@ -94,21 +94,31 @@ class Channel{
this.infinite=new InfiniteScroller(async function(this:Channel,id:string,offset:number):Promise<string>{
const snowflake=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake<Message>;
if(offset===1){
if(this.idToPrev.get(snowflake)){
if(this.idToPrev.has(snowflake)){
return this.idToPrev.get(snowflake)?.id;
}else{
await this.grabBefore(id);
return this.idToPrev.get(snowflake)?.id;
}
}else{
if(this.idToNext.has(snowflake)){
return this.idToNext.get(snowflake)?.id;
}else if(this.lastmessage.id!==id){
await this.grabAfter(id);
return this.idToNext.get(snowflake)?.id;
}else{
console.log("at bottom")
}
}
}.bind(this),
function(this:Channel,id:string){
async function(this:Channel,id:string){
let res:Function;
const promise=new Promise(_=>{res=_;}) as Promise<void>;
const snowflake=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake<Message>;
const html=this.messageids.get(snowflake).buildhtml(this.messageids.get(this.idToPrev.get(snowflake)),promise);
const snowflake=SnowFlake.getSnowFlakeFromID(id,Message);
if(!snowflake.getObject()){
await this.grabArround(id);
}
const html=snowflake.getObject().buildhtml(this.messageids.get(this.idToPrev.get(snowflake)),promise);
ids[id]=res;
return html;
}.bind(this),
@ -540,7 +550,7 @@ class Channel{
return;
}
this.makereplybox();
this.buildmessages();
await this.buildmessages();
history.pushState(null, null,"/channels/"+this.guild_id+"/"+this.snowflake);
document.getElementById("channelname").textContent="#"+this.name;
console.log(this);
@ -581,6 +591,41 @@ class Channel{
}
this.children=build;
}
async grabAfter(id:string){
if(id===this.lastmessage.id){
return;
}
await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100&after="+id,{
headers:this.headers
}).then((j)=>{return j.json()}).then(response=>{
let next:Message;
let previd:SnowFlake<Message>=undefined;
for(const i in response){
let messager:Message;
if(!next){
messager=new Message(response[i],this);
}else{
messager=next;
}
if(response[+i+1]!==undefined){
next=new Message(response[+i+1],this);
}else{
next=undefined;
console.log("ohno",+i+1);
}
if(this.messageids.get(messager.snowflake)===undefined){
this.idToNext.set(messager.snowflake,previd);
this.idToPrev.set(previd,messager.snowflake);
previd=messager.snowflake;
this.messageids.set(messager.snowflake,messager);
}else{
console.log("How???")
}
}
//out.buildmessages();
})
return;
}
async grabBefore(id:string){
if(this.allthewayup){
return;
@ -620,21 +665,62 @@ class Channel{
})
return;
}
async grabArround(id:string){
await fetch(this.info.api.toString()+"/channels/"+this.snowflake+"/messages?around="+id+"&limit=100",{
headers:this.headers
}).then((j)=>{return j.json()}).then(response=>{
let next:Message;
if(response.length===0){
this.allthewayup=true;
}
let previd=SnowFlake.getSnowFlakeFromID(id,Message) as SnowFlake<Message>;
for(const i in response){
let messager:Message;
if(!next){
messager=new Message(response[i],this);
}else{
messager=next;
}
if(response[+i+1]!==undefined){
next=new Message(response[+i+1],this);
}else{
next=undefined;
console.log("ohno",+i+1);
}
if(this.messageids.get(messager.snowflake)===undefined){
this.idToNext.set(messager.snowflake,previd);
this.idToPrev.set(previd,messager.snowflake);
previd=messager.snowflake;
this.messageids.set(messager.snowflake,messager);
}else{
console.log("How???")
}
}
//out.buildmessages();
})
return;
}
buildmessage(message:Message,next:Message){
const built=message.buildhtml(next);
document.getElementById("messages").prepend(built);
}
buildmessages(){
async buildmessages(){
const messages=document.getElementById("channelw");
messages.innerHTML="";
let id:SnowFlake<Message>;
if(this.messageids.get(this.lastreadmessageid)){
if(this.lastreadmessageid&&this.lastreadmessageid.getObject()){
id=this.lastreadmessageid;
}else if(this.lastmessage.snowflake){
id=this.goBackIds(this.lastmessage.snowflake,50);
console.log("shouldn't")
}
messages.append(this.infinite.getDiv(id.id));
console.log(this.lastreadmessageid,id.id);
messages.append(await this.infinite.getDiv(id.id));
this.infinite.updatestuff();
this.infinite.watchForChange().then(async _=>{
await new Promise(resolve => setTimeout(resolve, 100));
this.infinite.focus(id.id,false);//if someone could figure out how to make this work correctly without this, that's be great :P
})
}
private goBackIds(id:SnowFlake<Message>,back:number):SnowFlake<Message>{
while(back!==0){
@ -757,7 +843,9 @@ class Channel{
}
}
this.guild.unreads();
if(this===this.localuser.channelfocus){
this.infinite.addedBottom();
}
if(messagez.author===this.localuser.user){
return;
}

View file

@ -1,6 +1,6 @@
class InfiniteScroller{
readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string>;
readonly getHTMLFromID:(ID:string)=>HTMLElement;
readonly getHTMLFromID:(ID:string)=>Promise<HTMLElement>;
readonly destroyFromID:(ID:string)=>Promise<boolean>;
readonly reachesBottom:()=>void;
private readonly minDist=3000;
@ -15,7 +15,7 @@ class InfiniteScroller{
this.reachesBottom=reachesBottom;
}
interval:NodeJS.Timeout;
getDiv(initialId:string,bottom=true):HTMLDivElement{
async getDiv(initialId:string,bottom=true):Promise<HTMLDivElement>{
const div=document.createElement("div");
div.classList.add("messagecontainer");
//div.classList.add("flexttb")
@ -30,10 +30,10 @@ class InfiniteScroller{
new ResizeObserver(this.watchForChange.bind(this)).observe(div);
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
this.firstElement(initialId);
await this.firstElement(initialId)
this.updatestuff();
await this.watchForChange().then(_=>{
this.updatestuff();
this.watchForChange().then(_=>{
this.scroll.scrollTop=this.scroll.scrollHeight;
})
return div;
}
@ -47,8 +47,8 @@ class InfiniteScroller{
}
//this.watchForChange();
}
firstElement(id:string){
const html=this.getHTMLFromID(id);
async firstElement(id:string){
const html=await this.getHTMLFromID(id);
this.scroll.append(html);
this.HTMLElements.push([html,id]);
}
@ -79,15 +79,13 @@ class InfiniteScroller{
this.scroll.scrollTop=1;
}
if(this.scrollTop<this.minDist){
const previd=this.HTMLElements.at(0)[1];
const nextid=await this.getIDFromOffset(previd,1);
if(!nextid){
}else{
again=true;
const html=this.getHTMLFromID(nextid);
const html=await this.getHTMLFromID(nextid);
this.scroll.prepend(html);
this.HTMLElements.unshift([html,nextid]);
this.scrollTop+=60;
@ -109,7 +107,7 @@ class InfiniteScroller{
if(!nextid){
}else{
again=true;
const html=this.getHTMLFromID(nextid);
const html=await this.getHTMLFromID(nextid);
this.scroll.append(html);
this.HTMLElements.push([html,nextid]);
this.scrollBottom+=60;
@ -132,6 +130,33 @@ class InfiniteScroller{
}
this.currrunning=false;
}
async focus(id:string,flash=true){
let element:HTMLElement;
for(const thing of this.HTMLElements){
if(thing[1]===id){
element=thing[0];
}
}
console.log(element,id,":3");
if(element){
element.scrollIntoView();
if(flash){
element.classList.remove("jumped");
await new Promise(resolve => setTimeout(resolve, 100));
element.classList.add("jumped");
}
}else{
for(const thing of this.HTMLElements){
await this.destroyFromID(thing[1]);
}
this.HTMLElements=[];
await this.firstElement(id);
this.updatestuff();
await this.watchForChange();
await new Promise(resolve => setTimeout(resolve, 100));
await this.focus(id,true);
}
}
async delete():Promise<void>{
for(const thing of this.HTMLElements){
await this.destroyFromID(thing[1]);

View file

@ -91,8 +91,8 @@ class Localuser{
this.typing=[];
}
outoffocus():void{
document.getElementById("servers").textContent="";
document.getElementById("channels").textContent="";
document.getElementById("servers").innerHTML="";
document.getElementById("channels").innerHTML="";
if(this.channelfocus){
this.channelfocus.infinite.delete();
}
@ -100,16 +100,18 @@ class Localuser{
this.channelfocus=null;
}
unload():void{
console.log("please say this ran");
this.initialized=false;
clearInterval(this.wsinterval);
this.outoffocus();
this.guilds=[];
this.guildids=new Map();
this.ws.close(4000)
this.ws.close(4001)
}
async initwebsocket():Promise<void>{
let returny=null
const promise=new Promise((res)=>{returny=res});
console.warn("info");
this.ws = new WebSocket(this.serverurls.gateway.toString());
this.ws.addEventListener('open', (event) => {
console.log('WebSocket connected');
@ -227,7 +229,6 @@ class Localuser{
this.unload();
document.getElementById("loading").classList.remove("doneloading");
document.getElementById("loading").classList.add("loading");
if (((event.code>1000 && event.code<1016) || wsCodesRetry.has(event.code))) {
if (this.connectionSucceed!==0 && Date.now()>this.connectionSucceed+20000) this.errorBackoff=0;
else this.errorBackoff++;
@ -643,9 +644,9 @@ class Localuser{
["vdiv",
["html",hypotheticalProfile]
]
],_=>{},function(){
],_=>{},function(this:Localuser){
console.log(this);
hypouser=new User(this.user,this);
hypouser=this.user.clone();
regen();
file=null;
newprouns=null;

View file

@ -49,7 +49,7 @@ class Message{
this.channel.setReplying(this);
});
Message.contextmenu.addbutton("Copy message id",function(){
navigator.clipboard.writeText(this.id.id);
navigator.clipboard.writeText(this.id);
});
Message.contextmenu.addbutton("Edit",function(){
this.channel.editing=this;
@ -246,6 +246,10 @@ class Message{
username.textContent=author.username;
author.bind(username);
});
reply.onclick=_=>{
console.log("this got clicked :3")
this.channel.infinite.focus(this.message_reference.message_id);
}
div.appendChild(replyline);
}
build.classList.add("message");

View file

@ -1,7 +1,7 @@
class SnowFlake<x>{
class SnowFlake<x extends WeakKey>{
public readonly id:string;
private static readonly SnowFlakes:Map<any,Map<string,WeakRef<SnowFlake<any>>>>=new Map();
private static readonly FinalizationRegistry=new FinalizationRegistry((a:[string,any])=>{
private static readonly FinalizationRegistry=new FinalizationRegistry((a:[string,WeakKey])=>{
SnowFlake.SnowFlakes.get(a[1]).delete(a[0]);
});
private obj:x;
@ -15,8 +15,12 @@ class SnowFlake<x>{
}
if(SnowFlake.SnowFlakes.get(obj.constructor).get(id)){
const snowflake=SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref();
if(snowflake){
snowflake.obj=obj;
return snowflake;
}else{
SnowFlake.SnowFlakes.get(obj.constructor).delete(id);
}
}
this.id=id;
SnowFlake.SnowFlakes.get(obj.constructor).set(id,new WeakRef(this));
@ -33,7 +37,12 @@ class SnowFlake<x>{
}
const snowflake=SnowFlake.SnowFlakes.get(type).get(id);
if(snowflake){
return snowflake.deref();
const obj=snowflake.deref();
if(obj){
return obj;
}else{
SnowFlake.SnowFlakes.get(type).delete(id);
}
}
{
const snowflake=new SnowFlake(id,undefined);

View file

@ -74,6 +74,22 @@ th {
.messagediv:hover {
background-color: var(--message-bg-hover);
}
.jumped{
animation-duration: .5s;
animation-name: jumped;
}
@keyframes jumped{
0% {
background-color: transparent;
}
50% {
background-color: var(--message-jump);
}
100% {
background-color: transparent;
}
}
.messagediv{
overflow: hidden;
max-width:100%;
@ -546,7 +562,7 @@ hr {
.replypfp {
border-radius: 50%;
width: .2in;
height: 2.in;
height: .2in;
padding: .05in;
user-select: none;
cursor: pointer;
@ -567,6 +583,7 @@ hr {
/* display: inline-block !important; */
width: 25vw;
grid-column: 2;
cursor: pointer;
}
.replytext pre {
/* padding: 0 .05in; */
@ -1395,7 +1412,7 @@ span {
.messagediv .flexttb{
display:flex;
overflow: hidden;
flex-wrap: wrap;
flex-wrap: nowrap;
width: 100%;
flex-direction: column;
max-height:100in;

View file

@ -51,6 +51,7 @@
--embed: #1a1823;
--link: #8888ff;
--discovery-bg: #37373b;
--message-jump:#7678b0;
}
.WHITE-theme {
color-scheme: light;
@ -101,6 +102,7 @@
--embed: #f2f3f5;
--link: #3333ee;
--discovery-bg: #c6c6d8;
--message-jump:#52558a;
}
.Light-theme {
color-scheme: light;
@ -159,4 +161,5 @@
--embed: #cdccd1;
--link: #5566cc;
--discovery-bg: #c6c6d8;
--message-jump:#52558a;
}