Records all deleted messages in every opened channel and stores them so you can read it later ;)
< Feedback on Discord Watch Deleted Messages
It would seem that discord removes the same node for clicking a reply (only first time) and it is treated the same as a delete. it seems from the HTML, one can't tell the difference between a "delete" and a "clicked on reply link"
the attatched is the first one is clicking on the reply, and the second is deleting a message
seems when you click a reply, the element is removed then wrapped in a div tag to add the backgroundFlash flash. I guess you would need to check for added nodes and ensure that the node just removed wasn't added back to the dom wrapped in a backgroundFlash div tag.
This also means a message you clicked on the reply link was deleted, the script would not pick it up because a div tag would have been deleted, not a li
.
removed_node.tagName == 'LI'
might also need to check for DIV
I think i fixed it. I added || removed_node.tagName === 'DIV')
to check method to see if you are removing a div tag. then i added a check for the message ID being removed still exists, as the wrapped element contains the same message ID, and message ID's are unique.
const messageId = removed_node.id.split("-").pop();
if(document.querySelector(`#message-content-${messageId}`) !== null){
return;
}
I added that just inside the if statement:
if ((removed_node.tagName == 'LI' || removed_node.tagName === 'DIV') && !removed_node.querySelector('[class*="isSending-"]') && (removed_node.querySelector('[class^="markup-"]'))) {
here is the full method:
if ((removed_node.tagName == 'LI' || removed_node.tagName === 'DIV') && !removed_node.querySelector('[class*="isSending-"]') && (removed_node.querySelector('[class^="markup-"]'))) {
const messageId = removed_node.id.split("-").pop();
if(document.querySelector(`#message-content-${messageId}`) !== null){
return;
}
let prevCount = 0;
let prevNode = mutation.previousSibling;
let olCount = 0; // OL child elements count
if (prevNode) {
if (prevNode.parentNode.tagName == 'OL') {
olCount = prevNode.parentNode.childElementCount;
}
}
while (prevNode /* && prevNode.tagName != 'OL'*/) {
prevCount++;
prevNode = prevNode.previousSibling;
}
let prevLimit = 10;
if (olCount > prevLimit * 3 && prevCount < prevLimit) {
return; // Skip adding deleted msgs to list if the there are less than 10 elements before the beginning of OL tag. Prevents adding deleted messages when channel dels them from cache.
}
/// USERNAME IN DELETED NODE
let delmsg_usrname = ''; // Nickname of deleted msg
let delmsg_time = ''; // time of deleted msg
if (!(removed_node.querySelector('[class*="username-"]'))) {
let findNode = mutation.previousSibling;
let usrnameNode = false;
while (findNode) {
usrnameNode = findNode.querySelector('[class*="username-"]');
if (usrnameNode) {
break;
}
findNode = findNode.previousSibling;
}
if (usrnameNode) {
delmsg_usrname = usrnameNode.textContent; // Nickname of deleted msg
}
} else { // if deleted message has nickname in it
delmsg_usrname = removed_node.querySelector('[class*="username-"]').textContent;
}
if (delmsglist) {
let id_curtimestamp = 'delmsg' + Date.now();
let new_delnode = removed_node.querySelector('[id*="message-content-"]');
let delnode_imgs = removed_node.querySelector('[id*="message-accessories-"]'); //if message has images and other accessories
let msg_time_node = removed_node.querySelector('[id*="message-timestamp-"]');
let msg_time_text = msg_time_node.getAttribute('datetime');
//delmsg_time = msg_time_node.textContent;
const mregex = /^20(\d{2})-(\d{2})-(\d{2})T(.+):.+Z/i;
delmsg_time = msg_time_text.replace(mregex, '$4 $3/$2/$1');
/// ADD NEW ITEM TO DELMSGS LIST /////////////
let new_html = '<div id="' + id_curtimestamp + '" class="right-onhover-btn" style="position:absolute;">X</div> <b>' + delmsg_usrname + '</b> (' + delmsg_time + ') <br /> ' + new_delnode.innerHTML + delnode_imgs.outerHTML;// + msgs_underline;
new_delnode.innerHTML = extra_change_message(new_html);
new_delnode.classList.add("delmsgborder");
delmsglist.appendChild(new_delnode);
//delmsglist.innerHTML = delmsglist.innerHTML + msgs_underline;
let cur_elem = delmsglist.querySelector('[id*="' + id_curtimestamp + '"]');
// Set all mouse events for delete [X] button
cur_elem.onclick = delmsg_close;
delmsgs_count += 1;
CheckMessagesCount(delmsgs_count);
delmsgs_scroll.scrollTop = delmsgs_scroll.scrollHeight; // Scroll to the bottom of the list
addLocalStorageItem(new_delnode.outerHTML); // Add new deleted message to localStorage array
}
let nextSibl = mutation.nextSibling;
let new_node = removed_node;
let parent_elem = mutation.parentNode;
}
if ((removed_node.tagName == 'LI' || removed_node.tagName === 'DIV') && !removed_node.querySelector('[class*="isSending-"]') && (removed_node.querySelector('[class^="markup-"]'))) {
const messageId = removed_node.id.split("-").pop();
if(document.querySelector(`#message-content-${messageId}`) !== null){
return;
}
let prevCount = 0;
let prevNode = mutation.previousSibling;
let olCount = 0; // OL child elements count
if (prevNode) {
if (prevNode.parentNode.tagName == 'OL') {
olCount = prevNode.parentNode.childElementCount;
}
}
while (prevNode /* && prevNode.tagName != 'OL'*/) {
prevCount++;
prevNode = prevNode.previousSibling;
}
let prevLimit = 10;
if (olCount > prevLimit * 3 && prevCount < prevLimit) {
return; // Skip adding deleted msgs to list if the there are less than 10 elements before the beginning of OL tag. Prevents adding deleted messages when channel dels them from cache.
}
/// USERNAME IN DELETED NODE
let delmsg_usrname = ''; // Nickname of deleted msg
let delmsg_time = ''; // time of deleted msg
if (!(removed_node.querySelector('[class*="username-"]'))) {
let findNode = mutation.previousSibling;
let usrnameNode = false;
while (findNode) {
usrnameNode = findNode.querySelector('[class*="username-"]');
if (usrnameNode) {
break;
}
findNode = findNode.previousSibling;
}
if (usrnameNode) {
delmsg_usrname = usrnameNode.textContent; // Nickname of deleted msg
}
} else { // if deleted message has nickname in it
delmsg_usrname = removed_node.querySelector('[class*="username-"]').textContent;
}
if (delmsglist) {
let id_curtimestamp = 'delmsg' + Date.now();
let new_delnode = removed_node.querySelector('[id*="message-content-"]');
let delnode_imgs = removed_node.querySelector('[id*="message-accessories-"]'); //if message has images and other accessories
let msg_time_node = removed_node.querySelector('[id*="message-timestamp-"]');
let msg_time_text = msg_time_node.getAttribute('datetime');
//delmsg_time = msg_time_node.textContent;
const mregex = /^20(\d{2})-(\d{2})-(\d{2})T(.+):.+Z/i;
delmsg_time = msg_time_text.replace(mregex, '$4 $3/$2/$1');
/// ADD NEW ITEM TO DELMSGS LIST /////////////
let new_html = '<div id="' + id_curtimestamp + '" class="right-onhover-btn" style="position:absolute;">X</div> <b>' + delmsg_usrname + '</b> (' + delmsg_time + ') <br /> ' + new_delnode.innerHTML + delnode_imgs.outerHTML;// + msgs_underline;
new_delnode.innerHTML = extra_change_message(new_html);
new_delnode.classList.add("delmsgborder");
delmsglist.appendChild(new_delnode);
//delmsglist.innerHTML = delmsglist.innerHTML + msgs_underline;
let cur_elem = delmsglist.querySelector('[id*="' + id_curtimestamp + '"]');
// Set all mouse events for delete [X] button
cur_elem.onclick = delmsg_close;
delmsgs_count += 1;
CheckMessagesCount(delmsgs_count);
delmsgs_scroll.scrollTop = delmsgs_scroll.scrollHeight; // Scroll to the bottom of the list
addLocalStorageItem(new_delnode.outerHTML); // Add new deleted message to localStorage array
}
let nextSibl = mutation.nextSibling;
let new_node = removed_node;
let parent_elem = mutation.parentNode;
}
and this seems to fix the issue
Sorry to keep replying, but it seems deleting a message that you replied to can cause multiple issues. namely the
let new_delnode = removed_node.querySelector('[id*="message-content-"]');
if you allow div tags (because replied links messages are now div tags), then the deleted_node contains BOTH the replied message AND the deleted message, and querySelector('[id*="message-content-"]');
will only return the frist one (the replied message), so you will end up with the wrong message in the list.
to combat this, a querySelectorAll needs to be performed:
const contentElements = removed_node.querySelectorAll('[id*="message-content-"]');
let new_delnode = [...contentElements].find(el => !el.className.includes("repliedTextContent"));
this will ensure that the repliedTextContent
is filtered out.
i also had to make changes to the above change i did:
if(document.querySelector(`#message-content-${messageId}`) !== null){
return;
}
this would fail because the message of the same ID can be left over from the "are you sure you want to delete this message" modal. to fix this, you just need to check if the message is NOT inside a modal.
const messageId = removed_node.id.split("-").pop();
const messageContent = document.querySelector(`#message-content-${messageId}`);
if(messageContent){
const popup = messageContent?.closest(`[class^="focusLock"]`) ?? null;
if(!popup){
return;
}
}
now with these changes, i can confirm the following all work:
here is the full check
method, please disregard the previous message i sent:
function check(mutations) { // checks DOM mutations, fires when mouse over msg and new msg, even if scroll in somewhere up
check_channel_change();
let delmsgs_scroll = savedeletedWindow.querySelector('[id*="DELMSGS_CLASSDIV"]');
let delmsglist = savedeletedWindow.querySelector('[id*="DELMSGS_OLMSGLIST"]');
let scroll_elem = document.body.querySelector('[class*="scroller-kQBbkU"]');
mutations.forEach(function (mutation) { // iterate all mutations
mutation.removedNodes.forEach(function (removed_node) {
let check_old_msgs = document.body.querySelector('[class*="jumpToPresentBar-"]');
if (check_old_msgs) {
return; // Skips adding new deleted msgs when scrolling old messages
}
let scroll_elem = document.body.querySelector('[class*="scroller-kQBbkU"]');
if (scroll_elem && scroll_elem.scrollHeight > 7000 && scroll_elem.scrollTop) {
let diff_scroll = 1;
diff_scroll = scroll_elem.scrollHeight / scroll_elem.scrollTop;
if (diff_scroll > 1.7) {
return; // Skip adding deleted mssgs because of scroll
}
}
if ((removed_node.tagName == 'LI' || removed_node.tagName === 'DIV') && !removed_node.querySelector('[class*="isSending-"]') && (removed_node.querySelector('[class^="markup-"]'))) {
const messageId = removed_node.id.split("-").pop();
const messageContent = document.querySelector(`#message-content-${messageId}`);
if(messageContent){
const popup = messageContent?.closest(`[class^="focusLock"]`) ?? null;
if(!popup){
return;
}
}
let prevCount = 0;
let prevNode = mutation.previousSibling;
let olCount = 0; // OL child elements count
if (prevNode) {
if (prevNode.parentNode.tagName == 'OL') {
olCount = prevNode.parentNode.childElementCount;
}
}
while (prevNode /* && prevNode.tagName != 'OL'*/) {
prevCount++;
prevNode = prevNode.previousSibling;
}
let prevLimit = 10;
if (olCount > prevLimit * 3 && prevCount < prevLimit) {
return; // Skip adding deleted msgs to list if the there are less than 10 elements before the beginning of OL tag. Prevents adding deleted messages when channel dels them from cache.
}
/// USERNAME IN DELETED NODE
let delmsg_usrname = ''; // Nickname of deleted msg
let delmsg_time = ''; // time of deleted msg
if (!(removed_node.querySelector('[class*="username-"]'))) {
let findNode = mutation.previousSibling;
let usrnameNode = false;
while (findNode) {
usrnameNode = findNode.querySelector('[class*="username-"]');
if (usrnameNode) {
break;
}
findNode = findNode.previousSibling;
}
if (usrnameNode) {
delmsg_usrname = usrnameNode.textContent; // Nickname of deleted msg
}
} else { // if deleted message has nickname in it
delmsg_usrname = removed_node.querySelector('[class*="username-"]').textContent;
}
if (delmsglist) {
let id_curtimestamp = 'delmsg' + Date.now();
const contentElements = removed_node.querySelectorAll('[id*="message-content-"]');
let new_delnode = [...contentElements].find(el => !el.className.includes("repliedTextContent"));
let delnode_imgs = removed_node.querySelector('[id*="message-accessories-"]'); //if message has images and other accessories
let msg_time_node = removed_node.querySelector('[id*="message-timestamp-"]');
let msg_time_text = msg_time_node.getAttribute('datetime');
//delmsg_time = msg_time_node.textContent;
const mregex = /^20(\d{2})-(\d{2})-(\d{2})T(.+):.+Z/i;
delmsg_time = msg_time_text.replace(mregex, '$4 $3/$2/$1');
/// ADD NEW ITEM TO DELMSGS LIST /////////////
let new_html = '<div id="' + id_curtimestamp + '" class="right-onhover-btn" style="position:absolute;">X</div> <b>' + delmsg_usrname + '</b> (' + delmsg_time + ') <br /> ' + new_delnode.innerHTML + delnode_imgs.outerHTML;// + msgs_underline;
new_delnode.innerHTML = extra_change_message(new_html);
new_delnode.classList.add("delmsgborder");
delmsglist.appendChild(new_delnode);
//delmsglist.innerHTML = delmsglist.innerHTML + msgs_underline;
let cur_elem = delmsglist.querySelector('[id*="' + id_curtimestamp + '"]');
// Set all mouse events for delete [X] button
cur_elem.onclick = delmsg_close;
delmsgs_count += 1;
CheckMessagesCount(delmsgs_count);
delmsgs_scroll.scrollTop = delmsgs_scroll.scrollHeight; // Scroll to the bottom of the list
addLocalStorageItem(new_delnode.outerHTML); // Add new deleted message to localStorage array
}
let nextSibl = mutation.nextSibling;
let new_node = removed_node;
let parent_elem = mutation.parentNode;
}
});
});
}
thanks,
Victoria
oh. ONE more thing.
delmsg_usrname = removed_node.querySelector('[class*="username-"]').textContent;
needs to be replaced with
[...removed_node.querySelectorAll('[class*="username-"]')].find(el => el.closest(`[id^='message-reply-context']`) === null).textContent;
same issue as above with the message content including both the replied context AND the deleted message in it
I approved that and updated the script, thankx a lot Victoria.
There is a bug, if you click on a reply, it will appear in the deleted message.
|to reproduce:
click on a reply to a message (see image)
the replied message will appear in the deleted list