way improved editing of messages
This commit is contained in:
parent
c1645099b8
commit
ce538b3909
8 changed files with 204 additions and 145 deletions
|
@ -791,6 +791,15 @@ class Channel extends SnowFlake{
|
||||||
return new Message(json[0], this);
|
return new Message(json[0], this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
editLast(){
|
||||||
|
let message:Message|undefined=this.lastmessage;
|
||||||
|
while(message&&message.author!==this.localuser.user){
|
||||||
|
message=this.messages.get(this.idToPrev.get(message.id) as string);
|
||||||
|
}
|
||||||
|
if(message){
|
||||||
|
message.setEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
static genid: number = 0;
|
static genid: number = 0;
|
||||||
async getHTML(){
|
async getHTML(){
|
||||||
const id = ++Channel.genid;
|
const id = ++Channel.genid;
|
||||||
|
@ -842,6 +851,7 @@ class Channel extends SnowFlake{
|
||||||
await this.buildmessages();
|
await this.buildmessages();
|
||||||
//loading.classList.remove("loading");
|
//loading.classList.remove("loading");
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).focus();
|
||||||
}
|
}
|
||||||
typingmap: Map<Member, number> = new Map();
|
typingmap: Map<Member, number> = new Map();
|
||||||
async typingStart(typing: startTypingjson): Promise<void>{
|
async typingStart(typing: startTypingjson): Promise<void>{
|
||||||
|
|
|
@ -197,6 +197,7 @@ class Group extends Channel{
|
||||||
}
|
}
|
||||||
this.buildmessages();
|
this.buildmessages();
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).focus();
|
||||||
}
|
}
|
||||||
messageCreate(messagep: { d: messagejson }){
|
messageCreate(messagep: { d: messagejson }){
|
||||||
const messagez = new Message(messagep.d, this);
|
const messagez = new Message(messagep.d, this);
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="position: relative;">
|
<div style="position: relative;">
|
||||||
<div id="searchOptions" class="flexttb"></div>
|
<div id="searchOptions" class="flexttb searchOptions"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="pasteimage" class="flexltr"></div>
|
<div id="pasteimage" class="flexltr"></div>
|
||||||
<div id="replybox" class="hideReplyBox"></div>
|
<div id="replybox" class="hideReplyBox"></div>
|
||||||
|
|
|
@ -153,36 +153,30 @@ import { I18n } from "./i18n.js";
|
||||||
if(thisUser.keyup(event)){return}
|
if(thisUser.keyup(event)){return}
|
||||||
const channel = thisUser.channelfocus;
|
const channel = thisUser.channelfocus;
|
||||||
if(!channel)return;
|
if(!channel)return;
|
||||||
|
if(markdown.rawString===""&&event.key==="ArrowUp"){
|
||||||
|
channel.editLast();
|
||||||
|
return;
|
||||||
|
}
|
||||||
channel.typingstart();
|
channel.typingstart();
|
||||||
|
|
||||||
if(event.key === "Enter" && !event.shiftKey){
|
if(event.key === "Enter" && !event.shiftKey){
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
replyingTo = thisUser.channelfocus? thisUser.channelfocus.replyingto: null;
|
||||||
if(channel.editing){
|
if(replyingTo?.div){
|
||||||
channel.editing.edit(markdown.rawString);
|
replyingTo.div.classList.remove("replying");
|
||||||
channel.editing = null;
|
}
|
||||||
}else{
|
if(thisUser.channelfocus){
|
||||||
replyingTo = thisUser.channelfocus
|
thisUser.channelfocus.replyingto = null;
|
||||||
? thisUser.channelfocus.replyingto
|
}
|
||||||
: null;
|
channel.sendMessage(markdown.rawString, {
|
||||||
if(replyingTo?.div){
|
attachments: images,
|
||||||
replyingTo.div.classList.remove("replying");
|
// @ts-ignore This is valid according to the API
|
||||||
}
|
embeds: [], // Add an empty array for the embeds property
|
||||||
if(thisUser.channelfocus){
|
replyingto: replyingTo,
|
||||||
thisUser.channelfocus.replyingto = null;
|
});
|
||||||
}
|
if(thisUser.channelfocus){
|
||||||
channel.sendMessage(markdown.rawString, {
|
thisUser.channelfocus.makereplybox();
|
||||||
attachments: images,
|
|
||||||
// @ts-ignore This is valid according to the API
|
|
||||||
embeds: [], // Add an empty array for the embeds property
|
|
||||||
replyingto: replyingTo,
|
|
||||||
});
|
|
||||||
if(thisUser.channelfocus){
|
|
||||||
thisUser.channelfocus.makereplybox();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while(images.length){
|
while(images.length){
|
||||||
images.pop();
|
images.pop();
|
||||||
pasteImageElement.removeChild(imagesHtml.pop() as HTMLElement);
|
pasteImageElement.removeChild(imagesHtml.pop() as HTMLElement);
|
||||||
|
|
|
@ -1717,34 +1717,32 @@ class Localuser{
|
||||||
Bot.InviteMaker(appId,form,this.info);
|
Bot.InviteMaker(appId,form,this.info);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
typeMd?:MarkDown;
|
|
||||||
readonly autofillregex=Object.freeze(/[@#:]([a-z0-9 ]*)$/i);
|
readonly autofillregex=Object.freeze(/[@#:]([a-z0-9 ]*)$/i);
|
||||||
mdBox(){
|
mdBox(){
|
||||||
interface CustomHTMLDivElement extends HTMLDivElement {markdown: MarkDown;}
|
interface CustomHTMLDivElement extends HTMLDivElement {markdown: MarkDown;}
|
||||||
|
|
||||||
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
|
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
|
||||||
this.typeMd=typebox.markdown;
|
const typeMd=typebox.markdown;
|
||||||
this.typeMd.owner=this;
|
typeMd.owner=this;
|
||||||
this.typeMd.onUpdate=this.search.bind(this);
|
typeMd.onUpdate=(str,pre)=>{
|
||||||
|
this.search(document.getElementById("searchOptions") as HTMLDivElement,typeMd,str,pre);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MDReplace(replacewith:string,original:string){
|
MDReplace(replacewith:string,original:string,typebox:MarkDown){
|
||||||
const typebox = document.getElementById("typebox") as HTMLDivElement;
|
let raw=typebox.rawString;
|
||||||
if(!this.typeMd)return;
|
|
||||||
let raw=this.typeMd.rawString;
|
|
||||||
raw=raw.split(original)[1];
|
raw=raw.split(original)[1];
|
||||||
if(raw===undefined) return;
|
if(raw===undefined) return;
|
||||||
raw=original.replace(this.autofillregex,"")+replacewith+raw;
|
raw=original.replace(this.autofillregex,"")+replacewith+raw;
|
||||||
console.log(raw);
|
console.log(raw);
|
||||||
console.log(replacewith);
|
console.log(replacewith);
|
||||||
console.log(original);
|
console.log(original);
|
||||||
this.typeMd.txt = raw.split("");
|
typebox.txt = raw.split("");
|
||||||
const match=original.match(this.autofillregex);
|
const match=original.match(this.autofillregex);
|
||||||
if(match){
|
if(match){
|
||||||
this.typeMd.boxupdate(typebox,replacewith.length-match[0].length);
|
typebox.boxupdate(replacewith.length-match[0].length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MDSearchOptions(options:[string,string,void|HTMLElement][],original:string){
|
MDSearchOptions(options:[string,string,void|HTMLElement][],original:string,div:HTMLDivElement,typebox:MarkDown){
|
||||||
const div=document.getElementById("searchOptions");
|
|
||||||
if(!div)return;
|
if(!div)return;
|
||||||
div.innerHTML="";
|
div.innerHTML="";
|
||||||
let i=0;
|
let i=0;
|
||||||
|
@ -1757,7 +1755,6 @@ class Localuser{
|
||||||
const span=document.createElement("span");
|
const span=document.createElement("span");
|
||||||
htmloptions.push(span);
|
htmloptions.push(span);
|
||||||
if(thing[2]){
|
if(thing[2]){
|
||||||
console.log(thing);
|
|
||||||
span.append(thing[2]);
|
span.append(thing[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1766,19 +1763,21 @@ class Localuser{
|
||||||
|
|
||||||
if(e){
|
if(e){
|
||||||
const selection = window.getSelection() as Selection;
|
const selection = window.getSelection() as Selection;
|
||||||
const typebox = document.getElementById("typebox") as HTMLDivElement;
|
const box=typebox.box.deref();
|
||||||
|
if(!box) return;
|
||||||
if(selection){
|
if(selection){
|
||||||
console.warn(original);
|
console.warn(original);
|
||||||
const pos = getTextNodeAtPosition(typebox, original.length-(original.match(this.autofillregex) as RegExpMatchArray)[0].length+thing[1].length);
|
|
||||||
|
const pos = getTextNodeAtPosition(box, original.length-(original.match(this.autofillregex) as RegExpMatchArray)[0].length+thing[1].length);
|
||||||
selection.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
const range = new Range();
|
const range = new Range();
|
||||||
range.setStart(pos.node, pos.position);
|
range.setStart(pos.node, pos.position);
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
typebox.focus();
|
box.focus();
|
||||||
}
|
}
|
||||||
this.MDReplace(thing[1],original);
|
this.MDReplace(thing[1],original,typebox);
|
||||||
div.innerHTML="";
|
div.innerHTML="";
|
||||||
remove();
|
remove();
|
||||||
}
|
}
|
||||||
|
@ -1837,7 +1836,7 @@ class Localuser{
|
||||||
remove();
|
remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MDFindChannel(name:string,orginal:string){
|
MDFindChannel(name:string,orginal:string,box:HTMLDivElement,typebox:MarkDown){
|
||||||
const maybe:[number,Channel][]=[];
|
const maybe:[number,Channel][]=[];
|
||||||
if(this.lookingguild&&this.lookingguild.id!=="@me"){
|
if(this.lookingguild&&this.lookingguild.id!=="@me"){
|
||||||
for(const channel of this.lookingguild.channels){
|
for(const channel of this.lookingguild.channels){
|
||||||
|
@ -1848,7 +1847,7 @@ class Localuser{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maybe.sort((a,b)=>b[0]-a[0]);
|
maybe.sort((a,b)=>b[0]-a[0]);
|
||||||
this.MDSearchOptions(maybe.map((a)=>["# "+a[1].name,`<#${a[1].id}> `,undefined]),orginal);
|
this.MDSearchOptions(maybe.map((a)=>["# "+a[1].name,`<#${a[1].id}> `,undefined]),orginal,box,typebox);
|
||||||
}
|
}
|
||||||
async getUser(id:string){
|
async getUser(id:string){
|
||||||
if(this.userMap.has(id)){
|
if(this.userMap.has(id)){
|
||||||
|
@ -1856,7 +1855,7 @@ class Localuser{
|
||||||
}
|
}
|
||||||
return new User(await (await fetch(this.info.api+"/users/"+id)).json(),this);
|
return new User(await (await fetch(this.info.api+"/users/"+id)).json(),this);
|
||||||
}
|
}
|
||||||
MDFineMentionGen(name:string,original:string){
|
MDFineMentionGen(name:string,original:string,box:HTMLDivElement,typebox:MarkDown){
|
||||||
let members:[Member,number][]=[];
|
let members:[Member,number][]=[];
|
||||||
if(this.lookingguild){
|
if(this.lookingguild){
|
||||||
for(const member of this.lookingguild.members){
|
for(const member of this.lookingguild.members){
|
||||||
|
@ -1867,11 +1866,11 @@ class Localuser{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
members.sort((a,b)=>b[1]-a[1]);
|
members.sort((a,b)=>b[1]-a[1]);
|
||||||
this.MDSearchOptions(members.map((a)=>["@"+a[0].name,`<@${a[0].id}> `,undefined]),original);
|
this.MDSearchOptions(members.map((a)=>["@"+a[0].name,`<@${a[0].id}> `,undefined]),original,box,typebox);
|
||||||
}
|
}
|
||||||
MDFindMention(name:string,original:string){
|
MDFindMention(name:string,original:string,box:HTMLDivElement,typebox:MarkDown){
|
||||||
if(this.ws&&this.lookingguild){
|
if(this.ws&&this.lookingguild){
|
||||||
this.MDFineMentionGen(name,original);
|
this.MDFineMentionGen(name,original,box,typebox);
|
||||||
const nonce=Math.floor(Math.random()*10**8)+"";
|
const nonce=Math.floor(Math.random()*10**8)+"";
|
||||||
if(this.lookingguild.member_count<=this.lookingguild.members.size) return;
|
if(this.lookingguild.member_count<=this.lookingguild.members.size) return;
|
||||||
this.ws.send(JSON.stringify(
|
this.ws.send(JSON.stringify(
|
||||||
|
@ -1906,19 +1905,19 @@ class Localuser{
|
||||||
await Member.new(thing,this.lookingguild as Guild)
|
await Member.new(thing,this.lookingguild as Guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.MDFineMentionGen(name,original);
|
this.MDFineMentionGen(name,original,box,typebox);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
findEmoji(search:string,orginal:string){
|
findEmoji(search:string,orginal:string,box:HTMLDivElement,typebox:MarkDown){
|
||||||
const emj=Emoji.searchEmoji(search,this,10);
|
const emj=Emoji.searchEmoji(search,this,10);
|
||||||
const map=emj.map(([emoji]):[string,string,HTMLElement]=>{
|
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()]
|
return [emoji.name,emoji.id?`<${emoji.animated?"a":""}:${emoji.name}:${emoji.id}>`:emoji.emoji as string,emoji.getHTML()]
|
||||||
})
|
})
|
||||||
this.MDSearchOptions(map,orginal);
|
this.MDSearchOptions(map,orginal,box,typebox);
|
||||||
}
|
}
|
||||||
search(str:string,pre:boolean){
|
search(box:HTMLDivElement,md:MarkDown,str:string,pre:boolean){
|
||||||
if(!pre){
|
if(!pre){
|
||||||
const match=str.match(this.autofillregex);
|
const match=str.match(this.autofillregex);
|
||||||
|
|
||||||
|
@ -1926,25 +1925,23 @@ class Localuser{
|
||||||
const [type, search]=[match[0][0],match[0].split(/@|#|:/)[1]];
|
const [type, search]=[match[0][0],match[0].split(/@|#|:/)[1]];
|
||||||
switch(type){
|
switch(type){
|
||||||
case "#":
|
case "#":
|
||||||
this.MDFindChannel(search,str);
|
this.MDFindChannel(search,str,box,md);
|
||||||
break;
|
break;
|
||||||
case "@":
|
case "@":
|
||||||
this.MDFindMention(search,str);
|
this.MDFindMention(search,str,box,md);
|
||||||
break;
|
break;
|
||||||
case ":":
|
case ":":
|
||||||
if(search.length>=2){
|
if(search.length>=2){
|
||||||
this.findEmoji(search,str)
|
this.findEmoji(search,str,box,md)
|
||||||
}else{
|
}else{
|
||||||
this.MDSearchOptions([],"");
|
this.MDSearchOptions([],"",box,md);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const div=document.getElementById("searchOptions");
|
box.innerHTML="";
|
||||||
if(!div)return;
|
|
||||||
div.innerHTML="";
|
|
||||||
}
|
}
|
||||||
keydown:(event:KeyboardEvent)=>unknown=()=>{};
|
keydown:(event:KeyboardEvent)=>unknown=()=>{};
|
||||||
keyup:(event:KeyboardEvent)=>boolean=()=>false;
|
keyup:(event:KeyboardEvent)=>boolean=()=>false;
|
||||||
|
|
|
@ -686,7 +686,9 @@ txt[j + 1] === undefined)
|
||||||
e.target.classList.add("unspoiled");
|
e.target.classList.add("unspoiled");
|
||||||
}
|
}
|
||||||
onUpdate:(upto:string,pre:boolean)=>unknown=()=>{};
|
onUpdate:(upto:string,pre:boolean)=>unknown=()=>{};
|
||||||
|
box=new WeakRef(document.createElement("div"));
|
||||||
giveBox(box: HTMLDivElement,onUpdate:(upto:string,pre:boolean)=>unknown=()=>{}){
|
giveBox(box: HTMLDivElement,onUpdate:(upto:string,pre:boolean)=>unknown=()=>{}){
|
||||||
|
this.box=new WeakRef(box);
|
||||||
this.onUpdate=onUpdate;
|
this.onUpdate=onUpdate;
|
||||||
box.onkeydown = _=>{
|
box.onkeydown = _=>{
|
||||||
//console.log(_);
|
//console.log(_);
|
||||||
|
@ -697,7 +699,7 @@ txt[j + 1] === undefined)
|
||||||
if(content !== prevcontent){
|
if(content !== prevcontent){
|
||||||
prevcontent = content;
|
prevcontent = content;
|
||||||
this.txt = content.split("");
|
this.txt = content.split("");
|
||||||
this.boxupdate(box);
|
this.boxupdate();
|
||||||
MarkDown.gatherBoxText(box);
|
MarkDown.gatherBoxText(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +715,9 @@ txt[j + 1] === undefined)
|
||||||
box.onkeyup(new KeyboardEvent("_"));
|
box.onkeyup(new KeyboardEvent("_"));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
boxupdate(box: HTMLElement,offset=0){
|
boxupdate(offset=0){
|
||||||
|
const box=this.box.deref();
|
||||||
|
if(!box) return;
|
||||||
const restore = saveCaretPosition(box,offset);
|
const restore = saveCaretPosition(box,offset);
|
||||||
box.innerHTML = "";
|
box.innerHTML = "";
|
||||||
box.append(this.makeHTML({ keep: true }));
|
box.append(this.makeHTML({ keep: true }));
|
||||||
|
@ -832,85 +836,91 @@ let formatted=false;
|
||||||
function saveCaretPosition(context: HTMLElement,offset=0){
|
function saveCaretPosition(context: HTMLElement,offset=0){
|
||||||
const selection = window.getSelection() as Selection;
|
const selection = window.getSelection() as Selection;
|
||||||
if(!selection)return;
|
if(!selection)return;
|
||||||
const range = selection.getRangeAt(0);
|
try{
|
||||||
let base=selection.anchorNode as Node;
|
const range = selection.getRangeAt(0);
|
||||||
range.setStart(base, 0);
|
|
||||||
let baseString:string;
|
let base=selection.anchorNode as Node;
|
||||||
if(!(base instanceof Text)){
|
range.setStart(base, 0);
|
||||||
let i=0;
|
let baseString:string;
|
||||||
const index=selection.focusOffset;
|
if(!(base instanceof Text)){
|
||||||
//@ts-ignore
|
let i=0;
|
||||||
for(const thing of base.childNodes){
|
const index=selection.focusOffset;
|
||||||
if(i===index){
|
//@ts-ignore
|
||||||
base=thing;
|
for(const thing of base.childNodes){
|
||||||
break;
|
if(i===index){
|
||||||
|
base=thing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(base instanceof HTMLElement){
|
||||||
|
baseString=MarkDown.gatherBoxText(base)
|
||||||
|
}else{
|
||||||
|
baseString=base.textContent as string;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if(base instanceof HTMLElement){
|
|
||||||
baseString=MarkDown.gatherBoxText(base)
|
|
||||||
}else{
|
}else{
|
||||||
baseString=base.textContent as string;
|
baseString=selection.toString();
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
baseString=selection.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
range.setStart(context, 0);
|
range.setStart(context, 0);
|
||||||
|
|
||||||
let build="";
|
let build="";
|
||||||
//I think this is working now :3
|
//I think this is working now :3
|
||||||
function crawlForText(context:Node){
|
function crawlForText(context:Node){
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
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+=MarkDown.gatherBoxText(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;
|
||||||
|
}else{
|
||||||
|
build+=context.textContent;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
build+=context.textContent;
|
console.error(context);
|
||||||
}
|
}
|
||||||
}else{
|
return;
|
||||||
console.error(context);
|
|
||||||
}
|
}
|
||||||
return;
|
for(const node of children as Node[]){
|
||||||
}
|
|
||||||
for(const node of children as Node[]){
|
|
||||||
|
|
||||||
if(selection.containsNode(node,false)){
|
if(selection.containsNode(node,false)){
|
||||||
if(node instanceof HTMLElement){
|
if(node instanceof HTMLElement){
|
||||||
build+=MarkDown.gatherBoxText(node);
|
build+=MarkDown.gatherBoxText(node);
|
||||||
|
}else{
|
||||||
|
build+=node.textContent;
|
||||||
|
}
|
||||||
|
}else if(selection.containsNode(node,true)){
|
||||||
|
if(node instanceof HTMLElement){
|
||||||
|
crawlForText(node);
|
||||||
|
}else{
|
||||||
|
console.error(node,"This shouldn't happen")
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
build+=node.textContent;
|
//console.error(node,"This shouldn't happen");
|
||||||
}
|
}
|
||||||
}else if(selection.containsNode(node,true)){
|
|
||||||
if(node instanceof HTMLElement){
|
|
||||||
crawlForText(node);
|
|
||||||
}else{
|
|
||||||
console.error(node,"This shouldn't happen")
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
console.error(node,"This shouldn't happen");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
crawlForText(context);
|
||||||
|
if(baseString==="\n"){
|
||||||
|
build+=baseString;
|
||||||
|
}
|
||||||
|
text=build;
|
||||||
|
let len=build.length+offset;
|
||||||
|
len=Math.min(len,MarkDown.gatherBoxText(context).length)
|
||||||
|
return function restore(){
|
||||||
|
if(!selection)return;
|
||||||
|
const pos = getTextNodeAtPosition(context, len);
|
||||||
|
selection.removeAllRanges();
|
||||||
|
const range = new Range();
|
||||||
|
range.setStart(pos.node, pos.position);
|
||||||
|
selection.addRange(range);
|
||||||
|
};
|
||||||
|
}catch{
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
crawlForText(context);
|
|
||||||
if(baseString==="\n"){
|
|
||||||
build+=baseString;
|
|
||||||
}
|
|
||||||
text=build;
|
|
||||||
const len=build.length+offset;
|
|
||||||
return function restore(){
|
|
||||||
if(!selection)return;
|
|
||||||
const pos = getTextNodeAtPosition(context, len);
|
|
||||||
selection.removeAllRanges();
|
|
||||||
const range = new Range();
|
|
||||||
range.setStart(pos.node, pos.position);
|
|
||||||
selection.addRange(range);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextNodeAtPosition(root: Node, index: number):{
|
function getTextNodeAtPosition(root: Node, index: number):{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import{ Contextmenu }from"./contextmenu.js";
|
import{ Contextmenu }from"./contextmenu.js";
|
||||||
import{ User }from"./user.js";
|
import{ User }from"./user.js";
|
||||||
import{ Member }from"./member.js";
|
import{ Member }from"./member.js";
|
||||||
import{ MarkDown }from"./markdown.js";
|
import{ MarkDown, saveCaretPosition }from"./markdown.js";
|
||||||
import{ Embed }from"./embed.js";
|
import{ Embed }from"./embed.js";
|
||||||
import{ Channel }from"./channel.js";
|
import{ Channel }from"./channel.js";
|
||||||
import{ Localuser }from"./localuser.js";
|
import{ Localuser }from"./localuser.js";
|
||||||
|
@ -96,14 +96,10 @@ class Message extends SnowFlake{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setEdit(){
|
setEdit(){
|
||||||
|
const prev=this.channel.editing;
|
||||||
this.channel.editing = this;
|
this.channel.editing = this;
|
||||||
const markdown = (
|
if(prev) prev.generateMessage();
|
||||||
document.getElementById("typebox") as HTMLDivElement & {
|
this.generateMessage(undefined,false)
|
||||||
markdown: MarkDown;
|
|
||||||
}
|
|
||||||
).markdown as MarkDown;
|
|
||||||
markdown.txt = this.content.rawString.split("");
|
|
||||||
markdown.boxupdate(document.getElementById("typebox") as HTMLDivElement);
|
|
||||||
}
|
}
|
||||||
constructor(messagejson: messagejson, owner: Channel){
|
constructor(messagejson: messagejson, owner: Channel){
|
||||||
super(messagejson.id);
|
super(messagejson.id);
|
||||||
|
@ -340,6 +336,7 @@ class Message extends SnowFlake{
|
||||||
}
|
}
|
||||||
generateMessage(premessage?: Message | undefined, ignoredblock = false){
|
generateMessage(premessage?: Message | undefined, ignoredblock = false){
|
||||||
if(!this.div)return;
|
if(!this.div)return;
|
||||||
|
const editmode=this.channel.editing===this;
|
||||||
if(!premessage){
|
if(!premessage){
|
||||||
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
|
||||||
|
@ -476,8 +473,7 @@ class Message extends SnowFlake{
|
||||||
const newt = new Date(this.timestamp).getTime() / 1000;
|
const newt = new Date(this.timestamp).getTime() / 1000;
|
||||||
current = newt - old > 600;
|
current = newt - old > 600;
|
||||||
}
|
}
|
||||||
const combine =
|
const combine = premessage?.author != this.author || current || this.message_reference;
|
||||||
premessage?.author != this.author || current || this.message_reference;
|
|
||||||
if(combine){
|
if(combine){
|
||||||
const pfp = this.author.buildpfp();
|
const pfp = this.author.buildpfp();
|
||||||
this.author.bind(pfp, this.guild, false);
|
this.author.bind(pfp, this.guild, false);
|
||||||
|
@ -526,13 +522,56 @@ class Message extends SnowFlake{
|
||||||
}else{
|
}else{
|
||||||
div.classList.remove("topMessage");
|
div.classList.remove("topMessage");
|
||||||
}
|
}
|
||||||
const messaged = this.content.makeHTML();
|
|
||||||
(div as any).txt = messaged;
|
|
||||||
const messagedwrap = document.createElement("div");
|
const messagedwrap = document.createElement("div");
|
||||||
messagedwrap.classList.add("flexttb");
|
if(editmode){
|
||||||
messagedwrap.appendChild(messaged);
|
const box=document.createElement("div");
|
||||||
text.appendChild(messagedwrap);
|
box.classList.add("messageEditContainer");
|
||||||
|
const area=document.createElement("div");
|
||||||
|
const sb=document.createElement("div");
|
||||||
|
sb.style.position="absolute";
|
||||||
|
sb.style.width="100%";
|
||||||
|
const search=document.createElement("div");
|
||||||
|
search.classList.add("searchOptions","flexttb");
|
||||||
|
area.classList.add("editMessage");
|
||||||
|
area.contentEditable="true";
|
||||||
|
const md=new MarkDown(this.content.rawString,this.owner)
|
||||||
|
area.append(md.makeHTML());
|
||||||
|
area.addEventListener("keyup", (event)=>{
|
||||||
|
if(this.localuser.keyup(event)) return;
|
||||||
|
if(event.key === "Enter" && !event.shiftKey){
|
||||||
|
this.edit(md.rawString);
|
||||||
|
this.channel.editing=null;
|
||||||
|
this.generateMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
area.addEventListener("keydown", event=>{
|
||||||
|
this.localuser.keydown(event);
|
||||||
|
if(event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
||||||
|
if(event.key === "Escape"){
|
||||||
|
this.channel.editing=null;
|
||||||
|
this.generateMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
md.giveBox(area,(str,pre)=>{
|
||||||
|
this.localuser.search(search,md,str,pre)
|
||||||
|
})
|
||||||
|
sb.append(search);
|
||||||
|
box.append(sb,area);
|
||||||
|
messagedwrap.append(box);
|
||||||
|
setTimeout(()=>{
|
||||||
|
area.focus();
|
||||||
|
const fun=saveCaretPosition(area,Infinity);
|
||||||
|
if(fun) fun();
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
this.content.onUpdate=()=>{};
|
||||||
|
const messaged = this.content.makeHTML();
|
||||||
|
(div as any).txt = messaged;
|
||||||
|
messagedwrap.classList.add("flexttb");
|
||||||
|
messagedwrap.appendChild(messaged);
|
||||||
|
|
||||||
|
}
|
||||||
|
text.appendChild(messagedwrap);
|
||||||
build.appendChild(text);
|
build.appendChild(text);
|
||||||
if(this.attachments.length){
|
if(this.attachments.length){
|
||||||
console.log(this.attachments);
|
console.log(this.attachments);
|
||||||
|
|
|
@ -21,7 +21,7 @@ body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#searchOptions{
|
.searchOptions{
|
||||||
padding:.05in .15in;
|
padding:.05in .15in;
|
||||||
border-radius: .1in;
|
border-radius: .1in;
|
||||||
background: var(--channels-bg);
|
background: var(--channels-bg);
|
||||||
|
@ -46,15 +46,17 @@ body {
|
||||||
span:hover{
|
span:hover{
|
||||||
background:var(--button-bg);
|
background:var(--button-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
border: solid .025in var(--black);
|
border: solid .025in var(--black);
|
||||||
}
|
}
|
||||||
#searchOptions:empty{
|
.searchOptions:empty{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
.messageEditContainer{
|
||||||
|
position: relative;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
.flexgrow {
|
.flexgrow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -268,6 +270,11 @@ textarea {
|
||||||
transition: opacity .2s;
|
transition: opacity .2s;
|
||||||
border: solid .03in var(--black);
|
border: solid .03in var(--black);
|
||||||
}
|
}
|
||||||
|
.editMessage{
|
||||||
|
background: var(--typebox-bg);
|
||||||
|
padding: .05in;
|
||||||
|
border-radius: .04in;
|
||||||
|
}
|
||||||
/* Animations */
|
/* Animations */
|
||||||
@keyframes fade {
|
@keyframes fade {
|
||||||
0%, 100% {
|
0%, 100% {
|
||||||
|
@ -1004,6 +1011,7 @@ span.instanceStatus {
|
||||||
.commentrow {
|
.commentrow {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.username {
|
.username {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue