feat: allow chat rooms in widgets

This commit is contained in:
Barış Soner Uşaklı
2024-08-16 14:21:33 -04:00
parent 6f7eecd183
commit f80b7b87fb
4 changed files with 98 additions and 46 deletions

View File

@@ -108,7 +108,7 @@
"nodebb-theme-lavender": "7.1.8", "nodebb-theme-lavender": "7.1.8",
"nodebb-theme-peace": "2.2.6", "nodebb-theme-peace": "2.2.6",
"nodebb-theme-persona": "13.3.25", "nodebb-theme-persona": "13.3.25",
"nodebb-widget-essentials": "7.0.18", "nodebb-widget-essentials": "7.0.19",
"nodemailer": "6.9.13", "nodemailer": "6.9.13",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"passport": "0.7.0", "passport": "0.7.0",

View File

@@ -1,8 +1,9 @@
{ {
"chat.room-id": "Room %1", "chat.room-id": "Room %1",
"chat.chatting-with": "Chat with", "chat.chatting-with": "Chat with",
"chat.placeholder": "Type chat message here, drag & drop images, press enter to send", "chat.placeholder": "Type chat message here, drag & drop images",
"chat.placeholder.mobile": "Type chat message here", "chat.placeholder.mobile": "Type chat message",
"chat.placeholder.message-room": "Message #%1",
"chat.scroll-up-alert": "Go to most recent message", "chat.scroll-up-alert": "Go to most recent message",
"chat.usernames-and-x-others": "%1 & %2 others", "chat.usernames-and-x-others": "%1 & %2 others",
"chat.chat-with-usernames": "Chat with %1", "chat.chat-with-usernames": "Chat with %1",

View File

@@ -1,10 +1,9 @@
'use strict'; 'use strict';
define('chat', [ define('chat', [
'components', 'taskbar', 'translator', 'hooks', 'bootbox', 'alerts', 'api', 'components', 'taskbar', 'translator', 'hooks', 'bootbox', 'alerts', 'api', 'scrollStop',
], function (components, taskbar, translator, hooks, bootbox, alerts, api) { ], function (components, taskbar, translator, hooks, bootbox, alerts, api, scrollStop) {
const module = {}; const module = {};
let newMessage = false;
module.openChat = function (roomId, uid) { module.openChat = function (roomId, uid) {
if (!app.user.uid) { if (!app.user.uid) {
@@ -182,9 +181,11 @@ define('chat', [
return; return;
} }
if (module.modalExists(data.roomId)) { if (module.modalExists(data.roomId)) {
const modal = module.getModal(data.roomId);
const newMessage = parseInt(modal.attr('new-message'), 10) === 1;
data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0; data.self = parseInt(app.user.uid, 10) === parseInt(data.fromUid, 10) ? 1 : 0;
if (!newMessage) { if (!newMessage) {
newMessage = data.self === 0; modal.attr('new-message', data.self === 0 ? 1 : 0);
} }
data.message.self = data.self; data.message.self = data.self;
data.message.timestamp = Math.min(Date.now(), data.message.timestamp); data.message.timestamp = Math.min(Date.now(), data.message.timestamp);
@@ -290,11 +291,61 @@ define('chat', [
return $('#chat-modal-' + roomId).length !== 0; return $('#chat-modal-' + roomId).length !== 0;
}; };
module.initWidget = function (roomId, chatModal) {
require(['forum/chats', 'forum/chats/messages'], function (Chats, ChatsMessages) {
socket.emit('modules.chats.enter', roomId);
api.del(`/chats/${roomId}/state`, {});
chatModal.find('.timeago').timeago();
chatModal.find('[data-bs-toggle="tooltip"]').tooltip({
trigger: 'hover', container: '#content',
});
ChatsMessages.wrapImagesInLinks(chatModal.find('[component="chat/messages"] .chat-content'));
scrollStop.apply(chatModal.find('[component="chat/messages"] .chat-content'));
chatModal.on('mousemove keypress click', function () {
if (parseInt(chatModal.attr('new-message'), 10) === 1) {
console.log('marking chat read');
api.del(`/chats/${roomId}/state`, {});
chatModal.removeAttr('new-message');
}
});
Chats.addActionHandlers(chatModal.find('[component="chat/message/window"]'), roomId);
Chats.addSendHandlers(roomId, chatModal.find('.chat-input'), chatModal.find('[data-action="send"]'));
Chats.createAutoComplete(roomId, chatModal.find('[component="chat/input"]'));
Chats.addScrollHandler(roomId, app.user.uid, chatModal.find('[component="chat/message/content"]'));
Chats.addScrollBottomHandler(roomId, chatModal.find('[component="chat/message/content"]'));
Chats.addParentHandler(chatModal.find('[component="chat/message/content"]'));
Chats.addCharactersLeftHandler(chatModal);
Chats.addTextareaResizeHandler(chatModal);
Chats.addTypingHandler(chatModal, roomId);
Chats.addIPHandler(chatModal);
Chats.addTooltipHandler(chatModal);
Chats.addUploadHandler({
dragDropAreaEl: chatModal.find('.modal-content'),
pasteEl: chatModal,
uploadFormEl: chatModal.find('[component="chat/upload"]'),
uploadBtnEl: chatModal.find('[component="chat/upload/button"]'),
inputEl: chatModal.find('[component="chat/input"]'),
});
ChatsMessages.addSocketListeners();
ChatsMessages.scrollToBottomAfterImageLoad(chatModal.find('.chat-content'));
hooks.fire('action:chat.loaded', chatModal);
});
};
module.createModal = function (data, callback) { module.createModal = function (data, callback) {
callback = callback || function () {}; callback = callback || function () {};
require([ require([
'scrollStop', 'forum/chats', 'forum/chats/messages', 'forum/chats/message-search', 'forum/chats', 'forum/chats/messages', 'forum/chats/message-search',
], function (scrollStop, Chats, ChatsMessages, messageSearch) { ], function (Chats, ChatsMessages, messageSearch) {
app.parseAndTranslate('chat', data, function (chatModal) { app.parseAndTranslate('chat', data, function (chatModal) {
const roomId = data.roomId; const roomId = data.roomId;
if (module.modalExists(roomId)) { if (module.modalExists(roomId)) {
@@ -305,45 +356,19 @@ define('chat', [
chatModal.attr('id', 'chat-modal-' + roomId); chatModal.attr('id', 'chat-modal-' + roomId);
chatModal.attr('data-roomid', roomId); chatModal.attr('data-roomid', roomId);
chatModal.attr('intervalId', 0);
chatModal.attr('data-uuid', uuid); chatModal.attr('data-uuid', uuid);
chatModal.css('position', 'fixed'); chatModal.css('position', 'fixed');
chatModal.appendTo($('body')); chatModal.appendTo($('body'));
chatModal.find('.timeago').timeago(); chatModal.find('.timeago').timeago();
chatModal.find('[data-bs-toggle="tooltip"]').tooltip({ trigger: 'hover', container: '#content' }); chatModal.find('[data-bs-toggle="tooltip"]').tooltip({ trigger: 'hover', container: '#content' });
ChatsMessages.wrapImagesInLinks(chatModal.find('[component="chat/messages"] .chat-content')); ChatsMessages.wrapImagesInLinks(chatModal.find('[component="chat/messages"] .chat-content'));
module.center(chatModal);
app.loadJQueryUI(function () {
chatModal.find('.modal-content').resizable({
handles: 'n, e, s, w, se',
minHeight: 250,
minWidth: 400,
});
chatModal.find('.modal-content').on('resize', function (event, ui) {
if (ui.originalSize.height === ui.size.height) {
return;
}
chatModal.find('.modal-body').css('height', module.calculateChatListHeight(chatModal));
});
chatModal.draggable({
start: function () {
taskbar.updateActive(uuid);
chatModal.css({ bottom: 'auto', right: 'auto' });
},
stop: function () {
module.focusInput(chatModal);
},
distance: 10,
handle: '.modal-header',
});
});
scrollStop.apply(chatModal.find('[component="chat/messages"] .chat-content')); scrollStop.apply(chatModal.find('[component="chat/messages"] .chat-content'));
module.center(chatModal);
makeModalResizeableDraggable(chatModal, uuid);
chatModal.find('#chat-close-btn').on('click', function () { chatModal.find('#chat-close-btn').on('click', function () {
module.close(uuid); module.close(uuid);
}); });
@@ -380,9 +405,9 @@ define('chat', [
}); });
chatModal.on('mousemove keypress click', function () { chatModal.on('mousemove keypress click', function () {
if (newMessage) { if (parseInt(chatModal.attr('new-message'), 10) === 1) {
api.del(`/chats/${roomId}/state`, {}); api.del(`/chats/${roomId}/state`, {});
newMessage = false; chatModal.removeAttr('new-message');
} }
}); });
@@ -433,6 +458,36 @@ define('chat', [
}); });
}; };
function makeModalResizeableDraggable(chatModal, uuid) {
app.loadJQueryUI(function () {
chatModal.find('.modal-content').resizable({
handles: 'n, e, s, w, se',
minHeight: 250,
minWidth: 400,
});
chatModal.find('.modal-content').on('resize', function (event, ui) {
if (ui.originalSize.height === ui.size.height) {
return;
}
chatModal.find('.modal-body').css('height', module.calculateChatListHeight(chatModal));
});
chatModal.draggable({
start: function () {
taskbar.updateActive(uuid);
chatModal.css({ bottom: 'auto', right: 'auto' });
},
stop: function () {
module.focusInput(chatModal);
},
distance: 10,
handle: '.modal-header',
});
});
}
module.focusInput = function (chatModal) { module.focusInput = function (chatModal) {
setTimeout(function () { setTimeout(function () {
chatModal.find('[component="chat/input"]').focus(); chatModal.find('[component="chat/input"]').focus();
@@ -441,8 +496,6 @@ define('chat', [
module.close = function (uuid) { module.close = function (uuid) {
const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]'); const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]');
clearInterval(chatModal.attr('intervalId'));
chatModal.attr('intervalId', 0);
chatModal.remove(); chatModal.remove();
chatModal.data('modal', null); chatModal.data('modal', null);
taskbar.discard('chat', uuid); taskbar.discard('chat', uuid);
@@ -529,8 +582,6 @@ define('chat', [
const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]'); const chatModal = $('.chat-modal[data-uuid="' + uuid + '"]');
chatModal.addClass('hide'); chatModal.addClass('hide');
taskbar.minimize('chat', uuid); taskbar.minimize('chat', uuid);
clearInterval(chatModal.attr('intervalId'));
chatModal.attr('intervalId', 0);
hooks.fire('action:chat.minimized', { hooks.fire('action:chat.minimized', {
uuid: uuid, uuid: uuid,
modal: chatModal, modal: chatModal,

View File

@@ -5,7 +5,7 @@
<div class="w-100 flex-grow-1 flex-nowrap position-relative d-flex rounded-2 border border-secondary p-1 align-items-end"> <div class="w-100 flex-grow-1 flex-nowrap position-relative d-flex rounded-2 border border-secondary p-1 align-items-end">
<button component="chat/upload/button" class="btn-ghost-sm px-2" type="button" title="[[global:upload]]" data-bs-toggle="tooltip"><i class="fa fa-fw fa-upload"></i></button> <button component="chat/upload/button" class="btn-ghost-sm px-2" type="button" title="[[global:upload]]" data-bs-toggle="tooltip"><i class="fa fa-fw fa-upload"></i></button>
<div class="flex-grow-1 align-self-center"> <div class="flex-grow-1 align-self-center">
<textarea component="chat/input" placeholder="[[modules:chat.placeholder.mobile]]" class="bg-transparent text-body form-control chat-input mousetrap rounded-0 border-0 shadow-none px-1 py-0" style="min-height: 1.5rem;height:0;max-height:30vh;resize:none;"></textarea> <textarea component="chat/input" placeholder="{{{ if roomName }}}[[modules:chat.placeholder.message-room, {roomName}]]{{{ else }}}[[modules:chat.placeholder.mobile]]{{{ end }}}" class="bg-transparent text-body form-control chat-input mousetrap rounded-0 border-0 shadow-none px-1 py-0" style="min-height: 1.5rem;height:0;max-height:30vh;resize:none;"></textarea>
</div> </div>
<div class="d-flex gap-1"> <div class="d-flex gap-1">
{{{ each composerActions }}} {{{ each composerActions }}}