mirror of
https://github.com/pierre42100/ComunicWeb
synced 2024-12-26 02:48:51 +00:00
1502 lines
39 KiB
JavaScript
1502 lines
39 KiB
JavaScript
/**
|
|
* Conversation chat window functions
|
|
*
|
|
* @author Pierre HUBERT
|
|
*/
|
|
|
|
const ConvChatWindow = {
|
|
|
|
/**
|
|
* @var {Object} __conversationsCache Chat windows cache
|
|
*/
|
|
__conversationsCache: {},
|
|
|
|
/**
|
|
* Open a new conversation window
|
|
*
|
|
* @param {Integer} conversationID The ID of the window to open
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
openConversation: function(conversationID){
|
|
|
|
//Log action
|
|
ComunicWeb.debug.logMessage("Opening conversation " + conversationID);
|
|
|
|
//Create a conversation window
|
|
var conversationWindow = this.create({
|
|
target: byId(ComunicWeb.components.conversations.manager.__conversationsContainerID),
|
|
conversationID: conversationID,
|
|
});
|
|
|
|
//Load the conversation
|
|
this.load(conversationID, conversationWindow);
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
|
|
/**
|
|
* Create a new chat window
|
|
*
|
|
* @param {Object} infos Informations required for the new chat window
|
|
* @info {HTMLElement} target The target of the new chat window
|
|
* @info {Integer} conversationID The ID of the target conversation
|
|
* @return {Object} Informations about the new chat window
|
|
*/
|
|
create: function(infos){
|
|
|
|
//Log action
|
|
ComunicWeb.debug.logMessage("Create a new chat window");
|
|
|
|
//First, create the generic conversation window
|
|
var infosBox = ComunicWeb.components.conversations.windows.create(infos.target.children[0]);
|
|
|
|
//Save conversation ID
|
|
infosBox.conversationID = infos.conversationID;
|
|
|
|
//Change box root class name
|
|
infosBox.rootElem.className += " chat-window direct-chat direct-chat-primary";
|
|
|
|
//Adapt close button behaviour
|
|
infosBox.closeFunction = function(){
|
|
|
|
//Remove root element
|
|
infosBox.rootElem.remove();
|
|
|
|
//Remove the conversation from opened ones
|
|
ComunicWeb.components.conversations.cachingOpened.remove(infosBox.conversationID);
|
|
|
|
//Unload conversation
|
|
ComunicWeb.components.conversations.chatWindows.unload(infosBox.conversationID);
|
|
}
|
|
|
|
infosBox.closeButton.onclick = infosBox.closeFunction;
|
|
|
|
|
|
//Debug
|
|
//Create messages container
|
|
infosBox.messagesArea = createElem2({
|
|
appendTo: infosBox.boxBody,
|
|
type: "div",
|
|
class: "direct-chat-messages",
|
|
innerHTML: "",
|
|
});
|
|
|
|
//Add button to get conversation members
|
|
infosBox.membersButton = createElem2({
|
|
type: "button",
|
|
insertBefore: infosBox.closeButton,
|
|
elemType: "button",
|
|
class: "btn btn-box-tool",
|
|
title: "Conversation members"
|
|
});
|
|
infosBox.membersButton.setAttribute("data-toggle", "tooltip");
|
|
infosBox.membersButton.setAttribute("data-widget", "chat-pane-toggle");
|
|
|
|
//Add button icon
|
|
var buttonIcon = createElem("i", infosBox.membersButton);
|
|
buttonIcon.className = "fa fa-users";
|
|
|
|
|
|
//Add conversation members pane
|
|
var membersPane = createElem("div", infosBox.boxBody);
|
|
membersPane.className = "direct-chat-contacts";
|
|
|
|
//Add conversation members list
|
|
infosBox.membersList = createElem("ul", membersPane);
|
|
infosBox.membersList.className = "contacts-list";
|
|
|
|
//Add send a message form
|
|
this.addMessageform(infosBox);
|
|
|
|
//Return informations about the chat window
|
|
return infosBox;
|
|
|
|
},
|
|
|
|
/**
|
|
* Add a message form to the chat windows
|
|
*
|
|
* @param {Object} infosBox Informations about the chat box
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
addMessageform: function(infosBox){
|
|
|
|
//Create form container
|
|
var conversationFormContainer = createElem2({
|
|
appendTo: infosBox.boxFooter,
|
|
type: "form",
|
|
class: "create-message-form"
|
|
});
|
|
|
|
//Create input group
|
|
var inputGroup = createElem2({
|
|
appendTo: conversationFormContainer,
|
|
type: "div",
|
|
class: "input-group"
|
|
});
|
|
|
|
//Create text input (for message)
|
|
var inputText = createElem2({
|
|
appendTo: inputGroup,
|
|
type: "textarea",
|
|
class: "form-control",
|
|
placeholder: tr("New message..."),
|
|
});
|
|
inputText.maxLength = ServerConfig.conf.max_conversation_message_len;
|
|
|
|
//Enable textarea 2.0 on the message
|
|
var textarea2 = new ComunicWeb.components.textarea();
|
|
textarea2.init({
|
|
element: inputText,
|
|
minHeight: "34px",
|
|
autosize: true,
|
|
});
|
|
|
|
//Create file input (for optionnal file)
|
|
var fileInput = createElem2({
|
|
type: "input",
|
|
elemType: "file",
|
|
});
|
|
fileInput.accept = ServerConfig.conf.allowed_conversation_files_type.join(", ");
|
|
|
|
|
|
//Create button group
|
|
var buttonGroup = createElem2({
|
|
appendTo: inputGroup,
|
|
type: "span",
|
|
class: "input-group-btn",
|
|
});
|
|
|
|
//Add emojie button
|
|
var emojiButton = createElem2({
|
|
appendTo: buttonGroup,
|
|
type: "button",
|
|
elemType: "button",
|
|
class: "btn btn-flat btn-add-emoji",
|
|
});
|
|
createElem2({
|
|
type: "i",
|
|
appendTo: emojiButton,
|
|
class: "fa fa-smile-o"
|
|
});
|
|
|
|
//Make emojie button lives
|
|
ComunicWeb.components.emoji.picker.addPicker(inputText, emojiButton, function(){
|
|
|
|
//Make the emojie picker visible
|
|
wdtEmojiBundle.popup.style.top = (abs_height_bottom_screen()-357)+"px";
|
|
|
|
//Make the smile button visible
|
|
var currLeft = Number(wdtEmojiBundle.popup.style.left.replace("px", ""));
|
|
var potentialLeft = currLeft - 20;
|
|
|
|
if(potentialLeft > 0)
|
|
wdtEmojiBundle.popup.style.left = potentialLeft + "px";
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// =========== SEND FILES ===========
|
|
//Add image button
|
|
const fileButton = createElem2({
|
|
appendTo: buttonGroup,
|
|
type: "button",
|
|
elemType: "button",
|
|
class: "btn btn-flat btn-add-image",
|
|
});
|
|
fileButton.onclick = function(){
|
|
//Call file selector
|
|
fileInput.click();
|
|
};
|
|
|
|
//Add image icon
|
|
createElem2({
|
|
type: "i",
|
|
appendTo: fileButton,
|
|
class: "fa fa-plus"
|
|
});
|
|
|
|
//Add send button
|
|
var sendButton = createElem2({
|
|
appendTo: buttonGroup,
|
|
type: "button",
|
|
class: "btn btn-primary btn-flat",
|
|
elemType: "submit",
|
|
});
|
|
|
|
//Add send icon
|
|
createElem2({
|
|
appendTo: sendButton,
|
|
type: "i",
|
|
class: "fa fa-send-o",
|
|
});
|
|
|
|
|
|
ConversationsUtils.registerInputToSendFile(infosBox.conversationID, fileInput, conversationFormContainer);
|
|
|
|
// =========== /SEND FILES ===========
|
|
|
|
|
|
|
|
|
|
//Prevent textarea from adding a new line when pressing enter
|
|
$(inputText).keypress(function(event){
|
|
if(event.keyCode == 13){
|
|
event.preventDefault();
|
|
sendButton.click();
|
|
}
|
|
});
|
|
|
|
//Add required elements to infosBox
|
|
infosBox.sendMessageForm = {
|
|
formRoot: conversationFormContainer,
|
|
sendButton: sendButton,
|
|
inputText: inputText,
|
|
textarea2: textarea2,
|
|
};
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Load (or reload) a conversation
|
|
*
|
|
* @param {Integer} conversationID The ID of the conversation to load
|
|
* @param {Object} conversationWindow Informations about the conversation window
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
load: async function(conversationID, conversationWindow, forceRefresh) {
|
|
|
|
try {
|
|
|
|
//Change conversation window name (loading state)
|
|
this.changeName("Loading", conversationWindow);
|
|
|
|
/** @type {Conversation} */
|
|
const conv = await new Promise((res, rej) => {
|
|
ConversationsInterface.getInfosOne(conversationID, (info) => {
|
|
if (info.error)
|
|
rej(info)
|
|
else
|
|
res(info)
|
|
}, forceRefresh);
|
|
})
|
|
|
|
const users = await getUsers(conv.members.map(m => m.user_id));
|
|
|
|
// Create conversation informations root object
|
|
var conversationInfos = {
|
|
box: conversationWindow,
|
|
membersInfos: users,
|
|
infos: conv
|
|
};
|
|
|
|
// Save conversation informations in the cache
|
|
this.__conversationsCache["conversation-"+conversationID] = conversationInfos;
|
|
|
|
//Change the name of the conversation
|
|
this.changeName(await getConvName(conv), conversationWindow);
|
|
|
|
// Apply the color of the conversation (if any)
|
|
if (conv.color)
|
|
conversationWindow.rootElem.setAttribute("style", "--primary-blue: #" +conv.color)
|
|
|
|
// Update conversation members informations
|
|
this.updateMembersList(conversationInfos);
|
|
|
|
// Display conversation settings pane
|
|
this.showConversationSettings(conversationInfos);
|
|
|
|
// Register the conversation in the service
|
|
ConvService.registerConversation(conversationID);
|
|
|
|
// Make send a message button lives
|
|
conversationInfos.box.sendMessageForm.formRoot.onsubmit = (e) => {
|
|
e.preventDefault();
|
|
|
|
//Submit new message
|
|
this.submitMessageForm(conversationInfos);
|
|
|
|
};
|
|
|
|
//Add call button (if possible)
|
|
this.showCallButton(conversationInfos);
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to load conversation!"), "danger");
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Unload a chat window
|
|
*
|
|
* @param {Integer} conversationID The ID of the conversation to unload
|
|
* @param {Boolean} keepInfos Keep informations about the chat window
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
unload: function(conversationID, keepInfos){
|
|
|
|
if(!this.__conversationsCache["conversation-"+conversationID]){
|
|
ComunicWeb.debug.logMessage("Couldn't unload conversation: " + conversationID +". It seems not to be loaded...");
|
|
return false;
|
|
}
|
|
|
|
//Log action
|
|
ComunicWeb.debug.logMessage("Unloading a conversation: " + conversationID);
|
|
|
|
//Get informations
|
|
var conversationInfos = this.__conversationsCache["conversation-"+conversationID];
|
|
|
|
//Empty messages area
|
|
emptyElem(conversationInfos.box.messagesArea);
|
|
conversationInfos.box.messagesArea.innerHTML = "";
|
|
|
|
//Un-register conversation
|
|
ComunicWeb.components.conversations.service.unregisterConversation(conversationID);
|
|
|
|
//Remove informations if required
|
|
if(!keepInfos){
|
|
delete this.__conversationsCache["conversation-"+conversationID];
|
|
}
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Unload all chat windows
|
|
*
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
unloadAll: function(){
|
|
|
|
//Clear conversation object
|
|
clearObject(this.__conversationsCache);
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Change the name of the converation at the top of the windows
|
|
*
|
|
* @param {String} newName The new name for the conversation window
|
|
* @param {Ojbect} info Information about the conversation window
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
changeName: function(newName, info){
|
|
|
|
//Reduce new name
|
|
if(newName.length > 18)
|
|
newName = newName.slice(0, 17) + "...";
|
|
|
|
//Empty name field
|
|
emptyElem(info.boxTitle);
|
|
|
|
//Create conversation icon
|
|
createElem2({
|
|
type: "i",
|
|
appendTo: info.boxTitle,
|
|
class: "fa fa-comments",
|
|
ondblclick: () => {
|
|
openConversation(info.conversationID, true);
|
|
info.closeFunction();
|
|
}
|
|
});
|
|
|
|
|
|
//Add conversation title
|
|
var conversationTitle = createElem("span", info.boxTitle);
|
|
conversationTitle.innerHTML = " " + newName;
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Update conversation members list
|
|
*
|
|
* @param {Object} conv Information about the conversation
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
updateMembersList: function(info) {
|
|
|
|
//First, make sure conversation members pane is empty
|
|
emptyElem(info.box.membersList);
|
|
|
|
/** @type {Conversation} */
|
|
const conv = info.infos;
|
|
let isAdmin = conv.members.find(m => m.user_id == userID()).is_admin;
|
|
let canAddUser = conv.group_id == null && (conv.can_everyone_add_members || isAdmin);
|
|
let canRemoveUsers = isAdmin && canAddUser;
|
|
|
|
// =================== Add a member ===================
|
|
if (canAddUser) {
|
|
//Create form container
|
|
var addUserForm = createElem2({
|
|
appendTo: info.box.membersList,
|
|
type: "form",
|
|
class: "invite-user-form"
|
|
});
|
|
|
|
//Form input
|
|
let userInput = createFormGroup({
|
|
target: addUserForm,
|
|
multiple: false,
|
|
placeholder: "Select user",
|
|
type: "select2"});
|
|
userInput.parentNode.className = "input-group";
|
|
|
|
ComunicWeb.components.userSelect.init(userInput);
|
|
|
|
//Add submit button
|
|
var groupsButton = createElem2({
|
|
appendTo: userInput.parentNode,
|
|
type: "div",
|
|
class: "input-group-btn"
|
|
});
|
|
|
|
createElem2({
|
|
appendTo: groupsButton,
|
|
type: "button",
|
|
elemType: "submit",
|
|
class: "btn btn-primary",
|
|
innerHTML: "Add"
|
|
});
|
|
|
|
addUserForm.addEventListener("submit", async e => {
|
|
try {
|
|
e.preventDefault();
|
|
|
|
//Get the list of selected users
|
|
var usersToInvite = ComunicWeb.components.userSelect.getResults(userInput);
|
|
|
|
//Check if there is not any user to invite
|
|
if(usersToInvite.length == 0){
|
|
notify(tr("Please choose a user to add!"), "danger");
|
|
return;
|
|
}
|
|
|
|
await ConversationsInterface.addUser(conv.id, usersToInvite[0]);
|
|
|
|
ConvChatWindow.reload(info)
|
|
}
|
|
|
|
catch(e)
|
|
{
|
|
console.error(e);
|
|
notify(tr("Failed to update conversation settings!"), "danger")
|
|
}
|
|
|
|
})
|
|
}
|
|
|
|
// =================== / Add a member ===================
|
|
|
|
// Then process each user
|
|
for(let member of conv.members) {
|
|
let user = info.membersInfos.get(member.user_id);
|
|
if(!user)
|
|
continue;
|
|
|
|
//Display user informations
|
|
var userLi = createElem("li", info.box.membersList);
|
|
var userLink = createElem("a", userLi);
|
|
|
|
//Add user account image
|
|
var userImage = createElem("img", userLink);
|
|
userImage.className = "contacts-list-img";
|
|
userImage.src = user.image;
|
|
|
|
//Add member informations
|
|
var memberInfosList = createElem2({
|
|
type: "div",
|
|
appendTo: userLink,
|
|
class: "contacts-list-info",
|
|
});
|
|
|
|
//Add user name
|
|
var memberName = createElem2({
|
|
type: "span",
|
|
appendTo: memberInfosList,
|
|
class: "contacts-list-name",
|
|
innerHTML: user.fullName,
|
|
});
|
|
|
|
//Add member status
|
|
let status = createElem2({
|
|
type: "span",
|
|
appendTo: memberInfosList,
|
|
class: "contacts-list-msg",
|
|
innerHTML: (member.is_admin ? tr("Admin") : tr("Member")) + " "
|
|
});
|
|
|
|
|
|
// Set / unset admin
|
|
if(canRemoveUsers && member.user_id != userID()) {
|
|
let removeLink = createElem2({
|
|
type: "a",
|
|
appendTo: status,
|
|
innerHTML: (member.is_admin ? tr("Unset admin") : tr("Set admin"))
|
|
})
|
|
|
|
removeLink.addEventListener("click", async e => {
|
|
e.preventDefault();
|
|
|
|
try {
|
|
await ConversationsInterface.toggleAdminStatus(conv.id, member.user_id, !member.is_admin);
|
|
|
|
ConvChatWindow.reload(info);
|
|
} catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to toggle admin status of %1%!", {"1": user.fullName}), "danger");
|
|
}
|
|
})
|
|
}
|
|
|
|
add_space(status)
|
|
|
|
// Remove user
|
|
if(canRemoveUsers && member.user_id != userID()) {
|
|
let removeLink = createElem2({
|
|
type: "a",
|
|
appendTo: status,
|
|
innerHTML: tr("Remove")
|
|
})
|
|
|
|
removeLink.addEventListener("click", async e => {
|
|
e.preventDefault();
|
|
|
|
if(!await showConfirmDialog(tr("Do you really want to remove %1% from the conversation?", {"1": user.fullName})))
|
|
return;
|
|
|
|
try {
|
|
await ConversationsInterface.removeUser(conv.id, member.user_id);
|
|
|
|
ConvChatWindow.reload(info);
|
|
} catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to remove %1% from the conversation!", {"1": user.fullName}), "danger");
|
|
}
|
|
})
|
|
}
|
|
|
|
// Leave conversation
|
|
if(member.user_id == userID()) {
|
|
let removeLink = createElem2({
|
|
type: "a",
|
|
appendTo: status,
|
|
innerHTML: tr("Leave")
|
|
})
|
|
|
|
removeLink.addEventListener("click", async e => {
|
|
e.preventDefault();
|
|
|
|
const isLastAdmin = conv.members.filter(m => m.is_admin && m.user_id != userID()).length == 0;
|
|
const msg = isLastAdmin ? tr("As you are its last admin, if you leave this conversation, it will be permanently deleted!")
|
|
: tr("Do you really want to leave this conversation?");
|
|
|
|
if(!await showConfirmDialog(msg))
|
|
return;
|
|
|
|
try {
|
|
await ConversationsInterface.leaveConversation(conv.id, member.user_id);
|
|
|
|
// Close the conversation
|
|
info.box.closeFunction();
|
|
} catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to leave conversation!"), "danger");
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
//Enable slimscrooll
|
|
$(info.box.membersList).slimscroll({
|
|
height: "100%",
|
|
color: "#FFFFFF"
|
|
});
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Show conversation settings (button + pane)
|
|
*
|
|
* @param {Object} conversation Informations about the conversation
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
showConversationSettings: function(conversation){
|
|
|
|
//First, check conversation settings button and pane don't exists yet
|
|
if(conversation.box.settingsButton && conversation.box.settingsButton.remove){
|
|
conversation.box.settingsButton.remove();
|
|
}
|
|
if(conversation.box.settingsPane && conversation.box.settingsPane.remove){
|
|
conversation.box.settingsPane.remove();
|
|
}
|
|
|
|
//Create and display conversation settings button wheel
|
|
conversation.box.settingsButton = createElem2({
|
|
type: "button",
|
|
insertBefore: conversation.box.membersButton,
|
|
class: "btn btn-box-tool",
|
|
type: "button"
|
|
});
|
|
|
|
//Add button icon
|
|
createElem2({
|
|
type: "i",
|
|
appendTo: conversation.box.settingsButton,
|
|
class: "fa fa-gear",
|
|
});
|
|
|
|
//Create settings pane
|
|
var settingsPane = createElem2({
|
|
type: "div",
|
|
appendTo: conversation.box.boxBody,
|
|
class: "conversation-settings-pane",
|
|
});
|
|
conversation.box.settingsPane = settingsPane;
|
|
|
|
//Make the settings button lives
|
|
conversation.box.settingsButton.onclick = function(){
|
|
//Update settings pane classname
|
|
if(settingsPane.className.includes(" open"))
|
|
settingsPane.className = settingsPane.className.replace(" open", ""); //Close the pane
|
|
else
|
|
settingsPane.className += " open"; //Open the pane
|
|
};
|
|
|
|
//Create the conversation form
|
|
const settingsForm = ConversationsUtils.createConversationForm(settingsPane);
|
|
|
|
//Update form informations
|
|
settingsForm.createButton.innerHTML = "Update settings";
|
|
|
|
//Update conversation name
|
|
if(conversation.infos.name)
|
|
settingsForm.conversationNameInput.value = conversation.infos.name;
|
|
|
|
// Apply conversation color
|
|
if (conversation.infos.color) {
|
|
settingsForm.conversationColorInput.value = "#" + conversation.infos.color;
|
|
settingsForm.conversationColorInput.dispatchEvent(new CustomEvent("change"))
|
|
}
|
|
|
|
//Update conversation members
|
|
ComunicWeb.components.userSelect.pushEntries(settingsForm.usersElement, conversation.infos.members.map(m => m.user_id));
|
|
|
|
// Update checkbox to allow or not everyone to add members
|
|
$(settingsForm.allowEveryoneToAddMembers).iCheck(conversation.infos.can_everyone_add_members ? "check" : "uncheck");
|
|
|
|
settingsForm.usersElement.parentNode.style.display = "none";
|
|
|
|
//Check if user is a conversation moderator or not
|
|
if(!conversation.infos.members.find(m => m.user_id == userID()).is_admin) {
|
|
settingsForm.conversationNameInput.disabled = true;
|
|
settingsForm.conversationColorInput.parentNode.parentNode.style.display = "none";
|
|
|
|
settingsForm.allowEveryoneToAddMembers.parentNode.parentNode.remove();
|
|
}
|
|
|
|
//Update follow conversation checkbox status
|
|
$(settingsForm.followConversationInput).iCheck(conversation.infos.members.find(m => m.user_id == userID()).following ? "check" : "uncheck");
|
|
|
|
//Save settings form in global form
|
|
conversation.settingsForm = settingsForm;
|
|
|
|
//Make update settings button lives
|
|
settingsForm.createButton.onclick = () => {
|
|
this.submitUpdateForm(conversation);
|
|
};
|
|
|
|
|
|
// Add conversation image section
|
|
if (conversation.infos.members.find(m => m.user_id == userID()).is_admin) {
|
|
|
|
const convImageSection = createElem2({
|
|
appendTo: settingsForm.rootElem,
|
|
type: "div",
|
|
class: "conversation-image-settings",
|
|
innerHTML: "<br/><br/><p><strong>" + tr("Conversation image") + "</strong></p>"
|
|
})
|
|
|
|
|
|
// Show current
|
|
if (conversation.infos.logo != null) {
|
|
createElem2({
|
|
appendTo: convImageSection,
|
|
type: "img",
|
|
src: conversation.infos.logo,
|
|
class: "current-image"
|
|
})
|
|
}
|
|
|
|
|
|
// Upload a new logo
|
|
const newConvImagebutton = createElem2({
|
|
appendTo: convImageSection,
|
|
type: "button",
|
|
class: "btn btn-default",
|
|
innerHTML: tr("Upload a new conversation logo")
|
|
});
|
|
|
|
newConvImagebutton.addEventListener("click", async e => {
|
|
e.preventDefault();
|
|
try {
|
|
await ConversationsUtils.uploadNewConversationImage(conversation.infos.id);
|
|
ConvChatWindow.reload(conversation)
|
|
} catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to change conversation image!"), "danger");
|
|
}
|
|
})
|
|
|
|
|
|
// Delete current image
|
|
if (conversation.infos.logo != null) {
|
|
const deleteConvImage = createElem2({
|
|
appendTo: convImageSection,
|
|
type: "button",
|
|
class: "btn btn-danger",
|
|
innerHTML: tr("Delete current logo")
|
|
});
|
|
|
|
deleteConvImage.addEventListener("click", async e => {
|
|
e.preventDefault();
|
|
try {
|
|
if (!await showConfirmDialog(tr("Do you really want to delete this image ?")))
|
|
return;
|
|
|
|
await ConversationsInterface.deleteConversationImage(conversation.infos.id);
|
|
ConvChatWindow.reload(conversation)
|
|
} catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to remove conversation image!"), "danger");
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Add a call button to the conversation, if possible
|
|
*
|
|
* @param {Object} conversation Information about the conversation
|
|
*/
|
|
showCallButton: function(conversation){
|
|
|
|
// Remove previous button (if any)
|
|
let previousButton = conversation.box.boxTools.querySelector(".phone-button");
|
|
if(previousButton)
|
|
previousButton.remove();
|
|
|
|
//Check if calls are disabled
|
|
if(!conversation.infos.can_have_call)
|
|
return;
|
|
|
|
//Add the call button
|
|
const button = createElem2({
|
|
insertBefore: conversation.box.boxTools.firstChild,
|
|
type: "button",
|
|
class: "btn btn-box-tool phone-button",
|
|
innerHTML: "<i class='fa fa-phone'></i>"
|
|
});
|
|
conversation.box.callButton = button;
|
|
|
|
button.addEventListener("click", function(){
|
|
CallsController.Open(conversation.infos)
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Process submited update conversation form
|
|
*
|
|
* @param {Object} conversation Information about the conversation
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
submitUpdateForm: function(conversation){
|
|
|
|
//Then, get information about the input
|
|
var newValues = {
|
|
conversationID: conversation.infos.id,
|
|
following: conversation.settingsForm.followConversationInput.checked,
|
|
}
|
|
|
|
//Add other fields if the user is a conversation moderator
|
|
if(conversation.infos.members.find(m => m.user_id == userID()).is_admin){
|
|
//Specify conversation name
|
|
let nameValue = conversation.settingsForm.conversationNameInput.value
|
|
newValues.name = (nameValue === "" ? null : nameValue);
|
|
|
|
let colorValue = conversation.settingsForm.conversationColorInput.value
|
|
newValues.color = (colorValue == "" ? null : colorValue)
|
|
|
|
newValues.canEveryoneAddMembers = conversation.settingsForm.allowEveryoneToAddMembers.checked;
|
|
|
|
}
|
|
|
|
//Now, freeze the submit button
|
|
conversation.settingsForm.createButton.disabled = true;
|
|
|
|
//Peform a request through the interface
|
|
ConversationsInterface.updateSettings(newValues, function(result){
|
|
|
|
//Enable again update button
|
|
conversation.settingsForm.createButton.disabled = false;
|
|
|
|
//Check for errors
|
|
if(result.error)
|
|
notify("An error occured while trying to update conversation settings !", "danger", 4);
|
|
|
|
//Reload the conversation
|
|
ConvChatWindow.reload(conversation);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Reload the conversation
|
|
*
|
|
* @param {Object} conversation Information about the conversation
|
|
*/
|
|
reload: function(conversation) {
|
|
ConvChatWindow.unload(conversation.infos.id, true);
|
|
ConvChatWindow.load(conversation.infos.id, conversation.box, true);
|
|
},
|
|
|
|
/**
|
|
* Submit a new message form
|
|
*
|
|
* @param {Object} convInfos Information about the conversation
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
submitMessageForm: async function(convInfos){
|
|
|
|
try {
|
|
|
|
//Extract main fields
|
|
var form = convInfos.box.sendMessageForm;
|
|
|
|
//Check if message is empty.
|
|
let message = form.inputText.value;
|
|
|
|
if (message.length == 0)
|
|
return;
|
|
|
|
if(message.length < ServerConfig.conf.min_conversation_message_len || message.length > ServerConfig.conf.max_conversation_message_len){
|
|
notify(tr("Invalid message length!"), "danger", 2);
|
|
return;
|
|
}
|
|
|
|
//Lock send button
|
|
form.sendButton.disabled = true;
|
|
|
|
await ConversationsInterface.sendMessage(convInfos.infos.id, message);
|
|
|
|
//Reset the form
|
|
ConvChatWindow.resetCreateMessageForm(convInfos);
|
|
}
|
|
|
|
catch(e)
|
|
{
|
|
console.error(e)
|
|
notify(tr("An error occured while trying to send message! Please try again..."), "danger", 2);
|
|
}
|
|
|
|
//Unlock send button
|
|
form.sendButton.disabled = false;
|
|
},
|
|
|
|
/**
|
|
* Reset a create a message form
|
|
*
|
|
* @param {Object} infos Information about the conversation
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
resetCreateMessageForm: function(infos){
|
|
|
|
//Extract form informations
|
|
var form = infos.box.sendMessageForm;
|
|
|
|
//Unlock send button and reset its value
|
|
form.sendButton.disabled = false;
|
|
|
|
//Empty textarea
|
|
form.inputText.value = "";
|
|
form.textarea2.resetHeight();
|
|
},
|
|
|
|
/**
|
|
* Add a message to a conversation window
|
|
*
|
|
* @param {Integer} conversationID The ID of the conversation to update
|
|
* @param {Object} messageInfo Information about the message to add
|
|
* @return {Boolean} True for a success
|
|
*/
|
|
addMessage: function(conversationID, messageInfo){
|
|
|
|
//First, check if the conversation information can be found
|
|
if(!this.__conversationsCache["conversation-"+conversationID]){
|
|
ComunicWeb.debug.logMessage("Conversation Chat Windows : Error ! Couldn't add a message to the conversation because the conversation was not found !");
|
|
return false;
|
|
}
|
|
|
|
//Else extract conversation informations
|
|
var convInfos = this.__conversationsCache["conversation-"+conversationID];
|
|
|
|
//Check if this is the first message of the conversation or not
|
|
if(!convInfos.messages){
|
|
convInfos.messages = [];
|
|
}
|
|
|
|
//Get message HTML element add append it
|
|
var uiMessageInfo = this._get_message_element(convInfos, messageInfo);
|
|
convInfos.box.messagesArea.appendChild(uiMessageInfo.rootElem);
|
|
|
|
//Perform post-processing operations
|
|
var num = convInfos.messages.push(uiMessageInfo);
|
|
|
|
//Check if it is not the first message from the current user
|
|
this._makeMessageFollowAnotherMessage(convInfos, num - 1);
|
|
|
|
//Enable slimscroll
|
|
$(convInfos.box.messagesArea).slimscroll({
|
|
height: "250px",
|
|
});
|
|
|
|
//Scroll to the bottom of the conversation
|
|
var scrollBottom = $(convInfos.box.messagesArea).prop("scrollHeight")+"px";
|
|
$(convInfos.box.messagesArea).slimScroll({
|
|
scrollTo: scrollBottom
|
|
});
|
|
|
|
//Initialize top scroll detection if required
|
|
this.initTopScrollDetection(conversationID);
|
|
|
|
//Success
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Add old messages to a conversation window
|
|
*
|
|
* @param {number} conversationID The ID of the target conversation
|
|
* @param {array} messages The list of messages to add
|
|
*/
|
|
addOldMessages: function(conversationID, messages){
|
|
|
|
//First, check if the conversation information can be found
|
|
if(!this.__conversationsCache["conversation-"+conversationID]){
|
|
ComunicWeb.debug.logMessage("Conversation Chat Windows : Error ! Couldn't add a message to the conversation because the conversation was not found !");
|
|
return false;
|
|
}
|
|
|
|
//Else extract conversation informations
|
|
var conv = this.__conversationsCache["conversation-"+conversationID];
|
|
|
|
//Save the position of the oldest message element
|
|
var currOldestMessageElem = conv.messages[0].rootElem;
|
|
|
|
//Process the list of messages in reverse order
|
|
messages.reverse();
|
|
messages.forEach(function(message){
|
|
|
|
//Get message element
|
|
var uiMessageInfo = ComunicWeb.components.conversations.chatWindows._get_message_element(conv, message);
|
|
|
|
//Add the messages at the begining of the conversation
|
|
conv.box.messagesArea.insertBefore(uiMessageInfo.rootElem, conv.messages[0].rootElem);
|
|
|
|
//Add the message to the list
|
|
conv.messages.unshift(uiMessageInfo);
|
|
|
|
//Check if some information about the post can be updated
|
|
ComunicWeb.components.conversations.chatWindows._makeMessageFollowAnotherMessage(conv, 1);
|
|
|
|
});
|
|
|
|
//Update slimscroll
|
|
newScrollPos = currOldestMessageElem.offsetTop - 30;
|
|
if(newScrollPos < 0)
|
|
newScrollPos = 0;
|
|
$(conv.box.messagesArea).slimScroll({
|
|
scrollTo: newScrollPos + "px"
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Generate message HTML node based on given information
|
|
*
|
|
* @param {object} conversationInfo Information about the created conversation
|
|
* @param {ConversationMessage} message Information about the target message
|
|
* @return {object} Information about the created message element
|
|
*/
|
|
_get_message_element: function(conversationInfo, message){
|
|
if (message.user_id != null && message.user_id > 0)
|
|
return this._get_user_message(conversationInfo, message);
|
|
|
|
else
|
|
return this._get_server_message(conversationInfo, message);
|
|
},
|
|
|
|
/**
|
|
* @param {Object} conversationInfo
|
|
* @param {ConversationMessage} message
|
|
*/
|
|
_get_user_message: (conversationInfo, message) => {
|
|
//Check if it is the current user who sent the message
|
|
var userIsPoster = message.user_id == userID();
|
|
|
|
//Create message element
|
|
const messageContainer = createElem2({
|
|
type: "div",
|
|
class: "direct-chat-msg " + (userIsPoster ? "right" : "")
|
|
});
|
|
messageContainer.setAttribute("data-chatwin-msg-id", message.id)
|
|
|
|
//Display message header
|
|
var messageHeader = createElem2({
|
|
appendTo: messageContainer,
|
|
type: "div",
|
|
class: "direct-chat-info clearfix"
|
|
});
|
|
|
|
//Add top information
|
|
var topInfosElem = createElem2({
|
|
appendTo: messageHeader,
|
|
type: "div",
|
|
class: "direct-chat-name pull-" + (userIsPoster ? "right" : "left"),
|
|
});
|
|
|
|
//Add user name
|
|
var usernameElem = createElem2({
|
|
appendTo: topInfosElem,
|
|
type: "span",
|
|
innerHTML: "Loading",
|
|
});
|
|
|
|
//Hide user name if it is the current user
|
|
if(userIsPoster)
|
|
usernameElem.style.display = "none";
|
|
|
|
//Add user account image
|
|
var userAccountImage = createElem2({
|
|
appendTo: messageContainer,
|
|
type: "img",
|
|
class: "direct-chat-img",
|
|
src: ComunicWeb.__config.assetsURL + "img/defaultAvatar.png",
|
|
alt: "User account image",
|
|
});
|
|
|
|
//Load user informations
|
|
let userInfo = conversationInfo.membersInfos.get(message.user_id);
|
|
if(userInfo) {
|
|
usernameElem.innerHTML = userInfo.fullName;
|
|
userAccountImage.src = userInfo.image;
|
|
}
|
|
|
|
else {
|
|
async () => {
|
|
try {
|
|
const userInfo = await userInfo(message.user_id);
|
|
usernameElem.innerHTML = userInfo.fullName;
|
|
userAccountImage.src = userInfo.image;
|
|
} catch(e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Add message
|
|
var messageTargetElem = createElem2({
|
|
appendTo: messageContainer,
|
|
type: "div",
|
|
class: "direct-chat-text ",
|
|
});
|
|
|
|
//Add text message
|
|
var textMessage = createElem2({
|
|
appendTo: messageTargetElem,
|
|
type: "span",
|
|
innerHTML: removeHtmlTags(message.message), //Remove HTML tags
|
|
});
|
|
|
|
//Check if an image has to be added
|
|
if(message.file != null){
|
|
const messageFile = message.file;
|
|
|
|
if (messageFile.type == "image/png") {
|
|
var imageLink = createElem2({
|
|
appendTo: messageTargetElem,
|
|
type: "a",
|
|
href: messageFile.url
|
|
});
|
|
|
|
//Apply image
|
|
createElem2({
|
|
appendTo: imageLink,
|
|
type: "img",
|
|
class: "conversation-msg-image",
|
|
src: messageFile.thumbnail == null ? messageFile.url : messageFile.thumbnail
|
|
});
|
|
|
|
imageLink.onclick = function(){
|
|
$(this).ekkoLightbox({
|
|
alwaysShowClose: true,
|
|
});
|
|
return false;
|
|
};
|
|
}
|
|
|
|
else if(messageFile.type == "audio/mpeg") {
|
|
new SmallMediaPlayer(messageTargetElem, messageFile.url, false)
|
|
}
|
|
|
|
else if(messageFile.type == "video/mp4") {
|
|
new SmallMediaPlayer(messageTargetElem, messageFile.url, true)
|
|
}
|
|
|
|
// Fallback
|
|
else {
|
|
let letFileLink = createElem2({
|
|
appendTo: messageTargetElem,
|
|
type: "a",
|
|
href: messageFile.url,
|
|
innerHTML: "<i class='fa fa-download'></i> "+ messageFile.name + " ("+fileSizeToHuman(messageFile.size)+")",
|
|
})
|
|
letFileLink.target = "_blank"
|
|
}
|
|
}
|
|
|
|
//Add date
|
|
var dateElem = createElem2({
|
|
appendTo: messageContainer,
|
|
type: "div",
|
|
class: "date-conversation-message",
|
|
innerHTML: ComunicWeb.common.date.timeDiffToStr(message.time_sent)
|
|
});
|
|
|
|
//Parse emojies in text message
|
|
ComunicWeb.components.textParser.parse({
|
|
element: textMessage,
|
|
user: userInfo,
|
|
});
|
|
|
|
|
|
//Add message dropdown menu
|
|
messageContainer.className += " dropdown";
|
|
|
|
var dropdownToggle = createElem2({
|
|
insertBefore: dateElem,
|
|
type: "i",
|
|
class: "hidden"
|
|
});
|
|
dropdownToggle.setAttribute("data-toggle", "dropdown");
|
|
|
|
var dropdownMenu = createElem2({
|
|
insertBefore: dateElem,
|
|
type: "ul",
|
|
class: "dropdown-menu"
|
|
});
|
|
dropdownMenu.setAttribute("role", "menu");
|
|
|
|
messageTargetElem.addEventListener("dblclick", function(){
|
|
$(dropdownToggle).dropdown("toggle");
|
|
});
|
|
|
|
//Add message options
|
|
if(userIsPoster){
|
|
|
|
if (message.file == null)
|
|
{
|
|
//Update message content
|
|
var updateLi = createElem2({
|
|
type: "li",
|
|
appendTo: dropdownMenu
|
|
});
|
|
|
|
var updateLink = createElem2({
|
|
type: "a",
|
|
appendTo: updateLi,
|
|
innerHTML: "Edit"
|
|
});
|
|
|
|
updateLink.addEventListener("click", function(){
|
|
ComunicWeb.components.conversations.messageEditor.open(message, function(newContent){
|
|
/*
|
|
DEPRECATED WITH WEBSOCKETS
|
|
*/
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
//Delete the message
|
|
var deleteLi = createElem2({
|
|
type: "li",
|
|
appendTo: dropdownMenu
|
|
});
|
|
|
|
var deleteLink = createElem2({
|
|
type: "a",
|
|
appendTo: deleteLi,
|
|
innerHTML: "Delete"
|
|
});
|
|
|
|
deleteLink.addEventListener("click", function(){
|
|
ComunicWeb.common.messages.confirm(
|
|
"Do you really want to delete this message? The operation can not be reverted!",
|
|
function(confirm){
|
|
if(!confirm) return;
|
|
|
|
//Hide the message
|
|
messageTargetElem.style.display = "none";
|
|
|
|
//Execute the request
|
|
ConversationsInterface.DeleteSingleMessage(
|
|
message.id,
|
|
function(result){
|
|
if(!result){
|
|
messageTargetElem.style.display = "block";
|
|
notify("Could delete conversation message!", "danger");
|
|
}
|
|
}
|
|
);
|
|
}
|
|
)
|
|
});
|
|
|
|
}
|
|
|
|
//Return information about the message
|
|
return {
|
|
userID: message.user_id,
|
|
rootElem: messageContainer,
|
|
userNameElem: usernameElem,
|
|
dateElem: dateElem,
|
|
time_sent: message.time_sent,
|
|
messageTargetElem: messageTargetElem,
|
|
accountImage: userAccountImage
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
* Apply a server message
|
|
*
|
|
* @param {Object} convInfo Information about the conversation
|
|
* @param {ConversationMessage} message The message
|
|
*/
|
|
_get_server_message: (convInfo, message) => {
|
|
|
|
//Create message element
|
|
const messageContainer = createElem2({
|
|
type: "div",
|
|
class: "direct-chat-msg "
|
|
});
|
|
messageContainer.setAttribute("data-chatwin-msg-id", message.id);
|
|
|
|
//Add message
|
|
let messageTargetElem = createElem2({
|
|
appendTo: messageContainer,
|
|
type: "div",
|
|
class: "server_message",
|
|
});
|
|
|
|
(async () => {
|
|
try {
|
|
|
|
let ids = ConversationsUtils.getUsersIDForMessage(message)
|
|
let users = await getUsers(ids);
|
|
let msg = ConversationsUtils.getServerMessage(message, users);
|
|
|
|
messageTargetElem.innerHTML = msg
|
|
|
|
}
|
|
catch(e) {
|
|
console.error(e);
|
|
notify(tr("Failed to load a server message!"))
|
|
}
|
|
})();
|
|
|
|
return {
|
|
userID: null,
|
|
rootElem: messageContainer,
|
|
userNameElem: document.createElement("span"),
|
|
dateElem: document.createElement("span"),
|
|
time_sent: message.time_sent,
|
|
messageTargetElem: messageTargetElem,
|
|
accountImage: document.createElement("span")
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Make a conversation message "follow" another conversation message from the
|
|
* same user
|
|
*
|
|
* @param {object} conv Information about the target conversation
|
|
* @param {number} num The number of the conversation message to update
|
|
*/
|
|
_makeMessageFollowAnotherMessage: function(conv, num){
|
|
|
|
if(conv.messages[num - 1]){
|
|
|
|
if(conv.messages[num-1].userID == conv.messages[num].userID){
|
|
|
|
//Update object class name
|
|
conv.messages[num].messageTargetElem.className += " not-first-message";
|
|
|
|
//Hide user name and account image
|
|
conv.messages[num].userNameElem.style.display = "none";
|
|
conv.messages[num].accountImage.style.display = "none";
|
|
|
|
//Update the class of the previous message
|
|
conv.messages[num-1].rootElem.className += " not-last-message-from-user";
|
|
|
|
}
|
|
|
|
|
|
//Check the difference of time between the two messages
|
|
if(conv.messages[num].time_sent - conv.messages[num - 1].time_sent < 3600
|
|
|| conv.messages[num].dateElem.innerHTML == conv.messages[num - 1].dateElem.innerHTML)
|
|
conv.messages[num].dateElem.style.display = "none";
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
* Init top scroll detection (if required)
|
|
*
|
|
* @param {number} conversationID The ID of the target conversation
|
|
*/
|
|
initTopScrollDetection: function(conversationID){
|
|
|
|
//Extract conversation informations
|
|
var convInfo = this.__conversationsCache["conversation-"+conversationID];
|
|
|
|
//Check if nothing has to be done
|
|
if(convInfo.box.initializedScrollDetection)
|
|
return;
|
|
|
|
//Mark scroll detection as initialized
|
|
convInfo.box.initializedScrollDetection = true;
|
|
|
|
var scrollDetectionLocked = false;
|
|
var scrollTopCount = 0;
|
|
$(convInfo.box.messagesArea).slimScroll().bind("slimscrolling", function(e, pos){
|
|
|
|
if(scrollDetectionLocked)
|
|
return;
|
|
|
|
if(pos != 0){
|
|
scrollTopCount = 0;
|
|
}
|
|
|
|
scrollTopCount++;
|
|
|
|
//Check top count
|
|
if(scrollTopCount < 3)
|
|
return;
|
|
|
|
//Lock the detection
|
|
scrollDetectionLocked = true;
|
|
|
|
//Fetch older messages
|
|
ConversationsInterface.getOlderMessages(
|
|
conversationID,
|
|
ConvService.getOldestMessageID(conversationID),
|
|
10,
|
|
function(result){
|
|
|
|
//Unlock scroll detection
|
|
scrollDetectionLocked = false;
|
|
|
|
//Check for errors
|
|
if(result.error){
|
|
notify("An error occured while trying to fetch older messages for the conversation !");
|
|
return;
|
|
}
|
|
|
|
//Check for results
|
|
if(result.length == 0){
|
|
//Lock scroll detection in order to avoid useless traffic
|
|
scrollDetectionLocked = true;
|
|
return;
|
|
}
|
|
|
|
//Save the ID of the oldest message
|
|
ConvService.setOldestMessageID(conversationID, result[0].id);
|
|
|
|
//Display the list of messages
|
|
ComunicWeb.components.conversations.chatWindows.addOldMessages(conversationID, result);
|
|
}
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
ComunicWeb.components.conversations.chatWindows = ConvChatWindow;
|
|
|
|
//Register conversations cache cleaning function
|
|
ComunicWeb.common.cacheManager.registerCacheCleaner("ComunicWeb.components.conversations.chatWindows.unloadAll");
|
|
|
|
// Register to messages update events
|
|
document.addEventListener("updatedConvMessage", (e) => {
|
|
const msg = e.detail;
|
|
|
|
// Get message target
|
|
const target = document.querySelector("[data-chatwin-msg-id='"+msg.id+"']");
|
|
if(!target)
|
|
return;
|
|
|
|
|
|
// Get conversation info
|
|
const convInfo = ConvChatWindow.__conversationsCache["conversation-"+msg.conv_id];
|
|
if(!convInfo)
|
|
return;
|
|
|
|
|
|
target.replaceWith(ConvChatWindow._get_message_element(convInfo, msg).rootElem)
|
|
});
|
|
|
|
// Register to message deletion events
|
|
document.addEventListener("deletedConvMessage", (e) => {
|
|
const msgID = e.detail;
|
|
|
|
// Get message target
|
|
const target = document.querySelector("[data-chatwin-msg-id='"+msgID+"'] .direct-chat-text");
|
|
if(!target)
|
|
return;
|
|
|
|
target.style.display = "none";
|
|
})
|
|
|
|
|
|
// Register to conversation removal
|
|
document.addEventListener("removedUserFromConv", e => {
|
|
const msg = e.detail;
|
|
|
|
if (msg.user_id != userID())
|
|
return;
|
|
|
|
if(!ConvService.__serviceCache.hasOwnProperty("conversation-" + msg.conv_id))
|
|
return;
|
|
|
|
ConvChatWindow.__conversationsCache["conversation-"+msg.conv_id].box.closeFunction();
|
|
}); |