A self hosted chat application with end-to-end encrypted messaging.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
7.0 KiB

5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. import { Observer } from "../observe/Observer";
  2. import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
  3. import { ChatModel } from "../model/ChatModel";
  4. import log = require("loglevel");
  5. import * as DOMPurify from "dompurify";
  6. import { SearchService } from "../service/SearchService";
  7. import { UserModel } from "../model/UserModel";
  8. import { UserViewDeps } from "./UserViewDeps";
  9. import { ObserverData } from "../observe/ObserverData";
  10. import { JsonAPI } from "../singleton/JsonAPI";
  11. import { NotificationService } from "../service/NotificationService";
  12. export class UserView implements Observer<ActiveUserViewModel> {
  13. private readonly _model: UserModel;
  14. private readonly _chatModel: ChatModel;
  15. private readonly _usersListElement: HTMLElement;
  16. private readonly _userSearchInputElement: HTMLInputElement;
  17. private readonly _userSearchButton: HTMLElement;
  18. private readonly _userSearchCancelButton: HTMLElement;
  19. private readonly _searchService: SearchService<ActiveUserViewModel>;
  20. private readonly _userContactOnlineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
  21. private readonly _userContactOfflineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
  22. private readonly _notificationService: NotificationService;
  23. constructor(deps: UserViewDeps) {
  24. this._model = deps.model;
  25. this._chatModel = deps.chatModel;
  26. this._usersListElement = deps.usersListElement;
  27. this._userSearchInputElement = deps.userSearchInputElement;
  28. this._userSearchButton = deps.userSearchButton;
  29. this._userSearchCancelButton = deps.userSearchCancelButton;
  30. this._searchService = deps.searchService;
  31. this._userContactOnlineTemplate = deps.userContactOnlineTemplate;
  32. this._userContactOfflineTemplate = deps.userContactOfflineTemplate;
  33. this._notificationService = deps.notificationService;
  34. this._addSearchEventListeners();
  35. }
  36. update(d: ObserverData<ActiveUserViewModel>): void {
  37. let html: string = "";
  38. d.data.forEach((element: ActiveUserViewModel) => {
  39. element.online ? html += this._userContactOnlineTemplate(element) :
  40. html += this._userContactOfflineTemplate(element);
  41. });
  42. $(this._usersListElement).html(DOMPurify.sanitize(html));
  43. this._addUserCallBacks();
  44. }
  45. private _addSearchEventListeners(): void {
  46. this._addSearchButtonEL();
  47. this._addSearchCancelEL();
  48. this._addSearchInputEL();
  49. }
  50. private _addUserCallBacks(): void {
  51. let userBoxes = document.getElementsByClassName('user-box');
  52. Array.from(userBoxes).forEach((ub: Element) =>
  53. ub.addEventListener('click', this._userCallBack.bind(this, ub)))
  54. }
  55. private _userCallBack(el: Element): void {
  56. this._chatModel.clear();
  57. let current = document.getElementsByClassName('user-box active');
  58. let passphrase: string = '';
  59. if (current.length > 0) {
  60. let passphraseInput = document.getElementById('passphrase') as any;
  61. if (passphraseInput == null) {
  62. log.error('passphraseInput element reference is null');
  63. return;
  64. }
  65. passphrase = passphraseInput.value
  66. if (passphrase == '' || passphrase == null) {
  67. // alert('Please input passphrase')
  68. // alertify.error('Please enter a passphrase');
  69. log.error('passphrase is empty or null');
  70. return;
  71. }
  72. current[0].className = current[0].className.replace(" active", "");
  73. }
  74. // Add the active class to the current/clicked button
  75. else if (current.length == 0) {
  76. let elem = document.getElementById('passphrase-initial') as any;
  77. if (elem == null) {
  78. log.error('passphraseInput element reference is null');
  79. return;
  80. }
  81. passphrase = elem.value;
  82. if (passphrase == '' || passphrase == null) {
  83. // // alert('Please input passphrase')
  84. // // alertify.error('Please enter a passphrase');
  85. log.error('passphrase is empty or null');
  86. return;
  87. }
  88. // @ts-ignore: Object is possibly 'null'.
  89. document.getElementById('no-user-selected').hidden = true;
  90. // @ts-ignore: Object is possibly 'null'.
  91. document.getElementById('chat-card').hidden = false;
  92. // @ts-ignore: Object is possibly 'null'.
  93. elem.hidden = true;
  94. }
  95. // console.log(this.getElementsByClassName('to-user-span'));
  96. let elem = el.getElementsByClassName('to-user-span')[0] as HTMLElement;
  97. let userName = elem.innerText;
  98. JsonAPI.contactName = userName;
  99. // @ts-ignore: Object is possibly 'null'.
  100. document.getElementById('user-name-span').innerText = userName;
  101. let vm = this._model.activeUsersList.find(vm => vm.userName === userName);
  102. if (!vm) {
  103. vm = new ActiveUserViewModel();
  104. vm.userName = userName;
  105. }
  106. this._notificationService.passphrasePrompt(vm, this._model.activeUsersList,
  107. this._chatModel.getMessages.bind(this._chatModel),
  108. this._promptHandler.bind(this));
  109. // this._chatModel.getMessages(userName, vm.passphrase, null, "new");
  110. el.className += " active";
  111. }
  112. private _promptHandler(vm: ActiveUserViewModel, vms: ActiveUserViewModel[]) {
  113. // vms.filter(v => v.userName == vm.userName).map(v => v.userName = vm.userName)
  114. log.debug(vms)
  115. this._model.notify();
  116. }
  117. private _addSearchButtonEL() {
  118. this._userSearchButton.addEventListener('submit', (e) => {
  119. e.preventDefault();
  120. // log.trace(temp);
  121. const searchTerm = this._userSearchInputElement.value;
  122. log.debug("search term value = " + searchTerm);
  123. const list = this._model.activeUsersList;
  124. log.debug("active users");
  125. log.debug(list);
  126. if (list == null) {
  127. log.error("Users list is null");
  128. return;
  129. }
  130. let searchResult = this._searchService.search(list, searchTerm);
  131. this.update({ data: searchResult, op: "" });
  132. log.debug(searchResult);
  133. })
  134. }
  135. private _addSearchInputEL() {
  136. this._userSearchInputElement.addEventListener('input', (e) => {
  137. e.preventDefault();
  138. if (this._userSearchInputElement.value.length < 2) {
  139. log.debug("inputted")
  140. this._userSearchCancelButton.hidden = false;
  141. }
  142. })
  143. }
  144. private _addSearchCancelEL() {
  145. this._userSearchCancelButton.addEventListener('click', (e) => {
  146. e.preventDefault();
  147. this._userSearchInputElement.value = "";
  148. this._userSearchCancelButton.hidden = true;
  149. let list = this._model.activeUsersList;
  150. this.update({ data: list, op: "" })
  151. })
  152. }
  153. }