temp commit

This commit is contained in:
nova 2020-02-14 19:18:22 +05:30
parent 4b4df5baf9
commit 78ed6430da
11 changed files with 183 additions and 17 deletions

View File

@ -1,11 +1,13 @@
{
"dependencies": {
"@types/bootbox": "^5.2.0",
"@types/dompurify": "^2.0.0",
"@types/jquery": "^3.3.31",
"@types/markdown-it": "^0.0.9",
"@types/sjcl": "^1.0.28",
"@types/sprintf-js": "^1.1.2",
"alertifyjs": "^1.12.0",
"bootbox": "^5.4.0",
"builder-pattern": "^1.2.3",
"chart.js": "^2.9.3",
"dompurify": "^2.0.7",
@ -43,7 +45,13 @@
"fuse.js": "global:Fuse",
"sjcl": "global:sjcl",
"sprintf-js": "global:sprintf",
"alertifyjs": "global:alertify"
"alertifyjs": "global:alertify",
"bootbox": {
"exports": "global:bootbox",
"depends": [
"@types/jquery"
]
}
},
"scripts": {
"watch": "watchify ts/src/main.ts -p [ tsify --target ES6 --noImplicitAny ] --debug -o ../resources/static/js/bundle.js"

View File

@ -66,7 +66,8 @@ const uvDeps: UserViewDeps = {
userSearchCancelButton: userSearchCancelButton,
searchService: activeUserSearchService,
userContactOnlineTemplate: TemplateFactory.getTemplate('user-contact-online-template'),
userContactOfflineTemplate: TemplateFactory.getTemplate('user-contact-offline-template')
userContactOfflineTemplate: TemplateFactory.getTemplate('user-contact-offline-template'),
notificationService: ns
}
const userView = new UserView(uvDeps);
userModel.attach(userView);
@ -79,14 +80,22 @@ 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>';
});
Handlebars.registerHelper('fromNow', function (date: string) {
if(date == null)
return ": Never"
if (date == null)
return ": Never"
return moment(date).fromNow();
})
Handlebars.registerHelper('msgDateFormat', function (date: string) {
return moment(date).calendar(moment.now(), { lastWeek: "DD/MM/YY hh:mm A", sameElse: "DD/MM/YY hh:mm A" })
})
Handlebars.registerHelper('lockIcon', function (unlocked: boolean) {
switch (unlocked) {
case true: { return '<i class="fas fa-lock-open user-passphrase"></i>'; }
default: { return '<i class="fas fa-lock user-passphrase"></i>'; }
}
})
ns.success("Welcome");

View File

@ -94,8 +94,9 @@ export class ChatModel implements Subject<ChatMessageViewModel> {
}
public clear(): void {
log.info("Clearing model")
this._messagePageMap.set(JsonAPI.contactName!, 0);
this.storeUserMessages(JsonAPI.contactName!, [], "clear");
this.storeUserMessages(JsonAPI.contactName!, Array(), "clear");
this.notify({ userName: "", data: [], op: "clear" })
}

View File

