2020-05-27 17:33:42 +00:00
|
|
|
import * as DOMPurify from "dompurify";
|
|
|
|
import * as log from "loglevel";
|
2019-12-12 12:53:41 +00:00
|
|
|
import { ChatMessageDTO } from "../dto/ChatMessageDTO";
|
2019-12-07 15:15:50 +00:00
|
|
|
import { MessageCipherDTO } from "../dto/MessageCipherDTO";
|
2019-12-12 12:53:41 +00:00
|
|
|
import { ChatModel } from "../model/ChatModel";
|
|
|
|
import { Observer } from "../observe/Observer";
|
2019-12-07 15:15:50 +00:00
|
|
|
import { EncryptionService } from "../service/EncryptionService";
|
2019-12-12 12:53:41 +00:00
|
|
|
import { MarkDownService } from "../service/MarkDownService";
|
|
|
|
import { JsonAPI } from "../singleton/JsonAPI";
|
|
|
|
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
2019-12-11 10:30:45 +00:00
|
|
|
import { ChatViewDeps } from "./ChatViewDeps";
|
2019-12-12 12:53:41 +00:00
|
|
|
import { fetchHandler } from "./FetchHandler";
|
2020-05-27 17:33:42 +00:00
|
|
|
import { ObserverData } from "../observe/ObserverData";
|
|
|
|
import { NotificationService } from "../service/NotificationService";
|
|
|
|
import { UserModel } from "../model/UserModel";
|
2019-12-06 14:21:07 +00:00
|
|
|
|
2020-01-27 16:13:38 +00:00
|
|
|
export class ChatView implements Observer<ChatMessageViewModel> {
|
2020-05-27 17:33:42 +00:00
|
|
|
private readonly _chatModel: ChatModel;
|
|
|
|
private readonly _messageContainer: HTMLElement;
|
|
|
|
private readonly _messageSendTemplate: Handlebars.TemplateDelegate<
|
|
|
|
ChatMessageViewModel
|
|
|
|
>;
|
|
|
|
private readonly _messageReceiveTemplate: Handlebars.TemplateDelegate<
|
|
|
|
ChatMessageViewModel
|
|
|
|
>;
|
|
|
|
private readonly _markdownService: MarkDownService;
|
|
|
|
private readonly _encryptionService: EncryptionService;
|
|
|
|
private readonly _notificationService: NotificationService;
|
|
|
|
private readonly _userModel: UserModel;
|
|
|
|
|
|
|
|
constructor(deps: ChatViewDeps) {
|
|
|
|
this._messageContainer = deps.messageContainer;
|
|
|
|
this._chatModel = deps.chatModel;
|
|
|
|
this._messageSendTemplate = deps.messageSendTemplate;
|
|
|
|
this._messageReceiveTemplate = deps.messageReceiveTemplate;
|
|
|
|
this._markdownService = deps.markdownService;
|
|
|
|
this._encryptionService = deps.encryptionService;
|
|
|
|
this._notificationService = deps.notificationService;
|
|
|
|
this._userModel = deps.userModel;
|
|
|
|
this._initEventListeners();
|
|
|
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
$("#action_menu_btn").click(function () {
|
|
|
|
$(".action_menu").toggle();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
this._chatMessagePageLoadAjax();
|
|
|
|
}
|
|
|
|
|
|
|
|
update(cd: ObserverData<ChatMessageViewModel>): void {
|
|
|
|
log.info("ChatView: updating view");
|
|
|
|
|
|
|
|
switch (cd.op) {
|
|
|
|
case "clear":
|
|
|
|
{
|
|
|
|
$(this._messageContainer).html("");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "new":
|
|
|
|
{
|
|
|
|
cd.data.forEach((vm: ChatMessageViewModel) => {
|
|
|
|
let rendered = this.renderMessage(vm);
|
|
|
|
$(this._messageContainer).append(rendered);
|
|
|
|
});
|
|
|
|
$(this._messageContainer)
|
|
|
|
.stop()
|
|
|
|
.animate(
|
|
|
|
{
|
|
|
|
scrollTop: $(this._messageContainer)[0].scrollHeight,
|
|
|
|
},
|
|
|
|
1500
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "update":
|
|
|
|
{
|
|
|
|
cd.data.forEach((vm: ChatMessageViewModel) => {
|
|
|
|
let rendered = this.renderMessage(vm);
|
|
|
|
$(this._messageContainer).append(rendered);
|
|
|
|
});
|
|
|
|
// if (cd.data.length > 0) {
|
|
|
|
// this._userModel.notify();
|
|
|
|
// }
|
2020-05-30 05:21:24 +00:00
|
|
|
$(this._messageContainer)
|
2020-06-19 11:48:31 +00:00
|
|
|
.stop()
|
|
|
|
.animate(
|
|
|
|
{
|
|
|
|
scrollTop: $(this._messageContainer)[0].scrollHeight,
|
|
|
|
},
|
|
|
|
1500
|
|
|
|
);
|
2020-05-27 17:33:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "page":
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const rev: ChatMessageViewModel[] = Object.create(cd.data);
|
|
|
|
rev.reverse();
|
|
|
|
rev.forEach((vm: ChatMessageViewModel) => {
|
|
|
|
let rendered = this.renderMessage(vm);
|
|
|
|
$(this._messageContainer).prepend(rendered);
|
2019-12-12 05:12:23 +00:00
|
|
|
});
|
2020-05-27 17:33:42 +00:00
|
|
|
}
|
2020-01-27 16:13:38 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
new Error("Invalid option");
|
2019-12-06 14:21:07 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private renderMessage(vm: ChatMessageViewModel): string {
|
|
|
|
const vmTemp: ChatMessageViewModel = { ...vm };
|
|
|
|
vmTemp.message = this._markdownService.render(vm.message);
|
|
|
|
switch (vmTemp.fromUser) {
|
|
|
|
case JsonAPI.principleName:
|
|
|
|
return DOMPurify.sanitize(this._messageSendTemplate(vmTemp));
|
|
|
|
default:
|
|
|
|
return DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp));
|
2019-12-07 15:15:50 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private _initEventListeners(): void {
|
|
|
|
this._addChatFormEL();
|
|
|
|
}
|
|
|
|
|
|
|
|
private _addChatFormEL() {
|
|
|
|
const chatForm = document.getElementById(
|
|
|
|
"chatMessageForm"
|
|
|
|
) as HTMLSelectElement;
|
|
|
|
|
|
|
|
if (chatForm == null) {
|
|
|
|
log.error("Chat form is null");
|
|
|
|
} else {
|
|
|
|
chatForm.addEventListener("submit", (e) =>
|
|
|
|
this._createChatMessageDTO(e, chatForm)
|
|
|
|
);
|
2019-12-07 15:15:50 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
}
|
2019-12-07 15:15:50 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
private _createChatMessageDTO(e: Event, chatForm: HTMLSelectElement): void {
|
|
|
|
e.preventDefault();
|
2019-12-07 15:15:50 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
let contactName = JsonAPI.contactName;
|
2019-12-07 15:15:50 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
if (!chatForm.checkValidity()) {
|
|
|
|
log.error("Form is not valid");
|
|
|
|
chatForm.classList.add("was-validated");
|
|
|
|
return;
|
2019-12-07 15:15:50 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
chatForm.classList.add("was-validated");
|
2019-12-07 15:15:50 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
const chatInput = document.getElementById("chatInput") as HTMLInputElement;
|
|
|
|
const vm = this._userModel.activeUsersList.find(
|
|
|
|
(u) => u.userName == JsonAPI.contactName
|
|
|
|
);
|
|
|
|
// new Date().
|
|
|
|
vm!.lastMessageTime = new Date();
|
2019-12-07 15:15:50 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
const passphrase = vm?.passphrase;
|
2019-12-12 12:29:42 +00:00
|
|
|
|
2020-05-27 17:33:42 +00:00
|
|
|
if (chatInput.value == "") {
|
|
|
|
this._notificationService.error("Please enter a message");
|
|
|
|
return;
|
2019-12-12 12:29:42 +00:00
|
|
|
}
|
2020-05-27 17:33:42 +00:00
|
|
|
|
|
|
|
// if (passphraseInput.value == '' || passphraseInput.value == null) {
|
|
|
|
// this._notificationService.error("Please enter a passphrase");
|
|
|
|
// log.error("Passphrase is null.");
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
const messageContent = chatInput.value;
|
|
|
|
vm!.lastMessageText = messageContent.slice(0, 15) + "...";
|
|
|
|
const msgTime = new Date();
|
|
|
|
const context: ChatMessageViewModel = {
|
|
|
|
fromUser: JsonAPI.principleName,
|
2020-06-20 08:18:55 +00:00
|
|
|
toUser: contactName,
|
2020-05-27 17:33:42 +00:00
|
|
|
message: messageContent,
|
|
|
|
messageTime: msgTime,
|
|
|
|
};
|
|
|
|
|
|
|
|
this.update({ data: new Array(context), op: "new" });
|
2020-06-19 11:48:31 +00:00
|
|
|
this._userModel.updateLastActive(contactName, msgTime)
|
2020-05-27 17:33:42 +00:00
|
|
|
this._userModel.notify();
|
|
|
|
|
|
|
|
let messageCipher: MessageCipherDTO = this._encryptionService.encrypt(
|
|
|
|
passphrase!,
|
|
|
|
messageContent
|
|
|
|
);
|
|
|
|
let chatMessageDTO = {
|
|
|
|
fromUser: JsonAPI.principleName,
|
|
|
|
toUser: contactName,
|
|
|
|
messageCipher: messageCipher,
|
2020-06-20 08:18:55 +00:00
|
|
|
messageTime: msgTime.toISOString(),
|
2020-05-27 17:33:42 +00:00
|
|
|
};
|
|
|
|
this._sendMessageAJAX(chatMessageDTO);
|
|
|
|
}
|
|
|
|
|
2020-06-20 08:18:55 +00:00
|
|
|
private _sendMessageAJAX(chatMessageDTO: any): void {
|
2020-05-27 17:33:42 +00:00
|
|
|
let headers = new Headers();
|
|
|
|
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
|
|
|
|
|
|
|
// headers.append('Accept','application/json')
|
|
|
|
headers.append("Content-Type", "application/json");
|
|
|
|
// headers.append('Authorization', basicAuthToken);
|
|
|
|
// @ts-ignore
|
|
|
|
headers.append("X-AUTH-TOKEN", JsonAPI.authToken);
|
|
|
|
fetch(JsonAPI.MESSAGE_POST, {
|
|
|
|
method: "POST",
|
|
|
|
headers: headers,
|
|
|
|
body: JSON.stringify(chatMessageDTO),
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
log.debug(response);
|
|
|
|
return response.clone();
|
|
|
|
})
|
|
|
|
.then((response) => fetchHandler(response, this._notificationService));
|
|
|
|
}
|
|
|
|
|
|
|
|
private _chatMessagePageLoadAjax() {
|
|
|
|
this._messageContainer.addEventListener("scroll", (e) => {
|
|
|
|
if (
|
|
|
|
$(this._messageContainer).scrollTop() == 0 &&
|
|
|
|
$(this._messageContainer).html() != ""
|
|
|
|
) {
|
|
|
|
let currentMsg = $(".msg:first");
|
|
|
|
log.debug("Reached top");
|
|
|
|
const vm = this._userModel.activeUsersList.find(
|
|
|
|
(u) => u.userName == JsonAPI.contactName
|
|
|
|
);
|
|
|
|
this._chatModel.getMessages(vm!, "page").then(() => {
|
|
|
|
if (currentMsg != null) {
|
|
|
|
// log.debug(currentMsg.offset()!.top)
|
|
|
|
$(this._messageContainer).scrollTop(
|
|
|
|
currentMsg.position().top - $(".msg").position()!.top
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|