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