Files
movim-rs/frontend/widgets/Chat/chat.js
T
2026-10-24 14:03:52 +07:00

1863 lines
63 KiB
JavaScript

var Chat = {
left: null,
right: null,
date: null,
separator: null,
edit: false,
// Scroll
lastHeight: null,
lastScroll: null,
// Intersection discussion observer
discussionObserver: null,
// Chat state
composing: false,
since: null,
sent: false,
// Timer
typingTimer: null,
// Autocomplete vars.
autocompleteList: null,
lastAutocomplete: null,
searchAutocomplete: null,
// Touch
delay: 20,
clientWidth: null,
startX: 0,
startY: 0,
translateX: 0,
translateY: 0,
slideAuthorized: false,
messageStartX: 0,
messageStartY: 0,
messageTranslateX: 0,
messageTranslateY: 0,
messageSlideAuthorized: false,
// Temporary messages, for OMEMO local messages
tempMessages: {},
// Last sent id, to clear the chatbox if the message is coming back by the websocket
lastSentUUID: null,
// Local list of the room members, used to encrypt the messages
groupChatMembers: [],
// Jingle types
jingleTypes: ['jingle_incoming', 'jingle_outgoing', 'jingle_end'],
// Keep track of replaced messages hash when loading history or refreshing
replacedHash: [],
init: function (date, separator, config) {
var div = document.createElement('div');
Chat.clientWidth = Math.abs(document.body.clientWidth);
div.innerHTML = date;
Chat.date = div.firstChild.cloneNode(true);
div.innerHTML = separator;
Chat.separator = div.firstChild.cloneNode(true);
Chat.pagination = config['pagination'];
Chat.delivery_error = config['delivery_error'];
Chat.action_impossible_encrypted_error = config['action_impossible_encrypted_error'];
},
autocomplete: function (event, jid) {
RoomsUtils_ajaxMucUsersAutocomplete(jid);
},
onAutocomplete: function (usersList) {
Chat.autocompleteList = usersList;
usersList = Object.values(usersList);
var textarea = Chat.getTextarea();
var words = textarea.value.toLowerCase().trim().split(' ');
var last = words[words.length - 1].trim();
if (last == '') {
// Space or nothing, so we put the first one in the list
textarea.value += usersList[0] + ' ';
Chat.lastAutocomplete = usersList[0];
Chat.searchAutocomplete = null;
} else if (typeof Chat.lastAutocomplete === 'string'
&& Chat.lastAutocomplete.toLowerCase() == last
&& Chat.searchAutocomplete == null) {
var index = (usersList.indexOf(Chat.lastAutocomplete) == usersList.length - 1)
? -1
: usersList.indexOf(Chat.lastAutocomplete);
if (textarea.value.slice(-1) == ' ') textarea.value = textarea.value.trim() + ' ';
// Full complete, so we iterate
Chat.lastAutocomplete = usersList[index + 1];
textarea.value = textarea.value.slice(0, -last.length - 1) + Chat.lastAutocomplete + ' ';
Chat.searchAutocomplete = null;
} else {
// Searching for nicknames starting with
if (Chat.lastAutocomplete == null
|| last != Chat.lastAutocomplete.toLowerCase()) {
Chat.searchAutocomplete = last;
Chat.lastAutocomplete = null;
}
var start = (typeof Chat.lastAutocomplete === 'string')
? usersList.indexOf(Chat.lastAutocomplete) + 1
: start = 0;
var end = false;
for (var i = start; i < usersList.length; i++) {
if (Chat.searchAutocomplete == usersList[i].substring(0, Chat.searchAutocomplete.length).toLowerCase()) {
textarea.value = textarea.value.trim().slice(0, -last.length) + usersList[i] + ' ';
Chat.lastAutocomplete = usersList[i];
end = true;
break;
}
}
if (end == false) {
var found = usersList.find((user) => Chat.searchAutocomplete == user.substring(0, Chat.searchAutocomplete.length).toLowerCase());
if (found) {
textarea.value = textarea.value.trim().slice(0, -last.length) + found + ' ';
Chat.lastAutocomplete = found;
}
}
}
},
quoteMUC: function (nickname, add) {
var textarea = Chat.getTextarea();
if (add) {
if (textarea.value.search(nickname) === -1) {
textarea.value = nickname + ' ' + textarea.value;
}
} else {
textarea.value = nickname + ' ';
}
textarea.focus();
},
insertAtCursor: function (textToInsert) {
textarea = Chat.getTextarea();
const value = textarea.value;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
textarea.value = value.slice(0, start) + textToInsert + value.slice(end);
textarea.selectionStart = textarea.selectionEnd = start + textToInsert.length;
textarea.focus();
Chat.toggleAction();
},
get: function (jid, light) {
if (MovimUtils.urlParts().page == 'chat') {
if (jid != undefined) {
MovimTpl.showPanel();
document.querySelector('#chat_widget').innerHTML = '';
Chats.setActive(jid);
} else {
Chats.clearAllActives();
MovimUtils.clearAllActivesRooms();
}
Chat_ajaxGet(jid, light);
} else if (MovimUtils.urlParts().page == 'space') {
if (MovimUtils.isMobile()) {
Chat_ajaxGet();
} else {
MovimTpl.hidePanel();
}
}
},
getPresences: function (room) {
if (!MovimUtils.isMobile()) {
Chat_ajaxHttpGetPresences(room);
}
},
getRoom: function (jid) {
MovimTpl.showPanel();
document.querySelector('#chat_widget').innerHTML = '';
MovimUtils.setActiveRoom(jid);
Chat_ajaxGetRoom(jid);
},
getHistory: function (tryMam) {
var textarea = Chat.getTextarea();
let firstMessage = Chat.getDiscussion()?.querySelector('.message');
if (textarea) {
Chat_ajaxGetHistory(
textarea.dataset.jid,
firstMessage ? firstMessage.dataset.published : null,
Boolean(textarea.dataset.muc),
true,
tryMam);
}
},
sendMessage: function () {
var textarea = Chat.getTextarea();
var text = textarea.value;
var isMuc = Boolean(textarea.dataset.muc);
var mucReceipts = false;
var jid = textarea.dataset.jid;
if (isMuc) {
var counter = document.querySelector('#chat_widget header span.counter');
mucReceipts = (counter && counter.dataset.mucreceipts == 'true');
}
Chat.removeSeparator();
Chat.scrollTotally();
document.querySelector('#embed').innerHTML = '';
// In case it was in edit mode
textarea.parentNode.parentNode.parentNode.classList.remove('edit');
textarea.focus();
if (!Chat.sent) {
Chat.enableSending();
if (Chat.edit) {
Chat.edit = false;
if (text == '') {
Chat.disableSending();
} else {
let correct = Chat_ajaxHttpDaemonCorrect(jid, textarea.dataset.mid, text);
correct.then(e => {
Chat.sentMessage();
}).catch(e => {
Chat.failedMessage(text);
});
}
delete textarea.dataset.mid;
} else {
var reply = document.querySelector('#reply > div');
replyMid = false;
if (reply) {
replyMid = reply.dataset.mid;
Chat_ajaxClearReply();
};
if (Chat.getOmemoState() == 'build') {
var store = new ChatOmemoStorage();
store.getLocalRegistrationId().then(deviceId => {
if (deviceId) {
if (isMuc) {
Chat.checkOMEMOState(jid, isMuc);
} else {
ChatOmemo_ajaxGetDevicesList(jid);
}
} else {
Chat.disableSending();
ChatOmemo.refreshBundle(store.getOwnSessionsIds());
}
});
} else if (Chat.getOmemoState() == 'yes') {
if (!text) {
Chat.disableSending();
return;
}
// Try to encrypt the message
let omemo = ChatOmemo.encrypt(jid, text, isMuc);
if (omemo) {
// TODO, disable the other risky features
omemo.then(omemoheader => {
Chat.lastSentUUID = id = omemoheader.id = crypto.randomUUID();
Chat.tempMessages[id] = text;
let request = Chat_ajaxHttpDaemonSendMessage(id, jid, null, isMuc, null, replyMid, mucReceipts, omemoheader);
request.then(e => {
Chat.sentMessage();
}).catch(e => {
Chat.failedMessage();
});
});
}
} else {
Chat.lastSentUUID = id = crypto.randomUUID();
let request = Chat_ajaxHttpDaemonSendMessage(id, jid, text, isMuc, null, replyMid, mucReceipts);
request.then(response => {
response.ok ? Chat.sentMessage() : Chat.failedMessage(text);
}).catch(e => {
Chat.failedMessage(text);
});
}
}
}
},
sentId: function (id) {
if (Chat.tempMessages[id]) {
ChatOmemoDB.putMessage(id, Chat.tempMessages[id]);
delete Chat.tempMessages[id];
}
},
setGroupChatMembers: function (members) {
Chat.groupChatMembers = members;
},
checkOMEMOState: function (jid, muc) {
var store = new ChatOmemoStorage();
let build = muc
? Chat.groupChatMembers.some(
member => !store.isJidResolved(member)
)
: !store.isJidResolved(jid);
ChatOmemo.getContactState(jid).then(enabled => {
let state = 'no';
if (enabled) {
state = build
? 'build'
: 'yes';
} else {
state = 'disabled';
}
Chat.setOmemoState(state);
});
},
setOmemoState: function (state) {
let textarea = Chat.getTextarea();
if (textarea) {
textarea.dataset.encryptedstate = state;
}
},
getOmemoState: function () {
let textarea = Chat.getTextarea();
if (textarea) {
return textarea.dataset.encryptedstate;
}
},
enableSending: function () {
Chat.sent = true;
var send = document.querySelector('.chat_box');
if (send) {
send.classList.add('sending');
send.classList.remove('finished');
}
},
disableSending: function () {
Chat.sent = false;
var send = document.querySelector('.chat_box');
if (send) {
send.classList.remove('sending');
}
},
finishedSending: function () {
Chat.sent = false;
var send = document.querySelector('.chat_box');
if (send) send.classList.add('finished');
},
sentMessage: function () {
Chat.disableSending();
var textarea = Chat.getTextarea();
localStorage.removeItem(textarea.dataset.jid + '_message');
Chat.clearReplace();
Chat.toggleAction();
Chat.lastSentUUID = null;
},
failedMessage: function (text) {
// Race condition if the Ajax request failed but the message was still handled
if (Chat.lastSentUUID == null) return;
Toast.send(Chat.delivery_error);
Chat.disableSending();
Chat.lastSentUUID = null;
// We try to put back the text in place
var textarea = Chat.getTextarea();
if (textarea.value == '') {
textarea.value = text;
}
},
clearReplace: function () {
Chat.edit = false;
var textarea = Chat.getTextarea();
textarea.value = localStorage.getItem(textarea.dataset.jid + '_message');
},
editPrevious: function () {
var textarea = Chat.getTextarea();
if (textarea.value != '') {
return;
}
if (!Chat.isEncrypted()) {
Chat_ajaxLast(textarea.dataset.jid, Boolean(textarea.dataset.muc));
} else {
Toast.send(Chat.action_impossible_encrypted_error);
}
},
resolveMessage: function (mid) {
ChatActions_ajaxResolveMessage(mid);
},
refreshMessage: function (mid) {
Chat_ajaxRefreshMessage(mid);
},
focus: function () {
Chat.sent = false;
Chat.composing = false;
Chat.clearReplace();
Chat.toggleAction();
var textarea = Chat.getTextarea();
textarea.onkeydown = function (event) {
if ((event.key == 'ArrowLeft' && Chat.tryPreviousEmoji())
|| (event.key == 'ArrowRight' && Chat.tryNextEmoji())) {
event.preventDefault();
return;
}
if (this.dataset.muc
&& textarea.value.length > 0
&& event.key == 'Tab') {
event.preventDefault();
if (Chat.autocompleteList == null) {
Chat.autocomplete(event, this.dataset.jid);
} else {
Chat.onAutocomplete(Chat.autocompleteList);
}
return;
}
if (event.key == 'ArrowUp' && !Chat.isEncrypted()) {
Chat.editPrevious();
} else if (event.key == 'Escape'
&& (this.value == '' || Chat.edit == true)) {
localStorage.removeItem(textarea.dataset.jid + '_message');
textarea.parentNode.parentNode.parentNode.classList.remove('edit');
Chat.clearReplace();
}
};
textarea.onkeypress = function (event) {
if (event.key == 'Enter') {
// An emoji was selected
var emoji = document.querySelector('.chat_box .emojis img.selected');
if (emoji) {
Chat.selectEmoji(emoji);
event.preventDefault();
return;
}
if ((MovimEvents.isTouch && !event.shiftKey)
|| (!MovimEvents.isTouch && event.shiftKey)) {
return;
}
Chat.composing = false;
Chat.sendMessage();
return false;
} else if (Chat.composing === false) {
Chat.composing = true;
Chat_ajaxSendComposing(this.dataset.jid, Boolean(this.dataset.muc));
Chat.since = new Date().getTime();
}
};
textarea.oninput = function () {
localStorage.setItem(this.dataset.jid + '_message', this.value);
// A little timeout to not spam the server with composing states
setTimeout(function () {
if (Chat.since + 3000 < new Date().getTime()) {
Chat.composing = false;
}
}, 3000);
if (Chat.typingTimer != null) clearTimeout(Chat.typingTimer);
if (this.value) {
if (Chat.lastResolvedUrl != this.value) Chat.lastResolvedUrl = null;
Chat.typingTimer = setTimeout(e => Chat.checkResolveUrl(this.value), 1000);
}
Chat.checkEmojis(this.value);
Chat.scrollRestore();
Chat.toggleAction();
document.querySelector('#embed').innerHTML = '';
}
textarea.addEventListener('paste', function (e) {
clearTimeout(Chat.typingTimer);
let clipboardData = e.clipboardData || window.clipboardData;
let pastedData = clipboardData.getData('Text');
Chat.checkResolveUrl(pastedData);
Chat.toggleAction();
});
if (document.documentElement.clientWidth > 1024) {
textarea.focus();
}
Chat.autocompleteList = null;
},
checkResolveUrl(content) {
let url;
try {
url = new URL(content);
} catch (_) {
return false;
}
if ((url.protocol === "http:" || url.protocol === "https:")
&& !Chat.isEncrypted()
&& !content.includes(' ')
&& Chat.lastResolvedUrl != content) {
Chat.enableSending();
ChatActions_ajaxResolveUrl(content);
Chat.lastResolvedUrl = content;
}
},
checkEmojis: function (value, reaction, noColon) {
value = value.toLowerCase();
listSelector = reaction
? '.emojis_grid.results'
: '.chat_box .emojis';
var emojisList = document.querySelector(listSelector);
emojisList.innerHTML = '';
if (!value) return;
if (noColon || value.lastIndexOf(':') > -1 && value.length > value.lastIndexOf(':') + 2) {
var first = true;
Object.keys(window.favoriteEmojis)
.filter(key => key.includes(value.substring(value.lastIndexOf(':') + 1)) && !key.includes('type'))
.slice(0, 20)
.forEach(found => {
var img = document.createElement('img');
img.setAttribute('src', favoriteEmojis[found]);
img.classList.add('emoji');
if (reaction) img.classList.add('large');
if (first) {
img.classList.add('selected');
first = false;
}
img.title = ':' + found + ':';
img.dataset.emoji = ':' + found + ':';
if (!reaction) {
img.addEventListener('click', e => {
Chat.selectEmoji(e.target);
});
}
emojisList.appendChild(img);
});
Object.keys(window.emojis)
.filter(key => key.includes(value.substring(value.lastIndexOf(':') + 1)) && !key.includes('type'))
.slice(0, 30)
.forEach(found => {
var img = document.createElement('img');
img.setAttribute('src', BASE_URI + '/theme/img/emojis/svg/' + emojis[found].c + '.svg');
img.classList.add('emoji');
if (reaction) img.classList.add('large');
if (first) {
img.classList.add('selected');
first = false;
}
img.title = ':' + found + ':';
img.dataset.emoji = emojis[found].e;
if (!reaction) {
img.addEventListener('click', e => {
Chat.selectEmoji(e.target);
});
}
emojisList.appendChild(img);
});
}
},
selectEmoji: function (emoji) {
var emojisList = document.querySelector('.chat_box .emojis');
var textarea = Chat.getTextarea();
textarea.value = textarea.value.substring(0, textarea.value.lastIndexOf(':'));
emojisList.innerHTML = '';
Chat.insertAtCursor(emoji.dataset.emoji + ' ');
},
tryNextEmoji: function () {
var currentEmoji = document.querySelector('.chat_box .emojis img.selected');
if (currentEmoji) {
currentEmoji.classList.remove('selected');
if (currentEmoji.nextSibling) {
currentEmoji.nextSibling.classList.add('selected');
} else {
document.querySelector('.chat_box .emojis img:first-child').classList.add('selected');
}
return true;
}
return false;
},
tryPreviousEmoji: function () {
var currentEmoji = document.querySelector('.chat_box .emojis img.selected');
if (currentEmoji) {
currentEmoji.classList.remove('selected');
if (currentEmoji.previousSibling) {
currentEmoji.previousSibling.classList.add('selected');
} else {
document.querySelector('.chat_box .emojis img:last-child').classList.add('selected');
}
return true;
}
return false;
},
setTextarea: function (value, mid) {
Chat.edit = true;
var textarea = Chat.getTextarea();
textarea.value = value;
textarea.parentNode.parentNode.parentNode.classList.add('edit');
if (mid) {
textarea.dataset.mid = mid;
}
textarea.focus();
},
setConfig(pagination, delivery_error, action_impossible_encrypted_error) {
Chat.pagination = pagination;
Chat.delivery_error = delivery_error;
Chat.action_impossible_encrypted_error = action_impossible_encrypted_error;
},
setSpecificElements: function (left, right) {
var div = document.createElement('div');
div.innerHTML = left;
Chat.left = div.firstChild.cloneNode(true);
div.innerHTML = right;
Chat.right = div.firstChild.cloneNode(true);
},
setScrollBehaviour: function () {
var discussion = Chat.getDiscussion();
if (!discussion) return;
discussion.onscroll = function () {
// Don't get more history the conversation is already empty
if (discussion.querySelector('.conversation').innerHTML != '' && this.scrollTop < 10) {
Chat.getHistory(true);
}
Chat.setScroll();
};
Chat.setScroll();
},
setScroll: function () {
var discussion = Chat.getDiscussion();
if (!discussion) return;
Chat.lastHeight = discussion.scrollHeight;
Chat.lastScroll = discussion.scrollTop + discussion.clientHeight;
var button = document.querySelector('#chat_widget #scroll_down.button.action');
if (Chat.isScrolled()) {
button.classList.remove('show');
} else {
button.classList.add('show');
}
},
isScrolled: function () {
return Chat.lastHeight - 5 <= Chat.lastScroll;
},
scrollRestore: function () {
var discussion = Chat.getDiscussion();
if (!discussion) return;
if (Chat.isScrolled()) {
Chat.scrollTotally();
} else {
discussion.scrollTop = Chat.lastScroll - discussion.clientHeight;
}
},
scrollTotally: function () {
var discussion = Chat.getDiscussion();
if (!discussion) return;
discussion.scrollTop = discussion.scrollHeight;
},
setObservers: function () {
var options = {
root: Chat.getDiscussion(),
rootMargin: '0px',
threshold: 1.0
};
Chat.discussionObserver = new IntersectionObserver((entries) => {
entries.forEach((entrie) => {
if (entrie.target.classList.contains('gif') && entrie.isIntersecting == true) {
entrie.target.play();
} else {
entrie.target.pause();
}
});
}, options);
},
scrollToSeparator: function () {
var discussion = Chat.getDiscussion();
if (!discussion) return;
var separator = discussion.querySelector('.separator');
if (separator) {
discussion.scrollTop = separator.offsetTop - 65;
Chat.setScroll();
}
},
removeSeparator: function () {
var separator = Chat.getDiscussion().querySelector('li.separator');
if (separator) separator.remove();
},
setReactionButtonBehaviour: function () {
let reactions = document.querySelectorAll('#chat_widget span.reaction');
let i = 0;
while (i < reactions.length) {
reactions[i].onclick = function (e) {
e.stopPropagation();
Stickers_ajaxReaction(this.dataset.mid);
}
i++;
}
},
setParentScrollBehaviour: function () {
let toParents = document.querySelectorAll('#chat_widget div.parent');
let i = 0;
while (i < toParents.length) {
toParents[i].onclick = function (e) {
var parentMsg = document.getElementById('id' + this.dataset.parentId);
if (!parentMsg) {
parentMsg = document.getElementById('id' + this.dataset.parentReplaceId)
}
if (parentMsg) {
Chat.scrollAndBlinkMessage(parentMsg)
}
}
i++;
}
},
scrollAndBlinkMessage: function (msg) {
scrollToLi = msg.parentNode.parentNode;
msg.parentNode.classList.add('scroll_blink');
setTimeout(() => {
msg.parentNode.classList.remove('scroll_blink');
}, 1000);
document.querySelector('#chat_widget .contained').scrollTo({
top: scrollToLi.offsetTop - 160,
left: 0
});
},
scrollAndBlinkMessageMid: function (mid) {
setTimeout(() => {
Chat.scrollAndBlinkMessage(document.querySelector('div[data-mid="' + mid + '"'));
}, 500)
},
setVideoObserverBehaviour: function () {
document.querySelectorAll('.file video').forEach(video => {
Chat.discussionObserver.observe(video);
});
},
setAudioPlayersBehaviour: function () {
document.querySelectorAll('.audio_player').forEach((audioPlayer, index, audioPlayers) => {
var audio = audioPlayer.querySelector('audio');
var buttonPlayPause = audioPlayer.querySelector('span.play_pause');
var progressBar = audioPlayer.querySelector('input[type=range]');
var timer = audioPlayer.querySelector('p.timer');
let mouseDownOnSlider = false;
audio.onloadeddata = function () {
progressBar.value = 0;
timer.innerHTML = MovimUtils.cleanTime(audio.currentTime) + ' / ' + MovimUtils.cleanTime(0);
}
audio.ontimeupdate = function () {
if (!mouseDownOnSlider) {
progressBar.value = audio.currentTime / audio.duration * 100;
timer.innerHTML = MovimUtils.cleanTime(audio.currentTime)
+ ' / '
+ MovimUtils.cleanTime(Number.isFinite(audio.duration) ? audio.duration : 0);
}
}
audio.onplay = function () {
buttonPlayPause.querySelector('i').innerHTML = 'pause';
};
audio.onpause = function () {
buttonPlayPause.querySelector('i').innerHTML = 'play_arrow';
};
audio.onended = function () {
var maybeNext = audioPlayers[index + 1];
if (maybeNext) {
maybeNext.querySelector('audio').play();
}
}
progressBar.onchange = function () {
const pct = progressBar.value / 100;
audio.currentTime = (audio.duration || 0) * pct;
}
progressBar.onmousedown = function () {
mouseDownOnSlider = true;
}
progressBar.onmouseup = function () {
mouseDownOnSlider = false;
}
buttonPlayPause.onclick = function () {
if (audio.paused) {
document.querySelectorAll('.audio_player:not(#' + audioPlayer.id + ') audio').forEach(otherAudio => otherAudio.pause());
audio.play();
} else {
audio.pause();
}
};
});
},
setActionsButtonBehaviour: function () {
document.querySelectorAll('#chat_widget .contained span.reply').forEach(reply =>
reply.onclick = function (e) {
e.stopPropagation();
Chat_ajaxHttpDaemonReply(this.dataset.mid);
}
);
},
setMessagePressBehaviour: function () {
document.querySelectorAll('#chat_widget li div.bubble:not(.file) > div.message').forEach(message => {
message.onmousedown = function (e) {
setTimeout(() => {
if (e.button == 0
&& (e.target.classList.contains('message')
|| e.target.parentElement.classList.contains('message')) && !(window.getSelection().toString() != ''
)
&& this.dataset.mid
&& e.target.tagName.toLowerCase() != 'span') {
ChatActions_ajaxShowMessageDialog(this.dataset.mid);
}
}, 200);
}
});
document.querySelectorAll('#chat_widget li div.bubble.file > div.message').forEach(message => {
if (card = message.querySelector('ul.list.card > li:not(.ticket) > div')) {
card.onclick = function (e) {
ChatActions_ajaxShowMessageDialog(message.dataset.mid);
};
}
});
},
setMessageSwipeBehaviour: function () {
if (MovimUtils.isMobile()) {
document.querySelectorAll('#chat_widget li div.bubble:not(.file) > div.message').forEach(message => {
message.ontouchstart = function (event) {
Chat.messageStartX = event.targetTouches[0].pageX;
Chat.messageStartY = event.targetTouches[0].pageY;
};
message.ontouchmove = function (event) {
Chat.messageTranslateX = parseInt(event.targetTouches[0].pageX - Chat.messageStartX);
Chat.messageTranslateY = parseInt(event.targetTouches[0].pageY - Chat.messageStartY);
if (Math.abs(Chat.messageTranslateX) > Chat.delay && Math.abs(Chat.messageTranslateX) <= Chat.clientWidth) {
if (Math.abs(Chat.messageTranslateY) < Chat.delay) {
Chat.messageSlideAuthorized = true;
}
if (Chat.messageTranslateX < -100) {
message.classList.add('reply');
} else {
message.classList.remove('reply');
}
if (Chat.messageSlideAuthorized && Chat.messageTranslateX < 0 && Chat.messageTranslateX > -110) {
message.parentNode.style.transform = 'translateX(' + (Chat.messageTranslateX + Chat.delay) + 'px)';
}
} else {
message.parentNode.style.transform = '';
message.classList.remove('reply');
}
};
message.ontouchend = function (event) {
if (Math.abs(Chat.messageTranslateX) > 100 && Chat.messageSlideAuthorized) {
Chat_ajaxHttpDaemonReply(message.dataset.mid);
}
message.classList.remove('reply');
message.parentNode.style.transform = '';
Chat.messageSlideAuthorized = false;
Chat.messageStartX = Chat.messageStartY = Chat.messageTranslateX = Chat.messageTranslateY = 0;
};
});
}
},
checkDiscussion: function (page) {
for (var firstKey in page) break;
if (page[firstKey] == null) return false;
for (var firstMessageKey in page[firstKey]) break;
var firstMessage = page[firstKey][firstMessageKey];
if (firstMessage == null) return false;
var contactJid = firstMessage.user_id == firstMessage.jidfrom
? firstMessage.jidto
: firstMessage.jidfrom;
if (document.getElementById(MovimUtils.cleanupId(contactJid) + '-discussion')
== null) return false;
return true;
},
appendMessagesWrapper: async function (page, prepend) {
var discussion = Chat.getDiscussion();
if (page && Chat.checkDiscussion(page)) {
if (discussion == null) return;
discussion.querySelector('.placeholder.empty').classList.remove('show');
Chat.setScroll();
// Get all the messages keys
var ids = [];
Object.values(page).forEach(pageByDate => {
Object.values(pageByDate).map(message => {
if (message.omemoheader) ids.push(message.id)
});
});
// Try to preload the OMEMO messages from the cache
if (ids.length > 2 && OMEMO_ENABLED) {
await ChatOmemoDB.loadMessagesByIds(ids);
}
for (date in page) {
let messageDateTime = page[date][Object.keys(page[date])[0]].published;
let firstMessage = Chat.getDiscussion()?.querySelector('.message')
/**
* We might have old messages reacted pushed by the server
*/
if (firstMessage
&& (new Date(messageDateTime) < (new Date(firstMessage.dataset.published)))
&& !prepend) {
return;
}
if (prepend === undefined || prepend === false) {
Chat.appendDate(date, prepend);
}
for (speakertime in page[date]) {
Chat.appendMessage(speakertime, page[date][speakertime], prepend);
}
if (prepend && date) {
Chat.appendDate(date, prepend);
}
}
if (prepend) {
// And we scroll where we were
var scrollDiff = discussion.scrollHeight - Chat.lastHeight;
discussion.scrollTop += scrollDiff;
Chat.setScroll();
} else {
Chat.scrollRestore();
}
var chat = document.querySelector('#chat_widget');
var lastMessage = chat.querySelector('ul li:not(.oppose):last-child div.bubble > div:last-child');
var textarea = Chat.getTextarea();
if (textarea && lastMessage) {
Chat_ajaxDisplayed(
textarea.dataset.jid,
lastMessage.id.substring(2) // 'id' is appended to the id
);
}
} else if (discussion !== null) {
if (discussion.querySelector('ul').innerHTML === '') {
discussion.querySelector('ul').classList.remove('spin');
discussion.querySelector('.placeholder.empty').classList.add('show');
}
}
if (discussion !== null) {
if (discussion.querySelectorAll('ul li:not(.oppose)').length > 0 && discussion.querySelectorAll('ul li.oppose').length == 0
&& discussion.querySelectorAll('ul li').length < 5) {
discussion.querySelector('.placeholder.first_messages').classList.add('show');
} else {
discussion.querySelector('.placeholder.first_messages').classList.remove('show');
}
}
Chat.setScrollBehaviour();
Chat.setReactionButtonBehaviour();
Chat.setActionsButtonBehaviour();
Chat.setParentScrollBehaviour();
Chat.setVideoObserverBehaviour();
Chat.setAudioPlayersBehaviour();
Chat.setMessagePressBehaviour();
Chat.setMessageSwipeBehaviour();
},
appendMessage: function (idjidtime, data, prepend) {
if (data.body === null) return;
// Sent message where the Ajax request somehow but the message was still handled by the server
if (data.id == Chat.lastSentUUID) {
Chat.sentMessage();
}
var bubble = null,
mergeMsg = false,
msgStack,
refBubble;
var textarea = Chat.getTextarea();
var isMuc = Boolean(textarea.dataset.muc);
var jidtime = idjidtime.substring(idjidtime.indexOf('<') + 1);
if (prepend) {
refBubble = document.querySelector('#chat_widget .contained section > ul > li:first-child');
msgStack = document.querySelector("[data-bubble='" + jidtime + "']");
} else {
refBubble = document.querySelector("#chat_widget .contained section > ul > li:last-child");
var stack = document.querySelectorAll("[data-bubble='" + jidtime + "']");
msgStack = stack[stack.length - 1];
}
if (msgStack != null
&& msgStack.parentNode == refBubble
&& data.url === false
&& (data.file === undefined || data.file === null)
&& (data.sticker === undefined || data.sticker === null)
&& !refBubble.querySelector('div.bubble').classList.contains('sticker')
&& !refBubble.querySelector('div.bubble').classList.contains('file')
&& Chat.jingleTypes.indexOf(data.type) < 0
) {
bubble = msgStack.parentNode;
mergeMsg = true;
} else {
if (data.user_id == data.jidfrom || data.mine) {
bubble = Chat.right.cloneNode(true);
id = (data.mine)
? data.jidfrom
: data.jidto;
} else {
bubble = Chat.left.cloneNode(true);
id = data.jidfrom;
}
id = MovimUtils.cleanupId(id) + '-conversation';
bubble.querySelector('div.bubble').dataset.bubble = jidtime;
bubble.querySelector('div.bubble').dataset.publishedprepared = data.publishedPrepared;
}
if (isMuc) {
bubble.dataset.resource = data.resource;
}
if (refBubble && refBubble.dataset.resource == bubble.dataset.resource
&& mergeMsg == false
&& isMuc) {
if (prepend) {
refBubble.classList.add('sequel');
} else {
bubble.classList.add('sequel');
}
}
// If there is already a msg in this bubble, create another div (next msg or replacement)
var msg = (bubble.querySelector('div.bubble p')
&& bubble.querySelector('div.bubble p').innerHTML != '')
? Chat.right.querySelector('div.bubble > div.message').cloneNode(true)
: bubble.querySelector('div.bubble > div.message');
var info = msg.querySelector('span.info');
var p = msg.getElementsByTagName('p')[0];
var reaction = msg.querySelector('span.reaction');
var reply = msg.querySelector('span.reply');
var reactions = msg.querySelector('ul.reactions');
// And we complete the message structure from the data we got...
if (data.retracted) {
p.classList.add('retracted');
}
if (data.encrypted) {
msg.classList.add('encrypted');
p.classList.add('encrypted');
}
if (data.body.match(/^\/me\s/)) {
p.classList.add('quote');
data.body = data.body.substring(4);
}
if (data.id != null) {
msg.setAttribute('id', 'id' + data.id);
}
if (data.messageid != null) {
msg.dataset.messageid = 'messageid-' + MovimUtils.hash(data.messageid + data.jidfrom);
/**
* If we append (during a reload) or prepend, we might have already a
* replacement message displayed, in that case we just stop here
*/
if (this.replacedHash.includes(msg.dataset.messageid)) return;
}
if (data.rtl) {
msg.setAttribute('dir', 'rtl');
}
let omemo = false;
// OMEMO handling
if (data.omemoheader && data.encrypted && !data.retracted && OMEMO_ENABLED) {
p.innerHTML = data.omemoheader.payload.substring(0, data.omemoheader.payload.length / 2);
ChatOmemo.decrypt(data).then(plaintext => {
let refreshP = document.querySelector('#id' + data.id + ' p.encrypted');
if (refreshP) {
if (plaintext) {
let escaped = MovimUtils.linkify(MovimUtils.htmlEscape(plaintext));
refreshP.innerHTML = ChatOmemo.searchEncryptedFile(escaped);
refreshP.classList.remove('encrypted');
} else {
refreshP.classList.add('error');
}
}
});
omemo = true;
}
if (data.replaceid) {
msg.classList.add('edited');
}
if (data.user_id == data.jidfrom || (isMuc && data.mine)) {
if (data.displayed) {
msg.classList.add('displayed');
} else if (data.delivered) {
msg.classList.add('delivered');
}
}
if (data.reactionsHtml !== undefined && data.retracted == false) {
reactions.innerHTML = data.reactionsHtml;
}
if (isMuc && data.resource) {
var resourceSpan = document.createElement('span');
resourceSpan.classList.add('resource');
resourceSpan.classList.add(data.color);
resourceSpan.innerText = data.resource;
msg.appendChild(resourceSpan);
}
if (data.sticker != null && data.retracted == false) {
bubble.querySelector('div.bubble').classList.add('file');
p.appendChild(Chat.getStickerHtml(data));
} else if (data.file != null && data.card === undefined && data.file.type !== 'xmpp' && data.retracted == false) {
bubble.querySelector('div.bubble').classList.add('file');
msg.appendChild(Chat.getFileHtml(data.file, data));
}
if (data.published) {
info.title = data.published;
}
// Parent
if (data.parent) {
msg.appendChild(Chat.getParentHtml(data.parent));
} /*else if (data.parentQuote) {
msg.appendChild(Chat.getSimpleParentHtml(data.parentQuote));
}*/
if (data.card) {
bubble.querySelector('div.bubble').classList.add('file');
msg.appendChild(Chat.getCardHtml(data.card, data.story));
}
msg.dataset.published = data.published;
if (omemo == false && data.sticker === undefined) {
Chat.addQuotesHtml(msg, data.body);
}
msg.appendChild(p);
msg.appendChild(info);
msg.appendChild(reactions);
if (data.mid) {
if ((isMuc && data.stanzaid)
|| (!isMuc && data.messageid)) {
reaction.dataset.mid = data.mid;
msg.appendChild(reaction);
}
if (reply) {
reply.dataset.mid = data.mid;
msg.appendChild(reply);
}
msg.dataset.mid = data.mid;
}
var elem;
// The following commented part introduces a security issue, see https://xmpp.org/extensions/xep-0308.html#security
if (data.replaceid /*&& (!isMuc || Boolean(textarea.dataset.mucGroup) == true)*/) {
elem = document.querySelector("[data-messageid=messageid-" + MovimUtils.hash(data.replaceid + data.jidfrom) + "]");
msg.dataset.messageid = 'messageid-' + MovimUtils.hash(data.replaceid + data.jidfrom);
this.replacedHash.push(msg.dataset.messageid);
}
if (!elem) {
elem = document.getElementById('id' + data.id);
}
if (elem) {
elem.parentElement.replaceChild(msg, elem);
mergeMsg = true;
// If the previous message was not a file or card and is replaced by it
if ((data.file != null || data.card != null) && data.retracted == false) {
msg.parentElement.classList.add('file');
} else {
msg.parentElement.classList.remove('file');
}
if (data.sticker != null && data.retracted == false) {
msg.parentElement.classList.add('sticker', 'file');
} else {
msg.parentElement.classList.remove('sticker');
}
} else {
if (prepend) {
bubble.querySelector('div.bubble').insertBefore(msg, bubble.querySelector('div.bubble').firstChild);
} else {
bubble.querySelector('div.bubble').appendChild(msg);
}
}
// MUC specific
if (isMuc) {
if (data.moderator) {
bubble.querySelector('div.bubble').classList.add('moderator');
}
icon = bubble.querySelector('span.primary.icon');
if (icon.querySelector('img') == undefined) {
if (data.icon_url) {
var img = document.createElement('img');
img.setAttribute('src', data.icon_url);
img.setAttribute('loading', 'lazy');
icon.appendChild(img);
}
if (data.resource) {
icon.dataset.resource = data.resource;
} else {
icon.innerHTML = '';
var i = document.createElement('i');
i.className = 'material-symbols';
i.innerText = 'notes';
icon.appendChild(i);
}
}
if (data.quoted) {
bubble.querySelector('div.bubble').classList.add('quoted');
}
}
if (!mergeMsg) {
if (prepend) {
MovimTpl.prepend('#' + id, bubble.outerHTML);
} else {
MovimTpl.append('#' + id, bubble.outerHTML);
}
}
},
appendDate: function (date, prepend) {
var list = document.querySelector('#chat_widget > div ul.conversation');
if (!list) return;
dateNode = Chat.date.cloneNode(true);
dateNode.querySelector('p').innerHTML = date;
dateNode.id = MovimUtils.cleanupId(date);
if (prepend) {
if (list.firstChild.className == 'date') return;
if (existingDate = document.getElementById(MovimUtils.cleanupId(date))) {
existingDate.remove();
}
list.insertBefore(dateNode, list.firstChild);
} else {
if (document.getElementById(MovimUtils.cleanupId(date))) {
return;
}
list.appendChild(dateNode);
}
},
insertSeparator: function (counter) {
separatorNode = Chat.separator.cloneNode(true);
var list = document.querySelector('#chat_widget > div ul.conversation');
if (!list || list.querySelector('li.separator')) return;
var messages = document.querySelectorAll('#chat_widget > div ul.conversation div.bubble p');
if (messages.length > counter && counter > 0) {
var p = messages[messages.length - counter];
list.insertBefore(separatorNode, p.parentNode.parentNode.parentNode);
}
},
getStickerHtml: function (data) {
var img = document.createElement('img');
img.classList.add('sticker');
if (data.sticker.url) {
if (data.sticker.thumb) {
img.setAttribute('src', data.sticker.thumb);
} else {
img.setAttribute('src', data.sticker.url);
}
if (data.sticker.width) img.setAttribute('width', data.sticker.width);
if (data.sticker.height) {
img.setAttribute('height', data.sticker.height);
} else {
img.setAttribute('height', '170');
}
}
return img;
},
getCardHtml: function (card, story) {
var ul = document.createElement('ul');
ul.innerHTML = card;
ul.setAttribute('class', story
? 'list card shadow flex fourth gallery active'
: 'list card middle noanim shadow active');
if (story) {
ul.querySelector('li').classList.add('story');
}
return ul;
},
getFileHtml: function (file, data) {
// Inline files
if (file.disposition == 'inline' && (!file.preview || !file.preview.height) && file.type.substring(0, 5) == 'image') {
var img = document.createElement('img');
img.classList.add('sticker');
img.setAttribute('src', file.url);
img.setAttribute('height', '170');
return img;
}
var div = document.createElement('div');
div.classList.add('file');
if (file.name) {
div.dataset.type = file.type;
if (file.preview) {
var img = document.createElement('img');
if (file.preview.url) {
img.setAttribute('src', file.preview.thumb ?? file.preview.url);
if (file.preview.width && file.preview.height) {
img.setAttribute('width', file.preview.width);
img.setAttribute('height', file.preview.height);
} else if (file.thumbnail_width && file.thumbnail_height) {
img.setAttribute('width', file.thumbnail_width);
img.setAttribute('height', file.thumbnail_height);
}
}
if (file.preview.title) {
img.title = file.preview.title;
}
if (file.preview.picture) {
img.classList.add('active');
img.setAttribute('onclick', 'Preview_ajaxHttpShow("' + file.preview.url + '", ' + data.mid + ')');
}
if (file.preview.thumbnail_type == 'image/thumbhash' && file.preview.thumbnail_url) {
try {
div.style.background = `center / cover url(${thumbHashToDataURL(MovimUtils.base64ToBinary(file.preview.thumbnail_url))})`;
} catch (error) {
console.log('Cannot handle thumbhash hash');
}
}
div.appendChild(img);
}
if (file.type == 'audio/ogg' || file.type == 'audio/opus' || file.type == 'audio/mpeg') {
div.appendChild(Chat.getAudioPlayer(file));
} else if (file.type == 'video/webm' || file.type == 'video/mp4') {
div.appendChild(Chat.getVideoPlayer(file));
}
var url = new URL(file.url);
// Tenor implementation and inline files
if (url.host && ['media.tenor.com', 'static.klipy.com'].includes(url.host)
|| file.type == 'audio/ogg' || file.type == 'audio/opus' || file.type == 'audio/mpeg'
|| file.disposition == 'inline') {
return div;
}
if (!file.preview) {
var a = document.createElement('a');
a.textContent = file.name;
a.href = file.url;
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.title = file.url;
div.appendChild(a);
if (file.host) {
var host = document.createElement('span');
host.innerHTML = file.host;
host.className = 'host';
a.prepend(host);
}
if (file.size > 0) {
var span = document.createElement('span');
span.innerHTML = file.cleansize;
span.className = 'size';
a.prepend(span);
}
}
}
return div;
},
getAudioPlayer: function (file) {
var div = document.createElement('div');
div.setAttribute('title', file.name);
div.classList.add('audio_player');
div.id = 'a_' + file.message_mid;
var audio = document.createElement('audio');
audio.setAttribute('src', file.url + '#t=0.01');
//audio.setAttribute('controls', '');
div.appendChild(audio);
var playPauseButton = document.createElement('span');
playPauseButton.classList.add('button', 'flat', 'gray');
playPauseButton.classList.add('play_pause');
var i = document.createElement('i');
i.className = 'material-symbols';
i.innerText = 'play_arrow';
playPauseButton.appendChild(i);
div.appendChild(playPauseButton);
var timer = document.createElement('p');
timer.classList.add('timer');
div.appendChild(timer);
var progressBar = document.createElement('input');
progressBar.type = 'range';
progressBar.value = 0;
progressBar.setAttribute('min', 0);
progressBar.setAttribute('max', 100);
progressBar.setAttribute('step', 0.1);
div.appendChild(progressBar);
var downloadButton = document.createElement('a');
downloadButton.classList.add('button', 'flat', 'gray');
downloadButton.href = file.url;
downloadButton.target = '_blank';
var i = document.createElement('i');
i.className = 'material-symbols';
i.innerText = 'file_download';
downloadButton.appendChild(i);
div.appendChild(downloadButton);
return div;
},
getVideoPlayer: function (file) {
var video = document.createElement('video');
video.setAttribute('src', file.url + '#t=0.01');
video.setAttribute('loop', 'loop');
if (file.thumbnail_url != null) {
video.setAttribute('poster', file.thumbnail_url);
video.setAttribute('width', file.thumbnail_width);
video.setAttribute('height', file.thumbnail_height);
} else {
video.setAttribute('poster', BASE_URI + 'theme/img/poster.svg');
}
var url = new URL(file.url);
// Tenor implementation
if ((url.host && ['media.tenor.com', 'static.klipy.com'].includes(url.host)) || file.disposition == 'inline') {
video.classList.add('gif');
} else {
video.setAttribute('controls', 'controls');
video.setAttribute('preload', 'metadata');
}
return video;
},
addQuotesHtml: function (msg, body) {
let div = null;
let p = null;
if (!body.startsWith('<code ') && body.includes('&gt; ')) {
body.split("\n").forEach(line => {
if (line.startsWith('&gt; ') || line == '&gt;') {
p = null;
if (div == null) {
div = document.createElement('div');
div.classList.add('parent');
}
let divP = document.createElement('p');
let trimmed = line.substring('4');
divP.innerHTML = trimmed == ''
? ' '
: trimmed
div.appendChild(divP);
msg.appendChild(div);
} else {
div = null;
if (p == null) {
p = document.createElement('p');
p.innerHTML = line;
} else {
p.innerHTML += "\n" + line;
}
msg.appendChild(p);
}
});
return;
}
p = msg.getElementsByTagName('p')[0];
p.innerHTML = body;
},
getParentHtml: function (parent) {
var div = document.createElement('div');
div.classList.add('parent');
div.dataset.parentReplaceId = parent.replaceid
div.dataset.parentId = parent.id;
div.id = 'parent' + parent.id;
var span = document.createElement('span');
if (parent.color) {
span.classList.add('resource');
span.classList.add(parent.color);
}
span.classList.add('from');
span.innerHTML = parent.fromName;
div.appendChild(span);
var p = document.createElement('p');
div.appendChild(p);
if (parent.omemoheader && OMEMO_ENABLED) {
p.innerHTML = parent.omemoheader.payload.substring(0, parent.omemoheader.payload.length / 2);
ChatOmemo.decrypt(parent).then(plaintext => {
let refreshP = document.querySelector('#parent' + parent.id + ' p');
if (refreshP) {
if (plaintext) {
refreshP.innerText = plaintext;
} else {
refreshP.classList.add('error');
}
}
});
} else {
p.innerHTML = parent.body;
}
return div;
},
toggleAction: function () {
var chatBox = document.querySelector('#chat_widget .chat_box');
if (chatBox) {
if (Chat.getTextarea().value.length > 0) {
chatBox.classList.add('compose');
Chat.toggleAttach(true);
} else {
chatBox.classList.remove('compose');
}
}
},
toggleAttach: function (forceDisabled) {
var attach = document.querySelector('#chat_widget .chat_box span.attach');
if (attach) {
if (forceDisabled) {
attach.classList.remove('enabled');
} else {
attach.classList.toggle('enabled');
}
}
},
getTextarea: function () {
var textarea = document.querySelector('#chat_textarea');
if (textarea) return textarea;
},
isEncrypted: function () {
return (Chat.getTextarea() && Chat.getTextarea().dataset.encryptedstate == 'yes');
},
getDiscussion: function () {
return document.querySelector('#chat_widget div.contained');
},
touchEvents: function () {
var chat = document.querySelector('#chat_widget');
if (!chat) return;
chat.addEventListener('touchstart', function (event) {
chat.classList.remove('moving');
Chat.startX = event.targetTouches[0].pageX;
Chat.startY = event.targetTouches[0].pageY;
}, true);
chat.addEventListener('touchmove', function (event) {
Chat.translateX = parseInt(event.targetTouches[0].pageX - Chat.startX);
Chat.translateY = parseInt(event.targetTouches[0].pageY - Chat.startY);
if (Chat.translateX > Chat.delay && Chat.translateX <= Chat.clientWidth) {
// If the horizontal movement is allowed and the vertical one is not important
// we authorize the slide
if (Math.abs(Chat.translateY) < Chat.delay) {
Chat.slideAuthorized = true;
}
if (Chat.slideAuthorized) {
chat.style.transform = 'translateX(' + (Chat.translateX - Chat.delay) + 'px)';
}
}
}, true);
chat.addEventListener('touchend', function (event) {
chat.classList.add('moving');
if (Chat.translateX > (Chat.clientWidth / 4) && Chat.slideAuthorized) {
MovimTpl.hidePanel();
Chat.get(null, true);
}
chat.style.transform = '';
Chat.slideAuthorized = false;
Chat.startX = Chat.translateX = Chat.startY = Chat.translateY = 0;
}, true);
},
isValidHttpUrl: function (string) {
let url;
try {
url = new URL(string);
} catch (_) {
return false;
}
return url.protocol === "http:" || url.protocol === "https:";
},
getNewerMessages: function () {
var jid = MovimUtils.urlParts().params[0];
let lastMessage = Chat.getDiscussion()?.querySelector('li:last-child .bubble:last-child .message:last-child');
if (jid) {
Chat_ajaxGetHistory(
jid,
lastMessage ? lastMessage.dataset.published : null,
(MovimUtils.urlParts().params[1] === 'room'),
false,
false
);
}
},
searchMembers: function (key) {
var selector = '#room_nav_members > li';
document.querySelectorAll(selector)
.forEach(item => item.classList.remove('found'));
var founds = document.querySelectorAll(
selector + '[name*="' + MovimUtils.cleanupId(key).slice(3) + '"]'
);
founds.forEach(item => item.classList.add('found'));
}
};
MovimWebsocket.attach(function () {
if (!Chat.pagination) {
Chat_ajaxInit();
}
var jid = MovimUtils.urlParts().params[0];
if (jid) {
if (Boolean(document.getElementById(MovimUtils.cleanupId(jid) + '-conversation'))) {
Chat.getNewerMessages();
} else {
(MovimUtils.urlParts().params[1] === 'room')
? Chat.getRoom(jid)
: Chat.get(jid);
}
} else {
if (!MovimUtils.isMobile()) {
Chat_ajaxHttpGetEmpty();
}
if (MovimUtils.urlParts().page == 'chat') {
Notif.current('chat');
}
}
});
MovimEvents.registerWindow('focus', 'chat', () => {
if (MovimWebsocket.connection) {
var jid = MovimUtils.urlParts().params[0];
var room = (MovimUtils.urlParts().params[1] === 'room');
if (jid) {
Chat_ajaxGetHeader(jid, room);
if (room) {
Chat_ajaxHttpGetPresences(jid);
}
}
}
var textarea = Chat.getTextarea();
if (textarea) textarea.focus();
});
MovimEvents.registerWindow('resize', 'chat', () => Chat.scrollRestore());
MovimEvents.registerWindow('loaded', 'chat', () => {
if (MovimUtils.isMobile()) Chat.touchEvents();
if (typeof Upload != 'undefined') {
Upload.initiate((file) => {
if (['chat', 'space'].includes(MovimUtils.urlParts().page)
&& (typeof (PublishStories) == 'undefined' || PublishStories.main == undefined)) {
Upload.prependName = 'chat';
}
});
Upload.attach((file) => {
if (['chat', 'space'].includes(MovimUtils.urlParts().page)
&& (typeof (PublishStories) == 'undefined' || PublishStories.main == undefined)) {
Chat_ajaxHttpDaemonSendMessage(
Chat.getTextarea().dataset.jid,
false,
Boolean(Chat.getTextarea().dataset.muc),
file
);
}
});
}
// Really early panel showing in case we have a JID
var parts = MovimUtils.urlParts();
if (parts.page == 'chat' && parts.params[0]) {
MovimTpl.showPanel();
}
});
var state = 0;