@banta/sdk 4.0.10 → 4.0.13

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.
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs'), require('rxjs/operators'), require('@angular/core'), require('@angular/common'), require('@angular/material/icon'), require('@angular/platform-browser'), require('@angular/material/button'), require('@angular/material/form-field'), require('@angular/material/input'), require('@angular/forms'), require('@angular/material/dialog'), require('@banta/common'), require('@angular/router'), require('@angular/material/menu'), require('@angular/material/progress-spinner'), require('@angular/cdk/text-field'), require('@angular/material/tooltip'), require('@angular/material/select')) :
3
- typeof define === 'function' && define.amd ? define('@banta/sdk', ['exports', 'rxjs', 'rxjs/operators', '@angular/core', '@angular/common', '@angular/material/icon', '@angular/platform-browser', '@angular/material/button', '@angular/material/form-field', '@angular/material/input', '@angular/forms', '@angular/material/dialog', '@banta/common', '@angular/router', '@angular/material/menu', '@angular/material/progress-spinner', '@angular/cdk/text-field', '@angular/material/tooltip', '@angular/material/select'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.banta = global.banta || {}, global.banta.sdk = {}), global.rxjs, global.rxjs.operators, global.ng.core, global.ng.common, global.ng.material.icon, global.ng.platformBrowser, global.ng.material.button, global.ng.material.formField, global.ng.material.input, global.ng.forms, global.ng.material.dialog, global.common$1, global.ng.router, global.ng.material.menu, global.ng.material.progressSpinner, global.ng.cdk.textField, global.ng.material.tooltip, global.ng.material.select));
5
- }(this, (function (exports, rxjs, operators, core, common, icon, platformBrowser, button, formField, input, forms, dialog, common$1, router, menu, progressSpinner, textField, tooltip, select) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs'), require('rxjs/operators'), require('@angular/core'), require('@angular/common'), require('@angular/material/icon'), require('@angular/platform-browser'), require('@angular/material/button'), require('@angular/material/form-field'), require('@angular/material/input'), require('@angular/forms'), require('@angular/material/dialog'), require('@banta/common'), require('@angular/router'), require('@angular/material/snack-bar'), require('@angular/material/menu'), require('@angular/material/progress-spinner'), require('@angular/cdk/text-field'), require('@angular/material/tooltip'), require('@angular/material/select')) :
3
+ typeof define === 'function' && define.amd ? define('@banta/sdk', ['exports', 'rxjs', 'rxjs/operators', '@angular/core', '@angular/common', '@angular/material/icon', '@angular/platform-browser', '@angular/material/button', '@angular/material/form-field', '@angular/material/input', '@angular/forms', '@angular/material/dialog', '@banta/common', '@angular/router', '@angular/material/snack-bar', '@angular/material/menu', '@angular/material/progress-spinner', '@angular/cdk/text-field', '@angular/material/tooltip', '@angular/material/select'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.banta = global.banta || {}, global.banta.sdk = {}), global.rxjs, global.rxjs.operators, global.ng.core, global.ng.common, global.ng.material.icon, global.ng.platformBrowser, global.ng.material.button, global.ng.material.formField, global.ng.material.input, global.ng.forms, global.ng.material.dialog, global.common$1, global.ng.router, global.ng.material.snackBar, global.ng.material.menu, global.ng.material.progressSpinner, global.ng.cdk.textField, global.ng.material.tooltip, global.ng.material.select));
5
+ }(this, (function (exports, rxjs, operators, core, common, icon, platformBrowser, button, formField, input, forms, dialog, common$1, router, snackBar, menu, progressSpinner, textField, tooltip, select) { 'use strict';
6
6
 
7
7
  function lazyConnection(options) {
8
8
  var obs = new rxjs.Observable(function (observer) {
@@ -8293,11 +8293,11 @@
8293
8293
  .map(function (x) { return x.url; }));
8294
8294
  };
8295
8295
  CommentComponent.prototype.avatarForUser = function (user) {
8296
+ var url = this.genericAvatarUrl;
8296
8297
  if (user && user.avatarUrl) {
8297
- var url = user.avatarUrl;
8298
- return "url(" + url + ")";
8298
+ url = user.avatarUrl;
8299
8299
  }
8300
- return null;
8300
+ return "url(" + url + ")";
8301
8301
  };
8302
8302
  return CommentComponent;
8303
8303
  }());
@@ -8329,6 +8329,7 @@
8329
8329
  editStarted: [{ type: core.Output }],
8330
8330
  editEnded: [{ type: core.Output }],
8331
8331
  shared: [{ type: core.Output }],
8332
+ genericAvatarUrl: [{ type: core.Input }],
8332
8333
  commentId: [{ type: core.HostBinding, args: ['attr.data-comment-id',] }],
8333
8334
  lightbox: [{ type: core.ViewChild, args: ['lightbox',] }]
8334
8335
  };
@@ -8609,18 +8610,12 @@
8609
8610
  return true;
8610
8611
  return false;
8611
8612
  };
8612
- CommentViewComponent.prototype.avatarForUser = function (user) {
8613
- var url = this.genericAvatarUrl;
8614
- if (user && user.avatarUrl)
8615
- url = user.avatarUrl;
8616
- return "url(" + url + ")";
8617
- };
8618
8613
  return CommentViewComponent;
8619
8614
  }());
8620
8615
  CommentViewComponent.decorators = [
8621
8616
  { type: core.Component, args: [{
8622
8617
  selector: 'banta-comment-view',
8623
- template: "<div class=\"message-container\">\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n\r\n <a mat-button class=\"nav\" [class.visible]=\"isViewingMore || customSortEnabled\" href=\"javascript:;\" (click)=\"showNew()\">\r\n <mat-icon>file_upload</mat-icon>\r\n New\r\n <ng-container *ngIf=\"newMessages.length >= 1\">\r\n ({{newMessages.length}})\r\n </ng-container>\r\n </a>\r\n\r\n <ng-container *ngIf=\"messages.length === 0\">\r\n <div class=\"empty-state\" *ngIf=\"showEmptyState\">\r\n Be the first to comment!\r\n </div>\r\n </ng-container>\r\n <ng-container *ngFor=\"let message of messages; trackBy: messageIdentity\">\r\n <banta-comment\r\n *ngIf=\"!message.hidden\"\r\n class=\"abbreviated\"\r\n \r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n (click)=\"isViewingMore = true\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n ></banta-comment>\r\n </ng-container>\r\n\r\n <a mat-button class=\"nav\" [class.visible]=\"hasMore && !isLoadingMore\" href=\"javascript:;\" (click)=\"showMore()\">Show more</a>\r\n\r\n <div class=\"loading-more\" *ngIf=\"isLoadingMore\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n\r\n <!-- <div style=\"color: #666\">\r\n n={{newMessages.length}}, m={{messages.length}}, o={{olderMessages.length}},\r\n v={{maxVisibleMessages}}, M={{maxMessages}}\r\n </div> -->\r\n\r\n <ng-content select=\":not([data-before])\"></ng-content>\r\n</div>\r\n",
8618
+ template: "<div class=\"message-container\">\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n\r\n <a mat-button class=\"nav\" [class.visible]=\"isViewingMore || customSortEnabled\" href=\"javascript:;\" (click)=\"showNew()\">\r\n <mat-icon>file_upload</mat-icon>\r\n New\r\n <ng-container *ngIf=\"newMessages.length >= 1\">\r\n ({{newMessages.length}})\r\n </ng-container>\r\n </a>\r\n\r\n <ng-container *ngIf=\"messages.length === 0\">\r\n <div class=\"empty-state\" *ngIf=\"showEmptyState\">\r\n Be the first to comment!\r\n </div>\r\n </ng-container>\r\n <ng-container *ngFor=\"let message of messages; trackBy: messageIdentity\">\r\n <banta-comment\r\n *ngIf=\"!message.hidden\"\r\n class=\"abbreviated\"\r\n \r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (click)=\"isViewingMore = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n ></banta-comment>\r\n </ng-container>\r\n\r\n <a mat-button class=\"nav\" [class.visible]=\"hasMore && !isLoadingMore\" href=\"javascript:;\" (click)=\"showMore()\">Show more</a>\r\n\r\n <div class=\"loading-more\" *ngIf=\"isLoadingMore\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n\r\n <!-- <div style=\"color: #666\">\r\n n={{newMessages.length}}, m={{messages.length}}, o={{olderMessages.length}},\r\n v={{maxVisibleMessages}}, M={{maxMessages}}\r\n </div> -->\r\n\r\n <ng-content select=\":not([data-before])\"></ng-content>\r\n</div>\r\n",
8624
8619
  styles: [":host{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition:opacity .2s ease-in}.message-container{flex-grow:1;overflow-x:hidden;color:#111;background:#fff;padding:.5em 1em 3em .5em;opacity:1;transition:opacity .5s ease-in-out;position:relative}.message-container.no-scroll{height:auto;overflow-y:visible}.message-container.faded{opacity:.25}.message-container .overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:10}:host.fixed-height .message-container{overflow-y:auto}:host-context(.mat-dark-theme) .message-container{color:#fff;background:#111}.empty-state{text-align:center;margin:3em;color:#666}:host-context(.mat-dark-theme) .empty-state{color:#666}a.nav{position:absolute;right:.5em;z-index:10;text-align:center;opacity:0;transition:opacity .4s ease-in-out;pointer-events:none;border-radius:2em;background:#222}a.nav.visible{opacity:1;pointer-events:auto}.loading-more{padding:2em;text-align:center;margin:0 auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}@media (max-width:400px){.message-container{padding:0 0 3em}}"]
8625
8620
  },] }
8626
8621
  ];
@@ -8654,11 +8649,12 @@
8654
8649
  * Comments component
8655
8650
  */
8656
8651
  var BantaCommentsComponent = /** @class */ (function () {
8657
- function BantaCommentsComponent(backend, elementRef, activatedRoute) {
8652
+ function BantaCommentsComponent(backend, elementRef, activatedRoute, matSnackBar) {
8658
8653
  var _this = this;
8659
8654
  this.backend = backend;
8660
8655
  this.elementRef = elementRef;
8661
8656
  this.activatedRoute = activatedRoute;
8657
+ this.matSnackBar = matSnackBar;
8662
8658
  // Loading Screen
8663
8659
  this._loadingMessage = '';
8664
8660
  this.loadingMessageVisible = false;
@@ -8684,6 +8680,12 @@
8684
8680
  this._shared = new rxjs.Subject();
8685
8681
  this._usernameSelected = new rxjs.Subject();
8686
8682
  this._avatarSelected = new rxjs.Subject();
8683
+ /**
8684
+ * Track whether we created this source. If we did not (ie it was passed in from the caller),
8685
+ * then we are not responsible for calling close(). If we do own it though, we will call close()
8686
+ * when we are done with it.
8687
+ */
8688
+ this._sourceIsOwned = false;
8687
8689
  this._subs = new rxjs.Subscription();
8688
8690
  this._sortOrder = common$1.CommentsOrder.NEWEST;
8689
8691
  this.selectedMessageVisible = false;
@@ -8695,7 +8697,8 @@
8695
8697
  this.permissionDeniedLabel = 'Send';
8696
8698
  this.postCommentLabel = 'Post a comment';
8697
8699
  this.postReplyLabel = 'Post a reply';
8698
- this.allowAttachments = false;
8700
+ this.allowAttachments = true;
8701
+ this.genericAvatarUrl = "https://gravatar.com/avatar/" + Date.now().toString(16) + "?s=512&d=robohash";
8699
8702
  this.participants = [];
8700
8703
  this.hashtags = [
8701
8704
  { hashtag: 'error', description: 'Cause an error' },
@@ -8802,13 +8805,8 @@
8802
8805
  return __awaiter(this, void 0, void 0, function () {
8803
8806
  var _this = this;
8804
8807
  return __generator(this, function (_d) {
8805
- if (this._source) {
8806
- this._source.close();
8807
- this._source = null;
8808
- }
8809
8808
  setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
8810
8809
  var _d;
8811
- var _this = this;
8812
8810
  return __generator(this, function (_e) {
8813
8811
  switch (_e.label) {
8814
8812
  case 0:
@@ -8816,14 +8814,8 @@
8816
8814
  _d = this;
8817
8815
  return [4 /*yield*/, this.backend.getSourceForTopic(topicID, { sortOrder: this.sortOrder })];
8818
8816
  case 1:
8819
- _d._source = _e.sent();
8820
- if (this.sharedCommentID) {
8821
- this.navigateToSharedComment(this.sharedCommentID);
8822
- this.sharedCommentID = null;
8823
- }
8824
- this._source.messageReceived.subscribe(function (m) { return _this.addParticipant(m); });
8825
- this._source.messageSent.subscribe(function (m) { return _this.addParticipant(m); });
8826
- this._source.messages.forEach(function (m) { return _this.addParticipant(m); });
8817
+ _d.source = _e.sent();
8818
+ this._sourceIsOwned = true;
8827
8819
  return [2 /*return*/];
8828
8820
  }
8829
8821
  });
@@ -8906,10 +8898,35 @@
8906
8898
  Object.defineProperty(BantaCommentsComponent.prototype, "source", {
8907
8899
  get: function () { return this._source; },
8908
8900
  set: function (value) {
8901
+ var _this = this;
8902
+ var _a;
8903
+ if (this._source && this._sourceIsOwned) {
8904
+ this._source.close();
8905
+ (_a = this._sourceSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
8906
+ this._source = null;
8907
+ this.participants = [];
8908
+ }
8909
8909
  this._source = value;
8910
- if (value && this.sharedCommentID) {
8911
- this.navigateToSharedComment(this.sharedCommentID);
8912
- this.sharedCommentID = null;
8910
+ this._sourceIsOwned = false; // Assume we don't own this source.
8911
+ this._sourceSubscription = new rxjs.Subscription();
8912
+ if (value) {
8913
+ if (this.sharedCommentID) {
8914
+ this.navigateToSharedComment(this.sharedCommentID);
8915
+ this.sharedCommentID = null;
8916
+ }
8917
+ this._source.messages.forEach(function (m) { return _this.addParticipant(m); });
8918
+ this._sourceSubscription.add(this._source.messageReceived.subscribe(function (m) { return _this.addParticipant(m); }));
8919
+ this._sourceSubscription.add(this._source.messageSent.subscribe(function (m) { return _this.addParticipant(m); }));
8920
+ this._sourceSubscription.add(this._source.messageUpdated.subscribe(function (msg) {
8921
+ var _a;
8922
+ console.log("comments received message: ", msg);
8923
+ if (msg.id === ((_a = _this.selectedMessage) === null || _a === void 0 ? void 0 : _a.id) && msg.hidden) {
8924
+ _this.unselectMessage();
8925
+ _this.matSnackBar.open("The thread you were viewing was removed.", undefined, {
8926
+ duration: 2500
8927
+ });
8928
+ }
8929
+ }));
8913
8930
  }
8914
8931
  },
8915
8932
  enumerable: false,
@@ -9333,14 +9350,15 @@
9333
9350
  BantaCommentsComponent.decorators = [
9334
9351
  { type: core.Component, args: [{
9335
9352
  selector: 'banta-comments',
9336
- template: "<ng-container *ngIf=\"loading\">\r\n <div class=\"loading-screen\" [class.visible]=\"showLoadingScreen\">\r\n <h1>Loading Comments</h1>\r\n <div>\r\n <mat-spinner [diameter]=\"300\" [strokeWidth]=\"2\"></mat-spinner>\r\n </div>\r\n\r\n <p class=\"loading-message\" [class.visible]=\"loadingMessageVisible\">{{loadingMessage}}</p>\r\n </div>\r\n</ng-container>\r\n<ng-container *ngIf=\"!loading\">\r\n <div class=\"focused\" [class.visible]=\"selectedMessageVisible\" *ngIf=\"selectedMessage\">\r\n\r\n <div>\r\n <a mat-button href=\"javascript:;\" (click)=\"unselectMessage()\">\r\n <mat-icon>arrow_back</mat-icon>\r\n Latest Comments\r\n </a>\r\n </div>\r\n\r\n <banta-comment\r\n [message]=\"selectedMessage\"\r\n [liking]=\"selectedMessage.transientState.liking\"\r\n [mine]=\"user?.id === selectedMessage.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"false\"\r\n [editing]=\"selectedMessage.transientState.editing\"\r\n (editStarted)=\"startEditing(selectedMessage)\"\r\n (editEnded)=\"selectedMessage.transientState.editing = false\"\r\n (edited)=\"saveEdit(selectedMessage, $event)\"\r\n (userSelected)=\"selectMessageUser(selectedMessage)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(source, selectedMessage)\"\r\n (unliked)=\"unlikeMessage(source, selectedMessage)\"\r\n (reported)=\"reportMessage(selectedMessage)\"\r\n (selected)=\"selectMessage(selectedMessage)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage(selectedMessage)\"\r\n ></banta-comment>\r\n\r\n <div class=\"replies\">\r\n\r\n <ng-container *ngIf=\"!selectedMessageThread\">\r\n <div class=\"loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"selectedMessageThread\">\r\n <banta-comment-view\r\n [source]=\"selectedMessageThread\"\r\n [allowReplies]=\"false\"\r\n [fixedHeight]=\"false\"\r\n [showEmptyState]=\"false\"\r\n [newestLast]=\"true\"\r\n (liked)=\"likeMessage(selectedMessageThread, $event)\"\r\n (unliked)=\"unlikeMessage(selectedMessageThread, $event)\"\r\n (messageEdited)=\"editMessage(selectedMessageThread, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n\r\n <banta-comment-field\r\n [sendLabel]=\"replyLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n (signInSelected)=\"showSignIn()\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n [source]=\"selectedMessageThread\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [signInLabel]=\"signInLabel\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\r\n [submit]=\"sendReply\"\r\n [allowAttachments]=\"allowAttachments\"\r\n >\r\n <ng-content select=\".reply-send-options\"></ng-content>\r\n </banta-comment-field>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"main\" [class.hidden]=\"selectedMessage\">\r\n <banta-comment-field\r\n [source]=\"source\"\r\n [user]=\"user\"\r\n [sendLabel]=\"sendLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [signInLabel]=\"signInLabel\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n [label]=\"postCommentLabel\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n (signInSelected)=\"showSignIn()\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [submit]=\"sendMessage\"\r\n [allowAttachments]=\"allowAttachments\"\r\n >\r\n \r\n </banta-comment-field>\r\n\r\n <banta-comment-sort\r\n [(sort)]=\"sortOrder\"></banta-comment-sort>\r\n\r\n <banta-comment-view\r\n [class.faded]=\"selectedMessage\"\r\n [source]=\"source\"\r\n [fixedHeight]=\"fixedHeight\"\r\n [maxMessages]=\"maxMessages\"\r\n [maxVisibleMessages]=\"maxVisibleMessages\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (userSelected)=\"selectMessageUser($event)\"\r\n (sortOrderChanged)=\"sortOrder = $event\"\r\n (selected)=\"selectMessage($event)\"\r\n (liked)=\"likeMessage(source, $event)\"\r\n (unliked)=\"unlikeMessage(source, $event)\"\r\n (messageEdited)=\"editMessage(source, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n </div>\r\n</ng-container>\r\n",
9353
+ template: "<ng-container *ngIf=\"loading\">\r\n <div class=\"loading-screen\" [class.visible]=\"showLoadingScreen\">\r\n <h1>Loading Comments</h1>\r\n <div>\r\n <mat-spinner [diameter]=\"300\" [strokeWidth]=\"2\"></mat-spinner>\r\n </div>\r\n\r\n <p class=\"loading-message\" [class.visible]=\"loadingMessageVisible\">{{loadingMessage}}</p>\r\n </div>\r\n</ng-container>\r\n<ng-container *ngIf=\"!loading\">\r\n <div class=\"focused\" [class.visible]=\"selectedMessageVisible\" *ngIf=\"selectedMessage\">\r\n\r\n <div>\r\n <a mat-button href=\"javascript:;\" (click)=\"unselectMessage()\">\r\n <mat-icon>arrow_back</mat-icon>\r\n Latest Comments\r\n </a>\r\n </div>\r\n\r\n <banta-comment\r\n [message]=\"selectedMessage\"\r\n [liking]=\"selectedMessage.transientState.liking\"\r\n [mine]=\"user?.id === selectedMessage.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"false\"\r\n [editing]=\"selectedMessage.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (editStarted)=\"startEditing(selectedMessage)\"\r\n (editEnded)=\"selectedMessage.transientState.editing = false\"\r\n (edited)=\"saveEdit(selectedMessage, $event)\"\r\n (userSelected)=\"selectMessageUser(selectedMessage)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(source, selectedMessage)\"\r\n (unliked)=\"unlikeMessage(source, selectedMessage)\"\r\n (reported)=\"reportMessage(selectedMessage)\"\r\n (selected)=\"selectMessage(selectedMessage)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage(selectedMessage)\"\r\n ></banta-comment>\r\n\r\n <div class=\"replies\">\r\n\r\n <ng-container *ngIf=\"!selectedMessageThread\">\r\n <div class=\"loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"selectedMessageThread\">\r\n <banta-comment-view\r\n [source]=\"selectedMessageThread\"\r\n [allowReplies]=\"false\"\r\n [fixedHeight]=\"false\"\r\n [showEmptyState]=\"false\"\r\n [newestLast]=\"true\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (liked)=\"likeMessage(selectedMessageThread, $event)\"\r\n (unliked)=\"unlikeMessage(selectedMessageThread, $event)\"\r\n (messageEdited)=\"editMessage(selectedMessageThread, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n\r\n <banta-comment-field\r\n [sendLabel]=\"replyLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n (signInSelected)=\"showSignIn()\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n [source]=\"selectedMessageThread\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [signInLabel]=\"signInLabel\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\r\n [submit]=\"sendReply\"\r\n [allowAttachments]=\"allowAttachments\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n >\r\n <ng-content select=\".reply-send-options\"></ng-content>\r\n </banta-comment-field>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div class=\"main\" [class.hidden]=\"selectedMessage\">\r\n <banta-comment-field\r\n [source]=\"source\"\r\n [user]=\"user\"\r\n [sendLabel]=\"sendLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [signInLabel]=\"signInLabel\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n [label]=\"postCommentLabel\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n (signInSelected)=\"showSignIn()\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [submit]=\"sendMessage\"\r\n [allowAttachments]=\"allowAttachments\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n >\r\n \r\n </banta-comment-field>\r\n\r\n <banta-comment-sort\r\n [(sort)]=\"sortOrder\"></banta-comment-sort>\r\n\r\n <banta-comment-view\r\n [class.faded]=\"selectedMessage\"\r\n [source]=\"source\"\r\n [fixedHeight]=\"fixedHeight\"\r\n [maxMessages]=\"maxMessages\"\r\n [maxVisibleMessages]=\"maxVisibleMessages\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (userSelected)=\"selectMessageUser($event)\"\r\n (sortOrderChanged)=\"sortOrder = $event\"\r\n (selected)=\"selectMessage($event)\"\r\n (liked)=\"likeMessage(source, $event)\"\r\n (unliked)=\"unlikeMessage(source, $event)\"\r\n (messageEdited)=\"editMessage(source, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n </div>\r\n</ng-container>\r\n",
9337
9354
  styles: [":host{display:flex;flex-direction:column}@-webkit-keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}@keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}.focused{-webkit-animation-name:select-comment;animation-name:select-comment;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.focused .replies{margin-top:1em;margin-left:4em}banta-comment-view{opacity:1;transition:opacity .4s ease-in-out}banta-comment-view.faded{opacity:.25}.loading{display:block;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto;min-height:16em}.main.hidden{display:none}@media (max-width:500px){.focused .replies{margin-left:0}}.loading-screen{text-align:center;opacity:0;transition:opacity .25s ease-in-out}.loading-screen.visible{opacity:1}.loading-screen h1{font-weight:100}.loading-screen mat-spinner{margin:5em auto}.loading-screen .loading-message{opacity:0;transition:opacity .25s ease-in-out;width:500px;max-width:100%;margin:0 auto}.loading-screen .loading-message.visible{opacity:1}banta-comment-sort{margin:0 0 0 auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;display:block}@media (max-width:450px){banta-comment-sort{margin:0;width:100%}}"]
9338
9355
  },] }
9339
9356
  ];
9340
9357
  BantaCommentsComponent.ctorParameters = function () { return [
9341
9358
  { type: ChatBackendBase },
9342
9359
  { type: core.ElementRef },
9343
- { type: router.ActivatedRoute }
9360
+ { type: router.ActivatedRoute },
9361
+ { type: snackBar.MatSnackBar }
9344
9362
  ]; };
9345
9363
  BantaCommentsComponent.propDecorators = {
9346
9364
  loadingMessages: [{ type: core.Input }],
@@ -9474,6 +9492,14 @@
9474
9492
  this.autoCompleteSelected = 0;
9475
9493
  this.chatMessageAttachments = [];
9476
9494
  }
9495
+ Object.defineProperty(CommentFieldComponent.prototype, "userAvatarUrl", {
9496
+ get: function () {
9497
+ var _a;
9498
+ return ((_a = this.user) === null || _a === void 0 ? void 0 : _a.avatarUrl) || this.genericAvatarUrl;
9499
+ },
9500
+ enumerable: false,
9501
+ configurable: true
9502
+ });
9477
9503
  Object.defineProperty(CommentFieldComponent.prototype, "permissionDeniedError", {
9478
9504
  get: function () {
9479
9505
  return this._permissionDeniedError;
@@ -9525,7 +9551,7 @@
9525
9551
  CommentFieldComponent.prototype.autocomplete = function (replacement) {
9526
9552
  return __awaiter(this, void 0, void 0, function () {
9527
9553
  var el;
9528
- return __generator(this, function (_a) {
9554
+ return __generator(this, function (_b) {
9529
9555
  el = this.textareaEl.nativeElement;
9530
9556
  this.text = this.text.slice(0, el.selectionStart - this.completionPrefix.length) + replacement + this.text.slice(el.selectionStart);
9531
9557
  return [2 /*return*/];
@@ -9535,7 +9561,7 @@
9535
9561
  CommentFieldComponent.prototype.insert = function (str) {
9536
9562
  return __awaiter(this, void 0, void 0, function () {
9537
9563
  var el;
9538
- return __generator(this, function (_a) {
9564
+ return __generator(this, function (_b) {
9539
9565
  el = this.textareaEl.nativeElement;
9540
9566
  this.text = this.text.slice(0, el.selectionStart) + str + this.text.slice(el.selectionStart);
9541
9567
  return [2 /*return*/];
@@ -9545,8 +9571,8 @@
9545
9571
  CommentFieldComponent.prototype.onKeyDown = function (event) {
9546
9572
  return __awaiter(this, void 0, void 0, function () {
9547
9573
  var _this = this;
9548
- return __generator(this, function (_a) {
9549
- switch (_a.label) {
9574
+ return __generator(this, function (_b) {
9575
+ switch (_b.label) {
9550
9576
  case 0:
9551
9577
  if (this.autocompleteVisible) {
9552
9578
  if (event.key === 'Escape') {
@@ -9581,7 +9607,7 @@
9581
9607
  if (!(event.key === 'Enter' && event.ctrlKey)) return [3 /*break*/, 2];
9582
9608
  return [4 /*yield*/, this.sendMessage()];
9583
9609
  case 1:
9584
- _a.sent();
9610
+ _b.sent();
9585
9611
  return [2 /*return*/];
9586
9612
  case 2:
9587
9613
  if (this.completionFunc) {
@@ -9666,16 +9692,16 @@
9666
9692
  CommentFieldComponent.prototype.sendMessage = function () {
9667
9693
  return __awaiter(this, void 0, void 0, function () {
9668
9694
  var text, message, e_1;
9669
- return __generator(this, function (_a) {
9670
- switch (_a.label) {
9695
+ return __generator(this, function (_b) {
9696
+ switch (_b.label) {
9671
9697
  case 0:
9672
9698
  if (!this.source)
9673
9699
  return [2 /*return*/];
9674
9700
  this.sending = true;
9675
9701
  this.sendError = null;
9676
- _a.label = 1;
9702
+ _b.label = 1;
9677
9703
  case 1:
9678
- _a.trys.push([1, , 7, 8]);
9704
+ _b.trys.push([1, , 7, 8]);
9679
9705
  text = (this.text || '').trim();
9680
9706
  if (text === '')
9681
9707
  return [2 /*return*/];
@@ -9687,19 +9713,19 @@
9687
9713
  message: text,
9688
9714
  attachments: this.chatMessageAttachments
9689
9715
  };
9690
- _a.label = 2;
9716
+ _b.label = 2;
9691
9717
  case 2:
9692
- _a.trys.push([2, 4, , 6]);
9718
+ _b.trys.push([2, 4, , 6]);
9693
9719
  return [4 /*yield*/, this.submit(message)];
9694
9720
  case 3:
9695
- _a.sent();
9721
+ _b.sent();
9696
9722
  this.text = '';
9697
9723
  return [3 /*break*/, 6];
9698
9724
  case 4:
9699
- e_1 = _a.sent();
9725
+ e_1 = _b.sent();
9700
9726
  return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 1000); })];
9701
9727
  case 5:
9702
- _a.sent();
9728
+ _b.sent();
9703
9729
  this.indicateError(e_1.message);
9704
9730
  return [3 /*break*/, 6];
9705
9731
  case 6: return [3 /*break*/, 8];
@@ -9727,8 +9753,8 @@
9727
9753
  CommentFieldComponent.decorators = [
9728
9754
  { type: core.Component, args: [{
9729
9755
  selector: 'banta-comment-field',
9730
- template: "<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n <div class=\"avatar-container\">\r\n <a href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"showEditAvatar()\"\r\n [style.background-image]=\"'url(' + user?.avatarUrl + ')'\"\r\n ></a>\r\n </div>\r\n <div class=\"text-container\">\r\n <div class=\"field-container\">\r\n <div class=\"field-row\">\r\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>{{label}}</mat-label>\r\n <textarea\r\n #textarea\r\n name=\"message\"\r\n [placeholder]=\"placeholder\"\r\n matInput\r\n cdkTextareaAutosize\r\n (keydown)=\"onKeyDown($event)\"\r\n (blur)=\"onBlur()\"\r\n [disabled]=\"sending\"\r\n [(ngModel)]=\"text\"></textarea>\r\n </mat-form-field>\r\n <div class=\"options-line\">\r\n <mat-spinner *ngIf=\"sending\" class=\"icon loading\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n <div *ngIf=\"sendError\" class=\"error-message\" [class.expanded]=\"expandError\" [matTooltip]=\"sendError.message\" (click)=\"alertError()\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div class=\"custom\">\r\n <ng-content></ng-content>\r\n </div>\r\n <banta-attachment-button (addedAttachment)=\"addedAttachment($event)\" *ngIf=\"allowAttachments\"></banta-attachment-button>\r\n <emoji-selector-button (selected)=\"insertEmoji($event)\"></emoji-selector-button>\r\n </div>\r\n \r\n </div>\r\n <div #autocompleteContainer class=\"autocomplete-container\">\r\n <div #autocomplete class=\"autocomplete\" [class.visible]=\"autocompleteVisible\">\r\n\r\n <div>\r\n <strong>{{completionPrefix}}</strong>...\r\n </div>\r\n <a\r\n mat-button\r\n *ngFor=\"let option of autocompleteOptions; index as index\"\r\n (click)=\"activateAutoComplete(option)\"\r\n [class.active]=\"autoCompleteSelected === index\"\r\n >\r\n {{option.label}}\r\n </a>\r\n </div>\r\n </div>\r\n\r\n\r\n <div *ngIf=\"chatMessageAttachments && chatMessageAttachments.length\" class=\"message-attachments-container\">\r\n <div *ngFor=\"let attachment of chatMessageAttachments; index as attachmentIndex\"\r\n class=\"message-attachment\">\r\n <button (click)=\"removeAttachment(attachmentIndex)\" mat-mini-fab color=\"primary\" class=\"remove-img\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n <img [src]=\"attachment.url\" alt=\"Message Attachment\">\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n <div class=\"actions\">\r\n <ng-container *ngIf=\"!user\">\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"showSignIn()\"\r\n >{{signInLabel}}</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"user\">\r\n <button\r\n mat-raised-button\r\n class=\"send\"\r\n color=\"primary\"\r\n [disabled]=\"canComment && ((!text && !chatMessageAttachments.length) || sending)\"\r\n >\r\n <ng-container *ngIf=\"canComment\">\r\n <mat-icon *ngIf=\"!sending\">chevron_right</mat-icon>\r\n <mat-spinner *ngIf=\"sending\" class=\"icon\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n </ng-container>\r\n <span class=\"label\">\r\n <ng-container *ngIf=\"!canComment\">\r\n {{permissionDeniedLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"canComment\">\r\n <ng-container *ngIf=\"!sending\">\r\n {{sendLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"sending\">\r\n {{sendingLabel}}\r\n </ng-container>\r\n </ng-container>\r\n </span>\r\n </button>\r\n </ng-container>\r\n </div>\r\n</form>",
9731
- styles: ["@-webkit-keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}:host{margin:0 2em 0 0;display:block;-webkit-animation-name:comment-field-appear;animation-name:comment-field-appear;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-delay:.4s;animation-delay:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.avatar-container{width:calc(48px + 1.75em);display:flex;justify-content:flex-end;flex-shrink:0}.avatar-container .avatar{width:48px;height:48px;background:pink;border-radius:100%;background-size:cover;background-repeat:no-repeat;background-position:50%;margin-top:.75em;margin-right:.75em}form{display:flex;padding:.5em;align-items:center}form .text-container{position:relative;display:flex;flex-grow:1;min-width:0}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .options-line{display:flex;align-items:center}form .text-container .options-line>*{flex-shrink:0}form .text-container .options-line .error-message{left:.5em;bottom:.5em;color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:max-width 2s ease-in-out;text-overflow:ellipsis;overflow:hidden;flex-shrink:1}form .text-container .options-line .error-message.expanded,form .text-container .options-line .error-message:hover{max-width:100%}form .text-container .options-line .error-message mat-icon{vertical-align:middle}form input[type=text]{background:#000;color:#fff;border:1px solid #333;width:100%;height:1em}form .actions{margin-left:1em;flex-shrink:0}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start;min-width:0}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column;min-width:0}form.new-message mat-form-field{width:100%}form.new-message mat-form-field ::ng-deep .mat-form-field-wrapper{padding-bottom:0}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{width:calc(100% - 2em);position:relative;pointer-events:none;top:-2em}.autocomplete{visibility:hidden;pointer-events:none;position:absolute;background:#333;padding:.5em;display:flex;flex-direction:column;z-index:100}.autocomplete.visible{visibility:visible;pointer-events:auto}.autocomplete a{width:100%;text-align:left}.autocomplete a.active{background:#555}@media (max-width:500px){:host{margin:0}.avatar-container{width:auto;flex-shrink:0}.avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}button.send{min-width:auto;margin-top:1.5em}button.send .label{display:none}}.message-attachments-container{display:flex;gap:20px}.message-attachments-container .message-attachment{width:300px;position:relative}.message-attachments-container .message-attachment img{width:300px;border-radius:10px}.message-attachments-container .message-attachment .remove-img{position:absolute;right:10px;top:10px;margin:0}.field-row{position:relative}"]
9756
+ template: "<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n <div class=\"avatar-container\">\r\n <a href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"showEditAvatar()\"\r\n [style.background-image]=\"'url(' + userAvatarUrl + ')'\"\r\n ></a>\r\n </div>\r\n <div class=\"text-container\">\r\n <div class=\"field-container\">\r\n <div class=\"field-row\">\r\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>{{label}}</mat-label>\r\n <textarea\r\n #textarea\r\n name=\"message\"\r\n [placeholder]=\"placeholder\"\r\n matInput\r\n cdkTextareaAutosize\r\n (keydown)=\"onKeyDown($event)\"\r\n (blur)=\"onBlur()\"\r\n [disabled]=\"sending\"\r\n [(ngModel)]=\"text\"></textarea>\r\n </mat-form-field>\r\n <div class=\"options-line\">\r\n <mat-spinner *ngIf=\"sending\" class=\"icon loading\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n <div *ngIf=\"sendError\" class=\"error-message\" [class.expanded]=\"expandError\" [matTooltip]=\"sendError.message\" (click)=\"alertError()\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div class=\"custom\">\r\n <ng-content></ng-content>\r\n </div>\r\n <banta-attachment-button (addedAttachment)=\"addedAttachment($event)\" *ngIf=\"allowAttachments\"></banta-attachment-button>\r\n <emoji-selector-button (selected)=\"insertEmoji($event)\"></emoji-selector-button>\r\n </div>\r\n \r\n </div>\r\n <div #autocompleteContainer class=\"autocomplete-container\">\r\n <div #autocomplete class=\"autocomplete\" [class.visible]=\"autocompleteVisible\">\r\n\r\n <div>\r\n <strong>{{completionPrefix}}</strong>...\r\n </div>\r\n <a\r\n mat-button\r\n *ngFor=\"let option of autocompleteOptions; index as index\"\r\n (click)=\"activateAutoComplete(option)\"\r\n [class.active]=\"autoCompleteSelected === index\"\r\n >\r\n {{option.label}}\r\n </a>\r\n </div>\r\n </div>\r\n\r\n\r\n <div *ngIf=\"chatMessageAttachments && chatMessageAttachments.length\" class=\"message-attachments-container\">\r\n <div *ngFor=\"let attachment of chatMessageAttachments; index as attachmentIndex\"\r\n class=\"message-attachment\">\r\n <button (click)=\"removeAttachment(attachmentIndex)\" mat-mini-fab color=\"primary\" class=\"remove-img\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n <img [src]=\"attachment.url\" alt=\"Message Attachment\">\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n <div class=\"actions\">\r\n <ng-container *ngIf=\"!user\">\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"showSignIn()\"\r\n >{{signInLabel}}</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"user\">\r\n <button\r\n mat-raised-button\r\n class=\"send\"\r\n color=\"primary\"\r\n [disabled]=\"canComment && ((!text && !chatMessageAttachments.length) || sending)\"\r\n >\r\n <ng-container *ngIf=\"canComment\">\r\n <mat-icon *ngIf=\"!sending\">chevron_right</mat-icon>\r\n <mat-spinner *ngIf=\"sending\" class=\"icon\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n </ng-container>\r\n <span class=\"label\">\r\n <ng-container *ngIf=\"!canComment\">\r\n {{permissionDeniedLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"canComment\">\r\n <ng-container *ngIf=\"!sending\">\r\n {{sendLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"sending\">\r\n {{sendingLabel}}\r\n </ng-container>\r\n </ng-container>\r\n </span>\r\n </button>\r\n </ng-container>\r\n </div>\r\n</form>",
9757
+ styles: ["@-webkit-keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}:host{margin:0 2em 0 0;display:block;-webkit-animation-name:comment-field-appear;animation-name:comment-field-appear;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-delay:.4s;animation-delay:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.avatar-container{width:calc(48px + 1.75em);display:flex;justify-content:flex-end;flex-shrink:0}.avatar-container .avatar{width:48px;height:48px;background:#000;border-radius:100%;background-size:cover;background-repeat:no-repeat;background-position:50%;margin-top:.75em;margin-right:.75em}form{display:flex;padding:.5em;align-items:center}form .text-container{position:relative;display:flex;flex-grow:1;min-width:0}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .options-line{display:flex;align-items:center}form .text-container .options-line>*{flex-shrink:0}form .text-container .options-line .error-message{left:.5em;bottom:.5em;color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:max-width 2s ease-in-out;text-overflow:ellipsis;overflow:hidden;flex-shrink:1}form .text-container .options-line .error-message.expanded,form .text-container .options-line .error-message:hover{max-width:100%}form .text-container .options-line .error-message mat-icon{vertical-align:middle}form input[type=text]{background:#000;color:#fff;border:1px solid #333;width:100%;height:1em}form .actions{margin-left:1em;flex-shrink:0}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start;min-width:0}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column;min-width:0}form.new-message mat-form-field{width:100%}form.new-message mat-form-field ::ng-deep .mat-form-field-wrapper{padding-bottom:0}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{width:calc(100% - 2em);position:relative;pointer-events:none;top:-2em}.autocomplete{visibility:hidden;pointer-events:none;position:absolute;background:#333;padding:.5em;display:flex;flex-direction:column;z-index:100}.autocomplete.visible{visibility:visible;pointer-events:auto}.autocomplete a{width:100%;text-align:left}.autocomplete a.active{background:#555}@media (max-width:500px){:host{margin:0}.avatar-container{width:auto;flex-shrink:0}.avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}button.send{min-width:auto;margin-top:1.5em}button.send .label{display:none}}.message-attachments-container{display:flex;gap:20px}.message-attachments-container .message-attachment{width:300px;position:relative}.message-attachments-container .message-attachment img{width:300px;border-radius:10px}.message-attachments-container .message-attachment .remove-img{position:absolute;right:10px;top:10px;margin:0}.field-row{position:relative}"]
9732
9758
  },] }
9733
9759
  ];
9734
9760
  CommentFieldComponent.propDecorators = {
@@ -9751,6 +9777,7 @@
9751
9777
  textareaEl: [{ type: core.ViewChild, args: ['textarea',] }],
9752
9778
  hashtags: [{ type: core.Input }],
9753
9779
  participants: [{ type: core.Input }],
9780
+ genericAvatarUrl: [{ type: core.Input }],
9754
9781
  permissionDeniedError: [{ type: core.Output }],
9755
9782
  submit: [{ type: core.Input }]
9756
9783
  };
@@ -9856,7 +9883,7 @@
9856
9883
  { type: core.Component, args: [{
9857
9884
  selector: 'banta-attachment-button',
9858
9885
  template: "<button matTooltip=\"Add an image or gif\" #button type=\"button\" mat-icon-button (click)=\"show()\">\r\n\t<mat-icon>image</mat-icon>\r\n</button>\r\n<input style=\"display: none;\" #fileUpload [multiple]=\"false\" (change)=\"fileChange($event)\" type=\"file\" >",
9859
- styles: [""]
9886
+ styles: ["button{color:#666}"]
9860
9887
  },] }
9861
9888
  ];
9862
9889
  AttachmentButtonComponent.ctorParameters = function () { return [
@@ -9915,6 +9942,7 @@
9915
9942
  _this.state = 'connecting';
9916
9943
  _this.messageMap = new Map();
9917
9944
  _this._messageReceived = new rxjs.Subject();
9945
+ _this._messageUpdated = new rxjs.Subject();
9918
9946
  _this._messageSent = new rxjs.Subject();
9919
9947
  _this.messages = [];
9920
9948
  _this.ready = new Promise(function (resolve) { return _this.markReady = resolve; });
@@ -10037,6 +10065,7 @@
10037
10065
  ChatSource.prototype.onChatMessage = function (message) {
10038
10066
  if (this.messageMap.has(message.id)) {
10039
10067
  Object.assign(this.messageMap.get(message.id), message);
10068
+ this._messageUpdated.next(message);
10040
10069
  }
10041
10070
  else if (!message.hidden) {
10042
10071
  // Only process non-hidden messages through here.
@@ -10051,6 +10080,11 @@
10051
10080
  enumerable: false,
10052
10081
  configurable: true
10053
10082
  });
10083
+ Object.defineProperty(ChatSource.prototype, "messageUpdated", {
10084
+ get: function () { return this._messageUpdated.asObservable(); },
10085
+ enumerable: false,
10086
+ configurable: true
10087
+ });
10054
10088
  Object.defineProperty(ChatSource.prototype, "messageSent", {
10055
10089
  get: function () { return this._messageSent.asObservable(); },
10056
10090
  enumerable: false,
@@ -10294,7 +10328,8 @@
10294
10328
  dialog.MatDialogModule,
10295
10329
  formField.MatFormFieldModule,
10296
10330
  input.MatInputModule,
10297
- progressSpinner.MatProgressSpinnerModule
10331
+ progressSpinner.MatProgressSpinnerModule,
10332
+ snackBar.MatSnackBarModule
10298
10333
  ],
10299
10334
  declarations: [
10300
10335
  BantaComponent,