search updates

This commit is contained in:
MathMan05 2024-12-20 18:59:40 -06:00
parent 161181f8de
commit ffe21e6d6c
10 changed files with 185 additions and 43 deletions

View file

@ -16,6 +16,7 @@
"express": "^4.19.2", "express": "^4.19.2",
"gulp-sourcemaps": "^2.6.5", "gulp-sourcemaps": "^2.6.5",
"gulp-swc": "^2.2.0", "gulp-swc": "^2.2.0",
"prettier": "^3.4.2",
"rimraf": "^6.0.1" "rimraf": "^6.0.1"
}, },
"devDependencies": { "devDependencies": {

View file

@ -777,6 +777,14 @@ class Channel extends SnowFlake{
return new Message(json[0], this); return new Message(json[0], this);
} }
} }
async focus(id:string){
console.time()
console.log(await this.getmessage(id));
await this.getHTML();
console.timeEnd()
console.warn(id);
this.infinite.focus(id);
}
editLast(){ editLast(){
let message:Message|undefined=this.lastmessage; let message:Message|undefined=this.lastmessage;
while(message&&message.author!==this.localuser.user){ while(message&&message.author!==this.localuser.user){
@ -1180,7 +1188,7 @@ class Channel extends SnowFlake{
} }
async buildmessages(){ async buildmessages(){
this.infinitefocus = false; this.infinitefocus = false;
this.tryfocusinfinate(); await this.tryfocusinfinate();
} }
infinitefocus = false; infinitefocus = false;
async tryfocusinfinate(){ async tryfocusinfinate(){
@ -1548,3 +1556,5 @@ class Channel extends SnowFlake{
} }
Channel.setupcontextmenu(); Channel.setupcontextmenu();
export{ Channel }; export{ Channel };

View file

@ -60,6 +60,7 @@
<span id="channelname">Channel name</span> <span id="channelname">Channel name</span>
<span id="channelTopic" class="ellipsis" hidden>Channel topic</span> <span id="channelTopic" class="ellipsis" hidden>Channel topic</span>
</span> </span>
<div contenteditable="true" class="searchBox" id="searchBox"></div>
<label for="memberlisttoggle" id="memberlisttoggleicon"> <label for="memberlisttoggle" id="memberlisttoggleicon">
<span class="svgicon svg-friends"></span> <span class="svgicon svg-friends"></span>
</label> </label>

View file

@ -204,7 +204,28 @@ import { I18n } from "./i18n.js";
if(event.key === "Enter" && !event.shiftKey) event.preventDefault(); if(event.key === "Enter" && !event.shiftKey) event.preventDefault();
}); });
markdown.giveBox(typebox); markdown.giveBox(typebox);
{
const searchBox = document.getElementById("searchBox") as CustomHTMLDivElement;
const markdown = new MarkDown("", thisUser);
searchBox.markdown = markdown;
searchBox.addEventListener("keydown", event=>{
if(event.key === "Enter") {
event.preventDefault();
thisUser.mSearch(markdown.rawString)
};
});
markdown.giveBox(searchBox);
markdown.setCustomBox((e)=>{
const span=document.createElement("span");
span.textContent=e.replace("\n","");
return span;
});
}
const images: Blob[] = []; const images: Blob[] = [];
const imagesHtml: HTMLElement[] = []; const imagesHtml: HTMLElement[] = [];

View file

