@banta/sdk 3.3.9 → 4.0.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 (64) hide show
  1. package/banta-sdk.metadata.json +1 -1
  2. package/bundles/banta-sdk.umd.js +1142 -410
  3. package/bundles/banta-sdk.umd.js.map +1 -1
  4. package/bundles/banta-sdk.umd.min.js +1 -1
  5. package/bundles/banta-sdk.umd.min.js.map +1 -1
  6. package/esm2015/banta-sdk.js +1 -1
  7. package/esm2015/lib/banta/banta.component.js +10 -16
  8. package/esm2015/lib/banta-logo.component.js +1 -1
  9. package/esm2015/lib/banta-sdk.module.js +10 -4
  10. package/esm2015/lib/chat/banta-chat/banta-chat.component.js +15 -18
  11. package/esm2015/lib/chat/chat-message/chat-message.component.js +3 -3
  12. package/esm2015/lib/chat/chat-view/chat-view.component.js +8 -7
  13. package/esm2015/lib/chat/chat.module.js +1 -1
  14. package/esm2015/lib/chat/index.js +1 -1
  15. package/esm2015/lib/chat/live-chat-message.component.js +3 -3
  16. package/esm2015/lib/chat-backend-base.js +17 -0
  17. package/esm2015/lib/chat-backend.js +74 -0
  18. package/esm2015/lib/chat-source-base.js +2 -0
  19. package/esm2015/lib/chat-source.js +151 -0
  20. package/esm2015/lib/comments/banta-comments/banta-comments.component.js +331 -172
  21. package/esm2015/lib/comments/comment/comment.component.js +56 -18
  22. package/esm2015/lib/comments/comment-field/comment-field.component.js +17 -15
  23. package/esm2015/lib/comments/comment-sort/comment-sort.component.js +1 -1
  24. package/esm2015/lib/comments/comment-view/comment-view.component.js +78 -40
  25. package/esm2015/lib/comments/comments.module.js +1 -1
  26. package/esm2015/lib/comments/index.js +1 -1
  27. package/esm2015/lib/comments/live-comment.component.js +3 -3
  28. package/esm2015/lib/common/common.module.js +1 -1
  29. package/esm2015/lib/common/index.js +1 -3
  30. package/esm2015/lib/common/lazy-connection.js +1 -1
  31. package/esm2015/lib/common/timestamp.component.js +1 -1
  32. package/esm2015/lib/emoji/emoji-selector-button.component.js +1 -1
  33. package/esm2015/lib/emoji/emoji-selector-panel/emoji-selector-panel.component.js +2 -2
  34. package/esm2015/lib/emoji/emoji.module.js +1 -1
  35. package/esm2015/lib/emoji/emojis.js +1 -1
  36. package/esm2015/lib/emoji/index.js +1 -1
  37. package/esm2015/lib/index.js +6 -1
  38. package/esm2015/lib/live-message.component.js +1 -1
  39. package/esm2015/lib/sdk-options.js +2 -0
  40. package/esm2015/public-api.js +1 -1
  41. package/fesm2015/banta-sdk.js +750 -308
  42. package/fesm2015/banta-sdk.js.map +1 -1
  43. package/lib/banta/banta.component.d.ts +8 -9
  44. package/lib/banta-sdk.module.d.ts +2 -1
  45. package/lib/chat/banta-chat/banta-chat.component.d.ts +8 -10
  46. package/lib/chat/chat-view/chat-view.component.d.ts +7 -4
  47. package/lib/chat/live-chat-message.component.d.ts +2 -2
  48. package/lib/chat-backend-base.d.ts +22 -0
  49. package/lib/chat-backend.d.ts +21 -0
  50. package/lib/chat-source-base.d.ts +31 -0
  51. package/lib/chat-source.d.ts +38 -0
  52. package/lib/comments/banta-comments/banta-comments.component.d.ts +65 -60
  53. package/lib/comments/comment/comment.component.d.ts +25 -5
  54. package/lib/comments/comment-field/comment-field.component.d.ts +7 -3
  55. package/lib/comments/comment-view/comment-view.component.d.ts +26 -8
  56. package/lib/comments/live-comment.component.d.ts +2 -2
  57. package/lib/common/index.d.ts +0 -2
  58. package/lib/index.d.ts +5 -0
  59. package/lib/sdk-options.d.ts +4 -0
  60. package/package.json +2 -2
  61. package/esm2015/lib/common/banta.service.js +0 -21
  62. package/esm2015/lib/common/chat-backend.service.js +0 -7
  63. package/lib/common/banta.service.d.ts +0 -9
  64. package/lib/common/chat-backend.service.d.ts +0 -14
@@ -17,34 +17,6 @@
17
17
  return obs.pipe(operators.publish()).refCount();
18
18
  }
19
19
 
20
- var BantaService = /** @class */ (function () {
21
- function BantaService() {
22
- this._userChanged = new rxjs.BehaviorSubject(null);
23
- }
24
- Object.defineProperty(BantaService.prototype, "userChanged", {
25
- get: function () {
26
- return this._userChanged;
27
- },
28
- enumerable: false,
29
- configurable: true
30
- });
31
- Object.defineProperty(BantaService.prototype, "user", {
32
- get: function () {
33
- return this._user;
34
- },
35
- set: function (user) {
36
- this._user = user;
37
- this._userChanged.next(user);
38
- },
39
- enumerable: false,
40
- configurable: true
41
- });
42
- return BantaService;
43
- }());
44
- BantaService.decorators = [
45
- { type: core.Injectable }
46
- ];
47
-
48
20
  var TimestampComponent = /** @class */ (function () {
49
21
  function TimestampComponent() {
50
22
  this.relative = '';
@@ -149,15 +121,6 @@
149
121
  value: [{ type: core.Input }]
150
122
  };
151
123
 
152
- var ChatBackendService = /** @class */ (function () {
153
- function ChatBackendService() {
154
- }
155
- return ChatBackendService;
156
- }());
157
- ChatBackendService.decorators = [
158
- { type: core.Injectable }
159
- ];
160
-
161
124
  var COMPONENTS = [
162
125
  TimestampComponent
163
126
  ];
@@ -176,7 +139,7 @@
176
139
  },] }
177
140
  ];
178
141
 
179
- /*! *****************************************************************************
142
+ /******************************************************************************
180
143
  Copyright (c) Microsoft Corporation.
181
144
 
182
145
  Permission to use, copy, modify, and/or distribute this software for any
@@ -338,7 +301,11 @@
338
301
  var __createBinding = Object.create ? (function (o, m, k, k2) {
339
302
  if (k2 === undefined)
340
303
  k2 = k;
341
- Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } });
304
+ var desc = Object.getOwnPropertyDescriptor(m, k);
305
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
306
+ desc = { enumerable: true, get: function () { return m[k]; } };
307
+ }
308
+ Object.defineProperty(o, k2, desc);
342
309
  }) : (function (o, m, k, k2) {
343
310
  if (k2 === undefined)
344
311
  k2 = k;
@@ -492,6 +459,11 @@
492
459
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver))
493
460
  throw new TypeError("Cannot write private member to an object whose class did not declare it");
494
461
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
462
+ }
463
+ function __classPrivateFieldIn(state, receiver) {
464
+ if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function"))
465
+ throw new TypeError("Cannot use 'in' operator on non-object");
466
+ return typeof state === "function" ? receiver === state : state.has(receiver);
495
467
  }
496
468
 
497
469
  var EMOJIS = {
@@ -7093,7 +7065,7 @@
7093
7065
  { type: core.Component, args: [{
7094
7066
  selector: 'emoji-selector-panel',
7095
7067
  template: "<div class=\"search-box\" *ngIf=\"searchVisible\">\r\n\t<a mat-icon-button href=\"javascript:;\" (click)=\"hideSearch()\">\r\n\t\t<mat-icon>arrow_back</mat-icon>\r\n\t</a>\r\n\t<mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n\t\t<mat-label>Search for emoji</mat-label>\r\n\t\t<input name=\"search\" type=\"text\" matInput placeholder=\"Start typing\" [(ngModel)]=\"searchQuery\" />\r\n\t</mat-form-field>\r\n</div>\r\n\r\n<div class=\"selector\">\r\n\t<ng-container *ngIf=\"searchVisible\">\r\n\t\t<div class=\"emoji-list\">\r\n\t\t\t<a href=\"javascript:;\" (click)=\"select(emoji.char)\" \r\n\t\t\t\t*ngFor=\"let emoji of searchResults\" [innerHtml]=\"emoji.html || ''\">\r\n\t\t\t</a>\r\n\t\t</div>\r\n\t</ng-container>\r\n\t<ng-container *ngIf=\"!searchVisible\">\r\n\t\t<div class=\"categories\">\r\n\t\t\t<ng-container *ngIf=\"!searchVisible\">\r\n\t\t\t\t<a [title]=\"humanize(category.name)\" [class.active]=\"activeCategory === category.name\" mat-icon-button *ngFor=\"let category of categories\" (click)=\"activeCategory = category.name\">\r\n\t\t\t\t\t<mat-icon>{{category.icon}}</mat-icon>\r\n\t\t\t\t</a>\r\n\r\n\t\t\t\t<a title=\"Search\" [class.active] mat-icon-button (click)=\"showSearch()\">\r\n\t\t\t\t\t<mat-icon>search</mat-icon>\r\n\t\t\t\t</a>\r\n\t\t\t</ng-container>\r\n\t\t</div>\r\n\t\t<ng-container *ngFor=\"let category of categories\">\r\n\t\t\t<div class=\"emoji-list\" *ngIf=\"activeCategory && activeCategory == category.name\">\r\n\t\t\t\t<a href=\"javascript:;\" (click)=\"select(emoji.char)\" \r\n\t\t\t\t\t*ngFor=\"let emoji of category.emojis\" [innerHtml]=\"emoji.html || ''\">\r\n\t\t\t\t</a>\r\n\t\t\t</div>\r\n\t\t</ng-container>\r\n\t</ng-container>\r\n</div>",
7096
- styles: [":host{background:#111;border:1px solid #333;border-radius:5px;color:#fff;max-width:calc(100vw - 1.5em);padding:.5em;width:calc(288px + 9em)}.selector{display:flex;flex-direction:column}.categories a{opacity:.25;transition:opacity .4s ease-in-out}.categories a:hover{opacity:.5}.categories a.active{opacity:1}.emoji-list{flex-grow:1;height:20em;overflow-y:auto}.emoji-list a{background-color:#111;display:inline-block;margin:4px;padding:2px}.emoji-list a ::ng-deep .emoji{height:32px;width:32px}.emoji-list a:hover{background-color:#333}.search-box{align-items:baseline;display:flex}.search-box mat-form-field{flex-grow:1}@media (max-width:500px){.selector{flex-direction:row;height:27em}.emoji-list{height:auto}}"]
7068
+ styles: [":host{background:#111;color:#fff;border:1px solid #333;border-radius:5px;padding:.5em;width:calc(9*(32px + 1em));max-width:calc(100vw - 1.5em)}.selector{display:flex;flex-direction:column}.categories a{opacity:.25;transition:opacity .4s ease-in-out}.categories a:hover{opacity:.5}.categories a.active{opacity:1}.emoji-list{flex-grow:1;overflow-y:auto;height:20em}.emoji-list a{display:inline-block;padding:2px;margin:4px;background-color:#111}.emoji-list a ::ng-deep .emoji{width:32px;height:32px}.emoji-list a:hover{background-color:#333}.search-box{display:flex;align-items:baseline}.search-box mat-form-field{flex-grow:1}@media (max-width:500px){.selector{flex-direction:row;height:27em}.emoji-list{height:auto}}"]
7097
7069
  },] }
7098
7070
  ];
7099
7071
  EmojiSelectorPanelComponent.ctorParameters = function () { return [
@@ -7211,12 +7183,36 @@
7211
7183
  },] }
7212
7184
  ];
7213
7185
 
7186
+ var ChatBackendBase = /** @class */ (function () {
7187
+ function ChatBackendBase() {
7188
+ this._userChanged = new rxjs.BehaviorSubject(null);
7189
+ }
7190
+ Object.defineProperty(ChatBackendBase.prototype, "userChanged", {
7191
+ get: function () {
7192
+ return this._userChanged;
7193
+ },
7194
+ enumerable: false,
7195
+ configurable: true
7196
+ });
7197
+ Object.defineProperty(ChatBackendBase.prototype, "user", {
7198
+ get: function () {
7199
+ return this._user;
7200
+ },
7201
+ set: function (user) {
7202
+ this._user = user;
7203
+ this._userChanged.next(user);
7204
+ },
7205
+ enumerable: false,
7206
+ configurable: true
7207
+ });
7208
+ return ChatBackendBase;
7209
+ }());
7210
+
7214
7211
  /**
7215
7212
  * Unified chat and comments component
7216
7213
  */
