moved to typescript for frontend
This commit is contained in:
parent
bfe2c21e1b
commit
f0e8beb27c
@ -1,31 +1,32 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"alertifyjs": "^1.12.0",
|
"alertifyjs": "^1.12.0",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
"dompurify": "^2.0.7",
|
"dompurify": "^2.0.7",
|
||||||
"fuse.js": "^3.4.6",
|
"fuse.js": "^3.4.6",
|
||||||
"handlebars": "^4.5.3",
|
"handlebars": "^4.5.3",
|
||||||
"loglevel": "^1.6.6",
|
"loglevel": "^1.6.6",
|
||||||
"markdown-it": "^10.0.0",
|
"markdown-it": "^10.0.0",
|
||||||
"sjcl": "^1.0.8"
|
"sjcl": "^1.0.8",
|
||||||
},
|
"tsify": "^4.0.1"
|
||||||
"devDependencies": {
|
},
|
||||||
"browserify": "^16.5.0",
|
"devDependencies": {
|
||||||
"browserify-css": "^0.15.0",
|
"browserify": "^16.5.0",
|
||||||
"browserify-shim": "^3.8.14",
|
"browserify-css": "^0.15.0",
|
||||||
"webpack": "^4.41.2"
|
"browserify-shim": "^3.8.14",
|
||||||
},
|
"webpack": "^4.41.2"
|
||||||
"browserify": {
|
},
|
||||||
"transform": [
|
"browserify": {
|
||||||
"browserify-shim"
|
"transform": [
|
||||||
]
|
"browserify-shim"
|
||||||
},
|
]
|
||||||
"browserify-shim": {
|
},
|
||||||
"loglevel": "global:log",
|
"browserify-shim": {
|
||||||
"markdown-it": "global:markdownit",
|
"loglevel": "global:log",
|
||||||
"handlebars": "global:Handlebars",
|
"markdown-it": "global:markdownit",
|
||||||
"dompurify": "global:DOMPurify",
|
"handlebars": "global:Handlebars",
|
||||||
"fuse.js": "global:Fuse",
|
"dompurify": "global:DOMPurify",
|
||||||
"sjcl": "global:sjcl"
|
"fuse.js": "global:Fuse",
|
||||||
}
|
"sjcl": "global:sjcl"
|
||||||
}
|
}
|
||||||
|
}
|
237
chatto/src/main/javascript/ts/bundle.js
Normal file
237
chatto/src/main/javascript/ts/bundle.js
Normal file
File diff suppressed because one or more lines are too long
@ -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;
|
10
chatto/src/main/javascript/ts/out/main.js
Normal file
10
chatto/src/main/javascript/ts/out/main.js
Normal file
@ -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);
|
2
chatto/src/main/javascript/ts/out/model/AbstractModel.js
Normal file
2
chatto/src/main/javascript/ts/out/model/AbstractModel.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
41
chatto/src/main/javascript/ts/out/model/UserModel.js
Normal file
41
chatto/src/main/javascript/ts/out/model/UserModel.js
Normal file
@ -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;
|
64
chatto/src/main/javascript/ts/out/observe/observable.js
Normal file
64
chatto/src/main/javascript/ts/out/observe/observable.js
Normal file
@ -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();
|
27
chatto/src/main/javascript/ts/out/observe/observer.js
Normal file
27
chatto/src/main/javascript/ts/out/observe/observer.js
Normal file
@ -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.');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
1
chatto/src/main/javascript/ts/out/ts.js
Normal file
1
chatto/src/main/javascript/ts/out/ts.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
"use strict";
|
2
chatto/src/main/javascript/ts/out/view/AbstractView.js
Normal file
2
chatto/src/main/javascript/ts/out/view/AbstractView.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
49
chatto/src/main/javascript/ts/out/view/UserView.js
Normal file
49
chatto/src/main/javascript/ts/out/view/UserView.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
chatto/src/main/javascript/ts/src/main.ts
Normal file
41
chatto/src/main/javascript/ts/src/main.ts
Normal file
@ -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);
|
5
chatto/src/main/javascript/ts/src/model/AbstractModel.ts
Normal file
5
chatto/src/main/javascript/ts/src/model/AbstractModel.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { Subject } from "../observe/Observable";
|
||||||
|
|
||||||
|
export interface Model extends Subject{
|
||||||
|
someBusinessMethod(data: any): void;
|
||||||
|
}
|
12
chatto/src/main/javascript/ts/src/model/ModelFactory.ts
Normal file
12
chatto/src/main/javascript/ts/src/model/ModelFactory.ts
Normal file
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
chatto/src/main/javascript/ts/src/model/UserModel.ts
Normal file
48
chatto/src/main/javascript/ts/src/model/UserModel.ts
Normal file
@ -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() {}
|
||||||
|
|
||||||
|
}
|
93
chatto/src/main/javascript/ts/src/observe/Observable.ts
Normal file
93
chatto/src/main/javascript/ts/src/observe/Observable.ts
Normal file
@ -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();
|
34
chatto/src/main/javascript/ts/src/observe/Observer.ts
Normal file
34
chatto/src/main/javascript/ts/src/observe/Observer.ts
Normal file
@ -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.');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
8
chatto/src/main/javascript/ts/src/view/AbstractView.ts
Normal file
8
chatto/src/main/javascript/ts/src/view/AbstractView.ts
Normal file
@ -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
|
||||||
|
}
|
63
chatto/src/main/javascript/ts/src/view/UserView.ts
Normal file
63
chatto/src/main/javascript/ts/src/view/UserView.ts
Normal file
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
311
chatto/src/main/javascript/ts/test.html
Normal file
311
chatto/src/main/javascript/ts/test.html
Normal file
@ -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> -->
|
63
chatto/src/main/javascript/ts/tsconfig.json
Normal file
63
chatto/src/main/javascript/ts/tsconfig.json
Normal file
@ -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/**/*"
|
||||||
|
]
|
||||||
|
}
|
@ -249,6 +249,11 @@ ansi-regex@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||||
|
|
||||||
|
any-promise@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||||
|
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
|
||||||
|
|
||||||
anymatch@^2.0.0:
|
anymatch@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
|
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
|
||||||
@ -805,6 +810,13 @@ constants-browserify@^1.0.0, constants-browserify@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||||
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
||||||
|
|
||||||
|
convert-source-map@^1.1.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
||||||
|
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "~5.1.1"
|
||||||
|
|
||||||
convert-source-map@~1.1.0:
|
convert-source-map@~1.1.0:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
|
||||||
@ -1096,6 +1108,13 @@ errno@^0.1.3, errno@~0.1.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prr "~1.0.1"
|
prr "~1.0.1"
|
||||||
|
|
||||||
|
error-ex@^1.2.0:
|
||||||
|
version "1.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||||
|
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
|
||||||
|
dependencies:
|
||||||
|
is-arrayish "^0.2.1"
|
||||||
|
|
||||||
escape-string-regexp@^1.0.3:
|
escape-string-regexp@^1.0.3:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
@ -1647,6 +1666,11 @@ is-accessor-descriptor@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
kind-of "^6.0.0"
|
kind-of "^6.0.0"
|
||||||
|
|
||||||
|
is-arrayish@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||||
|
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
|
||||||
|
|
||||||
is-binary-path@^1.0.0:
|
is-binary-path@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
|
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
|
||||||
@ -1758,6 +1782,11 @@ is-regexp@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
|
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
|
||||||
integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
|
integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
|
||||||
|
|
||||||
|
is-utf8@^0.2.0:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||||
|
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
|
||||||
|
|
||||||
is-windows@^1.0.1, is-windows@^1.0.2:
|
is-windows@^1.0.1, is-windows@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||||
@ -2405,6 +2434,13 @@ parse-asn1@^5.0.0:
|
|||||||
pbkdf2 "^3.0.3"
|
pbkdf2 "^3.0.3"
|
||||||
safe-buffer "^5.1.1"
|
safe-buffer "^5.1.1"
|
||||||
|
|
||||||
|
parse-json@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||||
|
integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
|
||||||
|
dependencies:
|
||||||
|
error-ex "^1.2.0"
|
||||||
|
|
||||||
parse-passwd@^1.0.0:
|
parse-passwd@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
||||||
@ -3060,6 +3096,13 @@ strip-ansi@^4.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex "^3.0.0"
|
ansi-regex "^3.0.0"
|
||||||
|
|
||||||
|
strip-bom@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
||||||
|
integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
|
||||||
|
dependencies:
|
||||||
|
is-utf8 "^0.2.0"
|
||||||
|
|
||||||
strip-css-comments@^3.0.0:
|
strip-css-comments@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/strip-css-comments/-/strip-css-comments-3.0.0.tgz#7a5625eff8a2b226cf8947a11254da96e13dae89"
|
resolved "https://registry.yarnpkg.com/strip-css-comments/-/strip-css-comments-3.0.0.tgz#7a5625eff8a2b226cf8947a11254da96e13dae89"
|
||||||
@ -3067,7 +3110,7 @@ strip-css-comments@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
strip-json-comments@~2.0.1:
|
strip-json-comments@^2.0.0, strip-json-comments@~2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||||
@ -3205,6 +3248,28 @@ transformify@~0.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
readable-stream "~1.1.9"
|
readable-stream "~1.1.9"
|
||||||
|
|
||||||
|
tsconfig@^5.0.3:
|
||||||
|
version "5.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-5.0.3.tgz#5f4278e701800967a8fc383fd19648878f2a6e3a"
|
||||||
|
integrity sha1-X0J45wGACWeo/Dg/0ZZIh48qbjo=
|
||||||
|
dependencies:
|
||||||
|
any-promise "^1.3.0"
|
||||||
|
parse-json "^2.2.0"
|
||||||
|
strip-bom "^2.0.0"
|
||||||
|
strip-json-comments "^2.0.0"
|
||||||
|
|
||||||
|
tsify@^4.0.1:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tsify/-/tsify-4.0.1.tgz#b19b0ddf7f184368dbf65839293d2c5a6d48453d"
|
||||||
|
integrity sha512-ClznEI+pmwY5wmD0J7HCSVERwkD+l71ch3Dqyod2JuQLEsFaiNDI+vPjaGadsuVFVvmzgoI7HghrBtWsSmCDHQ==
|
||||||
|
dependencies:
|
||||||
|
convert-source-map "^1.1.0"
|
||||||
|
fs.realpath "^1.0.0"
|
||||||
|
object-assign "^4.1.0"
|
||||||
|
semver "^5.6.0"
|
||||||
|
through2 "^2.0.0"
|
||||||
|
tsconfig "^5.0.3"
|
||||||
|
|
||||||
tslib@^1.9.0:
|
tslib@^1.9.0:
|
||||||
version "1.10.0"
|
version "1.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||||
|
311
chatto/src/main/resources/templates/ts-test.html
Normal file
311
chatto/src/main/resources/templates/ts-test.html
Normal file
@ -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> -->
|
Loading…
Reference in New Issue
Block a user