diff --git a/src/webpage/emoji.ts b/src/webpage/emoji.ts index 7380cd8..03b1d42 100644 --- a/src/webpage/emoji.ts +++ b/src/webpage/emoji.ts @@ -1,18 +1,20 @@ import{ Contextmenu }from"./contextmenu.js"; import{ Guild }from"./guild.js"; +import { emojijson } from "./jsontypes.js"; import{ Localuser }from"./localuser.js"; //I need to recompile the emoji format for translation class Emoji{ static emojis: { - name: string; - emojis: { - name: string; - emoji: string; - }[]; - }[]; + name: string; + emojis: { + name: string; + emoji: string; + }[]; + }[]; name: string; - id: string; + id?: string; + emoji?:string; animated: boolean; owner: Guild | Localuser; get guild(){ @@ -32,30 +34,34 @@ class Emoji{ return this.owner.info; } constructor( - json: { name: string; id: string; animated: boolean }, + json: emojijson, owner: Guild | Localuser ){ this.name = json.name; this.id = json.id; - this.animated = json.animated; + this.animated = json.animated||false; this.owner = owner; + this.emoji=json.emoji; } getHTML(bigemoji: boolean = false){ - const emojiElem = document.createElement("img"); - emojiElem.classList.add("md-emoji"); - emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji"); - emojiElem.crossOrigin = "anonymous"; - emojiElem.src = - this.info.cdn + - "/emojis/" + - this.id + - "." + - (this.animated ? "gif" : "png") + - "?size=32"; - - emojiElem.alt = this.name; - emojiElem.loading = "lazy"; - return emojiElem; + if(this.id){ + const emojiElem = document.createElement("img"); + emojiElem.classList.add("md-emoji"); + emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji"); + emojiElem.crossOrigin = "anonymous"; + emojiElem.src =this.info.cdn+"/emojis/"+this.id+"."+(this.animated ? "gif" : "png")+"?size=32"; + emojiElem.alt = this.name; + emojiElem.loading = "lazy"; + return emojiElem; + }else if(this.emoji){ + const emojiElem = document.createElement("span"); + emojiElem.classList.add("md-emoji"); + emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji"); + emojiElem.textContent=this.emoji; + return emojiElem; + }else{ + throw new Error("This path should *never* be gone down, this means a malformed emoji"); + } } static decodeEmojiList(buffer: ArrayBuffer){ const view = new DataView(buffer, 0); @@ -92,10 +98,10 @@ class Emoji{ for(; cats !== 0; cats--){ const name = readString16(); const emojis: { - name: string; - skin_tone_support: boolean; - emoji: string; - }[] = []; + name: string; + skin_tone_support: boolean; + emoji: string; + }[] = []; let emojinumber = read16(); for(; emojinumber !== 0; emojinumber--){ //console.log(emojis); @@ -248,6 +254,40 @@ class Emoji{ menu.append(body); return promise; } + static searchEmoji(search:string,localuser:Localuser,results=50):[Emoji,number][]{ + const ranked:[emojijson,number][]=[]; + function similar(json:emojijson){ + if(json.name.includes(search)){ + ranked.push([json,search.length/json.name.length]); + return true; + }else if(json.name.toLowerCase().includes(search.toLowerCase())){ + ranked.push([json,search.length/json.name.length/1.4]); + return true; + }else{ + return false; + } + } + for(const group of this.emojis){ + for(const emoji of group.emojis){ + similar(emoji) + } + } + const weakGuild=new WeakMap(); + for(const guild of localuser.guilds){ + if(guild.id!=="@me"&&guild.emojis.length!==0){ + for(const emoji of guild.emojis){ + if(similar(emoji)){ + weakGuild.set(emoji,guild); + }; + } + } + } + ranked.sort((a,b)=>b[1]-a[1]); + return ranked.splice(0,results).map(a=>{ + return [new Emoji(a[0],weakGuild.get(a[0])||localuser),a[1]]; + + }) + } } Emoji.grabEmoji(); export{ Emoji }; diff --git a/src/webpage/jsontypes.ts b/src/webpage/jsontypes.ts index 39114cf..d9a2d2c 100644 --- a/src/webpage/jsontypes.ts +++ b/src/webpage/jsontypes.ts @@ -166,6 +166,7 @@ type emojijson = { name: string; id?: string; animated?: boolean; + emoji?:string }; type guildjson = { diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index 9bb7a3f..36f6cc8 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -5,14 +5,15 @@ import{ AVoice }from"./audio.js"; import{ User }from"./user.js"; import{ Dialog }from"./dialog.js"; import{ getapiurls, getBulkInfo, setTheme, Specialuser, SW }from"./login.js"; -import{channeljson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,userjson,wsjson,}from"./jsontypes.js"; +import{channeljson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js"; import{ Member }from"./member.js"; import{ Form, FormError, Options, Settings }from"./settings.js"; -import{ getTextNodeAtPosition, MarkDown, saveCaretPosition }from"./markdown.js"; +import{ getTextNodeAtPosition, MarkDown }from"./markdown.js"; import { Bot } from "./bot.js"; import { Role } from "./role.js"; import { VoiceFactory } from "./voice.js"; import { I18n, langmap } from "./i18n.js"; +import { Emoji } from "./emoji.js"; const wsCodesRetry = new Set([4000,4001,4002, 4003, 4005, 4007, 4008, 4009]); @@ -1738,7 +1739,7 @@ class Localuser{ this.typeMd.txt = raw.split(""); this.typeMd.boxupdate(typebox); } - MDSearchOptions(options:[string,string][],original:string){ + MDSearchOptions(options:[string,string,void|HTMLElement][],original:string){ const div=document.getElementById("searchOptions"); if(!div)return; div.innerHTML=""; @@ -1751,7 +1752,12 @@ class Localuser{ i++; const span=document.createElement("span"); htmloptions.push(span); - span.textContent=thing[0]; + if(thing[2]){ + console.log(thing); + span.append(thing[2]); + } + + span.append(thing[0]); span.onclick=(e)=>{ if(e){ @@ -1838,7 +1844,7 @@ class Localuser{ } } maybe.sort((a,b)=>b[0]-a[0]); - this.MDSearchOptions(maybe.map((a)=>["# "+a[1].name,`<#${a[1].id}> `]),orginal); + this.MDSearchOptions(maybe.map((a)=>["# "+a[1].name,`<#${a[1].id}> `,undefined]),orginal); } async getUser(id:string){ if(this.userMap.has(id)){ @@ -1857,7 +1863,7 @@ class Localuser{ } } members.sort((a,b)=>b[1]-a[1]); - this.MDSearchOptions(members.map((a)=>["@"+a[0].name,`<@${a[0].id}> `]),original); + this.MDSearchOptions(members.map((a)=>["@"+a[0].name,`<@${a[0].id}> `,undefined]),original); } MDFindMention(name:string,original:string){ if(this.ws&&this.lookingguild){ @@ -1901,6 +1907,13 @@ class Localuser{ }) } } + findEmoji(search:string,orginal:string){ + const emj=Emoji.searchEmoji(search,this,10); + const map=emj.map(([emoji]):[string,string,HTMLElement]=>{ + return [emoji.name,emoji.id?`<${emoji.animated?"a":""}:${emoji.name}:${emoji.id}`:emoji.emoji as string,emoji.getHTML()] + }) + this.MDSearchOptions(map,orginal); + } search(str:string,pre:boolean){ if(!pre){ const match=str.match(this.autofillregex); @@ -1916,7 +1929,9 @@ class Localuser{ break; case ":": if(search.length>=2){ - console.log("implement me"); + this.findEmoji(search,str) + }else{ + this.MDSearchOptions([],""); } break; } diff --git a/src/webpage/markdown.ts b/src/webpage/markdown.ts index 1179d1e..f512fea 100644 --- a/src/webpage/markdown.ts +++ b/src/webpage/markdown.ts @@ -612,8 +612,7 @@ txt[j + 1] === undefined) appendcurrent(); i = j; const isEmojiOnly = txt.join("").trim() === buildjoin.trim(); - const owner = - this.owner instanceof Channel ? this.owner.guild : this.owner; + const owner = this.owner instanceof Channel ? this.owner.guild : this.owner; if(!owner) continue; const emoji = new Emoji( { name: buildjoin, id: parts[2], animated: Boolean(parts[1]) }, diff --git a/src/webpage/style.css b/src/webpage/style.css index 28d0fee..e18717f 100644 --- a/src/webpage/style.css +++ b/src/webpage/style.css @@ -29,13 +29,16 @@ body { bottom:0; width: calc(100% - 32px); box-sizing: border-box; - span { + > span { transition: background .1s; margin-bottom:.025in; margin-top:.025in; padding:.075in .05in; border-radius:.03in; cursor:pointer; + > span, img{ + margin-right:.05in; + } } span.selected{ background:var(--button-bg);