7217
7214
  var BantaComponent = /** @class */ (function () {
7218
- function BantaComponent(banta, backend, matDialog) {
7219
- this.banta = banta;
7215
+ function BantaComponent(backend, matDialog) {
7220
7216
  this.backend = backend;
7221
7217
  this.matDialog = matDialog;
7222
7218
  this._subs = new rxjs.Subscription();
@@ -7235,7 +7231,7 @@
7235
7231
  }
7236
7232
  BantaComponent.prototype.ngOnInit = function () {
7237
7233
  var _this = this;
7238
- this._subs.add(this.banta.userChanged.subscribe(function (user) { return _this.currentUser = user; }));
7234
+ this._subs.add(this.backend.userChanged.subscribe(function (user) { return _this.currentUser = user; }));
7239
7235
  this._subs.add(this.backend.notificationsChanged.subscribe(function (notifs) { return _this.notifications = notifs; }));
7240
7236
  this._subs.add(this.backend.newNotification.subscribe(function (notif) {
7241
7237
  _this.newNotifications = true;
@@ -7254,7 +7250,7 @@
7254
7250
  message = {
7255
7251
  user: null,
7256
7252
  sentAt: Date.now(),
7257
- upvotes: 0,
7253
+ likes: 0,
7258
7254
  message: text
7259
7255
  };
7260
7256
  _a.label = 1;
@@ -7418,19 +7414,7 @@
7418
7414
  BantaComponent.prototype.upvoteMessage = function (message) {
7419
7415
  return __awaiter(this, void 0, void 0, function () {
7420
7416
  return __generator(this, function (_a) {
7421
- switch (_a.label) {
7422
- case 0:
7423
- if (!message.parentMessageId) return [3 /*break*/, 2];
7424
- return [4 /*yield*/, this.backend.upvoteMessage(message.topicId, message.parentMessageId, message.id)];
7425
- case 1:
7426
- _a.sent();
7427
- return [3 /*break*/, 4];
7428
- case 2: return [4 /*yield*/, this.backend.upvoteMessage(message.topicId, message.id)];
7429
- case 3:
7430
- _a.sent();
7431
- _a.label = 4;
7432
- case 4: return [2 /*return*/];
7433
- }
7417
+ return [2 /*return*/];
7434
7418
  });
7435
7419
  });
7436
7420
  };
@@ -7451,13 +7435,12 @@
7451
7435
  BantaComponent.decorators = [
7452
7436
  { type: core.Component, args: [{
7453
7437
  selector: "banta",
7454
- template: "\r\n<mat-menu #userMenu=\"matMenu\">\r\n <ng-container *ngIf=\"currentUser\">\r\n <button [disabled]=\"true\" mat-menu-item>{{currentUser.displayName}} (@{{currentUser.username}})</button>\r\n <button mat-menu-item (click)=\"signOut()\">Sign Out</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!currentUser\">\r\n <button mat-menu-item>Sign In</button>\r\n </ng-container>\r\n <button mat-menu-item>Help</button>\r\n</mat-menu>\r\n\r\n<div class=\"tabs\">\r\n <div>\r\n <a mat-button (click)=\"mobileFocus = 'chat'\">{{chatLabel}}</a>\r\n <a mat-button (click)=\"mobileFocus = 'comments'\">{{commentsLabel}}</a>\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div>\r\n <ng-container *ngIf=\"currentUser\">\r\n <button mat-button [matMenuTriggerFor]=\"userMenu\">\r\n @{{currentUser.username}}\r\n </button>\r\n <button mat-icon-button (click)=\"showNotifications()\">\r\n <mat-icon>notification_important</mat-icon>\r\n </button>\r\n </ng-container>\r\n \r\n <button mat-button *ngIf=\"!currentUser\" (click)=\"showSignIn()\">\r\n Sign In\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div class=\"firehose\" [class.focus]=\"mobileFocus === 'chat'\">\r\n <header>\r\n <div>\r\n <label (click)=\"mobileFocus = 'chat'\">{{chatLabel}}</label>\r\n <div class=\"spacer\"></div>\r\n\r\n <ng-container *ngIf=\"currentUser\">\r\n <button mat-button [matMenuTriggerFor]=\"userMenu\">\r\n @{{currentUser.username}}\r\n </button>\r\n <button mat-icon-button (click)=\"showNotifications()\">\r\n <mat-icon>notification_important</mat-icon>\r\n </button>\r\n </ng-container>\r\n \r\n <button mat-button *ngIf=\"!currentUser\" (click)=\"showSignIn()\">\r\n Sign In\r\n </button>\r\n </div>\r\n </header>\r\n <banta-chat \r\n #firehose\r\n [source]=\"firehoseSource\"\r\n (signInSelected)=\"showSignIn()\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n (reported)=\"reportMessage($event)\"\r\n ></banta-chat>\r\n</div>\r\n\r\n<div class=\"aux\" [class.focus]=\"mobileFocus === 'aux'\" [class.open]=\"auxOpen\">\r\n <header>\r\n <div>\r\n <label>{{auxTitle}}</label>\r\n <div class=\"spacer\"></div>\r\n <button mat-icon-button (click)=\"auxOpen = false\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n <div class=\"aux-contents\">\r\n <ng-container *ngIf=\"auxMode === 'profile'\">\r\n <ng-container *ngIf=\"profileUser\">\r\n\r\n <div>\r\n <strong style=\"font-size: 125%;\">\r\n {{profileUser.displayName}}\r\n </strong>\r\n @{{profileUser.username}}\r\n </div>\r\n\r\n <br/>\r\n <strong>Top Messages</strong>\r\n\r\n <div>\r\n <em>Not yet available</em>\r\n </div>\r\n\r\n <br/>\r\n <strong>Recent Messages</strong>\r\n\r\n <div>\r\n <em>Not yet available</em>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"auxMode === 'report'\">\r\n <p>Are you sure you want to report this message?</p>\r\n\r\n <banta-live-message [message]=\"reportedMessage\"></banta-live-message>\r\n\r\n <div style=\"text-align: center;\">\r\n <button mat-raised-button color=\"primary\" (click)=\"sendReport(reportedMessage)\">Yes, Report</button>\r\n &nbsp;\r\n <button mat-raised-button color=\"secondary\" (click)=\"auxOpen = false\">No, Cancel</button>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"auxMode === 'notifications'\">\r\n\r\n <div *ngIf=\"!notifications || notifications.length === 0\">\r\n <em>You do not have any notifications yet</em>\r\n </div>\r\n \r\n <div class=\"notifications\">\r\n <div class=\"notification\" *ngFor=\"let notif of notifications\">\r\n <div>\r\n <ng-container *ngIf=\"notif.type === 'upvote'\">\r\n @{{notif.message?.user?.username}} upvoted your post\r\n \r\n <banta-live-message\r\n [message]=\"notif.message\"\r\n (upvoted)=\"upvoteMessage(notif.message)\"\r\n (reported)=\"reportMessage(notif.message)\"\r\n (selected)=\"goToMessage(notif.message)\">\r\n </banta-live-message>\r\n\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'notice'\">\r\n <div>\r\n {{notif.message}}\r\n </div>\r\n <a mat-button target=\"_blank\" href=\"{{notif.actionUrl}}\">\r\n {{notif.actionLabel}}\r\n </a>\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'mention'\">\r\n You were mentioned by @{{notif.message?.user?.username}}\r\n\r\n <banta-live-message\r\n [message]=\"notif.message\"\r\n (upvoted)=\"upvoteMessage(notif.message)\"\r\n (reported)=\"reportMessage(notif.message)\"\r\n (selected)=\"goToMessage(notif.message)\">\r\n </banta-live-message>\r\n\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'reply'\">\r\n @{{notif.replyMessage?.user?.username}} replied to your post\r\n \r\n <banta-live-message\r\n [message]=\"notif.replyMessage\"\r\n (upvoted)=\"upvoteMessage(notif.replyMessage)\"\r\n (reported)=\"reportMessage(notif.replyMessage)\"\r\n (selected)=\"goToMessage(notif.replyMessage)\">\r\n </banta-live-message>\r\n </ng-container>\r\n </div>\r\n\r\n <banta-timestamp [value]=\"notif.sentAt\"></banta-timestamp>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>\r\n<div class=\"points\" [class.focus]=\"mobileFocus === 'points'\">\r\n <header>\r\n <div>\r\n <label>{{commentsLabel}}</label>\r\n </div>\r\n </header>\r\n <div class=\"point-focus\">\r\n <div class=\"actions\">\r\n <button mat-button (click)=\"pointUnfocus()\">\r\n <mat-icon>arrow_back</mat-icon>\r\n Back\r\n </button>\r\n\r\n <div class=\"spacer\"></div>\r\n \r\n <ng-container *ngIf=\"pointOpen\">\r\n <div class=\"counted-action\">\r\n <div class=\"count-indicator\"> \r\n {{pointOpen.upvotes}}\r\n </div>\r\n <button mat-icon-button>\r\n <mat-icon>thumb_up</mat-icon>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div *ngIf=\"!pointSubChat\">\r\n Error: No subchat\r\n </div>\r\n \r\n <banta-comment-view\r\n class=\"subcomments\"\r\n *ngIf=\"pointSubChat\"\r\n [newestLast]=\"true\"\r\n [allowReplies]=\"false\"\r\n [source]=\"pointSubChat\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (reported)=\"reportMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n >\r\n \r\n <banta-comment\r\n class=\"focused-comment\"\r\n data-before\r\n *ngIf=\"pointOpen\"\r\n (upvoted)=\"upvoteMessage(pointOpen)\"\r\n (userSelected)=\"showProfile(pointOpen.user)\"\r\n (reported)=\"reportMessage(pointOpen)\"\r\n [showReplyAction]=\"false\"\r\n [message]=\"pointOpen\"\r\n ></banta-comment>\r\n \r\n <div class=\"message reply\">\r\n Reply:\r\n <form class=\"new-message\" (submit)=\"sendPointSubMessage()\">\r\n <textarea \r\n name=\"message\" \r\n (keydown)=\"newPointSubMessageKeyDown($event)\"\r\n [(ngModel)]=\"newPointSubMessage.message\"></textarea>\r\n \r\n <div class=\"actions\">\r\n <button [disabled]=\"!newPointSubMessage.message\" \r\n mat-raised-button color=\"primary\">Send</button>\r\n </div>\r\n </form>\r\n </div>\r\n </banta-comment-view>\r\n </div>\r\n <div class=\"points-section\">\r\n <banta-comments\r\n [source]=\"pointSource\"\r\n (signInSelected)=\"showSignIn()\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (reported)=\"reportMessage($event)\"\r\n (selected)=\"goToMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n ></banta-comments>\r\n </div>\r\n</div>",
7455
- styles: [":host{display:flex;flex-direction:row;height:40em;padding:.5em;position:relative}.counted-action{align-items:center;display:flex}.count-indicator{border:1px solid #333;border-radius:3px;font-size:9pt;padding:0 3px}header{margin-bottom:1em;position:relative}header div{align-items:center;display:flex;height:30px}header button{color:#666}header label{color:#333;font-size:12pt;font-weight:100;letter-spacing:2px;margin:0 auto 0 0;overflow-x:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;z-index:1}header:after,header label{display:block;position:relative}header:after{border:1px solid #ccc;content:\"\";height:0;width:100%;z-index:0}.points{display:flex;flex-direction:column;max-width:50em}:host.point-focus .points{max-width:50em;width:66%}:host.point-focus .points .points-section{opacity:0;pointer-events:none}:host.point-focus .points .point-focus{opacity:1;pointer-events:auto}:host.point-focus .points .point-focus .actions{display:flex}banta-comments{flex-grow:1}.points{flex-shrink:0;font-size:12pt;margin-left:.5em;max-width:30em;position:relative;transition:width .2s ease-in,max-width .2s ease-in;width:33%}.points .points-section{opacity:1;z-index:2}.points .point-focus,.points .points-section{display:flex;flex-direction:column;flex-grow:1;transition:opacity .2s ease-in}.points .point-focus{bottom:0;left:0;opacity:0;padding:.5em;position:absolute;right:0;top:1.75em;width:100%}.firehose{display:flex;flex-direction:column;flex-grow:1;font-size:10pt}form{align-items:center;display:flex;padding:.5em 0}form textarea{font-size:14pt;min-height:6em}form input[type=text],form textarea{background:#000;border:1px solid #333;color:#fff;width:100%}form input[type=text]{height:1em}form .actions{margin-left:1em}form button{display:block;margin:0 0 0 auto}.subcomments ::ng-deep banta-comment{font-size:10pt}.subcomments ::ng-deep banta-comment.focused-comment{background:#001321;color:#fff;font-size:12pt}.aux{display:flex;flex-direction:column;min-width:0;overflow-x:hidden;transition:width .4s ease-out,min-width .4s ease-out;width:0}.aux.open{min-width:18em;width:30em}.aux .aux-contents{align-items:center;display:flex;flex-direction:column;flex-grow:1;justify-content:center;max-width:100%;min-width:10em;width:30em}.notifications .notification{border-bottom:1px solid #333;padding:1em}.notifications .notification banta-timestamp{color:#999;display:block;font-size:9pt;text-align:right}.message.reply{padding:1em}.tabs{display:none}@media (max-width:1015px){:host{flex-direction:column}.tabs{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:rgba(0,0,0,.5);display:flex;left:0;position:absolute;right:0;top:0;width:100%;z-index:10}.points{margin-left:0;max-width:100%;width:100%}header{display:none}.aux,:host.point-focus .points{max-width:100%;width:100%}.aux{min-width:0}.aux,.firehose,.points{background:#000;bottom:0;left:0;position:absolute;right:0;top:2em;z-index:0}.aux.focus,.firehose.focus,.points.focus{z-index:2}}:host-context(.mat-dark-theme) :host{background:#090909;color:#fff}:host-context(.mat-dark-theme) form textarea{background:#ccc;color:#333}:host-context(.mat-dark-theme) header:after{border-color:#222}:host-context(.mat-dark-theme) header label{color:#aaa}"]
7438
+ template: "\r\n<mat-menu #userMenu=\"matMenu\">\r\n <ng-container *ngIf=\"currentUser\">\r\n <button [disabled]=\"true\" mat-menu-item>{{currentUser.displayName}} (@{{currentUser.username}})</button>\r\n <button mat-menu-item (click)=\"signOut()\">Sign Out</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!currentUser\">\r\n <button mat-menu-item>Sign In</button>\r\n </ng-container>\r\n <button mat-menu-item>Help</button>\r\n</mat-menu>\r\n\r\n<div class=\"tabs\">\r\n <div>\r\n <a mat-button (click)=\"mobileFocus = 'chat'\">{{chatLabel}}</a>\r\n <a mat-button (click)=\"mobileFocus = 'comments'\">{{commentsLabel}}</a>\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div>\r\n <ng-container *ngIf=\"currentUser\">\r\n <button mat-button [matMenuTriggerFor]=\"userMenu\">\r\n @{{currentUser.username}}\r\n </button>\r\n <button mat-icon-button (click)=\"showNotifications()\">\r\n <mat-icon>notification_important</mat-icon>\r\n </button>\r\n </ng-container>\r\n \r\n <button mat-button *ngIf=\"!currentUser\" (click)=\"showSignIn()\">\r\n Sign In\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<div class=\"firehose\" [class.focus]=\"mobileFocus === 'chat'\">\r\n <header>\r\n <div>\r\n <label (click)=\"mobileFocus = 'chat'\">{{chatLabel}}</label>\r\n <div class=\"spacer\"></div>\r\n\r\n <ng-container *ngIf=\"currentUser\">\r\n <button mat-button [matMenuTriggerFor]=\"userMenu\">\r\n @{{currentUser.username}}\r\n </button>\r\n <button mat-icon-button (click)=\"showNotifications()\">\r\n <mat-icon>notification_important</mat-icon>\r\n </button>\r\n </ng-container>\r\n \r\n <button mat-button *ngIf=\"!currentUser\" (click)=\"showSignIn()\">\r\n Sign In\r\n </button>\r\n </div>\r\n </header>\r\n <banta-chat \r\n #firehose\r\n [source]=\"firehoseSource\"\r\n (signInSelected)=\"showSignIn()\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n (reported)=\"reportMessage($event)\"\r\n ></banta-chat>\r\n</div>\r\n\r\n<div class=\"aux\" [class.focus]=\"mobileFocus === 'aux'\" [class.open]=\"auxOpen\">\r\n <header>\r\n <div>\r\n <label>{{auxTitle}}</label>\r\n <div class=\"spacer\"></div>\r\n <button mat-icon-button (click)=\"auxOpen = false\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </header>\r\n <div class=\"aux-contents\">\r\n <ng-container *ngIf=\"auxMode === 'profile'\">\r\n <ng-container *ngIf=\"profileUser\">\r\n\r\n <div>\r\n <strong style=\"font-size: 125%;\">\r\n {{profileUser.displayName}}\r\n </strong>\r\n @{{profileUser.username}}\r\n </div>\r\n\r\n <br/>\r\n <strong>Top Messages</strong>\r\n\r\n <div>\r\n <em>Not yet available</em>\r\n </div>\r\n\r\n <br/>\r\n <strong>Recent Messages</strong>\r\n\r\n <div>\r\n <em>Not yet available</em>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"auxMode === 'report'\">\r\n <p>Are you sure you want to report this message?</p>\r\n\r\n <banta-live-message [message]=\"reportedMessage\"></banta-live-message>\r\n\r\n <div style=\"text-align: center;\">\r\n <button mat-raised-button color=\"primary\" (click)=\"sendReport(reportedMessage)\">Yes, Report</button>\r\n &nbsp;\r\n <button mat-raised-button color=\"secondary\" (click)=\"auxOpen = false\">No, Cancel</button>\r\n </div>\r\n\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"auxMode === 'notifications'\">\r\n\r\n <div *ngIf=\"!notifications || notifications.length === 0\">\r\n <em>You do not have any notifications yet</em>\r\n </div>\r\n \r\n <div class=\"notifications\">\r\n <div class=\"notification\" *ngFor=\"let notif of notifications\">\r\n <div>\r\n <ng-container *ngIf=\"notif.type === 'upvote'\">\r\n @{{notif.message?.user?.username}} upvoted your post\r\n \r\n <banta-live-message\r\n [message]=\"notif.message\"\r\n (upvoted)=\"upvoteMessage(notif.message)\"\r\n (reported)=\"reportMessage(notif.message)\"\r\n (selected)=\"goToMessage(notif.message)\">\r\n </banta-live-message>\r\n\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'notice'\">\r\n <div>\r\n {{notif.message}}\r\n </div>\r\n <a mat-button target=\"_blank\" href=\"{{notif.actionUrl}}\">\r\n {{notif.actionLabel}}\r\n </a>\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'mention'\">\r\n You were mentioned by @{{notif.message?.user?.username}}\r\n\r\n <banta-live-message\r\n [message]=\"notif.message\"\r\n (upvoted)=\"upvoteMessage(notif.message)\"\r\n (reported)=\"reportMessage(notif.message)\"\r\n (selected)=\"goToMessage(notif.message)\">\r\n </banta-live-message>\r\n\r\n </ng-container>\r\n <ng-container *ngIf=\"notif.type === 'reply'\">\r\n @{{notif.replyMessage?.user?.username}} replied to your post\r\n \r\n <banta-live-message\r\n [message]=\"notif.replyMessage\"\r\n (upvoted)=\"upvoteMessage(notif.replyMessage)\"\r\n (reported)=\"reportMessage(notif.replyMessage)\"\r\n (selected)=\"goToMessage(notif.replyMessage)\">\r\n </banta-live-message>\r\n </ng-container>\r\n </div>\r\n\r\n <banta-timestamp [value]=\"notif.sentAt\"></banta-timestamp>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>\r\n<div class=\"points\" [class.focus]=\"mobileFocus === 'points'\">\r\n <header>\r\n <div>\r\n <label>{{commentsLabel}}</label>\r\n </div>\r\n </header>\r\n <div class=\"point-focus\">\r\n <div class=\"actions\">\r\n <button mat-button (click)=\"pointUnfocus()\">\r\n <mat-icon>arrow_back</mat-icon>\r\n Back\r\n </button>\r\n\r\n <div class=\"spacer\"></div>\r\n \r\n <ng-container *ngIf=\"pointOpen\">\r\n <div class=\"counted-action\">\r\n <div class=\"count-indicator\"> \r\n {{pointOpen.likes}}\r\n </div>\r\n <button mat-icon-button>\r\n <mat-icon>thumb_up</mat-icon>\r\n </button>\r\n </div>\r\n\r\n </ng-container>\r\n </div>\r\n\r\n <div *ngIf=\"!pointSubChat\">\r\n Error: No subchat\r\n </div>\r\n \r\n <banta-comment-view\r\n class=\"subcomments\"\r\n *ngIf=\"pointSubChat\"\r\n [newestLast]=\"true\"\r\n [allowReplies]=\"false\"\r\n [source]=\"pointSubChat\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (reported)=\"reportMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n >\r\n \r\n <banta-comment\r\n class=\"focused-comment\"\r\n data-before\r\n *ngIf=\"pointOpen\"\r\n (upvoted)=\"upvoteMessage(pointOpen)\"\r\n (userSelected)=\"showProfile(pointOpen.user)\"\r\n (reported)=\"reportMessage(pointOpen)\"\r\n [showReplyAction]=\"false\"\r\n [message]=\"pointOpen\"\r\n ></banta-comment>\r\n \r\n <div class=\"message reply\">\r\n Reply:\r\n <form class=\"new-message\" (submit)=\"sendPointSubMessage()\">\r\n <textarea \r\n name=\"message\" \r\n (keydown)=\"newPointSubMessageKeyDown($event)\"\r\n [(ngModel)]=\"newPointSubMessage.message\"></textarea>\r\n \r\n <div class=\"actions\">\r\n <button [disabled]=\"!newPointSubMessage.message\" \r\n mat-raised-button color=\"primary\">Send</button>\r\n </div>\r\n </form>\r\n </div>\r\n </banta-comment-view>\r\n </div>\r\n <div class=\"points-section\">\r\n <banta-comments\r\n [source]=\"pointSource\"\r\n (signInSelected)=\"showSignIn()\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (reported)=\"reportMessage($event)\"\r\n (selected)=\"goToMessage($event)\"\r\n (userSelected)=\"showProfile($event.user)\"\r\n ></banta-comments>\r\n </div>\r\n</div>",
7439
+ styles: [":host{display:flex;flex-direction:row;padding:.5em;height:40em;position:relative}.counted-action{display:flex;align-items:center}.count-indicator{font-size:9pt;padding:0 3px;border-radius:3px;border:1px solid #333}header{position:relative;margin-bottom:1em}header div{display:flex;align-items:center;height:30px}header button{color:#666}header label{text-transform:uppercase;z-index:1;font-size:12pt;letter-spacing:2px;font-weight:100;color:#333;margin:0 auto 0 0;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}header:after,header label{display:block;position:relative}header:after{content:\"\";border:1px solid #ccc;height:0;width:100%;z-index:0}.points{max-width:50em;display:flex;flex-direction:column}:host.point-focus .points{width:66%;max-width:50em}:host.point-focus .points .points-section{opacity:0;pointer-events:none}:host.point-focus .points .point-focus{opacity:1;pointer-events:auto}:host.point-focus .points .point-focus .actions{display:flex}banta-comments{flex-grow:1}.points{width:33%;margin-left:.5em;font-size:12pt;flex-shrink:0;max-width:30em;transition:width .2s ease-in,max-width .2s ease-in;position:relative}.points .points-section{opacity:1;z-index:2}.points .point-focus,.points .points-section{flex-grow:1;display:flex;flex-direction:column;transition:opacity .2s ease-in}.points .point-focus{position:absolute;width:100%;bottom:0;top:1.75em;right:0;left:0;padding:.5em;opacity:0}.firehose{flex-grow:1;font-size:10pt;display:flex;flex-direction:column}form{display:flex;padding:.5em 0;align-items:center}form textarea{font-size:14pt;min-height:6em}form input[type=text],form textarea{background:#000;color:#fff;border:1px solid #333;width:100%}form input[type=text]{height:1em}form .actions{margin-left:1em}form button{display:block;margin:0 0 0 auto}.subcomments ::ng-deep banta-comment{font-size:10pt}.subcomments ::ng-deep banta-comment.focused-comment{background:#001321;color:#fff;font-size:12pt}.aux{width:0;min-width:0;overflow-x:hidden;transition:width .4s ease-out,min-width .4s ease-out;display:flex;flex-direction:column}.aux.open{width:30em;min-width:18em}.aux .aux-contents{width:30em;min-width:10em;max-width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;flex-grow:1}.notifications .notification{border-bottom:1px solid #333;padding:1em}.notifications .notification banta-timestamp{display:block;text-align:right;font-size:9pt;color:#999}.message.reply{padding:1em}.tabs{display:none}@media (max-width:1015px){:host{flex-direction:column}.tabs{display:flex;position:absolute;top:0;left:0;right:0;width:100%;z-index:10;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);background:rgba(0,0,0,.5)}.points{width:100%;max-width:100%;margin-left:0}header{display:none}.aux,:host.point-focus .points{width:100%;max-width:100%}.aux{min-width:0}.aux,.firehose,.points{position:absolute;top:2em;left:0;right:0;bottom:0;z-index:0;background:#000}.aux.focus,.firehose.focus,.points.focus{z-index:2}}:host-context(.mat-dark-theme) :host{background:#090909;color:#fff}:host-context(.mat-dark-theme) form textarea{background:#ccc;color:#333}:host-context(.mat-dark-theme) header:after{border-color:#222}:host-context(.mat-dark-theme) header label{color:#aaa}"]
7456
7440
  },] }
7457
7441
  ];
7458
7442
  BantaComponent.ctorParameters = function () { return [
7459
- { type: BantaService },
7460
- { type: ChatBackendService },
7443
+ { type: ChatBackendBase },
7461
7444
  { type: dialog.MatDialog }
7462
7445
  ]; };
7463
7446
  BantaComponent.propDecorators = {
@@ -7541,8 +7524,8 @@
7541
7524
  ChatMessageComponent.decorators = [
7542
7525
  { type: core.Component, args: [{
7543
7526
  selector: 'banta-chat-message',
7544
- template: "<div class=\"message-content\">\r\n <div class=\"user\" (click)=\"selectUser()\">\r\n <div class=\"avatar\" [style.background-image]=\"avatarForUser(message.user)\"></div>\r\n <label>{{message.user.username}}</label>\r\n </div>\r\n <div class=\"content\">\r\n <div (click)=\"select()\">\r\n {{message.message}}\r\n </div>\r\n <div class=\"status\">\r\n <div class=\"count-indicator\" *ngIf=\"message.upvotes > 0\">\r\n {{message.upvotes}} <mat-icon [inline]=\"true\">star</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n<div class=\"actions\">\r\n <button mat-icon-button matTooltip=\"Upvote\" matTooltipPosition=\"below\" (click)=\"upvote()\">\r\n <mat-icon [inline]=\"true\">thumb_up</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Report\" matTooltipPosition=\"below\" (click)=\"report()\">\r\n <mat-icon [inline]=\"true\">report</mat-icon>\r\n </button>\r\n</div>",
7545
- styles: [":host{align-items:center;background-color:#fff;color:#000;display:flex;flex-direction:row;padding:0 1em;transition:background-color .4s ease-out}:host .message-content .content{color:#111}:host:hover{background-color:#ddd}:host.highlight{background:#00121b}:host.highlight:hover{background:#01324d}:host:nth-child(2n){background-color:#eee}:host:nth-child(2n):hover{background:#ddd}:host:nth-child(2n) .message-content .content{color:#222}:host:nth-child(2n).highlight{background:#001a2a}:host:nth-child(2n).highlight:hover{background:#002b44}:host .message-content{align-items:center;display:flex;flex-direction:row;flex-grow:1}:host .message-content .content{display:flex;flex-direction:row;padding:5px 0}:host .message-content .content .status{align-items:center;display:flex;flex-direction:row;margin-left:1em}:host .message-content .content .status mat-icon{margin-left:.5em}:host .user{align-items:center;color:#999;display:flex;flex-shrink:0;font-weight:400;margin-right:.25em;text-align:right}:host .user .avatar{background-color:#333;background-position:50%;background-size:cover;border-radius:100%;flex-grow:0;flex-shrink:0;height:2em;margin-right:1em;width:2em}:host .user:after{content:\":\";margin-right:1em}:host .content{flex-grow:1}:host .actions{flex-shrink:0;opacity:0;transition:opacity .4s ease-out;white-space:nowrap}:host:hover .actions{opacity:1}.count-indicator{white-space:nowrap}:host-context(.mat-dark-theme){background-color:#000;color:#fff}:host-context(.mat-dark-theme) .message-content .content{color:#ddd}:host-context(.mat-dark-theme):hover{background-color:#111}:host-context(.mat-dark-theme):nth-child(2n).highlight{background:#001a2a}:host-context(.mat-dark-theme):nth-child(2n).highlight:hover{background:#002b44}:host-context(.mat-dark-theme):nth-child(2n):hover{background-color:#111}:host-context(.mat-dark-theme):nth-child(2n){background-color:#080808}:host-context(.mat-dark-theme):nth-child(2n) .message-content .content{color:#eee}label{margin:0}"]
7527
+ template: "<div class=\"message-content\">\r\n <div class=\"user\" (click)=\"selectUser()\">\r\n <div class=\"avatar\" [style.background-image]=\"avatarForUser(message.user)\"></div>\r\n <label>{{message.user.username}}</label>\r\n </div>\r\n <div class=\"content\">\r\n <div (click)=\"select()\">\r\n {{message.message}}\r\n </div>\r\n <div class=\"status\">\r\n <div class=\"count-indicator\" *ngIf=\"message.likes > 0\">\r\n {{message.likes}} <mat-icon [inline]=\"true\">star</mat-icon>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n<div class=\"actions\">\r\n <button mat-icon-button matTooltip=\"Upvote\" matTooltipPosition=\"below\" (click)=\"upvote()\">\r\n <mat-icon [inline]=\"true\">thumb_up</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Report\" matTooltipPosition=\"below\" (click)=\"report()\">\r\n <mat-icon [inline]=\"true\">report</mat-icon>\r\n </button>\r\n</div>",
7528
+ styles: [":host{display:flex;flex-direction:row;align-items:center;padding:0 1em;background-color:#fff;color:#000;transition:background-color .4s ease-out}:host .message-content .content{color:#111}:host:hover{background-color:#ddd}:host.highlight{background:#00121b}:host.highlight:hover{background:#01324d}:host:nth-child(2n){background-color:#eee}:host:nth-child(2n):hover{background:#ddd}:host:nth-child(2n) .message-content .content{color:#222}:host:nth-child(2n).highlight{background:#001a2a}:host:nth-child(2n).highlight:hover{background:#002b44}:host .message-content{display:flex;flex-direction:row;flex-grow:1;align-items:center}:host .message-content .content{display:flex;flex-direction:row;padding:5px 0}:host .message-content .content .status{display:flex;flex-direction:row;align-items:center;margin-left:1em}:host .message-content .content .status mat-icon{margin-left:.5em}:host .user{color:#999;font-weight:400;text-align:right;margin-right:.25em;flex-shrink:0;display:flex;align-items:center}:host .user .avatar{background-position:50%;background-size:cover;background-color:#333;border-radius:100%;flex-shrink:0;flex-grow:0;margin-right:1em;width:2em;height:2em}:host .user:after{content:\":\";margin-right:1em}:host .content{flex-grow:1}:host .actions{flex-shrink:0;white-space:nowrap;opacity:0;transition:opacity .4s ease-out}:host:hover .actions{opacity:1}.count-indicator{white-space:nowrap}:host-context(.mat-dark-theme){background-color:#000;color:#fff}:host-context(.mat-dark-theme) .message-content .content{color:#ddd}:host-context(.mat-dark-theme):hover{background-color:#111}:host-context(.mat-dark-theme):nth-child(2n).highlight{background:#001a2a}:host-context(.mat-dark-theme):nth-child(2n).highlight:hover{background:#002b44}:host-context(.mat-dark-theme):nth-child(2n):hover{background-color:#111}:host-context(.mat-dark-theme):nth-child(2n){background-color:#080808}:host-context(.mat-dark-theme):nth-child(2n) .message-content .content{color:#eee}label{margin:0}"]
7546
7529
  },] }
7547
7530
  ];
7548
7531
  ChatMessageComponent.propDecorators = {
@@ -7622,7 +7605,7 @@
7622
7605
  },] }
7623
7606
  ];
7624
7607
  LiveChatMessageComponent.ctorParameters = function () { return [
7625
- { type: ChatBackendService }
7608
+ { type: ChatBackendBase }
7626
7609
  ]; };
7627
7610
  LiveChatMessageComponent.propDecorators = {
7628
7611
  upvoted: [{ type: core.Output }],
@@ -7632,7 +7615,8 @@
7632
7615
  };
7633
7616
 
7634
7617
  var ChatViewComponent = /** @class */ (function () {
7635
- function ChatViewComponent(elementRef) {
7618
+ function ChatViewComponent(backend, elementRef) {
7619
+ this.backend = backend;
7636
7620
  this.elementRef = elementRef;
7637
7621
  this._sourceSubs = new rxjs.Subscription();
7638
7622
  this._selected = new rxjs.Subject();
@@ -7663,10 +7647,8 @@
7663
7647
  console.dir(this.messages);
7664
7648
  this._sourceSubs.add(this._source.messageReceived.subscribe(function (msg) { return _this.messageReceived(msg); }));
7665
7649
  this._sourceSubs.add(this._source.messageSent.subscribe(function (msg) { return _this.messageSent(msg); }));
7666
- if (this._source.currentUserChanged) {
7667
- this._sourceSubs.add(this._source.currentUserChanged
7668
- .subscribe(function (user) { return _this.currentUser = user; }));
7669
- }
7650
+ this._sourceSubs.add(this.backend.userChanged
7651
+ .subscribe(function (user) { return _this.currentUser = user; }));
7670
7652
  }
7671
7653
  },
7672
7654
  enumerable: false,
@@ -7782,10 +7764,11 @@
7782
7764
  { type: core.Component, args: [{
7783
7765
  selector: 'banta-chat-view',
7784
7766
  template: "<div class=\"message-container\" #messageContainer>\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n <ng-container *ngFor=\"let message of messages\">\r\n <banta-chat-message\r\n *ngIf=\"!message.hidden\"\r\n [message]=\"message\"\r\n [class.highlight]=\"mentionsMe(message)\" \r\n [class.flash]=\"message.id === flashedMessageId\"\r\n (selected)=\"selectMessage(message)\"\r\n (upvoted)=\"upvoteMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n [attr.data-id]=\"message.id\"\r\n >\r\n </banta-chat-message>\r\n </ng-container>\r\n <ng-content select=\":not([data-before])\"></ng-content>\r\n</div>",
7785
- styles: [":host{display:flex;flex-direction:column;flex-grow:1}.message-container{background:#fff;color:#000;flex-grow:1;height:10em;overflow-x:hidden;overflow-y:auto;padding:.5em 1em .5em .5em}.message-container.no-scroll{height:auto;overflow-y:visible}:host-context(.mat-dark-theme) .message-container{background:#000;color:#fff}banta-chat-message.flash{-webkit-animation:flash;-webkit-animation-duration:2.5s;-webkit-animation-iteration-count:1;animation:flash;animation-duration:2.5s;animation-iteration-count:1}@-webkit-keyframes flash{0%{background:#425700;transform:scale(1)}25%{transform:scale(1.05)}50%{transform:scale(1)}75%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes flash{0%{background:#425700;transform:scale(1)}25%{transform:scale(1.05)}50%{transform:scale(1)}75%{transform:scale(1.05)}to{transform:scale(1)}}"]
7767
+ styles: [":host{display:flex;flex-direction:column;flex-grow:1}.message-container{flex-grow:1;overflow-y:auto;overflow-x:hidden;height:10em;color:#000;background:#fff;padding:.5em 1em .5em .5em}.message-container.no-scroll{height:auto;overflow-y:visible}:host-context(.mat-dark-theme) .message-container{color:#fff;background:#000}banta-chat-message.flash{-webkit-animation:flash;animation:flash;-webkit-animation-duration:2.5s;animation-duration:2.5s;-webkit-animation-iteration-count:1;animation-iteration-count:1}@-webkit-keyframes flash{0%{transform:scale(1);background:#425700}25%{transform:scale(1.05)}50%{transform:scale(1)}75%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes flash{0%{transform:scale(1);background:#425700}25%{transform:scale(1.05)}50%{transform:scale(1)}75%{transform:scale(1.05)}to{transform:scale(1)}}"]
7786
7768
  },] }
7787
7769
  ];
7788
7770
  ChatViewComponent.ctorParameters = function () { return [
7771
+ { type: ChatBackendBase },
7789
7772
  { type: core.ElementRef }
7790
7773
  ]; };
7791
7774
  ChatViewComponent.propDecorators = {
@@ -7802,10 +7785,8 @@
7802
7785
  * Chat component
7803
7786
  */
7804
7787
  var BantaChatComponent = /** @class */ (function () {
7805
- function BantaChatComponent(banta, backend, elementRef) {
7806
- this.banta = banta;
7788
+ function BantaChatComponent(backend) {
7807
7789
  this.backend = backend;
7808
- this.elementRef = elementRef;
7809
7790
  this._subs = new rxjs.Subscription();
7810
7791
  this.user = null;
7811
7792
  this.signInLabel = 'Sign In';
@@ -7822,7 +7803,7 @@
7822
7803
  }
7823
7804
  BantaChatComponent.prototype.ngOnInit = function () {
7824
7805
  var _this = this;
7825
- this._subs.add(this.banta.userChanged.subscribe(function (user) { return _this.user = user; }));
7806
+ this._subs.add(this.backend.userChanged.subscribe(function (user) { return _this.user = user; }));
7826
7807
  };
7827
7808
  BantaChatComponent.prototype.ngOnDestroy = function () {
7828
7809
  this._subs.unsubscribe();
@@ -7938,14 +7919,15 @@
7938
7919
  });
7939
7920
  Object.defineProperty(BantaChatComponent.prototype, "canChat", {
7940
7921
  get: function () {
7941
- var _a;
7942
7922
  if (!this.user)
7943
7923
  return false;
7944
- if (!this.user.permissions)
7945
- return true;
7946
- if (!this.user.permissions.canChat)
7947
- return true;
7948
- return (_a = this.user.permissions) === null || _a === void 0 ? void 0 : _a.canChat(this.source);
7924
+ // TODO
7925
+ // if (!this.user.permissions)
7926
+ // return true;
7927
+ // if (!this.user.permissions.canChat)
7928
+ // return true;
7929
+ // return this.user.permissions?.canChat(this.source);
7930
+ return true;
7949
7931
  },
7950
7932
  enumerable: false,
7951
7933
  configurable: true
@@ -7966,7 +7948,7 @@
7966
7948
  message = {
7967
7949
  user: null,
7968
7950
  sentAt: Date.now(),
7969
- upvotes: 0,
7951
+ likes: 0,
7970
7952
  url: location.href,
7971
7953
  message: text
7972
7954
  };
@@ -7998,13 +7980,11 @@
7998
7980
  { type: core.Component, args: [{
7999
7981
  selector: 'banta-chat',
8000
7982
  template: "<banta-chat-view \r\n #chatView\r\n [source]=\"source\"\r\n (upvoted)=\"upvote($event)\"\r\n (reported)=\"report($event)\"\r\n (selected)=\"select($event)\"\r\n (userSelected)=\"selectUser($event)\"\r\n ></banta-chat-view>\r\n\r\n<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n \r\n <div class=\"entry-container\">\r\n <input\r\n type=\"text\"\r\n name=\"message\" \r\n (keydown)=\"onKeyDown($event)\"\r\n [(ngModel)]=\"newMessage.message\" />\r\n \r\n <emoji-selector-button\r\n (selected)=\"insertEmoji($event)\"\r\n ></emoji-selector-button>\r\n </div>\r\n\r\n <div class=\"actions\">\r\n\r\n <ng-container *ngIf=\"!user\">\r\n <button type=\"button\" (click)=\"showSignIn()\" mat-raised-button color=\"primary\">{{signInLabel}}</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"user\">\r\n <button *ngIf=\"canChat\" [disabled]=\"!newMessage.message\" mat-raised-button color=\"primary\">{{sendLabel}}</button>\r\n <button *ngIf=\"!canChat\" type=\"button\" (click)=\"sendPermissionError()\" mat-raised-button color=\"primary\">{{permissionDeniedLabel}}</button>\r\n </ng-container>\r\n </div>\r\n</form>",
8001
- styles: [":host{border-radius:5px;flex-direction:column;font-size:10pt;padding:10px}.entry-container,:host{display:flex;flex-grow:1}.entry-container{flex-direction:row;position:relative}.entry-container emoji-selector-button{position:absolute;right:0;top:.15em}.entry-container input{font-size:12pt;height:2.6em;padding-left:1em}.entry-container input:-webkit-autofill,.entry-container input:-webkit-autofill:focus,.entry-container input:-webkit-autofill:hover{-webkit-box-shadow:0 0 0 1000px #211e07 inset;-webkit-text-fill-color:#9da302;-webkit-transition:background-color 5000s ease-in-out 0s;caret-color:#9da302;outline:1px solid #9da302;transition:background-color 5000s ease-in-out 0s}.entry-container emoji-selector-panel{bottom:3.5em;opacity:0;pointer-events:none;position:absolute;right:0}.entry-container emoji-selector-panel.visible{opacity:1;pointer-events:auto}form{align-items:center;display:flex;padding:.5em 0}form textarea{background:#000;border:1px solid #333;color:#fff;font-size:14pt;min-height:6em;width:100%}form input[type=text]{background:#fff;border:1px solid #ccc;color:#000;height:2.5em;width:100%}form .actions{margin-left:1em}form button{display:block;margin:0 0 0 auto}:host-context(.mat-dark-theme) form input[type=text]{background:#000;border:1px solid #333;color:#fff}"]
7983
+ styles: [":host{flex-direction:column;border-radius:5px;padding:10px;font-size:10pt}.entry-container,:host{display:flex;flex-grow:1}.entry-container{flex-direction:row;position:relative}.entry-container emoji-selector-button{position:absolute;right:0;top:.15em}.entry-container input{height:2.6em;font-size:12pt;padding-left:1em}.entry-container input:-webkit-autofill,.entry-container input:-webkit-autofill:focus,.entry-container input:-webkit-autofill:hover{outline:1px solid #9da302;-webkit-text-fill-color:#9da302;-webkit-box-shadow:0 0 0 1000px #211e07 inset;-webkit-transition:background-color 5000s ease-in-out 0s;transition:background-color 5000s ease-in-out 0s;caret-color:#9da302}.entry-container emoji-selector-panel{pointer-events:none;opacity:0;position:absolute;bottom:3.5em;right:0}.entry-container emoji-selector-panel.visible{opacity:1;pointer-events:auto}form{display:flex;padding:.5em 0;align-items:center}form textarea{font-size:14pt;background:#000;color:#fff;border:1px solid #333;min-height:6em;width:100%}form input[type=text]{background:#fff;color:#000;border:1px solid #ccc;width:100%;height:2.5em}form .actions{margin-left:1em}form button{display:block;margin:0 0 0 auto}:host-context(.mat-dark-theme) form input[type=text]{background:#000;color:#fff;border:1px solid #333}"]
8002
7984
  },] }
8003
7985
  ];
8004
7986
  BantaChatComponent.ctorParameters = function () { return [
8005
- { type: BantaService },
8006
- { type: ChatBackendService },
8007
- { type: core.ElementRef }
7987
+ { type: ChatBackendBase }
8008
7988
  ]; };
8009
7989
  BantaChatComponent.propDecorators = {
8010
7990
  shouldInterceptMessageSend: [{ type: core.Input }],
@@ -8122,7 +8102,8 @@
8122
8102
  function CommentComponent() {
8123
8103
  this._reported = new rxjs.Subject();
8124
8104
  this._selected = new rxjs.Subject();
8125
- this._upvoted = new rxjs.Subject();
8105
+ this._liked = new rxjs.Subject();
8106
+ this._unliked = new rxjs.Subject();
8126
8107
  this._shared = new rxjs.Subject();
8127
8108
  this._userSelected = new rxjs.Subject();
8128
8109
  this._avatarSelected = new rxjs.Subject();
@@ -8130,6 +8111,12 @@
8130
8111
  this.isNew = false;
8131
8112
  this.visible = false;
8132
8113
  this.showReplyAction = true;
8114
+ this.mine = false;
8115
+ this.editing = false;
8116
+ this._editStarted = new rxjs.Subject();
8117
+ this._deleted = new rxjs.Subject();
8118
+ this._editEnded = new rxjs.Subject();
8119
+ this._edited = new rxjs.Subject();
8133
8120
  }
8134
8121
  CommentComponent.prototype.ngOnInit = function () {
8135
8122
  var _this = this;
@@ -8142,6 +8129,14 @@
8142
8129
  setTimeout(function () { return _this.isNew = false; }, 1000);
8143
8130
  }, randomTime);
8144
8131
  };
8132
+ Object.defineProperty(CommentComponent.prototype, "isHighlighted", {
8133
+ get: function () {
8134
+ var _a, _b, _c;
8135
+ return (_c = (_b = (_a = this.message) === null || _a === void 0 ? void 0 : _a.transientState) === null || _b === void 0 ? void 0 : _b.highlighted) !== null && _c !== void 0 ? _c : false;
8136
+ },
8137
+ enumerable: false,
8138
+ configurable: true
8139
+ });
8145
8140
  Object.defineProperty(CommentComponent.prototype, "userSelected", {
8146
8141
  get: function () {
8147
8142
  return this._userSelected.asObservable();
@@ -8170,40 +8165,78 @@
8170
8165
  enumerable: false,
8171
8166
  configurable: true
8172
8167
  });
8173
- Object.defineProperty(CommentComponent.prototype, "upvoted", {
8168
+ CommentComponent.prototype.saveEdit = function () {
8169
+ this._edited.next(this.editedMessage);
8170
+ };
8171
+ CommentComponent.prototype.endEditing = function () {
8172
+ this._editEnded.next();
8173
+ };
8174
+ CommentComponent.prototype.startEdit = function () {
8175
+ this._editStarted.next();
8176
+ this.editedMessage = this.message.message;
8177
+ };
8178
+ CommentComponent.prototype.delete = function () {
8179
+ this._deleted.next();
8180
+ };
8181
+ Object.defineProperty(CommentComponent.prototype, "liked", {
8174
8182
  get: function () {
8175
- return this._upvoted.asObservable();
8183
+ return this._liked.asObservable();
8176
8184
  },
8177
8185
  enumerable: false,
8178
8186
  configurable: true
8179
8187
  });
8180
- Object.defineProperty(CommentComponent.prototype, "selected", {
8188
+ Object.defineProperty(CommentComponent.prototype, "unliked", {
8181
8189
  get: function () {
8182
- return this._selected.asObservable();
8190
+ return this._unliked.asObservable();
8183
8191
  },
8184
8192
  enumerable: false,
8185
8193
  configurable: true
8186
8194
  });
8187
- Object.defineProperty(CommentComponent.prototype, "commentId", {
8195
+ Object.defineProperty(CommentComponent.prototype, "selected", {
8188
8196
  get: function () {
8189
- var _a;
8190
- return (_a = this.message) === null || _a === void 0 ? void 0 : _a.id;
8197
+ return this._selected.asObservable();
8191
8198
  },
8192
8199
  enumerable: false,
8193
8200
  configurable: true
8194
8201
  });
8202
+ Object.defineProperty(CommentComponent.prototype, "edited", {
8203
+ get: function () { return this._edited.asObservable(); },
8204
+ enumerable: false,
8205
+ configurable: true
8206
+ });
8207
+ Object.defineProperty(CommentComponent.prototype, "deleted", {
8208
+ get: function () { return this._deleted.asObservable(); },
8209
+ enumerable: false,
8210
+ configurable: true
8211
+ });
8212
+ Object.defineProperty(CommentComponent.prototype, "editStarted", {
8213
+ get: function () { return this._editStarted.asObservable(); },
8214
+ enumerable: false,
8215
+ configurable: true
8216
+ });
8217
+ Object.defineProperty(CommentComponent.prototype, "editEnded", {
8218
+ get: function () { return this._editEnded.asObservable(); },
8219
+ enumerable: false,
8220
+ configurable: true
8221
+ });
8195
8222
  Object.defineProperty(CommentComponent.prototype, "shared", {
8196
- get: function () {
8197
- return this._shared.asObservable();
8198
- },
8223
+ get: function () { return this._shared.asObservable(); },
8224
+ enumerable: false,
8225
+ configurable: true
8226
+ });
8227
+ Object.defineProperty(CommentComponent.prototype, "commentId", {
8228
+ get: function () { var _a; return (_a = this.message) === null || _a === void 0 ? void 0 : _a.id; },
8199
8229
  enumerable: false,
8200
8230
  configurable: true
8201
8231
  });
8202
8232
  CommentComponent.prototype.report = function () {
8203
8233
  this._reported.next();
8204
8234
  };
8205
- CommentComponent.prototype.upvote = function () {
8206
- this._upvoted.next();
8235
+ CommentComponent.prototype.like = function () {
8236
+ this._liked.next();
8237
+ };
8238
+ CommentComponent.prototype.unlike = function () {
8239
+ this._unliked.next();
8207
8240
  };
8208
8241
  CommentComponent.prototype.share = function () {
8209
8242
  this._shared.next(this.message);
@@ -8234,12 +8267,13 @@
8234
8267
  CommentComponent.decorators = [
8235
8268
  { type: core.Component, args: [{
8236
8269
  selector: 'banta-comment',
8237
- template: "\r\n<mat-menu #pointItemMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"report()\">Report</button>\r\n <button mat-menu-item>Help</button>\r\n</mat-menu>\r\n\r\n<div class=\"message-content\">\r\n <div class=\"user\">\r\n <a\r\n href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"selectAvatar(message.user)\"\r\n [style.background-image]=\"avatarForUser(message.user)\"></a>\r\n <a href=\"javascript:;\" class=\"display-name\" (click)=\"selectUser()\">{{message.user.displayName}}</a>\r\n <a href=\"javascript:;\" class=\"username\" (click)=\"selectUsername(message.user)\">@{{message.user.username}}</a>\r\n </div>\r\n <div class=\"content\">\r\n {{message.message}}\r\n </div>\r\n\r\n <div class=\"actions\">\r\n <banta-timestamp [value]=\"message.sentAt\"></banta-timestamp>\r\n <div class=\"spacer\"></div>\r\n <div class=\"counted-action\" *ngIf=\"showReplyAction\">\r\n <div class=\"count-indicator\">\r\n {{message.submessages?.length || 0}}\r\n </div>\r\n <button mat-icon-button matTooltip=\"Comment\" matTooltipPosition=\"below\" (click)=\"select()\">\r\n <mat-icon [inline]=\"true\">comment</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"counted-action\">\r\n <div class=\"count-indicator\">\r\n {{message.upvotes}}\r\n </div>\r\n <button mat-icon-button matTooltip=\"Upvote\" matTooltipPosition=\"below\" (click)=\"upvote()\">\r\n <mat-icon [inline]=\"true\">thumb_up</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"counted-action\">\r\n <button mat-icon-button matTooltip=\"Share this comment\" matTooltipPosition=\"below\" (click)=\"share()\">\r\n <mat-icon [inline]=\"true\" >share</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <button mat-icon-button [matMenuTriggerFor]=\"pointItemMenu\">\r\n <mat-icon [inline]=\"true\">more_vert</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n",
8238
- styles: ["@-webkit-keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}@keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}:host{display:flex;flex-direction:column;padding:.5em;position:relative;visibility:hidden}:host.new{-webkit-animation-duration:.4s;-webkit-animation-fill-mode:both;-webkit-animation-name:comment-appear;animation-duration:.4s;animation-fill-mode:both;animation-name:comment-appear}:host.new,:host.visible{visibility:visible}:host:hover{background:#eee}:host .message-content .content{margin-left:60px;margin-right:.5em}:host.abbreviated .message-content .content{max-height:8.5em;overflow-y:hidden;text-overflow:ellipsis}:host .actions{align-items:center;display:flex;margin-left:60px;padding-right:10px}:host .actions button{color:#666}:host .actions banta-timestamp{color:#666;font-size:10pt}.user{align-items:center;display:flex;margin:1em 0 0;position:relative}.user .display-name,.user .username{color:#000;display:block;flex-grow:0;flex-shrink:1;font-size:10pt;margin:0 auto 0 0;max-width:100%;overflow:hidden;padding:0 0 0 1em;position:relative;text-overflow:ellipsis;white-space:nowrap;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;z-index:1}.user .display-name.username,.user .username.username{color:#666;flex-grow:1;flex-shrink:0}.avatar{background-color:#333;background-position:50%;background-size:cover;border-radius:100%;flex-grow:0;flex-shrink:0;height:48px;width:48px}.counted-action{align-items:center;display:flex}.count-indicator{color:#666;font-size:9pt;padding:0 0 0 3px}:host-context(.mat-dark-theme) .count-indicator{border-color:#333}:host-context(.mat-dark-theme):hover{background:#060606}:host-context(.mat-dark-theme) .user .display-name,:host-context(.mat-dark-theme) .user .username{color:#fff}@media (max-width:400px){.avatar{height:32px;width:32px}:host .actions{margin-left:44px}:host .message-content .content{margin-left:44px;margin-right:.5em}}"]
8270
+ template: "\r\n<mat-menu #pointItemMenu=\"matMenu\">\r\n <button *ngIf=\"!mine\" mat-menu-item (click)=\"report()\">Report</button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canEdit\" mat-menu-item (click)=\"startEdit()\">Edit</button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canDelete\" mat-menu-item (click)=\"delete()\">Delete</button>\r\n</mat-menu>\r\n\r\n<div class=\"message-content\">\r\n <div class=\"user\">\r\n <a\r\n href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"selectAvatar(message.user)\"\r\n [style.background-image]=\"avatarForUser(message.user)\"></a>\r\n <a href=\"javascript:;\" class=\"display-name\" (click)=\"selectUser()\">{{message.user.displayName}}</a>\r\n <a href=\"javascript:;\" class=\"username\" (click)=\"selectUsername(message.user)\">@{{message.user.username}}</a>\r\n <span class=\"user-tag\" *ngIf=\"message.user.tag\">{{message.user.tag}}</span>\r\n <span class=\"spacer\"></span>\r\n </div>\r\n <div class=\"content\" *ngIf=\"!editing\">\r\n {{message.message}}\r\n </div>\r\n <div class=\"content\" *ngIf=\"editing\" style=\"padding-bottom: 2em;\">\r\n <div>\r\n <mat-form-field floatLabel=\"always\" appearance=\"outline\" style=\"width: 100%;\">\r\n <mat-label>Edit Message</mat-label>\r\n <textarea matInput [(ngModel)]=\"editedMessage\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n <button mat-raised-button (click)=\"saveEdit()\">Save</button> &nbsp;\r\n <button mat-button (click)=\"endEditing()\">Cancel</button>\r\n </div>\r\n\r\n <div class=\"actions\">\r\n <banta-timestamp [value]=\"message.sentAt\"></banta-timestamp>\r\n <ul class=\"message-facts\">\r\n <li *ngIf=\"message.edits?.length > 0\">Edited</li>\r\n </ul>\r\n <div class=\"spacer\"></div>\r\n <div class=\"counted-action\" *ngIf=\"showReplyAction\">\r\n <div class=\"count-indicator\">\r\n {{message.submessages?.length || message.submessageCount || 0}}\r\n </div>\r\n <button mat-icon-button matTooltip=\"Comment\" matTooltipPosition=\"below\" (click)=\"select()\">\r\n <mat-icon [inline]=\"true\">comment</mat-icon>\r\n </button>\r\n </div>\r\n <div class=\"counted-action\" [class.active]=\"message.userState?.liked\">\r\n <div class=\"count-indicator\">\r\n {{message.likes}}\r\n </div>\r\n <button \r\n *ngIf=\"message.transientState?.liking\"\r\n mat-icon-button \r\n [disabled]=\"true\" \r\n [matTooltip]=\"upvoting ? 'Please wait...' : message.userState?.liked ? 'Unlike' : 'Like'\" \r\n matTooltipPosition=\"below\" \r\n >\r\n <mat-spinner [diameter]=\"15\" style=\"margin-left: 1em;\"></mat-spinner>\r\n </button>\r\n <button \r\n *ngIf=\"!message.transientState?.liking\"\r\n mat-icon-button \r\n [disabled]=\"!permissions?.canLike\" \r\n [matTooltip]=\"upvoting ? 'Please wait...' : 'Like'\" \r\n matTooltipPosition=\"below\" \r\n (click)=\"message.userState?.liked ? unlike() : like()\" \r\n >\r\n <mat-icon [inline]=\"true\">thumb_up</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"counted-action\">\r\n <button mat-icon-button matTooltip=\"Share this comment\" matTooltipPosition=\"below\" (click)=\"share()\">\r\n <mat-icon [inline]=\"true\" >share</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <button mat-icon-button [matMenuTriggerFor]=\"pointItemMenu\">\r\n <mat-icon [inline]=\"true\">more_vert</mat-icon>\r\n </button>\r\n </div>\r\n</div>\r\n",
8271
+ styles: ["@-webkit-keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}@keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}:host{display:flex;flex-direction:column;position:relative;padding:.5em;visibility:hidden}:host.new{visibility:visible;-webkit-animation-name:comment-appear;animation-name:comment-appear;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}:host.highlighted{background:#00223a;outline:2px solid #003277}:host.visible{visibility:visible}:host:hover{background:#eee}:host .message-content .content{margin-left:60px;margin-right:.5em}:host.abbreviated .message-content .content{max-height:8.5em;text-overflow:ellipsis;overflow-y:hidden}:host .actions{display:flex;padding-right:10px;margin-left:60px;align-items:center}:host .actions button{color:#666}:host .actions banta-timestamp{color:#666;font-size:10pt}.user{position:relative;margin:1em 0 0;display:flex;align-items:center}.user .display-name,.user .username{z-index:1;position:relative;padding:0 0 0 1em;font-size:10pt;color:#000;margin:0 auto 0 0;display:block;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex-shrink:1;flex-grow:0}.user .display-name.username.username.username,.user .username.username.username.username{color:#666}.avatar{height:48px;width:48px;background-position:50%;background-size:cover;background-color:#333;border-radius:100%;flex-shrink:0;flex-grow:0}.counted-action{display:flex;align-items:center}.counted-action.active .count-indicator,.counted-action.active button{color:#00a5ff}.count-indicator{font-size:9pt;padding:0 0 0 3px;color:#666}:host-context(.mat-dark-theme) .count-indicator{border-color:#333}:host-context(.mat-dark-theme):hover{background:#060606}:host-context(.mat-dark-theme) .user .display-name,:host-context(.mat-dark-theme) .user .username{color:#fff}@media (max-width:400px){.avatar{height:32px;width:32px}:host .actions{margin-left:44px}:host .message-content .content{margin-left:44px;margin-right:.5em}}.user-tag{text-transform:uppercase;font-size:12px;border:1px solid #b27373;background:#7a412b;color:#fff;padding:3px 5px;margin:0 .5em 0 1em;border-radius:3px}.spacer{flex-shrink:1;flex-grow:1}ul.message-facts{margin:0;padding:0;color:#666}ul.message-facts li{list-style-type:none;border-left:1px solid #666;font-size:10pt;padding-left:.5em;margin-left:.5em}"]
8239
8272
  },] }
8240
8273
  ];
8241
8274
  CommentComponent.propDecorators = {
8242
8275
  isNew: [{ type: core.HostBinding, args: ['class.new',] }],
8276
+ isHighlighted: [{ type: core.HostBinding, args: ['class.highlighted',] }],
8243
8277
  visible: [{ type: core.HostBinding, args: ['class.visible',] }],
8244
8278
  message: [{ type: core.Input }],
8245
8279
  showReplyAction: [{ type: core.Input }],
@@ -8247,10 +8281,18 @@
8247
8281
  usernameSelected: [{ type: core.Output }],
8248
8282
  avatarSelected: [{ type: core.Output }],
8249
8283
  reported: [{ type: core.Output }],
8250
- upvoted: [{ type: core.Output }],
8284
+ permissions: [{ type: core.Input }],
8285
+ mine: [{ type: core.Input }],
8286
+ editing: [{ type: core.Input }],
8287
+ liked: [{ type: core.Output }],
8288
+ unliked: [{ type: core.Output }],
8251
8289
  selected: [{ type: core.Output }],
8252
- commentId: [{ type: core.HostBinding, args: ['attr.data-comment-id',] }],
8253
- shared: [{ type: core.Output }]
8290
+ edited: [{ type: core.Output }],
8291
+ deleted: [{ type: core.Output }],
8292
+ editStarted: [{ type: core.Output }],
8293
+ editEnded: [{ type: core.Output }],
8294
+ shared: [{ type: core.Output }],
8295
+ commentId: [{ type: core.HostBinding, args: ['attr.data-comment-id',] }]
8254
8296
  };
8255
8297
 
8256
8298
  var CommentViewComponent = /** @class */ (function () {
@@ -8258,16 +8300,20 @@
8258
8300
  this.backend = backend;
8259
8301
  this._sourceSubs = new rxjs.Subscription();
8260
8302
  this._selected = new rxjs.Subject();
8261
- this._upvoted = new rxjs.Subject();
8303
+ this._liked = new rxjs.Subject();
8304
+ this._unliked = new rxjs.Subject();
8262
8305
  this._reported = new rxjs.Subject();
8263
8306
  this._userSelected = new rxjs.Subject();
8264
8307
  this._usernameSelected = new rxjs.Subject();
8265
8308
  this._avatarSelected = new rxjs.Subject();
8266
8309
  this._shared = new rxjs.Subject();
8310
+ this._deleted = new rxjs.Subject();
8311
+ this._messageEdited = new rxjs.Subject();
8267
8312
  this.showEmptyState = true;
8268
8313
  this.allowReplies = true;
8269
8314
  this.menuMessage = null;
8270
8315
  this.messages = [];
8316
+ this.customSortEnabled = false;
8271
8317
  this.maxMessages = 2000;
8272
8318
  this.maxVisibleMessages = 200;
8273
8319
  this.newestLast = false;
@@ -8276,6 +8322,7 @@
8276
8322
  this.hasMore = false;
8277
8323
  this.newMessages = [];
8278
8324
  this.olderMessages = [];
8325
+ this.sortOrderChanged = new rxjs.Subject();
8279
8326
  }
8280
8327
  Object.defineProperty(CommentViewComponent.prototype, "selected", {
8281
8328
  get: function () {
@@ -8284,45 +8331,53 @@
8284
8331
  enumerable: false,
8285
8332
  configurable: true
8286
8333
  });
8287
- Object.defineProperty(CommentViewComponent.prototype, "userSelected", {
8334
+ Object.defineProperty(CommentViewComponent.prototype, "messageEdited", {
8288
8335
  get: function () {
8289
- return this._userSelected;
8336
+ return this._messageEdited.asObservable();
8290
8337
  },
8291
8338
  enumerable: false,
8292
8339
  configurable: true
8293
8340
  });
8341
+ CommentViewComponent.prototype.saveEdit = function (message, newMessage) {
8342
+ this._messageEdited.next({ message: message, newMessage: newMessage });
8343
+ };
8344
+ Object.defineProperty(CommentViewComponent.prototype, "userSelected", {
8345
+ get: function () { return this._userSelected; },
8346
+ enumerable: false,
8347
+ configurable: true
8348
+ });
8294
8349
  Object.defineProperty(CommentViewComponent.prototype, "reported", {
8295
- get: function () {
8296
- return this._reported;
8297
- },
8350
+ get: function () { return this._reported; },
8298
8351
  enumerable: false,
8299
8352
  configurable: true
8300
8353
  });
8301
- Object.defineProperty(CommentViewComponent.prototype, "upvoted", {
8302
- get: function () {
8303
- return this._upvoted;
8304
- },
8354
+ Object.defineProperty(CommentViewComponent.prototype, "liked", {
8355
+ get: function () { return this._liked; },
8356
+ enumerable: false,
8357
+ configurable: true
8358
+ });
8359
+ Object.defineProperty(CommentViewComponent.prototype, "unliked", {
8360
+ get: function () { return this._unliked; },
8305
8361
  enumerable: false,
8306
8362
  configurable: true
8307
8363
  });
8308
8364
  Object.defineProperty(CommentViewComponent.prototype, "usernameSelected", {
8309
- get: function () {
8310
- return this._usernameSelected;
8311
- },
8365
+ get: function () { return this._usernameSelected; },
8312
8366
  enumerable: false,
8313
8367
  configurable: true
8314
8368
  });
8315
8369
  Object.defineProperty(CommentViewComponent.prototype, "avatarSelected", {
8316
- get: function () {
8317
- return this._avatarSelected;
8318
- },
8370
+ get: function () { return this._avatarSelected; },
8319
8371
  enumerable: false,
8320
8372
  configurable: true
8321
8373
  });
8322
8374
  Object.defineProperty(CommentViewComponent.prototype, "shared", {
8323
- get: function () {
8324
- return this._shared;
8325
- },
8375
+ get: function () { return this._shared; },
8376
+ enumerable: false,
8377
+ configurable: true
8378
+ });
8379
+ Object.defineProperty(CommentViewComponent.prototype, "deleted", {
8380
+ get: function () { return this._deleted; },
8326
8381
  enumerable: false,
8327
8382
  configurable: true
8328
8383
  });
@@ -8332,30 +8387,35 @@
8332
8387
  },
8333
8388
  set: function (value) {
8334
8389
  var _this = this;
8390
+ this.customSortEnabled = (value === null || value === void 0 ? void 0 : value.sortOrder) !== common$1.CommentsOrder.NEWEST;
8391
+ this.newMessages = [];
8392
+ this.olderMessages = [];
8393
+ window.bantaSourceDebug = value;
8335
8394
  if (this._sourceSubs) {
8336
8395
  this._sourceSubs.unsubscribe();
8337
8396
  this._sourceSubs = null;
8338
8397
  }
8339
8398
  this._source = value;
8340
8399
  if (value) {
8341
- console.log("[banta-comment-view] Subscribing to source...");
8342
8400
  var messages = (value.messages || []).slice();
8343
8401
  this.messages = messages;
8344
8402
  this.olderMessages = messages.splice(this.maxVisibleMessages, messages.length);
8345
- this.hasMore = this.olderMessages.length > 0;
8403
+ this.hasMore = true; //this.olderMessages.length > 0;
8346
8404
  this._sourceSubs = new rxjs.Subscription();
8347
8405
  this._sourceSubs.add(this._source.messageReceived.subscribe(function (msg) { return _this.messageReceived(msg); }));
8348
8406
  this._sourceSubs.add(this._source.messageSent.subscribe(function (msg) { return _this.messageSent(msg); }));
8349
- if (this._source.currentUserChanged) {
8350
- this._sourceSubs.add(this._source.currentUserChanged.subscribe(function (user) { return _this.currentUser = user; }));
8351
- }
8407
+ this._sourceSubs.add(this.backend.userChanged.subscribe(function (user) { return _this.currentUser = user; }));
8408
+ this.getInitialMessages();
8352
8409
  }
8353
8410
  },
8354
8411
  enumerable: false,
8355
8412
  configurable: true
8356
8413
  });
8357
- CommentViewComponent.prototype.upvoteMessage = function (message) {
8358
- this._upvoted.next(message);
8414
+ CommentViewComponent.prototype.likeMessage = function (message) {
8415
+ this._liked.next(message);
8416
+ };
8417
+ CommentViewComponent.prototype.unlikeMessage = function (message) {
8418
+ this._unliked.next(message);
8359
8419
  };
8360
8420
  CommentViewComponent.prototype.reportMessage = function (message) {
8361
8421
  this._reported.next(message);
@@ -8375,13 +8435,39 @@
8375
8435
  CommentViewComponent.prototype.sharedMessage = function (message) {
8376
8436
  this._shared.next(message);
8377
8437
  };
8438
+ CommentViewComponent.prototype.startEditing = function (message) {
8439
+ this.messages.forEach(function (m) { return m.transientState.editing = false; });
8440
+ message.transientState.editing = true;
8441
+ };
8442
+ CommentViewComponent.prototype.deleteMessage = function (message) {
8443
+ this._deleted.next(message);
8444
+ };
8445
+ CommentViewComponent.prototype.getInitialMessages = function () {
8446
+ return __awaiter(this, void 0, void 0, function () {
8447
+ var messages;
8448
+ return __generator(this, function (_b) {
8449
+ switch (_b.label) {
8450
+ case 0: return [4 /*yield*/, this._source.getExistingMessages()];
8451
+ case 1:
8452
+ messages = (_b.sent());
8453
+ messages.forEach(function (m) { var _a; return (_a = m.transientState) !== null && _a !== void 0 ? _a : (m.transientState = {}); });
8454
+ this.messages = messages;
8455
+ return [2 /*return*/];
8456
+ }
8457
+ });
8458
+ });
8459
+ };
8378
8460
  CommentViewComponent.prototype.messageIdentity = function (index, chatMessage) {
8379
8461
  return chatMessage.id;
8380
8462
  };
8381
8463
  CommentViewComponent.prototype.showNew = function () {
8382
8464
  return __awaiter(this, void 0, void 0, function () {
8383
8465
  var overflow;
8384
- return __generator(this, function (_a) {
8466
+ return __generator(this, function (_b) {
8467
+ if (this.source && this.source.sortOrder !== common$1.CommentsOrder.NEWEST) {
8468
+ this.sortOrderChanged.next(common$1.CommentsOrder.NEWEST);
8469
+ return [2 /*return*/];
8470
+ }
8385
8471
  this.isViewingMore = false;
8386
8472
  this.messages = this.newMessages.splice(0, this.newMessages.length).concat(this.messages);
8387
8473
  overflow = this.messages.splice(this.maxVisibleMessages, this.messages.length);
@@ -8393,43 +8479,53 @@
8393
8479
  };
8394
8480
  CommentViewComponent.prototype.showMore = function () {
8395
8481
  return __awaiter(this, void 0, void 0, function () {
8396
- var lastMessage, messages;
8397
- return __generator(this, function (_a) {
8398
- switch (_a.label) {
8482
+ var nextPageSize, lastMessage, messages;
8483
+ return __generator(this, function (_b) {
8484
+ switch (_b.label) {
8399
8485
  case 0:
8400
8486
  this.isViewingMore = true;
8401
8487
  if (!(this.olderMessages.length > 0)) return [3 /*break*/, 1];
8402
8488
  this.isLoadingMore = false;
8403
8489
  this.messages = this.messages.concat(this.olderMessages.splice(0, 50));
8404
- return [3 /*break*/, 4];
8490
+ return [3 /*break*/, 3];
8405
8491
  case 1:
8406
- if (!this.source.loadAfter) return [3 /*break*/, 3];
8407
8492
  this.isLoadingMore = true;
8493
+ nextPageSize = 20;
8494
+ lastMessage = void 0;
8408
8495
  lastMessage = this.messages[this.messages.length - 1];
8409
- return [4 /*yield*/, this.source.loadAfter(lastMessage, 100)];
8496
+ if (!lastMessage) {
8497
+ this.isLoadingMore = false;
8498
+ this.hasMore = false;
8499
+ return [2 /*return*/];
8500
+ }
8501
+ return [4 /*yield*/, this.source.loadAfter(lastMessage, nextPageSize)];
8410
8502
  case 2:
8411
- messages = _a.sent();
8503
+ messages = _b.sent();
8504
+ messages.forEach(function (m) { var _a; return (_a = m.transientState) !== null && _a !== void 0 ? _a : (m.transientState = {}); });
8412
8505
  this.messages = this.messages.concat(messages);
8413
8506
  this.isLoadingMore = false;
8414
- if (messages.length === 0)
8507
+ if (messages.length === 0) {
8508
+ console.log("Reached the end of the list.");
8415
8509
  this.hasMore = false;
8416
- return [3 /*break*/, 4];
8417
- case 3:
8418
- this.hasMore = false;
8419
- _a.label = 4;
8420
- case 4: return [2 /*return*/];
8510
+ }
8511
+ _b.label = 3;
8512
+ case 3: return [2 /*return*/];
8421
8513
  }
8422
8514
  });
8423
8515
  });
8424
8516
  };
8425
8517
  CommentViewComponent.prototype.addMessage = function (message) {
8518
+ var _a;
8519
+ if (!message.transientState)
8520
+ (_a = message.transientState) !== null && _a !== void 0 ? _a : (message.transientState = {});
8426
8521
  var destination = this.messages;
8427
8522
  var bucket = this.olderMessages;
8428
8523
  if (this.isViewingMore) {
8429
8524
  destination = this.newMessages;
8430
8525
  bucket = null;
8431
8526
  }
8432
- if (this.newestLast) {
8527
+ var newestLast = this.newestLast;
8528
+ if (newestLast) {
8433
8529
  destination.push(message);
8434
8530
  var overflow = destination.splice(this.maxVisibleMessages, destination.length);
8435
8531
  bucket === null || bucket === void 0 ? void 0 : bucket.push.apply(bucket, __spread(overflow));
@@ -8486,41 +8582,63 @@
8486
8582
  CommentViewComponent.decorators = [
8487
8583
  { type: core.Component, args: [{
8488
8584
  selector: 'banta-comment-view',
8489
- 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\" 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 [message]=\"message\"\r\n (click)=\"isViewingMore = true\"\r\n [showReplyAction]=\"allowReplies\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (upvoted)=\"upvoteMessage(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",
8490
- styles: [":host{display:flex;flex-direction:column;flex-grow:1;opacity:1;transition:opacity .2s ease-in}.message-container{background:#fff;color:#111;flex-grow:1;opacity:1;overflow-x:hidden;padding:.5em 1em 3em .5em;position:relative;transition:opacity .5s ease-in-out}.message-container.no-scroll{height:auto;overflow-y:visible}.message-container.faded{opacity:.25}.message-container .overlay{bottom:0;left:0;position:absolute;right:0;top:0;z-index:10}:host.fixed-height .message-container{overflow-y:auto}:host-context(.mat-dark-theme) .message-container{background:#111;color:#fff}.empty-state{color:#666;margin:3em;text-align:center}:host-context(.mat-dark-theme) .empty-state{color:#666}a.nav{background:#222;border-radius:2em;opacity:0;pointer-events:none;position:absolute;right:.5em;text-align:center;transition:opacity .4s ease-in-out;z-index:10}a.nav.visible{opacity:1;pointer-events:auto}.loading-more{margin:0 auto;padding:2em;text-align:center;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}@media (max-width:400px){.message-container{padding:0 0 3em}}"]
8585
+ 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",
8586
+ 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}}"]
8491
8587
  },] }
8492
8588
  ];
8493
8589
  CommentViewComponent.ctorParameters = function () { return [
8494
- { type: ChatBackendService }
8590
+ { type: ChatBackendBase }
8495
8591
  ]; };
8496
8592
  CommentViewComponent.propDecorators = {
8497
8593
  showEmptyState: [{ type: core.Input }],
8498
8594
  allowReplies: [{ type: core.Input }],
8499
8595
  fixedHeight: [{ type: core.Input }, { type: core.HostBinding, args: ['class.fixed-height',] }],
8500
8596
  selected: [{ type: core.Output }],
8597
+ messageEdited: [{ type: core.Output }],
8501
8598
  userSelected: [{ type: core.Output }],
8502
8599
  reported: [{ type: core.Output }],
8503
- upvoted: [{ type: core.Output }],
8600
+ liked: [{ type: core.Output }],
8601
+ unliked: [{ type: core.Output }],
8504
8602
  usernameSelected: [{ type: core.Output }],
8505
8603
  avatarSelected: [{ type: core.Output }],
8506
8604
  shared: [{ type: core.Output }],
8605
+ deleted: [{ type: core.Output }],
8507
8606
  source: [{ type: core.Input }],
8508
8607
  genericAvatarUrl: [{ type: core.Input }],
8509
8608
  messageContainer: [{ type: core.ViewChild, args: ['messageContainer',] }],
8510
8609
  maxMessages: [{ type: core.Input }],
8511
8610
  maxVisibleMessages: [{ type: core.Input }],
8512
- newestLast: [{ type: core.Input }]
8611
+ newestLast: [{ type: core.Input }],
8612
+ sortOrderChanged: [{ type: core.Output }]
8513
8613
  };
8514
8614
 
8515
8615
  /**
8516
8616
  * Comments component
8517
8617
  */
8518
8618
  var BantaCommentsComponent = /** @class */ (function () {
8519
- function BantaCommentsComponent(banta, backend, elementRef, activatedRoute) {
8520
- this.banta = banta;
8619
+ function BantaCommentsComponent(backend, elementRef, activatedRoute) {
8620
+ var _this = this;
8521
8621
  this.backend = backend;
8522
8622
  this.elementRef = elementRef;
8523
8623
  this.activatedRoute = activatedRoute;
8624
+ // Loading Screen
8625
+ this._loadingMessage = '';
8626
+ this.loadingMessageVisible = false;
8627
+ this.loading = true;
8628
+ this.showLoadingScreen = false;
8629
+ this._loadingMessageIndex = 0;
8630
+ this.loadingMessages = [
8631
+ "Just a second...",
8632
+ "We're definitely working on it.",
8633
+ "There's no need to refresh.",
8634
+ "It's definitely worth the wait!",
8635
+ "This has never happened before.",
8636
+ "We'll keep trying, but it's not looking great. \n Commenting & chat services may be down. \n If you continue to experience issues, please contact support.\n "
8637
+ ];
8638
+ // Properties
8639
+ this._signInSelected = new rxjs.Subject();
8640
+ this._permissionDeniedError = new rxjs.Subject();
8641
+ this._editAvatarSelected = new rxjs.Subject();
8524
8642
  this._upvoted = new rxjs.Subject();
8525
8643
  this._reported = new rxjs.Subject();
8526
8644
  this._selected = new rxjs.Subject();
@@ -8530,12 +8648,8 @@
8530
8648
  this._avatarSelected = new rxjs.Subject();
8531
8649
  this._subs = new rxjs.Subscription();
8532
8650
  this._sortOrder = common$1.CommentsOrder.NEWEST;
8533
- this.hashtags = [
8534
- { hashtag: 'error', description: 'Cause an error' },
8535
- { hashtag: 'timeout', description: 'Cause a slow timeout error' },
8536
- { hashtag: 'slow', description: 'Be slow when this message is posted' },
8537
- ];
8538
- this.participants = [];
8651
+ this.selectedMessageVisible = false;
8652
+ // Inputs
8539
8653
  this.signInLabel = 'Sign In';
8540
8654
  this.sendLabel = 'Send';
8541
8655
  this.replyLabel = 'Reply';
@@ -8543,97 +8657,113 @@
8543
8657
  this.permissionDeniedLabel = 'Send';
8544
8658
  this.postCommentLabel = 'Post a comment';
8545
8659
  this.postReplyLabel = 'Post a reply';
8546
- this._signInSelected = new rxjs.Subject();
8547
- this._permissionDeniedError = new rxjs.Subject();
8548
- this._editAvatarSelected = new rxjs.Subject();
8549
- this.sending = false;
8550
- this.expandError = false;
8551
- this.selectedMessageVisible = false;
8660
+ this.participants = [];
8661
+ this.hashtags = [
8662
+ { hashtag: 'error', description: 'Cause an error' },
8663
+ { hashtag: 'timeout', description: 'Cause a slow timeout error' },
8664
+ { hashtag: 'slow', description: 'Be slow when this message is posted' },
8665
+ ];
8666
+ this.sendMessage = function (message) { return __awaiter(_this, void 0, void 0, function () {
8667
+ var _a, intercept, e_1;
8668
+ return __generator(this, function (_d) {
8669
+ switch (_d.label) {
8670
+ case 0:
8671
+ _d.trys.push([0, 4, , 5]);
8672
+ return [4 /*yield*/, ((_a = this.shouldInterceptMessageSend) === null || _a === void 0 ? void 0 : _a.call(this, message, this.source))];
8673
+ case 1:
8674
+ intercept = _d.sent();
8675
+ if (!!intercept) return [3 /*break*/, 3];
8676
+ return [4 /*yield*/, this.source.send(message)];
8677
+ case 2:
8678
+ _d.sent();
8679
+ _d.label = 3;
8680
+ case 3:
8681
+ if (this.source.sortOrder !== common$1.CommentsOrder.NEWEST) {
8682
+ this.sortOrder = common$1.CommentsOrder.NEWEST;
8683
+ }
8684
+ return [2 /*return*/, true];
8685
+ case 4:
8686
+ e_1 = _d.sent();
8687
+ console.error("Failed to send message: ", message);
8688
+ console.error(e_1);
8689
+ throw new Error("Could not send: " + e_1.message);
8690
+ case 5: return [2 /*return*/];
8691
+ }
8692
+ });
8693
+ }); };
8694
+ this.sendReply = function (message) { return __awaiter(_this, void 0, void 0, function () {
8695
+ var _b, intercept, e_2;
8696
+ return __generator(this, function (_d) {
8697
+ switch (_d.label) {
8698
+ case 0:
8699
+ _d.trys.push([0, 4, , 5]);
8700
+ return [4 /*yield*/, ((_b = this.shouldInterceptMessageSend) === null || _b === void 0 ? void 0 : _b.call(this, message, this.source))];
8701
+ case 1:
8702
+ intercept = _d.sent();
8703
+ if (!!intercept) return [3 /*break*/, 3];
8704
+ return [4 /*yield*/, this.selectedMessageThread.send(message)];
8705
+ case 2:
8706
+ _d.sent();
8707
+ _d.label = 3;
8708
+ case 3: return [2 /*return*/, true];
8709
+ case 4:
8710
+ e_2 = _d.sent();
8711
+ console.error("Failed to send message: ", message);
8712
+ console.error(e_2);
8713
+ throw new Error("Could not send reply: " + e_2.message);
8714
+ case 5: return [2 /*return*/];
8715
+ }
8716
+ });
8717
+ }); };
8552
8718
  }
8553
- Object.defineProperty(BantaCommentsComponent.prototype, "sortOrder", {
8554
- get: function () {
8555
- return this._sortOrder;
8556
- },
8557
- set: function (value) {
8558
- var _this = this;
8559
- if (this._sortOrder !== value) {
8560
- this._sortOrder = value;
8561
- setTimeout(function () {
8562
- _this.setSourceFromTopicID(_this.topicID);
8563
- });
8564
- }
8565
- },
8566
- enumerable: false,
8567
- configurable: true
8568
- });
8719
+ // Lifecycle Events / Initialization
8569
8720
  BantaCommentsComponent.prototype.ngOnInit = function () {
8570
8721
  var _this = this;
8571
- this._subs.add(this.banta.userChanged.subscribe(function (user) { return _this.user = user; }));
8572
- };
8573
- BantaCommentsComponent.prototype.ngAfterViewInit = function () {
8574
- if (typeof window !== 'undefined')
8575
- this.checkForSharedComment();
8576
- };
8577
- BantaCommentsComponent.prototype.scrollToComment = function (commentId) {
8578
- setTimeout(function () {
8579
- var comment = document.querySelectorAll("[data-comment-id=\"" + commentId + "\"]");
8580
- console.log(comment);
8581
- if (comment.length > 0) {
8582
- // comment.item(0).scroll({behavior: 'smooth'});
8583
- comment.item(0).scrollIntoView();
8722
+ this._subs.add(this.backend.userChanged.subscribe(function (user) { return _this.user = user; }));
8723
+ this.startLoading();
8724
+ console.log("Checking...");
8725
+ if (typeof window !== 'undefined') {
8726
+ var queryString = window.location.search.substring(1);
8727
+ var query = queryString.split('&')
8728
+ .map(function (s) { return s.split('='); })
8729
+ .reduce(function (o, _d) {
8730
+ var _e = __read(_d, 2), k = _e[0], v = _e[1];
8731
+ return (o[k] = v, o);
8732
+ }, {});
8733
+ console.log('here:');
8734
+ console.dir(query);
8735
+ var commentID = query['comment'];
8736
+ if (commentID) {
8737
+ this.sharedCommentID = commentID;
8584
8738
  }
8585
- }, 1000);
8586
- };
8587
- BantaCommentsComponent.prototype.checkForSharedComment = function () {
8588
- var commentID = this.activatedRoute.snapshot.queryParamMap.get('comment');
8589
- if (commentID)
8590
- this.scrollToComment(commentID);
8739
+ }
8591
8740
  };
8592
8741
  BantaCommentsComponent.prototype.ngOnDestroy = function () {
8593
8742
  this._subs.unsubscribe();
8594
8743
  };
8595
- Object.defineProperty(BantaCommentsComponent.prototype, "source", {
8596
- get: function () {
8597
- return this._source;
8598
- },
8599
- set: function (value) {
8600
- this._source = value;
8601
- },
8602
- enumerable: false,
8603
- configurable: true
8604
- });
8605
- Object.defineProperty(BantaCommentsComponent.prototype, "topicID", {
8606
- get: function () {
8607
- return this._topicID;
8608
- },
8609
- set: function (value) {
8610
- var _this = this;
8611
- if (this._topicID !== value) {
8612
- this._topicID = value;
8613
- setTimeout(function () { return _this.setSourceFromTopicID(value); });
8614
- }
8615
- },
8616
- enumerable: false,
8617
- configurable: true
8618
- });
8619
8744
  BantaCommentsComponent.prototype.setSourceFromTopicID = function (topicID) {
8620
- var _a, _b;
8621
8745
  return __awaiter(this, void 0, void 0, function () {
8622
8746
  var _this = this;
8623
- return __generator(this, function (_c) {
8624
- (_b = (_a = this._source) === null || _a === void 0 ? void 0 : _a.close) === null || _b === void 0 ? void 0 : _b.call(_a);
8625
- this._source = null;
8747
+ return __generator(this, function (_d) {
8748
+ if (this._source) {
8749
+ this._source.close();
8750
+ this._source = null;
8751
+ }
8626
8752
  setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
8627
- var _c;
8753
+ var _d;
8628
8754
  var _this = this;
8629
- return __generator(this, function (_d) {
8630
- switch (_d.label) {
8755
+ return __generator(this, function (_e) {
8756
+ switch (_e.label) {
8631
8757
  case 0:
8632
- _c = this;
8758
+ console.log("[banta-comments] Subscribing to topic source '" + topicID + "'");
8759
+ _d = this;
8633
8760
  return [4 /*yield*/, this.backend.getSourceForTopic(topicID, { sortOrder: this.sortOrder })];
8634
8761
  case 1:
8635
- _c._source = _d.sent();
8636
- console.log("[banta-comments] Subscribing to source for topic '" + topicID + "'");
8762
+ _d._source = _e.sent();
8763
+ if (this.sharedCommentID) {
8764
+ this.navigateToSharedComment(this.sharedCommentID);
8765
+ this.sharedCommentID = null;
8766
+ }
8637
8767
  this._source.messageReceived.subscribe(function (m) { return _this.addParticipant(m); });
8638
8768
  this._source.messageSent.subscribe(function (m) { return _this.addParticipant(m); });
8639
8769
  this._source.messages.forEach(function (m) { return _this.addParticipant(m); });
@@ -8645,162 +8775,331 @@
8645
8775
  });
8646
8776
  });
8647
8777
  };
8648
- BantaCommentsComponent.prototype.addParticipant = function (message) {
8649
- if (!message || !message.user || !message.user.id)
8650
- return;
8651
- var existing = this.participants.find(function (x) { return x.id === message.user.id; });
8652
- if (existing)
8653
- return;
8654
- this.participants.push(message.user);
8655
- };
8656
- BantaCommentsComponent.prototype.showSignIn = function () {
8657
- this._signInSelected.next();
8658
- };
8659
- BantaCommentsComponent.prototype.showEditAvatar = function () {
8660
- this._editAvatarSelected.next();
8661
- };
8662
- Object.defineProperty(BantaCommentsComponent.prototype, "newMessageText", {
8778
+ Object.defineProperty(BantaCommentsComponent.prototype, "loadingMessage", {
8663
8779
  get: function () {
8664
- return this._newMessageText;
8780
+ return this._loadingMessage;
8665
8781
  },
8666
8782
  set: function (value) {
8667
8783
  var _this = this;
8668
- this._newMessageText = value;
8669
- if (this._newMessageText === '' && this.sendError)
8670
- setTimeout(function () { return _this.sendError = null; });
8784
+ this.loadingMessageVisible = false;
8785
+ setTimeout(function () {
8786
+ _this._loadingMessage = value;
8787
+ _this._loadingMessage = value;
8788
+ setTimeout(function () {
8789
+ _this.loadingMessageVisible = true;
8790
+ });
8791
+ }, 500);
8671
8792
  },
8672
8793
  enumerable: false,
8673
8794
  configurable: true
8674
8795
  });
8675
- Object.defineProperty(BantaCommentsComponent.prototype, "signInSelected", {
8676
- get: function () {
8677
- return this._signInSelected;
8796
+ BantaCommentsComponent.prototype.startLoading = function () {
8797
+ return __awaiter(this, void 0, void 0, function () {
8798
+ var _this = this;
8799
+ return __generator(this, function (_d) {
8800
+ switch (_d.label) {
8801
+ case 0:
8802
+ this.loadingStartedAt = this.messageChangedAt = Date.now();
8803
+ if (this.updateLoading())
8804
+ return [2 /*return*/];
8805
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 100); })];
8806
+ case 1:
8807
+ _d.sent();
8808
+ if (this.updateLoading())
8809
+ return [2 /*return*/];
8810
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 250); })];
8811
+ case 2:
8812
+ _d.sent();
8813
+ if (this.updateLoading())
8814
+ return [2 /*return*/];
8815
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 500); })];
8816
+ case 3:
8817
+ _d.sent();
8818
+ if (this.updateLoading())
8819
+ return [2 /*return*/];
8820
+ console.log("[Banta] Loading is taking a long time! Showing loading screen.");
8821
+ this.showLoadingScreen = true;
8822
+ if (typeof window !== 'undefined')
8823
+ this._loadingTimer = setInterval(function () { return _this.updateLoading(); }, 1000);
8824
+ return [2 /*return*/];
8825
+ }
8826
+ });
8827
+ });
8828
+ };
8829
+ BantaCommentsComponent.prototype.updateLoading = function () {
8830
+ var _this = this;
8831
+ var _a, _b, _c;
8832
+ if (((_a = this.source) === null || _a === void 0 ? void 0 : _a.state) && ((_b = this.source) === null || _b === void 0 ? void 0 : _b.state) !== 'connecting') {
8833
+ clearInterval(this._loadingTimer);
8834
+ this.loadingMessage = "Here we go!";
8835
+ setTimeout(function () {
8836
+ _this.loading = false;
8837
+ }, 750);
8838
+ return true;
8839
+ }
8840
+ console.log("[Banta] Status check: " + (((_c = this.source) === null || _c === void 0 ? void 0 : _c.state) || 'connecting'));
8841
+ var messageSwitchTime = 5 * 1000;
8842
+ if (this.messageChangedAt + messageSwitchTime < Date.now()) {
8843
+ if (this.loadingMessages[this._loadingMessageIndex]) {
8844
+ this.loadingMessage = this.loadingMessages[this._loadingMessageIndex++];
8845
+ this.messageChangedAt = Date.now();
8846
+ }
8847
+ }
8848
+ return false;
8849
+ };
8850
+ Object.defineProperty(BantaCommentsComponent.prototype, "source", {
8851
+ get: function () { return this._source; },
8852
+ set: function (value) {
8853
+ this._source = value;
8854
+ if (value && this.sharedCommentID) {
8855
+ this.navigateToSharedComment(this.sharedCommentID);
8856
+ this.sharedCommentID = null;
8857
+ }
8678
8858
  },
8679
8859
  enumerable: false,
8680
8860
  configurable: true
8681
8861
  });
8682
- Object.defineProperty(BantaCommentsComponent.prototype, "editAvatarSelected", {
8683
- get: function () {
8684
- return this._editAvatarSelected;
8862
+ Object.defineProperty(BantaCommentsComponent.prototype, "topicID", {
8863
+ get: function () { return this._topicID; },
8864
+ set: function (value) {
8865
+ var _this = this;
8866
+ if (this._topicID !== value) {
8867
+ this._topicID = value;
8868
+ setTimeout(function () { return _this.setSourceFromTopicID(value); });
8869
+ }
8685
8870
  },
8686
8871
  enumerable: false,
8687
8872
  configurable: true
8688
8873
  });
8689
- Object.defineProperty(BantaCommentsComponent.prototype, "permissionDeniedError", {
8690
- get: function () {
8691
- return this._permissionDeniedError;
8692
- },
8874
+ Object.defineProperty(BantaCommentsComponent.prototype, "signInSelected", {
8875
+ // Outputs
8876
+ get: function () { return this._signInSelected; },
8693
8877
  enumerable: false,
8694
8878
  configurable: true
8695
8879
  });
8696
- BantaCommentsComponent.prototype.showPermissionDenied = function () {
8697
- this._permissionDeniedError.next();
8698
- };
8699
- Object.defineProperty(BantaCommentsComponent.prototype, "canComment", {
8700
- get: function () {
8701
- var _a;
8702
- if (!this.user)
8703
- return false;
8704
- if (!this.user.permissions)
8705
- return true;
8706
- if (!this.user.permissions.canComment)
8707
- return true;
8708
- return (_a = this.user.permissions) === null || _a === void 0 ? void 0 : _a.canComment(this.source);
8709
- },
8880
+ Object.defineProperty(BantaCommentsComponent.prototype, "editAvatarSelected", {
8881
+ get: function () { return this._editAvatarSelected; },
8882
+ enumerable: false,
8883
+ configurable: true
8884
+ });
8885
+ Object.defineProperty(BantaCommentsComponent.prototype, "permissionDeniedError", {
8886
+ get: function () { return this._permissionDeniedError; },
8710
8887
  enumerable: false,
8711
8888
  configurable: true
8712
8889
  });
8713
8890
  Object.defineProperty(BantaCommentsComponent.prototype, "upvoted", {
8714
- get: function () {
8715
- return this._upvoted.asObservable();
8716
- },
8891
+ get: function () { return this._upvoted.asObservable(); },
8717
8892
  enumerable: false,
8718
8893
  configurable: true
8719
8894
  });
8720
8895
  Object.defineProperty(BantaCommentsComponent.prototype, "reported", {
8721
- get: function () {
8722
- return this._reported.asObservable();
8723
- },
8896
+ get: function () { return this._reported.asObservable(); },
8724
8897
  enumerable: false,
8725
8898
  configurable: true
8726
8899
  });
8727
8900
  Object.defineProperty(BantaCommentsComponent.prototype, "selected", {
8728
- get: function () {
8729
- return this._selected.asObservable();
8730
- },
8901
+ get: function () { return this._selected.asObservable(); },
8731
8902
  enumerable: false,
8732
8903
  configurable: true
8733
8904
  });
8734
8905
  Object.defineProperty(BantaCommentsComponent.prototype, "userSelected", {
8735
- get: function () {
8736
- return this._userSelected.asObservable();
8737
- },
8906
+ get: function () { return this._userSelected.asObservable(); },
8738
8907
  enumerable: false,
8739
8908
  configurable: true
8740
8909
  });
8741
8910
  Object.defineProperty(BantaCommentsComponent.prototype, "usernameSelected", {
8742
- get: function () {
8743
- return this._usernameSelected.asObservable();
8744
- },
8911
+ get: function () { return this._usernameSelected.asObservable(); },
8745
8912
  enumerable: false,
8746
8913
  configurable: true
8747
8914
  });
8748
8915
  Object.defineProperty(BantaCommentsComponent.prototype, "avatarSelected", {
8749
- get: function () {
8750
- return this._avatarSelected.asObservable();
8751
- },
8916
+ get: function () { return this._avatarSelected.asObservable(); },
8752
8917
  enumerable: false,
8753
8918
  configurable: true
8754
8919
  });
8755
8920
  Object.defineProperty(BantaCommentsComponent.prototype, "shared", {
8756
- get: function () {
8757
- return this._shared.asObservable();
8921
+ get: function () { return this._shared.asObservable(); },
8922
+ enumerable: false,
8923
+ configurable: true
8924
+ });
8925
+ Object.defineProperty(BantaCommentsComponent.prototype, "sortOrder", {
8926
+ get: function () { return this._sortOrder; },
8927
+ set: function (value) {
8928
+ var _this = this;
8929
+ if (this._sortOrder !== value) {
8930
+ this._sortOrder = value;
8931
+ setTimeout(function () {
8932
+ _this.setSourceFromTopicID(_this.topicID);
8933
+ });
8934
+ }
8758
8935
  },
8759
8936
  enumerable: false,
8760
8937
  configurable: true
8761
8938
  });
8762
- BantaCommentsComponent.prototype.onKeyDown = function (event) {
8939
+ // UI Interactions
8940
+ BantaCommentsComponent.prototype.scrollToComment = function (commentId) {
8941
+ setTimeout(function () {
8942
+ var comment = document.querySelectorAll("[data-comment-id=\"" + commentId + "\"]");
8943
+ console.dir(comment);
8944
+ if (comment.length > 0) {
8945
+ // comment.item(0).scroll({behavior: 'smooth'});
8946
+ comment.item(0).scrollIntoView();
8947
+ }
8948
+ }, 1000);
8763
8949
  };
8764
- BantaCommentsComponent.prototype.insertEmoji = function (text) {
8765
- this.newMessageText += text;
8950
+ BantaCommentsComponent.prototype.navigateToSharedComment = function (id) {
8951
+ var _a, _b, _c;
8952
+ return __awaiter(this, void 0, void 0, function () {
8953
+ var source, message, e_3, parentMessage, thread;
8954
+ return __generator(this, function (_d) {
8955
+ switch (_d.label) {
8956
+ case 0:
8957
+ source = this.source;
8958
+ return [4 /*yield*/, source.ready];
8959
+ case 1:
8960
+ _d.sent();
8961
+ console.log("Navigating to shared comment with ID '" + id + "'...");
8962
+ _d.label = 2;
8963
+ case 2:
8964
+ _d.trys.push([2, 4, , 5]);
8965
+ return [4 /*yield*/, this.source.get(id)];
8966
+ case 3:
8967
+ message = _d.sent();
8968
+ return [3 /*break*/, 5];
8969
+ case 4:
8970
+ e_3 = _d.sent();
8971
+ console.error("Failed to find comment from URL: " + e_3.message);
8972
+ return [2 /*return*/];
8973
+ case 5:
8974
+ (_a = message.transientState) !== null && _a !== void 0 ? _a : (message.transientState = {});
8975
+ if (!message.parentMessageId) return [3 /*break*/, 11];
8976
+ return [4 /*yield*/, this.source.get(message.parentMessageId)];
8977
+ case 6:
8978
+ parentMessage = _d.sent();
8979
+ (_b = parentMessage.transientState) !== null && _b !== void 0 ? _b : (parentMessage.transientState = {});
8980
+ return [4 /*yield*/, this.selectMessage(parentMessage)];
8981
+ case 7:
8982
+ thread = _d.sent();
8983
+ // Need to re-retrieve the message within the new chat source to affect its
8984
+ // transient state.
8985
+ return [4 /*yield*/, thread.ready];
8986
+ case 8:
8987
+ // Need to re-retrieve the message within the new chat source to affect its
8988
+ // transient state.
8989
+ _d.sent();
8990
+ return [4 /*yield*/, thread.get(message.id)];
8991
+ case 9:
8992
+ message = _d.sent();
8993
+ (_c = message.transientState) !== null && _c !== void 0 ? _c : (message.transientState = {});
8994
+ message.transientState.highlighted = true;
8995
+ console.dir(message);
8996
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 500); })];
8997
+ case 10:
8998
+ _d.sent();
8999
+ return [3 /*break*/, 12];
9000
+ case 11:
9001
+ this.selectMessage(message);
9002
+ _d.label = 12;
9003
+ case 12:
9004
+ this.scrollToComment(id);
9005
+ return [2 /*return*/];
9006
+ }
9007
+ });
9008
+ });
8766
9009
  };
8767
- BantaCommentsComponent.prototype.onReplyKeyDown = function (event) {
9010
+ BantaCommentsComponent.prototype.showPermissionDenied = function () {
9011
+ this._permissionDeniedError.next();
8768
9012
  };
8769
- BantaCommentsComponent.prototype.insertReplyEmoji = function (text) {
8770
- this.replyMessage += text;
9013
+ BantaCommentsComponent.prototype.scrollToMessage = function (message) {
9014
+ var el = this.elementRef.nativeElement.querySelector("[data-comment-id=\"" + message.id + "\"]");
9015
+ if (!el)
9016
+ return;
9017
+ el.scrollIntoView({ block: 'center', inline: 'start' });
8771
9018
  };
8772
- BantaCommentsComponent.prototype.indicateError = function (message) {
8773
- var _this = this;
8774
- this.sendError = new Error(message);
8775
- setTimeout(function () {
8776
- _this.expandError = true;
8777
- setTimeout(function () {
8778
- _this.expandError = false;
8779
- }, 5 * 1000);
9019
+ BantaCommentsComponent.prototype.addParticipant = function (message) {
9020
+ if (!message || !message.user || !message.user.id)
9021
+ return;
9022
+ var existing = this.participants.find(function (x) { return x.id === message.user.id; });
9023
+ if (existing)
9024
+ return;
9025
+ this.participants.push(message.user);
9026
+ };
9027
+ // Actions
9028
+ BantaCommentsComponent.prototype.likeMessage = function (source, message) {
9029
+ var _a;
9030
+ return __awaiter(this, void 0, void 0, function () {
9031
+ var e_4;
9032
+ return __generator(this, function (_d) {
9033
+ switch (_d.label) {
9034
+ case 0:
9035
+ this._upvoted.next(message);
9036
+ message.transientState.liking = true;
9037
+ if (!((_a = message.userState) === null || _a === void 0 ? void 0 : _a.liked))
9038
+ message.likes = (message.likes || 0) + 1;
9039
+ _d.label = 1;
9040
+ case 1:
9041
+ _d.trys.push([1, 3, , 4]);
9042
+ return [4 /*yield*/, source.likeMessage(message.id)];
9043
+ case 2:
9044
+ _d.sent();
9045
+ return [3 /*break*/, 4];
9046
+ case 3:
9047
+ e_4 = _d.sent();
9048
+ alert("Could not like this message: " + e_4.message);
9049
+ return [2 /*return*/];
9050
+ case 4: return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 250); })];
9051
+ case 5:
9052
+ _d.sent();
9053
+ message.transientState.liking = false;
9054
+ return [2 /*return*/];
9055
+ }
9056
+ });
8780
9057
  });
8781
9058
  };
8782
- BantaCommentsComponent.prototype.upvoteMessage = function (message) {
9059
+ BantaCommentsComponent.prototype.unlikeMessage = function (source, message) {
9060
+ var _a;
8783
9061
  return __awaiter(this, void 0, void 0, function () {
8784
- return __generator(this, function (_c) {
8785
- switch (_c.label) {
9062
+ var e_5;
9063
+ return __generator(this, function (_d) {
9064
+ switch (_d.label) {
8786
9065
  case 0:
8787
9066
  this._upvoted.next(message);
8788
- return [4 /*yield*/, this.backend.upvoteMessage(message.topicId, message.parentMessageId ? message.parentMessageId : message.id, message.parentMessageId ? message.id : undefined)];
9067
+ message.transientState.liking = true;
9068
+ if ((_a = message.userState) === null || _a === void 0 ? void 0 : _a.liked)
9069
+ message.likes = (message.likes || 0) - 1;
9070
+ _d.label = 1;
8789
9071
  case 1:
8790
- _c.sent();
9072
+ _d.trys.push([1, 3, , 4]);
9073
+ return [4 /*yield*/, source.unlikeMessage(message.id)];
9074
+ case 2:
9075
+ _d.sent();
9076
+ return [3 /*break*/, 4];
9077
+ case 3:
9078
+ e_5 = _d.sent();
9079
+ alert("Failed to unlike message: " + e_5.message);
9080
+ return [3 /*break*/, 4];
9081
+ case 4: return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 250); })];
9082
+ case 5:
9083
+ _d.sent();
9084
+ message.transientState.liking = false;
8791
9085
  return [2 /*return*/];
8792
9086
  }
8793
9087
  });
8794
9088
  });
8795
9089
  };
8796
9090
  BantaCommentsComponent.prototype.reportMessage = function (message) {
8797
- this._reported.next(message);
9091
+ return __awaiter(this, void 0, void 0, function () {
9092
+ return __generator(this, function (_d) {
9093
+ this._reported.next(message);
9094
+ return [2 /*return*/];
9095
+ });
9096
+ });
8798
9097
  };
8799
9098
  BantaCommentsComponent.prototype.unselectMessage = function () {
8800
9099
  return __awaiter(this, void 0, void 0, function () {
8801
9100
  var message;
8802
9101
  var _this = this;
8803
- return __generator(this, function (_c) {
9102
+ return __generator(this, function (_d) {
8804
9103
  message = this.selectedMessage;
8805
9104
  this._selected.next(null);
8806
9105
  this.selectedMessage = null;
@@ -8817,93 +9116,155 @@
8817
9116
  };
8818
9117
  BantaCommentsComponent.prototype.selectMessage = function (message) {
8819
9118
  return __awaiter(this, void 0, void 0, function () {
9119
+ var selectedMessageThread;
8820
9120
  var _this = this;
8821
- return __generator(this, function (_c) {
8822
- this._selected.next(message);
8823
- this.selectedMessage = message;
8824
- setTimeout(function () { return _this.selectedMessageVisible = true; });
8825
- setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
8826
- var _c;
8827
- return __generator(this, function (_d) {
8828
- switch (_d.label) {
8829
- case 0:
8830
- _c = this;
8831
- return [4 /*yield*/, this.backend.getSourceForThread(this.topicID, message.id)];
8832
- case 1:
8833
- _c.selectedMessageThread = _d.sent();
9121
+ return __generator(this, function (_d) {
9122
+ switch (_d.label) {
9123
+ case 0:
9124
+ this._selected.next(message);
9125
+ this.selectedMessage = message;
9126
+ return [4 /*yield*/, this.backend.getSourceForThread(this.topicID, message.id)];
9127
+ case 1:
9128
+ selectedMessageThread = _d.sent();
9129
+ setTimeout(function () { return _this.selectedMessageVisible = true; });
9130
+ setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
9131
+ return __generator(this, function (_d) {
9132
+ this.selectedMessageThread = selectedMessageThread;
8834
9133
  return [2 /*return*/];
8835
- }
8836
- });
8837
- }); }, 250);
9134
+ });
9135
+ }); }, 250);
9136
+ return [2 /*return*/, selectedMessageThread];
9137
+ }
9138
+ });
9139
+ });
9140
+ };
9141
+ BantaCommentsComponent.prototype.showSignIn = function () {
9142
+ return __awaiter(this, void 0, void 0, function () {
9143
+ return __generator(this, function (_d) {
9144
+ this._signInSelected.next();
9145
+ return [2 /*return*/];
9146
+ });
9147
+ });
9148
+ };
9149
+ BantaCommentsComponent.prototype.showEditAvatar = function () {
9150
+ return __awaiter(this, void 0, void 0, function () {
9151
+ return __generator(this, function (_d) {
9152
+ this._editAvatarSelected.next();
8838
9153
  return [2 /*return*/];
8839
9154
  });
8840
9155
  });
8841
9156
  };
8842
9157
  BantaCommentsComponent.prototype.selectMessageUser = function (message) {
8843
- this._userSelected.next(message);
9158
+ return __awaiter(this, void 0, void 0, function () {
9159
+ return __generator(this, function (_d) {
9160
+ this._userSelected.next(message);
9161
+ return [2 /*return*/];
9162
+ });
9163
+ });
8844
9164
  };
8845
9165
  BantaCommentsComponent.prototype.selectUsername = function (user) {
8846
- this._usernameSelected.next(user);
9166
+ return __awaiter(this, void 0, void 0, function () {
9167
+ return __generator(this, function (_d) {
9168
+ this._usernameSelected.next(user);
9169
+ return [2 /*return*/];
9170
+ });
9171
+ });
8847
9172
  };
8848
9173
  BantaCommentsComponent.prototype.selectAvatar = function (user) {
8849
- this._avatarSelected.next(user);
9174
+ return __awaiter(this, void 0, void 0, function () {
9175
+ return __generator(this, function (_d) {
9176
+ this._avatarSelected.next(user);
9177
+ return [2 /*return*/];
9178
+ });
9179
+ });
8850
9180
  };
8851
9181
  BantaCommentsComponent.prototype.shareMessage = function (message) {
8852
- this._shared.next(message);
9182
+ return __awaiter(this, void 0, void 0, function () {
9183
+ return __generator(this, function (_d) {
9184
+ this._shared.next(message);
9185
+ return [2 /*return*/];
9186
+ });
9187
+ });
8853
9188
  };
8854
- BantaCommentsComponent.prototype.sendReply = function () {
9189
+ BantaCommentsComponent.prototype.deleteMessage = function (message) {
8855
9190
  return __awaiter(this, void 0, void 0, function () {
8856
- return __generator(this, function (_c) {
8857
- switch (_c.label) {
8858
- case 0: return [4 /*yield*/, this.selectedMessageThread.send({
8859
- message: this.replyMessage,
8860
- parentMessageId: this.selectedMessage.id,
8861
- upvotes: 0,
8862
- user: this.user,
8863
- submessages: [],
8864
- topicId: this.topicID,
8865
- sentAt: Date.now(),
8866
- updatedAt: Date.now()
8867
- })];
9191
+ return __generator(this, function (_d) {
9192
+ if (!confirm("Are you sure you want to delete this comment? You cannot undo this action."))
9193
+ return [2 /*return*/];
9194
+ this.source.deleteMessage(message.id);
9195
+ return [2 /*return*/];
9196
+ });
9197
+ });
9198
+ };
9199
+ BantaCommentsComponent.prototype.editMessage = function (source, message, newText) {
9200
+ return __awaiter(this, void 0, void 0, function () {
9201
+ var e_6;
9202
+ return __generator(this, function (_d) {
9203
+ switch (_d.label) {
9204
+ case 0:
9205
+ _d.trys.push([0, 2, , 3]);
9206
+ return [4 /*yield*/, source.editMessage(message.id, newText)];
8868
9207
  case 1:
8869
- _c.sent();
8870
- this.replyMessage = '';
9208
+ _d.sent();
9209
+ return [3 /*break*/, 3];
9210
+ case 2:
9211
+ e_6 = _d.sent();
9212
+ alert(e_6.message);
9213
+ return [2 /*return*/];
9214
+ case 3:
9215
+ message.message = newText;
9216
+ message.transientState.editing = false;
8871
9217
  return [2 /*return*/];
8872
9218
  }
8873
9219
  });
8874
9220
  });
8875
9221
  };
8876
- BantaCommentsComponent.prototype.scrollToMessage = function (message) {
8877
- var el = this.elementRef.nativeElement.querySelector("[data-comment-id=\"" + message.id + "\"]");
8878
- if (!el)
8879
- return;
8880
- el.scrollIntoView({ block: 'center', inline: 'start' });
9222
+ BantaCommentsComponent.prototype.startEditing = function (message) {
9223
+ return __awaiter(this, void 0, void 0, function () {
9224
+ return __generator(this, function (_d) {
9225
+ this.selectedMessage.transientState.editing = false;
9226
+ message.transientState.editing = true;
9227
+ return [2 /*return*/];
9228
+ });
9229
+ });
9230
+ };
9231
+ BantaCommentsComponent.prototype.saveEdit = function (message, text) {
9232
+ return __awaiter(this, void 0, void 0, function () {
9233
+ var e_7;
9234
+ return __generator(this, function (_d) {
9235
+ switch (_d.label) {
9236
+ case 0:
9237
+ _d.trys.push([0, 2, , 3]);
9238
+ return [4 /*yield*/, this.source.editMessage(message.id, text)];
9239
+ case 1:
9240
+ _d.sent();
9241
+ message.transientState.editing = false;
9242
+ return [3 /*break*/, 3];
9243
+ case 2:
9244
+ e_7 = _d.sent();
9245
+ alert("Could not edit message: " + e_7.message);
9246
+ return [3 /*break*/, 3];
9247
+ case 3: return [2 /*return*/];
9248
+ }
9249
+ });
9250
+ });
8881
9251
  };
8882
9252
  return BantaCommentsComponent;
8883
9253
  }());
8884
9254
  BantaCommentsComponent.decorators = [
8885
9255
  { type: core.Component, args: [{
8886
9256
  selector: 'banta-comments',
8887
- template: "\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 ></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 ></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]=\"canComment\"\r\n [signInLabel]=\"signInLabel\"\r\n [permissionDeniedLabel]=\"permissionDeniedLabel\"\r\n (permissionDeniedError)=\"showPermissionDenied()\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\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]=\"canComment\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n [label]=\"postCommentLabel\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n (signInSelected)=\"showSignIn()\"\r\n [permissionDeniedLabel]=\"permissionDeniedLabel\"\r\n (permissionDeniedError)=\"showPermissionDenied()\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\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 (selected)=\"selectMessage($event)\"\r\n (upvoted)=\"upvoteMessage($event)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n ></banta-comment-view>\r\n</div>\r\n",
8888
- 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-duration:.4s;-webkit-animation-fill-mode:both;-webkit-animation-name:select-comment;animation-duration:.4s;animation-fill-mode:both;animation-name:select-comment}.focused .replies{margin-left:4em;margin-top:1em}banta-comment-view{opacity:1;transition:opacity .4s ease-in-out}banta-comment-view.faded{opacity:.25}.loading{display:block;margin:0 auto;min-height:16em;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.main.hidden{display:none}@media (max-width:500px){.focused .replies{margin-left:0}}"]
9257
+ 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(selectedMessage)\"\r\n (unliked)=\"unlikeMessage(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]=\"permissionDeniedLabel\"\r\n (permissionDeniedError)=\"showPermissionDenied()\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\r\n [submit]=\"sendReply\"\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]=\"permissionDeniedLabel\"\r\n (permissionDeniedError)=\"showPermissionDenied()\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [submit]=\"sendMessage\"\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>",
9258
+ 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}"]
8889
9259
  },] }
8890
9260
  ];
8891
9261
  BantaCommentsComponent.ctorParameters = function () { return [
8892
- { type: BantaService },
8893
- { type: ChatBackendService },
9262
+ { type: ChatBackendBase },
8894
9263
  { type: core.ElementRef },
8895
9264
  { type: router.ActivatedRoute }
8896
9265
  ]; };
8897
9266
  BantaCommentsComponent.propDecorators = {
8898
- hashtags: [{ type: core.Input }],
8899
- participants: [{ type: core.Input }],
8900
- source: [{ type: core.Input }],
8901
- fixedHeight: [{ type: core.Input }],
8902
- maxMessages: [{ type: core.Input }],
8903
- maxVisibleMessages: [{ type: core.Input }],
8904
- genericAvatarUrl: [{ type: core.Input }],
8905
- shouldInterceptMessageSend: [{ type: core.Input }],
8906
- topicID: [{ type: core.Input }],
9267
+ loadingMessages: [{ type: core.Input }],
8907
9268
  signInLabel: [{ type: core.Input }],
8908
9269
  sendLabel: [{ type: core.Input }],
8909
9270
  replyLabel: [{ type: core.Input }],
@@ -8911,6 +9272,15 @@
8911
9272
  permissionDeniedLabel: [{ type: core.Input }],
8912
9273
  postCommentLabel: [{ type: core.Input }],
8913
9274
  postReplyLabel: [{ type: core.Input }],
9275
+ fixedHeight: [{ type: core.Input }],
9276
+ maxMessages: [{ type: core.Input }],
9277
+ maxVisibleMessages: [{ type: core.Input }],
9278
+ genericAvatarUrl: [{ type: core.Input }],
9279
+ shouldInterceptMessageSend: [{ type: core.Input }],
9280
+ participants: [{ type: core.Input }],
9281
+ source: [{ type: core.Input }],
9282
+ hashtags: [{ type: core.Input }],
9283
+ topicID: [{ type: core.Input }],
8914
9284
  signInSelected: [{ type: core.Output }],
8915
9285
  editAvatarSelected: [{ type: core.Output }],
8916
9286
  permissionDeniedError: [{ type: core.Output }],
@@ -8992,7 +9362,7 @@
8992
9362
  },] }
8993
9363
  ];
8994
9364
  LiveCommentComponent.ctorParameters = function () { return [
8995
- { type: ChatBackendService }
9365
+ { type: ChatBackendBase }
8996
9366
  ]; };
8997
9367
  LiveCommentComponent.propDecorators = {
8998
9368
  upvoted: [{ type: core.Output }],
@@ -9015,6 +9385,7 @@
9015
9385
  this.permissionDeniedLabel = 'Unavailable';
9016
9386
  this.signInLabel = 'Sign In';
9017
9387
  this.placeholder = '';
9388
+ this.textChanged = new rxjs.Subject();
9018
9389
  this.participants = [];
9019
9390
  this._permissionDeniedError = new rxjs.Subject();
9020
9391
  this.autocompleteVisible = false;
@@ -9057,17 +9428,19 @@
9057
9428
  CommentFieldComponent.prototype.indicateError = function (message) {
9058
9429
  var _this = this;
9059
9430
  this.sendError = new Error(message);
9060
- setTimeout(function () {
9431
+ this.expandError = false;
9432
+ clearTimeout(this.errorTimeout);
9433
+ this.errorTimeout = setTimeout(function () {
9061
9434
  _this.expandError = true;
9062
- setTimeout(function () {
9435
+ _this.errorTimeout = setTimeout(function () {
9063
9436
  _this.expandError = false;
9064
9437
  }, 5 * 1000);
9065
- });
9438
+ }, 100);
9066
9439
  };
9067
9440
  CommentFieldComponent.prototype.autocomplete = function (replacement) {
9068
9441
  return __awaiter(this, void 0, void 0, function () {
9069
9442
  var el;
9070
- return __generator(this, function (_b) {
9443
+ return __generator(this, function (_a) {
9071
9444
  el = this.textareaEl.nativeElement;
9072
9445
  this.text = this.text.slice(0, el.selectionStart - this.completionPrefix.length) + replacement + this.text.slice(el.selectionStart);
9073
9446
  return [2 /*return*/];
@@ -9077,7 +9450,7 @@
9077
9450
  CommentFieldComponent.prototype.insert = function (str) {
9078
9451
  return __awaiter(this, void 0, void 0, function () {
9079
9452
  var el;
9080
- return __generator(this, function (_b) {
9453
+ return __generator(this, function (_a) {
9081
9454
  el = this.textareaEl.nativeElement;
9082
9455
  this.text = this.text.slice(0, el.selectionStart) + str + this.text.slice(el.selectionStart);
9083
9456
  return [2 /*return*/];
@@ -9087,8 +9460,8 @@
9087
9460
  CommentFieldComponent.prototype.onKeyDown = function (event) {
9088
9461
  return __awaiter(this, void 0, void 0, function () {
9089
9462
  var _this = this;
9090
- return __generator(this, function (_b) {
9091
- switch (_b.label) {
9463
+ return __generator(this, function (_a) {
9464
+ switch (_a.label) {
9092
9465
  case 0:
9093
9466
  if (this.autocompleteVisible) {
9094
9467
  if (event.key === 'Escape') {
@@ -9123,7 +9496,7 @@
9123
9496
  if (!(event.key === 'Enter' && event.ctrlKey)) return [3 /*break*/, 2];
9124
9497
  return [4 /*yield*/, this.sendMessage()];
9125
9498
  case 1:
9126
- _b.sent();
9499
+ _a.sent();
9127
9500
  return [2 /*return*/];
9128
9501
  case 2:
9129
9502
  if (this.completionFunc) {
@@ -9206,19 +9579,18 @@
9206
9579
  this.editAvatarSelected.next();
9207
9580
  };
9208
9581
  CommentFieldComponent.prototype.sendMessage = function () {
9209
- var _a;
9210
9582
  return __awaiter(this, void 0, void 0, function () {
9211
- var text, message, intercept, e_1;
9212
- return __generator(this, function (_b) {
9213
- switch (_b.label) {
9583
+ var text, message, e_1;
9584
+ return __generator(this, function (_a) {
9585
+ switch (_a.label) {
9214
9586
  case 0:
9215
9587
  if (!this.source)
9216
9588
  return [2 /*return*/];
9217
9589
  this.sending = true;
9218
9590
  this.sendError = null;
9219
- _b.label = 1;
9591
+ _a.label = 1;
9220
9592
  case 1:
9221
- _b.trys.push([1, , 8, 9]);
9593
+ _a.trys.push([1, , 7, 8]);
9222
9594
  text = (this.text || '').trim();
9223
9595
  if (text === '')
9224
9596
  return [2 /*return*/];
@@ -9226,34 +9598,29 @@
9226
9598
  user: this.user,
9227
9599
  sentAt: Date.now(),
9228
9600
  url: location.href,
9229
- upvotes: 0,
9601
+ likes: 0,
9230
9602
  message: text
9231
9603
  };
9232
- _b.label = 2;
9604
+ _a.label = 2;
9233
9605
  case 2:
9234
- _b.trys.push([2, 6, , 7]);
9235
- return [4 /*yield*/, ((_a = this.shouldInterceptMessageSend) === null || _a === void 0 ? void 0 : _a.call(this, message, this.source))];
9606
+ _a.trys.push([2, 4, , 6]);
9607
+ return [4 /*yield*/, this.submit(message)];
9236
9608
  case 3:
9237
- intercept = _b.sent();
9238
- if (!!intercept) return [3 /*break*/, 5];
9239
- return [4 /*yield*/, this.source.send(message)];
9609
+ _a.sent();
9610
+ this.text = '';
9611
+ return [3 /*break*/, 6];
9240
9612
  case 4:
9241
- _b.sent();
9242
- _b.label = 5;
9613
+ e_1 = _a.sent();
9614
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(function () { return resolve(); }, 1000); })];
9243
9615
  case 5:
9244
- this.text = '';
9245
- return [3 /*break*/, 7];
9246
- case 6:
9247
- e_1 = _b.sent();
9248
- this.indicateError("Could not send: " + e_1.message);
9249
- console.error("Failed to send message: ", message);
9250
- console.error(e_1);
9251
- return [3 /*break*/, 7];
9252
- case 7: return [3 /*break*/, 9];
9253
- case 8:
9616
+ _a.sent();
9617
+ this.indicateError(e_1.message);
9618
+ return [3 /*break*/, 6];
9619
+ case 6: return [3 /*break*/, 8];
9620
+ case 7:
9254
9621
  this.sending = false;
9255
9622
  return [7 /*endfinally*/];
9256
- case 9: return [2 /*return*/];
9623
+ case 8: return [2 /*return*/];
9257
9624
  }
9258
9625
  });
9259
9626
  });
@@ -9264,7 +9631,7 @@
9264
9631
  { type: core.Component, args: [{
9265
9632
  selector: 'banta-comment-field',
9266
9633
  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 <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 <ng-content></ng-content>\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\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 </div>\r\n\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\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <emoji-selector-button\r\n class=\"top-right\"\r\n (selected)=\"insertEmoji($event)\"\r\n ></emoji-selector-button>\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 *ngIf=\"canComment\"\r\n mat-raised-button\r\n class=\"send\"\r\n color=\"primary\"\r\n [disabled]=\"!text || sending\"\r\n >\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 <span class=\"label\">\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 </span>\r\n\r\n </button>\r\n <button\r\n *ngIf=\"!canComment\"\r\n type=\"button\"\r\n (click)=\"showPermissionDenied()\"\r\n mat-raised-button\r\n color=\"primary\"\r\n >{{permissionDeniedLabel}}</button>\r\n </ng-container>\r\n </div>\r\n</form>\r\n",
9267
- styles: ["@-webkit-keyframes comment-field-appear{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translate(0)}}@keyframes comment-field-appear{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translate(0)}}:host{-webkit-animation-delay:.4s;-webkit-animation-duration:.8s;-webkit-animation-fill-mode:both;-webkit-animation-name:comment-field-appear;animation-delay:.4s;animation-duration:.8s;animation-fill-mode:both;animation-name:comment-field-appear;display:block;margin:0 2em 0 0}.avatar-container{display:flex;justify-content:flex-end;width:calc(48px + 1.75em)}.avatar-container .avatar{background:pink;background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:100%;height:48px;margin-right:.75em;margin-top:.75em;width:48px}form{align-items:center;display:flex;padding:.5em}form .text-container{display:flex;flex-grow:1;position:relative}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-form-field{margin-bottom:1em}form .text-container emoji-selector-button{bottom:0;position:absolute;right:0}form .text-container .error-message,form .text-container mat-spinner.loading{bottom:.5em;left:.5em;position:absolute}form .text-container .error-message{color:#683333;max-width:1.5em;overflow-x:hidden;transition:max-width 2s ease-in-out;white-space:nowrap}form .text-container .error-message.expanded,form .text-container .error-message:hover{max-width:100%}form .text-container .error-message mat-icon{vertical-align:middle}form input[type=text]{background:#000;border:1px solid #333;color:#fff;height:1em;width:100%}form .actions{margin-left:1em}form button{display:block;margin:0 0 0 auto}form.new-message{align-items:flex-start;display:flex}form.new-message .field-container{display:flex;flex-direction:column;flex-grow:1}form.new-message mat-form-field{width:100%}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{pointer-events:none;position:relative;top:-2em;width:calc(100% - 2em)}.autocomplete{background:#333;display:flex;flex-direction:column;padding:.5em;pointer-events:none;position:absolute;visibility:hidden;z-index:100}.autocomplete.visible{pointer-events:auto;visibility:visible}.autocomplete a{text-align:left;width:100%}.autocomplete a.active{background:#555}@media (max-width:500px){:host{margin:0}.avatar-container{width:auto}.avatar-container .avatar{height:32px;margin-top:1.5em;width:32px}button.send{margin-top:1.5em;min-width:auto}button.send .label{display:none}}"]
9634
+ 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}.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}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-form-field{margin-bottom:1em}form .text-container emoji-selector-button{bottom:0;right:0;position:absolute}form .text-container .error-message,form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .error-message{color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:max-width 2s ease-in-out}form .text-container .error-message.expanded,form .text-container .error-message:hover{max-width:100%}form .text-container .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}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column}form.new-message mat-form-field{width:100%}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}.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}}"]
9268
9635
  },] }
9269
9636
  ];
9270
9637
  CommentFieldComponent.propDecorators = {
@@ -9273,19 +9640,23 @@
9273
9640
  canComment: [{ type: core.Input }],
9274
9641
  signInSelected: [{ type: core.Output }],
9275
9642
  editAvatarSelected: [{ type: core.Output }],
9643
+ sendError: [{ type: core.Input }],
9644
+ expandError: [{ type: core.Input }],
9276
9645
  sendLabel: [{ type: core.Input }],
9277
9646
  sendingLabel: [{ type: core.Input }],
9278
9647
  label: [{ type: core.Input }],
9279
9648
  permissionDeniedLabel: [{ type: core.Input }],
9280
9649
  signInLabel: [{ type: core.Input }],
9281
9650
  placeholder: [{ type: core.Input }],
9651
+ textChanged: [{ type: core.Output }],
9282
9652
  shouldInterceptMessageSend: [{ type: core.Input }],
9283
9653
  autocompleteEl: [{ type: core.ViewChild, args: ['autocomplete',] }],
9284
9654
  autocompleteContainerEl: [{ type: core.ViewChild, args: ['autocompleteContainer',] }],
9285
9655
  textareaEl: [{ type: core.ViewChild, args: ['textarea',] }],
9286
9656
  hashtags: [{ type: core.Input }],
9287
9657
  participants: [{ type: core.Input }],
9288
- permissionDeniedError: [{ type: core.Output }]
9658
+ permissionDeniedError: [{ type: core.Output }],
9659
+ submit: [{ type: core.Input }]
9289
9660
  };
9290
9661
 
9291
9662
  var CommentSortComponent = /** @class */ (function () {
@@ -9364,14 +9735,373 @@
9364
9735
  },] }
9365
9736
  ];
9366
9737
 
9738
+ var ChatSource = /** @class */ (function (_super_1) {
9739
+ __extends(ChatSource, _super_1);
9740
+ function ChatSource(backend, identifier, parentIdentifier, sortOrder) {
9741
+ var _this = _super_1.call(this) || this;
9742
+ _this.backend = backend;
9743
+ _this.identifier = identifier;
9744
+ _this.parentIdentifier = parentIdentifier;
9745
+ _this.sortOrder = sortOrder;
9746
+ _this.subscription = new rxjs.Subscription();
9747
+ _this.state = 'connecting';
9748
+ _this.messageMap = new Map();
9749
+ _this._messageReceived = new rxjs.Subject();
9750
+ _this._messageSent = new rxjs.Subject();
9751
+ _this.messages = [];
9752
+ _this.ready = new Promise(function (resolve) { return _this.markReady = resolve; });
9753
+ return _this;
9754
+ }
9755
+ ChatSource.prototype.bind = function (socket) {
9756
+ var _super = Object.create(null, {
9757
+ bind: { get: function () { return _super_1.prototype.bind; } }
9758
+ });
9759
+ return __awaiter(this, void 0, void 0, function () {
9760
+ var _this = this;
9761
+ return __generator(this, function (_b) {
9762
+ switch (_b.label) {
9763
+ case 0:
9764
+ _super.bind.call(this, socket);
9765
+ this.state = 'connected';
9766
+ this.markReady();
9767
+ return [4 /*yield*/, this.subscribeToTopic()];
9768
+ case 1:
9769
+ _b.sent();
9770
+ this.subscription.add(this.backend.userChanged.subscribe(function () { return _this.authenticate(); }));
9771
+ socket.addEventListener('open', function () { return __awaiter(_this, void 0, void 0, function () {
9772
+ return __generator(this, function (_b) {
9773
+ this.state = 'connected';
9774
+ return [2 /*return*/];
9775
+ });
9776
+ }); });
9777
+ socket.addEventListener('lost', function () { return __awaiter(_this, void 0, void 0, function () {
9778
+ return __generator(this, function (_b) {
9779
+ this.state = 'lost';
9780
+ return [2 /*return*/];
9781
+ });
9782
+ }); });
9783
+ socket.addEventListener('restore', function () { return __awaiter(_this, void 0, void 0, function () {
9784
+ return __generator(this, function (_b) {
9785
+ switch (_b.label) {
9786
+ case 0:
9787
+ this.state = 'restored';
9788
+ return [4 /*yield*/, this.authenticate()];
9789
+ case 1:
9790
+ _b.sent();
9791
+ return [4 /*yield*/, this.subscribeToTopic()];
9792
+ case 2:
9793
+ _b.sent();
9794
+ return [2 /*return*/];
9795
+ }
9796
+ });
9797
+ }); });
9798
+ return [2 /*return*/, this];
9799
+ }
9800
+ });
9801
+ });
9802
+ };
9803
+ ChatSource.prototype.getExistingMessages = function () {
9804
+ return __awaiter(this, void 0, void 0, function () {
9805
+ var messages;
9806
+ var _this = this;
9807
+ return __generator(this, function (_b) {
9808
+ switch (_b.label) {
9809
+ case 0: return [4 /*yield*/, this.peer.getExistingMessages()];
9810
+ case 1:
9811
+ messages = _b.sent();
9812
+ messages = messages.map(function (message) {
9813
+ var existingMessage = _this.messageMap.get(message.id);
9814
+ if (existingMessage)
9815
+ message = Object.assign(existingMessage, message);
9816
+ else
9817
+ _this.messageMap.set(message.id, message);
9818
+ return message;
9819
+ });
9820
+ return [2 /*return*/, messages];
9821
+ }
9822
+ });
9823
+ });
9824
+ };
9825
+ ChatSource.prototype.editMessage = function (messageId, text) {
9826
+ return __awaiter(this, void 0, void 0, function () {
9827
+ return __generator(this, function (_b) {
9828
+ this.peer.editMessage(messageId, text);
9829
+ return [2 /*return*/];
9830
+ });
9831
+ });
9832
+ };
9833
+ ChatSource.prototype.subscribeToTopic = function () {
9834
+ return __awaiter(this, void 0, void 0, function () {
9835
+ return __generator(this, function (_b) {
9836
+ switch (_b.label) {
9837
+ case 0: return [4 /*yield*/, this.peer.subscribe(this.identifier, this.parentIdentifier, this.sortOrder)];
9838
+ case 1:
9839
+ _b.sent();
9840
+ return [2 /*return*/];
9841
+ }
9842
+ });
9843
+ });
9844
+ };
9845
+ ChatSource.prototype.authenticate = function () {
9846
+ var _a;
9847
+ return __awaiter(this, void 0, void 0, function () {
9848
+ return __generator(this, function (_b) {
9849
+ switch (_b.label) {
9850
+ case 0: return [4 /*yield*/, this.peer.authenticate((_a = this.backend.user) === null || _a === void 0 ? void 0 : _a.token)];
9851
+ case 1:
9852
+ _b.sent();
9853
+ return [2 /*return*/];
9854
+ }
9855
+ });
9856
+ });
9857
+ };
9858
+ ChatSource.prototype.close = function () {
9859
+ _super_1.prototype.close.call(this);
9860
+ this.subscription.unsubscribe();
9861
+ };
9862
+ ChatSource.prototype.onPermissions = function (permissions) {
9863
+ window.bantaPermissionsDebug = permissions;
9864
+ this.permissions = permissions;
9865
+ };
9866
+ ChatSource.prototype.onChatMessage = function (message) {
9867
+ if (this.messageMap.has(message.id)) {
9868
+ Object.assign(this.messageMap.get(message.id), message);
9869
+ }
9870
+ else if (!message.hidden) {
9871
+ // Only process non-hidden messages through here.
9872
+ // Hidden messages may be sent to us when they become hidden (ie moderation is occurring).
9873
+ // But if we never had the message to begin with, we should discard it.
9874
+ this.messageMap.set(message.id, message);
9875
+ this._messageReceived.next(message);
9876
+ }
9877
+ };
9878
+ Object.defineProperty(ChatSource.prototype, "messageReceived", {
9879
+ get: function () { return this._messageReceived.asObservable(); },
9880
+ enumerable: false,
9881
+ configurable: true
9882
+ });
9883
+ Object.defineProperty(ChatSource.prototype, "messageSent", {
9884
+ get: function () { return this._messageSent.asObservable(); },
9885
+ enumerable: false,
9886
+ configurable: true
9887
+ });
9888
+ ChatSource.prototype.send = function (message) {
9889
+ return __awaiter(this, void 0, void 0, function () {
9890
+ return __generator(this, function (_b) {
9891
+ switch (_b.label) {
9892
+ case 0: return [4 /*yield*/, this.peer.sendMessage(message)];
9893
+ case 1: return [2 /*return*/, _b.sent()];
9894
+ }
9895
+ });
9896
+ });
9897
+ };
9898
+ ChatSource.prototype.loadAfter = function (message, count) {
9899
+ return __awaiter(this, void 0, void 0, function () {
9900
+ return __generator(this, function (_b) {
9901
+ if (!message)
9902
+ return [2 /*return*/];
9903
+ if (!message.pagingCursor)
9904
+ return [2 /*return*/, []];
9905
+ return [2 /*return*/, this.peer.loadAfter(Number(message.pagingCursor), count)];
9906
+ });
9907
+ });
9908
+ };
9909
+ ChatSource.prototype.get = function (id) {
9910
+ return __awaiter(this, void 0, void 0, function () {
9911
+ var message;
9912
+ return __generator(this, function (_b) {
9913
+ switch (_b.label) {
9914
+ case 0:
9915
+ if (this.messageMap.has(id))
9916
+ return [2 /*return*/, this.messageMap.get(id)];
9917
+ return [4 /*yield*/, this.peer.getMessage(id)];
9918
+ case 1:
9919
+ message = _b.sent();
9920
+ this.messageMap.set(id, message);
9921
+ return [2 /*return*/, message];
9922
+ }
9923
+ });
9924
+ });
9925
+ };
9926
+ ChatSource.prototype.getCount = function () {
9927
+ return __awaiter(this, void 0, void 0, function () {
9928
+ return __generator(this, function (_b) {
9929
+ switch (_b.label) {
9930
+ case 0: return [4 /*yield*/, this.peer.getCount()];
9931
+ case 1: return [2 /*return*/, _b.sent()];
9932
+ }
9933
+ });
9934
+ });
9935
+ };
9936
+ ChatSource.prototype.likeMessage = function (messageId) {
9937
+ return __awaiter(this, void 0, void 0, function () {
9938
+ return __generator(this, function (_b) {
9939
+ switch (_b.label) {
9940
+ case 0: return [4 /*yield*/, this.peer.likeMessage(messageId)];
9941
+ case 1: return [2 /*return*/, _b.sent()];
9942
+ }
9943
+ });
9944
+ });
9945
+ };
9946
+ ChatSource.prototype.unlikeMessage = function (messageId) {
9947
+ return __awaiter(this, void 0, void 0, function () {
9948
+ return __generator(this, function (_b) {
9949
+ switch (_b.label) {
9950
+ case 0: return [4 /*yield*/, this.peer.unlikeMessage(messageId)];
9951
+ case 1: return [2 /*return*/, _b.sent()];
9952
+ }
9953
+ });
9954
+ });
9955
+ };
9956
+ ChatSource.prototype.deleteMessage = function (messageId) {
9957
+ return __awaiter(this, void 0, void 0, function () {
9958
+ return __generator(this, function (_b) {
9959
+ switch (_b.label) {
9960
+ case 0: return [4 /*yield*/, this.peer.deleteMessage(messageId)];
9961
+ case 1: return [2 /*return*/, _b.sent()];
9962
+ }
9963
+ });
9964
+ });
9965
+ };
9966
+ return ChatSource;
9967
+ }(common$1.SocketRPC));
9968
+ __decorate([
9969
+ common$1.RpcEvent(),
9970
+ __metadata("design:type", Function),
9971
+ __metadata("design:paramtypes", [Object]),
9972
+ __metadata("design:returntype", void 0)
9973
+ ], ChatSource.prototype, "onPermissions", null);
9974
+ __decorate([
9975
+ common$1.RpcEvent(),
9976
+ __metadata("design:type", Function),
9977
+ __metadata("design:paramtypes", [Object]),
9978
+ __metadata("design:returntype", void 0)
9979
+ ], ChatSource.prototype, "onChatMessage", null);
9980
+
9981
+ var BANTA_SDK_OPTIONS = 'BANTA_SDK_OPTIONS';
9982
+
9983
+ var ChatBackend = /** @class */ (function (_super) {
9984
+ __extends(ChatBackend, _super);
9985
+ function ChatBackend(options) {
9986
+ var _this = _super.call(this) || this;
9987
+ _this.options = options;
9988
+ return _this;
9989
+ }
9990
+ Object.defineProperty(ChatBackend.prototype, "serviceUrl", {
9991
+ get: function () {
9992
+ var _a, _b;
9993
+ return "" + ((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.serviceUrl) !== null && _b !== void 0 ? _b : 'http://localhost:3422');
9994
+ },
9995
+ enumerable: false,
9996
+ configurable: true
9997
+ });
9998
+ ChatBackend.prototype.connectToService = function () {
9999
+ return __awaiter(this, void 0, void 0, function () {
10000
+ var socket;
10001
+ return __generator(this, function (_c) {
10002
+ switch (_c.label) {
10003
+ case 0:
10004
+ socket = new common$1.DurableSocket(this.serviceUrl.replace(/^http/, 'ws') + "/socket");
10005
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
10006
+ socket.onopen = function () {
10007
+ resolve();
10008
+ };
10009
+ socket.onclose = function (e) {
10010
+ if (e.code === 503) {
10011
+ console.error("Failed to connect to chat service!");
10012
+ reject(e);
10013
+ }
10014
+ };
10015
+ })];
10016
+ case 1:
10017
+ _c.sent();
10018
+ socket.onerror = undefined;
10019
+ return [2 /*return*/, socket];
10020
+ }
10021
+ });
10022
+ });
10023
+ };
10024
+ ChatBackend.prototype.getSourceForTopic = function (topicId, options) {
10025
+ return __awaiter(this, void 0, void 0, function () {
10026
+ var _c, _d;
10027
+ return __generator(this, function (_e) {
10028
+ switch (_e.label) {
10029
+ case 0:
10030
+ _d = (_c = new ChatSource(this, topicId, undefined, (options === null || options === void 0 ? void 0 : options.sortOrder) || common$1.CommentsOrder.NEWEST))
10031
+ .bind;
10032
+ return [4 /*yield*/, this.connectToService()];
10033
+ case 1: return [4 /*yield*/, _d.apply(_c, [_e.sent()])];
10034
+ case 2: return [2 /*return*/, _e.sent()];
10035
+ }
10036
+ });
10037
+ });
10038
+ };
10039
+ ChatBackend.prototype.getSourceForThread = function (topicId, messageId, options) {
10040
+ return __awaiter(this, void 0, void 0, function () {
10041
+ var _c, _d;
10042
+ return __generator(this, function (_e) {
10043
+ switch (_e.label) {
10044
+ case 0:
10045
+ _d = (_c = new ChatSource(this, topicId, messageId, (options === null || options === void 0 ? void 0 : options.sortOrder) || common$1.CommentsOrder.NEWEST))
10046
+ .bind;
10047
+ return [4 /*yield*/, this.connectToService()];
10048
+ case 1: return [4 /*yield*/, _d.apply(_c, [_e.sent()])];
10049
+ case 2: return [2 /*return*/, _e.sent()];
10050
+ }
10051
+ });
10052
+ });
10053
+ };
10054
+ ChatBackend.prototype.getSourceCountForTopic = function (topicId) {
10055
+ return __awaiter(this, void 0, void 0, function () {
10056
+ var response, topic;
10057
+ return __generator(this, function (_c) {
10058
+ switch (_c.label) {
10059
+ case 0: return [4 /*yield*/, fetch(this.serviceUrl + "/topics/" + topicId)];
10060
+ case 1:
10061
+ response = _c.sent();
10062
+ if (response.status >= 400)
10063
+ return [2 /*return*/, 0];
10064
+ return [4 /*yield*/, response.json()];
10065
+ case 2:
10066
+ topic = _c.sent();
10067
+ return [2 /*return*/, topic.messageCount || 0];
10068
+ }
10069
+ });
10070
+ });
10071
+ };
10072
+ ChatBackend.prototype.refreshMessage = function (message) {
10073
+ throw new Error("Method not implemented.");
10074
+ };
10075
+ ChatBackend.prototype.getMessage = function (topicId, messageId) {
10076
+ throw new Error("Method not implemented.");
10077
+ };
10078
+ ChatBackend.prototype.getSubMessage = function (topicId, parentMessageId, messageId) {
10079
+ throw new Error("Method not implemented.");
10080
+ };
10081
+ ChatBackend.prototype.watchMessage = function (message, handler) {
10082
+ throw new Error("Method not implemented.");
10083
+ };
10084
+ return ChatBackend;
10085
+ }(ChatBackendBase));
10086
+ ChatBackend.decorators = [
10087
+ { type: core.Injectable }
10088
+ ];
10089
+ ChatBackend.ctorParameters = function () { return [
10090
+ { type: undefined, decorators: [{ type: core.Inject, args: [BANTA_SDK_OPTIONS,] }] }
10091
+ ]; };
10092
+
9367
10093
  var BantaSdkModule = /** @class */ (function () {
9368
10094
  function BantaSdkModule() {
9369
10095
  }
9370
- BantaSdkModule.forRoot = function () {
10096
+ BantaSdkModule.configure = function (options) {
9371
10097
  return {
9372
10098
  ngModule: BantaSdkModule,
9373
10099
  providers: [
9374
- BantaService
10100
+ {
10101
+ provide: BANTA_SDK_OPTIONS,
10102
+ useValue: options || {}
10103
+ },
10104
+ { provide: ChatBackendBase, useClass: ChatBackend }
9375
10105
  ]
9376
10106
  };
9377
10107
  };
@@ -9418,16 +10148,18 @@
9418
10148
  * Generated bundle index. Do not edit.
9419
10149
  */
9420
10150
 
10151
+ exports.BANTA_SDK_OPTIONS = BANTA_SDK_OPTIONS;
9421
10152
  exports.BantaChatComponent = BantaChatComponent;
9422
10153
  exports.BantaCommentsComponent = BantaCommentsComponent;
9423
10154
  exports.BantaCommonModule = BantaCommonModule;
9424
10155
  exports.BantaComponent = BantaComponent;
9425
10156
  exports.BantaLogoComponent = BantaLogoComponent;
9426
10157
  exports.BantaSdkModule = BantaSdkModule;
9427
- exports.BantaService = BantaService;
9428
- exports.ChatBackendService = ChatBackendService;
10158
+ exports.ChatBackend = ChatBackend;
10159
+ exports.ChatBackendBase = ChatBackendBase;
9429
10160
  exports.ChatMessageComponent = ChatMessageComponent;
9430
10161
  exports.ChatModule = ChatModule;
10162
+ exports.ChatSource = ChatSource;
9431
10163
  exports.ChatViewComponent = ChatViewComponent;
9432
10164
  exports.CommentComponent = CommentComponent;
9433
10165
  exports.CommentFieldComponent = CommentFieldComponent;