@muraai/mnl-chat 0.0.1-alpha-82b7eb9 → 0.0.1-alpha-3a3a286

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