diff --git a/layouts/header/script.js b/layouts/header/script.js
index 440449e3..3b1e48b3 100644
--- a/layouts/header/script.js
+++ b/layouts/header/script.js
@@ -811,23 +811,46 @@ let userDataFunction = async user => {
} else {
messageElement.classList.add('message-element-self');
}
- messageElement.id = `message-${m.id}`;
- messageElement.innerHTML = `
- ${sender.id_str !== user.id_str ? `
-
- ${escapeHTML(m.message_data.text).replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '$1').replace(/(?@$1`)}
- ` : `
-
-
${escapeHTML(m.message_data.text).replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '$1').replace(/(?@$1`)}
-
-
+ messageElement.dataset.messageId = m.id;
+ messageElement.innerHTML = /*html*/`
+ ${sender.id_str !== user.id_str ? /*html*/`
+
+
+
+
${escapeHTML(m.message_data.text).replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '$1').replace(/(?@$1`)}
+
+
+
+
+ ` : /*html*/`
+
+
+
+
${escapeHTML(m.message_data.text).replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '$1').replace(/(?@$1`)}
+
+
+
+
+
+
`}
`;
let messageBlockInner = messageElement.querySelector('.message-block-inner');
let messageBlock = messageElement.querySelector('.message-block');
let menuOpen = messageBlockInner.querySelector('.message-menu-open');
+ let messageAttachments = messageElement.querySelector('.message-attachments');
+ let messageReactions = messageElement.querySelector('.message-reactions');
+
if(menuOpen) {
let menu = messageBlockInner.querySelector('.message-menu');
let menuDelete = messageBlockInner.querySelector('.message-menu-delete');
@@ -900,11 +923,7 @@ let userDataFunction = async user => {
});
e.target.click();
})
- if(span.innerHTML === '' || span.innerHTML === ' ')
- messageBlockInner.append(photoElement);
- else
- messageBlockInner.append(document.createElement('br'), photoElement);
-
+ messageAttachments.append(photoElement);
}
if(attachment.animated_gif) {
let gif = attachment.animated_gif;
@@ -917,10 +936,7 @@ let userDataFunction = async user => {
gifElement.width = w;
gifElement.height = h;
gifElement.classList.add('message-element-media');
- if(span.innerHTML === '' || span.innerHTML === ' ')
- messageBlockInner.append(gifElement);
- else
- messageBlockInner.append(document.createElement('br'), gifElement);
+ messageAttachments.append(gifElement);
}
if(attachment.video) {
let video = attachment.video;
@@ -931,10 +947,17 @@ let userDataFunction = async user => {
videoElement.width = w;
videoElement.height = h;
videoElement.classList.add('message-element-media');
- if(span.innerHTML === '' || span.innerHTML === ' ')
- messageBlockInner.append(videoElement);
- else
- messageBlockInner.append(document.createElement('br'), videoElement);
+ messageAttachments.append(videoElement);
+ }
+ }
+ if(m.message_reactions) {
+ for(let reaction of m.message_reactions) {
+ let reactionElement = document.createElement('span');
+ reactionElement.classList.add('message-reaction');
+ reactionElement.innerText = reaction.emoji_reaction;
+ reactionElement.dataset.userId = reaction.sender_id;
+ if(vars.enableTwemoji) twemoji.parse(reactionElement);
+ messageReactions.append(reactionElement);
}
}
timestamp=document.createElement('span');
@@ -1332,13 +1355,42 @@ let userDataFunction = async user => {
let messages = e.message_delete.messages;
for(let j in messages) {
let message = messages[j];
- let messageElement = document.getElementById(`message-${message.message_id}`);
+ let messageElement = document.querySelector(`div.message-element[data-message-id="${message.message_id}"]`);
if(messageElement) {
messageElement.remove();
}
}
}
});
+ for(let i in updates.user_events.entries) {
+ let e = updates.user_events.entries[i];
+ if(e.reaction_create) {
+ let reaction = e.reaction_create;
+ let messageElement = document.querySelector(`div.message-element[data-message-id="${reaction.message_id}"]`);
+ if(messageElement) {
+ let reactionElement = document.createElement('span');
+ reactionElement.classList.add('message-reaction');
+ reactionElement.innerText = reaction.emoji_reaction;
+ reactionElement.dataset.userId = reaction.sender_id;
+
+ if(vars.enableTwemoji) twemoji.parse(reactionElement);
+ let oldReaction = messageElement.querySelector(`span.message-reaction[data-user-id="${reaction.sender_id}"]`);
+ if(oldReaction) {
+ oldReaction.remove();
+ }
+ messageElement.getElementsByClassName('message-reactions')[0].append(reactionElement);
+ }
+ } else if(e.reaction_delete) {
+ let reaction = e.reaction_delete;
+ let messageElement = document.querySelector(`div.message-element[data-message-id="${reaction.message_id}"]`);
+ if(messageElement) {
+ let reactionElement = messageElement.querySelector(`span.message-reaction[data-user-id="${reaction.sender_id}"]`);
+ if(reactionElement) {
+ reactionElement.remove();
+ }
+ }
+ }
+ }
updates.user_events.entries = updates.user_events.entries.filter(m => m.message && m.message.conversation_id === lastConvo.conversation_id);
renderConversation(updates.user_events, lastConvo.conversation_id, true, false);
}
diff --git a/layouts/header/style.css b/layouts/header/style.css
index 07468182..5bf28e72 100644
--- a/layouts/header/style.css
+++ b/layouts/header/style.css
@@ -2198,6 +2198,24 @@ emoji-picker {
vertical-align: text-bottom;
margin-right: 5px;
}
+.message-reactions {
+ position: relative;
+ display: block;
+}
+.message-reactions > span {
+ margin-top: -13px;
+ display: inline-block;
+ font-size: 24px;
+ user-select: none;
+ margin-left: -15px;
+}
+.message-element-other .message-reactions > span {
+ margin-left: 0;
+}
+.message-reaction .emoji {
+ width: 24px;
+ height: 24px;
+}
.tweet-media-cws {
color: var(--cw);
font-size: 12px;
diff --git a/scripts/apis.js b/scripts/apis.js
index 30e1f05d..75d84f33 100644
--- a/scripts/apis.js
+++ b/scripts/apis.js
@@ -4083,7 +4083,7 @@ const API = {
},
getConversation: (id, max_id) => {
return new Promise((resolve, reject) => {
- fetch(`https://api.twitter.com/1.1/dm/conversation/${id}.json?ext=altText${max_id ? `&max_id=${max_id}` : ''}&count=100&cards_platform=Web-13&include_entities=1&include_user_entities=1&include_cards=1&send_error_codes=1&tweet_mode=extended&include_ext_alt_text=true&include_reply_count=true&include_conversation_info=true`, {
+ fetch(`https://twitter.com/i/api/1.1/dm/conversation/${id}.json?${max_id ? `max_id=${max_id}&` : ''}count=100&context=FETCH_DM_CONVERSATION_HISTORY&include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_has_nft_avatar=1&include_ext_is_blue_verified=1&include_ext_verified_type=1&include_ext_profile_image_shape=1&skip_status=1&dm_secret_conversations_enabled=false&krs_registration_enabled=true&cards_platform=Web-12&include_cards=1&include_ext_alt_text=true&include_ext_limited_action_results=true&include_quote_count=true&include_reply_count=1&tweet_mode=extended&include_ext_views=true&dm_users=false&include_groups=true&include_inbox_timelines=true&include_ext_media_color=true&supports_reactions=true&include_conversation_info=true&ext=mediaColor%2CaltText%2CmediaStats%2ChighlightedLabel%2ChasNftAvatar%2CvoiceInfo%2CbirdwatchPivot%2CsuperFollowMetadata%2CunmentionInfo%2CeditControl`, {
headers: {
"authorization": OLDTWITTER_CONFIG.oauth_key,
"x-csrf-token": OLDTWITTER_CONFIG.csrf,