@muraai/mnl-chat 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2020/lib/chat.module.mjs +87 -0
- package/esm2020/lib/components/ng-chat/ng-chat.component.mjs +588 -0
- package/esm2020/lib/components/ng-chat-friends-list/ng-chat-friends-list.component.mjs +128 -0
- package/esm2020/lib/components/ng-chat-options/ng-chat-options.component.mjs +29 -0
- package/esm2020/lib/components/ng-chat-window/ng-chat-window.component.mjs +247 -0
- package/esm2020/lib/core/chat-adapter.mjs +18 -0
- package/esm2020/lib/core/chat-controller.mjs +2 -0
- package/esm2020/lib/core/chat-group-adapter.mjs +2 -0
- package/esm2020/lib/core/chat-option.mjs +2 -0
- package/esm2020/lib/core/chat-participant-status-descriptor.mjs +6 -0
- package/esm2020/lib/core/chat-participant-status.enum.mjs +8 -0
- package/esm2020/lib/core/chat-participant-type.enum.mjs +6 -0
- package/esm2020/lib/core/chat-participant.mjs +2 -0
- package/esm2020/lib/core/default-file-upload-adapter.mjs +43 -0
- package/esm2020/lib/core/file-upload-adapter.mjs +2 -0
- package/esm2020/lib/core/group.mjs +14 -0
- package/esm2020/lib/core/guid.mjs +11 -0
- package/esm2020/lib/core/localization.mjs +2 -0
- package/esm2020/lib/core/message-counter.mjs +25 -0
- package/esm2020/lib/core/message-type.enum.mjs +7 -0
- package/esm2020/lib/core/message.mjs +7 -0
- package/esm2020/lib/core/paged-history-chat-adapter.mjs +9 -0
- package/esm2020/lib/core/participant-metadata.mjs +6 -0
- package/esm2020/lib/core/participant-response.mjs +3 -0
- package/esm2020/lib/core/scroll-direction.enum.mjs +6 -0
- package/esm2020/lib/core/theme.enum.mjs +7 -0
- package/esm2020/lib/core/user.mjs +7 -0
- package/esm2020/lib/core/window.mjs +20 -0
- package/esm2020/lib/firstLetter.pipe.mjs +20 -0
- package/esm2020/lib/material.module.mjs +50 -0
- package/esm2020/lib/pipes/emojify.pipe.mjs +41 -0
- package/esm2020/lib/pipes/group-message-display-name.pipe.mjs +24 -0
- package/esm2020/lib/pipes/linkfy.pipe.mjs +34 -0
- package/esm2020/lib/pipes/sanitize.pipe.mjs +21 -0
- package/esm2020/lib/services/chat.service.mjs +14 -0
- package/esm2020/muraai-mnl-chat.mjs +5 -0
- package/esm2020/public-api.mjs +25 -0
- package/fesm2015/muraai-mnl-chat.mjs +1426 -0
- package/fesm2015/muraai-mnl-chat.mjs.map +1 -0
- package/fesm2020/muraai-mnl-chat.mjs +1424 -0
- package/fesm2020/muraai-mnl-chat.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/chat.module.d.ts +24 -0
- package/lib/components/ng-chat/ng-chat.component.d.ts +130 -0
- package/lib/components/ng-chat-friends-list/ng-chat-friends-list.component.d.ts +45 -0
- package/lib/components/ng-chat-options/ng-chat-options.component.d.ts +12 -0
- package/lib/components/ng-chat-window/ng-chat-window.component.d.ts +65 -0
- package/lib/core/chat-adapter.d.ts +15 -0
- package/lib/core/chat-controller.d.ts +6 -0
- package/lib/core/chat-group-adapter.d.ts +4 -0
- package/lib/core/chat-option.d.ts +9 -0
- package/lib/core/chat-participant-status-descriptor.d.ts +3 -0
- package/lib/core/chat-participant-status.enum.d.ts +6 -0
- package/lib/core/chat-participant-type.enum.d.ts +4 -0
- package/lib/core/chat-participant.d.ts +9 -0
- package/lib/core/default-file-upload-adapter.d.ts +14 -0
- package/lib/core/file-upload-adapter.d.ts +5 -0
- package/lib/core/group.d.ts +13 -0
- package/lib/core/guid.d.ts +3 -0
- package/lib/core/localization.d.ts +15 -0
- package/lib/core/message-counter.d.ts +10 -0
- package/lib/core/message-type.enum.d.ts +5 -0
- package/lib/core/message.d.ts +10 -0
- package/lib/core/paged-history-chat-adapter.d.ts +10 -0
- package/lib/core/participant-metadata.d.ts +3 -0
- package/lib/core/participant-response.d.ts +6 -0
- package/lib/core/scroll-direction.enum.d.ts +4 -0
- package/lib/core/theme.enum.d.ts +5 -0
- package/lib/core/user.d.ts +10 -0
- package/lib/core/window.d.ts +13 -0
- package/lib/firstLetter.pipe.d.ts +7 -0
- package/lib/material.module.d.ts +14 -0
- package/lib/pipes/emojify.pipe.d.ts +7 -0
- package/lib/pipes/group-message-display-name.pipe.d.ts +9 -0
- package/lib/pipes/linkfy.pipe.d.ts +7 -0
- package/lib/pipes/sanitize.pipe.d.ts +10 -0
- package/lib/services/chat.service.d.ts +6 -0
- package/package.json +31 -0
- package/public-api.d.ts +21 -0
- package/src/assets/icons.css +140 -0
- package/src/assets/loading-spinner.css +59 -0
- package/src/assets/ng-chat.component.default.css +106 -0
- package/src/assets/notification.png +0 -0
- package/src/assets/notification.wav +0 -0
- package/src/assets/themes/ng-chat.theme.dark.scss +71 -0
- package/src/assets/themes/ng-chat.theme.default.scss +63 -0
- package/src/assets/user.png +0 -0
|
@@ -0,0 +1,1424 @@
|
|
|
1
|
+
import * as i1$2 from '@angular/common/http';
|
|
2
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
3
|
+
import * as i2 from '@angular/common';
|
|
4
|
+
import { CommonModule } from '@angular/common';
|
|
5
|
+
import * as i0 from '@angular/core';
|
|
6
|
+
import { NgModule, Injectable, Pipe, EventEmitter, Component, ViewEncapsulation, Input, Output, ViewChild, ViewChildren, HostListener, APP_INITIALIZER } from '@angular/core';
|
|
7
|
+
import { AppConfigService } from '@muraai/mnl-commons';
|
|
8
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
9
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
+
import { MatInputModule } from '@angular/material/input';
|
|
11
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
12
|
+
import * as i1$1 from '@angular/forms';
|
|
13
|
+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
14
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
15
|
+
import { map } from 'rxjs/operators';
|
|
16
|
+
import * as i1 from '@angular/platform-browser';
|
|
17
|
+
|
|
18
|
+
function modules() {
|
|
19
|
+
return [
|
|
20
|
+
MatButtonModule,
|
|
21
|
+
MatFormFieldModule,
|
|
22
|
+
MatIconModule,
|
|
23
|
+
MatInputModule,
|
|
24
|
+
FormsModule,
|
|
25
|
+
ReactiveFormsModule,
|
|
26
|
+
MatMenuModule,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
class ChatMaterialModule {
|
|
30
|
+
}
|
|
31
|
+
ChatMaterialModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatMaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
32
|
+
ChatMaterialModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: ChatMaterialModule, imports: [MatButtonModule,
|
|
33
|
+
MatFormFieldModule,
|
|
34
|
+
MatIconModule,
|
|
35
|
+
MatInputModule,
|
|
36
|
+
FormsModule,
|
|
37
|
+
ReactiveFormsModule,
|
|
38
|
+
MatMenuModule], exports: [MatButtonModule,
|
|
39
|
+
MatFormFieldModule,
|
|
40
|
+
MatIconModule,
|
|
41
|
+
MatInputModule,
|
|
42
|
+
FormsModule,
|
|
43
|
+
ReactiveFormsModule,
|
|
44
|
+
MatMenuModule] });
|
|
45
|
+
ChatMaterialModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatMaterialModule, imports: [modules(), MatButtonModule,
|
|
46
|
+
MatFormFieldModule,
|
|
47
|
+
MatIconModule,
|
|
48
|
+
MatInputModule,
|
|
49
|
+
FormsModule,
|
|
50
|
+
ReactiveFormsModule,
|
|
51
|
+
MatMenuModule] });
|
|
52
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatMaterialModule, decorators: [{
|
|
53
|
+
type: NgModule,
|
|
54
|
+
args: [{
|
|
55
|
+
imports: modules(),
|
|
56
|
+
exports: modules()
|
|
57
|
+
}]
|
|
58
|
+
}] });
|
|
59
|
+
|
|
60
|
+
class ChatService {
|
|
61
|
+
constructor() { }
|
|
62
|
+
}
|
|
63
|
+
ChatService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
64
|
+
ChatService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatService, providedIn: 'root' });
|
|
65
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatService, decorators: [{
|
|
66
|
+
type: Injectable,
|
|
67
|
+
args: [{
|
|
68
|
+
providedIn: 'root'
|
|
69
|
+
}]
|
|
70
|
+
}], ctorParameters: function () { return []; } });
|
|
71
|
+
|
|
72
|
+
var MessageType;
|
|
73
|
+
(function (MessageType) {
|
|
74
|
+
MessageType[MessageType["Text"] = 1] = "Text";
|
|
75
|
+
MessageType[MessageType["File"] = 2] = "File";
|
|
76
|
+
MessageType[MessageType["Image"] = 3] = "Image";
|
|
77
|
+
})(MessageType || (MessageType = {}));
|
|
78
|
+
|
|
79
|
+
class Window {
|
|
80
|
+
constructor(participant, isLoadingHistory, isCollapsed) {
|
|
81
|
+
this.messages = [];
|
|
82
|
+
this.newMessage = "";
|
|
83
|
+
// UI Behavior properties
|
|
84
|
+
this.isCollapsed = false;
|
|
85
|
+
this.isLoadingHistory = false;
|
|
86
|
+
this.hasFocus = false;
|
|
87
|
+
this.hasMoreMessages = true;
|
|
88
|
+
this.historyPage = 0;
|
|
89
|
+
this.participant = participant;
|
|
90
|
+
this.messages = [];
|
|
91
|
+
this.isLoadingHistory = isLoadingHistory;
|
|
92
|
+
this.hasFocus = false; // This will be triggered when the 'newMessage' input gets the current focus
|
|
93
|
+
this.isCollapsed = isCollapsed;
|
|
94
|
+
this.hasMoreMessages = false;
|
|
95
|
+
this.historyPage = 0;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var ChatParticipantStatus;
|
|
100
|
+
(function (ChatParticipantStatus) {
|
|
101
|
+
ChatParticipantStatus[ChatParticipantStatus["Online"] = 0] = "Online";
|
|
102
|
+
ChatParticipantStatus[ChatParticipantStatus["Busy"] = 1] = "Busy";
|
|
103
|
+
ChatParticipantStatus[ChatParticipantStatus["Away"] = 2] = "Away";
|
|
104
|
+
ChatParticipantStatus[ChatParticipantStatus["Offline"] = 3] = "Offline";
|
|
105
|
+
})(ChatParticipantStatus || (ChatParticipantStatus = {}));
|
|
106
|
+
|
|
107
|
+
var ScrollDirection;
|
|
108
|
+
(function (ScrollDirection) {
|
|
109
|
+
ScrollDirection[ScrollDirection["Top"] = 0] = "Top";
|
|
110
|
+
ScrollDirection[ScrollDirection["Bottom"] = 1] = "Bottom";
|
|
111
|
+
})(ScrollDirection || (ScrollDirection = {}));
|
|
112
|
+
|
|
113
|
+
class ChatAdapter {
|
|
114
|
+
constructor() {
|
|
115
|
+
// ### Abstract adapter methods ###
|
|
116
|
+
// Event handlers
|
|
117
|
+
/** @internal */
|
|
118
|
+
this.friendsListChangedHandler = (participantsResponse) => { };
|
|
119
|
+
/** @internal */
|
|
120
|
+
this.messageReceivedHandler = (participant, message) => { };
|
|
121
|
+
}
|
|
122
|
+
// ### Adapter/Chat income/ingress events ###
|
|
123
|
+
onFriendsListChanged(participantsResponse) {
|
|
124
|
+
this.friendsListChangedHandler(participantsResponse);
|
|
125
|
+
}
|
|
126
|
+
onMessageReceived(participant, message) {
|
|
127
|
+
this.messageReceivedHandler(participant, message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// import { User } from "./user";
|
|
132
|
+
/**
|
|
133
|
+
* @description Chat Adapter decorator class that adds pagination to load the history of messagesr.
|
|
134
|
+
* You will need an existing @see ChatAdapter implementation
|
|
135
|
+
*/
|
|
136
|
+
class PagedHistoryChatAdapter extends ChatAdapter {
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/*import { IFileUploadAdapter } from './file-upload-adapter';
|
|
140
|
+
import { HttpClient, HttpRequest, HttpEventType, HttpResponse, HttpHeaders } from '@angular/common/http';
|
|
141
|
+
import { Observable, Subject } from 'rxjs';
|
|
142
|
+
import { User } from './user';
|
|
143
|
+
import { Message } from './message';*/
|
|
144
|
+
class DefaultFileUploadAdapter {
|
|
145
|
+
/**
|
|
146
|
+
* @summary Basic file upload adapter implementation for HTTP request form file consumption
|
|
147
|
+
* @param _serverEndpointUrl The API endpoint full qualified address that will receive a form file to process and return the metadata.
|
|
148
|
+
*/
|
|
149
|
+
constructor(_serverEndpointUrl, _http) {
|
|
150
|
+
this._serverEndpointUrl = _serverEndpointUrl;
|
|
151
|
+
this._http = _http;
|
|
152
|
+
}
|
|
153
|
+
uploadFile(file, participantId) {
|
|
154
|
+
const formData = new FormData();
|
|
155
|
+
//formData.append('ng-chat-sender-userid', currentUserId);
|
|
156
|
+
formData.append('ng-chat-participant-id', participantId);
|
|
157
|
+
formData.append('file', file, file.name);
|
|
158
|
+
return this._http.post(this._serverEndpointUrl, formData);
|
|
159
|
+
// TODO: Leaving this if we want to track upload progress in detail in the future. Might need a different Subject generic type wrapper
|
|
160
|
+
// const fileRequest = new HttpRequest('POST', this._serverEndpointUrl, formData, {
|
|
161
|
+
// reportProgress: true
|
|
162
|
+
// });
|
|
163
|
+
// const uploadProgress = new Subject<number>();
|
|
164
|
+
// const uploadStatus = uploadProgress.asObservable();
|
|
165
|
+
//const responsePromise = new Subject<Message>();
|
|
166
|
+
// this._http
|
|
167
|
+
// .request(fileRequest)
|
|
168
|
+
// .subscribe(event => {
|
|
169
|
+
// // if (event.type == HttpEventType.UploadProgress)
|
|
170
|
+
// // {
|
|
171
|
+
// // const percentDone = Math.round(100 * event.loaded / event.total);
|
|
172
|
+
// // uploadProgress.next(percentDone);
|
|
173
|
+
// // }
|
|
174
|
+
// // else if (event instanceof HttpResponse)
|
|
175
|
+
// // {
|
|
176
|
+
// // uploadProgress.complete();
|
|
177
|
+
// // }
|
|
178
|
+
// });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var Theme;
|
|
183
|
+
(function (Theme) {
|
|
184
|
+
Theme["Custom"] = "custom-theme";
|
|
185
|
+
Theme["Light"] = "light-theme";
|
|
186
|
+
Theme["Dark"] = "dark-theme";
|
|
187
|
+
})(Theme || (Theme = {}));
|
|
188
|
+
|
|
189
|
+
// Poached from: https://github.com/Steve-Fenton/TypeScriptUtilities
|
|
190
|
+
// @dynamic
|
|
191
|
+
class Guid {
|
|
192
|
+
static newGuid() {
|
|
193
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
194
|
+
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
195
|
+
return v.toString(16);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
var ChatParticipantType;
|
|
201
|
+
(function (ChatParticipantType) {
|
|
202
|
+
ChatParticipantType[ChatParticipantType["User"] = 0] = "User";
|
|
203
|
+
ChatParticipantType[ChatParticipantType["Group"] = 1] = "Group";
|
|
204
|
+
})(ChatParticipantType || (ChatParticipantType = {}));
|
|
205
|
+
|
|
206
|
+
class Group {
|
|
207
|
+
constructor(participants) {
|
|
208
|
+
this.id = Guid.newGuid();
|
|
209
|
+
this.participantType = ChatParticipantType.Group;
|
|
210
|
+
this.chattingTo = participants;
|
|
211
|
+
this.status = ChatParticipantStatus.Online;
|
|
212
|
+
// TODO: Add some customization for this in future releases
|
|
213
|
+
this.displayName = participants.map((p) => p.displayName).sort((first, second) => second > first ? -1 : 1).join(", ");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
class MessageCounter {
|
|
218
|
+
static formatUnreadMessagesTotal(totalUnreadMessages) {
|
|
219
|
+
if (totalUnreadMessages > 0) {
|
|
220
|
+
if (totalUnreadMessages > 99)
|
|
221
|
+
return "99+";
|
|
222
|
+
else
|
|
223
|
+
return String(totalUnreadMessages);
|
|
224
|
+
}
|
|
225
|
+
// Empty fallback.
|
|
226
|
+
return "";
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Returns a formatted string containing the total unread messages of a chat window.
|
|
230
|
+
* @param window The window instance to count the unread total messages.
|
|
231
|
+
* @param currentUserId The current chat instance user id. In this context it would be the sender.
|
|
232
|
+
*/
|
|
233
|
+
static unreadMessagesTotal(window, currentUserId) {
|
|
234
|
+
let totalUnreadMessages = 0;
|
|
235
|
+
if (window) {
|
|
236
|
+
totalUnreadMessages = window.messages.filter(x => x.fromId != currentUserId && !x.dateSeen).length;
|
|
237
|
+
}
|
|
238
|
+
return MessageCounter.formatUnreadMessagesTotal(totalUnreadMessages);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function chatParticipantStatusDescriptor(status, localization) {
|
|
243
|
+
const currentStatus = ChatParticipantStatus[status].toString().toLowerCase();
|
|
244
|
+
return localization.statusDescription[currentStatus];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/*
|
|
248
|
+
* Sanitizes an URL resource
|
|
249
|
+
*/
|
|
250
|
+
class SanitizePipe {
|
|
251
|
+
constructor(sanitizer) {
|
|
252
|
+
this.sanitizer = sanitizer;
|
|
253
|
+
}
|
|
254
|
+
transform(url) {
|
|
255
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
SanitizePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SanitizePipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
259
|
+
SanitizePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: SanitizePipe, name: "sanitize" });
|
|
260
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SanitizePipe, decorators: [{
|
|
261
|
+
type: Pipe,
|
|
262
|
+
args: [{ name: 'sanitize' }]
|
|
263
|
+
}], ctorParameters: function () { return [{ type: i1.DomSanitizer }]; } });
|
|
264
|
+
|
|
265
|
+
class FirstLetterPipe {
|
|
266
|
+
transform(value) {
|
|
267
|
+
// const parts = value.split(" ");
|
|
268
|
+
// const firstLetter = parts[0][0];
|
|
269
|
+
// const secondLetters = parts.length > 1 ? parts[1].slice(0, 2) : '';
|
|
270
|
+
let parts = value.split(" ");
|
|
271
|
+
let firstLetter = parts[0].slice(0, 1);
|
|
272
|
+
let secondLetters = parts.length > 1 ? parts[1].slice(0, 1) : '';
|
|
273
|
+
return (firstLetter.toUpperCase() + secondLetters.toUpperCase());
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
FirstLetterPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FirstLetterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
277
|
+
FirstLetterPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: FirstLetterPipe, name: "firstLetterPipe" });
|
|
278
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FirstLetterPipe, decorators: [{
|
|
279
|
+
type: Pipe,
|
|
280
|
+
args: [{ name: 'firstLetterPipe' }]
|
|
281
|
+
}] });
|
|
282
|
+
|
|
283
|
+
/* eslint-disable */
|
|
284
|
+
class NgChatFriendsListComponent {
|
|
285
|
+
constructor() {
|
|
286
|
+
this.participantsInteractedWith = [];
|
|
287
|
+
this.onParticipantClicked = new EventEmitter();
|
|
288
|
+
this.onOptionPromptCanceled = new EventEmitter();
|
|
289
|
+
this.onOptionPromptConfirmed = new EventEmitter();
|
|
290
|
+
this.hideFriendsList = false;
|
|
291
|
+
this.onCloseWindowClick = new EventEmitter();
|
|
292
|
+
this.selectedUsersFromFriendsList = [];
|
|
293
|
+
this.searchInput = '';
|
|
294
|
+
// Exposes enums and functions for the ng-template
|
|
295
|
+
this.ChatParticipantStatus = ChatParticipantStatus;
|
|
296
|
+
this.chatParticipantStatusDescriptor = chatParticipantStatusDescriptor;
|
|
297
|
+
this.cleanUpUserSelection = () => this.selectedUsersFromFriendsList = [];
|
|
298
|
+
}
|
|
299
|
+
ngOnChanges(changes) {
|
|
300
|
+
if (this.currentActiveOption) {
|
|
301
|
+
const currentOptionTriggeredBy = this.currentActiveOption && this.currentActiveOption.chattingTo.participant.id;
|
|
302
|
+
const isActivatedUserInSelectedList = (this.selectedUsersFromFriendsList.filter(item => item.id == currentOptionTriggeredBy)).length > 0;
|
|
303
|
+
if (!isActivatedUserInSelectedList) {
|
|
304
|
+
this.selectedUsersFromFriendsList = this.selectedUsersFromFriendsList.concat(this.currentActiveOption.chattingTo.participant);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// let input = user.displayName;
|
|
308
|
+
// let parts = input.split(" ");
|
|
309
|
+
// let firstLetter = parts[0];
|
|
310
|
+
// let secondLetters = parts[1].slice(0, 2);
|
|
311
|
+
}
|
|
312
|
+
get filteredParticipants() {
|
|
313
|
+
if (this.searchInput.length > 0) {
|
|
314
|
+
// Searches in the friend list by the inputted search string
|
|
315
|
+
return this.participants.filter(x => x.displayName.toUpperCase().includes(this.searchInput.toUpperCase()));
|
|
316
|
+
}
|
|
317
|
+
console.log("this.participants", this.participants);
|
|
318
|
+
return this.participants;
|
|
319
|
+
}
|
|
320
|
+
isUserSelectedFromFriendsList(user) {
|
|
321
|
+
return (this.selectedUsersFromFriendsList.filter(item => item.id == user.id)).length > 0;
|
|
322
|
+
}
|
|
323
|
+
unreadMessagesTotalByParticipant(participant) {
|
|
324
|
+
let openedWindow = this.windows.find(x => x.participant.id == participant.id);
|
|
325
|
+
if (openedWindow) {
|
|
326
|
+
return MessageCounter.unreadMessagesTotal(openedWindow, this.userId);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
let totalUnreadMessages = this.participantsResponse
|
|
330
|
+
.filter(x => x.participant.id == participant.id && !this.participantsInteractedWith.find(u => u.id == participant.id) && x.metadata && x.metadata.totalUnreadMessages > 0)
|
|
331
|
+
.map((participantResponse) => {
|
|
332
|
+
return participantResponse.metadata.totalUnreadMessages;
|
|
333
|
+
})[0];
|
|
334
|
+
return MessageCounter.formatUnreadMessagesTotal(totalUnreadMessages);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Toggle friends list visibility
|
|
338
|
+
onChatTitleClicked() {
|
|
339
|
+
this.isCollapsed = !this.isCollapsed;
|
|
340
|
+
}
|
|
341
|
+
onFriendsListCheckboxChange(selectedUser, isChecked) {
|
|
342
|
+
if (isChecked) {
|
|
343
|
+
this.selectedUsersFromFriendsList.push(selectedUser);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
this.selectedUsersFromFriendsList.splice(this.selectedUsersFromFriendsList.indexOf(selectedUser), 1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
onUserClick(clickedUser) {
|
|
350
|
+
this.onParticipantClicked.emit(clickedUser);
|
|
351
|
+
}
|
|
352
|
+
onFriendsListActionCancelClicked() {
|
|
353
|
+
this.onOptionPromptCanceled.emit();
|
|
354
|
+
this.cleanUpUserSelection();
|
|
355
|
+
}
|
|
356
|
+
onFriendsListActionConfirmClicked() {
|
|
357
|
+
this.onOptionPromptConfirmed.emit(this.selectedUsersFromFriendsList);
|
|
358
|
+
this.cleanUpUserSelection();
|
|
359
|
+
}
|
|
360
|
+
onCloseWindow() {
|
|
361
|
+
this.onCloseWindowClick.emit(true);
|
|
362
|
+
console.log('hoi latest friendlist', this.shouldDisplay);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
NgChatFriendsListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatFriendsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
366
|
+
NgChatFriendsListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgChatFriendsListComponent, selector: "ng-chat-friends-list", inputs: { participants: "participants", participantsResponse: "participantsResponse", participantsInteractedWith: "participantsInteractedWith", windows: "windows", userId: "userId", localization: "localization", shouldDisplay: "shouldDisplay", isCollapsed: "isCollapsed", searchEnabled: "searchEnabled", currentActiveOption: "currentActiveOption", hideFriendsList: "hideFriendsList" }, outputs: { onParticipantClicked: "onParticipantClicked", onOptionPromptCanceled: "onOptionPromptCanceled", onOptionPromptConfirmed: "onOptionPromptConfirmed", onCloseWindowClick: "onCloseWindowClick" }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"shouldDisplay\" id=\"ng-chat-people\" [ngClass]=\"{'primary-outline-color': true, 'primary-background': true, 'ng-chat-people-collapsed': isCollapsed}\">\n\t<a href=\"javascript:void(0);\" class=\"ng-chat-title secondary-background shadowed\" (click)=\"onChatTitleClicked()\">\n\t\t<span>\n\t\t\t{{localization.title}}\n\t\t</span>\n\t<a href=\"javascript:void(0);\" class=\" ng-chat-close \" (click)=\"onCloseWindow()\" >✕</a>\n\t</a>\n\t<div *ngIf=\"currentActiveOption\" class=\"ng-chat-people-actions\" (click)=\"onFriendsListActionCancelClicked()\">\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-people-action\">\n\t\t\t<i class=\"remove-icon\"></i>\n\t\t</a>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-people-action\" (click)=\"onFriendsListActionConfirmClicked()\">\n\t\t\t<i class=\"check-icon\"></i>\n\t\t</a>\n\t</div>\n\t<input *ngIf=\"searchEnabled\" id=\"ng-chat-search_friend\" class=\"friends-search-bar\" type=\"search\" [placeholder]=\"localization.searchPlaceholder\" [(ngModel)]=\"searchInput\" />\n\t<ul id=\"ng-chat-users\" *ngIf=\"!isCollapsed\" [ngClass]=\"{'offset-search': searchEnabled}\">\n\t\t<li *ngFor=\"let user of filteredParticipants\">\n\t\t\t<input \n\t\t\t\t*ngIf=\"currentActiveOption && currentActiveOption.validateContext(user)\" \n\t\t\t\ttype=\"checkbox\" \n\t\t\t\tclass=\"ng-chat-users-checkbox\" \n\t\t\t\t(change)=\"onFriendsListCheckboxChange(user, $event.target.checked)\" \n\t\t\t\t[checked]=\"isUserSelectedFromFriendsList(user)\"/>\n\t\t\t<div [ngClass]=\"{'ng-chat-friends-list-selectable-offset': currentActiveOption, 'ng-chat-friends-list-container': true}\" (click)=\"onUserClick(user)\">\n\t\t\t\t<!-- <div *ngIf=\"!user.avatar\" class=\"icon-wrapper\">\n\t\t\t\t\t<i class=\"user-icon\"></i>\n\t\t\t\t</div> -->\n\t\t\t\t<div class=\"user\" *ngIf=\"!user.avatar\">\n\t\t\t\t\t{{user.displayName|firstLetterPipe}}\n\n\t\t\t\t</div>\n\n\t\t\t\t<img *ngIf=\"user.avatar\" alt=\"\" class=\"avatar\" height=\"30\" width=\"30\" [src]=\"user.avatar | sanitize\"/>\n\t\t\t\t<div class=\"\"></div>\n\t\t\t\t<strong title=\"{{user.displayName}}\">{{user.displayName}}</strong>\n\t\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': user.status === ChatParticipantStatus.Online, 'busy': user.status === ChatParticipantStatus.Busy, 'away': user.status === ChatParticipantStatus.Away, 'offline': user.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(user.status, localization)}}\"></span>\n\t\t\t\t<span *ngIf=\"unreadMessagesTotalByParticipant(user).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotalByParticipant(user)}}</span>\n\t\t\t</div>\n\t\t</li>\n\t</ul>\n</div>", styles: ["#ng-chat-people{position:relative;width:240px;height:360px;border-width:1px;border-style:solid;margin-right:20px;box-shadow:0 4px 8px #00000040;border-bottom:0;border-radius:10px!important;box-sizing:border-box!important;overflow:hidden!important;margin-bottom:10px!important;border:1px solid grey!important}#ng-chat-people.ng-chat-people-collapsed{height:30px}#ng-chat-search_friend{display:block;padding:7px 10px;margin:10px auto 0;width:calc(100% - 20px);font-size:.9em;border-radius:20px!important;border:.5px solid grey!important}#ng-chat-users{padding:0 10px;list-style:none;margin:0;overflow:auto;position:absolute;top:42px;bottom:0;width:100%;box-sizing:border-box}#ng-chat-users.offset-search{top:84px}#ng-chat-users .ng-chat-users-checkbox{float:left;margin-right:5px;margin-top:8px}#ng-chat-users li{clear:both;margin-bottom:10px;overflow:hidden;cursor:pointer;max-height:30px}#ng-chat-users li>.ng-chat-friends-list-selectable-offset{margin-left:22px}#ng-chat-users li .ng-chat-friends-list-container{display:inline-block;width:100%}#ng-chat-users li>.ng-chat-friends-list-selectable-offset.ng-chat-friends-list-container{display:block;width:auto}#ng-chat-users li .ng-chat-friends-list-container>img.avatar,#ng-chat-users li .ng-chat-friends-list-container>.user{float:left;display:flex;justify-content:center;margin-right:5px}#ng-chat-users li .ng-chat-friends-list-container>.user{overflow:hidden;width:30px;height:30px}#ng-chat-users li .ng-chat-friends-list-container>.user>i{color:#fff;transform:scale(.7)}#ng-chat-users li .ng-chat-friends-list-container>strong{float:left;line-height:30px;font-size:.8em;max-width:57%;max-height:30px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}#ng-chat-users li .ng-chat-friends-list-container>.ng-chat-participant-status{float:right}.ng-chat-people-actions{position:absolute;top:4px;right:5px;margin:0;padding:0;z-index:2}.ng-chat-people-actions>a.ng-chat-people-action{display:inline-block;width:21px;height:21px;margin-right:8px;text-decoration:none;border:none;border-radius:25px;padding:1px}@media only screen and (max-width: 581px){#ng-chat-people{width:300px;height:360px;margin-right:0}}.user{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background-color:#00b04c;color:#fff;font-size:12px;font-family:inherit}\n"], dependencies: [{ kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: SanitizePipe, name: "sanitize" }, { kind: "pipe", type: FirstLetterPipe, name: "firstLetterPipe" }], encapsulation: i0.ViewEncapsulation.None });
|
|
367
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatFriendsListComponent, decorators: [{
|
|
368
|
+
type: Component,
|
|
369
|
+
args: [{ selector: 'ng-chat-friends-list', encapsulation: ViewEncapsulation.None, template: "<div *ngIf=\"shouldDisplay\" id=\"ng-chat-people\" [ngClass]=\"{'primary-outline-color': true, 'primary-background': true, 'ng-chat-people-collapsed': isCollapsed}\">\n\t<a href=\"javascript:void(0);\" class=\"ng-chat-title secondary-background shadowed\" (click)=\"onChatTitleClicked()\">\n\t\t<span>\n\t\t\t{{localization.title}}\n\t\t</span>\n\t<a href=\"javascript:void(0);\" class=\" ng-chat-close \" (click)=\"onCloseWindow()\" >✕</a>\n\t</a>\n\t<div *ngIf=\"currentActiveOption\" class=\"ng-chat-people-actions\" (click)=\"onFriendsListActionCancelClicked()\">\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-people-action\">\n\t\t\t<i class=\"remove-icon\"></i>\n\t\t</a>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-people-action\" (click)=\"onFriendsListActionConfirmClicked()\">\n\t\t\t<i class=\"check-icon\"></i>\n\t\t</a>\n\t</div>\n\t<input *ngIf=\"searchEnabled\" id=\"ng-chat-search_friend\" class=\"friends-search-bar\" type=\"search\" [placeholder]=\"localization.searchPlaceholder\" [(ngModel)]=\"searchInput\" />\n\t<ul id=\"ng-chat-users\" *ngIf=\"!isCollapsed\" [ngClass]=\"{'offset-search': searchEnabled}\">\n\t\t<li *ngFor=\"let user of filteredParticipants\">\n\t\t\t<input \n\t\t\t\t*ngIf=\"currentActiveOption && currentActiveOption.validateContext(user)\" \n\t\t\t\ttype=\"checkbox\" \n\t\t\t\tclass=\"ng-chat-users-checkbox\" \n\t\t\t\t(change)=\"onFriendsListCheckboxChange(user, $event.target.checked)\" \n\t\t\t\t[checked]=\"isUserSelectedFromFriendsList(user)\"/>\n\t\t\t<div [ngClass]=\"{'ng-chat-friends-list-selectable-offset': currentActiveOption, 'ng-chat-friends-list-container': true}\" (click)=\"onUserClick(user)\">\n\t\t\t\t<!-- <div *ngIf=\"!user.avatar\" class=\"icon-wrapper\">\n\t\t\t\t\t<i class=\"user-icon\"></i>\n\t\t\t\t</div> -->\n\t\t\t\t<div class=\"user\" *ngIf=\"!user.avatar\">\n\t\t\t\t\t{{user.displayName|firstLetterPipe}}\n\n\t\t\t\t</div>\n\n\t\t\t\t<img *ngIf=\"user.avatar\" alt=\"\" class=\"avatar\" height=\"30\" width=\"30\" [src]=\"user.avatar | sanitize\"/>\n\t\t\t\t<div class=\"\"></div>\n\t\t\t\t<strong title=\"{{user.displayName}}\">{{user.displayName}}</strong>\n\t\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': user.status === ChatParticipantStatus.Online, 'busy': user.status === ChatParticipantStatus.Busy, 'away': user.status === ChatParticipantStatus.Away, 'offline': user.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(user.status, localization)}}\"></span>\n\t\t\t\t<span *ngIf=\"unreadMessagesTotalByParticipant(user).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotalByParticipant(user)}}</span>\n\t\t\t</div>\n\t\t</li>\n\t</ul>\n</div>", styles: ["#ng-chat-people{position:relative;width:240px;height:360px;border-width:1px;border-style:solid;margin-right:20px;box-shadow:0 4px 8px #00000040;border-bottom:0;border-radius:10px!important;box-sizing:border-box!important;overflow:hidden!important;margin-bottom:10px!important;border:1px solid grey!important}#ng-chat-people.ng-chat-people-collapsed{height:30px}#ng-chat-search_friend{display:block;padding:7px 10px;margin:10px auto 0;width:calc(100% - 20px);font-size:.9em;border-radius:20px!important;border:.5px solid grey!important}#ng-chat-users{padding:0 10px;list-style:none;margin:0;overflow:auto;position:absolute;top:42px;bottom:0;width:100%;box-sizing:border-box}#ng-chat-users.offset-search{top:84px}#ng-chat-users .ng-chat-users-checkbox{float:left;margin-right:5px;margin-top:8px}#ng-chat-users li{clear:both;margin-bottom:10px;overflow:hidden;cursor:pointer;max-height:30px}#ng-chat-users li>.ng-chat-friends-list-selectable-offset{margin-left:22px}#ng-chat-users li .ng-chat-friends-list-container{display:inline-block;width:100%}#ng-chat-users li>.ng-chat-friends-list-selectable-offset.ng-chat-friends-list-container{display:block;width:auto}#ng-chat-users li .ng-chat-friends-list-container>img.avatar,#ng-chat-users li .ng-chat-friends-list-container>.user{float:left;display:flex;justify-content:center;margin-right:5px}#ng-chat-users li .ng-chat-friends-list-container>.user{overflow:hidden;width:30px;height:30px}#ng-chat-users li .ng-chat-friends-list-container>.user>i{color:#fff;transform:scale(.7)}#ng-chat-users li .ng-chat-friends-list-container>strong{float:left;line-height:30px;font-size:.8em;max-width:57%;max-height:30px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}#ng-chat-users li .ng-chat-friends-list-container>.ng-chat-participant-status{float:right}.ng-chat-people-actions{position:absolute;top:4px;right:5px;margin:0;padding:0;z-index:2}.ng-chat-people-actions>a.ng-chat-people-action{display:inline-block;width:21px;height:21px;margin-right:8px;text-decoration:none;border:none;border-radius:25px;padding:1px}@media only screen and (max-width: 581px){#ng-chat-people{width:300px;height:360px;margin-right:0}}.user{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:50%;background-color:#00b04c;color:#fff;font-size:12px;font-family:inherit}\n"] }]
|
|
370
|
+
}], ctorParameters: function () { return []; }, propDecorators: { participants: [{
|
|
371
|
+
type: Input
|
|
372
|
+
}], participantsResponse: [{
|
|
373
|
+
type: Input
|
|
374
|
+
}], participantsInteractedWith: [{
|
|
375
|
+
type: Input
|
|
376
|
+
}], windows: [{
|
|
377
|
+
type: Input
|
|
378
|
+
}], userId: [{
|
|
379
|
+
type: Input
|
|
380
|
+
}], localization: [{
|
|
381
|
+
type: Input
|
|
382
|
+
}], shouldDisplay: [{
|
|
383
|
+
type: Input
|
|
384
|
+
}], isCollapsed: [{
|
|
385
|
+
type: Input
|
|
386
|
+
}], searchEnabled: [{
|
|
387
|
+
type: Input
|
|
388
|
+
}], currentActiveOption: [{
|
|
389
|
+
type: Input
|
|
390
|
+
}], onParticipantClicked: [{
|
|
391
|
+
type: Output
|
|
392
|
+
}], onOptionPromptCanceled: [{
|
|
393
|
+
type: Output
|
|
394
|
+
}], onOptionPromptConfirmed: [{
|
|
395
|
+
type: Output
|
|
396
|
+
}], hideFriendsList: [{
|
|
397
|
+
type: Input
|
|
398
|
+
}], onCloseWindowClick: [{
|
|
399
|
+
type: Output
|
|
400
|
+
}] } });
|
|
401
|
+
|
|
402
|
+
class Message {
|
|
403
|
+
constructor() {
|
|
404
|
+
this.type = MessageType.Text;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
let emojiDictionary = [
|
|
409
|
+
{ patterns: [':)', ':-)', '=)'], unicode: '😃' },
|
|
410
|
+
{ patterns: [':D', ':-D', '=D'], unicode: '😀' },
|
|
411
|
+
{ patterns: [':(', ':-(', '=('], unicode: '🙁' },
|
|
412
|
+
{ patterns: [':|', ':-|', '=|'], unicode: '😐' },
|
|
413
|
+
{ patterns: [':*', ':-*', '=*'], unicode: '😙' },
|
|
414
|
+
{ patterns: ['T_T', 'T.T'], unicode: '😭' },
|
|
415
|
+
{ patterns: [':O', ':-O', '=O', ':o', ':-o', '=o'], unicode: '😮' },
|
|
416
|
+
{ patterns: [':P', ':-P', '=P', ':p', ':-p', '=p'], unicode: '😋' },
|
|
417
|
+
{ patterns: ['>.<'], unicode: '😣' },
|
|
418
|
+
{ patterns: ['@.@'], unicode: '😵' },
|
|
419
|
+
{ patterns: ['*.*'], unicode: '😍' },
|
|
420
|
+
{ patterns: ['<3'], unicode: '❤️' },
|
|
421
|
+
{ patterns: ['^.^'], unicode: '😊' },
|
|
422
|
+
{ patterns: [':+1'], unicode: '👍' },
|
|
423
|
+
{ patterns: [':-1'], unicode: '👎' }
|
|
424
|
+
];
|
|
425
|
+
/*
|
|
426
|
+
* Transforms common emoji text to UTF encoded emojis
|
|
427
|
+
*/
|
|
428
|
+
class EmojifyPipe {
|
|
429
|
+
transform(message, pipeEnabled) {
|
|
430
|
+
if (pipeEnabled && message && message.length > 1) {
|
|
431
|
+
emojiDictionary.forEach(emoji => {
|
|
432
|
+
emoji.patterns.forEach(pattern => {
|
|
433
|
+
message = message.replace(pattern, emoji.unicode);
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
return message;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
EmojifyPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: EmojifyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
441
|
+
EmojifyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: EmojifyPipe, name: "emojify" });
|
|
442
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: EmojifyPipe, decorators: [{
|
|
443
|
+
type: Pipe,
|
|
444
|
+
args: [{ name: 'emojify' }]
|
|
445
|
+
}] });
|
|
446
|
+
|
|
447
|
+
/*
|
|
448
|
+
* Transforms text containing URLs or E-mails to valid links/mailtos
|
|
449
|
+
*/
|
|
450
|
+
class LinkfyPipe {
|
|
451
|
+
transform(message, pipeEnabled) {
|
|
452
|
+
if (pipeEnabled && message && message.length > 1) {
|
|
453
|
+
let replacedText;
|
|
454
|
+
let replacePatternProtocol;
|
|
455
|
+
let replacePatternWWW;
|
|
456
|
+
let replacePatternMailTo;
|
|
457
|
+
// URLs starting with http://, https://, or ftp://
|
|
458
|
+
replacePatternProtocol = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
|
459
|
+
replacedText = message.replace(replacePatternProtocol, '<a href="$1" target="_blank">$1</a>');
|
|
460
|
+
// URLs starting with "www." (ignoring // before it).
|
|
461
|
+
replacePatternWWW = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
|
462
|
+
replacedText = replacedText.replace(replacePatternWWW, '$1<a href="http://$2" target="_blank">$2</a>');
|
|
463
|
+
// Change email addresses to mailto:: links.
|
|
464
|
+
replacePatternMailTo = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
|
|
465
|
+
replacedText = replacedText.replace(replacePatternMailTo, '<a href="mailto:$1">$1</a>');
|
|
466
|
+
return replacedText;
|
|
467
|
+
}
|
|
468
|
+
else
|
|
469
|
+
return message;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
LinkfyPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LinkfyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
473
|
+
LinkfyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: LinkfyPipe, name: "linkfy" });
|
|
474
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: LinkfyPipe, decorators: [{
|
|
475
|
+
type: Pipe,
|
|
476
|
+
args: [{ name: 'linkfy' }]
|
|
477
|
+
}] });
|
|
478
|
+
|
|
479
|
+
/*
|
|
480
|
+
* Renders the display name of a participant in a group based on who's sent the message
|
|
481
|
+
*/
|
|
482
|
+
class GroupMessageDisplayNamePipe {
|
|
483
|
+
transform(participant, message) {
|
|
484
|
+
if (participant && participant.participantType == ChatParticipantType.Group) {
|
|
485
|
+
let group = participant;
|
|
486
|
+
let userIndex = group.chattingTo.findIndex(x => x.id == message.fromId);
|
|
487
|
+
return group.chattingTo[userIndex >= 0 ? userIndex : 0].displayName;
|
|
488
|
+
}
|
|
489
|
+
else
|
|
490
|
+
return "";
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
GroupMessageDisplayNamePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GroupMessageDisplayNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
494
|
+
GroupMessageDisplayNamePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: GroupMessageDisplayNamePipe, name: "groupMessageDisplayName" });
|
|
495
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: GroupMessageDisplayNamePipe, decorators: [{
|
|
496
|
+
type: Pipe,
|
|
497
|
+
args: [{ name: 'groupMessageDisplayName' }]
|
|
498
|
+
}] });
|
|
499
|
+
|
|
500
|
+
/* eslint-disable */
|
|
501
|
+
class NgChatWindowComponent {
|
|
502
|
+
constructor() {
|
|
503
|
+
this.emojisEnabled = true;
|
|
504
|
+
this.linkfyEnabled = true;
|
|
505
|
+
this.showMessageDate = true;
|
|
506
|
+
this.messageDatePipeFormat = "short";
|
|
507
|
+
this.hasPagedHistory = true;
|
|
508
|
+
this.onChatWindowClosed = new EventEmitter();
|
|
509
|
+
this.onMessagesSeen = new EventEmitter();
|
|
510
|
+
this.onMessageSent = new EventEmitter();
|
|
511
|
+
this.onTabTriggered = new EventEmitter();
|
|
512
|
+
this.onOptionTriggered = new EventEmitter();
|
|
513
|
+
this.onLoadHistoryTriggered = new EventEmitter();
|
|
514
|
+
// File upload state
|
|
515
|
+
this.fileUploadersInUse = []; // Id bucket of uploaders in use
|
|
516
|
+
// Exposes enums and functions for the ng-template
|
|
517
|
+
this.ChatParticipantType = ChatParticipantType;
|
|
518
|
+
this.ChatParticipantStatus = ChatParticipantStatus;
|
|
519
|
+
this.MessageType = MessageType;
|
|
520
|
+
this.chatParticipantStatusDescriptor = chatParticipantStatusDescriptor;
|
|
521
|
+
}
|
|
522
|
+
defaultWindowOptions(currentWindow) {
|
|
523
|
+
if (this.showOptions && currentWindow.participant.participantType == ChatParticipantType.User) {
|
|
524
|
+
return [{
|
|
525
|
+
isActive: false,
|
|
526
|
+
chattingTo: currentWindow,
|
|
527
|
+
validateContext: (participant) => {
|
|
528
|
+
return participant.participantType == ChatParticipantType.User;
|
|
529
|
+
},
|
|
530
|
+
displayLabel: 'Add People' // TODO: Localize this
|
|
531
|
+
}];
|
|
532
|
+
}
|
|
533
|
+
return [];
|
|
534
|
+
}
|
|
535
|
+
// Asserts if a user avatar is visible in a chat cluster
|
|
536
|
+
isAvatarVisible(window, message, index) {
|
|
537
|
+
if (message.fromId != this.userId) {
|
|
538
|
+
if (index == 0) {
|
|
539
|
+
return true; // First message, good to show the thumbnail
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
// Check if the previous message belongs to the same user, if it belongs there is no need to show the avatar again to form the message cluster
|
|
543
|
+
if (window.messages[index - 1].fromId != message.fromId) {
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
getChatWindowAvatar(participant, message) {
|
|
551
|
+
if (participant.participantType == ChatParticipantType.User) {
|
|
552
|
+
return participant.avatar;
|
|
553
|
+
}
|
|
554
|
+
else if (participant.participantType == ChatParticipantType.Group) {
|
|
555
|
+
let group = participant;
|
|
556
|
+
let userIndex = group.chattingTo.findIndex(x => x.id == message.fromId);
|
|
557
|
+
return group.chattingTo[userIndex >= 0 ? userIndex : 0].avatar;
|
|
558
|
+
}
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
isUploadingFile(window) {
|
|
562
|
+
const fileUploadInstanceId = this.getUniqueFileUploadInstanceId(window);
|
|
563
|
+
return this.fileUploadersInUse.indexOf(fileUploadInstanceId) > -1;
|
|
564
|
+
}
|
|
565
|
+
// Generates a unique file uploader id for each participant
|
|
566
|
+
getUniqueFileUploadInstanceId(window) {
|
|
567
|
+
if (window && window.participant) {
|
|
568
|
+
return `ng-chat-file-upload-${window.participant.id}`;
|
|
569
|
+
}
|
|
570
|
+
return 'ng-chat-file-upload';
|
|
571
|
+
}
|
|
572
|
+
unreadMessagesTotal(window) {
|
|
573
|
+
return MessageCounter.unreadMessagesTotal(window, this.userId);
|
|
574
|
+
}
|
|
575
|
+
// Scrolls a chat window message flow to the bottom
|
|
576
|
+
scrollChatWindow(window, direction) {
|
|
577
|
+
if (!window.isCollapsed) {
|
|
578
|
+
setTimeout(() => {
|
|
579
|
+
if (this.chatMessages) {
|
|
580
|
+
let element = this.chatMessages.nativeElement;
|
|
581
|
+
let position = (direction === ScrollDirection.Top) ? 0 : element.scrollHeight;
|
|
582
|
+
element.scrollTop = position;
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
activeOptionTrackerChange(option) {
|
|
588
|
+
this.onOptionTriggered.emit(option);
|
|
589
|
+
}
|
|
590
|
+
// Triggers native file upload for file selection from the user
|
|
591
|
+
triggerNativeFileUpload(window) {
|
|
592
|
+
if (window) {
|
|
593
|
+
if (this.nativeFileInput)
|
|
594
|
+
this.nativeFileInput.nativeElement.click();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// Toggles a window focus on the focus/blur of a 'newMessage' input
|
|
598
|
+
toggleWindowFocus(window) {
|
|
599
|
+
window.hasFocus = !window.hasFocus;
|
|
600
|
+
if (window.hasFocus) {
|
|
601
|
+
const unreadMessages = window.messages
|
|
602
|
+
.filter(message => message.dateSeen == null
|
|
603
|
+
&& (message.toId == this.userId || window.participant.participantType === ChatParticipantType.Group));
|
|
604
|
+
if (unreadMessages && unreadMessages.length > 0) {
|
|
605
|
+
this.onMessagesSeen.emit(unreadMessages);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
markMessagesAsRead(messages) {
|
|
610
|
+
this.onMessagesSeen.emit(messages);
|
|
611
|
+
}
|
|
612
|
+
fetchMessageHistory(window) {
|
|
613
|
+
this.onLoadHistoryTriggered.emit(window);
|
|
614
|
+
}
|
|
615
|
+
// Closes a chat window via the close 'X' button
|
|
616
|
+
onCloseChatWindow() {
|
|
617
|
+
this.onChatWindowClosed.emit({ closedWindow: this.window, closedViaEscapeKey: false });
|
|
618
|
+
}
|
|
619
|
+
/* Monitors pressed keys on a chat window
|
|
620
|
+
- Dispatches a message when the ENTER key is pressed
|
|
621
|
+
- Tabs between windows on TAB or SHIFT + TAB
|
|
622
|
+
- Closes the current focused window on ESC
|
|
623
|
+
*/
|
|
624
|
+
onChatInputTyped(event, window) {
|
|
625
|
+
switch (event.keyCode) {
|
|
626
|
+
case 13:
|
|
627
|
+
if (window.newMessage && window.newMessage.trim() != "") {
|
|
628
|
+
let message = new Message();
|
|
629
|
+
message.fromId = this.userId;
|
|
630
|
+
message.toId = window.participant.id;
|
|
631
|
+
message.message = window.newMessage;
|
|
632
|
+
message.dateSent = new Date();
|
|
633
|
+
window.messages.push(message);
|
|
634
|
+
this.onMessageSent.emit(message);
|
|
635
|
+
window.newMessage = ""; // Resets the new message input
|
|
636
|
+
this.scrollChatWindow(window, ScrollDirection.Bottom);
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
case 9:
|
|
640
|
+
event.preventDefault();
|
|
641
|
+
this.onTabTriggered.emit({ triggeringWindow: window, shiftKeyPressed: event.shiftKey });
|
|
642
|
+
break;
|
|
643
|
+
case 27:
|
|
644
|
+
this.onChatWindowClosed.emit({ closedWindow: window, closedViaEscapeKey: true });
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
// Toggles a chat window visibility between maximized/minimized
|
|
649
|
+
onChatWindowClicked(window) {
|
|
650
|
+
window.isCollapsed = !window.isCollapsed;
|
|
651
|
+
this.scrollChatWindow(window, ScrollDirection.Bottom);
|
|
652
|
+
}
|
|
653
|
+
clearInUseFileUploader(fileUploadInstanceId) {
|
|
654
|
+
const uploaderInstanceIdIndex = this.fileUploadersInUse.indexOf(fileUploadInstanceId);
|
|
655
|
+
if (uploaderInstanceIdIndex > -1) {
|
|
656
|
+
this.fileUploadersInUse.splice(uploaderInstanceIdIndex, 1);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
// Handles file selection and uploads the selected file using the file upload adapter
|
|
660
|
+
onFileChosen(window) {
|
|
661
|
+
const fileUploadInstanceId = this.getUniqueFileUploadInstanceId(window);
|
|
662
|
+
const uploadElementRef = this.nativeFileInput;
|
|
663
|
+
if (uploadElementRef) {
|
|
664
|
+
const file = uploadElementRef.nativeElement.files[0];
|
|
665
|
+
this.fileUploadersInUse.push(fileUploadInstanceId);
|
|
666
|
+
this.fileUploadAdapter.uploadFile(file, window.participant.id)
|
|
667
|
+
.subscribe(fileMessage => {
|
|
668
|
+
this.clearInUseFileUploader(fileUploadInstanceId);
|
|
669
|
+
fileMessage.fromId = this.userId;
|
|
670
|
+
// Push file message to current user window
|
|
671
|
+
window.messages.push(fileMessage);
|
|
672
|
+
this.onMessageSent.emit(fileMessage);
|
|
673
|
+
this.scrollChatWindow(window, ScrollDirection.Bottom);
|
|
674
|
+
// Resets the file upload element
|
|
675
|
+
uploadElementRef.nativeElement.value = '';
|
|
676
|
+
}, (error) => {
|
|
677
|
+
this.clearInUseFileUploader(fileUploadInstanceId);
|
|
678
|
+
// Resets the file upload element
|
|
679
|
+
uploadElementRef.nativeElement.value = '';
|
|
680
|
+
// TODO: Invoke a file upload adapter error here
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
NgChatWindowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatWindowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
686
|
+
NgChatWindowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgChatWindowComponent, selector: "ng-chat-window", inputs: { fileUploadAdapter: "fileUploadAdapter", window: "window", userId: "userId", localization: "localization", showOptions: "showOptions", emojisEnabled: "emojisEnabled", linkfyEnabled: "linkfyEnabled", showMessageDate: "showMessageDate", messageDatePipeFormat: "messageDatePipeFormat", hasPagedHistory: "hasPagedHistory" }, outputs: { onChatWindowClosed: "onChatWindowClosed", onMessagesSeen: "onMessagesSeen", onMessageSent: "onMessageSent", onTabTriggered: "onTabTriggered", onOptionTriggered: "onOptionTriggered", onLoadHistoryTriggered: "onLoadHistoryTriggered" }, viewQueries: [{ propertyName: "chatMessages", first: true, predicate: ["chatMessages"], descendants: true }, { propertyName: "nativeFileInput", first: true, predicate: ["nativeFileInput"], descendants: true }, { propertyName: "chatWindowInput", first: true, predicate: ["chatWindowInput"], descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"window && window.isCollapsed\">\n\t<div class=\"ng-chat-title secondary-background\">\n\t\t<div class=\"ng-chat-title-visibility-toggle-area\" (click)=\"onChatWindowClicked(window)\">\n\t\t\t<strong title=\"{{window.participant.displayName}}\">\n\t\t\t\t{{window.participant.displayName}}\n\t\t\t</strong>\n\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': window.participant.status === ChatParticipantStatus.Online, 'busy': window.participant.status === ChatParticipantStatus.Busy, 'away': window.participant.status === ChatParticipantStatus.Away, 'offline': window.participant.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(window.participant.status, localization)}}\"></span>\n\t\t\t<span *ngIf=\"unreadMessagesTotal(window).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotal(window)}}</span>\n\t\t</div>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-close primary-text\" (click)=\"onCloseChatWindow()\">✕</a>\n\t</div>\n</ng-container>\n<ng-container *ngIf=\"window && !window.isCollapsed\"> \n\t<div class=\"ng-chat-title secondary-background\">\n\t\t<div class=\"ng-chat-title-visibility-toggle-area\" (click)=\"onChatWindowClicked(window)\">\n\t\t\t<strong title=\"{{window.participant.displayName}}\">\n\t\t\t\t{{window.participant.displayName}}\n\t\t\t</strong>\n\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': window.participant.status === ChatParticipantStatus.Online, 'busy': window.participant.status === ChatParticipantStatus.Busy, 'away': window.participant.status === ChatParticipantStatus.Away, 'offline': window.participant.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(window.participant.status, localization)}}\"></span>\n\t\t\t<span *ngIf=\"unreadMessagesTotal(window).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotal(window)}}</span>\n\t\t</div>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-close primary-text\" (click)=\"onCloseChatWindow()\">✕</a>\n\t\t<!-- <ng-chat-options [ngClass]=\"'ng-chat-options-container'\" [options]=\"defaultWindowOptions(window)\" (activeOptionTrackerChange)=\"activeOptionTrackerChange($event)\"></ng-chat-options> -->\n\t</div>\n\t\t<div #chatMessages class=\"ng-chat-messages primary-background\">\n\t\t\t<div *ngIf=\"window.isLoadingHistory\" class=\"ng-chat-loading-wrapper\">\n\t\t\t\t<div class=\"loader\">Loading history...</div>\n\t\t\t</div>\n\t\t\t<div *ngIf=\"hasPagedHistory && window.hasMoreMessages && !window.isLoadingHistory\" class=\"ng-chat-load-history\">\n\t\t\t\t<a class=\"load-history-action\" (click)=\"fetchMessageHistory(window)\">{{localization.loadMessageHistoryPlaceholder}}</a>\n\t\t\t</div>\n\n\t\t\t<div *ngFor=\"let message of window.messages; let i = index\" [ngClass]=\"{'ng-chat-message': true, 'ng-chat-message-received': message.fromId !== userId}\">\n\t\t\t\t<ng-container *ngIf=\"isAvatarVisible(window, message, i)\">\n\t\t\t\t\t<div *ngIf=\"!getChatWindowAvatar(window.participant, message)\" class=\"icon-wrapper\">\n\t\t\t\t\t\t<i class=\"user-icon\"></i>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- <img *ngIf=\"getChatWindowAvatar(window.participant, message)\" alt=\"\" class=\"avatar\" height=\"30\" width=\"30\" [src]=\"getChatWindowAvatar(window.participant, message) | sanitize\" /> -->\n\t\t\t\t\t<span *ngIf=\"window.participant.participantType === ChatParticipantType.Group\" class=\"ng-chat-participant-name\">{{window.participant | groupMessageDisplayName:message}}</span>\n\t\t\t\t</ng-container>\n\t\t\t\t<ng-container [ngSwitch]=\"message.type\">\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.Text\" [ngClass]=\"{'sent-chat-message-container': message.fromId === userId, 'received-chat-message-container': message.fromId !== userId}\">\n\t\t\t \t\t\t<span [innerHtml]=\"message.message | emojify:emojisEnabled | linkfy:linkfyEnabled\"></span>\n\t\t\t\t\t\t<span *ngIf=\"showMessageDate && message.dateSent\" class=\"message-sent-date\">{{message.dateSent | date:'dd'}}/{{message.dateSent | date:'MM'}}/{{message.dateSent | date:'y'}} {{message.dateSent | date:'h:mm a '}}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.Image\" [ngClass]=\"{'sent-chat-message-container': message.fromId === userId, 'received-chat-message-container': message.fromId !== userId}\">\n\t\n\t\t\t \t\t\t<img src=\"{{message.message}}\" class=\"image-message\" />\n\t\n\t\t\t\t\t\t<span *ngIf=\"showMessageDate && message.dateSent\" class=\"message-sent-date\">{{message.dateSent | date:'dd'}}/{{message.dateSent | date:'MM'}}/{{message.dateSent | date:'y'}} {{message.dateSent | date:'h:mm a '}}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.File\" [ngClass]=\"{'file-message-container': true, 'received': message.fromId !== userId}\">\n\t\t\t\t\t\t<div class=\"file-message-icon-container\">\n\t\t\t\t\t\t\t<i class=\"paperclip-icon\"></i>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- <a class=\"file-details\" [attr.href]=\"message.downloadUrl\" target=\"_blank\" rel=\"noopener noreferrer\" (click)=\"this.markMessagesAsRead([message])\" download>\n\t\t\t\t\t\t\t<span class=\"file-message-title\" [attr.title]=\"message.message\">{{message.message}}</span>\n\t\t\t\t\t\t\t<span *ngIf=\"message.fileSizeInBytes\" class=\"file-message-size\">{{message.fileSizeInBytes}} Bytes</span>\n\t\t\t\t\t\t</a> -->\n\t\t\t\t\t</div>\n\t\t\t\t</ng-container>\n\t\t\t</div>\n\t</div>\n\n\t<div class=\"ng-chat-footer primary-outline-color primary-background\">\n\t\t<input #chatWindowInput\n\t\t\ttype=\"text\"\n\t\t\t[ngModel]=\"window.newMessage | emojify:emojisEnabled\"\n\t\t\t(ngModelChange)=\"window.newMessage=$event\"\n\t\t\t[placeholder]=\"localization.messagePlaceholder\"\n\t\t\t[ngClass]=\"{'chat-window-input': true, 'has-side-action': fileUploadAdapter}\"\n\t\t\t(keydown)=\"onChatInputTyped($event, window)\"\n\t\t\t(blur)=\"toggleWindowFocus(window)\"\n\t\t\t(focus)=\"toggleWindowFocus(window)\"/>\n\n\t\t<!-- File Upload -->\n\t\t<ng-container *ngIf=\"fileUploadAdapter\">\n\t\t\t<a *ngIf=\"!isUploadingFile(window)\" class=\"btn-add-file\" (click)=\"triggerNativeFileUpload(window)\">\n\t\t\t\t<i class=\"upload-icon\"></i>\n\t\t\t</a>\n\t\t\t<input\n\t\t\t\ttype=\"file\"\n\t\t\t\t#nativeFileInput\n\t\t\t\tstyle=\"display: none;\"\n\t\t\t\t[attr.id]=\"getUniqueFileUploadInstanceId(window)\"\n\t\t\t\t(change)=\"onFileChosen(window)\" />\n\t\t\t<div *ngIf=\"isUploadingFile(window)\" class=\"loader\"></div>\n\t\t</ng-container>\n\t</div>\n</ng-container>", styles: [".ng-chat-window{right:260px;height:360px;z-index:999;bottom:0;width:300px;position:fixed;border-width:1px;border-style:solid;border-bottom:0;box-shadow:0 4px 8px #00000040;margin-bottom:10px!important;border:1px solid grey!important;border-radius:10px!important;box-sizing:border-box!important;overflow:hidden!important;background-color:#fff;::-webkit-scrollbar {width: 8px !important;} ::-webkit-scrollbar-thumb {background: #1b1b70 !important; border-radius: 5px !important;}}.ng-chat-window-collapsed{height:30px!important}.ng-chat-window .ng-chat-footer{box-sizing:border-box!important;padding-bottom:10px!important;display:block;height:10%;width:95%!important;margin:auto!important;background-color:inherit!important}.ng-chat-window .ng-chat-footer>input{font-size:.8em;box-sizing:border-box!important;padding:15px!important;height:100%;width:100%;border-radius:20px!important;border:1px solid grey!important}.ng-chat-window .ng-chat-footer>input.has-side-action{width:calc(100% - 30px)}.ng-chat-window .ng-chat-footer .btn-add-file{position:absolute;right:5px;bottom:7px;height:20px;width:20px;cursor:pointer}.ng-chat-window .ng-chat-footer .loader{position:absolute;right:14px;bottom:8px}.ng-chat-window .ng-chat-load-history{height:30px;text-align:center;font-size:.8em}.ng-chat-window .ng-chat-load-history>a{border-radius:15px;cursor:pointer;padding:5px 10px}.ng-chat-window .ng-chat-messages{padding:10px;width:100%;height:calc(90% - 30px);box-sizing:border-box;position:relative;overflow:auto}.ng-chat-window .ng-chat-messages .ng-chat-message{clear:both}.ng-chat-window .ng-chat-messages .ng-chat-message>img.avatar,.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper{position:absolute;left:10px;border-radius:25px}.ng-chat-window .ng-chat-messages .ng-chat-message .ng-chat-participant-name{display:inline-block;margin-left:40px;padding-bottom:5px;font-weight:700;font-size:.8em;text-overflow:ellipsis;max-width:180px}.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper{background-color:#bababa;overflow:hidden;width:30px;height:30px;padding:0}.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper>i{color:#fff;transform:scale(.7)}.ng-chat-window .ng-chat-messages .ng-chat-message .message-sent-date{font-size:.5em!important;display:block;text-align:right;margin-top:5px;color:#a1a0a0!important;font-style:italic!important}.ng-chat-window .ng-chat-messages .ng-chat-message>div{float:right;width:182px;border-radius:15px 15px 0!important;padding:10px;margin-top:0;margin-bottom:5px;font-size:.9em;word-wrap:break-word;background-color:#93d4f0!important}.ng-chat-window .ng-chat-message-received>div.received-chat-message-container{float:left;margin-left:40px;padding-top:7px;padding-bottom:7px;margin-top:0;margin-bottom:5px;background-color:#daf2fc!important;border-radius:15px 15px 15px 0!important}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container{float:right;width:202px;border-style:solid;border-width:3px;border-radius:5px;overflow:hidden;margin-bottom:5px;display:block;text-decoration:none;font-size:.9em;padding:0;box-sizing:border-box}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container.received{float:left;margin-left:40px;width:208px}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-message-icon-container{width:20px;height:35px;padding:10px 5px;float:left}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-message-icon-container i{margin-top:8px}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details{float:left;padding:10px;width:calc(100% - 60px);color:currentColor;text-decoration:none}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details:hover{text-decoration:underline}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details span{display:block;width:100%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details .file-message-title{font-weight:700}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details .file-message-size{font-size:.8em;margin-top:5px}.ng-chat-window .image-message{width:100%;height:auto}@media only screen and (max-width: 581px){.ng-chat-window{position:initial}}\n"], dependencies: [{ kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }, { kind: "pipe", type: EmojifyPipe, name: "emojify" }, { kind: "pipe", type: LinkfyPipe, name: "linkfy" }, { kind: "pipe", type: GroupMessageDisplayNamePipe, name: "groupMessageDisplayName" }], encapsulation: i0.ViewEncapsulation.None });
|
|
687
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatWindowComponent, decorators: [{
|
|
688
|
+
type: Component,
|
|
689
|
+
args: [{ selector: 'ng-chat-window', encapsulation: ViewEncapsulation.None, template: "<ng-container *ngIf=\"window && window.isCollapsed\">\n\t<div class=\"ng-chat-title secondary-background\">\n\t\t<div class=\"ng-chat-title-visibility-toggle-area\" (click)=\"onChatWindowClicked(window)\">\n\t\t\t<strong title=\"{{window.participant.displayName}}\">\n\t\t\t\t{{window.participant.displayName}}\n\t\t\t</strong>\n\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': window.participant.status === ChatParticipantStatus.Online, 'busy': window.participant.status === ChatParticipantStatus.Busy, 'away': window.participant.status === ChatParticipantStatus.Away, 'offline': window.participant.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(window.participant.status, localization)}}\"></span>\n\t\t\t<span *ngIf=\"unreadMessagesTotal(window).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotal(window)}}</span>\n\t\t</div>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-close primary-text\" (click)=\"onCloseChatWindow()\">✕</a>\n\t</div>\n</ng-container>\n<ng-container *ngIf=\"window && !window.isCollapsed\"> \n\t<div class=\"ng-chat-title secondary-background\">\n\t\t<div class=\"ng-chat-title-visibility-toggle-area\" (click)=\"onChatWindowClicked(window)\">\n\t\t\t<strong title=\"{{window.participant.displayName}}\">\n\t\t\t\t{{window.participant.displayName}}\n\t\t\t</strong>\n\t\t\t<span [ngClass]=\"{'ng-chat-participant-status': true, 'online': window.participant.status === ChatParticipantStatus.Online, 'busy': window.participant.status === ChatParticipantStatus.Busy, 'away': window.participant.status === ChatParticipantStatus.Away, 'offline': window.participant.status === ChatParticipantStatus.Offline}\" title=\"{{chatParticipantStatusDescriptor(window.participant.status, localization)}}\"></span>\n\t\t\t<span *ngIf=\"unreadMessagesTotal(window).length > 0\" class=\"ng-chat-unread-messages-count unread-messages-counter-container primary-text\">{{unreadMessagesTotal(window)}}</span>\n\t\t</div>\n\t\t<a href=\"javascript:void(0);\" class=\"ng-chat-close primary-text\" (click)=\"onCloseChatWindow()\">✕</a>\n\t\t<!-- <ng-chat-options [ngClass]=\"'ng-chat-options-container'\" [options]=\"defaultWindowOptions(window)\" (activeOptionTrackerChange)=\"activeOptionTrackerChange($event)\"></ng-chat-options> -->\n\t</div>\n\t\t<div #chatMessages class=\"ng-chat-messages primary-background\">\n\t\t\t<div *ngIf=\"window.isLoadingHistory\" class=\"ng-chat-loading-wrapper\">\n\t\t\t\t<div class=\"loader\">Loading history...</div>\n\t\t\t</div>\n\t\t\t<div *ngIf=\"hasPagedHistory && window.hasMoreMessages && !window.isLoadingHistory\" class=\"ng-chat-load-history\">\n\t\t\t\t<a class=\"load-history-action\" (click)=\"fetchMessageHistory(window)\">{{localization.loadMessageHistoryPlaceholder}}</a>\n\t\t\t</div>\n\n\t\t\t<div *ngFor=\"let message of window.messages; let i = index\" [ngClass]=\"{'ng-chat-message': true, 'ng-chat-message-received': message.fromId !== userId}\">\n\t\t\t\t<ng-container *ngIf=\"isAvatarVisible(window, message, i)\">\n\t\t\t\t\t<div *ngIf=\"!getChatWindowAvatar(window.participant, message)\" class=\"icon-wrapper\">\n\t\t\t\t\t\t<i class=\"user-icon\"></i>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- <img *ngIf=\"getChatWindowAvatar(window.participant, message)\" alt=\"\" class=\"avatar\" height=\"30\" width=\"30\" [src]=\"getChatWindowAvatar(window.participant, message) | sanitize\" /> -->\n\t\t\t\t\t<span *ngIf=\"window.participant.participantType === ChatParticipantType.Group\" class=\"ng-chat-participant-name\">{{window.participant | groupMessageDisplayName:message}}</span>\n\t\t\t\t</ng-container>\n\t\t\t\t<ng-container [ngSwitch]=\"message.type\">\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.Text\" [ngClass]=\"{'sent-chat-message-container': message.fromId === userId, 'received-chat-message-container': message.fromId !== userId}\">\n\t\t\t \t\t\t<span [innerHtml]=\"message.message | emojify:emojisEnabled | linkfy:linkfyEnabled\"></span>\n\t\t\t\t\t\t<span *ngIf=\"showMessageDate && message.dateSent\" class=\"message-sent-date\">{{message.dateSent | date:'dd'}}/{{message.dateSent | date:'MM'}}/{{message.dateSent | date:'y'}} {{message.dateSent | date:'h:mm a '}}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.Image\" [ngClass]=\"{'sent-chat-message-container': message.fromId === userId, 'received-chat-message-container': message.fromId !== userId}\">\n\t\n\t\t\t \t\t\t<img src=\"{{message.message}}\" class=\"image-message\" />\n\t\n\t\t\t\t\t\t<span *ngIf=\"showMessageDate && message.dateSent\" class=\"message-sent-date\">{{message.dateSent | date:'dd'}}/{{message.dateSent | date:'MM'}}/{{message.dateSent | date:'y'}} {{message.dateSent | date:'h:mm a '}}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div *ngSwitchCase=\"MessageType.File\" [ngClass]=\"{'file-message-container': true, 'received': message.fromId !== userId}\">\n\t\t\t\t\t\t<div class=\"file-message-icon-container\">\n\t\t\t\t\t\t\t<i class=\"paperclip-icon\"></i>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- <a class=\"file-details\" [attr.href]=\"message.downloadUrl\" target=\"_blank\" rel=\"noopener noreferrer\" (click)=\"this.markMessagesAsRead([message])\" download>\n\t\t\t\t\t\t\t<span class=\"file-message-title\" [attr.title]=\"message.message\">{{message.message}}</span>\n\t\t\t\t\t\t\t<span *ngIf=\"message.fileSizeInBytes\" class=\"file-message-size\">{{message.fileSizeInBytes}} Bytes</span>\n\t\t\t\t\t\t</a> -->\n\t\t\t\t\t</div>\n\t\t\t\t</ng-container>\n\t\t\t</div>\n\t</div>\n\n\t<div class=\"ng-chat-footer primary-outline-color primary-background\">\n\t\t<input #chatWindowInput\n\t\t\ttype=\"text\"\n\t\t\t[ngModel]=\"window.newMessage | emojify:emojisEnabled\"\n\t\t\t(ngModelChange)=\"window.newMessage=$event\"\n\t\t\t[placeholder]=\"localization.messagePlaceholder\"\n\t\t\t[ngClass]=\"{'chat-window-input': true, 'has-side-action': fileUploadAdapter}\"\n\t\t\t(keydown)=\"onChatInputTyped($event, window)\"\n\t\t\t(blur)=\"toggleWindowFocus(window)\"\n\t\t\t(focus)=\"toggleWindowFocus(window)\"/>\n\n\t\t<!-- File Upload -->\n\t\t<ng-container *ngIf=\"fileUploadAdapter\">\n\t\t\t<a *ngIf=\"!isUploadingFile(window)\" class=\"btn-add-file\" (click)=\"triggerNativeFileUpload(window)\">\n\t\t\t\t<i class=\"upload-icon\"></i>\n\t\t\t</a>\n\t\t\t<input\n\t\t\t\ttype=\"file\"\n\t\t\t\t#nativeFileInput\n\t\t\t\tstyle=\"display: none;\"\n\t\t\t\t[attr.id]=\"getUniqueFileUploadInstanceId(window)\"\n\t\t\t\t(change)=\"onFileChosen(window)\" />\n\t\t\t<div *ngIf=\"isUploadingFile(window)\" class=\"loader\"></div>\n\t\t</ng-container>\n\t</div>\n</ng-container>", styles: [".ng-chat-window{right:260px;height:360px;z-index:999;bottom:0;width:300px;position:fixed;border-width:1px;border-style:solid;border-bottom:0;box-shadow:0 4px 8px #00000040;margin-bottom:10px!important;border:1px solid grey!important;border-radius:10px!important;box-sizing:border-box!important;overflow:hidden!important;background-color:#fff;::-webkit-scrollbar {width: 8px !important;} ::-webkit-scrollbar-thumb {background: #1b1b70 !important; border-radius: 5px !important;}}.ng-chat-window-collapsed{height:30px!important}.ng-chat-window .ng-chat-footer{box-sizing:border-box!important;padding-bottom:10px!important;display:block;height:10%;width:95%!important;margin:auto!important;background-color:inherit!important}.ng-chat-window .ng-chat-footer>input{font-size:.8em;box-sizing:border-box!important;padding:15px!important;height:100%;width:100%;border-radius:20px!important;border:1px solid grey!important}.ng-chat-window .ng-chat-footer>input.has-side-action{width:calc(100% - 30px)}.ng-chat-window .ng-chat-footer .btn-add-file{position:absolute;right:5px;bottom:7px;height:20px;width:20px;cursor:pointer}.ng-chat-window .ng-chat-footer .loader{position:absolute;right:14px;bottom:8px}.ng-chat-window .ng-chat-load-history{height:30px;text-align:center;font-size:.8em}.ng-chat-window .ng-chat-load-history>a{border-radius:15px;cursor:pointer;padding:5px 10px}.ng-chat-window .ng-chat-messages{padding:10px;width:100%;height:calc(90% - 30px);box-sizing:border-box;position:relative;overflow:auto}.ng-chat-window .ng-chat-messages .ng-chat-message{clear:both}.ng-chat-window .ng-chat-messages .ng-chat-message>img.avatar,.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper{position:absolute;left:10px;border-radius:25px}.ng-chat-window .ng-chat-messages .ng-chat-message .ng-chat-participant-name{display:inline-block;margin-left:40px;padding-bottom:5px;font-weight:700;font-size:.8em;text-overflow:ellipsis;max-width:180px}.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper{background-color:#bababa;overflow:hidden;width:30px;height:30px;padding:0}.ng-chat-window .ng-chat-messages .ng-chat-message>.icon-wrapper>i{color:#fff;transform:scale(.7)}.ng-chat-window .ng-chat-messages .ng-chat-message .message-sent-date{font-size:.5em!important;display:block;text-align:right;margin-top:5px;color:#a1a0a0!important;font-style:italic!important}.ng-chat-window .ng-chat-messages .ng-chat-message>div{float:right;width:182px;border-radius:15px 15px 0!important;padding:10px;margin-top:0;margin-bottom:5px;font-size:.9em;word-wrap:break-word;background-color:#93d4f0!important}.ng-chat-window .ng-chat-message-received>div.received-chat-message-container{float:left;margin-left:40px;padding-top:7px;padding-bottom:7px;margin-top:0;margin-bottom:5px;background-color:#daf2fc!important;border-radius:15px 15px 15px 0!important}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container{float:right;width:202px;border-style:solid;border-width:3px;border-radius:5px;overflow:hidden;margin-bottom:5px;display:block;text-decoration:none;font-size:.9em;padding:0;box-sizing:border-box}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container.received{float:left;margin-left:40px;width:208px}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-message-icon-container{width:20px;height:35px;padding:10px 5px;float:left}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-message-icon-container i{margin-top:8px}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details{float:left;padding:10px;width:calc(100% - 60px);color:currentColor;text-decoration:none}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details:hover{text-decoration:underline}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details span{display:block;width:100%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details .file-message-title{font-weight:700}.ng-chat-window .ng-chat-messages .ng-chat-message .file-message-container>.file-details .file-message-size{font-size:.8em;margin-top:5px}.ng-chat-window .image-message{width:100%;height:auto}@media only screen and (max-width: 581px){.ng-chat-window{position:initial}}\n"] }]
|
|
690
|
+
}], ctorParameters: function () { return []; }, propDecorators: { fileUploadAdapter: [{
|
|
691
|
+
type: Input
|
|
692
|
+
}], window: [{
|
|
693
|
+
type: Input
|
|
694
|
+
}], userId: [{
|
|
695
|
+
type: Input
|
|
696
|
+
}], localization: [{
|
|
697
|
+
type: Input
|
|
698
|
+
}], showOptions: [{
|
|
699
|
+
type: Input
|
|
700
|
+
}], emojisEnabled: [{
|
|
701
|
+
type: Input
|
|
702
|
+
}], linkfyEnabled: [{
|
|
703
|
+
type: Input
|
|
704
|
+
}], showMessageDate: [{
|
|
705
|
+
type: Input
|
|
706
|
+
}], messageDatePipeFormat: [{
|
|
707
|
+
type: Input
|
|
708
|
+
}], hasPagedHistory: [{
|
|
709
|
+
type: Input
|
|
710
|
+
}], onChatWindowClosed: [{
|
|
711
|
+
type: Output
|
|
712
|
+
}], onMessagesSeen: [{
|
|
713
|
+
type: Output
|
|
714
|
+
}], onMessageSent: [{
|
|
715
|
+
type: Output
|
|
716
|
+
}], onTabTriggered: [{
|
|
717
|
+
type: Output
|
|
718
|
+
}], onOptionTriggered: [{
|
|
719
|
+
type: Output
|
|
720
|
+
}], onLoadHistoryTriggered: [{
|
|
721
|
+
type: Output
|
|
722
|
+
}], chatMessages: [{
|
|
723
|
+
type: ViewChild,
|
|
724
|
+
args: ['chatMessages']
|
|
725
|
+
}], nativeFileInput: [{
|
|
726
|
+
type: ViewChild,
|
|
727
|
+
args: ['nativeFileInput']
|
|
728
|
+
}], chatWindowInput: [{
|
|
729
|
+
type: ViewChild,
|
|
730
|
+
args: ['chatWindowInput']
|
|
731
|
+
}] } });
|
|
732
|
+
|
|
733
|
+
/* eslint-disable */
|
|
734
|
+
class NgChat {
|
|
735
|
+
constructor(_httpClient) {
|
|
736
|
+
this._httpClient = _httpClient;
|
|
737
|
+
// Exposes enums for the ng-template
|
|
738
|
+
this.ChatParticipantType = ChatParticipantType;
|
|
739
|
+
this.ChatParticipantStatus = ChatParticipantStatus;
|
|
740
|
+
this.MessageType = MessageType;
|
|
741
|
+
this._isDisabled = false;
|
|
742
|
+
this.isCollapsed = false;
|
|
743
|
+
this.maximizeWindowOnNewMessage = true;
|
|
744
|
+
this.pollFriendsList = false;
|
|
745
|
+
this.pollingInterval = 5000;
|
|
746
|
+
this.historyEnabled = true;
|
|
747
|
+
this.emojisEnabled = true;
|
|
748
|
+
this.linkfyEnabled = true;
|
|
749
|
+
this.audioEnabled = true;
|
|
750
|
+
this.searchEnabled = true;
|
|
751
|
+
this.audioSource = '../../../assets/notification.wav';
|
|
752
|
+
this.persistWindowsState = true;
|
|
753
|
+
this.title = "Quick chat";
|
|
754
|
+
this.messagePlaceholder = "Type a message";
|
|
755
|
+
this.searchPlaceholder = "Search";
|
|
756
|
+
this.browserNotificationsEnabled = true;
|
|
757
|
+
this.browserNotificationIconSource = '../../../assets/notification.png';
|
|
758
|
+
this.browserNotificationTitle = "New message from";
|
|
759
|
+
this.historyPageSize = 10;
|
|
760
|
+
this.hideFriendsList = false;
|
|
761
|
+
this.hideFriendsListOnUnsupportedViewport = true;
|
|
762
|
+
this.theme = Theme.Light;
|
|
763
|
+
this.messageDatePipeFormat = "short";
|
|
764
|
+
this.showMessageDate = true;
|
|
765
|
+
this.isViewportOnMobileEnabled = false;
|
|
766
|
+
this.onParticipantClicked = new EventEmitter();
|
|
767
|
+
this.onParticipantChatOpened = new EventEmitter();
|
|
768
|
+
this.onParticipantChatClosed = new EventEmitter();
|
|
769
|
+
this.onMessagesSeen = new EventEmitter();
|
|
770
|
+
this.onCloseWindowClicked = new EventEmitter();
|
|
771
|
+
this.browserNotificationsBootstrapped = false;
|
|
772
|
+
this.hasPagedHistory = false;
|
|
773
|
+
// Don't want to add this as a setting to simplify usage. Previous placeholder and title settings available to be used, or use full Localization object.
|
|
774
|
+
this.statusDescription = {
|
|
775
|
+
online: 'Online',
|
|
776
|
+
busy: 'Busy',
|
|
777
|
+
away: 'Away',
|
|
778
|
+
offline: 'Offline'
|
|
779
|
+
};
|
|
780
|
+
this.participantsInteractedWith = [];
|
|
781
|
+
// Defines the size of each opened window to calculate how many windows can be opened on the viewport at the same time.
|
|
782
|
+
this.windowSizeFactor = 320;
|
|
783
|
+
// Total width size of the friends list section
|
|
784
|
+
this.friendsListWidth = 262;
|
|
785
|
+
// Set to true if there is no space to display at least one chat window and 'hideFriendsListOnUnsupportedViewport' is true
|
|
786
|
+
this.unsupportedViewport = false;
|
|
787
|
+
this.windows = [];
|
|
788
|
+
this.isBootstrapped = false;
|
|
789
|
+
}
|
|
790
|
+
get isDisabled() {
|
|
791
|
+
return this._isDisabled;
|
|
792
|
+
}
|
|
793
|
+
set isDisabled(value) {
|
|
794
|
+
this._isDisabled = value;
|
|
795
|
+
if (value) {
|
|
796
|
+
window.clearInterval(this.pollingIntervalWindowInstance);
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
this.activateFriendListFetch();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
get localStorageKey() {
|
|
803
|
+
return `ng-chat-users-${this.userId}`; // Appending the user id so the state is unique per user in a computer.
|
|
804
|
+
}
|
|
805
|
+
;
|
|
806
|
+
ngOnInit() {
|
|
807
|
+
this.bootstrapChat();
|
|
808
|
+
}
|
|
809
|
+
onResize(event) {
|
|
810
|
+
this.viewPortTotalArea = event.target.innerWidth;
|
|
811
|
+
this.NormalizeWindows();
|
|
812
|
+
}
|
|
813
|
+
// Checks if there are more opened windows than the view port can display
|
|
814
|
+
NormalizeWindows() {
|
|
815
|
+
const maxSupportedOpenedWindows = Math.floor((this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0)) / this.windowSizeFactor);
|
|
816
|
+
const difference = this.windows.length - maxSupportedOpenedWindows;
|
|
817
|
+
if (difference >= 0) {
|
|
818
|
+
this.windows.splice(this.windows.length - difference);
|
|
819
|
+
}
|
|
820
|
+
this.updateWindowsState(this.windows);
|
|
821
|
+
// Viewport should have space for at least one chat window but should show in mobile if option is enabled.
|
|
822
|
+
this.unsupportedViewport = this.isViewportOnMobileEnabled ? false : this.hideFriendsListOnUnsupportedViewport && maxSupportedOpenedWindows < 1;
|
|
823
|
+
}
|
|
824
|
+
// Initializes the chat plugin and the messaging adapter
|
|
825
|
+
bootstrapChat() {
|
|
826
|
+
let initializationException = null;
|
|
827
|
+
if (this.adapter != null && this.userId != null) {
|
|
828
|
+
try {
|
|
829
|
+
this.viewPortTotalArea = window.innerWidth;
|
|
830
|
+
this.initializeTheme();
|
|
831
|
+
this.initializeDefaultText();
|
|
832
|
+
this.initializeBrowserNotifications();
|
|
833
|
+
// Binding event listeners
|
|
834
|
+
this.adapter.messageReceivedHandler = (participant, msg) => this.onMessageReceived(participant, msg);
|
|
835
|
+
this.adapter.friendsListChangedHandler = (participantsResponse) => this.onFriendsListChanged(participantsResponse);
|
|
836
|
+
this.activateFriendListFetch();
|
|
837
|
+
this.bufferAudioFile();
|
|
838
|
+
this.hasPagedHistory = this.adapter instanceof PagedHistoryChatAdapter;
|
|
839
|
+
if (this.fileUploadUrl && this.fileUploadUrl !== "") {
|
|
840
|
+
this.fileUploadAdapter = new DefaultFileUploadAdapter(this.fileUploadUrl, this._httpClient);
|
|
841
|
+
}
|
|
842
|
+
this.NormalizeWindows();
|
|
843
|
+
this.isBootstrapped = true;
|
|
844
|
+
}
|
|
845
|
+
catch (ex) {
|
|
846
|
+
initializationException = ex;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
if (!this.isBootstrapped) {
|
|
850
|
+
console.error("ng-chat component couldn't be bootstrapped.");
|
|
851
|
+
if (this.userId == null) {
|
|
852
|
+
console.error("ng-chat can't be initialized without an user id. Please make sure you've provided an userId as a parameter of the ng-chat component.");
|
|
853
|
+
}
|
|
854
|
+
if (this.adapter == null) {
|
|
855
|
+
console.error("ng-chat can't be bootstrapped without a ChatAdapter. Please make sure you've provided a ChatAdapter implementation as a parameter of the ng-chat component.");
|
|
856
|
+
}
|
|
857
|
+
if (initializationException) {
|
|
858
|
+
console.error(`An exception has occurred while initializing ng-chat. Details: ${initializationException.message}`);
|
|
859
|
+
console.error(initializationException);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
activateFriendListFetch() {
|
|
864
|
+
if (this.adapter) {
|
|
865
|
+
// Loading current users list
|
|
866
|
+
if (this.pollFriendsList) {
|
|
867
|
+
// Setting a long poll interval to update the friends list
|
|
868
|
+
this.fetchFriendsList(true);
|
|
869
|
+
this.pollingIntervalWindowInstance = window.setInterval(() => this.fetchFriendsList(false), this.pollingInterval);
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
// Since polling was disabled, a friends list update mechanism will have to be implemented in the ChatAdapter.
|
|
873
|
+
this.fetchFriendsList(true);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
// Initializes browser notifications
|
|
878
|
+
async initializeBrowserNotifications() {
|
|
879
|
+
if (this.browserNotificationsEnabled && ("Notification" in window)) {
|
|
880
|
+
if (await Notification.requestPermission() === "granted") {
|
|
881
|
+
this.browserNotificationsBootstrapped = true;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
// Initializes default text
|
|
886
|
+
initializeDefaultText() {
|
|
887
|
+
if (!this.localization) {
|
|
888
|
+
this.localization = {
|
|
889
|
+
messagePlaceholder: this.messagePlaceholder,
|
|
890
|
+
searchPlaceholder: this.searchPlaceholder,
|
|
891
|
+
title: this.title,
|
|
892
|
+
statusDescription: this.statusDescription,
|
|
893
|
+
browserNotificationTitle: this.browserNotificationTitle,
|
|
894
|
+
loadMessageHistoryPlaceholder: "Load older messages"
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
initializeTheme() {
|
|
899
|
+
if (this.customTheme) {
|
|
900
|
+
this.theme = Theme.Custom;
|
|
901
|
+
}
|
|
902
|
+
else if (this.theme != Theme.Light && this.theme != Theme.Dark) {
|
|
903
|
+
// TODO: Use es2017 in future with Object.values(Theme).includes(this.theme) to do this check
|
|
904
|
+
throw new Error(`Invalid theme configuration for ng-chat. "${this.theme}" is not a valid theme value.`);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
// Sends a request to load the friends list
|
|
908
|
+
fetchFriendsList(isBootstrapping) {
|
|
909
|
+
this.adapter.listFriends()
|
|
910
|
+
.pipe(map((participantsResponse) => {
|
|
911
|
+
this.participantsResponse = participantsResponse;
|
|
912
|
+
this.participants = participantsResponse.map((response) => {
|
|
913
|
+
return response.participant;
|
|
914
|
+
});
|
|
915
|
+
})).subscribe(() => {
|
|
916
|
+
if (isBootstrapping) {
|
|
917
|
+
this.restoreWindowsState();
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
fetchMessageHistory(window) {
|
|
922
|
+
// Not ideal but will keep this until we decide if we are shipping pagination with the default adapter
|
|
923
|
+
if (this.adapter instanceof PagedHistoryChatAdapter) {
|
|
924
|
+
window.isLoadingHistory = true;
|
|
925
|
+
this.adapter.getMessageHistoryByPage(window.participant.id, this.historyPageSize, ++window.historyPage)
|
|
926
|
+
.pipe(map((result) => {
|
|
927
|
+
result.forEach((message) => this.assertMessageType(message));
|
|
928
|
+
window.messages = result.concat(window.messages);
|
|
929
|
+
window.isLoadingHistory = false;
|
|
930
|
+
const direction = (window.historyPage == 1) ? ScrollDirection.Bottom : ScrollDirection.Top;
|
|
931
|
+
window.hasMoreMessages = result.length == this.historyPageSize;
|
|
932
|
+
setTimeout(() => this.onFetchMessageHistoryLoaded(result, window, direction, true));
|
|
933
|
+
})).subscribe();
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
this.adapter.getMessageHistory(window.participant.id)
|
|
937
|
+
.pipe(map((result) => {
|
|
938
|
+
result.forEach((message) => this.assertMessageType(message));
|
|
939
|
+
window.messages = result.concat(window.messages);
|
|
940
|
+
window.isLoadingHistory = false;
|
|
941
|
+
setTimeout(() => this.onFetchMessageHistoryLoaded(result, window, ScrollDirection.Bottom));
|
|
942
|
+
})).subscribe();
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
onFetchMessageHistoryLoaded(messages, window, direction, forceMarkMessagesAsSeen = false) {
|
|
946
|
+
this.scrollChatWindow(window, direction);
|
|
947
|
+
if (window.hasFocus || forceMarkMessagesAsSeen) {
|
|
948
|
+
const unseenMessages = messages.filter(m => !m.dateSeen);
|
|
949
|
+
this.markMessagesAsRead(unseenMessages);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
// Updates the friends list via the event handler
|
|
953
|
+
onFriendsListChanged(participantsResponse) {
|
|
954
|
+
if (participantsResponse) {
|
|
955
|
+
this.participantsResponse = participantsResponse;
|
|
956
|
+
this.participants = participantsResponse.map((response) => {
|
|
957
|
+
return response.participant;
|
|
958
|
+
});
|
|
959
|
+
this.participantsInteractedWith = [];
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
// Handles received messages by the adapter
|
|
963
|
+
onMessageReceived(participant, message) {
|
|
964
|
+
if (participant && message) {
|
|
965
|
+
const chatWindow = this.openChatWindow(participant);
|
|
966
|
+
this.assertMessageType(message);
|
|
967
|
+
if (!chatWindow[1] || !this.historyEnabled) {
|
|
968
|
+
chatWindow[0].messages.push(message);
|
|
969
|
+
this.scrollChatWindow(chatWindow[0], ScrollDirection.Bottom);
|
|
970
|
+
if (chatWindow[0].hasFocus) {
|
|
971
|
+
this.markMessagesAsRead([message]);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
this.emitMessageSound(chatWindow[0]);
|
|
975
|
+
// Do not push browser notifications with message content for privacy purposes if the 'maximizeWindowOnNewMessage' setting is off and this is a new chat window.
|
|
976
|
+
if (this.maximizeWindowOnNewMessage || (!chatWindow[1] && !chatWindow[0].isCollapsed)) {
|
|
977
|
+
// Some messages are not pushed because they are loaded by fetching the history hence why we supply the message here
|
|
978
|
+
this.emitBrowserNotification(chatWindow[0], message);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
onParticipantClickedFromFriendsList(participant) {
|
|
983
|
+
this.openChatWindow(participant, true, true);
|
|
984
|
+
}
|
|
985
|
+
cancelOptionPrompt() {
|
|
986
|
+
if (this.currentActiveOption) {
|
|
987
|
+
this.currentActiveOption.isActive = false;
|
|
988
|
+
this.currentActiveOption = null;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
onOptionPromptCanceled() {
|
|
992
|
+
this.cancelOptionPrompt();
|
|
993
|
+
}
|
|
994
|
+
onOptionPromptConfirmed(event) {
|
|
995
|
+
// For now this is fine as there is only one option available. Introduce option types and type checking if a new option is added.
|
|
996
|
+
this.confirmNewGroup(event);
|
|
997
|
+
// Canceling current state
|
|
998
|
+
this.cancelOptionPrompt();
|
|
999
|
+
}
|
|
1000
|
+
confirmNewGroup(users) {
|
|
1001
|
+
const newGroup = new Group(users);
|
|
1002
|
+
this.openChatWindow(newGroup);
|
|
1003
|
+
if (this.groupAdapter) {
|
|
1004
|
+
this.groupAdapter.groupCreated(newGroup);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
// Opens a new chat whindow. Takes care of available viewport
|
|
1008
|
+
// Works for opening a chat window for an user or for a group
|
|
1009
|
+
// Returns => [Window: Window object reference, boolean: Indicates if this window is a new chat window]
|
|
1010
|
+
openChatWindow(participant, focusOnNewWindow = false, invokedByUserClick = false) {
|
|
1011
|
+
// Is this window opened?
|
|
1012
|
+
const openedWindow = this.windows.find(x => x.participant.id == participant.id);
|
|
1013
|
+
if (!openedWindow) {
|
|
1014
|
+
if (invokedByUserClick) {
|
|
1015
|
+
this.onParticipantClicked.emit(participant);
|
|
1016
|
+
}
|
|
1017
|
+
// Refer to issue #58 on Github
|
|
1018
|
+
const collapseWindow = invokedByUserClick ? false : !this.maximizeWindowOnNewMessage;
|
|
1019
|
+
const newChatWindow = new Window(participant, this.historyEnabled, collapseWindow);
|
|
1020
|
+
// Loads the chat history via an RxJs Observable
|
|
1021
|
+
if (this.historyEnabled) {
|
|
1022
|
+
this.fetchMessageHistory(newChatWindow);
|
|
1023
|
+
}
|
|
1024
|
+
this.windows.unshift(newChatWindow);
|
|
1025
|
+
// Is there enough space left in the view port ? but should be displayed in mobile if option is enabled
|
|
1026
|
+
if (!this.isViewportOnMobileEnabled) {
|
|
1027
|
+
if (this.windows.length * this.windowSizeFactor >= this.viewPortTotalArea - (!this.hideFriendsList ? this.friendsListWidth : 0)) {
|
|
1028
|
+
this.windows.pop();
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
this.updateWindowsState(this.windows);
|
|
1032
|
+
if (focusOnNewWindow && !collapseWindow) {
|
|
1033
|
+
this.focusOnWindow(newChatWindow);
|
|
1034
|
+
}
|
|
1035
|
+
this.participantsInteractedWith.push(participant);
|
|
1036
|
+
this.onParticipantChatOpened.emit(participant);
|
|
1037
|
+
return [newChatWindow, true];
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
// Returns the existing chat window
|
|
1041
|
+
return [openedWindow, false];
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
// Focus on the input element of the supplied window
|
|
1045
|
+
focusOnWindow(window, callback = () => { }) {
|
|
1046
|
+
const windowIndex = this.windows.indexOf(window);
|
|
1047
|
+
if (windowIndex >= 0) {
|
|
1048
|
+
setTimeout(() => {
|
|
1049
|
+
if (this.chatWindows) {
|
|
1050
|
+
const chatWindowToFocus = this.chatWindows.toArray()[windowIndex];
|
|
1051
|
+
chatWindowToFocus.chatWindowInput.nativeElement.focus();
|
|
1052
|
+
}
|
|
1053
|
+
callback();
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
assertMessageType(message) {
|
|
1058
|
+
// Always fallback to "Text" messages to avoid rendenring issues
|
|
1059
|
+
if (!message.type) {
|
|
1060
|
+
message.type = MessageType.Text;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
// Marks all messages provided as read with the current time.
|
|
1064
|
+
markMessagesAsRead(messages) {
|
|
1065
|
+
const currentDate = new Date();
|
|
1066
|
+
messages.forEach((msg) => {
|
|
1067
|
+
msg.dateSeen = currentDate;
|
|
1068
|
+
});
|
|
1069
|
+
this.onMessagesSeen.emit(messages);
|
|
1070
|
+
}
|
|
1071
|
+
// Buffers audio file (For component's bootstrapping)
|
|
1072
|
+
bufferAudioFile() {
|
|
1073
|
+
if (this.audioSource && this.audioSource.length > 0) {
|
|
1074
|
+
this.audioFile = new Audio();
|
|
1075
|
+
this.audioFile.src = this.audioSource;
|
|
1076
|
+
this.audioFile.load();
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
// Emits a message notification audio if enabled after every message received
|
|
1080
|
+
emitMessageSound(window) {
|
|
1081
|
+
if (this.audioEnabled && !window.hasFocus && this.audioFile) {
|
|
1082
|
+
this.audioFile.play();
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
// Emits a browser notification
|
|
1086
|
+
emitBrowserNotification(window, message) {
|
|
1087
|
+
// if (this.browserNotificationsBootstrapped && !window.hasFocus && message) {
|
|
1088
|
+
if (this.browserNotificationsBootstrapped && message) {
|
|
1089
|
+
const notification = new Notification(`${this.localization.browserNotificationTitle} ${window.participant.displayName}`, {
|
|
1090
|
+
'body': message.message,
|
|
1091
|
+
'icon': this.browserNotificationIconSource
|
|
1092
|
+
});
|
|
1093
|
+
setTimeout(() => {
|
|
1094
|
+
notification.close();
|
|
1095
|
+
}, message.message.length <= 50 ? 5000 : 7000); // More time to read longer messages
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
// Saves current windows state into local storage if persistence is enabled
|
|
1099
|
+
updateWindowsState(windows) {
|
|
1100
|
+
if (this.persistWindowsState) {
|
|
1101
|
+
const participantIds = windows.map((w) => {
|
|
1102
|
+
return w.participant.id;
|
|
1103
|
+
});
|
|
1104
|
+
localStorage.setItem(this.localStorageKey, JSON.stringify(participantIds));
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
restoreWindowsState() {
|
|
1108
|
+
try {
|
|
1109
|
+
if (this.persistWindowsState) {
|
|
1110
|
+
const stringfiedParticipantIds = localStorage.getItem(this.localStorageKey);
|
|
1111
|
+
if (stringfiedParticipantIds && stringfiedParticipantIds.length > 0) {
|
|
1112
|
+
const participantIds = JSON.parse(stringfiedParticipantIds);
|
|
1113
|
+
const participantsToRestore = this.participants.filter(u => participantIds.indexOf(u.id) >= 0);
|
|
1114
|
+
participantsToRestore.forEach((participant) => {
|
|
1115
|
+
this.openChatWindow(participant);
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
catch (ex) {
|
|
1121
|
+
console.error(`An error occurred while restoring ng-chat windows state. Details: ${ex}`);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
// Gets closest open window if any. Most recent opened has priority (Right)
|
|
1125
|
+
getClosestWindow(window) {
|
|
1126
|
+
const index = this.windows.indexOf(window);
|
|
1127
|
+
if (index > 0) {
|
|
1128
|
+
return this.windows[index - 1];
|
|
1129
|
+
}
|
|
1130
|
+
else if (index == 0 && this.windows.length > 1) {
|
|
1131
|
+
return this.windows[index + 1];
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
closeWindow(window) {
|
|
1135
|
+
const index = this.windows.indexOf(window);
|
|
1136
|
+
this.windows.splice(index, 1);
|
|
1137
|
+
this.updateWindowsState(this.windows);
|
|
1138
|
+
this.onParticipantChatClosed.emit(window.participant);
|
|
1139
|
+
}
|
|
1140
|
+
getChatWindowComponentInstance(targetWindow) {
|
|
1141
|
+
const windowIndex = this.windows.indexOf(targetWindow);
|
|
1142
|
+
if (this.chatWindows) {
|
|
1143
|
+
let targetWindow = this.chatWindows.toArray()[windowIndex];
|
|
1144
|
+
return targetWindow;
|
|
1145
|
+
}
|
|
1146
|
+
return null;
|
|
1147
|
+
}
|
|
1148
|
+
// Scrolls a chat window message flow to the bottom
|
|
1149
|
+
scrollChatWindow(window, direction) {
|
|
1150
|
+
const chatWindow = this.getChatWindowComponentInstance(window);
|
|
1151
|
+
if (chatWindow) {
|
|
1152
|
+
chatWindow.scrollChatWindow(window, direction);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
onWindowMessagesSeen(messagesSeen) {
|
|
1156
|
+
this.markMessagesAsRead(messagesSeen);
|
|
1157
|
+
}
|
|
1158
|
+
onWindowChatClosed(payload) {
|
|
1159
|
+
const { closedWindow, closedViaEscapeKey } = payload;
|
|
1160
|
+
if (closedViaEscapeKey) {
|
|
1161
|
+
let closestWindow = this.getClosestWindow(closedWindow);
|
|
1162
|
+
if (closestWindow) {
|
|
1163
|
+
this.focusOnWindow(closestWindow, () => { this.closeWindow(closedWindow); });
|
|
1164
|
+
}
|
|
1165
|
+
else {
|
|
1166
|
+
this.closeWindow(closedWindow);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
else {
|
|
1170
|
+
this.closeWindow(closedWindow);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
onWindowTabTriggered(payload) {
|
|
1174
|
+
const { triggeringWindow, shiftKeyPressed } = payload;
|
|
1175
|
+
const currentWindowIndex = this.windows.indexOf(triggeringWindow);
|
|
1176
|
+
let windowToFocus = this.windows[currentWindowIndex + (shiftKeyPressed ? 1 : -1)]; // Goes back on shift + tab
|
|
1177
|
+
if (!windowToFocus) {
|
|
1178
|
+
// Edge windows, go to start or end
|
|
1179
|
+
windowToFocus = this.windows[currentWindowIndex > 0 ? 0 : this.chatWindows.length - 1];
|
|
1180
|
+
}
|
|
1181
|
+
this.focusOnWindow(windowToFocus);
|
|
1182
|
+
}
|
|
1183
|
+
onWindowMessageSent(messageSent) {
|
|
1184
|
+
this.adapter.sendMessage(messageSent);
|
|
1185
|
+
}
|
|
1186
|
+
onWindowOptionTriggered(option) {
|
|
1187
|
+
this.currentActiveOption = option;
|
|
1188
|
+
}
|
|
1189
|
+
triggerOpenChatWindow(user) {
|
|
1190
|
+
if (user) {
|
|
1191
|
+
this.openChatWindow(user);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
triggerCloseChatWindow(userId) {
|
|
1195
|
+
const openedWindow = this.windows.find(x => x.participant.id == userId);
|
|
1196
|
+
if (openedWindow) {
|
|
1197
|
+
this.closeWindow(openedWindow);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
triggerToggleChatWindowVisibility(userId) {
|
|
1201
|
+
const openedWindow = this.windows.find(x => x.participant.id == userId);
|
|
1202
|
+
if (openedWindow) {
|
|
1203
|
+
const chatWindow = this.getChatWindowComponentInstance(openedWindow);
|
|
1204
|
+
if (chatWindow) {
|
|
1205
|
+
chatWindow.onChatWindowClicked(openedWindow);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
// closeFriendList(){
|
|
1210
|
+
// this.hideFriendsList = !this.hideFriendsList
|
|
1211
|
+
// this.hideFriendsListChange.emit(this.hideFriendsList)
|
|
1212
|
+
// }
|
|
1213
|
+
onCloseWindowClick(click) {
|
|
1214
|
+
this.onCloseWindowClicked.emit(click);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
NgChat.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChat, deps: [{ token: i1$2.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
|
|
1218
|
+
NgChat.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgChat, selector: "mnl-chat", inputs: { isDisabled: "isDisabled", adapter: "adapter", groupAdapter: "groupAdapter", userId: "userId", isCollapsed: "isCollapsed", maximizeWindowOnNewMessage: "maximizeWindowOnNewMessage", pollFriendsList: "pollFriendsList", pollingInterval: "pollingInterval", historyEnabled: "historyEnabled", emojisEnabled: "emojisEnabled", linkfyEnabled: "linkfyEnabled", audioEnabled: "audioEnabled", searchEnabled: "searchEnabled", audioSource: "audioSource", persistWindowsState: "persistWindowsState", title: "title", messagePlaceholder: "messagePlaceholder", searchPlaceholder: "searchPlaceholder", browserNotificationsEnabled: "browserNotificationsEnabled", browserNotificationIconSource: "browserNotificationIconSource", browserNotificationTitle: "browserNotificationTitle", historyPageSize: "historyPageSize", localization: "localization", hideFriendsList: "hideFriendsList", hideFriendsListOnUnsupportedViewport: "hideFriendsListOnUnsupportedViewport", fileUploadUrl: "fileUploadUrl", theme: "theme", customTheme: "customTheme", messageDatePipeFormat: "messageDatePipeFormat", showMessageDate: "showMessageDate", isViewportOnMobileEnabled: "isViewportOnMobileEnabled", fileUploadAdapter: "fileUploadAdapter" }, outputs: { onParticipantClicked: "onParticipantClicked", onParticipantChatOpened: "onParticipantChatOpened", onParticipantChatClosed: "onParticipantChatClosed", onMessagesSeen: "onMessagesSeen", onCloseWindowClicked: "onCloseWindowClicked" }, host: { listeners: { "window:resize": "onResize($event)" } }, viewQueries: [{ propertyName: "chatWindows", predicate: ["chatWindow"], descendants: true }], ngImport: i0, template: "<link *ngIf=\"customTheme\" rel=\"stylesheet\" [href]='customTheme | sanitize'>\n\n<div id=\"ng-chat\" *ngIf=\"!isDisabled && isBootstrapped && !unsupportedViewport\" [ngClass]=\"theme\">\n <ng-chat-friends-list\n [localization]=\"localization\"\n [shouldDisplay]=\"!hideFriendsList\"\n [userId]=\"userId\"\n [isCollapsed]=\"isCollapsed\"\n [searchEnabled]=\"searchEnabled\"\n [participants]=\"participants\"\n [participantsResponse]=\"participantsResponse\"\n [participantsInteractedWith]=\"participantsInteractedWith\"\n [windows]=\"windows\"\n [currentActiveOption]=\"currentActiveOption\"\n (onParticipantClicked)=\"onParticipantClickedFromFriendsList($event)\"\n (onOptionPromptCanceled)=\"onOptionPromptCanceled()\"\n (onOptionPromptConfirmed)=\"onOptionPromptConfirmed($event)\"\n (onCloseWindowClick)=\"onCloseWindowClick($event)\"\n >\n </ng-chat-friends-list>\n\n <div *ngFor=\"let window of windows; let i = index\" [ngClass]=\"{'ng-chat-window': true, 'primary-outline-color': true, 'ng-chat-window-collapsed': window.isCollapsed}\" [ngStyle]=\"{'right': (!hideFriendsList ? friendsListWidth : 0) + 20 + windowSizeFactor * i + 'px'}\">\n <ng-chat-window\n #chatWindow\n [fileUploadAdapter]=\"fileUploadAdapter\"\n [localization]=\"localization\"\n [userId]=\"userId\"\n [window]=\"window\"\n [showOptions]=\"groupAdapter\"\n [emojisEnabled]=\"emojisEnabled\"\n [linkfyEnabled]=\"linkfyEnabled\"\n [showMessageDate]=\"showMessageDate\"\n [messageDatePipeFormat]=\"messageDatePipeFormat\"\n [hasPagedHistory]=\"hasPagedHistory\"\n (onMessagesSeen)=\"onWindowMessagesSeen($event)\"\n (onMessageSent)=\"onWindowMessageSent($event)\"\n (onTabTriggered)=\"onWindowTabTriggered($event)\"\n (onChatWindowClosed)=\"onWindowChatClosed($event)\"\n (onOptionTriggered)=\"onWindowOptionTriggered($event)\"\n (onLoadHistoryTriggered)=\"fetchMessageHistory($event)\"\n >\n </ng-chat-window>\n </div>\n</div>\n", styles: [".user-icon{box-sizing:border-box;background-color:#fff;border:2px solid;width:32px;height:20px;border-radius:64px 64px 0 0/64px;margin-top:14px;margin-left:-1px;display:inline-block;vertical-align:middle;position:relative;font-style:normal;color:#ddd;text-align:left;text-indent:-9999px}.user-icon:before{border:2px solid;background-color:#fff;width:12px;height:12px;top:-19px;border-radius:50%;position:absolute;left:50%;transform:translate(-50%)}.user-icon:before,.user-icon:after{content:\"\";pointer-events:none}.upload-icon{position:absolute;margin-left:3px;margin-top:12px;width:13px;height:4px;border:solid 1px currentColor;border-top:none;border-radius:1px}.upload-icon:before{content:\"\";position:absolute;top:-8px;left:6px;width:1px;height:9px;background-color:currentColor}.upload-icon:after{content:\"\";position:absolute;top:-8px;left:4px;width:4px;height:4px;border-top:solid 1px currentColor;border-right:solid 1px currentColor;transform:rotate(-45deg)}.paperclip-icon{position:absolute;margin-left:9px;margin-top:2px;width:6px;height:12px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor;transform:rotate(45deg)}.paperclip-icon:before{content:\"\";position:absolute;top:11px;left:-1px;width:4px;height:6px;border-radius:0 0 3px 3px;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-bottom:solid 1px currentColor}.paperclip-icon:after{content:\"\";position:absolute;left:1px;top:1px;width:2px;height:10px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor}.check-icon{color:#000;position:absolute;margin-left:3px;margin-top:4px;width:14px;height:8px;border-bottom:solid 1px currentColor;border-left:solid 1px currentColor;transform:rotate(-45deg)}.remove-icon{color:#000;position:absolute;margin-left:3px;margin-top:10px}.remove-icon:before{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(45deg)}.remove-icon:after{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(-45deg)}\n", ".loader,.loader:before,.loader:after{background:#E3E3E3;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#e3e3e3;text-indent:-9999em;margin:4px auto 0;position:relative;font-size:4px;transform:translateZ(0);animation-delay:-.16s}.loader:before,.loader:after{position:absolute;top:0;content:\"\"}.loader:before{left:-1.5em;animation-delay:-.32s}.loader:after{left:1.5em}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", "#ng-chat{position:fixed;z-index:999;right:0;bottom:0;box-sizing:initial;font-size:11pt;text-align:left}#ng-chat input{outline:none}#ng-chat .shadowed{box-shadow:0 4px 8px #00000040}.ng-chat-loading-wrapper{height:30px;text-align:center;font-size:.9em}.ng-chat-close{text-decoration:none!important;color:red!important;float:right!important;font-weight:900!important;font-size:15px!important}.ng-chat-title,.ng-chat-title:hover{position:relative;z-index:2;height:30px;line-height:30px;font-size:.9em;padding:0 10px;display:block;text-decoration:none;color:#fff!important;font-weight:600!important;cursor:pointer;background-color:#1b1b70!important}.ng-chat-title .ng-chat-title-visibility-toggle-area{display:inline-block;width:85%}.ng-chat-title .ng-chat-title-visibility-toggle-area>strong{font-weight:600;display:block;overflow:hidden;height:30px;text-overflow:ellipsis;white-space:nowrap;max-width:85%;float:left}.ng-chat-title .ng-chat-title-visibility-toggle-area .ng-chat-participant-status{float:left;margin-left:5px}.ng-chat-participant-status{display:inline-block;border-radius:25px;width:8px;height:8px;margin-top:10px}.ng-chat-participant-status.online{background-color:#92a400}.ng-chat-participant-status.busy{background-color:#f91c1e}.ng-chat-participant-status.away{background-color:#f7d21b}.ng-chat-participant-status.offline{background-color:#bababa}.ng-chat-unread-messages-count{margin-left:5px;padding:0 5px;border-radius:25px;font-size:.9em;line-height:30px}.ng-chat-options-container{float:right;margin-right:5px}\n", "#ng-chat.light-theme .primary-text,#ng-chat.light-theme{color:#5c5c5c;font-family:Arial,Helvetica,sans-serif}#ng-chat.light-theme .primary-background{background-color:#fff}#ng-chat.light-theme .secondary-background{background-color:#fafafa}#ng-chat.light-theme .primary-outline-color{border-color:#a3a3a3}#ng-chat.light-theme .friends-search-bar{background-color:#fff}#ng-chat.light-theme .unread-messages-counter-container,#ng-chat.light-theme .ng-chat-people-action,#ng-chat.light-theme .ng-chat-people-action>i{color:#5c5c5c;background-color:#e3e3e3}#ng-chat.light-theme .load-history-action{background-color:#e3e3e3}#ng-chat.light-theme .chat-window-input{background-color:#fff}#ng-chat.light-theme .sent-chat-message-container,#ng-chat.light-theme .file-message-container{background-color:#e3e3e3;border-color:#e3e3e3}#ng-chat.light-theme .received-chat-message-container,#ng-chat.light-theme .file-message-container.received{background-color:#fff;border-color:#e3e3e3}body{font-family:Roboto,Helvetica Neue,sans-serif!important}*{box-shadow:none!important}\n", "#ng-chat.dark-theme .primary-text,#ng-chat.dark-theme{color:#fff;font-family:Arial,Helvetica,sans-serif}#ng-chat.dark-theme .primary-background{background-color:#565656}#ng-chat.dark-theme .secondary-background{background-color:#444}#ng-chat.dark-theme .primary-outline-color{border-color:#353535}#ng-chat.dark-theme .friends-search-bar{background-color:#444;border:1px solid #444;color:#fff}#ng-chat.dark-theme .unread-messages-counter-container,#ng-chat.dark-theme .ng-chat-people-action,#ng-chat.dark-theme .ng-chat-people-action>i{background-color:#fff;color:#444}#ng-chat.dark-theme .load-history-action{background-color:#444}#ng-chat.dark-theme .chat-window-input{background-color:#444;color:#fff}#ng-chat.dark-theme .sent-chat-message-container,#ng-chat.dark-theme .file-message-container{border-color:#444;background-color:#444}#ng-chat.dark-theme .received-chat-message-container,#ng-chat.dark-theme .file-message-container.received{background-color:#565656;border-color:#444}#ng-chat.dark-theme .ng-chat-footer{background-color:#444}#ng-chat.dark-theme .ng-chat-message a{color:#fff}body{font-family:Roboto,Helvetica Neue,sans-serif!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: NgChatFriendsListComponent, selector: "ng-chat-friends-list", inputs: ["participants", "participantsResponse", "participantsInteractedWith", "windows", "userId", "localization", "shouldDisplay", "isCollapsed", "searchEnabled", "currentActiveOption", "hideFriendsList"], outputs: ["onParticipantClicked", "onOptionPromptCanceled", "onOptionPromptConfirmed", "onCloseWindowClick"] }, { kind: "component", type: NgChatWindowComponent, selector: "ng-chat-window", inputs: ["fileUploadAdapter", "window", "userId", "localization", "showOptions", "emojisEnabled", "linkfyEnabled", "showMessageDate", "messageDatePipeFormat", "hasPagedHistory"], outputs: ["onChatWindowClosed", "onMessagesSeen", "onMessageSent", "onTabTriggered", "onOptionTriggered", "onLoadHistoryTriggered"] }, { kind: "pipe", type: SanitizePipe, name: "sanitize" }], encapsulation: i0.ViewEncapsulation.None });
|
|
1219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChat, decorators: [{
|
|
1220
|
+
type: Component,
|
|
1221
|
+
args: [{ selector: 'mnl-chat', encapsulation: ViewEncapsulation.None, template: "<link *ngIf=\"customTheme\" rel=\"stylesheet\" [href]='customTheme | sanitize'>\n\n<div id=\"ng-chat\" *ngIf=\"!isDisabled && isBootstrapped && !unsupportedViewport\" [ngClass]=\"theme\">\n <ng-chat-friends-list\n [localization]=\"localization\"\n [shouldDisplay]=\"!hideFriendsList\"\n [userId]=\"userId\"\n [isCollapsed]=\"isCollapsed\"\n [searchEnabled]=\"searchEnabled\"\n [participants]=\"participants\"\n [participantsResponse]=\"participantsResponse\"\n [participantsInteractedWith]=\"participantsInteractedWith\"\n [windows]=\"windows\"\n [currentActiveOption]=\"currentActiveOption\"\n (onParticipantClicked)=\"onParticipantClickedFromFriendsList($event)\"\n (onOptionPromptCanceled)=\"onOptionPromptCanceled()\"\n (onOptionPromptConfirmed)=\"onOptionPromptConfirmed($event)\"\n (onCloseWindowClick)=\"onCloseWindowClick($event)\"\n >\n </ng-chat-friends-list>\n\n <div *ngFor=\"let window of windows; let i = index\" [ngClass]=\"{'ng-chat-window': true, 'primary-outline-color': true, 'ng-chat-window-collapsed': window.isCollapsed}\" [ngStyle]=\"{'right': (!hideFriendsList ? friendsListWidth : 0) + 20 + windowSizeFactor * i + 'px'}\">\n <ng-chat-window\n #chatWindow\n [fileUploadAdapter]=\"fileUploadAdapter\"\n [localization]=\"localization\"\n [userId]=\"userId\"\n [window]=\"window\"\n [showOptions]=\"groupAdapter\"\n [emojisEnabled]=\"emojisEnabled\"\n [linkfyEnabled]=\"linkfyEnabled\"\n [showMessageDate]=\"showMessageDate\"\n [messageDatePipeFormat]=\"messageDatePipeFormat\"\n [hasPagedHistory]=\"hasPagedHistory\"\n (onMessagesSeen)=\"onWindowMessagesSeen($event)\"\n (onMessageSent)=\"onWindowMessageSent($event)\"\n (onTabTriggered)=\"onWindowTabTriggered($event)\"\n (onChatWindowClosed)=\"onWindowChatClosed($event)\"\n (onOptionTriggered)=\"onWindowOptionTriggered($event)\"\n (onLoadHistoryTriggered)=\"fetchMessageHistory($event)\"\n >\n </ng-chat-window>\n </div>\n</div>\n", styles: [".user-icon{box-sizing:border-box;background-color:#fff;border:2px solid;width:32px;height:20px;border-radius:64px 64px 0 0/64px;margin-top:14px;margin-left:-1px;display:inline-block;vertical-align:middle;position:relative;font-style:normal;color:#ddd;text-align:left;text-indent:-9999px}.user-icon:before{border:2px solid;background-color:#fff;width:12px;height:12px;top:-19px;border-radius:50%;position:absolute;left:50%;transform:translate(-50%)}.user-icon:before,.user-icon:after{content:\"\";pointer-events:none}.upload-icon{position:absolute;margin-left:3px;margin-top:12px;width:13px;height:4px;border:solid 1px currentColor;border-top:none;border-radius:1px}.upload-icon:before{content:\"\";position:absolute;top:-8px;left:6px;width:1px;height:9px;background-color:currentColor}.upload-icon:after{content:\"\";position:absolute;top:-8px;left:4px;width:4px;height:4px;border-top:solid 1px currentColor;border-right:solid 1px currentColor;transform:rotate(-45deg)}.paperclip-icon{position:absolute;margin-left:9px;margin-top:2px;width:6px;height:12px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor;transform:rotate(45deg)}.paperclip-icon:before{content:\"\";position:absolute;top:11px;left:-1px;width:4px;height:6px;border-radius:0 0 3px 3px;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-bottom:solid 1px currentColor}.paperclip-icon:after{content:\"\";position:absolute;left:1px;top:1px;width:2px;height:10px;border-radius:4px 4px 0 0;border-left:solid 1px currentColor;border-right:solid 1px currentColor;border-top:solid 1px currentColor}.check-icon{color:#000;position:absolute;margin-left:3px;margin-top:4px;width:14px;height:8px;border-bottom:solid 1px currentColor;border-left:solid 1px currentColor;transform:rotate(-45deg)}.remove-icon{color:#000;position:absolute;margin-left:3px;margin-top:10px}.remove-icon:before{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(45deg)}.remove-icon:after{content:\"\";position:absolute;width:15px;height:1px;background-color:currentColor;transform:rotate(-45deg)}\n", ".loader,.loader:before,.loader:after{background:#E3E3E3;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader{color:#e3e3e3;text-indent:-9999em;margin:4px auto 0;position:relative;font-size:4px;transform:translateZ(0);animation-delay:-.16s}.loader:before,.loader:after{position:absolute;top:0;content:\"\"}.loader:before{left:-1.5em;animation-delay:-.32s}.loader:after{left:1.5em}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", "#ng-chat{position:fixed;z-index:999;right:0;bottom:0;box-sizing:initial;font-size:11pt;text-align:left}#ng-chat input{outline:none}#ng-chat .shadowed{box-shadow:0 4px 8px #00000040}.ng-chat-loading-wrapper{height:30px;text-align:center;font-size:.9em}.ng-chat-close{text-decoration:none!important;color:red!important;float:right!important;font-weight:900!important;font-size:15px!important}.ng-chat-title,.ng-chat-title:hover{position:relative;z-index:2;height:30px;line-height:30px;font-size:.9em;padding:0 10px;display:block;text-decoration:none;color:#fff!important;font-weight:600!important;cursor:pointer;background-color:#1b1b70!important}.ng-chat-title .ng-chat-title-visibility-toggle-area{display:inline-block;width:85%}.ng-chat-title .ng-chat-title-visibility-toggle-area>strong{font-weight:600;display:block;overflow:hidden;height:30px;text-overflow:ellipsis;white-space:nowrap;max-width:85%;float:left}.ng-chat-title .ng-chat-title-visibility-toggle-area .ng-chat-participant-status{float:left;margin-left:5px}.ng-chat-participant-status{display:inline-block;border-radius:25px;width:8px;height:8px;margin-top:10px}.ng-chat-participant-status.online{background-color:#92a400}.ng-chat-participant-status.busy{background-color:#f91c1e}.ng-chat-participant-status.away{background-color:#f7d21b}.ng-chat-participant-status.offline{background-color:#bababa}.ng-chat-unread-messages-count{margin-left:5px;padding:0 5px;border-radius:25px;font-size:.9em;line-height:30px}.ng-chat-options-container{float:right;margin-right:5px}\n", "#ng-chat.light-theme .primary-text,#ng-chat.light-theme{color:#5c5c5c;font-family:Arial,Helvetica,sans-serif}#ng-chat.light-theme .primary-background{background-color:#fff}#ng-chat.light-theme .secondary-background{background-color:#fafafa}#ng-chat.light-theme .primary-outline-color{border-color:#a3a3a3}#ng-chat.light-theme .friends-search-bar{background-color:#fff}#ng-chat.light-theme .unread-messages-counter-container,#ng-chat.light-theme .ng-chat-people-action,#ng-chat.light-theme .ng-chat-people-action>i{color:#5c5c5c;background-color:#e3e3e3}#ng-chat.light-theme .load-history-action{background-color:#e3e3e3}#ng-chat.light-theme .chat-window-input{background-color:#fff}#ng-chat.light-theme .sent-chat-message-container,#ng-chat.light-theme .file-message-container{background-color:#e3e3e3;border-color:#e3e3e3}#ng-chat.light-theme .received-chat-message-container,#ng-chat.light-theme .file-message-container.received{background-color:#fff;border-color:#e3e3e3}body{font-family:Roboto,Helvetica Neue,sans-serif!important}*{box-shadow:none!important}\n", "#ng-chat.dark-theme .primary-text,#ng-chat.dark-theme{color:#fff;font-family:Arial,Helvetica,sans-serif}#ng-chat.dark-theme .primary-background{background-color:#565656}#ng-chat.dark-theme .secondary-background{background-color:#444}#ng-chat.dark-theme .primary-outline-color{border-color:#353535}#ng-chat.dark-theme .friends-search-bar{background-color:#444;border:1px solid #444;color:#fff}#ng-chat.dark-theme .unread-messages-counter-container,#ng-chat.dark-theme .ng-chat-people-action,#ng-chat.dark-theme .ng-chat-people-action>i{background-color:#fff;color:#444}#ng-chat.dark-theme .load-history-action{background-color:#444}#ng-chat.dark-theme .chat-window-input{background-color:#444;color:#fff}#ng-chat.dark-theme .sent-chat-message-container,#ng-chat.dark-theme .file-message-container{border-color:#444;background-color:#444}#ng-chat.dark-theme .received-chat-message-container,#ng-chat.dark-theme .file-message-container.received{background-color:#565656;border-color:#444}#ng-chat.dark-theme .ng-chat-footer{background-color:#444}#ng-chat.dark-theme .ng-chat-message a{color:#fff}body{font-family:Roboto,Helvetica Neue,sans-serif!important}\n"] }]
|
|
1222
|
+
}], ctorParameters: function () { return [{ type: i1$2.HttpClient }]; }, propDecorators: { isDisabled: [{
|
|
1223
|
+
type: Input
|
|
1224
|
+
}], adapter: [{
|
|
1225
|
+
type: Input
|
|
1226
|
+
}], groupAdapter: [{
|
|
1227
|
+
type: Input
|
|
1228
|
+
}], userId: [{
|
|
1229
|
+
type: Input
|
|
1230
|
+
}], isCollapsed: [{
|
|
1231
|
+
type: Input
|
|
1232
|
+
}], maximizeWindowOnNewMessage: [{
|
|
1233
|
+
type: Input
|
|
1234
|
+
}], pollFriendsList: [{
|
|
1235
|
+
type: Input
|
|
1236
|
+
}], pollingInterval: [{
|
|
1237
|
+
type: Input
|
|
1238
|
+
}], historyEnabled: [{
|
|
1239
|
+
type: Input
|
|
1240
|
+
}], emojisEnabled: [{
|
|
1241
|
+
type: Input
|
|
1242
|
+
}], linkfyEnabled: [{
|
|
1243
|
+
type: Input
|
|
1244
|
+
}], audioEnabled: [{
|
|
1245
|
+
type: Input
|
|
1246
|
+
}], searchEnabled: [{
|
|
1247
|
+
type: Input
|
|
1248
|
+
}], audioSource: [{
|
|
1249
|
+
type: Input
|
|
1250
|
+
}], persistWindowsState: [{
|
|
1251
|
+
type: Input
|
|
1252
|
+
}], title: [{
|
|
1253
|
+
type: Input
|
|
1254
|
+
}], messagePlaceholder: [{
|
|
1255
|
+
type: Input
|
|
1256
|
+
}], searchPlaceholder: [{
|
|
1257
|
+
type: Input
|
|
1258
|
+
}], browserNotificationsEnabled: [{
|
|
1259
|
+
type: Input
|
|
1260
|
+
}], browserNotificationIconSource: [{
|
|
1261
|
+
type: Input
|
|
1262
|
+
}], browserNotificationTitle: [{
|
|
1263
|
+
type: Input
|
|
1264
|
+
}], historyPageSize: [{
|
|
1265
|
+
type: Input
|
|
1266
|
+
}], localization: [{
|
|
1267
|
+
type: Input
|
|
1268
|
+
}], hideFriendsList: [{
|
|
1269
|
+
type: Input
|
|
1270
|
+
}], hideFriendsListOnUnsupportedViewport: [{
|
|
1271
|
+
type: Input
|
|
1272
|
+
}], fileUploadUrl: [{
|
|
1273
|
+
type: Input
|
|
1274
|
+
}], theme: [{
|
|
1275
|
+
type: Input
|
|
1276
|
+
}], customTheme: [{
|
|
1277
|
+
type: Input
|
|
1278
|
+
}], messageDatePipeFormat: [{
|
|
1279
|
+
type: Input
|
|
1280
|
+
}], showMessageDate: [{
|
|
1281
|
+
type: Input
|
|
1282
|
+
}], isViewportOnMobileEnabled: [{
|
|
1283
|
+
type: Input
|
|
1284
|
+
}], fileUploadAdapter: [{
|
|
1285
|
+
type: Input
|
|
1286
|
+
}], onParticipantClicked: [{
|
|
1287
|
+
type: Output
|
|
1288
|
+
}], onParticipantChatOpened: [{
|
|
1289
|
+
type: Output
|
|
1290
|
+
}], onParticipantChatClosed: [{
|
|
1291
|
+
type: Output
|
|
1292
|
+
}], onMessagesSeen: [{
|
|
1293
|
+
type: Output
|
|
1294
|
+
}], onCloseWindowClicked: [{
|
|
1295
|
+
type: Output
|
|
1296
|
+
}], chatWindows: [{
|
|
1297
|
+
type: ViewChildren,
|
|
1298
|
+
args: ['chatWindow']
|
|
1299
|
+
}], onResize: [{
|
|
1300
|
+
type: HostListener,
|
|
1301
|
+
args: ['window:resize', ['$event']]
|
|
1302
|
+
}] } });
|
|
1303
|
+
|
|
1304
|
+
/* eslint-disable */
|
|
1305
|
+
class NgChatOptionsComponent {
|
|
1306
|
+
constructor() {
|
|
1307
|
+
this.activeOptionTrackerChange = new EventEmitter();
|
|
1308
|
+
}
|
|
1309
|
+
onOptionClicked(option) {
|
|
1310
|
+
option.isActive = true;
|
|
1311
|
+
if (option.action) {
|
|
1312
|
+
option.action(option.chattingTo);
|
|
1313
|
+
}
|
|
1314
|
+
this.activeOptionTrackerChange.emit(option);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
NgChatOptionsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1318
|
+
NgChatOptionsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgChatOptionsComponent, selector: "ng-chat-options", inputs: { options: "options", activeOptionTracker: "activeOptionTracker" }, outputs: { activeOptionTrackerChange: "activeOptionTrackerChange" }, ngImport: i0, template: "<div *ngIf=\"options && options.length > 0\" class=\"ng-chat-options\">\n\t\t<button class=\"ng-chat-options-activator\">\n\t\t\t<span class=\"primary-text\">...</span>\n\t\t</button>\n\t<div class=\"ng-chat-options-content primary-background shadowed\">\n\t\t<a *ngFor=\"let option of options; let i = index\" [ngClass]=\"'primary-text'\" (click)=\"onOptionClicked(option)\">\n\t\t\t{{option.displayLabel}}\n\t\t</a>\n\t</div> \n</div>\n", styles: [".ng-chat-options-activator{background-color:unset;color:#fff;line-height:28px;border:none;position:relative}.ng-chat-options-activator>span{position:relative;top:-5px;left:0}.ng-chat-options{position:relative;display:inline-block}.ng-chat-options:hover .ng-chat-options-content{display:block}.ng-chat-options:hover .ng-chat-options-activator{background-color:#ddd}.ng-chat-options-content{display:none;position:absolute;min-width:160px;z-index:1}.ng-chat-options-content a:hover{background-color:#ddd}.ng-chat-options-content a{padding:6px 16px;text-decoration:none;display:block}@media only screen and (max-width: 581px){.ng-chat-options-content{right:0}}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
1319
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgChatOptionsComponent, decorators: [{
|
|
1320
|
+
type: Component,
|
|
1321
|
+
args: [{ selector: 'ng-chat-options', template: "<div *ngIf=\"options && options.length > 0\" class=\"ng-chat-options\">\n\t\t<button class=\"ng-chat-options-activator\">\n\t\t\t<span class=\"primary-text\">...</span>\n\t\t</button>\n\t<div class=\"ng-chat-options-content primary-background shadowed\">\n\t\t<a *ngFor=\"let option of options; let i = index\" [ngClass]=\"'primary-text'\" (click)=\"onOptionClicked(option)\">\n\t\t\t{{option.displayLabel}}\n\t\t</a>\n\t</div> \n</div>\n", styles: [".ng-chat-options-activator{background-color:unset;color:#fff;line-height:28px;border:none;position:relative}.ng-chat-options-activator>span{position:relative;top:-5px;left:0}.ng-chat-options{position:relative;display:inline-block}.ng-chat-options:hover .ng-chat-options-content{display:block}.ng-chat-options:hover .ng-chat-options-activator{background-color:#ddd}.ng-chat-options-content{display:none;position:absolute;min-width:160px;z-index:1}.ng-chat-options-content a:hover{background-color:#ddd}.ng-chat-options-content a{padding:6px 16px;text-decoration:none;display:block}@media only screen and (max-width: 581px){.ng-chat-options-content{right:0}}\n"] }]
|
|
1322
|
+
}], ctorParameters: function () { return []; }, propDecorators: { options: [{
|
|
1323
|
+
type: Input
|
|
1324
|
+
}], activeOptionTracker: [{
|
|
1325
|
+
type: Input
|
|
1326
|
+
}], activeOptionTrackerChange: [{
|
|
1327
|
+
type: Output
|
|
1328
|
+
}] } });
|
|
1329
|
+
|
|
1330
|
+
class ChatModule {
|
|
1331
|
+
static forRoot() {
|
|
1332
|
+
return {
|
|
1333
|
+
ngModule: ChatModule,
|
|
1334
|
+
providers: [
|
|
1335
|
+
{
|
|
1336
|
+
provide: APP_INITIALIZER,
|
|
1337
|
+
useFactory: loadConfig,
|
|
1338
|
+
deps: [
|
|
1339
|
+
AppConfigService,
|
|
1340
|
+
ChatService
|
|
1341
|
+
],
|
|
1342
|
+
multi: true,
|
|
1343
|
+
},
|
|
1344
|
+
],
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
static forChild() {
|
|
1348
|
+
return {
|
|
1349
|
+
ngModule: ChatModule,
|
|
1350
|
+
};
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
ChatModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1354
|
+
ChatModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: ChatModule, declarations: [NgChat,
|
|
1355
|
+
EmojifyPipe,
|
|
1356
|
+
LinkfyPipe,
|
|
1357
|
+
SanitizePipe,
|
|
1358
|
+
GroupMessageDisplayNamePipe,
|
|
1359
|
+
NgChatOptionsComponent,
|
|
1360
|
+
NgChatFriendsListComponent,
|
|
1361
|
+
NgChatWindowComponent,
|
|
1362
|
+
FirstLetterPipe], imports: [ChatMaterialModule,
|
|
1363
|
+
CommonModule,
|
|
1364
|
+
FormsModule,
|
|
1365
|
+
HttpClientModule], exports: [NgChat] });
|
|
1366
|
+
ChatModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatModule, imports: [ChatMaterialModule,
|
|
1367
|
+
CommonModule,
|
|
1368
|
+
FormsModule,
|
|
1369
|
+
HttpClientModule] });
|
|
1370
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ChatModule, decorators: [{
|
|
1371
|
+
type: NgModule,
|
|
1372
|
+
args: [{
|
|
1373
|
+
declarations: [
|
|
1374
|
+
NgChat,
|
|
1375
|
+
EmojifyPipe,
|
|
1376
|
+
LinkfyPipe,
|
|
1377
|
+
SanitizePipe,
|
|
1378
|
+
GroupMessageDisplayNamePipe,
|
|
1379
|
+
NgChatOptionsComponent,
|
|
1380
|
+
NgChatFriendsListComponent,
|
|
1381
|
+
NgChatWindowComponent,
|
|
1382
|
+
FirstLetterPipe
|
|
1383
|
+
],
|
|
1384
|
+
imports: [
|
|
1385
|
+
ChatMaterialModule,
|
|
1386
|
+
CommonModule,
|
|
1387
|
+
FormsModule,
|
|
1388
|
+
HttpClientModule
|
|
1389
|
+
],
|
|
1390
|
+
exports: [
|
|
1391
|
+
NgChat
|
|
1392
|
+
],
|
|
1393
|
+
}]
|
|
1394
|
+
}] });
|
|
1395
|
+
function loadConfig(config) {
|
|
1396
|
+
const conf = () => config.load();
|
|
1397
|
+
return conf;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
class User {
|
|
1401
|
+
constructor() {
|
|
1402
|
+
this.participantType = ChatParticipantType.User;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
class ParticipantResponse {
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
class ParticipantMetadata {
|
|
1410
|
+
constructor() {
|
|
1411
|
+
this.totalUnreadMessages = 0;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
/*
|
|
1416
|
+
* Public API Surface of mnl-chat
|
|
1417
|
+
*/
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* Generated bundle index. Do not edit.
|
|
1421
|
+
*/
|
|
1422
|
+
|
|
1423
|
+
export { ChatAdapter, ChatModule, ChatParticipantStatus, ChatParticipantType, ChatService, Group, Message, MessageType, NgChat, PagedHistoryChatAdapter, ParticipantMetadata, ParticipantResponse, Theme, User, Window, loadConfig };
|
|
1424
|
+
//# sourceMappingURL=muraai-mnl-chat.mjs.map
|