nova
4 years ago
28 changed files with 1649 additions and 31 deletions
-
61chatto/src/main/javascript/package.json
-
237chatto/src/main/javascript/ts/bundle.js
-
2chatto/src/main/javascript/ts/out/controller/AbstractController.js
-
50chatto/src/main/javascript/ts/out/controller/UserController.js
-
10chatto/src/main/javascript/ts/out/main.js
-
2chatto/src/main/javascript/ts/out/model/AbstractModel.js
-
41chatto/src/main/javascript/ts/out/model/UserModel.js
-
64chatto/src/main/javascript/ts/out/observe/observable.js
-
27chatto/src/main/javascript/ts/out/observe/observer.js
-
1chatto/src/main/javascript/ts/out/ts.js
-
2chatto/src/main/javascript/ts/out/view/AbstractView.js
-
49chatto/src/main/javascript/ts/out/view/UserView.js
-
14chatto/src/main/javascript/ts/src/controller/AbstractController.ts
-
51chatto/src/main/javascript/ts/src/controller/UserController.ts
-
41chatto/src/main/javascript/ts/src/main.ts
-
5chatto/src/main/javascript/ts/src/model/AbstractModel.ts
-
12chatto/src/main/javascript/ts/src/model/ModelFactory.ts
-
48chatto/src/main/javascript/ts/src/model/UserModel.ts
-
93chatto/src/main/javascript/ts/src/observe/Observable.ts
-
34chatto/src/main/javascript/ts/src/observe/Observer.ts
-
8chatto/src/main/javascript/ts/src/view/AbstractView.ts
-
63chatto/src/main/javascript/ts/src/view/UserView.ts
-
5chatto/src/main/javascript/ts/src/viewmodel/ActiveUserViewModel.ts
-
8chatto/src/main/javascript/ts/src/viewmodel/ChatMessageViewModel.ts
-
311chatto/src/main/javascript/ts/test.html
-
63chatto/src/main/javascript/ts/tsconfig.json
-
67chatto/src/main/javascript/yarn.lock
-
311chatto/src/main/resources/templates/ts-test.html
@ -1,31 +1,32 @@ |
|||||
{ |
{ |
||||
"dependencies": { |
|
||||
"alertifyjs": "^1.12.0", |
|
||||
"chart.js": "^2.9.3", |
|
||||
"dompurify": "^2.0.7", |
|
||||
"fuse.js": "^3.4.6", |
|
||||
"handlebars": "^4.5.3", |
|
||||
"loglevel": "^1.6.6", |
|
||||
"markdown-it": "^10.0.0", |
|
||||
"sjcl": "^1.0.8" |
|
||||
}, |
|
||||
"devDependencies": { |
|
||||
"browserify": "^16.5.0", |
|
||||
"browserify-css": "^0.15.0", |
|
||||
"browserify-shim": "^3.8.14", |
|
||||
"webpack": "^4.41.2" |
|
||||
}, |
|
||||
"browserify": { |
|
||||
"transform": [ |
|
||||
"browserify-shim" |
|
||||
] |
|
||||
}, |
|
||||
"browserify-shim": { |
|
||||
"loglevel": "global:log", |
|
||||
"markdown-it": "global:markdownit", |
|
||||
"handlebars": "global:Handlebars", |
|
||||
"dompurify": "global:DOMPurify", |
|
||||
"fuse.js": "global:Fuse", |
|
||||
"sjcl": "global:sjcl" |
|
||||
} |
|
||||
} |
|
||||
|
"dependencies": { |
||||
|
"alertifyjs": "^1.12.0", |
||||
|
"chart.js": "^2.9.3", |
||||
|
"dompurify": "^2.0.7", |
||||
|
"fuse.js": "^3.4.6", |
||||
|
"handlebars": "^4.5.3", |
||||
|
"loglevel": "^1.6.6", |
||||
|
"markdown-it": "^10.0.0", |
||||
|
"sjcl": "^1.0.8", |
||||
|
"tsify": "^4.0.1" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"browserify": "^16.5.0", |
||||
|
"browserify-css": "^0.15.0", |
||||
|
"browserify-shim": "^3.8.14", |
||||
|
"webpack": "^4.41.2" |
||||
|
}, |
||||
|
"browserify": { |
||||
|
"transform": [ |
||||
|
"browserify-shim" |
||||
|
] |
||||
|
}, |
||||
|
"browserify-shim": { |
||||
|
"loglevel": "global:log", |
||||
|
"markdown-it": "global:markdownit", |
||||
|
"handlebars": "global:Handlebars", |
||||
|
"dompurify": "global:DOMPurify", |
||||
|
"fuse.js": "global:Fuse", |
||||
|
"sjcl": "global:sjcl" |
||||
|
} |
||||
|
} |
237
chatto/src/main/javascript/ts/bundle.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,2 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
@ -0,0 +1,50 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
require("../model/AbstractModel"); |
||||
|
require("../model/UserModel"); |
||||
|
require("../view/AbstractView"); |
||||
|
require("../view/UserView"); |
||||
|
var UserController = /** @class */ (function () { |
||||
|
function UserController(model, view) { |
||||
|
this._model = model; |
||||
|
this._view = view; |
||||
|
} |
||||
|
Object.defineProperty(UserController.prototype, "model", { |
||||
|
/** |
||||
|
* Getter model |
||||
|
* @return {Model} |
||||
|
*/ |
||||
|
get: function () { |
||||
|
return this._model; |
||||
|
}, |
||||
|
/** |
||||
|
* Setter model |
||||
|
* @param {Model} value |
||||
|
*/ |
||||
|
set: function (value) { |
||||
|
this._model = value; |
||||
|
}, |
||||
|
enumerable: true, |
||||
|
configurable: true |
||||
|
}); |
||||
|
Object.defineProperty(UserController.prototype, "view", { |
||||
|
/** |
||||
|
* Getter view |
||||
|
* @return {View} |
||||
|
*/ |
||||
|
get: function () { |
||||
|
return this._view; |
||||
|
}, |
||||
|
/** |
||||
|
* Setter view |
||||
|
* @param {View} value |
||||
|
*/ |
||||
|
set: function (value) { |
||||
|
this._view = value; |
||||
|
}, |
||||
|
enumerable: true, |
||||
|
configurable: true |
||||
|
}); |
||||
|
return UserController; |
||||
|
}()); |
||||
|
exports.UserController = UserController; |
@ -0,0 +1,10 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
var UserModel_1 = require("./model/UserModel"); |
||||
|
var UserView_1 = require("./view/UserView"); |
||||
|
var UserController_1 = require("./controller/UserController"); |
||||
|
var userModel = new UserModel_1.UserModel(); |
||||
|
var userView = new UserView_1.UserView(userModel, 2); |
||||
|
userModel.attach(userView); |
||||
|
// userView.model
|
||||
|
var userController = new UserController_1.UserController(userModel, userView); |
@ -0,0 +1,2 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
@ -0,0 +1,41 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
var UserModel = /** @class */ (function () { |
||||
|
function UserModel() { |
||||
|
/** |
||||
|
* @type {Observer[]} List of subscribers. In real life, the list of |
||||
|
* subscribers can be stored more comprehensively (categorized by event |
||||
|
* type, etc.). |
||||
|
*/ |
||||
|
this.observers = []; |
||||
|
this.state = 0; |
||||
|
} |
||||
|
/** |
||||
|
* The subscription management methods. |
||||
|
*/ |
||||
|
UserModel.prototype.attach = function (observer) { |
||||
|
console.log('Subject: Attached an observer.'); |
||||
|
this.observers.push(observer); |
||||
|
}; |
||||
|
UserModel.prototype.detach = function (observer) { |
||||
|
var observerIndex = this.observers.indexOf(observer); |
||||
|
this.observers.splice(observerIndex, 1); |
||||
|
console.log('Subject: Detached an observer.'); |
||||
|
}; |
||||
|
/** |
||||
|
* Trigger an update in each subscriber. |
||||
|
*/ |
||||
|
UserModel.prototype.notify = function () { |
||||
|
console.log('Subject: Notifying observers...'); |
||||
|
for (var _i = 0, _a = this.observers; _i < _a.length; _i++) { |
||||
|
var observer = _a[_i]; |
||||
|
observer.update(this.state); |
||||
|
} |
||||
|
}; |
||||
|
UserModel.prototype.someBusinessMethod = function () { |
||||
|
console.log("Subject: My state has just changed to: " + this.state); |
||||
|
this.notify(); |
||||
|
}; |
||||
|
return UserModel; |
||||
|
}()); |
||||
|
exports.UserModel = UserModel; |
@ -0,0 +1,64 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
/** |
||||
|
* The Subject owns some important state and notifies observers when the state |
||||
|
* changes. |
||||
|
*/ |
||||
|
// class ConcreteSubject implements Subject {
|
||||
|
// /**
|
||||
|
// * @type {number} For the sake of simplicity, the Subject's state, essential
|
||||
|
// * to all subscribers, is stored in this variable.
|
||||
|
// */
|
||||
|
// public state: number;
|
||||
|
// /**
|
||||
|
// * @type {Observer[]} List of subscribers. In real life, the list of
|
||||
|
// * subscribers can be stored more comprehensively (categorized by event
|
||||
|
// * type, etc.).
|
||||
|
// */
|
||||
|
// private observers: Observer[] = [];
|
||||
|
// /**
|
||||
|
// * The subscription management methods.
|
||||
|
// */
|
||||
|
// public attach(observer: Observer): void {
|
||||
|
// console.log('Subject: Attached an observer.');
|
||||
|
// this.observers.push(observer);
|
||||
|
// }
|
||||
|
// public detach(observer: Observer): void {
|
||||
|
// const observerIndex = this.observers.indexOf(observer);
|
||||
|
// this.observers.splice(observerIndex, 1);
|
||||
|
// console.log('Subject: Detached an observer.');
|
||||
|
// }
|
||||
|
// /**
|
||||
|
// * Trigger an update in each subscriber.
|
||||
|
// */
|
||||
|
// public notify(): void {
|
||||
|
// console.log('Subject: Notifying observers...');
|
||||
|
// for (const observer of this.observers) {
|
||||
|
// observer.update(this);
|
||||
|
// }
|
||||
|
// }
|
||||
|
// /**
|
||||
|
// * Usually, the subscription logic is only a fraction of what a Subject can
|
||||
|
// * really do. Subjects commonly hold some important business logic, that
|
||||
|
// * triggers a notification method whenever something important is about to
|
||||
|
// * happen (or after it).
|
||||
|
// */
|
||||
|
// public someBusinessLogic(): void {
|
||||
|
// console.log('\nSubject: I\'m doing something important.');
|
||||
|
// this.state = Math.floor(Math.random() * (10 + 1));
|
||||
|
// console.log(`Subject: My state has just changed to: ${this.state}`);
|
||||
|
// this.notify();
|
||||
|
// }
|
||||
|
// }
|
||||
|
// /**
|
||||
|
// * The client code.
|
||||
|
// */
|
||||
|
// const subject = new ConcreteSubject();
|
||||
|
// const observer1 = new ConcreteObserverA();
|
||||
|
// subject.attach(observer1);
|
||||
|
// const observer2 = new ConcreteObserverB();
|
||||
|
// subject.attach(observer2);
|
||||
|
// subject.someBusinessLogic();
|
||||
|
// subject.someBusinessLogic();
|
||||
|
// subject.detach(observer2);
|
||||
|
// subject.someBusinessLogic();
|
@ -0,0 +1,27 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
// /**
|
||||
|
// * The Observer interface declares the update method, used by subjects.
|
||||
|
// */
|
||||
|
// interface Observer {
|
||||
|
// // Receive update from subject.
|
||||
|
// update(subject: Subject): void;
|
||||
|
// }
|
||||
|
// /**
|
||||
|
// * Concrete Observers react to the updates issued by the Subject they had been
|
||||
|
// * attached to.
|
||||
|
// */
|
||||
|
// class ConcreteObserverA implements Observer {
|
||||
|
// public update(subject: Subject): void {
|
||||
|
// if (subject.state < 3) {
|
||||
|
// console.log('ConcreteObserverA: Reacted to the event.');
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
// class ConcreteObserverB implements Observer {
|
||||
|
// public update(subject: Subject): void {
|
||||
|
// if (subject.state === 0 || subject.state >= 2) {
|
||||
|
// console.log('ConcreteObserverB: Reacted to the event.');
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
@ -0,0 +1 @@ |
|||||
|
"use strict"; |
@ -0,0 +1,2 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
@ -0,0 +1,49 @@ |
|||||
|
"use strict"; |
||||
|
Object.defineProperty(exports, "__esModule", { value: true }); |
||||
|
var UserView = /** @class */ (function () { |
||||
|
function UserView(model, element) { |
||||
|
this._model = model; |
||||
|
this._element = element; |
||||
|
} |
||||
|
Object.defineProperty(UserView.prototype, "model", { |
||||
|
/** |
||||
|
* Getter model |
||||
|
* @return {Model} |
||||
|
*/ |
||||
|
get: function () { |
||||
|
return this._model; |
||||
|
}, |
||||
|
/** |
||||
|
* Setter model |
||||
|
* @param {Model} value |
||||
|
*/ |
||||
|
set: function (value) { |
||||
|
this._model = value; |
||||
|
}, |
||||
|
enumerable: true, |
||||
|
configurable: true |
||||
|
}); |
||||
|
Object.defineProperty(UserView.prototype, "element", { |
||||
|
/** |
||||
|
* Getter element |
||||
|
* @return {any} |
||||
|
*/ |
||||
|
get: function () { |
||||
|
return this._element; |
||||
|
}, |
||||
|
/** |
||||
|
* Setter element |
||||
|
* @param {any} value |
||||
|
*/ |
||||
|
set: function (value) { |
||||
|
this._element = value; |
||||
|
}, |
||||
|
enumerable: true, |
||||
|
configurable: true |
||||
|
}); |
||||
|
UserView.prototype.update = function (data) { |
||||
|
console.log(data); |
||||
|
}; |
||||
|
return UserView; |
||||
|
}()); |
||||
|
exports.UserView = UserView; |
@ -0,0 +1,14 @@ |
|||||
|
import { Model } from "../model/AbstractModel"; |
||||
|
|
||||
|
import { View } from "../view/AbstractView"; |
||||
|
// simple restrictions that MVC impose: The Control has a reference to the View and Model + the View has a reference to the Model and the Controller.It also does not have any Observer implementation in the Model, so that the View can update based on it.
|
||||
|
|
||||
|
// export abstract class Controller {
|
||||
|
// protected _model: Model | undefined;
|
||||
|
// protected _view: View | undefined;
|
||||
|
// }
|
||||
|
|
||||
|
export interface Controller { |
||||
|
model: Model, |
||||
|
view: View |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
import { Controller } from "./AbstractController"; |
||||
|
import "../model/AbstractModel" |
||||
|
import "../model/UserModel" |
||||
|
import "../view/AbstractView" |
||||
|
import "../view/UserView" |
||||
|
import { Model } from "../model/AbstractModel"; |
||||
|
import { View } from "../view/AbstractView"; |
||||
|
|
||||
|
export class UserController implements Controller{ |
||||
|
private _model: Model; |
||||
|
private _view: View; |
||||
|
|
||||
|
|
||||
|
constructor(model: Model, view: View) { |
||||
|
this._model = model; |
||||
|
this._view = view; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Getter model |
||||
|
* @return {Model} |
||||
|
*/ |
||||
|
public get model(): Model { |
||||
|
return this._model; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Getter view |
||||
|
* @return {View} |
||||
|
*/ |
||||
|
public get view(): View { |
||||
|
return this._view; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Setter model |
||||
|
* @param {Model} value |
||||
|
*/ |
||||
|
public set model(value: Model) { |
||||
|
this._model = value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Setter view |
||||
|
* @param {View} value |
||||
|
*/ |
||||
|
public set view(value: View) { |
||||
|
this._view = value; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
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 log from "loglevel"; |
||||
|
import { ModelFactory } from "./model/ModelFactory"; |
||||
|
import { ActiveUserViewModel } from "./viewmodel/ActiveUserViewModel"; |
||||
|
import { ChatMessageViewModel } from "./viewmodel/ChatMessageViewModel"; |
||||
|
import Handlebars from "handlebars"; |
||||
|
|
||||
|
|
||||
|
log.setLevel("TRACE") |
||||
|
// let userModel = new UserModel();
|
||||
|
const userModel = ModelFactory.createModel("USER"); |
||||
|
|
||||
|
const userView = new UserView(userModel, 2); |
||||
|
userModel.attach(userView); |
||||
|
// userView.model
|
||||
|
const userController = new UserController(userModel, userView); |
||||
|
userModel.someBusinessMethod(5); |
||||
|
log.info("hello"); |
||||
|
|
||||
|
const chatMessageViewModel= new ChatMessageViewModel(); |
||||
|
|
||||
|
const activeUserViewModel = new ActiveUserViewModel(); |
||||
|
activeUserViewModel.userName = "some user"; |
||||
|
activeUserViewModel.lastActive = new Date(); |
||||
|
activeUserViewModel.online = true; |
||||
|
|
||||
|
function someFunc(vm: ActiveUserViewModel): void { |
||||
|
log.info(vm); |
||||
|
} |
||||
|
|
||||
|
someFunc(activeUserViewModel); |
||||
|
|
||||
|
// @ts-ignore: Object is possibly 'null'.
|
||||
|
var source = document.getElementById("msg_container_template").innerHTML; |
||||
|
|
||||
|
var msgContainerTemplate = Handlebars.compile(source); |
@ -0,0 +1,5 @@ |
|||||
|
import { Subject } from "../observe/Observable"; |
||||
|
|
||||
|
export interface Model extends Subject{ |
||||
|
someBusinessMethod(data: any): void; |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
import { Model } from "./AbstractModel"; |
||||
|
import { UserModel } from "./UserModel"; |
||||
|
|
||||
|
export class ModelFactory { |
||||
|
static createModel(modelName: string): Model { |
||||
|
switch (modelName) { |
||||
|
case "USER": return new UserModel(); |
||||
|
break; |
||||
|
default: throw new Error("Invalid model name"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,48 @@ |
|||||
|
import { Subject } from "../observe/Observable"; |
||||
|
import { Model } from "./AbstractModel"; |
||||
|
import { Observer } from "../observe/Observer"; |
||||
|
|
||||
|
export class UserModel implements Model, Subject { |
||||
|
/** |
||||
|
* @type {Observer[]} List of subscribers. In real life, the list of |
||||
|
* subscribers can be stored more comprehensively (categorized by event |
||||
|
* type, etc.). |
||||
|
*/ |
||||
|
private observers: Observer[] = []; |
||||
|
private state: number = 0; |
||||
|
|
||||
|
constructor() { } |
||||
|
/** |
||||
|
* The subscription management methods. |
||||
|
*/ |
||||
|
public attach(observer: Observer): void { |
||||
|
console.log('Subject: Attached an observer.'); |
||||
|
this.observers.push(observer); |
||||
|
} |
||||
|
|
||||
|
public detach(observer: Observer): void { |
||||
|
const observerIndex = this.observers.indexOf(observer); |
||||
|
this.observers.splice(observerIndex, 1); |
||||
|
console.log('Subject: Detached an observer.'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Trigger an update in each subscriber. |
||||
|
*/ |
||||
|
public notify(): void { |
||||
|
console.log('Subject: Notifying observers...'); |
||||
|
for (const observer of this.observers) { |
||||
|
observer.update(this.state); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public someBusinessMethod(num: number): void { |
||||
|
this.state = num; |
||||
|
this.helperMethod(); |
||||
|
console.log(`Subject: My state has just changed to: ${this.state}`); |
||||
|
this.notify(); |
||||
|
} |
||||
|
|
||||
|
private helperMethod() {} |
||||
|
|
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
import { Observer } from "./Observer"; |
||||
|
|
||||
|
/** |
||||
|
* The Subject interface declares a set of methods for managing subscribers. |
||||
|
*/ |
||||
|
export interface Subject { |
||||
|
// Attach an observer to the subject.
|
||||
|
attach(observer: Observer): void; |
||||
|
|
||||
|
// Detach an observer from the subject.
|
||||
|
detach(observer: Observer): void; |
||||
|
|
||||
|
// Notify all observers about an event.
|
||||
|
notify(): void; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* The Subject owns some important state and notifies observers when the state |
||||
|
* changes. |
||||
|
*/ |
||||
|
// class ConcreteSubject implements Subject {
|
||||
|
// /**
|
||||
|
// * @type {number} For the sake of simplicity, the Subject's state, essential
|
||||
|
// * to all subscribers, is stored in this variable.
|
||||
|
// */
|
||||
|
// public state: number;
|
||||
|
|
||||
|
// /**
|
||||
|
// * @type {Observer[]} List of subscribers. In real life, the list of
|
||||
|
// * subscribers can be stored more comprehensively (categorized by event
|
||||
|
// * type, etc.).
|
||||
|
// */
|
||||
|
// private observers: Observer[] = [];
|
||||
|
|
||||
|
// /**
|
||||
|
// * The subscription management methods.
|
||||
|
// */
|
||||
|
// public attach(observer: Observer): void {
|
||||
|
// console.log('Subject: Attached an observer.');
|
||||
|
// this.observers.push(observer);
|
||||
|
// }
|
||||
|
|
||||
|
// public detach(observer: Observer): void {
|
||||
|
// const observerIndex = this.observers.indexOf(observer);
|
||||
|
// this.observers.splice(observerIndex, 1);
|
||||
|
// console.log('Subject: Detached an observer.');
|
||||
|
// }
|
||||
|
|
||||
|
// /**
|
||||
|
// * Trigger an update in each subscriber.
|
||||
|
// */
|
||||
|
// public notify(): void {
|
||||
|
// console.log('Subject: Notifying observers...');
|
||||
|
// for (const observer of this.observers) {
|
||||
|
// observer.update(this);
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
// /**
|
||||
|
// * Usually, the subscription logic is only a fraction of what a Subject can
|
||||
|
// * really do. Subjects commonly hold some important business logic, that
|
||||
|
// * triggers a notification method whenever something important is about to
|
||||
|
// * happen (or after it).
|
||||
|
// */
|
||||
|
// public someBusinessLogic(): void {
|
||||
|
// console.log('\nSubject: I\'m doing something important.');
|
||||
|
// this.state = Math.floor(Math.random() * (10 + 1));
|
||||
|
|
||||
|
// console.log(`Subject: My state has just changed to: ${this.state}`);
|
||||
|
// this.notify();
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
|
||||
|
|
||||
|
// /**
|
||||
|
// * The client code.
|
||||
|
// */
|
||||
|
|
||||
|
// const subject = new ConcreteSubject();
|
||||
|
|
||||
|
// const observer1 = new ConcreteObserverA();
|
||||
|
// subject.attach(observer1);
|
||||
|
|
||||
|
// const observer2 = new ConcreteObserverB();
|
||||
|
// subject.attach(observer2);
|
||||
|
|
||||
|
// subject.someBusinessLogic();
|
||||
|
// subject.someBusinessLogic();
|
||||
|
|
||||
|
// subject.detach(observer2);
|
||||
|
|
||||
|
// subject.someBusinessLogic();
|
@ -0,0 +1,34 @@ |
|||||
|
import { Subject } from "./Observable"; |
||||
|
|
||||
|
export interface Observer { |
||||
|
// Receive update from subject.
|
||||
|
update(data: any): void; |
||||
|
} |
||||
|
|
||||
|
// /**
|
||||
|
// * The Observer interface declares the update method, used by subjects.
|
||||
|
// */
|
||||
|
// interface Observer {
|
||||
|
// // Receive update from subject.
|
||||
|
// update(subject: Subject): void;
|
||||
|
// }
|
||||
|
|
||||
|
// /**
|
||||
|
// * Concrete Observers react to the updates issued by the Subject they had been
|
||||
|
// * attached to.
|
||||
|
// */
|
||||
|
// class ConcreteObserverA implements Observer {
|
||||
|
// public update(subject: Subject): void {
|
||||
|
// if (subject.state < 3) {
|
||||
|
// console.log('ConcreteObserverA: Reacted to the event.');
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
// class ConcreteObserverB implements Observer {
|
||||
|
// public update(subject: Subject): void {
|
||||
|
// if (subject.state === 0 || subject.state >= 2) {
|
||||
|
// console.log('ConcreteObserverB: Reacted to the event.');
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
@ -0,0 +1,8 @@ |
|||||
|
// simple restrictions that MVC impose: The Control has a reference to the View and Model + the View has a reference to the Model and the Controller.It also does not have any Observer implementation in the Model, so that the View can update based on it.
|
||||
|
import { Model } from "../model/AbstractModel"; |
||||
|
import { Controller } from "../controller/AbstractController"; |
||||
|
import { Observer } from "../observe/Observer"; |
||||
|
export interface View extends Observer { |
||||
|
model: Model, |
||||
|
element: any |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
import { Observer } from "../observe/Observer"; |
||||
|
import { Model } from "../model/AbstractModel"; |
||||
|
import { Subject } from "../observe/Observable"; |
||||
|
import { View } from "./AbstractView"; |
||||
|
import { Controller } from "../controller/AbstractController"; |
||||
|
|
||||
|
export class UserView implements Observer, View { |
||||
|
private _model: Model; |
||||
|
private _element: any; |
||||
|
|
||||
|
|
||||
|
|
||||
|
constructor(model: Model, element: any) { |
||||
|
this._model = model; |
||||
|
this._element = element; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Getter model |
||||
|
* @return {Model} |
||||
|
*/ |
||||
|
public get model(): Model { |
||||
|
return this._model; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Getter element |
||||
|
* @return {any} |
||||
|
*/ |
||||
|
public get element(): any { |
||||
|
return this._element; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Setter model |
||||
|
* @param {Model} value |
||||
|
*/ |
||||
|
public set model(value: Model) { |
||||
|
this._model = value; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* Setter element |
||||
|
* @param {any} value |
||||
|
*/ |
||||
|
public set element(value: any) { |
||||
|
this._element = value; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
update(data: any): void { |
||||
|
this.element = data; |
||||
|
console.log(this.element); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
export class ActiveUserViewModel { |
||||
|
userName: string | undefined; |
||||
|
online: boolean | undefined; |
||||
|
lastActive: Date | undefined; |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
export class ChatMessageViewModel { |
||||
|
public toUser: string | undefined; |
||||
|
public fromUser: string | undefined; |
||||
|
public messageCipher: any; |
||||
|
public messageTime!: Date; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,311 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html xmlns:th="http://www.thymeleaf.org"> |
||||
|
|
||||
|
<head> |
||||
|
|
||||
|
<script src="https://code.jquery.com/jquery-2.1.4.min.js" th:if="false"></script> |
||||
|
<script src="http://blackpeppersoftware.github.io/thymeleaf-fragment.js/thymeleaf-fragment.js" defer="defer" th:if="false"></script> |
||||
|
|
||||
|
<div th:replace="fragments/head :: headFragment"> |
||||
|
<meta charset="UTF-8"> |
||||
|
<title id="pageTitle">Chat</title> |
||||
|
</div> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js" integrity="sha256-nIoG9XIePM1QNttI6KAGLYGNxc4DNinxxmOZW0/Z7uA=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.4.2/handlebars.min.js" integrity="sha256-oh7N5nthuhldTk8/34Za7FXv3BkeVN9vAnYk/pLfC78=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.0.3/purify.min.js" integrity="sha256-58eGKW6SunbeAY1RP9WEbg3nViB9o1qDnxV4yCITqx4=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/10.0.0/markdown-it.min.js"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/alertify.min.js" integrity="sha256-yscIZgtlDR9q6eoYCRmcaiNE6W80UFSnq+6Llwu4NLI=" crossorigin="anonymous"></script> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/alertify.min.css" integrity="sha256-nhstgDCuZGQRk+wvwXZIPt278arHtuZKJ1YQ0rrXiL4=" crossorigin="anonymous" /> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/themes/default.css" integrity="sha256-dawRQVhnqw8jRXaGnK0aj/NpOsPaQm+Em1sWN+fvegI=" crossorigin="anonymous" /> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/themes/bootstrap.css" integrity="sha256-1fgYpB3cyITZIur7E+Mj3R54NtlN9HwHykgKTJf0pmU=" crossorigin="anonymous" /> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.4.5/fuse.min.js" integrity="sha256-Yrh3VGzE4d9b4KANknPJAhfcKt9SgHTL0v/FrJFoPzw=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/loglevel/1.6.4/loglevel.min.js" integrity="sha256-ACTlnmNCkOooSKkPCKYbiex8WLE82aeiN+Z9ElZag5Q=" crossorigin="anonymous"></script> |
||||
|
<script src="./bundle.js"></script> |
||||
|
<link rel="stylesheet" th:href="@{/css/chat.css}" href="../../resources/static/css/chat.css"> |
||||
|
|
||||
|
|
||||
|
|
||||
|
<!-- <script th:src="@{js/my_Crypto.js}" type="text/javascript"></script> --> |
||||
|
|
||||
|
|
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div th:include="fragments/navbar :: navbarFragment"></div> |
||||
|
<header id="chat-section"> |
||||
|
<div class="dark-overlay"> |
||||
|
<div class="chat-inner container bg-primary"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm d-lg-block"> |
||||
|
<h1 class="display-4">Chat with your friends</h1> |
||||
|
<div class="d-flex"> |
||||
|
<div class="p-4 align-self-start"> |
||||
|
|
||||
|
</div> |
||||
|
<div class="p-4 align-self-end"> |
||||
|
|
||||
|
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam dolorem nostrum consequatur eos voluptates. Ipsam ullam quos illo qui. Quaerat corrupti nisi numquam rerum quasi nesciunt deserunt fugit commodi consequatur! |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</header> |
||||
|
<div class="container-fluid h-100"> |
||||
|
<div class="row justify-content-center h-100 mt-3"> |
||||
|
<div class="col-md-4 col-xl-3 chat"> |
||||
|
<div class="card mb-sm-3 mb-md-0 contacts_card"> |
||||
|
<div class="card-header"> |
||||
|
<form action="#" id="user-search"> |
||||
|
<div class="input-group"> |
||||
|
<input type="text" placeholder="Search..." id="user-search-term" class="form-control search"> |
||||
|
<button class="search-cancel" id="user-search-cancel" hidden><i class="fas fa-times"></i></button> |
||||
|
<div class="input-group-prepend"> |
||||
|
|
||||
|
<button class="input-group-text search_btn"><i class="fas fa-search"></i></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="card-body contacts_body"> |
||||
|
<ui class="contacts"> |
||||
|
<li class="active"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span>Khalid</span> |
||||
|
<p>Kalid is online</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</ui> |
||||
|
<ui class="contacts" id="contacts-box"> |
||||
|
<th:block th:each="au: ${activeUsers}"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span th:if="${au.online == true}" class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span class="to-user-span" th:text="${au.userName}">Khalid</span> |
||||
|
<div th:switch="${au.online}"> |
||||
|
<p th:case="true" th:text="${au.userName} + ' is online'">Khalid is online</p> |
||||
|
<th:block th:case="false"> |
||||
|
<th:block th:if="${au.lastActive == null}"> |
||||
|
<p th:text="'User has not logged in yet'"></p> |
||||
|
</th:block> |
||||
|
<th:block th:if="${au.lastActive != null}"> |
||||
|
<p th:text="'Last active ' + ${au.lastActive}">Last active 3 hours ago</p> |
||||
|
</th:block> |
||||
|
<!-- <p th:case="${au.online == true}" th:text="${au.userName} + ' is online'">Khalid is online</p> |
||||
|
<p th:if="${au.online == false}" th:text="${au.userName} + ' is offline' + ' Last active = ' + ${au.lastActive}">Khalid is offline. --> |
||||
|
<!-- <span th:text="'Last active = ' + ${au.lastActive}"></span> --> |
||||
|
</th:block> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</th:block> |
||||
|
</ui> |
||||
|
</div> |
||||
|
<div class="card-footer"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-8 col-xl-6 chat"> |
||||
|
<div class="card" id="no-user-selected"> |
||||
|
<div class="m-auto"> |
||||
|
<div class="d-flex justify-content-center"> |
||||
|
<div class="align-self-center"> |
||||
|
<h2 class="display-4 no-user-selected-h2">Please select a user</h2> |
||||
|
<input class="form-control type_msg" size="10" type="password" id="passphrase-initial" placeholder="Passphrase " required> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card" id="chat-card" hidden> |
||||
|
<div class="card-header msg_head"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span id="user-name-span">Chat with Khalid</span> |
||||
|
<p id="num-messages-p">1767 Messages</p> |
||||
|
</div> |
||||
|
<div class="video_cam"> |
||||
|
<span><i class="fas fa-video"></i></span> |
||||
|
<span><i class="fas fa-phone"></i></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span id="action_menu_btn"><i class="fas fa-ellipsis-v"></i></span> |
||||
|
<div class="action_menu"> |
||||
|
<ul> |
||||
|
<li><i class="fas fa-user-circle"></i> View profile</li> |
||||
|
<li><i class="fas fa-users"></i> Add to close friends</li> |
||||
|
<li><i class="fas fa-plus"></i> Add to group</li> |
||||
|
<li><i class="fas fa-ban"></i> Block</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card-body msg_card_body" id="chat_area_new"> |
||||
|
</div> |
||||
|
<div class="card-footer"> |
||||
|
<form action="#" th:object="${chatMessageDTO}" method="post" id="chatMessageForm" class="needs-validation" novalidate> |
||||
|
<div class="input-group"> |
||||
|
<div class="input-group-append"> |
||||
|
<span class="input-group-text attach_btn"><i class="fas fa-paperclip"></i></span> |
||||
|
</div> |
||||
|
<input class="form-control type_msg" size="10" type="password" id="passphrase" placeholder="Passphrase " required> |
||||
|
<textarea name="" id="chatInput" class="form-control type_msg" placeholder="Type your message..." required></textarea> |
||||
|
<div class="input-group-append"> |
||||
|
<button class="input-group-text send_btn"><i class="fas fa-location-arrow"></i></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<section hidden> |
||||
|
<div class="container"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm"> |
||||
|
|
||||
|
<h4 class="display-4 text-center py-2">Chat</h4> |
||||
|
<div class="card text-white bg-primary mb-3 card-form rounded mx-auto"> |
||||
|
|
||||
|
<div class="card-body rounded"> |
||||
|
<!-- <h4 class="card-title">Chat</h4> --> |
||||
|
<div class="form-group"> |
||||
|
<textarea id="chatTextArea" class="form-control-lg py-2" disabled></textarea> |
||||
|
</div> |
||||
|
<!-- <form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post"> --> |
||||
|
<!-- th:action="@{/api/chat}" --> |
||||
|
<div class="card-text"> |
||||
|
|
||||
|
</div> |
||||
|
<form action="#" th:object="${chatMessageDTO}" method="post" class="needs-validation" novalidate> |
||||
|
<div class="row"> |
||||
|
<div class="col-3"> |
||||
|
<div class="form-group"> |
||||
|
<label class="lead" for="toUser">User to send to: </label> |
||||
|
<th:block th:each="userName: ${userNames}"> |
||||
|
<input class="form-control" type="radio" th:field="*{toUser}" th:value="${userName}"> |
||||
|
<label class="btn btn-secondary" th:for="${#ids.prev('toUser')}" th:text="${userName}"> |
||||
|
Demo User |
||||
|
</label> |
||||
|
</th:block> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="my-form-inputs container"> |
||||
|
<div class="form-group"> |
||||
|
<label for="chatInput">Your message: </label> |
||||
|
<textarea class="form-control" type="text" required></textarea> |
||||
|
<div class="invalid-feedback"> |
||||
|
Cannot be empty |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<label for="passphrase">Passphrase: </label> |
||||
|
<input class="form-control" type="password" required> |
||||
|
</div> |
||||
|
<div class="form-group text-center"> |
||||
|
<button class="btn btn-secondary mx-auto">Submit</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<template id="msg_container_template"> |
||||
|
<div class="d-flex justify-content-start mb-4"> |
||||
|
<div class="img_cont_msg"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg"> |
||||
|
</div> |
||||
|
<div class="msg_container"> |
||||
|
{{{message}}} |
||||
|
<span class="msg_time">{{time}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<template id="msg_container_send_template"> |
||||
|
<div class="d-flex justify-content-end mb-4"> |
||||
|
<div class="msg_container_send"> |
||||
|
{{{message}}} |
||||
|
<span class="msg_time_send">{{time}}</span> |
||||
|
</div> |
||||
|
<!-- <div class="img_cont_msg"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" |
||||
|
class="rounded-circle user_img_msg"> |
||||
|
</div> --> |
||||
|
{{{avatar}}} |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<template id="user-contact-online-template"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span class="to-user-span">{{userName}}</span> |
||||
|
<p>{{userName}} is online</p> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</template> |
||||
|
<template id="user-contact-offline-template"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<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> |
||||
|
<p>Last active {{lastActive}}</p> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</template> |
||||
|
|
||||
|
</body> |
||||
|
<!-- <script th:src="@{js/chat.js}" type="text/javascript"></script> --> |
||||
|
<script src="../static/js/bundle.js" th:src="@{/js/bundle.js}"></script> |
||||
|
<script src="../static/js/chatStatic.js" th:if="false"></script> |
||||
|
|
||||
|
|
||||
|
</html> |
||||
|
|
||||
|
<!-- <div th:include="::frag (${value1},${value2})">...</div> |
||||
|
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div> --> |
@ -0,0 +1,63 @@ |
|||||
|
{ |
||||
|
"compilerOptions": { |
||||
|
/* Basic Options */ |
||||
|
// "incremental": true, /* Enable incremental compilation */ |
||||
|
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ |
||||
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ |
||||
|
// "lib": [], /* Specify library files to be included in the compilation. */ |
||||
|
// "allowJs": true, /* Allow javascript files to be compiled. */ |
||||
|
// "checkJs": true, /* Report errors in .js files. */ |
||||
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ |
||||
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */ |
||||
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ |
||||
|
// "sourceMap": true, /* Generates corresponding '.map' file. */ |
||||
|
// "outFile": "./", /* Concatenate and emit output to single file. */ |
||||
|
"outDir": "./out", /* Redirect output structure to the directory. */ |
||||
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ |
||||
|
// "composite": true, /* Enable project compilation */ |
||||
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ |
||||
|
// "removeComments": true, /* Do not emit comments to output. */ |
||||
|
// "noEmit": true, /* Do not emit outputs. */ |
||||
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ |
||||
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ |
||||
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ |
||||
|
/* Strict Type-Checking Options */ |
||||
|
"strict": true, /* Enable all strict type-checking options. */ |
||||
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ |
||||
|
// "strictNullChecks": true, /* Enable strict null checks. */ |
||||
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ |
||||
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ |
||||
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ |
||||
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ |
||||
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ |
||||
|
/* Additional Checks */ |
||||
|
// "noUnusedLocals": true, /* Report errors on unused locals. */ |
||||
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */ |
||||
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ |
||||
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ |
||||
|
/* Module Resolution Options */ |
||||
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ |
||||
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ |
||||
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ |
||||
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ |
||||
|
// "typeRoots": [], /* List of folders to include type definitions from. */ |
||||
|
// "types": [], /* Type declaration files to be included in compilation. */ |
||||
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ |
||||
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ |
||||
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ |
||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ |
||||
|
/* Source Map Options */ |
||||
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ |
||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ |
||||
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ |
||||
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ |
||||
|
/* Experimental Options */ |
||||
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ |
||||
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ |
||||
|
/* Advanced Options */ |
||||
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ |
||||
|
}, |
||||
|
"include": [ |
||||
|
"src/**/*" |
||||
|
] |
||||
|
} |
@ -0,0 +1,311 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html xmlns:th="http://www.thymeleaf.org"> |
||||
|
|
||||
|
<head> |
||||
|
|
||||
|
<script src="https://code.jquery.com/jquery-2.1.4.min.js" th:if="false"></script> |
||||
|
<script src="http://blackpeppersoftware.github.io/thymeleaf-fragment.js/thymeleaf-fragment.js" defer="defer" th:if="false"></script> |
||||
|
|
||||
|
<div th:replace="fragments/head :: headFragment"> |
||||
|
<meta charset="UTF-8"> |
||||
|
<title id="pageTitle">Chat</title> |
||||
|
</div> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js" integrity="sha256-nIoG9XIePM1QNttI6KAGLYGNxc4DNinxxmOZW0/Z7uA=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.4.2/handlebars.min.js" integrity="sha256-oh7N5nthuhldTk8/34Za7FXv3BkeVN9vAnYk/pLfC78=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.0.3/purify.min.js" integrity="sha256-58eGKW6SunbeAY1RP9WEbg3nViB9o1qDnxV4yCITqx4=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/10.0.0/markdown-it.min.js"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/alertify.min.js" integrity="sha256-yscIZgtlDR9q6eoYCRmcaiNE6W80UFSnq+6Llwu4NLI=" crossorigin="anonymous"></script> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/alertify.min.css" integrity="sha256-nhstgDCuZGQRk+wvwXZIPt278arHtuZKJ1YQ0rrXiL4=" crossorigin="anonymous" /> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/themes/default.css" integrity="sha256-dawRQVhnqw8jRXaGnK0aj/NpOsPaQm+Em1sWN+fvegI=" crossorigin="anonymous" /> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/AlertifyJS/1.12.0/css/themes/bootstrap.css" integrity="sha256-1fgYpB3cyITZIur7E+Mj3R54NtlN9HwHykgKTJf0pmU=" crossorigin="anonymous" /> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.4.5/fuse.min.js" integrity="sha256-Yrh3VGzE4d9b4KANknPJAhfcKt9SgHTL0v/FrJFoPzw=" crossorigin="anonymous"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/loglevel/1.6.4/loglevel.min.js" integrity="sha256-ACTlnmNCkOooSKkPCKYbiex8WLE82aeiN+Z9ElZag5Q=" crossorigin="anonymous"></script> |
||||
|
<script src="./../../javascript/ts/bundle.js" defer></script> |
||||
|
<link rel="stylesheet" th:href="@{/css/chat.css}" href="../../resources/static/css/chat.css"> |
||||
|
|
||||
|
|
||||
|
|
||||
|
<!-- <script th:src="@{js/my_Crypto.js}" type="text/javascript"></script> --> |
||||
|
|
||||
|
|
||||
|
</head> |
||||
|
|
||||
|
<body> |
||||
|
<div th:include="fragments/navbar :: navbarFragment"></div> |
||||
|
<header id="chat-section"> |
||||
|
<div class="dark-overlay"> |
||||
|
<div class="chat-inner container bg-primary"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm d-lg-block"> |
||||
|
<h1 class="display-4">Chat with your friends</h1> |
||||
|
<div class="d-flex"> |
||||
|
<div class="p-4 align-self-start"> |
||||
|
|
||||
|
</div> |
||||
|
<div class="p-4 align-self-end"> |
||||
|
|
||||
|
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Laboriosam dolorem nostrum consequatur eos voluptates. Ipsam ullam quos illo qui. Quaerat corrupti nisi numquam rerum quasi nesciunt deserunt fugit commodi consequatur! |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
</header> |
||||
|
<div class="container-fluid h-100"> |
||||
|
<div class="row justify-content-center h-100 mt-3"> |
||||
|
<div class="col-md-4 col-xl-3 chat"> |
||||
|
<div class="card mb-sm-3 mb-md-0 contacts_card"> |
||||
|
<div class="card-header"> |
||||
|
<form action="#" id="user-search"> |
||||
|
<div class="input-group"> |
||||
|
<input type="text" placeholder="Search..." id="user-search-term" class="form-control search"> |
||||
|
<button class="search-cancel" id="user-search-cancel" hidden><i class="fas fa-times"></i></button> |
||||
|
<div class="input-group-prepend"> |
||||
|
|
||||
|
<button class="input-group-text search_btn"><i class="fas fa-search"></i></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="card-body contacts_body"> |
||||
|
<ui class="contacts"> |
||||
|
<li class="active"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span>Khalid</span> |
||||
|
<p>Kalid is online</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</ui> |
||||
|
<ui class="contacts" id="contacts-box"> |
||||
|
<th:block th:each="au: ${activeUsers}"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span th:if="${au.online == true}" class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span class="to-user-span" th:text="${au.userName}">Khalid</span> |
||||
|
<div th:switch="${au.online}"> |
||||
|
<p th:case="true" th:text="${au.userName} + ' is online'">Khalid is online</p> |
||||
|
<th:block th:case="false"> |
||||
|
<th:block th:if="${au.lastActive == null}"> |
||||
|
<p th:text="'User has not logged in yet'"></p> |
||||
|
</th:block> |
||||
|
<th:block th:if="${au.lastActive != null}"> |
||||
|
<p th:text="'Last active ' + ${au.lastActive}">Last active 3 hours ago</p> |
||||
|
</th:block> |
||||
|
<!-- <p th:case="${au.online == true}" th:text="${au.userName} + ' is online'">Khalid is online</p> |
||||
|
<p th:if="${au.online == false}" th:text="${au.userName} + ' is offline' + ' Last active = ' + ${au.lastActive}">Khalid is offline. --> |
||||
|
<!-- <span th:text="'Last active = ' + ${au.lastActive}"></span> --> |
||||
|
</th:block> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</th:block> |
||||
|
</ui> |
||||
|
</div> |
||||
|
<div class="card-footer"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-8 col-xl-6 chat"> |
||||
|
<div class="card" id="no-user-selected"> |
||||
|
<div class="m-auto"> |
||||
|
<div class="d-flex justify-content-center"> |
||||
|
<div class="align-self-center"> |
||||
|
<h2 class="display-4 no-user-selected-h2">Please select a user</h2> |
||||
|
<input class="form-control type_msg" size="10" type="password" id="passphrase-initial" placeholder="Passphrase " required> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card" id="chat-card" hidden> |
||||
|
<div class="card-header msg_head"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span id="user-name-span">Chat with Khalid</span> |
||||
|
<p id="num-messages-p">1767 Messages</p> |
||||
|
</div> |
||||
|
<div class="video_cam"> |
||||
|
<span><i class="fas fa-video"></i></span> |
||||
|
<span><i class="fas fa-phone"></i></span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<span id="action_menu_btn"><i class="fas fa-ellipsis-v"></i></span> |
||||
|
<div class="action_menu"> |
||||
|
<ul> |
||||
|
<li><i class="fas fa-user-circle"></i> View profile</li> |
||||
|
<li><i class="fas fa-users"></i> Add to close friends</li> |
||||
|
<li><i class="fas fa-plus"></i> Add to group</li> |
||||
|
<li><i class="fas fa-ban"></i> Block</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card-body msg_card_body" id="chat_area_new"> |
||||
|
</div> |
||||
|
<div class="card-footer"> |
||||
|
<form action="#" th:object="${chatMessageDTO}" method="post" id="chatMessageForm" class="needs-validation" novalidate> |
||||
|
<div class="input-group"> |
||||
|
<div class="input-group-append"> |
||||
|
<span class="input-group-text attach_btn"><i class="fas fa-paperclip"></i></span> |
||||
|
</div> |
||||
|
<input class="form-control type_msg" size="10" type="password" id="passphrase" placeholder="Passphrase " required> |
||||
|
<textarea name="" id="chatInput" class="form-control type_msg" placeholder="Type your message..." required></textarea> |
||||
|
<div class="input-group-append"> |
||||
|
<button class="input-group-text send_btn"><i class="fas fa-location-arrow"></i></button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<section hidden> |
||||
|
<div class="container"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm"> |
||||
|
|
||||
|
<h4 class="display-4 text-center py-2">Chat</h4> |
||||
|
<div class="card text-white bg-primary mb-3 card-form rounded mx-auto"> |
||||
|
|
||||
|
<div class="card-body rounded"> |
||||
|
<!-- <h4 class="card-title">Chat</h4> --> |
||||
|
<div class="form-group"> |
||||
|
<textarea id="chatTextArea" class="form-control-lg py-2" disabled></textarea> |
||||
|
</div> |
||||
|
<!-- <form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post"> --> |
||||
|
<!-- th:action="@{/api/chat}" --> |
||||
|
<div class="card-text"> |
||||
|
|
||||
|
</div> |
||||
|
<form action="#" th:object="${chatMessageDTO}" method="post" class="needs-validation" novalidate> |
||||
|
<div class="row"> |
||||
|
<div class="col-3"> |
||||
|
<div class="form-group"> |
||||
|
<label class="lead" for="toUser">User to send to: </label> |
||||
|
<th:block th:each="userName: ${userNames}"> |
||||
|
<input class="form-control" type="radio" th:field="*{toUser}" th:value="${userName}"> |
||||
|
<label class="btn btn-secondary" th:for="${#ids.prev('toUser')}" th:text="${userName}"> |
||||
|
Demo User |
||||
|
</label> |
||||
|
</th:block> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="my-form-inputs container"> |
||||
|
<div class="form-group"> |
||||
|
<label for="chatInput">Your message: </label> |
||||
|
<textarea class="form-control" type="text" required></textarea> |
||||
|
<div class="invalid-feedback"> |
||||
|
Cannot be empty |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<label for="passphrase">Passphrase: </label> |
||||
|
<input class="form-control" type="password" required> |
||||
|
</div> |
||||
|
<div class="form-group text-center"> |
||||
|
<button class="btn btn-secondary mx-auto">Submit</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<template id="msg_container_template"> |
||||
|
<div class="d-flex justify-content-start mb-4"> |
||||
|
<div class="img_cont_msg"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg"> |
||||
|
</div> |
||||
|
<div class="msg_container"> |
||||
|
{{{message}}} |
||||
|
<span class="msg_time">{{time}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<template id="msg_container_send_template"> |
||||
|
<div class="d-flex justify-content-end mb-4"> |
||||
|
<div class="msg_container_send"> |
||||
|
{{{message}}} |
||||
|
<span class="msg_time_send">{{time}}</span> |
||||
|
</div> |
||||
|
<!-- <div class="img_cont_msg"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" |
||||
|
class="rounded-circle user_img_msg"> |
||||
|
</div> --> |
||||
|
{{{avatar}}} |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<template id="user-contact-online-template"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img"> |
||||
|
<span class="online_icon"></span> |
||||
|
</div> |
||||
|
<div class="user_info"> |
||||
|
<span class="to-user-span">{{userName}}</span> |
||||
|
<p>{{userName}} is online</p> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</template> |
||||
|
<template id="user-contact-offline-template"> |
||||
|
<li name="user-box" class="user-box"> |
||||
|
<div class="d-flex bd-highlight"> |
||||
|
<div class="img_cont"> |
||||
|
<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> |
||||
|
<p>Last active {{lastActive}}</p> |
||||
|
</div> |
||||
|
<div class="d-flex flex-column ml-auto"> |
||||
|
<div class="text-right">Dec 25</div> |
||||
|
<div style="color: rgba(255,255,255,0.7);">Hello how are you</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</li> |
||||
|
</template> |
||||
|
|
||||
|
</body> |
||||
|
<!-- <script th:src="@{js/chat.js}" type="text/javascript"></script> --> |
||||
|
<!-- <script src="../static/js/bundle.js" th:src="@{/js/bundle.js}"></script> --> |
||||
|
<script src="../static/js/chatStatic.js" th:if="false"></script> |
||||
|
|
||||
|
|
||||
|
</html> |
||||
|
|
||||
|
<!-- <div th:include="::frag (${value1},${value2})">...</div> |
||||
|
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div> --> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue