stream-chat-angular 4.4.0 → 4.5.0

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 (34) hide show
  1. package/assets/i18n/en.d.ts +2 -0
  2. package/assets/version.d.ts +1 -1
  3. package/bundles/stream-chat-angular.umd.js +106 -23
  4. package/bundles/stream-chat-angular.umd.js.map +1 -1
  5. package/esm2015/assets/i18n/en.js +3 -1
  6. package/esm2015/assets/version.js +2 -2
  7. package/esm2015/lib/channel-preview/channel-preview.component.js +4 -2
  8. package/esm2015/lib/channel.service.js +23 -7
  9. package/esm2015/lib/get-message-translation.js +13 -0
  10. package/esm2015/lib/message/message.component.js +64 -16
  11. package/esm2015/lib/message-input/message-input.component.js +2 -2
  12. package/esm2015/lib/types.js +1 -1
  13. package/fesm2015/stream-chat-angular.js +103 -24
  14. package/fesm2015/stream-chat-angular.js.map +1 -1
  15. package/lib/get-message-translation.d.ts +3 -0
  16. package/lib/message/message.component.d.ts +7 -0
  17. package/lib/types.d.ts +3 -1
  18. package/package.json +1 -1
  19. package/src/assets/i18n/en.ts +3 -0
  20. package/src/assets/styles/css/index.css +1 -1
  21. package/src/assets/styles/css/index.css.map +1 -1
  22. package/src/assets/styles/scss/Attachment.scss +6 -2
  23. package/src/assets/styles/scss/Message.scss +18 -0
  24. package/src/assets/styles/v2/css/index.css +1 -1
  25. package/src/assets/styles/v2/css/index.css.map +1 -1
  26. package/src/assets/styles/v2/css/index.layout.css +1 -1
  27. package/src/assets/styles/v2/css/index.layout.css.map +1 -1
  28. package/src/assets/styles/v2/scss/AttachmentList/AttachmentList-layout.scss +16 -7
  29. package/src/assets/styles/v2/scss/Autocomplete/Autocomplete-layout.scss +2 -0
  30. package/src/assets/styles/v2/scss/Message/Message-layout.scss +12 -0
  31. package/src/assets/styles/v2/scss/Message/Message-theme.scss +20 -0
  32. package/src/assets/styles/v2/scss/index.scss +1 -1
  33. package/src/assets/styles/v2/scss/vendor/react-image-gallery.scss +232 -0
  34. package/src/assets/version.ts +1 -1
@@ -19,7 +19,7 @@ import transliterate from '@stream-io/transliterate';
19
19
  import * as i8 from 'angular-mentions';
20
20
  import { MentionModule } from 'angular-mentions';
21
21
 
22
- const version = '4.4.0';
22
+ const version = '4.5.0';
23
23
 
24
24
  /**
25
25
  * The `NotificationService` can be used to add or remove notifications. By default the [`NotificationList`](../components/NotificationListComponent.mdx) component displays the currently active notifications.
@@ -255,6 +255,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImpor
255
255
  }]
256
256
  }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: NotificationService }]; } });
257
257
 
258
+ const getMessageTranslation = (message, channel, user) => {
259
+ var _a, _b;
260
+ const language = (user === null || user === void 0 ? void 0 : user.language) ||
261
+ ((_a = channel === null || channel === void 0 ? void 0 : channel.data) === null || _a === void 0 ? void 0 : _a.auto_translation_language);
262
+ if (language && (message === null || message === void 0 ? void 0 : message.i18n) && ((_b = message === null || message === void 0 ? void 0 : message.user) === null || _b === void 0 ? void 0 : _b.id) !== (user === null || user === void 0 ? void 0 : user.id)) {
263
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
264
+ return message.i18n[`${language}_text`];
265
+ }
266
+ else {
267
+ return undefined;
268
+ }
269
+ };
270
+
258
271
  const createMessagePreview = (user, text, attachments = [], mentionedUsers = [], parentId = undefined, quotedMessageId = undefined, customData) => {
259
272
  const clientSideId = `${user.id}-${v4()}`;
260
273
  return Object.assign({ __html: text, created_at: new Date(), html: text, id: clientSideId, reactions: [], status: 'sending', text, type: 'regular', user,
@@ -387,6 +400,10 @@ class ChannelService {
387
400
  this.activeChannelSubject.next(channel);
388
401
  channel.state.messages.forEach((m) => {
389
402
  m.readBy = getReadBy(m, channel);
403
+ m.translation = getMessageTranslation(m, channel, this.chatClientService.chatClient.user);
404
+ if (m.quoted_message) {
405
+ m.quoted_message.translation = getMessageTranslation(m.quoted_message, channel, this.chatClientService.chatClient.user);
406
+ }
390
407
  });
391
408
  if (this.canSendReadEvents && this.shouldMarkActiveChannelAsRead) {
392
409
  void channel.markRead();
@@ -617,7 +634,9 @@ class ChannelService {
617
634
  */
618
635
  updateMessage(message) {
619
636
  return __awaiter(this, void 0, void 0, function* () {
620
- yield this.chatClientService.chatClient.updateMessage(message);
637
+ const messageToUpdate = Object.assign({}, message);
638
+ delete messageToUpdate.i18n;
639
+ yield this.chatClientService.chatClient.updateMessage(messageToUpdate);
621
640
  });
622
641
  }
623
642
  /**
@@ -1227,14 +1246,23 @@ class ChannelService {
1227
1246
  const isThreadMessage = !!message.parent_id;
1228
1247
  if (this.isStreamMessage(message) &&
1229
1248
  this.isFormatMessageResponse(message)) {
1249
+ if (message.quoted_message) {
1250
+ message.quoted_message.translation = getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user);
1251
+ }
1252
+ message.translation = getMessageTranslation(message, channel, this.chatClientService.chatClient.user);
1230
1253
  return message;
1231
1254
  }
1232
- else if (this.isFormatMessageResponse(message)) {
1233
- return Object.assign(Object.assign({}, message), { readBy: isThreadMessage ? [] : getReadBy(message, channel) });
1234
- }
1235
1255
  else {
1236
- const formatMessage = this.formatMessage(message);
1237
- return Object.assign(Object.assign({}, formatMessage), { readBy: isThreadMessage ? [] : getReadBy(formatMessage, channel) });
1256
+ if (message.quoted_message) {
1257
+ message.quoted_message = Object.assign(Object.assign({}, message.quoted_message), { translation: getMessageTranslation(message.quoted_message, channel, this.chatClientService.chatClient.user) });
1258
+ }
1259
+ if (this.isFormatMessageResponse(message)) {
1260
+ return Object.assign(Object.assign({}, message), { readBy: isThreadMessage ? [] : getReadBy(message, channel), translation: getMessageTranslation(message, channel, this.chatClientService.chatClient.user) });
1261
+ }
1262
+ else {
1263
+ const formatMessage = this.formatMessage(message);
1264
+ return Object.assign(Object.assign({}, formatMessage), { readBy: isThreadMessage ? [] : getReadBy(formatMessage, channel), translation: getMessageTranslation(message, channel, this.chatClientService.chatClient.user) });
1265
+ }
1238
1266
  }
1239
1267
  }
1240
1268
  handleTypingStartEvent(event) {
@@ -1911,6 +1939,8 @@ const en = {
1911
1939
  'user is typing': '{{ user }} is typing',
1912
1940
  'users are typing': '{{ users }} are typing',
1913
1941
  'Error loading channels': 'Error loading channels',
1942
+ 'See original (automatically translated)': 'See original (automatically translated)',
1943
+ 'See translation': 'See translation',
1914
1944
  },
1915
1945
  };
1916
1946
 
@@ -3107,7 +3137,7 @@ class MessageInputComponent {
3107
3137
  }
3108
3138
  }
3109
3139
  MessageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, deps: [{ token: ChannelService }, { token: NotificationService }, { token: AttachmentService }, { token: MessageInputConfigService }, { token: textareaInjectionToken }, { token: i0.ComponentFactoryResolver }, { token: i0.ChangeDetectorRef }, { token: ChatClientService }, { token: EmojiInputService }, { token: CustomTemplatesService }, { token: ThemeService }], target: i0.ɵɵFactoryTarget.Component });
3110
- MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mode: "mode", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message", sendMessage$: "sendMessage$" }, outputs: { messageUpdate: "messageUpdate" }, host: { properties: { "class": "this.class" } }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"themeVersion !== '2'\"\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div class=\"quoted-message-preview\" *ngIf=\"quotedMessage\">\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n style=\"font-size: 15px; line-height: 15px; width: 15px; height: 15px\"\n ></stream-icon-placeholder>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"quotedMessage?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <ng-template\n #defaultAttachmentsPreview\n let-attachmentUploads$=\"attachmentUploads$\"\n let-retryUploadHandler=\"retryUploadHandler\"\n let-deleteUploadHandler=\"deleteUploadHandler\"\n >\n <stream-attachment-preview-list\n [attachmentUploads$]=\"attachmentUploads$\"\n (retryAttachmentUpload)=\"retryUploadHandler($event)\"\n (deleteAttachment)=\"deleteUploadHandler($event)\"\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentPreviewListTemplate || defaultAttachmentsPreview;\n context: getAttachmentPreviewListContext()\n \"\n ></ng-container>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container *ngIf=\"emojiPickerTemplate\" data-testid=\"emoji-picker\">\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: getEmojiPickerContext()\n \"\n ></ng-container>\n </div>\n </ng-container>\n <ng-container *ngIf=\"canSendMessages; else disabledTextarea\">\n <ng-container\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionScope]=\"mentionScope\"\n [placeholder]=\"textareaPlaceholder\"\n ></ng-container>\n </ng-container>\n <ng-template #disabledTextarea>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"disabledTextareaText | translate\"\n class=\"rta__textarea str-chat__textarea__textarea\"\n data-testid=\"disabled-textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon-placeholder\n icon=\"file-upload\"\n ></stream-icon-placeholder>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages && !isCooldownInProgress\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__send-button-angular\"\n icon=\"send\"\n ></stream-icon-placeholder>\n </button>\n <div\n class=\"str-chat__input-flat-cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n <div class=\"str-chat__message-input-cooldown-text\">\n {{ cooldown$ | async }}\n </div>\n </div>\n </div>\n</div>\n\n<div\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-input str-chat-angular__message-input\"\n>\n <div *ngIf=\"quotedMessage\" class=\"str-chat__quoted-message-preview-header\">\n <div class=\"str-chat__quoted-message-reply-to-message\">\n {{ \"streamChat.Reply to Message\" | translate }}\n </div>\n <button\n class=\"str-chat__quoted-message-remove\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n ></stream-icon-placeholder>\n </button>\n </div>\n <ng-container *ngIf=\"canSendMessages; else notAllowed\">\n <div\n class=\"\n str-chat__message-input-inner\n str-chat-angular__message-input-inner\n \"\n >\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__file-input-container\"\n data-testid=\"file-upload-button\"\n >\n <input\n #fileInput\n type=\"file\"\n class=\"str-chat__file-input\"\n data-testid=\"file-input\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n id=\"{{ fileInputId }}\"\n />\n <label class=\"str-chat__file-input-label\" for=\"{{ fileInputId }}\">\n <stream-icon-placeholder icon=\"attach\"></stream-icon-placeholder>\n </label>\n </div>\n <div class=\"str-chat__message-textarea-container\">\n <div\n data-testid=\"quoted-message-container\"\n class=\"str-chat__quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"\n str-chat-angular__avatar-host\n str-chat__message-sender-avatar\n \"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"quotedMessage?.user || undefined\"\n ></stream-avatar-placeholder>\n <div\n class=\"\n quoted-message-preview-content-inner\n str-chat__quoted-message-bubble\n \"\n >\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n class=\"str-chat__quoted-message-text\"\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"quotedMessage?.html || quotedMessage?.text\"\n ></div>\n </div>\n </div>\n <ng-template\n #defaultAttachmentsPreview\n let-attachmentUploads$=\"attachmentUploads$\"\n let-retryUploadHandler=\"retryUploadHandler\"\n let-deleteUploadHandler=\"deleteUploadHandler\"\n >\n <stream-attachment-preview-list\n [attachmentUploads$]=\"attachmentUploads$\"\n (retryAttachmentUpload)=\"retryUploadHandler($event)\"\n (deleteAttachment)=\"deleteUploadHandler($event)\"\n class=\"str-chat__attachment-preview-list-angular-host\"\n ></stream-attachment-preview-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentPreviewListTemplate || defaultAttachmentsPreview;\n context: getAttachmentPreviewListContext()\n \"\n ></ng-container>\n <div class=\"str-chat__message-textarea-with-emoji-picker\">\n <ng-container\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionScope]=\"mentionScope\"\n [placeholder]=\"textareaPlaceholder\"\n ></ng-container>\n <div class=\"str-chat__message-textarea-emoji-picker\">\n <ng-container\n *ngIf=\"emojiPickerTemplate\"\n data-testid=\"emoji-picker\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: getEmojiPickerContext()\n \"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages && !isCooldownInProgress && !message\"\n [disabled]=\"\n (attachmentUploadInProgressCounter$ | async)! > 0 ||\n (!textareaValue && (attachmentUploads$ | async)!.length === 0)\n \"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon-placeholder icon=\"send\"></stream-icon-placeholder>\n </button>\n <div\n class=\"str-chat__message-input-cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n {{ cooldown$ | async }}\n </div>\n </div>\n </ng-container>\n <ng-template #notAllowed>\n <div\n class=\"str-chat__message-input-not-allowed\"\n data-testid=\"disabled-textarea\"\n >\n {{ disabledTextareaText | translate }}\n </div>\n </ng-template>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", inputs: ["attachmentUploads$"], outputs: ["retryAttachmentUpload", "deleteAttachment"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionScope", "value", "placeholder"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i4.AsyncPipe, "translate": i6.TranslatePipe } });
3140
+ MessageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageInputComponent, selector: "stream-message-input", inputs: { isFileUploadEnabled: "isFileUploadEnabled", areMentionsEnabled: "areMentionsEnabled", mentionScope: "mentionScope", mode: "mode", isMultipleFileUploadEnabled: "isMultipleFileUploadEnabled", message: "message", sendMessage$: "sendMessage$" }, outputs: { messageUpdate: "messageUpdate" }, host: { properties: { "class": "this.class" } }, providers: [AttachmentService, EmojiInputService], viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }, { propertyName: "textareaAnchor", first: true, predicate: TextareaDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n *ngIf=\"themeVersion !== '2'\"\n class=\"{{\n mode === 'main' ? 'str-chat__input-flat' : 'str-chat__small-message-input'\n }}\"\n [class.str-chat__input-flat-has-attachments]=\"\n (attachmentUploads$ | async)!.length > 0\n \"\n [class.str-chat__input-flat-quoted]=\"!!quotedMessage\"\n>\n <div class=\"quoted-message-preview\" *ngIf=\"quotedMessage\">\n <div class=\"quoted-message-preview-header\">\n <div>{{ \"streamChat.Reply to Message\" | translate }}</div>\n <button\n class=\"str-chat__square-button\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n style=\"font-size: 15px; line-height: 15px; width: 15px; height: 15px\"\n ></stream-icon-placeholder>\n </button>\n </div>\n <div class=\"quoted-message-preview-content\">\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host\"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"quotedMessage?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-preview-content-inner\">\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.translation ||\n quotedMessage?.html ||\n quotedMessage?.text\n \"\n ></div>\n </div>\n </div>\n </div>\n <div class=\"str-chat__input-flat-wrapper\" style=\"width: 100%\">\n <div\n class=\"{{\n mode === 'main'\n ? 'str-chat__input-flat--textarea-wrapper'\n : 'str-chat__small-message-input--textarea-wrapper'\n }}\"\n >\n <ng-template\n #defaultAttachmentsPreview\n let-attachmentUploads$=\"attachmentUploads$\"\n let-retryUploadHandler=\"retryUploadHandler\"\n let-deleteUploadHandler=\"deleteUploadHandler\"\n >\n <stream-attachment-preview-list\n [attachmentUploads$]=\"attachmentUploads$\"\n (retryAttachmentUpload)=\"retryUploadHandler($event)\"\n (deleteAttachment)=\"deleteUploadHandler($event)\"\n class=\"rfu-image-previewer-angular-host\"\n ></stream-attachment-preview-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentPreviewListTemplate || defaultAttachmentsPreview;\n context: getAttachmentPreviewListContext()\n \"\n ></ng-container>\n <div class=\"rta str-chat__textarea str-chat-angular__textarea\">\n <ng-container *ngIf=\"emojiPickerTemplate\" data-testid=\"emoji-picker\">\n <div\n class=\"\n str-chat__input-flat-emojiselect\n str-chat-angular__emojiselect\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: getEmojiPickerContext()\n \"\n ></ng-container>\n </div>\n </ng-container>\n <ng-container *ngIf=\"canSendMessages; else disabledTextarea\">\n <ng-container\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionScope]=\"mentionScope\"\n [placeholder]=\"textareaPlaceholder\"\n ></ng-container>\n </ng-container>\n <ng-template #disabledTextarea>\n <textarea\n disabled\n rows=\"1\"\n [value]=\"disabledTextareaText | translate\"\n class=\"rta__textarea str-chat__textarea__textarea\"\n data-testid=\"disabled-textarea\"\n ></textarea>\n </ng-template>\n </div>\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__fileupload-wrapper\"\n data-testid=\"file-upload-button\"\n >\n <div class=\"str-chat__tooltip\">\n {{ \"streamChat.Attach files\" | translate }}\n </div>\n <div class=\"rfu-file-upload-button\">\n <label>\n <input\n #fileInput\n type=\"file\"\n class=\"rfu-file-input\"\n data-testid=\"file-input\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n />\n <span class=\"str-chat__input-flat-fileupload\">\n <stream-icon-placeholder\n icon=\"file-upload\"\n ></stream-icon-placeholder>\n </span>\n </label>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages && !isCooldownInProgress\"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__send-button-angular\"\n icon=\"send\"\n ></stream-icon-placeholder>\n </button>\n <div\n class=\"str-chat__input-flat-cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n <div class=\"str-chat__message-input-cooldown-text\">\n {{ cooldown$ | async }}\n </div>\n </div>\n </div>\n</div>\n\n<div\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-input str-chat-angular__message-input\"\n>\n <div *ngIf=\"quotedMessage\" class=\"str-chat__quoted-message-preview-header\">\n <div class=\"str-chat__quoted-message-reply-to-message\">\n {{ \"streamChat.Reply to Message\" | translate }}\n </div>\n <button\n class=\"str-chat__quoted-message-remove\"\n data-testid=\"remove-quote\"\n (click)=\"deselectMessageToQuote()\"\n (keyup.enter)=\"deselectMessageToQuote()\"\n >\n <stream-icon-placeholder\n icon=\"close-no-outline\"\n ></stream-icon-placeholder>\n </button>\n </div>\n <ng-container *ngIf=\"canSendMessages; else notAllowed\">\n <div\n class=\"\n str-chat__message-input-inner\n str-chat-angular__message-input-inner\n \"\n >\n <div\n *ngIf=\"isFileUploadEnabled && isFileUploadAuthorized && canSendMessages\"\n class=\"str-chat__file-input-container\"\n data-testid=\"file-upload-button\"\n >\n <input\n #fileInput\n type=\"file\"\n class=\"str-chat__file-input\"\n data-testid=\"file-input\"\n [multiple]=\"isMultipleFileUploadEnabled\"\n (change)=\"filesSelected(fileInput.files)\"\n id=\"{{ fileInputId }}\"\n />\n <label class=\"str-chat__file-input-label\" for=\"{{ fileInputId }}\">\n <stream-icon-placeholder icon=\"attach\"></stream-icon-placeholder>\n </label>\n </div>\n <div class=\"str-chat__message-textarea-container\">\n <div\n data-testid=\"quoted-message-container\"\n class=\"str-chat__quoted-message-preview\"\n *ngIf=\"quotedMessage\"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"\n str-chat-angular__avatar-host\n str-chat__message-sender-avatar\n \"\n [imageUrl]=\"quotedMessage?.user?.image\"\n [name]=\"quotedMessage?.user?.name || quotedMessage?.user?.id\"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"quotedMessage?.user || undefined\"\n ></stream-avatar-placeholder>\n <div\n class=\"\n quoted-message-preview-content-inner\n str-chat__quoted-message-bubble\n \"\n >\n <stream-attachment-list\n *ngIf=\"\n quotedMessage?.attachments && quotedMessage?.attachments?.length\n \"\n [attachments]=\"quotedMessageAttachments\"\n [messageId]=\"quotedMessage?.id\"\n ></stream-attachment-list>\n <div\n class=\"str-chat__quoted-message-text\"\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n quotedMessage?.translation ||\n quotedMessage?.html ||\n quotedMessage?.text\n \"\n ></div>\n </div>\n </div>\n <ng-template\n #defaultAttachmentsPreview\n let-attachmentUploads$=\"attachmentUploads$\"\n let-retryUploadHandler=\"retryUploadHandler\"\n let-deleteUploadHandler=\"deleteUploadHandler\"\n >\n <stream-attachment-preview-list\n [attachmentUploads$]=\"attachmentUploads$\"\n (retryAttachmentUpload)=\"retryUploadHandler($event)\"\n (deleteAttachment)=\"deleteUploadHandler($event)\"\n class=\"str-chat__attachment-preview-list-angular-host\"\n ></stream-attachment-preview-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentPreviewListTemplate || defaultAttachmentsPreview;\n context: getAttachmentPreviewListContext()\n \"\n ></ng-container>\n <div class=\"str-chat__message-textarea-with-emoji-picker\">\n <ng-container\n streamTextarea\n [(value)]=\"textareaValue\"\n (valueChange)=\"typingStart$.next()\"\n (send)=\"messageSent()\"\n [componentRef]=\"textareaRef\"\n (userMentions)=\"mentionedUsers = $event\"\n [areMentionsEnabled]=\"areMentionsEnabled\"\n [mentionScope]=\"mentionScope\"\n [placeholder]=\"textareaPlaceholder\"\n ></ng-container>\n <div class=\"str-chat__message-textarea-emoji-picker\">\n <ng-container\n *ngIf=\"emojiPickerTemplate\"\n data-testid=\"emoji-picker\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n emojiPickerTemplate;\n context: getEmojiPickerContext()\n \"\n ></ng-container>\n </ng-container>\n </div>\n </div>\n </div>\n <button\n *ngIf=\"canSendMessages && !isCooldownInProgress && !message\"\n [disabled]=\"\n (attachmentUploadInProgressCounter$ | async)! > 0 ||\n (!textareaValue && (attachmentUploads$ | async)!.length === 0)\n \"\n data-testid=\"send-button\"\n class=\"str-chat__send-button\"\n (click)=\"messageSent()\"\n (keyup.enter)=\"messageSent()\"\n >\n <stream-icon-placeholder icon=\"send\"></stream-icon-placeholder>\n </button>\n <div\n class=\"str-chat__message-input-cooldown\"\n *ngIf=\"isCooldownInProgress\"\n data-testid=\"cooldown-timer\"\n >\n {{ cooldown$ | async }}\n </div>\n </div>\n </ng-container>\n <ng-template #notAllowed>\n <div\n class=\"str-chat__message-input-not-allowed\"\n data-testid=\"disabled-textarea\"\n >\n {{ disabledTextareaText | translate }}\n </div>\n </ng-template>\n</div>\n", components: [{ type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"] }, { type: AttachmentPreviewListComponent, selector: "stream-attachment-preview-list", inputs: ["attachmentUploads$"], outputs: ["retryAttachmentUpload", "deleteAttachment"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: TextareaDirective, selector: "[streamTextarea]", inputs: ["componentRef", "areMentionsEnabled", "mentionScope", "value", "placeholder"], outputs: ["valueChange", "send", "userMentions"] }], pipes: { "async": i4.AsyncPipe, "translate": i6.TranslatePipe } });
3111
3141
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageInputComponent, decorators: [{
3112
3142
  type: Component,
3113
3143
  args: [{
@@ -3629,7 +3659,8 @@ class ChannelPreviewComponent {
3629
3659
  this.latestMessage = 'streamChat.Message deleted';
3630
3660
  }
3631
3661
  else if (message === null || message === void 0 ? void 0 : message.text) {
3632
- this.latestMessage = message.text;
3662
+ this.latestMessage =
3663
+ getMessageTranslation(message, this.channel, this.chatClientService.chatClient.user) || message.text;
3633
3664
  }
3634
3665
  else if ((message === null || message === void 0 ? void 0 : message.attachments) && message.attachments.length) {
3635
3666
  this.latestMessage = 'streamChat.🏙 Attachment...';
@@ -3902,12 +3933,15 @@ class MessageComponent {
3902
3933
  this.popperTriggerClick = NgxPopperjsTriggers.click;
3903
3934
  this.popperTriggerHover = NgxPopperjsTriggers.hover;
3904
3935
  this.popperPlacementAuto = NgxPopperjsPlacements.AUTO;
3936
+ this.shouldDisplayTranslationNotice = false;
3937
+ this.displayedMessageTextContent = 'original';
3905
3938
  this.subscriptions = [];
3906
3939
  this.themeVersion = themeService.themeVersion;
3907
- this.user = this.chatClientService.chatClient.user;
3908
3940
  }
3909
3941
  ngOnInit() {
3910
- this.subscriptions.push(this.chatClientService.user$.subscribe((u) => (this.user = u)));
3942
+ this.subscriptions.push(this.chatClientService.user$.subscribe((u) => {
3943
+ this.user = u;
3944
+ }));
3911
3945
  this.subscriptions.push(this.customTemplatesService.mentionTemplate$.subscribe((template) => (this.mentionTemplate = template)));
3912
3946
  this.subscriptions.push(this.customTemplatesService.attachmentListTemplate$.subscribe((template) => (this.attachmentListTemplate = template)));
3913
3947
  this.subscriptions.push(this.customTemplatesService.messageActionsBoxTemplate$.subscribe((template) => (this.messageActionsBoxTemplate = template)));
@@ -3916,6 +3950,8 @@ class MessageComponent {
3916
3950
  ngOnChanges(changes) {
3917
3951
  var _a, _b;
3918
3952
  if (changes.message) {
3953
+ this.shouldDisplayTranslationNotice = false;
3954
+ this.displayedMessageTextContent = 'original';
3919
3955
  this.createMessageParts();
3920
3956
  const originalAttachments = (_b = (_a = this.message) === null || _a === void 0 ? void 0 : _a.quoted_message) === null || _b === void 0 ? void 0 : _b.attachments;
3921
3957
  this.quotedMessageAttachments =
@@ -4057,30 +4093,34 @@ class MessageComponent {
4057
4093
  jumpToMessage(messageId, parentMessageId) {
4058
4094
  void this.channelService.jumpToMessage(messageId, parentMessageId);
4059
4095
  }
4060
- createMessageParts() {
4061
- var _a, _b;
4062
- let content = ((_a = this.message) === null || _a === void 0 ? void 0 : _a.html) || ((_b = this.message) === null || _b === void 0 ? void 0 : _b.text);
4096
+ displayTranslatedMessage() {
4097
+ this.createMessageParts(true);
4098
+ }
4099
+ displayOriginalMessage() {
4100
+ this.createMessageParts(false);
4101
+ }
4102
+ createMessageParts(shouldTranslate = true) {
4103
+ let content = this.getMessageContent(shouldTranslate);
4063
4104
  if (!content) {
4064
4105
  this.messageTextParts = [];
4065
4106
  }
4066
4107
  else {
4108
+ let isHTML = false;
4067
4109
  // Backend will wrap HTML content with <p></p>\n
4068
4110
  if (content.startsWith('<p>')) {
4069
4111
  content = content.replace('<p>', '');
4112
+ isHTML = true;
4070
4113
  }
4071
4114
  if (content.endsWith('</p>\n')) {
4072
4115
  content = content.replace('</p>\n', '');
4116
+ isHTML = true;
4073
4117
  }
4074
4118
  if (!this.message.mentioned_users ||
4075
4119
  this.message.mentioned_users.length === 0) {
4076
- // Wrap emojis in span to display emojis correctly in Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=596223
4077
- const regex = new RegExp(emojiRegex(), 'g');
4078
- // Based on this: https://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome
4079
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
4080
- const isChrome = !!window.chrome &&
4081
- typeof window.opr === 'undefined';
4082
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
4083
- content = content.replace(regex, (match) => `<span ${isChrome ? 'class="str-chat__emoji-display-fix"' : ''}>${match}</span>`);
4120
+ content = this.fixEmojiDisplay(content);
4121
+ if (!isHTML) {
4122
+ content = this.wrapLinskWithAnchorTag(content);
4123
+ }
4084
4124
  this.messageTextParts = [{ content, type: 'text' }];
4085
4125
  }
4086
4126
  else {
@@ -4088,7 +4128,11 @@ class MessageComponent {
4088
4128
  let text = content;
4089
4129
  this.message.mentioned_users.forEach((user) => {
4090
4130
  const mention = `@${user.name || user.id}`;
4091
- const precedingText = text.substring(0, text.indexOf(mention));
4131
+ let precedingText = text.substring(0, text.indexOf(mention));
4132
+ precedingText = this.fixEmojiDisplay(precedingText);
4133
+ if (!isHTML) {
4134
+ precedingText = this.wrapLinskWithAnchorTag(precedingText);
4135
+ }
4092
4136
  this.messageTextParts.push({
4093
4137
  content: precedingText,
4094
4138
  type: 'text',
@@ -4101,14 +4145,49 @@ class MessageComponent {
4101
4145
  text = text.replace(precedingText + mention, '');
4102
4146
  });
4103
4147
  if (text) {
4148
+ text = this.fixEmojiDisplay(text);
4149
+ if (!isHTML) {
4150
+ text = this.wrapLinskWithAnchorTag(text);
4151
+ }
4104
4152
  this.messageTextParts.push({ content: text, type: 'text' });
4105
4153
  }
4106
4154
  }
4107
4155
  }
4108
4156
  }
4157
+ getMessageContent(shouldTranslate) {
4158
+ var _a, _b, _c;
4159
+ const originalContent = ((_a = this.message) === null || _a === void 0 ? void 0 : _a.html) || ((_b = this.message) === null || _b === void 0 ? void 0 : _b.text);
4160
+ if (shouldTranslate) {
4161
+ const translation = (_c = this.message) === null || _c === void 0 ? void 0 : _c.translation;
4162
+ if (translation) {
4163
+ this.shouldDisplayTranslationNotice = true;
4164
+ this.displayedMessageTextContent = 'translation';
4165
+ }
4166
+ return translation || originalContent;
4167
+ }
4168
+ else {
4169
+ this.displayedMessageTextContent = 'original';
4170
+ return originalContent;
4171
+ }
4172
+ }
4173
+ fixEmojiDisplay(content) {
4174
+ // Wrap emojis in span to display emojis correctly in Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=596223
4175
+ const regex = new RegExp(emojiRegex(), 'g');
4176
+ // Based on this: https://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome
4177
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
4178
+ const isChrome = !!window.chrome && typeof window.opr === 'undefined';
4179
+ /* eslint-enable @typescript-eslint/no-unsafe-member-access */
4180
+ content = content.replace(regex, (match) => `<span ${isChrome ? 'class="str-chat__emoji-display-fix"' : ''}>${match}</span>`);
4181
+ return content;
4182
+ }
4183
+ wrapLinskWithAnchorTag(content) {
4184
+ const urlRegexp = /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])/gim;
4185
+ content = content.replace(urlRegexp, (match) => `<a href="${match}" rel="nofollow">${match}</a>`);
4186
+ return content;
4187
+ }
4109
4188
  }
4110
4189
  MessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, deps: [{ token: ChatClientService }, { token: ChannelService }, { token: CustomTemplatesService }, { token: i0.ChangeDetectorRef }, { token: ThemeService }], target: i0.ɵɵFactoryTarget.Component });
4111
- MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", isLastSentMessage: "isLastSentMessage", mode: "mode", isHighlighted: "isHighlighted" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--other]=\"!isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"hasReactions\"\n [class.str-chat__message--highlighted]=\"isHighlighted\"\n [class.str-chat__message-with-thread-link]=\"shouldDisplayThreadLink\"\n [class.str-chat__message-send-can-be-retried]=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n \"\n data-testid=\"message-container\"\n (mouseleave)=\"isActionBoxOpen = false\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container *ngIf=\"themeVersion === '1'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <stream-avatar-placeholder\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n type=\"user\"\n location=\"message-sender\"\n [user]=\"message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions str-chat__message-options\"\n data-testid=\"message-options\"\n [class.str-chat__message-edit-in-progress]=\"isEditing\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n #messageActionsToggle\n class=\"\n str-chat__message-actions-container\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerClick\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"true\"\n [popperHideOnClickOutside]=\"true\"\n [popperHideOnMouseLeave]=\"false\"\n >\n <popper-content #popperContent>\n <ng-template\n #defaultMessageActionsBox\n let-isOpen=\"isOpen\"\n let-isMine=\"isMine\"\n let-enabledActions=\"enabledActions\"\n let-messageInput=\"message\"\n let-displayedActionsCountChaneHanler=\"displayedActionsCountChaneHanler\"\n let-isEditingChangeHandler=\"isEditingChangeHandler\"\n >\n <stream-message-actions-box\n [isOpen]=\"isOpen\"\n [isMine]=\"isMine\"\n [enabledActions]=\"enabledActions\"\n [message]=\"messageInput\"\n (displayedActionsCount)=\"\n displayedActionsCountChaneHanler($event)\n \"\n (isEditing)=\"isEditingChangeHandler($event)\"\n ></stream-message-actions-box>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageActionsBoxTemplate || defaultMessageActionsBox;\n context: getMessageActionsBoxContext()\n \"\n >\n </ng-container>\n </popper-content>\n <div\n class=\"str-chat__message-actions-box-button\"\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n >\n <stream-icon-placeholder\n icon=\"action-icon\"\n class=\"str-chat__message-action-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n str-chat__message-reply-in-thread-button\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reply-in-thread\"\n ></stream-icon-placeholder>\n </div>\n <div\n *ngIf=\"canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n str-chat__message-reactions-button\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reaction-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div class=\"str-chat__message-reactions-host\">\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <ng-template\n #defaultMessageReactions\n let-messageReactionCounts=\"messageReactionCounts\"\n let-latestReactions=\"latestReactions\"\n let-isSelectorOpen=\"isSelectorOpen\"\n let-isSelectorOpenChangeHandler=\"isSelectorOpenChangeHandler\"\n let-messageId=\"messageId\"\n let-ownReactions=\"ownReactions\"\n >\n <stream-message-reactions\n [messageReactionCounts]=\"messageReactionCounts\"\n [latestReactions]=\"latestReactions\"\n [isSelectorOpen]=\"isSelectorOpen\"\n (isSelectorOpenChange)=\"isSelectorOpenChangeHandler($event)\"\n [messageId]=\"messageId\"\n [ownReactions]=\"ownReactions\"\n ></stream-message-reactions>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageReactionsTemplate || defaultMessageReactions;\n context: getMessageReactionsContext()\n \"\n ></ng-container>\n </div>\n <div class=\"str-chat__message-bubble\">\n <ng-container *ngIf=\"hasAttachment && !message?.quoted_message\">\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentListTemplate || defaultAttachments;\n context: getAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n class=\"str-chat__message-text\"\n tabindex=\"0\"\n *ngIf=\"message?.text || (message?.quoted_message && hasAttachment)\"\n >\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <stream-attachment-list\n *ngIf=\"hasAttachment && message?.quoted_message\"\n [attachments]=\"message!.attachments!\"\n [messageId]=\"message!.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div data-testid=\"text\">\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-template #defaultMention let-content=\"content\">\n <span class=\"str-chat__message-mention\">{{\n content\n }}</span>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate || defaultMention;\n context: getMentionContext(part)\n \"\n ></ng-container>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-error-icon\"\n icon=\"error\"\n ></stream-icon-placeholder>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'outside-message-bubble', message: message }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'outside-message-bubble' }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message str-chat__quoted-message-preview\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n (click)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n (keyup.enter)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"message?.quoted_message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-inner str-chat__quoted-message-bubble\">\n <ng-container\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n >\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentListTemplate || defaultAttachments;\n context: getQuotedMessageAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.html || message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n\n<!-- We need these markups in slightly different positions in theme-v1 and theme-v2, this soultion makes that possible without duplicating the code -->\n<ng-template #messageDateAndSender let-position=\"position\">\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n class=\"\n str-chat__message-data\n str-chat__message-simple-data\n str-chat__message-metadata\n \"\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n >\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <ng-container *ngIf=\"themeVersion === '2'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name str-chat__message-sender-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n</ng-template>\n\n<ng-template #messageStatus>\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n mode === 'main' && isMessageDeliveredAndRead && canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n <ng-template #deliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"delivered-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n </popper-content>\n <stream-icon-placeholder\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon-placeholder>\n </span>\n </ng-template>\n <ng-template #sendingStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"sending-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n </popper-content>\n <stream-loading-indicator-placeholder\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator-placeholder>\n </span>\n </ng-template>\n <ng-template #readStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"read-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div\n class=\"str-chat__tooltip str-chat__tooltip-angular\"\n data-testid=\"read-by-tooltip\"\n >\n {{ readByText }}\n </div>\n </popper-content>\n <stream-avatar-placeholder\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n type=\"user\"\n location=\"message-reader\"\n [user]=\"lastReadUser\"\n ></stream-avatar-placeholder>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n </ng-template>\n </ng-container>\n</ng-template>\n\n<ng-template #replyCountButton let-position=\"position\">\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n class=\"\n str-chat__message-simple-reply-button\n str-chat__message-replies-count-button-wrapper\n \"\n >\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <button\n *ngIf=\"shouldDisplayThreadLink\"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '1'\"\n stream-icon-placeholder\n icon=\"reply\"\n ></stream-icon-placeholder>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type"] }, { type: i2.NgxPopperjsContentComponent, selector: "popper-content" }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgxPopperjsDirective, selector: "[popper]", inputs: ["popperTimeout", "popperTimeoutAfterShow", "popperApplyClass", "popper", "popperDisabled", "popperPlacement", "popperApplyArrowClass", "popperPreventOverflow", "popperHideOnClickOutside", "popperTrigger", "popperStyles", "popperAriaDescribeBy", "popperAriaRole", "popperBoundaries", "popperCloseOnClickOutside", "popperDisableAnimation", "popperDisableStyle", "popperHideOnMouseLeave", "popperHideOnScroll", "popperAppendTo", "popperModifiers", "popperPositionFixed", "popperDelay", "popperShowOnStart", "popperTarget"], outputs: ["popperOnHidden", "popperOnShown", "popperOnUpdate"], exportAs: ["popper"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i6.TranslatePipe } });
4190
+ MessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.5", type: MessageComponent, selector: "stream-message", inputs: { message: "message", enabledMessageActions: "enabledMessageActions", isLastSentMessage: "isLastSentMessage", mode: "mode", isHighlighted: "isHighlighted" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #container\n class=\"str-chat__message-simple str-chat__message str-chat__message--{{\n message?.type\n }} str-chat__message--{{ message?.status }} {{\n message?.text ? 'str-chat__message--has-text' : 'has-no-text'\n }}\"\n [class.str-chat__message--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--other]=\"!isSentByCurrentUser\"\n [class.str-chat__message-simple--me]=\"isSentByCurrentUser\"\n [class.str-chat__message--has-attachment]=\"hasAttachment\"\n [class.str-chat__message--with-reactions]=\"hasReactions\"\n [class.str-chat__message--highlighted]=\"isHighlighted\"\n [class.str-chat__message-with-thread-link]=\"shouldDisplayThreadLink\"\n [class.str-chat__message-send-can-be-retried]=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n \"\n data-testid=\"message-container\"\n (mouseleave)=\"isActionBoxOpen = false\"\n>\n <ng-container *ngIf=\"!message?.deleted_at; else deletedMessage\">\n <ng-container *ngIf=\"message?.type !== 'system'; else systemMessage\">\n <ng-container *ngIf=\"themeVersion === '1'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <stream-avatar-placeholder\n data-testid=\"avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.user?.image\"\n [name]=\"message?.user?.name || message?.user?.id\"\n type=\"user\"\n location=\"message-sender\"\n [user]=\"message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"str-chat__message-inner\">\n <div\n class=\"str-chat__message-simple__actions str-chat__message-options\"\n data-testid=\"message-options\"\n [class.str-chat__message-edit-in-progress]=\"isEditing\"\n *ngIf=\"areOptionsVisible\"\n >\n <div\n data-testid=\"message-actions-container\"\n #messageActionsToggle\n class=\"\n str-chat__message-actions-container\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--options\n \"\n [class.str-chat-angular__message-simple__actions__action--options--editing]=\"\n isEditing\n \"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerClick\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"true\"\n [popperHideOnClickOutside]=\"true\"\n [popperHideOnMouseLeave]=\"false\"\n >\n <popper-content #popperContent>\n <ng-template\n #defaultMessageActionsBox\n let-isOpen=\"isOpen\"\n let-isMine=\"isMine\"\n let-enabledActions=\"enabledActions\"\n let-messageInput=\"message\"\n let-displayedActionsCountChaneHanler=\"displayedActionsCountChaneHanler\"\n let-isEditingChangeHandler=\"isEditingChangeHandler\"\n >\n <stream-message-actions-box\n [isOpen]=\"isOpen\"\n [isMine]=\"isMine\"\n [enabledActions]=\"enabledActions\"\n [message]=\"messageInput\"\n (displayedActionsCount)=\"\n displayedActionsCountChaneHanler($event)\n \"\n (isEditing)=\"isEditingChangeHandler($event)\"\n ></stream-message-actions-box>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageActionsBoxTemplate || defaultMessageActionsBox;\n context: getMessageActionsBoxContext()\n \"\n >\n </ng-container>\n </popper-content>\n <div\n class=\"str-chat__message-actions-box-button\"\n *ngIf=\"visibleMessageActionsCount > 0\"\n data-testid=\"action-icon\"\n (click)=\"isActionBoxOpen = !isActionBoxOpen\"\n (keyup.enter)=\"isActionBoxOpen = !isActionBoxOpen\"\n >\n <stream-icon-placeholder\n icon=\"action-icon\"\n class=\"str-chat__message-action-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n enabledMessageActions.indexOf('send-reply') !== -1 &&\n mode === 'main'\n \"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--thread\n str-chat__message-reply-in-thread-button\n \"\n data-testid=\"reply-in-thread\"\n (click)=\"setAsActiveParentMessage()\"\n (keyup.enter)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reply-in-thread\"\n ></stream-icon-placeholder>\n </div>\n <div\n *ngIf=\"canReactToMessage\"\n class=\"\n str-chat__message-simple__actions__action\n str-chat__message-simple__actions__action--reactions\n str-chat__message-reactions-button\n \"\n data-testid=\"reaction-icon\"\n (click)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n (keyup.enter)=\"isReactionSelectorOpen = !isReactionSelectorOpen\"\n >\n <stream-icon-placeholder\n class=\"str-chat__message-action-icon\"\n icon=\"reaction-icon\"\n ></stream-icon-placeholder>\n </div>\n </div>\n <div class=\"str-chat__message-reactions-host\">\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <ng-template\n #defaultMessageReactions\n let-messageReactionCounts=\"messageReactionCounts\"\n let-latestReactions=\"latestReactions\"\n let-isSelectorOpen=\"isSelectorOpen\"\n let-isSelectorOpenChangeHandler=\"isSelectorOpenChangeHandler\"\n let-messageId=\"messageId\"\n let-ownReactions=\"ownReactions\"\n >\n <stream-message-reactions\n [messageReactionCounts]=\"messageReactionCounts\"\n [latestReactions]=\"latestReactions\"\n [isSelectorOpen]=\"isSelectorOpen\"\n (isSelectorOpenChange)=\"isSelectorOpenChangeHandler($event)\"\n [messageId]=\"messageId\"\n [ownReactions]=\"ownReactions\"\n ></stream-message-reactions>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n messageReactionsTemplate || defaultMessageReactions;\n context: getMessageReactionsContext()\n \"\n ></ng-container>\n </div>\n <div class=\"str-chat__message-bubble\">\n <ng-container *ngIf=\"hasAttachment && !message?.quoted_message\">\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentListTemplate || defaultAttachments;\n context: getAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n class=\"str-chat__message-text\"\n tabindex=\"0\"\n *ngIf=\"message?.text || (message?.quoted_message && hasAttachment)\"\n >\n <div\n data-testid=\"inner-message\"\n class=\"\n str-chat__message-text-inner str-chat__message-simple-text-inner\n \"\n [class.str-chat__message-light-text-inner--has-attachment]=\"\n hasAttachment\n \"\n (click)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n (keyup.enter)=\"\n message?.status === 'failed' && message?.errorStatusCode !== 403\n ? resendMessage()\n : undefined\n \"\n >\n <ng-container *ngTemplateOutlet=\"quotedMessage\"></ng-container>\n <stream-attachment-list\n *ngIf=\"hasAttachment && message?.quoted_message\"\n [attachments]=\"message!.attachments!\"\n [messageId]=\"message!.id\"\n ></stream-attachment-list>\n <div\n data-testid=\"client-error-message\"\n *ngIf=\"message?.type === 'error'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n {{ \"streamChat.Error \u00B7 Unsent\" | translate }}\n </div>\n <div\n data-testid=\"error-message\"\n *ngIf=\"message?.status === 'failed'\"\n class=\"\n str-chat__simple-message--error-message\n str-chat__message--error-message\n \"\n >\n {{\n (message?.errorStatusCode === 403\n ? \"streamChat.Message Failed \u00B7 Unauthorized\"\n : \"streamChat.Message Failed \u00B7 Click to try again\"\n ) | translate\n }}\n </div>\n <div data-testid=\"text\">\n <p>\n <!-- eslint-disable-next-line @angular-eslint/template/use-track-by-function -->\n <ng-container *ngFor=\"let part of messageTextParts\">\n <span\n *ngIf=\"part.type === 'text'; else mention\"\n [innerHTML]=\"part.content\"\n ></span>\n <ng-template #mention>\n <ng-template #defaultMention let-content=\"content\">\n <span class=\"str-chat__message-mention\">{{\n content\n }}</span>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n mentionTemplate || defaultMention;\n context: getMentionContext(part)\n \"\n ></ng-container>\n </ng-template>\n </ng-container>\n </p>\n </div>\n </div>\n </div>\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '2'\"\n class=\"str-chat__message-error-icon\"\n icon=\"error\"\n ></stream-icon-placeholder>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'inside-message-bubble' }\n \"\n ></ng-container>\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n replyCountButton;\n context: { position: 'outside-message-bubble', message: message }\n \"\n ></ng-container>\n\n <ng-container\n *ngTemplateOutlet=\"\n messageDateAndSender;\n context: { position: 'outside-message-bubble' }\n \"\n ></ng-container>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #deletedMessage>\n <div data-testid=\"message-deleted-component\">\n <div class=\"str-chat__message--deleted-inner\" translate>\n streamChat.This message was deleted...\n </div>\n </div>\n</ng-template>\n\n<ng-template #systemMessage>\n <div data-testid=\"system-message\" class=\"str-chat__message--system\">\n <div class=\"str-chat__message--system__text\">\n <div class=\"str-chat__message--system__line\"></div>\n <p>{{ message?.text }}</p>\n <div class=\"str-chat__message--system__line\"></div>\n </div>\n <div class=\"str-chat__message--system__date\">\n {{ parsedDate }}\n </div>\n </div>\n</ng-template>\n\n<ng-template #quotedMessage>\n <div\n *ngIf=\"message?.quoted_message\"\n class=\"quoted-message str-chat__quoted-message-preview\"\n data-testid=\"quoted-message-container\"\n [class.mine]=\"isSentByCurrentUser\"\n (click)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n (keyup.enter)=\"\n jumpToMessage(\n (message?.quoted_message)!.id,\n message?.quoted_message?.parent_id\n )\n \"\n >\n <stream-avatar-placeholder\n data-testid=\"qouted-message-avatar\"\n class=\"str-chat-angular__avatar-host str-chat__message-sender-avatar\"\n [imageUrl]=\"message?.quoted_message?.user?.image\"\n [name]=\"\n message?.quoted_message?.user?.name || message?.quoted_message?.user?.id\n \"\n [size]=\"20\"\n type=\"user\"\n location=\"quoted-message-sender\"\n [user]=\"message?.quoted_message?.user || undefined\"\n ></stream-avatar-placeholder>\n <div class=\"quoted-message-inner str-chat__quoted-message-bubble\">\n <ng-container\n *ngIf=\"\n message?.quoted_message?.attachments &&\n message?.quoted_message?.attachments?.length\n \"\n >\n <ng-template\n #defaultAttachments\n let-messageId=\"messageId\"\n let-attachments=\"attachments\"\n let-parentMessageId=\"parentMessageId\"\n >\n <stream-attachment-list\n [messageId]=\"messageId\"\n [attachments]=\"attachments\"\n [parentMessageId]=\"parentMessageId\"\n ></stream-attachment-list>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"\n attachmentListTemplate || defaultAttachments;\n context: getQuotedMessageAttachmentListContext()\n \"\n ></ng-container>\n </ng-container>\n <div\n data-testid=\"quoted-message-text\"\n [innerHTML]=\"\n message?.quoted_message?.translation ||\n message?.quoted_message?.html ||\n message?.quoted_message?.text\n \"\n ></div>\n </div>\n </div>\n</ng-template>\n\n<!-- We need these markups in slightly different positions in theme-v1 and theme-v2, this soultion makes that possible without duplicating the code -->\n<ng-template #messageDateAndSender let-position=\"position\">\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <ng-container\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n >\n <div\n class=\"str-chat__translation-notice\"\n *ngIf=\"shouldDisplayTranslationNotice\"\n data-testid=\"translation-notice\"\n >\n <button\n data-testid=\"see-original\"\n *ngIf=\"displayedMessageTextContent === 'translation'\"\n (click)=\"displayOriginalMessage()\"\n (keyup.enter)=\"displayOriginalMessage()\"\n translate\n >\n streamChat.See original (automatically translated)\n </button>\n <button\n data-testid=\"see-translation\"\n *ngIf=\"displayedMessageTextContent === 'original'\"\n (click)=\"displayTranslatedMessage()\"\n (keyup.enter)=\"displayTranslatedMessage()\"\n translate\n >\n streamChat.See translation\n </button>\n </div>\n <div\n class=\"\n str-chat__message-data\n str-chat__message-simple-data\n str-chat__message-metadata\n \"\n >\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <ng-container *ngIf=\"themeVersion === '2'\">\n <ng-container *ngTemplateOutlet=\"messageStatus\"></ng-container>\n </ng-container>\n <span\n data-testid=\"sender\"\n *ngIf=\"!isSentByCurrentUser\"\n class=\"str-chat__message-simple-name str-chat__message-sender-name\"\n >\n {{ message?.user?.name ? message?.user?.name : message?.user?.id }}\n </span>\n <span data-testid=\"date\" class=\"str-chat__message-simple-timestamp\">\n {{ parsedDate }}\n </span>\n </div>\n </ng-container>\n</ng-template>\n\n<ng-template #messageStatus>\n <ng-container\n *ngIf=\"\n isSentByCurrentUser &&\n ((isLastSentMessage && message?.status === 'received') ||\n message?.status === 'sending')\n \"\n >\n <ng-container *ngIf=\"message?.status === 'sending'; else sentStatus\">\n <ng-container *ngTemplateOutlet=\"sendingStatus\"></ng-container>\n </ng-container>\n <ng-template #sentStatus>\n <ng-container\n *ngIf=\"\n mode === 'main' && isMessageDeliveredAndRead && canDisplayReadStatus;\n else deliveredStatus\n \"\n >\n <ng-container *ngTemplateOutlet=\"readStatus\"></ng-container>\n </ng-container>\n </ng-template>\n <ng-template #deliveredStatus>\n <span\n *ngIf=\"mode === 'main'\"\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"delivered-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Delivered\" | translate }}\n </div>\n </popper-content>\n <stream-icon-placeholder\n data-testid=\"delivered-icon\"\n icon=\"delivered-icon\"\n ></stream-icon-placeholder>\n </span>\n </ng-template>\n <ng-template #sendingStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"sending-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div class=\"str-chat__tooltip str-chat__tooltip-angular\">\n {{ \"streamChat.Sending...\" | translate }}\n </div>\n </popper-content>\n <stream-loading-indicator-placeholder\n data-testid=\"loading-indicator\"\n ></stream-loading-indicator-placeholder>\n </span>\n </ng-template>\n <ng-template #readStatus>\n <span\n class=\"\n str-chat__message-simple-status\n str-chat__message-simple-status-angular\n str-chat__message-status\n \"\n data-testid=\"read-indicator\"\n [popper]=\"popperContent\"\n [popperTrigger]=\"popperTriggerHover\"\n [popperPlacement]=\"popperPlacementAuto\"\n [popperHideOnScroll]=\"false\"\n [popperHideOnClickOutside]=\"false\"\n (hover)=\"$event.stopPropagation()\"\n >\n <popper-content #popperContent>\n <div\n class=\"str-chat__tooltip str-chat__tooltip-angular\"\n data-testid=\"read-by-tooltip\"\n >\n {{ readByText }}\n </div>\n </popper-content>\n <stream-avatar-placeholder\n class=\"str-chat-angular__avatar-host\"\n data-test-id=\"last-read-user-avatar\"\n [size]=\"15\"\n [imageUrl]=\"lastReadUser?.image\"\n [name]=\"lastReadUser?.name || lastReadUser?.id\"\n type=\"user\"\n location=\"message-reader\"\n [user]=\"lastReadUser\"\n ></stream-avatar-placeholder>\n <span\n data-test-id=\"read-by-length\"\n *ngIf=\"isReadByMultipleUsers\"\n class=\"str-chat__message-simple-status-number\"\n >\n {{ (message?.readBy)!.length }}\n </span>\n </span>\n </ng-template>\n </ng-container>\n</ng-template>\n\n<ng-template #replyCountButton let-position=\"position\">\n <!-- eslint-disable @angular-eslint/template/conditional-complexity -->\n <div\n *ngIf=\"\n (position === 'inside-message-bubble' && themeVersion === '1') ||\n (position === 'outside-message-bubble' && themeVersion === '2')\n \"\n class=\"\n str-chat__message-simple-reply-button\n str-chat__message-replies-count-button-wrapper\n \"\n >\n <!-- eslint-enable @angular-eslint/template/conditional-complexity -->\n <button\n *ngIf=\"shouldDisplayThreadLink\"\n class=\"str-chat__message-replies-count-button\"\n data-testid=\"reply-count-button\"\n (click)=\"setAsActiveParentMessage()\"\n >\n <stream-icon-placeholder\n *ngIf=\"themeVersion === '1'\"\n stream-icon-placeholder\n icon=\"reply\"\n ></stream-icon-placeholder>\n {{message?.reply_count === 1 ? ('streamChat.1 reply' | translate) : ('streamChat.{{ replyCount }}\n replies' | translate:replyCountParam)}}\n </button>\n </div>\n</ng-template>\n", components: [{ type: AvatarPlaceholderComponent, selector: "stream-avatar-placeholder", inputs: ["name", "imageUrl", "size", "location", "channel", "user", "type"] }, { type: i2.NgxPopperjsContentComponent, selector: "popper-content" }, { type: MessageActionsBoxComponent, selector: "stream-message-actions-box", inputs: ["isOpen", "isMine", "message", "enabledActions"], outputs: ["displayedActionsCount", "isEditing"] }, { type: IconPlaceholderComponent, selector: "stream-icon-placeholder", inputs: ["icon", "size"] }, { type: MessageReactionsComponent, selector: "stream-message-reactions", inputs: ["messageId", "messageReactionCounts", "isSelectorOpen", "latestReactions", "ownReactions"], outputs: ["isSelectorOpenChange"] }, { type: AttachmentListComponent, selector: "stream-attachment-list", inputs: ["messageId", "parentMessageId", "attachments"] }, { type: LoadingIndicatorPlaceholderComponent, selector: "stream-loading-indicator-placeholder", inputs: ["size", "color"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgxPopperjsDirective, selector: "[popper]", inputs: ["popperTimeout", "popperTimeoutAfterShow", "popperApplyClass", "popper", "popperDisabled", "popperPlacement", "popperApplyArrowClass", "popperPreventOverflow", "popperHideOnClickOutside", "popperTrigger", "popperStyles", "popperAriaDescribeBy", "popperAriaRole", "popperBoundaries", "popperCloseOnClickOutside", "popperDisableAnimation", "popperDisableStyle", "popperHideOnMouseLeave", "popperHideOnScroll", "popperAppendTo", "popperModifiers", "popperPositionFixed", "popperDelay", "popperShowOnStart", "popperTarget"], outputs: ["popperOnHidden", "popperOnShown", "popperOnUpdate"], exportAs: ["popper"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i6.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }], pipes: { "translate": i6.TranslatePipe } });
4112
4191
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: MessageComponent, decorators: [{
4113
4192
  type: Component,
4114
4193
  args: [{