Chat area is cleared when changing user
Also frontend code has een refactored significantly
This commit is contained in:
parent
52af8f39ba
commit
f34a5524fd
@ -9,7 +9,6 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -3,7 +3,6 @@ package org.ros.chatto.service;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -45,6 +45,6 @@
|
|||||||
"alertifyjs": "global:alertify"
|
"alertifyjs": "global:alertify"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch": "watchify ts/src/main.ts -p [ tsify --target es2017 --noImplicitAny ] --debug -o ../resources/static/js/bundle.js"
|
"watch": "watchify ts/src/main.ts -p [ tsify --target ES6 --noImplicitAny ] --debug -o ../resources/static/js/bundle.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,58 @@
|
|||||||
import { Controller } from "./controller/AbstractController";
|
|
||||||
import { UserModel } from "./model/UserModel"
|
|
||||||
import { Model } from "./model/AbstractModel";
|
|
||||||
import { View } from "./view/AbstractView";
|
|
||||||
import { UserView } from "./view/UserView";
|
|
||||||
import { UserController } from "./controller/UserController";
|
|
||||||
import { ModelFactory } from "./model/ModelFactory";
|
|
||||||
import { ActiveUserViewModel } from "./viewmodel/ActiveUserViewModel";
|
|
||||||
import { ChatMessageViewModel } from "./viewmodel/ChatMessageViewModel";
|
|
||||||
import * as Handlebars from "handlebars";
|
|
||||||
import { ChatModel } from "./model/ChatModel";
|
|
||||||
import { ChatView } from "./view/ChatView";
|
|
||||||
import { ChatController } from "./controller/ChatController";
|
|
||||||
import { JsonAPI } from "./singleton/JsonAPI";
|
|
||||||
import * as log from 'loglevel';
|
|
||||||
import { EncryptionService } from "./service/EncryptionService";
|
|
||||||
import { SJCLEncryptionService } from "./service/SJCLEncryptionService";
|
|
||||||
import { MessageCipherDTO } from "./dto/MessageCipherDTO";
|
|
||||||
import { SearchService } from "./service/SearchService";
|
|
||||||
import { FuseSearchService } from "./service/FuseSearchService";
|
|
||||||
import { ChatMessageDTO } from "./dto/ChatMessageDTO";
|
|
||||||
import { NotificationService } from "./service/NotificationService";
|
|
||||||
import { AlertifyNotificationService } from "./service/AlertifyNotificationService";
|
|
||||||
import { Builder } from "builder-pattern";
|
import { Builder } from "builder-pattern";
|
||||||
|
import * as Handlebars from "handlebars";
|
||||||
// import "./SprintfTest.d.ts"
|
import * as log from 'loglevel';
|
||||||
// import { sprintf } from "sprintf-js";
|
import { ChatController } from "./controller/ChatController";
|
||||||
// import sprintf = require('sprintf-js');
|
import { UserController } from "./controller/UserController";
|
||||||
import { TemplateFactory } from "./template/TemplateFactory";
|
import { ChatModel } from "./model/ChatModel";
|
||||||
import { UserViewDeps } from "./view/UserViewDeps";
|
import { ChatModelHelper } from "./model/ChatModelHelper";
|
||||||
import { ChatViewDeps } from "./view/ChatViewDeps";
|
import { UserModel } from "./model/UserModel";
|
||||||
import { MarkDownItMarkDownService } from "./service/MarkDownItMarkDownService";
|
import { AlertifyNotificationService } from "./service/AlertifyNotificationService";
|
||||||
import { Sprintf } from "./singleton/Sprintf";
|
|
||||||
import { EncryptionServiceFactory } from "./service/EncryptionServiceFactory";
|
import { EncryptionServiceFactory } from "./service/EncryptionServiceFactory";
|
||||||
|
import { FuseSearchService } from "./service/FuseSearchService";
|
||||||
|
import { MarkDownItMarkDownService } from "./service/MarkDownItMarkDownService";
|
||||||
|
import { NotificationService } from "./service/NotificationService";
|
||||||
|
import { SearchService } from "./service/SearchService";
|
||||||
|
import { TemplateFactory } from "./template/TemplateFactory";
|
||||||
|
import { ChatView } from "./view/ChatView";
|
||||||
|
import { ChatViewDeps } from "./view/ChatViewDeps";
|
||||||
|
import { UserView } from "./view/UserView";
|
||||||
|
import { UserViewDeps } from "./view/UserViewDeps";
|
||||||
|
import { ActiveUserViewModel } from "./viewmodel/ActiveUserViewModel";
|
||||||
|
|
||||||
|
log.setLevel("TRACE");
|
||||||
|
|
||||||
const usersListElement = document.getElementById('contacts-box');
|
const usersListElement = document.getElementById('contacts-box');
|
||||||
const userSearchButton = document.getElementById('user-search');
|
const userSearchButton = document.getElementById('user-search');
|
||||||
const userSearchInputElement = document.getElementById('user-search-term') as HTMLInputElement;
|
const userSearchInputElement = document.getElementById('user-search-term') as HTMLInputElement;
|
||||||
const userSearchCancelButton = document.getElementById('user-search-cancel');
|
const userSearchCancelButton = document.getElementById('user-search-cancel');
|
||||||
|
const chatArea = document.getElementById('chat-area-new');
|
||||||
|
|
||||||
|
|
||||||
const activeUserSearchService: SearchService<ActiveUserViewModel> = new FuseSearchService(["userName"]);
|
const activeUserSearchService: SearchService<ActiveUserViewModel> = new FuseSearchService(["userName"]);
|
||||||
|
const ns: NotificationService = new AlertifyNotificationService();
|
||||||
|
const encryptionService = EncryptionServiceFactory.getEncryptionService();
|
||||||
|
|
||||||
log.setLevel("TRACE")
|
|
||||||
|
|
||||||
const chatModel = new ChatModel();
|
|
||||||
|
|
||||||
const userModel = new UserModel();
|
const chatModelHelper = new ChatModelHelper(encryptionService, ns);
|
||||||
// const userModel = ModelFactory.createModel("USER");
|
const chatModel = new ChatModel(chatModelHelper);
|
||||||
|
const cvDeps: ChatViewDeps = {
|
||||||
|
chatModel: chatModel,
|
||||||
|
// @ts-ignore: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.
|
||||||
|
messageContainer: chatArea,
|
||||||
|
messageSendTemplate: TemplateFactory.getTemplate('msg_container_send_template'),
|
||||||
|
messageReceiveTemplate: TemplateFactory.getTemplate('msg_container_template'),
|
||||||
|
markdownService: new MarkDownItMarkDownService,
|
||||||
|
encryptionService: encryptionService,
|
||||||
|
notificationService: ns
|
||||||
|
}
|
||||||
|
const chatView = new ChatView(cvDeps);
|
||||||
|
chatModel.attach(chatView);
|
||||||
|
const chatController = new ChatController(chatModel, chatView);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const userModel = new UserModel(ns);
|
||||||
const uvDeps: UserViewDeps = {
|
const uvDeps: UserViewDeps = {
|
||||||
model: userModel,
|
model: userModel,
|
||||||
chatModel: chatModel,
|
chatModel: chatModel,
|
||||||
@ -61,82 +68,21 @@ const uvDeps: UserViewDeps = {
|
|||||||
userContactOfflineTemplate: TemplateFactory.getTemplate('user-contact-offline-template')
|
userContactOfflineTemplate: TemplateFactory.getTemplate('user-contact-offline-template')
|
||||||
}
|
}
|
||||||
const userView = new UserView(uvDeps);
|
const userView = new UserView(uvDeps);
|
||||||
|
|
||||||
// console.log(userBox);
|
|
||||||
|
|
||||||
userModel.attach(userView);
|
userModel.attach(userView);
|
||||||
// userView.model
|
|
||||||
|
|
||||||
|
|
||||||
const userController = new UserController(userModel, userView);
|
const userController = new UserController(userModel, userView);
|
||||||
// userController.test();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// userModel.someBusinessMethod(activeUsersMock);
|
|
||||||
log.info("hello");
|
|
||||||
|
|
||||||
const chatArea = document.getElementById('chat-area-new');
|
|
||||||
// @ts-ignore: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.
|
|
||||||
const cvDeps: ChatViewDeps = {
|
|
||||||
chatModel: chatModel,
|
|
||||||
// @ts-ignore: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'HTMLElement'. Type 'null' is not assignable to type 'HTMLElement'.
|
|
||||||
messageContainer: chatArea,
|
|
||||||
messageSendTemplate: TemplateFactory.getTemplate('msg_container_send_template'),
|
|
||||||
messageReceiveTemplate: TemplateFactory.getTemplate('msg_container_template'),
|
|
||||||
markdownService: new MarkDownItMarkDownService,
|
|
||||||
encryptionService: EncryptionServiceFactory.getEncryptionService()
|
|
||||||
|
|
||||||
}
|
|
||||||
const chatView = new ChatView(cvDeps);
|
|
||||||
chatModel.attach(chatView);
|
|
||||||
const chatController = new ChatController(chatModel, chatView);
|
|
||||||
|
|
||||||
|
|
||||||
function someFunc(vm: ActiveUserViewModel): void {
|
|
||||||
// log.info(vm);
|
|
||||||
// logger.info(vm)
|
|
||||||
}
|
|
||||||
|
|
||||||
userController.getActiveUsers();
|
userController.getActiveUsers();
|
||||||
|
|
||||||
log.info("test");
|
|
||||||
// someFunc(activeUserViewModelMock);
|
|
||||||
|
|
||||||
// @ts-ignore: Object is possibly 'null'.
|
|
||||||
var source = document.getElementById("msg_container_template").innerHTML;
|
|
||||||
|
|
||||||
var msgContainerTemplate = Handlebars.compile(source);
|
|
||||||
|
|
||||||
JsonAPI.ACTIVE_USERS_GET + 'aef';
|
|
||||||
|
|
||||||
const encryptionService: EncryptionService = EncryptionServiceFactory.getEncryptionService();
|
|
||||||
let messageCipherDTO: MessageCipherDTO = encryptionService.encrypt("password", "data");
|
|
||||||
console.log(encryptionService.decrypt("password", messageCipherDTO));
|
|
||||||
|
|
||||||
|
|
||||||
async function func(): Promise<void> {
|
|
||||||
const text = await encryptionService.decryptAsPromise("password", messageCipherDTO)
|
|
||||||
log.debug(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
func();
|
|
||||||
|
|
||||||
Handlebars.registerHelper('avatar', function () {
|
Handlebars.registerHelper('avatar', function () {
|
||||||
return '<div class="img_cont_msg"> <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg"> </div>';
|
return '<div class="img_cont_msg"> <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg"> </div>';
|
||||||
});
|
});
|
||||||
|
|
||||||
const testList: ChatMessageDTO[] = [];
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
console.log()
|
|
||||||
log.info(Sprintf("test sprintf"))
|
|
||||||
// log.info(sprintf2.sprintf("test sprintf"))
|
|
||||||
const ns: NotificationService = new AlertifyNotificationService();
|
|
||||||
ns.success("Welcome");
|
ns.success("Welcome");
|
||||||
// ns.errorWithDelay("Hmm very long error notif", 10);
|
// ns.errorWithDelay("Hmm very long error notif", 10);
|
||||||
|
|
||||||
const ss = FuseSearchService.getInstance<ActiveUserViewModel>([""]);
|
|
||||||
|
|
||||||
const test = Builder<UserViewDeps>().build();
|
const test = Builder<UserViewDeps>().build();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Subject } from "../observe/Observable";
|
import { Subject } from "../observe/Observable";
|
||||||
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
|
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
|
||||||
|
|
||||||
export interface Model extends Subject{
|
export interface Model extends Subject<any> {
|
||||||
someBusinessMethod(data: Object): void;
|
someBusinessMethod(data: Object): void;
|
||||||
|
|
||||||
}
|
}
|
@ -1,114 +1,126 @@
|
|||||||
import { Subject } from "../observe/Observable";
|
import { Subject } from "../observe/Observable";
|
||||||
import { Model } from "./AbstractModel";
|
|
||||||
import { Observer } from "../observe/Observer";
|
import { Observer } from "../observe/Observer";
|
||||||
import { fetchErrorHandler } from "./FetchErrorHandler";
|
|
||||||
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
|
|
||||||
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
|
||||||
import { JsonAPI } from "../singleton/JsonAPI";
|
import { JsonAPI } from "../singleton/JsonAPI";
|
||||||
import log = require('loglevel');
|
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
||||||
import { EncryptionService } from "../service/EncryptionService";
|
|
||||||
import { SJCLEncryptionService } from "../service/SJCLEncryptionService";
|
|
||||||
import { ChatMessageDTO } from "../dto/ChatMessageDTO";
|
|
||||||
import { ChatModelHelper } from "./ChatModelHelper";
|
import { ChatModelHelper } from "./ChatModelHelper";
|
||||||
|
import log = require('loglevel');
|
||||||
|
import { ObserverData } from "../observe/ObserverData";
|
||||||
|
|
||||||
export class ChatModel implements Subject {
|
interface Params {
|
||||||
|
userName: string,
|
||||||
|
data: ChatMessageViewModel[],
|
||||||
|
op: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChatModel implements Subject<ChatMessageViewModel> {
|
||||||
/**
|
/**
|
||||||
* @type {Observer[]} List of subscribers. In real life, the list of
|
* @type {Observer[]} List of subscribers. In real life, the list of
|
||||||
* subscribers can be stored more comprehensively (categorized by event
|
* subscribers can be stored more comprehensively (categorized by event
|
||||||
* type, etc.).
|
* type, etc.).
|
||||||
*/
|
*/
|
||||||
private readonly _observers: Observer[] = [];
|
private readonly _observers: Observer<ChatMessageViewModel>[] = [];
|
||||||
private state: ChatMessageViewModel[] | null;
|
|
||||||
private readonly _messagePageMap: Map<string, number>;
|
private readonly _messagePageMap: Map<string, number>;
|
||||||
private readonly _messagesMap: Map<string, ChatMessageViewModel[]>;
|
private readonly _messagesMap: Map<string, ChatMessageViewModel[]>;
|
||||||
|
private readonly _chatModelHelper: ChatModelHelper;
|
||||||
|
|
||||||
constructor() {
|
constructor(chatModelHelper: ChatModelHelper) {
|
||||||
this.state = null;
|
|
||||||
this._messagePageMap = new Map();
|
this._messagePageMap = new Map();
|
||||||
this._messagesMap = new Map();
|
this._messagesMap = new Map();
|
||||||
|
this._chatModelHelper = chatModelHelper;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The subscription management methods.
|
* The subscription management methods.
|
||||||
*/
|
*/
|
||||||
public attach(observer: Observer): void {
|
public attach(observer: Observer<ChatMessageViewModel>): void {
|
||||||
console.log('Subject: Attached an observer.');
|
log.info('Subject: Attached an observer.');
|
||||||
this._observers.push(observer);
|
this._observers.push(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public detach(observer: Observer): void {
|
public detach(observer: Observer<ChatMessageViewModel>): void {
|
||||||
const observerIndex = this._observers.indexOf(observer);
|
const observerIndex = this._observers.indexOf(observer);
|
||||||
this._observers.splice(observerIndex, 1);
|
this._observers.splice(observerIndex, 1);
|
||||||
console.log('Subject: Detached an observer.');
|
log.info('Subject: Detached an observer.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private storeUserMessages(username: string, messages: ChatMessageViewModel[], op: string) {
|
||||||
|
switch (op) {
|
||||||
|
case "clear": this._messagesMap.set(username, []);
|
||||||
|
case "page": this._messagesMap.set(username, messages.concat(this.getStoredUserMessages(username))); break;
|
||||||
|
// case "page": this._messagesMap.set(username, messages);
|
||||||
|
case "new": this._messagesMap.set(username, this.getStoredUserMessages(username).concat(messages)); break;
|
||||||
|
default: new Error("Invalid option");
|
||||||
}
|
}
|
||||||
|
|
||||||
private storeUserMessages(username: string, messages: ChatMessageViewModel[]) {
|
|
||||||
this._messagesMap.set(username, messages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStoredUserMessages(username: string): ChatMessageViewModel[] {
|
private getStoredUserMessages(username: string): ChatMessageViewModel[] {
|
||||||
return this._messagesMap.get(username)!;
|
let temp = this._messagesMap.get(username);
|
||||||
|
if (temp == null)
|
||||||
|
return [];
|
||||||
|
else {
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger an update in each subscriber.
|
* Trigger an update in each subscriber.
|
||||||
*/
|
*/
|
||||||
public notify(userName: string): void {
|
public notify(p: Params): void {
|
||||||
console.log('Subject: Notifying observers...');
|
log.info('Subject: Notifying observers...');
|
||||||
|
switch (p.op) {
|
||||||
|
case "clear": {
|
||||||
|
const od: ObserverData<ChatMessageViewModel> = { data: [], op: "clear" }
|
||||||
for (const observer of this._observers) {
|
for (const observer of this._observers) {
|
||||||
observer.update(this._messagesMap.get(userName));
|
observer.update(od);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case "new": {
|
||||||
|
const od: ObserverData<ChatMessageViewModel> = { data: p.data, op: p.op }
|
||||||
|
for (const observer of this._observers) {
|
||||||
|
observer.update(od);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case "page": {
|
||||||
|
const od: ObserverData<ChatMessageViewModel> = { data: p.data, op: p.op }
|
||||||
|
for (const observer of this._observers) {
|
||||||
|
observer.update(od);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: { log.error("error") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public someBusinessMethod(chatMessageList: ChatMessageViewModel[]): void {
|
public someBusinessMethod(chatMessageList: ChatMessageViewModel[]): void {
|
||||||
this.state = chatMessageList;
|
|
||||||
console.log(`Subject: My state has just changed`);
|
|
||||||
console.log(chatMessageList);
|
|
||||||
this.notify("some user");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getMessages(contactName: string, passphrase: string, lastMessageTime: string | null): Promise<ChatMessageViewModel[]> {
|
public clear(): void {
|
||||||
|
this._messagePageMap.set(JsonAPI.contactName!, 0);
|
||||||
|
this.storeUserMessages(JsonAPI.contactName!, [], "clear");
|
||||||
|
this.notify({ userName: "", data: [], op: "clear" })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getMessages(contactName: string, passphrase: string, lastMessageTime: string | null, op: string): Promise<ChatMessageViewModel[]> {
|
||||||
if (this._messagePageMap.get(contactName) == null)
|
if (this._messagePageMap.get(contactName) == null)
|
||||||
this._messagePageMap.set(contactName, 0);
|
this._messagePageMap.set(contactName, 0);
|
||||||
// else {
|
|
||||||
// log.debug('page number before = ' + this._messagePageMap.get(contactName)!)
|
|
||||||
// this._messagePageMap.set(contactName, this._messagePageMap.get(contactName)! + 1);
|
|
||||||
// log.debug('page number after = ' + this._messagePageMap.get(contactName)!)
|
|
||||||
// }
|
|
||||||
const pageNumber = this._messagePageMap.get(contactName)
|
const pageNumber = this._messagePageMap.get(contactName)
|
||||||
const cVMs = await ChatModelHelper.getMessages(contactName, passphrase, pageNumber!, lastMessageTime);
|
const cVMs = await this._chatModelHelper.getMessages(contactName, passphrase, pageNumber!, lastMessageTime, op);
|
||||||
if (cVMs != null) {
|
if (cVMs != null) {
|
||||||
log.info('Subject: My state has just changed')
|
log.info('Subject: My state has just changed')
|
||||||
|
|
||||||
// this._messagesMap.set(userName, cVMs);
|
|
||||||
const existingMessages = this.getStoredUserMessages(contactName);
|
const existingMessages = this.getStoredUserMessages(contactName);
|
||||||
|
log.debug('existing message:')
|
||||||
log.debug(existingMessages);
|
log.debug(existingMessages);
|
||||||
|
log.debug('new messages:')
|
||||||
log.debug(cVMs);
|
log.debug(cVMs);
|
||||||
if (existingMessages != null) {
|
this.storeUserMessages(contactName, cVMs, op);
|
||||||
// existingMessages.forEach(function (elem) {
|
this.notify({ userName: contactName, data: cVMs, op: op });
|
||||||
// cVMs.push(elem);
|
|
||||||
// })
|
|
||||||
const newArr = cVMs.concat(existingMessages)
|
|
||||||
// log.debug(newArr);
|
|
||||||
this.storeUserMessages(contactName, cVMs);
|
|
||||||
// this.storeUserMessages(contactName, cVMs);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.storeUserMessages(contactName, cVMs);
|
|
||||||
}
|
|
||||||
JsonAPI.contactName = contactName;
|
|
||||||
this.notify(contactName);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error('Messages were null');
|
log.error('Messages were null');
|
||||||
}
|
}
|
||||||
if(this._messagePageMap.get(contactName) == 0)
|
|
||||||
{
|
|
||||||
log.info(cVMs[cVMs.length - 1].messageTime)
|
|
||||||
}
|
|
||||||
if (cVMs.length != 0) {
|
if (cVMs.length != 0) {
|
||||||
// log.debug('page number before = ' + this._messagePageMap.get(contactName)!)
|
|
||||||
this._messagePageMap.set(contactName, this._messagePageMap.get(contactName)! + 1);
|
this._messagePageMap.set(contactName, this._messagePageMap.get(contactName)! + 1);
|
||||||
// log.debug('page number after = ' + this._messagePageMap.get(contactName)!)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cVMs;
|
return cVMs;
|
||||||
|
@ -1,30 +1,38 @@
|
|||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { ChatMessageDTO } from "../dto/ChatMessageDTO";
|
import { ChatMessageDTO } from "../dto/ChatMessageDTO";
|
||||||
import { EncryptionService } from "../service/EncryptionService";
|
import { EncryptionService } from "../service/EncryptionService";
|
||||||
import { EncryptionServiceFactory } from "../service/EncryptionServiceFactory";
|
import { NotificationService } from "../service/NotificationService";
|
||||||
import { JsonAPI } from "../singleton/JsonAPI";
|
import { JsonAPI } from "../singleton/JsonAPI";
|
||||||
import { Sprintf } from "../singleton/Sprintf";
|
import { Sprintf } from "../singleton/Sprintf";
|
||||||
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
||||||
import { fetchErrorHandler } from "./FetchErrorHandler";
|
import { fetchErrorHandler } from "./FetchErrorHandler";
|
||||||
|
|
||||||
export class ChatModelHelper {
|
export class ChatModelHelper {
|
||||||
private static readonly _encryptionService: EncryptionService = EncryptionServiceFactory.getEncryptionService();
|
private readonly _encryptionService: EncryptionService;
|
||||||
|
private readonly _notificationService: NotificationService;
|
||||||
|
|
||||||
public static async getMessages(userName: string, passphrase: string, page: number | null, lastMessageTime: string | null): Promise<ChatMessageViewModel[]> {
|
|
||||||
|
constructor(encryptionService: EncryptionService, notificationService: NotificationService) {
|
||||||
|
this._encryptionService = encryptionService;
|
||||||
|
this._notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async getMessages(userName: string, passphrase: string, page: number | null, lastMessageTime: string | null, op: string): Promise<ChatMessageViewModel[]> {
|
||||||
switch (lastMessageTime) {
|
switch (lastMessageTime) {
|
||||||
case null: {
|
case null: {
|
||||||
const data: ChatMessageDTO[] = await this.getPaginatedMessagesAjax(userName, page!);
|
const data: ChatMessageDTO[] = await this._getPaginatedMessagesAjax(userName, page!);
|
||||||
const cVMs = Promise.all(data.map(vm => this.toChatMessageVMAsync(vm, passphrase)).reverse());
|
const cVMs = Promise.all(data.map(vm => this._toChatMessageVMAsync(vm, passphrase)).reverse());
|
||||||
return cVMs;
|
return cVMs;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const data: ChatMessageDTO[] = await this.getNewMessagesAjax(userName, lastMessageTime);
|
const data: ChatMessageDTO[] = await this._getNewMessagesAjax(userName, lastMessageTime);
|
||||||
return data.map(vm => this.toChatMessageVM(vm, passphrase));
|
return data.map(vm => this._toChatMessageVM(vm, passphrase));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async toChatMessageVMAsync(chatMessageDTO: ChatMessageDTO, passphrase: string): Promise<ChatMessageViewModel> {
|
private async _toChatMessageVMAsync(chatMessageDTO: ChatMessageDTO, passphrase: string): Promise<ChatMessageViewModel> {
|
||||||
const vm = new ChatMessageViewModel();
|
const vm = new ChatMessageViewModel();
|
||||||
vm.fromUser = chatMessageDTO.fromUser;
|
vm.fromUser = chatMessageDTO.fromUser;
|
||||||
vm.toUser = chatMessageDTO.toUser;
|
vm.toUser = chatMessageDTO.toUser;
|
||||||
@ -34,7 +42,7 @@ export class ChatModelHelper {
|
|||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static toChatMessageVM(chatMessageDTO: ChatMessageDTO, passphrase: string): ChatMessageViewModel {
|
private _toChatMessageVM(chatMessageDTO: ChatMessageDTO, passphrase: string): ChatMessageViewModel {
|
||||||
const vm = new ChatMessageViewModel();
|
const vm = new ChatMessageViewModel();
|
||||||
vm.fromUser = chatMessageDTO.fromUser;
|
vm.fromUser = chatMessageDTO.fromUser;
|
||||||
vm.toUser = chatMessageDTO.toUser;
|
vm.toUser = chatMessageDTO.toUser;
|
||||||
@ -44,7 +52,7 @@ export class ChatModelHelper {
|
|||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getAllMessagesAjax(toUser: string): Promise<any> {
|
private async _getAllMessagesAjax(toUser: string): Promise<any> {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
if (JsonAPI.authToken == null) {
|
if (JsonAPI.authToken == null) {
|
||||||
log.error("authToken null");
|
log.error("authToken null");
|
||||||
@ -52,51 +60,41 @@ export class ChatModelHelper {
|
|||||||
};
|
};
|
||||||
headers.append('X-AUTH-TOKEN', JsonAPI.authToken);
|
headers.append('X-AUTH-TOKEN', JsonAPI.authToken);
|
||||||
const url = Sprintf(JsonAPI.CHAT_MESSAGES_GET, toUser);
|
const url = Sprintf(JsonAPI.CHAT_MESSAGES_GET, toUser);
|
||||||
// const url = Sprintf(JsonAPI.CHAT_MESSAGE_PAGE_GET, toUser,1,5);
|
|
||||||
log.debug(url)
|
log.debug(url)
|
||||||
// const response = await fetch(`${JsonAPI.CHAT_MESSAGES_GET}/${toUser}`, {
|
|
||||||
// method: 'GET',
|
|
||||||
// headers: headers
|
|
||||||
// });
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
console.log(response.clone());
|
log.debug(response.clone());
|
||||||
if (fetchErrorHandler(response.clone())) {
|
if (fetchErrorHandler(response.clone(), this._notificationService)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const data: Promise<any> = await response.json();
|
const data: Promise<any> = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getPaginatedMessagesAjax(toUser: string, page: number): Promise<any> {
|
private async _getPaginatedMessagesAjax(toUser: string, page: number): Promise<any> {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
if (JsonAPI.authToken == null) {
|
if (JsonAPI.authToken == null) {
|
||||||
log.error("authToken null");
|
log.error("authToken null");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
headers.append('X-AUTH-TOKEN', JsonAPI.authToken);
|
headers.append('X-AUTH-TOKEN', JsonAPI.authToken);
|
||||||
// const url = Sprintf(JsonAPI.CHAT_MESSAGES_GET, toUser);
|
|
||||||
const url = Sprintf(JsonAPI.CHAT_MESSAGE_PAGE_GET, toUser, page, 5);
|
const url = Sprintf(JsonAPI.CHAT_MESSAGE_PAGE_GET, toUser, page, 5);
|
||||||
log.debug(url)
|
log.debug(url)
|
||||||
// const response = await fetch(`${JsonAPI.CHAT_MESSAGES_GET}/${toUser}`, {
|
|
||||||
// method: 'GET',
|
|
||||||
// headers: headers
|
|
||||||
// });
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
console.log(response.clone());
|
log.debug(response.clone());
|
||||||
if (fetchErrorHandler(response.clone())) {
|
if (fetchErrorHandler(response.clone(), this._notificationService)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const data: Promise<any> = await response.json();
|
const data: Promise<any> = await response.json();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getNewMessagesAjax(toUser: string, lastMessageTimeStamp: string): Promise<any> {
|
private async _getNewMessagesAjax(toUser: string, lastMessageTimeStamp: string): Promise<any> {
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
if (JsonAPI.authToken == null) {
|
if (JsonAPI.authToken == null) {
|
||||||
log.error("authToken null");
|
log.error("authToken null");
|
||||||
@ -107,8 +105,8 @@ export class ChatModelHelper {
|
|||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
console.log(response.clone());
|
log.debug(response.clone());
|
||||||
if (fetchErrorHandler(response.clone())) {
|
if (fetchErrorHandler(response.clone(), this._notificationService)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const data: Promise<any> = await response.json();
|
const data: Promise<any> = await response.json();
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import log = require("loglevel");
|
import log = require("loglevel");
|
||||||
|
import { NotificationService } from "../service/NotificationService";
|
||||||
|
import { Sprintf } from "../singleton/Sprintf";
|
||||||
// import { sprintf } from "sprintf-js";
|
// import { sprintf } from "sprintf-js";
|
||||||
///<reference path="../SprintfTest.d.ts" />
|
///<reference path="../SprintfTest.d.ts" />
|
||||||
|
|
||||||
// import sprintf = require('sprintf-js').sprintf;
|
// import sprintf = require('sprintf-js').sprintf;
|
||||||
|
|
||||||
export function fetchErrorHandler(response: Response) {
|
export function fetchErrorHandler(response: Response, ns: NotificationService) {
|
||||||
// alertify.success('Current position : ' + alertify.get('notifier', 'position'));
|
// alertify.success('Current position : ' + alertify.get('notifier', 'position'));
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return response.text().catch(err => {
|
return response.text().catch(err => {
|
||||||
// the status was not ok and there is no json body
|
// the status was not ok and there is no json body
|
||||||
// throw new Error(response.statusText);
|
// throw new Error(response.statusText);
|
||||||
// window.alert(sprintf('Some error occured. Http code is %s', response.status));
|
// window.alert(sprintf('Some error occured. Http code is %s', response.status));
|
||||||
// alertify.error(sprintf('Some error occured. Http code is %s', response.status));
|
ns.error(Sprintf('Some error occured. Http code is %s', response.status));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
log.error(sprintf('Some error occured. Http code is %s', response.status));
|
log.error(sprintf('Some error occured. Http code is %s', response.status));
|
||||||
log.error();
|
log.error();
|
||||||
@ -20,7 +22,7 @@ export function fetchErrorHandler(response: Response) {
|
|||||||
// the status was not ok but there is a json body
|
// the status was not ok but there is a json body
|
||||||
// throw new Error(json.error.message); // example error message returned by a REST API
|
// throw new Error(json.error.message); // example error message returned by a REST API
|
||||||
// window.alert(sprintf('Error: %s (Http code %s)', json, response.status));
|
// window.alert(sprintf('Error: %s (Http code %s)', json, response.status));
|
||||||
// alertify.error(sprintf('Some error occured. Http code is %s', response.status));
|
ns.error(Sprintf('Some error occured. Http code is %s', response.status));
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
log.error(sprintf('Some error occured. Http code is %s', response.status));
|
log.error(sprintf('Some error occured. Http code is %s', response.status));
|
||||||
log.error(json);
|
log.error(json);
|
||||||
|
@ -1,31 +1,33 @@
|
|||||||
import { Subject } from "../observe/Observable";
|
|
||||||
import { Model } from "./AbstractModel";
|
|
||||||
import { Observer } from "../observe/Observer";
|
|
||||||
import { fetchErrorHandler } from "./FetchErrorHandler";
|
|
||||||
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
|
|
||||||
import { JsonAPI } from "../singleton/JsonAPI";
|
|
||||||
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
|
import { Subject } from "../observe/Observable";
|
||||||
|
import { Observer } from "../observe/Observer";
|
||||||
|
import { JsonAPI } from "../singleton/JsonAPI";
|
||||||
|
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
|
||||||
|
import { fetchErrorHandler } from "./FetchErrorHandler";
|
||||||
|
import { NotificationService } from "../service/NotificationService";
|
||||||
|
|
||||||
export class UserModel implements Subject {
|
export class UserModel implements Subject<ActiveUserViewModel> {
|
||||||
/**
|
/**
|
||||||
* @type {Observer[]} List of subscribers. In real life, the list of
|
* @type {Observer[]} List of subscribers. In real life, the list of
|
||||||
* subscribers can be stored more comprehensively (categorized by event
|
* subscribers can be stored more comprehensively (categorized by event
|
||||||
* type, etc.).
|
* type, etc.).
|
||||||
*/
|
*/
|
||||||
private readonly observers: Observer[] = [];
|
private readonly observers: Observer<ActiveUserViewModel>[] = [];
|
||||||
|
|
||||||
|
|
||||||
private _activeUsersList: ActiveUserViewModel[] | undefined;
|
private _activeUsersList: ActiveUserViewModel[];
|
||||||
// @ts-ignore: Cannot find name 'hostAddress'.
|
private readonly _notificationService: NotificationService;
|
||||||
|
|
||||||
constructor() { }
|
constructor(notificationService: NotificationService) {
|
||||||
|
this._activeUsersList = [];
|
||||||
|
this._notificationService = notificationService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter activeUsersList
|
* Getter activeUsersList
|
||||||
* @return {ActiveUserViewModel[] }
|
* @return {ActiveUserViewModel[] }
|
||||||
*/
|
*/
|
||||||
public get activeUsersList(): ActiveUserViewModel[] | undefined {
|
public get activeUsersList(): ActiveUserViewModel[] {
|
||||||
return this._activeUsersList;
|
return this._activeUsersList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,32 +35,32 @@ export class UserModel implements Subject {
|
|||||||
/**
|
/**
|
||||||
* The subscription management methods.
|
* The subscription management methods.
|
||||||
*/
|
*/
|
||||||
public attach(observer: Observer): void {
|
public attach(observer: Observer<ActiveUserViewModel>): void {
|
||||||
console.log('Subject: Attached an observer.');
|
log.info('Subject: Attached an observer.');
|
||||||
this.observers.push(observer);
|
this.observers.push(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public detach(observer: Observer): void {
|
public detach(observer: Observer<ActiveUserViewModel>): void {
|
||||||
const observerIndex = this.observers.indexOf(observer);
|
const observerIndex = this.observers.indexOf(observer);
|
||||||
this.observers.splice(observerIndex, 1);
|
this.observers.splice(observerIndex, 1);
|
||||||
console.log('Subject: Detached an observer.');
|
log.info('Subject: Detached an observer.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger an update in each subscriber.
|
* Trigger an update in each subscriber.
|
||||||
*/
|
*/
|
||||||
public notify(): void {
|
public notify(): void {
|
||||||
console.log('Subject: Notifying observers...');
|
log.info('Subject: Notifying observers...');
|
||||||
for (const observer of this.observers) {
|
for (const observer of this.observers) {
|
||||||
observer.update(this._activeUsersList);
|
observer.update({ data: this._activeUsersList!, op: "" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public someBusinessMethod(activeuserList: ActiveUserViewModel[]): void {
|
public someBusinessMethod(activeuserList: ActiveUserViewModel[]): void {
|
||||||
this._activeUsersList = activeuserList;
|
this._activeUsersList = activeuserList;
|
||||||
this.helperMethod();
|
this.helperMethod();
|
||||||
console.log(`Subject: My state has just changed`);
|
log.info(`Subject: My state has just changed`);
|
||||||
console.log(activeuserList);
|
log.trace(activeuserList);
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,13 +68,13 @@ export class UserModel implements Subject {
|
|||||||
* getActiveUsers
|
* getActiveUsers
|
||||||
*/
|
*/
|
||||||
public getActiveUsers(): void {
|
public getActiveUsers(): void {
|
||||||
if(JsonAPI.authToken!= null){
|
if (JsonAPI.authToken != null) {
|
||||||
this.getActiveUsersAjax(JsonAPI.authToken)
|
this._getActiveUsersAjax(JsonAPI.authToken)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
// // activeUsers = data;
|
// // activeUsers = data;
|
||||||
// sessionStorage.setItem('activeUsers', JSON.stringify(data));
|
// sessionStorage.setItem('activeUsers', JSON.stringify(data));
|
||||||
// console.log(sessionStorage.getItem('activeUsers'));
|
// log.trace(sessionStorage.getItem('activeUsers'));
|
||||||
console.log(`Subject: received ajax active users`);
|
log.info(`Subject: received ajax active users`);
|
||||||
this._activeUsersList = data;
|
this._activeUsersList = data;
|
||||||
this.notify();
|
this.notify();
|
||||||
})
|
})
|
||||||
@ -82,15 +84,15 @@ export class UserModel implements Subject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getActiveUsersAjax(authToken: string): Promise<any> {
|
private async _getActiveUsersAjax(authToken: string): Promise<any> {
|
||||||
let headers = new Headers();
|
let headers = new Headers();
|
||||||
headers.append('X-AUTH-TOKEN', authToken);
|
headers.append('X-AUTH-TOKEN', authToken);
|
||||||
let response = await fetch(JsonAPI.ACTIVE_USERS_GET, {
|
let response = await fetch(JsonAPI.ACTIVE_USERS_GET, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: headers
|
headers: headers
|
||||||
});
|
});
|
||||||
console.log(response.clone());
|
log.debug(response.clone());
|
||||||
if (fetchErrorHandler(response.clone())) {
|
if (fetchErrorHandler(response.clone(), this._notificationService)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let data = await response.json();
|
let data = await response.json();
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import { Observer } from "./Observer";
|
import { Observer } from "./Observer";
|
||||||
|
import { ObserverData } from "./ObserverData";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Subject interface declares a set of methods for managing subscribers.
|
* The Subject interface declares a set of methods for managing subscribers.
|
||||||
*/
|
*/
|
||||||
export interface Subject {
|
export interface Subject<T> {
|
||||||
// Attach an observer to the subject.
|
// Attach an observer to the subject.
|
||||||
attach(observer: Observer): void;
|
attach(observer: Observer<T>): void;
|
||||||
|
|
||||||
// Detach an observer from the subject.
|
// Detach an observer from the subject.
|
||||||
detach(observer: Observer): void;
|
detach(observer: Observer<T>): void;
|
||||||
|
|
||||||
// Notify all observers about an event.
|
// Notify all observers about an event.
|
||||||
notify(param: any | null): void;
|
notify(param: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Subject } from "./Observable";
|
import { Subject } from "./Observable";
|
||||||
|
import { ObserverData } from "./ObserverData";
|
||||||
|
|
||||||
export interface Observer {
|
export interface Observer<T> {
|
||||||
// Receive update from subject.
|
// Receive update from subject.
|
||||||
update(data: any): void;
|
update(data: ObserverData<T>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
export interface ObserverData<T> {
|
||||||
|
data: Array<T>
|
||||||
|
op: string
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
import { Model } from "../model/AbstractModel";
|
import { Model } from "../model/AbstractModel";
|
||||||
import { Controller } from "../controller/AbstractController";
|
import { Controller } from "../controller/AbstractController";
|
||||||
import { Observer } from "../observe/Observer";
|
import { Observer } from "../observe/Observer";
|
||||||
export interface View extends Observer {
|
export interface View extends Observer<any> {
|
||||||
readonly model: Model,
|
readonly model: Model,
|
||||||
readonly element: any
|
readonly element: any
|
||||||
}
|
}
|
@ -10,14 +10,17 @@ import { JsonAPI } from "../singleton/JsonAPI";
|
|||||||
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
||||||
import { ChatViewDeps } from "./ChatViewDeps";
|
import { ChatViewDeps } from "./ChatViewDeps";
|
||||||
import { fetchHandler } from "./FetchHandler";
|
import { fetchHandler } from "./FetchHandler";
|
||||||
|
import { ObserverData } from '../observe/ObserverData';
|
||||||
|
import { NotificationService } from '../service/NotificationService';
|
||||||
|
|
||||||
export class ChatView implements Observer {
|
export class ChatView implements Observer<ChatMessageViewModel> {
|
||||||
private readonly _chatModel: ChatModel;
|
private readonly _chatModel: ChatModel;
|
||||||
private readonly _messageContainer: HTMLElement;
|
private readonly _messageContainer: HTMLElement;
|
||||||
private readonly _messageSendTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
private readonly _messageSendTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
||||||
private readonly _messageReceiveTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
private readonly _messageReceiveTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
||||||
private readonly _markdownService: MarkDownService;
|
private readonly _markdownService: MarkDownService;
|
||||||
private readonly _encryptionService: EncryptionService;
|
private readonly _encryptionService: EncryptionService;
|
||||||
|
private readonly _notificationService: NotificationService;
|
||||||
|
|
||||||
|
|
||||||
constructor(deps: ChatViewDeps) {
|
constructor(deps: ChatViewDeps) {
|
||||||
@ -27,7 +30,8 @@ export class ChatView implements Observer {
|
|||||||
this._messageReceiveTemplate = deps.messageReceiveTemplate;
|
this._messageReceiveTemplate = deps.messageReceiveTemplate;
|
||||||
this._markdownService = deps.markdownService;
|
this._markdownService = deps.markdownService;
|
||||||
this._encryptionService = deps.encryptionService;
|
this._encryptionService = deps.encryptionService;
|
||||||
this.addEventListeners();
|
this._notificationService = deps.notificationService;
|
||||||
|
this._initEventListeners();
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#action_menu_btn').click(function () {
|
$('#action_menu_btn').click(function () {
|
||||||
@ -35,15 +39,18 @@ export class ChatView implements Observer {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.chatMessagePageLoadAjax();
|
this._chatMessagePageLoadAjax();
|
||||||
}
|
}
|
||||||
|
|
||||||
update(data: ChatMessageViewModel[]): void {
|
update(cd: ObserverData<ChatMessageViewModel>): void {
|
||||||
log.info('ChatView: updating view');
|
log.info('ChatView: updating view');
|
||||||
// let html: string = "";
|
|
||||||
// let currentMsg = $('.msg:first');
|
switch (cd.op) {
|
||||||
// this._messageContainer.innerHTML = "";
|
case "clear": {
|
||||||
const rev: ChatMessageViewModel[] = Object.create(data)
|
$(this._messageContainer).html("");
|
||||||
|
} break;
|
||||||
|
case "new": {
|
||||||
|
const rev: ChatMessageViewModel[] = Object.create(cd.data)
|
||||||
rev.reverse();
|
rev.reverse();
|
||||||
let arr: string[] = [];
|
let arr: string[] = [];
|
||||||
rev.forEach((vm: ChatMessageViewModel) => {
|
rev.forEach((vm: ChatMessageViewModel) => {
|
||||||
@ -61,41 +68,54 @@ export class ChatView implements Observer {
|
|||||||
rendered = DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp));
|
rendered = DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp));
|
||||||
}
|
}
|
||||||
$(this._messageContainer).prepend(rendered);
|
$(this._messageContainer).prepend(rendered);
|
||||||
// if (currentMsg.position() != null) {
|
|
||||||
// $(this._messageContainer).scrollTop(currentMsg.position().top)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// log.debug(vm)
|
|
||||||
// log.debug(vmTemp)
|
|
||||||
// html += this._messageSendTemplate(vm);
|
|
||||||
});
|
});
|
||||||
// if (currentMsg.position() != null) {
|
$(this._messageContainer).stop().animate({
|
||||||
// $(this._messageContainer).scrollTop(currentMsg.position().top)
|
scrollTop: $(this._messageContainer)[0].scrollHeight
|
||||||
// }
|
}, 1500);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
const rev: ChatMessageViewModel[] = Object.create(cd.data)
|
||||||
|
rev.reverse();
|
||||||
|
let arr: string[] = [];
|
||||||
|
rev.forEach((vm: ChatMessageViewModel) => {
|
||||||
|
const vmTemp: ChatMessageViewModel = { ...vm };
|
||||||
|
vmTemp.message = this._markdownService.render(vm.message);
|
||||||
|
/** Very Important!!!
|
||||||
|
* Sanitizing HTML before displaying on webpage to prevent XSS attacks!!
|
||||||
|
*/
|
||||||
|
let rendered;
|
||||||
|
if (vmTemp.fromUser == JsonAPI.principleName) {
|
||||||
|
rendered = DOMPurify.sanitize(this._messageSendTemplate(vmTemp));
|
||||||
|
|
||||||
// html = DOMPurify.sanitize(md.render(html));
|
}
|
||||||
// this._element.innerHTML = html;
|
else {
|
||||||
// log.debug(this._element.innerHTML);
|
rendered = DOMPurify.sanitize(this._messageReceiveTemplate(vmTemp));
|
||||||
|
}
|
||||||
|
$(this._messageContainer).prepend(rendered);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addEventListeners(): void {
|
|
||||||
this.addChatFormEL();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private addChatFormEL() {
|
private _initEventListeners(): void {
|
||||||
|
this._addChatFormEL();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addChatFormEL() {
|
||||||
const chatForm = document.getElementById('chatMessageForm') as HTMLSelectElement;
|
const chatForm = document.getElementById('chatMessageForm') as HTMLSelectElement;
|
||||||
|
|
||||||
if (chatForm == null) {
|
if (chatForm == null) {
|
||||||
log.error("Chat form is null");
|
log.error("Chat form is null");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
chatForm.addEventListener('submit', (e) => this.createChatMessageDTO(e, chatForm))
|
chatForm.addEventListener('submit', (e) => this._createChatMessageDTO(e, chatForm))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private createChatMessageDTO(e: Event, chatForm: HTMLSelectElement): void {
|
private _createChatMessageDTO(e: Event, chatForm: HTMLSelectElement): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
let contactName = JsonAPI.contactName;
|
let contactName = JsonAPI.contactName;
|
||||||
@ -106,7 +126,7 @@ export class ChatView implements Observer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!chatForm.checkValidity()) {
|
if (!chatForm.checkValidity()) {
|
||||||
console.log("error");
|
log.error("Form is not valid");
|
||||||
chatForm.classList.add('was-validated');
|
chatForm.classList.add('was-validated');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -117,18 +137,24 @@ export class ChatView implements Observer {
|
|||||||
const passphraseInput = document.getElementById('passphrase') as HTMLInputElement;
|
const passphraseInput = document.getElementById('passphrase') as HTMLInputElement;
|
||||||
|
|
||||||
if (chatInput.value == '' || chatInput.value == null) {
|
if (chatInput.value == '' || chatInput.value == null) {
|
||||||
|
this._notificationService.error("Please enter a message");
|
||||||
log.error("Chat input is null.");
|
log.error("Chat input is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passphraseInput.value == '' || passphraseInput.value == null) {
|
if (passphraseInput.value == '' || passphraseInput.value == null) {
|
||||||
log.error("Chat input is null.");
|
this._notificationService.error("Please enter a passphrase");
|
||||||
|
log.error("Passphrase is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const messageContent = chatInput.value;
|
const messageContent = chatInput.value;
|
||||||
const context = { fromUser: JsonAPI.principleName, toUser: "", message: this._markdownService.render(messageContent), messageTime: new Date().toLocaleString() };
|
const context = {
|
||||||
|
fromUser: JsonAPI.principleName, toUser: "",
|
||||||
|
message: this._markdownService.render(messageContent),
|
||||||
|
messageTime: new Date().toLocaleString()
|
||||||
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const msgContainer: string = this._messageSendTemplate(context);
|
const msgContainer: string = this._messageSendTemplate(context);
|
||||||
$(this._messageContainer).append(DOMPurify.sanitize(msgContainer));
|
$(this._messageContainer).append(DOMPurify.sanitize(msgContainer));
|
||||||
@ -143,10 +169,10 @@ export class ChatView implements Observer {
|
|||||||
// "messageTime": null
|
// "messageTime": null
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.sendMessageAJAX(chatMessageDTO);
|
this._sendMessageAJAX(chatMessageDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendMessageAJAX(chatMessageDTO: ChatMessageDTO): void {
|
private _sendMessageAJAX(chatMessageDTO: ChatMessageDTO): void {
|
||||||
let headers = new Headers();
|
let headers = new Headers();
|
||||||
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
// console.log("Token = " + btoa("hmm" + ":" + "hmm"))
|
||||||
|
|
||||||
@ -164,16 +190,15 @@ export class ChatView implements Observer {
|
|||||||
log.debug(response);
|
log.debug(response);
|
||||||
return response.clone();
|
return response.clone();
|
||||||
})
|
})
|
||||||
.then(response => fetchHandler(response));
|
.then(response => fetchHandler(response, this._notificationService));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chatMessagePageLoadAjax() {
|
private _chatMessagePageLoadAjax() {
|
||||||
this._messageContainer.addEventListener('scroll', (e) => {
|
this._messageContainer.addEventListener('scroll', (e) => {
|
||||||
if ($(this._messageContainer).scrollTop() == 0) {
|
if ($(this._messageContainer).scrollTop() == 0 && $(this._messageContainer).html() != "") {
|
||||||
let currentMsg = $('.msg:first');
|
let currentMsg = $('.msg:first');
|
||||||
log.debug('Reached top')
|
log.debug('Reached top')
|
||||||
// @ts-ignore
|
|
||||||
let passphrase: string;
|
let passphrase: string;
|
||||||
let passphraseInput = document.getElementById('passphrase') as HTMLInputElement;
|
let passphraseInput = document.getElementById('passphrase') as HTMLInputElement;
|
||||||
|
|
||||||
@ -189,9 +214,11 @@ export class ChatView implements Observer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (JsonAPI.contactName != null)
|
if (JsonAPI.contactName != null)
|
||||||
this._chatModel.getMessages(JsonAPI.contactName, passphrase, null).then(() => {
|
this._chatModel.getMessages(JsonAPI.contactName, passphrase, null, "page").then(() => {
|
||||||
log.debug(currentMsg.offset()!.top)
|
if (currentMsg != null) {
|
||||||
$(this._messageContainer).scrollTop(currentMsg.position()!.top - $('.msg').position()!.top)
|
// log.debug(currentMsg.offset()!.top)
|
||||||
|
$(this._messageContainer).scrollTop(currentMsg.position().top - $('.msg').position()!.top)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,6 +2,7 @@ import { ChatMessageViewModel } from "../viewmodel/ChatMessageViewModel";
|
|||||||
import { ChatModel } from "../model/ChatModel";
|
import { ChatModel } from "../model/ChatModel";
|
||||||
import { MarkDownService } from "../service/MarkDownService";
|
import { MarkDownService } from "../service/MarkDownService";
|
||||||
import { EncryptionService } from "../service/EncryptionService";
|
import { EncryptionService } from "../service/EncryptionService";
|
||||||
|
import { NotificationService } from "../service/NotificationService";
|
||||||
|
|
||||||
export interface ChatViewDeps {
|
export interface ChatViewDeps {
|
||||||
chatModel: ChatModel;
|
chatModel: ChatModel;
|
||||||
@ -10,5 +11,5 @@ export interface ChatViewDeps {
|
|||||||
messageReceiveTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
messageReceiveTemplate: Handlebars.TemplateDelegate<ChatMessageViewModel>;
|
||||||
markdownService: MarkDownService;
|
markdownService: MarkDownService;
|
||||||
encryptionService: EncryptionService;
|
encryptionService: EncryptionService;
|
||||||
|
notificationService: NotificationService
|
||||||
}
|
}
|
@ -1,9 +1,7 @@
|
|||||||
import { NotificationService } from "../service/NotificationService";
|
import { NotificationService } from "../service/NotificationService";
|
||||||
import { AlertifyNotificationService } from "../service/AlertifyNotificationService";
|
|
||||||
import { Sprintf } from "../singleton/Sprintf";
|
import { Sprintf } from "../singleton/Sprintf";
|
||||||
|
|
||||||
export function fetchHandler(response: any) {
|
export function fetchHandler(response: Response, ns: NotificationService) {
|
||||||
const ns: NotificationService = new AlertifyNotificationService();
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return response.json().then((json: any) => {
|
return response.json().then((json: any) => {
|
||||||
// the status was ok and there is a json body
|
// the status was ok and there is a json body
|
||||||
|
@ -6,8 +6,10 @@ import * as DOMPurify from "dompurify";
|
|||||||
import { SearchService } from "../service/SearchService";
|
import { SearchService } from "../service/SearchService";
|
||||||
import { UserModel } from "../model/UserModel";
|
import { UserModel } from "../model/UserModel";
|
||||||
import { UserViewDeps } from "./UserViewDeps";
|
import { UserViewDeps } from "./UserViewDeps";
|
||||||
|
import { ObserverData } from "../observe/ObserverData";
|
||||||
|
import { JsonAPI } from "../singleton/JsonAPI";
|
||||||
|
|
||||||
export class UserView implements Observer {
|
export class UserView implements Observer<ActiveUserViewModel> {
|
||||||
|
|
||||||
|
|
||||||
private readonly _model: UserModel;
|
private readonly _model: UserModel;
|
||||||
@ -31,35 +33,35 @@ export class UserView implements Observer {
|
|||||||
this._userContactOnlineTemplate = deps.userContactOnlineTemplate;
|
this._userContactOnlineTemplate = deps.userContactOnlineTemplate;
|
||||||
this._userContactOfflineTemplate = deps.userContactOfflineTemplate;
|
this._userContactOfflineTemplate = deps.userContactOfflineTemplate;
|
||||||
|
|
||||||
this.addSearchEventListeners();
|
this._addSearchEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
update(data: ActiveUserViewModel[]): void {
|
update(d: ObserverData<ActiveUserViewModel>): void {
|
||||||
let html: string = "";
|
let html: string = "";
|
||||||
data.forEach((element: ActiveUserViewModel) => {
|
d.data.forEach((element: ActiveUserViewModel) => {
|
||||||
element.online ? html += this._userContactOnlineTemplate(element) : html += this._userContactOfflineTemplate(element);
|
element.online ? html += this._userContactOnlineTemplate(element) : html += this._userContactOfflineTemplate(element);
|
||||||
});
|
});
|
||||||
$(this._usersListElement).html(DOMPurify.sanitize(html));
|
$(this._usersListElement).html(DOMPurify.sanitize(html));
|
||||||
this.addUserCallBacks();
|
this._addUserCallBacks();
|
||||||
console.log(this._usersListElement.innerHTML);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSearchEventListeners(): void {
|
private _addSearchEventListeners(): void {
|
||||||
this.addSearchButtonEL();
|
this._addSearchButtonEL();
|
||||||
this.addSearchCancelEL();
|
this._addSearchCancelEL();
|
||||||
this.addSearchInputEL();
|
this._addSearchInputEL();
|
||||||
}
|
}
|
||||||
|
|
||||||
private addUserCallBacks(): void {
|
private _addUserCallBacks(): void {
|
||||||
let userBoxes = document.getElementsByClassName('user-box');
|
let userBoxes = document.getElementsByClassName('user-box');
|
||||||
for (let i = 0; i < userBoxes.length; i++) {
|
for (let i = 0; i < userBoxes.length; i++) {
|
||||||
let userBox = userBoxes[i];
|
let userBox = userBoxes[i];
|
||||||
userBoxes[i].addEventListener('click', this.userCallBack.bind(this, userBox));
|
userBoxes[i].addEventListener('click', this._userCallBack.bind(this, userBox));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private userCallBack(el: Element): void {
|
private _userCallBack(el: Element): void {
|
||||||
|
this._chatModel.clear();
|
||||||
let current = document.getElementsByClassName('user-box active');
|
let current = document.getElementsByClassName('user-box active');
|
||||||
|
|
||||||
let passphrase: string = '';
|
let passphrase: string = '';
|
||||||
@ -104,13 +106,14 @@ export class UserView implements Observer {
|
|||||||
// console.log(this.getElementsByClassName('to-user-span'));
|
// console.log(this.getElementsByClassName('to-user-span'));
|
||||||
let elem = el.getElementsByClassName('to-user-span')[0] as HTMLElement;
|
let elem = el.getElementsByClassName('to-user-span')[0] as HTMLElement;
|
||||||
let userName = elem.innerText;
|
let userName = elem.innerText;
|
||||||
|
JsonAPI.contactName = userName;
|
||||||
// @ts-ignore: Object is possibly 'null'.
|
// @ts-ignore: Object is possibly 'null'.
|
||||||
document.getElementById('user-name-span').innerText = userName;
|
document.getElementById('user-name-span').innerText = userName;
|
||||||
this._chatModel.getMessages(userName, passphrase, null);
|
this._chatModel.getMessages(userName, passphrase, null, "new");
|
||||||
el.className += " active";
|
el.className += " active";
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSearchButtonEL() {
|
private _addSearchButtonEL() {
|
||||||
this._userSearchButton.addEventListener('submit', (e) => {
|
this._userSearchButton.addEventListener('submit', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// log.trace(temp);
|
// log.trace(temp);
|
||||||
@ -124,12 +127,12 @@ export class UserView implements Observer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let searchResult = this._searchService.search(list, searchTerm);
|
let searchResult = this._searchService.search(list, searchTerm);
|
||||||
this.update(searchResult);
|
this.update({data: searchResult, op: ""});
|
||||||
log.debug(searchResult);
|
log.debug(searchResult);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSearchInputEL() {
|
private _addSearchInputEL() {
|
||||||
this._userSearchInputElement.addEventListener('input', (e) => {
|
this._userSearchInputElement.addEventListener('input', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this._userSearchInputElement.value.length < 2) {
|
if (this._userSearchInputElement.value.length < 2) {
|
||||||
@ -139,14 +142,13 @@ export class UserView implements Observer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSearchCancelEL() {
|
private _addSearchCancelEL() {
|
||||||
this._userSearchCancelButton.addEventListener('click', (e) => {
|
this._userSearchCancelButton.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._userSearchInputElement.value = "";
|
this._userSearchInputElement.value = "";
|
||||||
this._userSearchCancelButton.hidden = true;
|
this._userSearchCancelButton.hidden = true;
|
||||||
let list = this._model.activeUsersList;
|
let list = this._model.activeUsersList;
|
||||||
// @ts-ignore
|
this.update({data: list, op: ""})
|
||||||
this.update(list)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user