diff --git a/.dist/channel.js b/.dist/channel.js index 3a2a907..87ccb76 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -212,7 +212,7 @@ class Channel extends SnowFlake { if (json.parent_id) { this.parent_id = json.parent_id; } - this.parent = null; + this.parent = undefined; this.children = []; this.guild_id = json.guild_id; this.permission_overwrites = new Map(); @@ -312,12 +312,12 @@ class Channel extends SnowFlake { const parentid = this.parent_id; if (!parentid) return false; - this.parent = guild.channelids[parentid]; - this.parent ??= null; - if (this.parent !== null) { + this.parent = this.localuser.channelids.get(parentid); + this.parent ??= undefined; + if (this.parent !== undefined) { this.parent.children.push(this); } - return this.parent !== null; + return this.parent !== undefined; } calculateReorder() { let position = -1; @@ -967,13 +967,13 @@ class Channel extends SnowFlake { updateChannel(json) { this.type = json.type; this.name = json.name; - const parent = this.guild.channelids[json.parent_id]; + const parent = this.localuser.channelids.get(json.parent_id); if (parent) { this.parent = parent; this.parent_id = parent.id; } else { - this.parent = null; + this.parent = undefined; this.parent_id = undefined; } this.children = []; diff --git a/.dist/guild.js b/.dist/guild.js index fa36348..6d5ac95 100644 --- a/.dist/guild.js +++ b/.dist/guild.js @@ -10,7 +10,6 @@ class Guild extends SnowFlake { owner; headers; channels; - channelids; properties; member_count; roles; @@ -86,7 +85,6 @@ class Guild extends SnowFlake { this.owner = owner; this.headers = this.owner.headers; this.channels = []; - this.channelids = {}; this.properties = json.properties; this.roles = []; this.roleids = new Map(); @@ -117,7 +115,7 @@ class Guild extends SnowFlake { for (const thing of json.channels) { const temp = new Channel(thing, this); this.channels.push(temp); - this.channelids[temp.id] = temp; + this.localuser.channelids.set(temp.id, temp); } this.headchannels = []; for (const thing of this.channels) { @@ -126,7 +124,7 @@ class Guild extends SnowFlake { this.headchannels.push(thing); } } - this.prevchannel = this.channelids[this.perminfo.prevchannel]; + this.prevchannel = this.localuser.channelids.get(this.perminfo.prevchannel); } get perminfo() { return this.localuser.perminfo.guilds[this.id]; @@ -429,9 +427,12 @@ class Guild extends SnowFlake { return this.member.hasRole(r); } loadChannel(ID) { - if (ID && this.channelids[ID]) { - this.channelids[ID].getHTML(); - return; + if (ID) { + const channel = this.localuser.channelids.get(ID); + if (channel) { + channel.getHTML(); + return; + } } if (this.prevchannel) { console.log(this.prevchannel); @@ -449,7 +450,7 @@ class Guild extends SnowFlake { this.localuser.loadGuild(this.id); } updateChannel(json) { - const channel = this.channelids[json.id]; + const channel = this.localuser.channelids.get(json.id); if (channel) { channel.updateChannel(json); this.headchannels = []; @@ -468,7 +469,7 @@ class Guild extends SnowFlake { } createChannelpac(json) { const thischannel = new Channel(json, this); - this.channelids[json.id] = thischannel; + this.localuser.channelids.set(json.id, thischannel); this.channels.push(thischannel); thischannel.resolveparent(this); if (!thischannel.parent) { @@ -515,8 +516,10 @@ class Guild extends SnowFlake { channelselect.show(); } delChannel(json) { - const channel = this.channelids[json.id]; - delete this.channelids[json.id]; + const channel = this.localuser.channelids.get(json.id); + this.localuser.channelids.delete(json.id); + if (!channel) + return; this.channels.splice(this.channels.indexOf(channel), 1); const indexy = this.headchannels.indexOf(channel); if (indexy !== -1) { diff --git a/.dist/infiniteScroller.js b/.dist/infiniteScroller.js index bfda98e..c26b92f 100644 --- a/.dist/infiniteScroller.js +++ b/.dist/infiniteScroller.js @@ -24,6 +24,9 @@ class InfiniteScroller { this.div = scroll; this.div.addEventListener("scroll", _ => { this.checkscroll(); + if (this.scrollBottom < 5) { + this.scrollBottom = 5; + } if (this.timeout === null) { this.timeout = setTimeout(this.updatestuff.bind(this), 300); } diff --git a/.dist/localuser.js b/.dist/localuser.js index 7808d9d..6c097f4 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -30,6 +30,7 @@ class Localuser { ws; connectionSucceed = 0; errorBackoff = 0; + channelids = new Map(); userMap = new Map(); instancePing = { name: "Unknown", @@ -64,8 +65,8 @@ class Localuser { this.userinfo.username = this.user.username; this.userinfo.pfpsrc = this.user.getpfpsrc(); this.status = this.ready.d.user_settings.status; - this.channelfocus = null; - this.lookingguild = null; + this.channelfocus = undefined; + this.lookingguild = undefined; this.guildhtml = new Map(); const members = {}; for (const thing of ready.d.merged_members) { @@ -86,15 +87,11 @@ class Localuser { this.guildids.get(thing.guild_id).notisetting(thing); } for (const thing of ready.d.read_state.entries) { - const channel = this.resolveChannelFromID(thing.id); + const channel = this.channelids.get(thing.channel_id); if (!channel) { continue; } - const guild = channel.guild; - if (guild === undefined) { - continue; - } - guild.channelids[thing.channel_id].readStateInfo(thing); + channel.readStateInfo(thing); } for (const thing of ready.d.relationships) { const user = new User(thing.user, this); @@ -112,8 +109,8 @@ class Localuser { if (this.channelfocus) { this.channelfocus.infinite.delete(); } - this.lookingguild = null; - this.channelfocus = null; + this.lookingguild = undefined; + this.channelfocus = undefined; } unload() { this.initialized = false; @@ -307,10 +304,7 @@ class Localuser { case "MESSAGE_DELETE": { temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) - break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.id); @@ -325,10 +319,7 @@ class Localuser { case "MESSAGE_UPDATE": { temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) - break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.id); @@ -389,7 +380,7 @@ class Localuser { const guild = this.guildids.get(temp.d.guild_id); if (!guild) break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.message_id); @@ -408,10 +399,7 @@ class Localuser { case "MESSAGE_REACTION_REMOVE": { temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) - break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.message_id); @@ -423,10 +411,7 @@ class Localuser { case "MESSAGE_REACTION_REMOVE_ALL": { temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) - break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.message_id); @@ -438,10 +423,7 @@ class Localuser { case "MESSAGE_REACTION_REMOVE_EMOJI": { temp.d.guild_id ??= "@me"; - const guild = this.guildids.get(temp.d.guild_id); - if (!guild) - break; - const channel = guild.channelids[temp.d.channel_id]; + const channel = this.channelids.get(temp.d.channel_id); if (!channel) break; const message = channel.messages.get(temp.d.message_id); @@ -473,13 +455,6 @@ class Localuser { } } heartbeat_interval; - resolveChannelFromID(ID) { - const resolve = this.guilds.find(guild => guild.channelids[ID]); - if (resolve) { - return resolve.channelids[ID]; - } - return undefined; - } updateChannel(json) { const guild = this.guildids.get(json.guild_id); if (guild) { @@ -506,13 +481,9 @@ class Localuser { } gotoid; async goToChannel(id) { - let guild; - for (const thing of this.guilds) { - if (thing.channelids[id]) { - guild = thing; - } - } - if (guild) { + const channel = this.channelids.get(id); + if (channel) { + const guild = channel.guild; guild.loadGuild(); guild.loadChannel(id); } @@ -540,7 +511,7 @@ class Localuser { return; } guild.loadChannel(location[5]); - this.channelfocus = guild.channelids[location[5]]; + this.channelfocus = this.channelids.get(location[5]); } } loaduser() { @@ -770,11 +741,11 @@ class Localuser { } messageCreate(messagep) { messagep.d.guild_id ??= "@me"; - const guild = this.guildids.get(messagep.d.guild_id); - if (!guild) - return; - guild.channelids[messagep.d.channel_id].messageCreate(messagep); - this.unreads(); + const channel = this.channelids.get(messagep.d.channel_id); + if (channel) { + channel.messageCreate(messagep); + this.unreads(); + } } unreads() { for (const thing of this.guilds) { @@ -787,10 +758,7 @@ class Localuser { } async typingStart(typing) { // - const guild = this.guildids.get(typing.d.guild_id); - if (!guild) - return; - const channel = guild.channelids[typing.d.channel_id]; + const channel = this.channelids.get(typing.d.channel_id); if (!channel) return; channel.typingStart(typing); diff --git a/.dist/markdown.js b/.dist/markdown.js index 4616b20..7675cbc 100644 --- a/.dist/markdown.js +++ b/.dist/markdown.js @@ -1,6 +1,8 @@ import { Channel } from "./channel.js"; import { Dialog } from "./dialog.js"; import { Emoji } from "./emoji.js"; +import { Localuser } from "./localuser.js"; +import { Member } from "./member.js"; class MarkDown { txt; keep; @@ -22,6 +24,14 @@ class MarkDown { this.owner = owner; this.stdsize = stdsize; } + get localuser() { + if (this.owner instanceof Localuser) { + return this.owner; + } + else { + return this.owner.localuser; + } + } get rawString() { return this.txt.join(""); } @@ -415,6 +425,68 @@ class MarkDown { continue; } } + if (txt[i] === "<" && (txt[i + 1] === "@" || txt[i + 1] === "#")) { + let id = ""; + let j = i + 2; + const numbers = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]); + for (; txt[j] !== undefined; j++) { + const char = txt[j]; + if (!numbers.has(char)) { + break; + } + id += char; + } + if (txt[j] === ">") { + appendcurrent(); + const mention = document.createElement("span"); + mention.classList.add("mentionMD"); + mention.contentEditable = "false"; + const char = txt[i + 1]; + i = j; + switch (char) { + case "@": + const user = this.localuser.userMap.get(id); + if (user) { + mention.textContent = `@${user.name}`; + let guild = null; + if (this.owner instanceof Channel) { + guild = this.owner.guild; + } + if (!keep) { + user.bind(mention, guild); + } + if (guild) { + Member.resolveMember(user, guild).then(member => { + if (member) { + mention.textContent = `@${member.name}`; + } + }); + } + } + else { + mention.textContent = `@unknown`; + } + break; + case "#": + const channel = this.localuser.channelids.get(id); + if (channel) { + mention.textContent = `#${channel.name}`; + if (!keep) { + mention.onclick = _ => { + this.localuser.goToChannel(id); + }; + } + } + else { + mention.textContent = `#unknown`; + } + break; + } + span.appendChild(mention); + mention.setAttribute("real", `<${char}${id}>`); + continue; + } + } if (txt[i] === "<" && txt[i + 1] === "t" && txt[i + 2] === ":") { let found = false; const build = ["<", "t", ":"]; @@ -571,6 +643,9 @@ class MarkDown { if (element.tagName.toLowerCase() === "br") { return "\n"; } + if (element.hasAttribute("real")) { + return element.getAttribute("real"); + } let build = ""; for (const thing of element.childNodes) { if (thing instanceof Text) { @@ -633,15 +708,29 @@ class MarkDown { throw Error(url + " is not a valid URL"); } } + static replace(base, newelm) { + const basechildren = base.children; + const newchildren = newelm.children; + for (const thing of newchildren) { + } + } } //solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div +let text = ""; function saveCaretPosition(context) { const selection = window.getSelection(); if (!selection) return; const range = selection.getRangeAt(0); range.setStart(context, 0); - const len = range.toString().length; + text = selection.toString(); + let len = text.length + 1; + for (const str in text.split("\n")) { + if (str.length !== 0) { + len--; + } + } + len += +(text[text.length - 1] === "\n"); return function restore() { if (!selection) return; diff --git a/.dist/message.js b/.dist/message.js index a17dedb..1bf4cf1 100644 --- a/.dist/message.js +++ b/.dist/message.js @@ -273,6 +273,11 @@ class Message extends SnowFlake { premessage = this.channel.messages.get(this.channel.idToPrev.get(this.id)); } const div = this.div; + for (const user of this.mentions) { + if (user === this.localuser.user) { + div.classList.add("mentioned"); + } + } if (this === this.channel.replyingto) { div.classList.add("replying"); } diff --git a/.dist/user.js b/.dist/user.js index f7f27a3..051f2c7 100644 --- a/.dist/user.js +++ b/.dist/user.js @@ -138,6 +138,9 @@ class User extends SnowFlake { get localuser() { return this.owner; } + get name() { + return this.username; + } constructor(userjson, owner, dontclone = false) { super(userjson.id); this.owner = owner; diff --git a/webpage/channel.ts b/webpage/channel.ts index 334dedb..0298ab2 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -26,7 +26,7 @@ class Channel extends SnowFlake{ headers:Localuser["headers"]; name:string; parent_id?:string; - parent:Channel|null; + parent:Channel|undefined; children:Channel[]; guild_id:string; permission_overwrites:Map; @@ -224,7 +224,7 @@ class Channel extends SnowFlake{ if(json.parent_id){ this.parent_id=json.parent_id; } - this.parent=null; + this.parent=undefined; this.children=[]; this.guild_id=json.guild_id; this.permission_overwrites=new Map(); @@ -325,12 +325,12 @@ class Channel extends SnowFlake{ resolveparent(guild:Guild){ const parentid=this.parent_id; if(!parentid)return false; - this.parent=guild.channelids[parentid]; - this.parent??=null; - if(this.parent!==null){ + this.parent=this.localuser.channelids.get(parentid); + this.parent??=undefined; + if(this.parent!==undefined){ this.parent.children.push(this); } - return this.parent!==null; + return this.parent!==undefined; } calculateReorder(){ let position=-1; @@ -970,12 +970,12 @@ class Channel extends SnowFlake{ updateChannel(json:channeljson){ this.type=json.type; this.name=json.name; - const parent=this.guild.channelids[json.parent_id]; + const parent=this.localuser.channelids.get(json.parent_id); if(parent){ this.parent=parent; this.parent_id=parent.id; }else{ - this.parent=null; + this.parent=undefined; this.parent_id=undefined; } diff --git a/webpage/guild.ts b/webpage/guild.ts index 3e0f4a9..6a12668 100644 --- a/webpage/guild.ts +++ b/webpage/guild.ts @@ -14,7 +14,6 @@ class Guild extends SnowFlake{ owner:Localuser; headers:Localuser["headers"]; channels:Channel[]; - channelids:{[key:string]:Channel}; properties; member_count:number; roles:Role[]; @@ -96,7 +95,6 @@ class Guild extends SnowFlake{ this.owner=owner; this.headers=this.owner.headers; this.channels=[]; - this.channelids={}; this.properties=json.properties; this.roles=[]; this.roleids=new Map(); @@ -126,7 +124,7 @@ class Guild extends SnowFlake{ for(const thing of json.channels){ const temp=new Channel(thing,this); this.channels.push(temp); - this.channelids[temp.id]=temp; + this.localuser.channelids.set(temp.id,temp); } this.headchannels=[]; for(const thing of this.channels){ @@ -135,7 +133,7 @@ class Guild extends SnowFlake{ this.headchannels.push(thing); } } - this.prevchannel=this.channelids[this.perminfo.prevchannel]; + this.prevchannel=this.localuser.channelids.get(this.perminfo.prevchannel); } get perminfo(){ return this.localuser.perminfo.guilds[this.id]; @@ -436,9 +434,12 @@ class Guild extends SnowFlake{ return this.member.hasRole(r); } loadChannel(ID?:string|undefined){ - if(ID&&this.channelids[ID]){ - this.channelids[ID].getHTML(); - return; + if(ID){ + const channel=this.localuser.channelids.get(ID); + if(channel){ + channel.getHTML(); + return; + } } if(this.prevchannel){ console.log(this.prevchannel); @@ -456,7 +457,7 @@ class Guild extends SnowFlake{ this.localuser.loadGuild(this.id); } updateChannel(json:channeljson){ - const channel=this.channelids[json.id]; + const channel=this.localuser.channelids.get(json.id); if(channel){ channel.updateChannel(json); this.headchannels=[]; @@ -475,7 +476,7 @@ class Guild extends SnowFlake{ } createChannelpac(json:channeljson){ const thischannel=new Channel(json,this); - this.channelids[json.id]=thischannel; + this.localuser.channelids.set(json.id,thischannel); this.channels.push(thischannel); thischannel.resolveparent(this); if(!thischannel.parent){ @@ -526,9 +527,9 @@ class Guild extends SnowFlake{ channelselect.show(); } delChannel(json:channeljson){ - const channel=this.channelids[json.id]; - delete this.channelids[json.id]; - + const channel=this.localuser.channelids.get(json.id); + this.localuser.channelids.delete(json.id); + if(!channel) return; this.channels.splice(this.channels.indexOf(channel),1); const indexy=this.headchannels.indexOf(channel); if(indexy!==-1){ diff --git a/webpage/infiniteScroller.ts b/webpage/infiniteScroller.ts index c16a97f..7a7988b 100644 --- a/webpage/infiniteScroller.ts +++ b/webpage/infiniteScroller.ts @@ -25,6 +25,9 @@ class InfiniteScroller{ this.div=scroll; this.div.addEventListener("scroll",_=>{ this.checkscroll(); + if(this.scrollBottom<5){ + this.scrollBottom=5; + } if(this.timeout===null){ this.timeout=setTimeout(this.updatestuff.bind(this),300); } diff --git a/webpage/localuser.ts b/webpage/localuser.ts index 0cc28b4..73400b9 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -28,12 +28,13 @@ class Localuser{ guildids:Map; user:User; status:string; - channelfocus:Channel|null; - lookingguild:Guild|null; + channelfocus:Channel|undefined; + lookingguild:Guild|undefined; guildhtml:Map; ws:WebSocket|undefined; connectionSucceed=0; errorBackoff=0; + channelids=new Map() readonly userMap=new Map(); instancePing={ name: "Unknown", @@ -68,8 +69,8 @@ class Localuser{ this.userinfo.username=this.user.username; this.userinfo.pfpsrc=this.user.getpfpsrc(); this.status=this.ready.d.user_settings.status; - this.channelfocus=null; - this.lookingguild=null; + this.channelfocus=undefined; + this.lookingguild=undefined; this.guildhtml=new Map(); const members={}; for(const thing of ready.d.merged_members){ @@ -94,15 +95,11 @@ class Localuser{ } for(const thing of ready.d.read_state.entries){ - const channel=this.resolveChannelFromID(thing.id); + const channel=this.channelids.get(thing.channel_id); if(!channel){ continue; } - const guild=channel.guild; - if(guild===undefined){ - continue; - } - guild.channelids[thing.channel_id].readStateInfo(thing); + channel.readStateInfo(thing); } for(const thing of ready.d.relationships){ const user=new User(thing.user,this); @@ -121,8 +118,8 @@ class Localuser{ if(this.channelfocus){ this.channelfocus.infinite.delete(); } - this.lookingguild=null; - this.channelfocus=null; + this.lookingguild=undefined; + this.channelfocus=undefined; } unload():void{ this.initialized=false; @@ -315,9 +312,7 @@ class Localuser{ case"MESSAGE_DELETE": { temp.d.guild_id??="@me"; - const guild=this.guildids.get(temp.d.guild_id); - if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.id); if(!message) break; @@ -330,9 +325,7 @@ class Localuser{ case"MESSAGE_UPDATE": { temp.d.guild_id??="@me"; - const guild=this.guildids.get(temp.d.guild_id); - if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.id); if(!message) break; @@ -390,7 +383,7 @@ class Localuser{ temp.d.guild_id??="@me"; const guild=this.guildids.get(temp.d.guild_id); if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.message_id); if(!message) break; @@ -406,9 +399,7 @@ class Localuser{ case"MESSAGE_REACTION_REMOVE": { temp.d.guild_id??="@me"; - const guild=this.guildids.get(temp.d.guild_id); - if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.message_id); if(!message) break; @@ -418,9 +409,7 @@ class Localuser{ case"MESSAGE_REACTION_REMOVE_ALL": { temp.d.guild_id??="@me"; - const guild=this.guildids.get(temp.d.guild_id); - if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.message_id); if(!message) break; @@ -430,9 +419,7 @@ class Localuser{ case"MESSAGE_REACTION_REMOVE_EMOJI": { temp.d.guild_id??="@me"; - const guild=this.guildids.get(temp.d.guild_id); - if(!guild) break; - const channel=guild.channelids[temp.d.channel_id]; + const channel=this.channelids.get(temp.d.channel_id); if(!channel) break; const message=channel.messages.get(temp.d.message_id); if(!message) break; @@ -457,13 +444,6 @@ class Localuser{ } } heartbeat_interval:number; - resolveChannelFromID(ID:string):Channel|undefined{ - const resolve=this.guilds.find(guild=>guild.channelids[ID]); - if(resolve){ - return resolve.channelids[ID]; - } - return undefined; - } updateChannel(json:channeljson):void{ const guild=this.guildids.get(json.guild_id); if(guild){ @@ -489,13 +469,10 @@ class Localuser{ } gotoid:string|undefined; async goToChannel(id:string){ - let guild:undefined|Guild; - for(const thing of this.guilds){ - if(thing.channelids[id]){ - guild=thing; - } - } - if(guild){ + + const channel=this.channelids.get(id); + if(channel){ + const guild=channel.guild; guild.loadGuild(); guild.loadChannel(id); }else{ @@ -523,7 +500,7 @@ class Localuser{ return; } guild.loadChannel(location[5]); - this.channelfocus=guild.channelids[location[5]]; + this.channelfocus=this.channelids.get(location[5]); } } loaduser():void{ @@ -762,10 +739,11 @@ class Localuser{ } messageCreate(messagep):void{ messagep.d.guild_id??="@me"; - const guild=this.guildids.get(messagep.d.guild_id); - if(!guild)return; - guild.channelids[messagep.d.channel_id].messageCreate(messagep); - this.unreads(); + const channel=this.channelids.get(messagep.d.channel_id); + if(channel){ + channel.messageCreate(messagep); + this.unreads(); + } } unreads():void{ for(const thing of this.guilds){ @@ -778,9 +756,7 @@ class Localuser{ } async typingStart(typing):Promise{ // - const guild=this.guildids.get(typing.d.guild_id); - if(!guild)return; - const channel=guild.channelids[typing.d.channel_id]; + const channel=this.channelids.get(typing.d.channel_id); if(!channel) return; channel.typingStart(typing); //this.typing.set(memb,Date.now()); diff --git a/webpage/markdown.ts b/webpage/markdown.ts index df3fc79..d3e414f 100644 --- a/webpage/markdown.ts +++ b/webpage/markdown.ts @@ -1,7 +1,9 @@ import{ Channel }from"./channel.js"; import { Dialog } from "./dialog.js"; import{ Emoji }from"./emoji.js"; +import { Guild } from "./guild.js"; import{ Localuser }from"./localuser.js"; +import { Member } from "./member.js"; class MarkDown{ @@ -24,6 +26,13 @@ class MarkDown{ this.owner=owner; this.stdsize=stdsize; } + get localuser(){ + if(this.owner instanceof Localuser){ + return this.owner; + }else{ + return this.owner.localuser; + } + } get rawString(){ return this.txt.join(""); } @@ -406,7 +415,67 @@ class MarkDown{ span.appendChild(a); continue; } + } + if(txt[i]==="<" && (txt[i + 1]==="@"||txt[i + 1]==="#")){ + let id=""; + let j = i+2; + const numbers=new Set(["0", "1", "2", "3", "4","5","6","7","8","9"]); + for(; txt[j] !== undefined; j++){ + const char=txt[j]; + if(!numbers.has(char)){ + break; + } + id+=char; + } + if(txt[j]===">"){ + appendcurrent(); + const mention=document.createElement("span"); + mention.classList.add("mentionMD"); + mention.contentEditable="false"; + const char=txt[i + 1]; + i=j; + switch(char){ + case "@": + const user=this.localuser.userMap.get(id); + if(user){ + mention.textContent=`@${user.name}`; + let guild:null|Guild=null; + if(this.owner instanceof Channel){ + guild=this.owner.guild; + } + if(!keep){ + user.bind(mention,guild); + } + if(guild){ + Member.resolveMember(user,guild).then(member=>{ + if(member){ + mention.textContent=`@${member.name}`; + } + }) + } + }else{ + mention.textContent=`@unknown`; + } + break; + case "#": + const channel=this.localuser.channelids.get(id); + if(channel){ + mention.textContent=`#${channel.name}`; + if(!keep){ + mention.onclick=_=>{ + this.localuser.goToChannel(id); + } + } + }else{ + mention.textContent=`#unknown`; + } + break; + } + span.appendChild(mention); + mention.setAttribute("real",`<${char}${id}>`); + continue; + } } if(txt[i]==="<" && txt[i + 1]==="t" && txt[i + 2]===":"){ let found=false; @@ -561,14 +630,16 @@ class MarkDown{ restore(); } } - static gatherBoxText(element:HTMLElement){ + static gatherBoxText(element:HTMLElement):string{ if(element.tagName.toLowerCase()==="img"){ return(element as HTMLImageElement).alt; } if(element.tagName.toLowerCase()==="br"){ return"\n"; } - + if(element.hasAttribute("real")){ + return element.getAttribute("real") as string; + } let build=""; for(const thing of element.childNodes){ if(thing instanceof Text){ @@ -627,15 +698,30 @@ class MarkDown{ throw Error(url+" is not a valid URL") } } + static replace(base:HTMLElement,newelm:HTMLElement){ + const basechildren=base.children; + const newchildren=newelm.children; + for(const thing of newchildren){ + + } + } } //solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div -function saveCaretPosition(context){ +let text=""; +function saveCaretPosition (context){ const selection = window.getSelection(); if(!selection)return; const range = selection.getRangeAt(0); range.setStart(context, 0); - const len = range.toString().length; + text=selection.toString(); + let len = text.length+1; + for(const str in text.split("\n")){ + if(str.length!==0){ + len--; + } + } + len+=+(text[text.length-1]==="\n"); return function restore(){ if(!selection)return; diff --git a/webpage/message.ts b/webpage/message.ts index 8a6efb1..09463a2 100644 --- a/webpage/message.ts +++ b/webpage/message.ts @@ -268,6 +268,11 @@ class Message extends SnowFlake{ premessage=this.channel.messages.get(this.channel.idToPrev.get(this.id) as string); } const div=this.div; + for(const user of this.mentions){ + if(user===this.localuser.user){ + div.classList.add("mentioned"); + } + } if(this===this.channel.replyingto){ div.classList.add("replying"); } diff --git a/webpage/style.css b/webpage/style.css index 86f250c..2829e75 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -925,9 +925,9 @@ input[type="checkbox"] { } .quote { - display: inline-flex; width: fit-content; position: relative; + display: inline; } .quoteline { @@ -940,7 +940,7 @@ input[type="checkbox"] { .quote > span { margin-left: 0.5em; - display: block; + display: inline-block; align-items: center; } span { @@ -2191,3 +2191,17 @@ form div{ margin-top: .04in; width: 100%; } +.mentioned{ + background-color:color-mix(in srgb, transparent,var(--yellow) 12%); +} +.mentionMD{ + background:var(--mention-md-bg); + flex-shrink:0; + padding:.03in; + border-radius:.1in; + font-weight:bold; + cursor:pointer; +} +.mentionMD:hover{ + background:color-mix(in srgb,var(--mention-md-bg),white 10%); +} \ No newline at end of file diff --git a/webpage/themes.css b/webpage/themes.css index 442b9f2..00717c7 100644 --- a/webpage/themes.css +++ b/webpage/themes.css @@ -30,6 +30,7 @@ --textarea-bg: color-mix(in srgb, #484848 80%, var(--accent-color)); --filename: #47bbff; --mention-bg: #F00; + --mention-md-bg: #3b588b; --pronouns: #797979; --profile-bg: color-mix(in srgb, #232323 90%, var(--accent-color)); --profile-info-bg: color-mix(in srgb, #121212 90%, var(--accent-color)); @@ -84,6 +85,7 @@ --textarea-bg: #b1b6ce; --filename: #47bbff; --mention-bg: #F00; + --mention-md-bg: #3b588b; --pronouns: #6a6a6d; --profile-bg: #cacad8; --profile-info-bg: #bbbbce; @@ -140,6 +142,7 @@ --textarea-bg: #abb1cd; --filename: #47bbff; --mention-bg: #F00; + --mention-md-bg: #3b588b; --pronouns: #202020; --channel-name-bg: #c0c0d4; --server-name-bg: #a3a3b5; diff --git a/webpage/user.ts b/webpage/user.ts index f1e91a2..877700b 100644 --- a/webpage/user.ts +++ b/webpage/user.ts @@ -139,6 +139,9 @@ class User extends SnowFlake{ get localuser(){ return this.owner; } + get name(){ + return this.username; + } constructor(userjson:userjson,owner:Localuser,dontclone=false){ super(userjson.id); this.owner=owner;