@ -1,7 +1,11 @@
import { NotificationService } from "./NotificationService";
// @ts-ignore
import * as alertify from "alertifyjs";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import log = require("loglevel");
import bootbox = require("bootbox")
export class AlertifyNotificationService implements NotificationService {
private readonly _alertify = alertify;
constructor() {
this._alertify.set('notifier', 'position', 'top-center');
@ -24,4 +28,84 @@ export class AlertifyNotificationService implements NotificationService {
message(message: string): void {
this._alertify.message(message);
}
passphrasePrompt(vm: ActiveUserViewModel, vms: ActiveUserViewModel[], cb1: (contactName: string, passphrase: string,
lastMessageTime: string | null, op: string) => void,
cb2: () => any): void {
// alertify.myprompt || alertify.dialog('myprompt', function () {
// // document.getElementById('passphraseFormNew')!.addEventListener('submit', function (e: Event) {
// // e.preventDefault();
// // log.debug(this.querySelectorAll('input'))
// // Array.from(this.querySelectorAll('input')).map((el) => {
// // const el2 = el as HTMLInputElement;
// // vm.passphrase = el2.value;
// // vm.unlocked = true;
// // cb1(vm.userName!, vm.passphrase, null, "new");
// // cb2();
// // alertify.myprompt().close();
// // })
// // log.debug(vm)
// // })
// return {
// main: function (content: HTMLElement) {
// log.debug(vm)
// // @ts-ignore
// this.setContent(content);
// },
// setup: function () {
// return {
// focus: {
// // @ts-ignore
// element: function () {
// // @ts-ignore
// return this.elements.body.querySelector(this.get('selector'));
// },
// select: true
// },
// options: {
// title: 'Enter Passphrase',
// basic: true,
// maximizable: false,
// resizable: false,
// padding: false
// }
// };
// },
// settings: {
// // @ts-ignore
// selector: undefined
// },
// }
// })
// alertify.myprompt(document.getElementById('passphraseFormNew')).set('selector', 'input[type="password"]');
if (vm.passphrase == null) {
bootbox.prompt({
title: "Please enter the passphrase",
inputType: 'password',
callback: function (result) {
if (result) {
log.debug(result);
cb1(vm.userName!, result, null, "new");
vm.unlocked = true
vms.filter(v => v.userName == vm.userName).map(v => { v.passphrase = result; v.unlocked = true })
cb2();
log.debug(vm)
log.debug(vms)
}
}
});
}
else {
cb1(vm.userName!, vm.passphrase, null, "new");
}
}
}

View File

@ -1,7 +1,10 @@
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
export interface NotificationService {
success(message: string): void;
error(message: string): void;
errorWithDelay(message: string, delay: number): void;
warning(message: string): void;
message(message: string): void;
passphrasePrompt(vm: ActiveUserViewModel, vms: ActiveUserViewModel[], cb1: (...x: any) => any, cb2: (...x: any) => any): void;
}

View File

@ -8,10 +8,11 @@ import { UserModel } from "../model/UserModel";
import { UserViewDeps } from "./UserViewDeps";
import { ObserverData } from "../observe/ObserverData";
import { JsonAPI } from "../singleton/JsonAPI";
import { NotificationService } from "../service/NotificationService";
export class UserView implements Observer<ActiveUserViewModel> {
private readonly _model: UserModel;
private readonly _chatModel: ChatModel;
private readonly _usersListElement: HTMLElement;
@ -21,6 +22,7 @@ export class UserView implements Observer<ActiveUserViewModel> {
private readonly _searchService: SearchService<ActiveUserViewModel>;
private readonly _userContactOnlineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
private readonly _userContactOfflineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
private readonly _notificationService: NotificationService;
constructor(deps: UserViewDeps) {
this._model = deps.model;
@ -32,6 +34,7 @@ export class UserView implements Observer<ActiveUserViewModel> {
this._searchService = deps.searchService;
this._userContactOnlineTemplate = deps.userContactOnlineTemplate;
this._userContactOfflineTemplate = deps.userContactOfflineTemplate;
this._notificationService = deps.notificationService;
this._addSearchEventListeners();
}
@ -39,7 +42,8 @@ export class UserView implements Observer<ActiveUserViewModel> {
update(d: ObserverData<ActiveUserViewModel>): void {
let html: string = "";
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._addUserCallBacks();
@ -53,10 +57,9 @@ export class UserView implements Observer<ActiveUserViewModel> {
private _addUserCallBacks(): void {
let userBoxes = document.getElementsByClassName('user-box');
for (let i = 0; i < userBoxes.length; i++) {
let userBox = userBoxes[i];
userBoxes[i].addEventListener('click', this._userCallBack.bind(this, userBox));
}
Array.from(userBoxes).forEach((ub: Element) =>
ub.addEventListener('click', this._userCallBack.bind(this, ub)))
}
@ -109,10 +112,24 @@ export class UserView implements Observer<ActiveUserViewModel> {
JsonAPI.contactName = userName;
// @ts-ignore: Object is possibly 'null'.
document.getElementById('user-name-span').innerText = userName;
this._chatModel.getMessages(userName, passphrase, null, "new");
let vm = this._model.activeUsersList.find(vm => vm.userName === userName);
if (!vm) {
vm = new ActiveUserViewModel();
vm.userName = userName;
}
this._notificationService.passphrasePrompt(vm, this._model.activeUsersList,
this._chatModel.getMessages.bind(this._chatModel),
this._promptHandler.bind(this));
// this._chatModel.getMessages(userName, vm.passphrase, null, "new");
el.className += " active";
}
private _promptHandler(vm: ActiveUserViewModel, vms: ActiveUserViewModel[]) {
// vms.filter(v => v.userName == vm.userName).map(v => v.userName = vm.userName)
log.debug(vms)
this._model.notify();
}
private _addSearchButtonEL() {
this._userSearchButton.addEventListener('submit', (e) => {
e.preventDefault();
@ -127,7 +144,7 @@ export class UserView implements Observer<ActiveUserViewModel> {
return;
}
let searchResult = this._searchService.search(list, searchTerm);
this.update({data: searchResult, op: ""});
this.update({ data: searchResult, op: "" });
log.debug(searchResult);
})
}
@ -148,7 +165,7 @@ export class UserView implements Observer<ActiveUserViewModel> {
this._userSearchInputElement.value = "";
this._userSearchCancelButton.hidden = true;
let list = this._model.activeUsersList;
this.update({data: list, op: ""})
this.update({ data: list, op: "" })
})
}

View File

@ -5,6 +5,7 @@ import { ChatModel } from "../model/ChatModel";
import { SearchService } from "../service/SearchService";
import { ActiveUserViewModel } from "../viewmodel/ActiveUserViewModel";
import { NotificationService } from "../service/NotificationService";
export interface UserViewDeps {
model: UserModel;
@ -16,4 +17,5 @@ export interface UserViewDeps {
searchService: SearchService<ActiveUserViewModel>;
userContactOnlineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
userContactOfflineTemplate: Handlebars.TemplateDelegate<ActiveUserViewModel>;
notificationService: NotificationService;
}

View File

@ -1,5 +1,7 @@
export class ActiveUserViewModel {
userName: string | undefined;
online: boolean | undefined;
online: boolean = false;
unlocked: boolean = false;
passphrase: string = "";
lastActive: Date | undefined;
}

View File

@ -2,6 +2,13 @@
# yarn lockfile v1
"@types/bootbox@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@types/bootbox/-/bootbox-5.2.0.tgz#0e51344914dbe2fbb5c720b3bc2797c467d2115a"
integrity sha512-aHKihTnKaYUqWvii5DlJDQqVud4Bp2fmfGKIaLRfsb/DzuLyvdFLnI9RKiXaNnVLQ0g6sorQZMwiV102r6UASw==
dependencies:
"@types/jquery" "*"
"@types/dompurify@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.0.tgz#9616caa5bf2569aea2e4889d4f929d968c081b40"
@ -9,6 +16,13 @@
dependencies:
"@types/trusted-types" "*"
"@types/jquery@*":
version "3.3.32"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.32.tgz#93e27fdc45dd38ee07f2f0acf34b59c1ccee036f"
integrity sha512-UKoof2mnV/X1/Ix2g+V2Ny5sgHjV8nK/UJbiYxuo4zPwzGyFlZ/mp4KaePb2VqQrqJctmcDQNA57buU84/2uIw==
dependencies:
"@types/sizzle" "*"
"@types/jquery@^3.3.31":
version "3.3.31"
resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.31.tgz#27c706e4bf488474e1cb54a71d8303f37c93451b"
@ -258,6 +272,20 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
bootbox@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/bootbox/-/bootbox-5.4.0.tgz#2857a63c270b1b797d62e4c5597e74b497267655"
integrity sha512-GCPrDwZpJsUnqzrto3ZURVafypl13+DAyE3YZx5jR5EIoTDSyREPhr77hlCuPKvM6VvXR5Mh/34W3DYMC7JE9g==
dependencies:
bootstrap "^4.4.0"
jquery "^3.4.1"
popper.js "^1.16.0"
bootstrap@^4.4.0:
version "4.4.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -1689,6 +1717,11 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
jquery@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2"
integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==
js-yaml@~3.13.0:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
@ -2215,6 +2248,11 @@ pinkie@^2.0.0:
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
popper.js@^1.16.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"

View File

@ -256,7 +256,7 @@
<span class="online_icon"></span>
</div>
<div class="user_info">
<span class="to-user-span">{{userName}}</span>
<span class="to-user-span">{{userName}}</span><span> {{{lockIcon unlocked}}}</span>
<p>{{userName}} is online</p>
</div>
<div class="d-flex flex-column ml-auto">
@ -273,7 +273,7 @@
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img">
</div>
<div class="user_info">
<span class="to-user-span">{{userName}}</span>
<span class="to-user-span">{{userName}}</span><span> {{{lockIcon unlocked}}}</span>
<p>Last active {{fromNow lastActive}}</p>
</div>
<div class="d-flex flex-column ml-auto">

View File

@ -14,6 +14,8 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.bundle.min.js" integrity="sha256-OUFW7hFO0/r5aEGTQOz9F/aXQOt+TwqI1Z4fbVvww04=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js" integrity="sha256-sfG8c9ILUB8EXQ5muswfjZsKICbRIJUG/kBogvvV5sY=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" integrity="sha256-+N4/V/SbAFiW1MPBCXnfnP9QSN3+Keu+NlB+0ev/YKQ=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha256-TQq84xX6vkwR0Qs1qH5ADkP+MvH0W+9E7TdHJsoIQiM=" crossorigin="anonymous"></script>