@ -37,7 +37,6 @@ offset: number
this.destroyFromID(thing[1]); this.destroyFromID(thing[1]);
} }
this.HTMLElements=[]; this.HTMLElements=[];
this.div=null;
} }
constructor( constructor(
getIDFromOffset: InfiniteScroller["getIDFromOffset"], getIDFromOffset: InfiniteScroller["getIDFromOffset"],

View file

@ -5,7 +5,7 @@ import{ AVoice }from"./audio/voice.js";
import{ User }from"./user.js"; import{ User }from"./user.js";
import{ getapiurls, SW }from"./utils/utils.js"; import{ getapiurls, SW }from"./utils/utils.js";
import { getBulkInfo, setTheme, Specialuser } from "./utils/utils.js"; import { getBulkInfo, setTheme, Specialuser } from "./utils/utils.js";
import{channeljson,emojipjson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js"; import{channeljson,emojipjson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,messagejson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js";
import{ Member }from"./member.js"; import{ Member }from"./member.js";
import{ Dialog, Form, FormError, Options, Settings }from"./settings.js"; import{ Dialog, Form, FormError, Options, Settings }from"./settings.js";
import{ getTextNodeAtPosition, MarkDown }from"./markdown.js"; import{ getTextNodeAtPosition, MarkDown }from"./markdown.js";
@ -15,6 +15,7 @@ import { VoiceFactory } from "./voice.js";
import { I18n, langmap } from "./i18n.js"; import { I18n, langmap } from "./i18n.js";
import { Emoji } from "./emoji.js"; import { Emoji } from "./emoji.js";
import { Play } from "./audio/play.js"; import { Play } from "./audio/play.js";
import { Message } from "./message.js";
const wsCodesRetry = new Set([4000,4001,4002, 4003, 4005, 4007, 4008, 4009]); const wsCodesRetry = new Set([4000,4001,4002, 4003, 4005, 4007, 4008, 4009]);
@ -669,8 +670,10 @@ class Localuser{
return channel; // Add this line to return the 'channel' variable return channel; // Add this line to return the 'channel' variable
} }
async memberListUpdate(list:memberlistupdatejson|void){ async memberListUpdate(list:memberlistupdatejson|void){
if(this.searching)return;
const div=document.getElementById("sideDiv") as HTMLDivElement; const div=document.getElementById("sideDiv") as HTMLDivElement;
div.innerHTML=""; div.innerHTML="";
div.classList.remove("searchDiv");
const guild=this.lookingguild; const guild=this.lookingguild;
if(!guild) return; if(!guild) return;
const channel=this.channelfocus; const channel=this.channelfocus;
@ -832,6 +835,7 @@ class Localuser{
} }
} }
loadGuild(id: string,forceReload=false): Guild | undefined{ loadGuild(id: string,forceReload=false): Guild | undefined{
this.searching=false;
let guild = this.guildids.get(id); let guild = this.guildids.get(id);
if(!guild){ if(!guild){
guild = this.guildids.get("@me"); guild = this.guildids.get("@me");
@ -1968,6 +1972,49 @@ class Localuser{
} }
box.innerHTML=""; box.innerHTML="";
} }
searching=false;
mSearch(query:string){
const p=new URLSearchParams("?");
this.searching=true;
p.set("content",query.trim());
fetch(this.info.api+`/guilds/${this.lookingguild?.id}/messages/search/?`+p.toString(),{
headers:this.headers
}).then(_=>_.json()).then((json:{messages:[messagejson][],total_results:number})=>{
//FIXME total_results shall be ignored as it's known to be bad, spacebar bug.
const messages=json.messages.map(([m])=>{
const c=this.channelids.get(m.channel_id);
if(!c) return;
if(c.messages.get(m.id)){
return c.messages.get(m.id);
}
return new Message(m,c,true);
}).filter(_=>_!==undefined);
const sideDiv= document.getElementById("sideDiv");
if(!sideDiv)return;
sideDiv.innerHTML="";
sideDiv.classList.add("searchDiv");
let channel:Channel|undefined=undefined;
for(const message of messages){
if(channel!==message.channel){
channel=message.channel;
const h3=document.createElement("h3");
h3.textContent=channel.name;
h3.classList.add("channelSTitle")
sideDiv.append(h3);
}
const html=message.buildhtml(undefined,true);
html.addEventListener("click",async ()=>{
try{
await message.channel.focus(message.id);
}catch(e){
console.error(e);
}
})
sideDiv.append(html)
}
});
}
keydown:(event:KeyboardEvent)=>unknown=()=>{}; keydown:(event:KeyboardEvent)=>unknown=()=>{};
keyup:(event:KeyboardEvent)=>boolean=()=>false; keyup:(event:KeyboardEvent)=>boolean=()=>false;
//---------- resolving members code ----------- //---------- resolving members code -----------

View file

@ -300,11 +300,7 @@ class MarkDown{
} }
} }
if( if(
find === count && find === count &&(count != 1 ||txt[j + 1] === " " ||txt[j + 1] === "\n" ||txt[j + 1] === undefined)
(count != 1 ||
txt[j + 1] === " " ||
txt[j + 1] === "\n" ||
txt[j + 1] === undefined)
){ ){
appendcurrent(); appendcurrent();
i = j; i = j;
@ -715,16 +711,37 @@ txt[j + 1] === undefined)
box.onkeyup(new KeyboardEvent("_")); box.onkeyup(new KeyboardEvent("_"));
}; };
} }
customBox?:[(arg1:string)=>HTMLElement,((arg1:HTMLElement)=>string)];
clearCustom(){
this.customBox=undefined;
}
setCustomBox(stringToHTML:(arg1:string)=>HTMLElement,HTMLToString=MarkDown.gatherBoxText.bind(MarkDown)){
this.customBox=[stringToHTML,HTMLToString];
}
boxupdate(offset=0){ boxupdate(offset=0){
const box=this.box.deref(); const box=this.box.deref();
if(!box) return; if(!box) return;
const restore = saveCaretPosition(box,offset); let restore:undefined|(()=>void);
if(this.customBox){
restore= saveCaretPosition(box,offset,this.customBox[1]);
}else{
restore= saveCaretPosition(box,offset)
}
box.innerHTML = ""; box.innerHTML = "";
box.append(this.makeHTML({ keep: true })); if(this.customBox){
box.append(this.customBox[0](this.rawString));
}else{
box.append(this.makeHTML({ keep: true }));
}
if(restore){ if(restore){
restore(); restore();
const test=saveCaretPosition(box); if(this.customBox){
if(test) test(); const test=saveCaretPosition(box,0,this.customBox[1]);
if(test) test();
}else{
const test=saveCaretPosition(box);
if(test) test();
}
} }
this.onUpdate(text,formatted); this.onUpdate(text,formatted);
} }
@ -816,7 +833,7 @@ txt[j + 1] === undefined)
//solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div //solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div
let text = ""; let text = "";
let formatted=false; let formatted=false;
function saveCaretPosition(context: HTMLElement,offset=0){ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.gatherBoxText.bind(MarkDown)){
const selection = window.getSelection() as Selection; const selection = window.getSelection() as Selection;
if(!selection)return; if(!selection)return;
try{ try{
@ -837,7 +854,7 @@ function saveCaretPosition(context: HTMLElement,offset=0){
i++; i++;
} }
if(base instanceof HTMLElement){ if(base instanceof HTMLElement){
baseString=MarkDown.gatherBoxText(base) baseString=txtLengthFunc(base)
}else{ }else{
baseString=base.textContent as string; baseString=base.textContent as string;
} }
@ -855,7 +872,7 @@ function saveCaretPosition(context: HTMLElement,offset=0){
const children=[...context.childNodes]; const children=[...context.childNodes];
if(children.length===1&&children[0] instanceof Text){ if(children.length===1&&children[0] instanceof Text){
if(selection.containsNode(context,false)){ if(selection.containsNode(context,false)){
build+=MarkDown.gatherBoxText(context as HTMLElement); build+=txtLengthFunc(context as HTMLElement);
}else if(selection.containsNode(context,true)){ }else if(selection.containsNode(context,true)){
if(context.contains(base)||context===base||base.contains(context)){ if(context.contains(base)||context===base||base.contains(context)){
build+=baseString; build+=baseString;
@ -871,7 +888,7 @@ function saveCaretPosition(context: HTMLElement,offset=0){
if(selection.containsNode(node,false)){ if(selection.containsNode(node,false)){
if(node instanceof HTMLElement){ if(node instanceof HTMLElement){
build+=MarkDown.gatherBoxText(node); build+=txtLengthFunc(node);
}else{ }else{
build+=node.textContent; build+=node.textContent;
} }
@ -892,10 +909,10 @@ function saveCaretPosition(context: HTMLElement,offset=0){
} }
text=build; text=build;
let len=build.length+offset; let len=build.length+offset;
len=Math.min(len,MarkDown.gatherBoxText(context).length) len=Math.min(len,txtLengthFunc(context).length)
return function restore(){ return function restore(){
if(!selection)return; if(!selection)return;
const pos = getTextNodeAtPosition(context, len); const pos = getTextNodeAtPosition(context, len,txtLengthFunc);
selection.removeAllRanges(); selection.removeAllRanges();
const range = new Range(); const range = new Range();
range.setStart(pos.node, pos.position); range.setStart(pos.node, pos.position);
@ -906,7 +923,7 @@ function saveCaretPosition(context: HTMLElement,offset=0){
} }
} }
function getTextNodeAtPosition(root: Node, index: number):{ function getTextNodeAtPosition(root: Node, index: number,txtLengthFunc=MarkDown.gatherBoxText.bind(MarkDown)):{
node: Node, node: Node,
position: number, position: number,
}{ }{
@ -931,7 +948,7 @@ function getTextNodeAtPosition(root: Node, index: number):{
lastElm=node; lastElm=node;
let len:number let len:number
if(node instanceof HTMLElement){ if(node instanceof HTMLElement){
len=MarkDown.gatherBoxText(node).length; len=txtLengthFunc(node).length;
}else{ }else{
len=(node.textContent as string).length len=(node.textContent as string).length
} }

View file

@ -101,12 +101,14 @@ class Message extends SnowFlake{
if(prev) prev.generateMessage(); if(prev) prev.generateMessage();
this.generateMessage(undefined,false) this.generateMessage(undefined,false)
} }
constructor(messagejson: messagejson, owner: Channel){ constructor(messagejson: messagejson, owner: Channel,dontStore=false){
super(messagejson.id); super(messagejson.id);
this.owner = owner; this.owner = owner;
this.headers = this.owner.headers; this.headers = this.owner.headers;
this.giveData(messagejson); this.giveData(messagejson);
this.owner.messages.set(this.id, this); if(!dontStore){
this.owner.messages.set(this.id, this);
}
} }
reactionToggle(emoji: string | Emoji){ reactionToggle(emoji: string | Emoji){
let remove = false; let remove = false;
@ -184,8 +186,11 @@ class Message extends SnowFlake{
} }
if(this.div){ if(this.div){
this.generateMessage(); this.generateMessage();
return;
}
if(+this.id>+(this.channel.lastmessageid||"0")){
func();
} }
func();
} }
canDelete(){ canDelete(){
return( return(
@ -338,15 +343,16 @@ class Message extends SnowFlake{
this.generateMessage(); this.generateMessage();
} }
} }
generateMessage(premessage?: Message | undefined, ignoredblock = false){ generateMessage(premessage?: Message | undefined, ignoredblock = false,dupe:false|HTMLDivElement=false){
if(!this.div)return; const div = dupe||this.div;
if(!div)return;
const editmode=this.channel.editing===this; const editmode=this.channel.editing===this;
if(!premessage){ if(!premessage&&!dupe){
premessage = this.channel.messages.get( premessage = this.channel.messages.get(
this.channel.idToPrev.get(this.id) as string this.channel.idToPrev.get(this.id) as string
); );
} }
const div = this.div;
for(const user of this.mentions){ for(const user of this.mentions){
if(user === this.localuser.user){ if(user === this.localuser.user){
div.classList.add("mentioned"); div.classList.add("mentioned");
@ -390,14 +396,10 @@ class Message extends SnowFlake{
build.classList.add("blocked", "topMessage"); build.classList.add("blocked", "topMessage");
const span = document.createElement("span"); const span = document.createElement("span");
let count = 1; let count = 1;
let next = this.channel.messages.get( let next = this.channel.messages.get(this.channel.idToNext.get(this.id) as string);
this.channel.idToNext.get(this.id) as string
);
while(next?.author === this.author){ while(next?.author === this.author){
count++; count++;
next = this.channel.messages.get( next = this.channel.messages.get(this.channel.idToNext.get(next.id) as string);
this.channel.idToNext.get(next.id) as string
);
} }
span.textContent = I18n.getTranslation("showBlockedMessages",count+""); span.textContent = I18n.getTranslation("showBlockedMessages",count+"");
build.append(span); build.append(span);
@ -620,12 +622,14 @@ class Message extends SnowFlake{
text.append(time); text.append(time);
div.classList.add("topMessage"); div.classList.add("topMessage");
} }
const reactions = document.createElement("div"); if(!dupe){
reactions.classList.add("flexltr", "reactiondiv"); const reactions = document.createElement("div");
this.reactdiv = new WeakRef(reactions); reactions.classList.add("flexltr", "reactiondiv");
this.updateReactions(); this.reactdiv = new WeakRef(reactions);
div.append(reactions); this.updateReactions();
this.bindButtonEvent(); div.append(reactions);
this.bindButtonEvent();
}
return div; return div;
} }
bindButtonEvent(){ bindButtonEvent(){
@ -829,7 +833,10 @@ class Message extends SnowFlake{
} }
} }
} }
buildhtml(premessage?: Message | undefined): HTMLElement{ buildhtml(premessage?: Message | undefined,dupe=false): HTMLElement{
if(dupe){
return this.generateMessage(premessage,false,document.createElement("div")) as HTMLElement;
}
if(this.div){ if(this.div){
console.error(`HTML for ${this.id} already exists, aborting`); console.error(`HTML for ${this.id} already exists, aborting`);
return this.div; return this.div;

View file

@ -61,6 +61,10 @@ body {
flex-grow: 1; flex-grow: 1;
min-height: 0; min-height: 0;
} }
.channelSTitle{
margin-top:.2in;
margin-bottom:0;
}
p, h1, h2, h3, pre, form { p, h1, h2, h3, pre, form {
margin: 0; margin: 0;
} }
@ -957,6 +961,26 @@ span.instanceStatus {
display:flex; display:flex;
flex-direction: row; flex-direction: row;
} }
.searchBox:empty {
width:2in;
}
.searchBox {
white-space: nowrap;
height: .075in;
padding: 7px 10px 13px 10px;
background: var(--dock-bg);
border-radius: 4px;
/* overflow-y: auto; */
display:flex;
flex-direction: row;
width: 3in;
margin: 0 .1in;
overflow: hidden;
margin-left: auto;
flex-shrink: 0;
transition: width .2s;
}
.outerTypeBox > span::before { .outerTypeBox > span::before {
content: "\feff"; content: "\feff";
} }
@ -1385,7 +1409,21 @@ img.bigembedimg {
.acceptinvbutton:hover, .acceptinvbutton:disabled { .acceptinvbutton:hover, .acceptinvbutton:disabled {
background: color-mix(in hsl, var(--green) 80%, var(--black)); background: color-mix(in hsl, var(--green) 80%, var(--black));
} }
#sideDiv.searchDiv{
width: 30vw;
.topMessage{
margin-top:2px;
margin-bottom:10px;
cursor:pointer;
padding:.05in;
border-radius:.075in;
background:#00000020;
}
.topMessage:hover{
background:#00000050;
}
}
/* Sidebar */ /* Sidebar */
#sideDiv { #sideDiv {
display: none; display: none;
@ -1396,6 +1434,7 @@ img.bigembedimg {
overflow-y: auto; overflow-y: auto;
box-sizing: border-box; box-sizing: border-box;
} }
.memberList { .memberList {
padding-bottom: 16px; padding-bottom: 16px;
color: var(--primary-text-soft); color: var(--primary-text-soft);
@ -1416,8 +1455,9 @@ img.bigembedimg {
#memberlisttoggleicon { #memberlisttoggleicon {
display: block; display: block;
padding: 12px 0; padding: 12px 0;
margin-left: auto; margin-left: 0;
cursor: pointer; cursor: pointer;
flex-grow: 0;
} }
#memberlisttoggleicon span { #memberlisttoggleicon span {
height: 16px; height: 16px;

View file

@ -9,7 +9,6 @@ import { Role } from "./role.js";
import { Search } from "./search.js"; import { Search } from "./search.js";
import { I18n } from "./i18n.js"; import { I18n } from "./i18n.js";
import { Direct } from "./direct.js"; import { Direct } from "./direct.js";
import { Settings } from "./settings.js";
class User extends SnowFlake{ class User extends SnowFlake{
owner: Localuser; owner: Localuser;