@banta/sdk 4.6.25 → 4.6.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bundles/banta-sdk.umd.js +79 -61
- package/bundles/banta-sdk.umd.js.map +1 -1
- package/esm2015/lib/banta/banta.component.js +3 -4
- package/esm2015/lib/chat/banta-chat/banta-chat.component.js +4 -5
- package/esm2015/lib/chat/chat-message/chat-message.component.js +1 -1
- package/esm2015/lib/chat/chat-view/chat-view.component.js +1 -1
- package/esm2015/lib/chat/live-chat-message.component.js +2 -2
- package/esm2015/lib/chat-backend.js +1 -1
- package/esm2015/lib/chat-source.js +4 -10
- package/esm2015/lib/comments/attachment-button/attachment-button.component.js +3 -3
- package/esm2015/lib/comments/attachment-scraper.directive.js +1 -1
- package/esm2015/lib/comments/banta-comments/banta-comments.component.js +4 -4
- package/esm2015/lib/comments/comment/comment.component.js +2 -2
- package/esm2015/lib/comments/comment-field/comment-field.component.js +4 -4
- package/esm2015/lib/comments/comment-sort/comment-sort.component.js +1 -1
- package/esm2015/lib/comments/comment-view/comment-view.component.js +3 -3
- package/esm2015/lib/comments/live-comment.component.js +2 -2
- package/esm2015/lib/common/attachment/attachment.component.js +2 -2
- package/esm2015/lib/common/attachments/attachments.component.js +2 -3
- package/esm2015/lib/common/lightbox/lightbox.component.js +3 -3
- package/esm2015/lib/common/markdown-to-html.pipe.js +21 -20
- package/esm2015/lib/emoji/emoji-selector-button.component.js +2 -3
- package/esm2015/lib/emoji/emoji-selector-panel/emoji-selector-panel.component.js +1 -1
- package/esm2015/lib/giphy-attachments.js +1 -1
- package/esm2015/lib/live-message.component.js +2 -2
- package/esm2015/lib/url-attachments.js +1 -1
- package/esm2015/public-api.js +1 -1
- package/fesm2015/banta-sdk.js +399 -404
- package/fesm2015/banta-sdk.js.map +1 -1
- package/lib/chat-source.d.ts +3 -3
- package/package.json +1 -1
- package/bundles/banta-sdk.umd.min.js +0 -2
- package/bundles/banta-sdk.umd.min.js.map +0 -1
package/fesm2015/banta-sdk.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Observable, Subject, BehaviorSubject, Subscription } from 'rxjs';
|
|
2
2
|
import { publish, take } from 'rxjs/operators';
|
|
3
3
|
import { Component, Input, ViewChild, Pipe, ElementRef, Output, HostBinding, NgModule, ViewChildren, Directive, NgZone, ContentChild, TemplateRef, Injectable, Inject } from '@angular/core';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import * as marked from 'marked';
|
|
5
|
+
import createDOMPurify from 'dompurify';
|
|
6
6
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
7
7
|
import { CommonModule } from '@angular/common';
|
|
8
8
|
import { MatIconModule } from '@angular/material/icon';
|
|
9
9
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
10
10
|
import { MatButtonModule } from '@angular/material/button';
|
|
11
11
|
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
12
|
-
import { PortalModule } from '@angular/cdk/portal';
|
|
13
12
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
14
13
|
import { MatInputModule } from '@angular/material/input';
|
|
15
14
|
import { FormsModule } from '@angular/forms';
|
|
16
|
-
import {
|
|
15
|
+
import { PortalModule } from '@angular/cdk/portal';
|
|
16
|
+
import { __awaiter, __decorate } from 'tslib';
|
|
17
17
|
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|
18
18
|
import { CommentsOrder, CDNProvider, SocketRPC, RpcEvent, DurableSocket } from '@banta/common';
|
|
19
19
|
import { ActivatedRoute } from '@angular/router';
|
|
@@ -163,7 +163,7 @@ LightboxComponent.decorators = [
|
|
|
163
163
|
{ type: Component, args: [{
|
|
164
164
|
selector: 'banta-lightbox',
|
|
165
165
|
template: "<div \r\n class=\"banta-lightbox-container\" \r\n #container\r\n [class.open]=\"isOpen\"\r\n >\r\n\r\n <a class=\"underlay\" (click)=\"close()\" href=\"javascript:;\"></a>\r\n\r\n <a class=\"close-button\" href=\"javascript:;\" (click)=\"close()\">\r\n <mat-icon>close</mat-icon>\r\n </a>\r\n\r\n <img [src]=\"currentImage\" />\r\n</div>\r\n",
|
|
166
|
-
styles: ["::ng-deep .banta-lightbox-container{position:fixed;top:0;left:0;right:0;bottom:0;opacity:0;pointer-events:none;background-color
|
|
166
|
+
styles: ["::ng-deep .banta-lightbox-container{position:fixed;top:0;left:0;right:0;bottom:0;opacity:0;pointer-events:none;background-color:#000000bf;color:#fff;z-index:10000;transition:.25s opacity ease-in-out;display:flex;align-items:center;justify-content:center}::ng-deep .banta-lightbox-container a.underlay{z-index:0;position:absolute;top:0;left:0;right:0;bottom:0;opacity:0}::ng-deep .banta-lightbox-container img{z-index:10;max-width:95%}::ng-deep .banta-lightbox-container.open{opacity:1;pointer-events:initial}::ng-deep .banta-lightbox-container a.close-button{position:absolute;top:0;right:0;padding:.75em;z-index:20}\n"]
|
|
167
167
|
},] }
|
|
168
168
|
];
|
|
169
169
|
LightboxComponent.propDecorators = {
|
|
@@ -181,7 +181,7 @@ const underline = {
|
|
|
181
181
|
return {
|
|
182
182
|
type: 'underline',
|
|
183
183
|
raw: match[0],
|
|
184
|
-
text: this.lexer.inlineTokens(match[1].trim()),
|
|
184
|
+
text: this.lexer.inlineTokens(match[1].trim()), // Additional custom properties
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
},
|
|
@@ -189,13 +189,13 @@ const underline = {
|
|
|
189
189
|
return `<u>${this.parser.parseInline(token.text)}</u>`;
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
|
-
marked.use({
|
|
192
|
+
marked.marked.use({
|
|
193
193
|
extensions: [underline]
|
|
194
194
|
});
|
|
195
195
|
class BantaMarkdownToHtmlPipe {
|
|
196
196
|
constructor(sanitizer) {
|
|
197
197
|
this.sanitizer = sanitizer;
|
|
198
|
-
this.renderer = new Renderer({
|
|
198
|
+
this.renderer = new marked.Renderer({
|
|
199
199
|
headerPrefix: ''
|
|
200
200
|
});
|
|
201
201
|
const linkRenderer = this.renderer.link;
|
|
@@ -207,7 +207,24 @@ class BantaMarkdownToHtmlPipe {
|
|
|
207
207
|
transform(value) {
|
|
208
208
|
if (!value)
|
|
209
209
|
return '';
|
|
210
|
-
|
|
210
|
+
let purifier = createDOMPurify(window);
|
|
211
|
+
// https://github.com/cure53/DOMPurify/blob/e1c19cf6407d782b666cb1d02a6af191f9cbc09e/demos/hooks-target-blank-demo.html
|
|
212
|
+
// Add a hook to make all links open a new window
|
|
213
|
+
purifier.addHook('afterSanitizeAttributes', function (node) {
|
|
214
|
+
// set all elements owning target to target=_blank
|
|
215
|
+
if ('target' in node) {
|
|
216
|
+
node.setAttribute('target', '_blank');
|
|
217
|
+
// prevent https://www.owasp.org/index.php/Reverse_Tabnabbing
|
|
218
|
+
node.setAttribute('rel', 'noopener noreferrer');
|
|
219
|
+
}
|
|
220
|
+
// set non-HTML/MathML links to xlink:show=new
|
|
221
|
+
if (!node.hasAttribute('target')
|
|
222
|
+
&& (node.hasAttribute('xlink:href')
|
|
223
|
+
|| node.hasAttribute('href'))) {
|
|
224
|
+
node.setAttribute('xlink:show', 'new');
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
return this.sanitizer.bypassSecurityTrustHtml(purifier.sanitize(marked.marked.parse(value, {
|
|
211
228
|
renderer: this.renderer
|
|
212
229
|
}), {
|
|
213
230
|
FORBID_TAGS: ['h1', 'h2', 'h3', 'h4'],
|
|
@@ -222,23 +239,7 @@ BantaMarkdownToHtmlPipe.decorators = [
|
|
|
222
239
|
];
|
|
223
240
|
BantaMarkdownToHtmlPipe.ctorParameters = () => [
|
|
224
241
|
{ type: DomSanitizer }
|
|
225
|
-
];
|
|
226
|
-
// https://github.com/cure53/DOMPurify/blob/e1c19cf6407d782b666cb1d02a6af191f9cbc09e/demos/hooks-target-blank-demo.html
|
|
227
|
-
// Add a hook to make all links open a new window
|
|
228
|
-
addHook('afterSanitizeAttributes', function (node) {
|
|
229
|
-
// set all elements owning target to target=_blank
|
|
230
|
-
if ('target' in node) {
|
|
231
|
-
node.setAttribute('target', '_blank');
|
|
232
|
-
// prevent https://www.owasp.org/index.php/Reverse_Tabnabbing
|
|
233
|
-
node.setAttribute('rel', 'noopener noreferrer');
|
|
234
|
-
}
|
|
235
|
-
// set non-HTML/MathML links to xlink:show=new
|
|
236
|
-
if (!node.hasAttribute('target')
|
|
237
|
-
&& (node.hasAttribute('xlink:href')
|
|
238
|
-
|| node.hasAttribute('href'))) {
|
|
239
|
-
node.setAttribute('xlink:show', 'new');
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
+
];
|
|
242
243
|
|
|
243
244
|
class BantaTrustResourceUrlPipe {
|
|
244
245
|
constructor(sanitizer) {
|
|
@@ -373,7 +374,7 @@ BantaAttachmentComponent.decorators = [
|
|
|
373
374
|
{ type: Component, args: [{
|
|
374
375
|
selector: 'banta-attachment',
|
|
375
376
|
template: "<button type=\"button\" (click)=\"remove()\" mat-mini-fab color=\"primary\" class=\"remove-button\" *ngIf=\"editing\">\r\n <mat-icon>close</mat-icon>\r\n</button>\r\n\r\n<ng-container *ngIf=\"isError\">\r\n <mat-icon class=\"error\">close</mat-icon>\r\n <em class=\"error\">{{theErrorMessage}}</em>\r\n</ng-container>\r\n<ng-container *ngIf=\"!isError\">\r\n <ng-container *ngIf=\"isLoading\">\r\n <mat-spinner></mat-spinner>\r\n <em>{{loadingMessage}}</em>\r\n </ng-container>\r\n <ng-container *ngIf=\"!isLoading\">\r\n <iframe *ngIf=\"hasFrame\"\r\n sandbox=\"allow-scripts allow-popups allow-same-origin allow-presentation\" \r\n [src]=\"frameUrl | trustResourceUrl\"></iframe>\r\n <a *ngIf=\"attachment.type === 'card'\" class=\"card-attachment\" [href]=\"attachment.url\" target=\"_blank\" [class.has-image]=\"attachment.card.image\">\r\n <img \r\n *ngIf=\"attachment.card.image\"\r\n class=\"thumbnail\" \r\n [src]=\"attachment.card.image\"\r\n />\r\n <div class=\"description\">\r\n <h1>{{attachment.card.title}}</h1>\r\n <div class=\"summary\">\r\n {{attachment.card.description}}\r\n </div>\r\n <cite>{{attachment.card.url}}</cite>\r\n </div>\r\n </a>\r\n <a class=\"image-attachment\" *ngIf=\"isImageAttachment\" href=\"javascript:;\" (click)=\"activate()\">\r\n <img [src]=\"attachment.url\" alt=\"Image Attachment\">\r\n </a>\r\n <blockquote *ngIf=\"attachment.type === 'tweet'\" \r\n class=\"twitter-tweet\">\r\n <p lang=\"en\" dir=\"ltr\"></p>\r\n <a [href]=\"attachment.url\"></a>\r\n </blockquote>\r\n </ng-container>\r\n</ng-container>",
|
|
376
|
-
styles: [":host{position:relative;display:block}:host.loading{outline:1px solid #333;padding:1em 0;width:300px;text-align:center}:host.loading mat-spinner{display:block;margin:0 auto .5em;width:-
|
|
377
|
+
styles: [":host{position:relative;display:block}:host.loading{outline:1px solid #333;padding:1em 0;width:300px;text-align:center}:host.loading mat-spinner{display:block;margin:0 auto .5em;width:-moz-fit-content;width:fit-content}a.card-attachment{display:flex;align-items:flex-start;grid-gap:1em;gap:1em;width:100%;border:1px solid #666;border-radius:4px;padding:1em;box-sizing:border-box;background-color:#191919;margin:1em 0}a.card-attachment img{width:250px;aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover;border-radius:10px}a.card-attachment.has-image h1{font-size:22px}a.card-attachment h1{min-width:0;margin:0 0 .5em;font-size:26px}a.card-attachment cite{min-width:0;opacity:.75;margin-top:1em;display:block;font-size:80%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}a.card-attachment .description{min-width:0;width:100%}a.card-attachment .summary{overflow-x:hidden;text-overflow:ellipsis}.remove-button{position:absolute;right:10px;top:10px;margin:0;z-index:1}a.image-attachment{width:300px;position:relative;text-align:center}a.image-attachment.with-border{outline:1px solid #333;padding:1em 0}a.image-attachment mat-spinner{display:block;margin:0 auto .5em;width:-moz-fit-content;width:fit-content}a.image-attachment mat-icon.error{display:block;font-size:48px;width:48px;height:48px;margin:0 auto .5em}a.image-attachment .error{color:#b76363}a.image-attachment img{width:300px;border-radius:10px;max-width:100%;max-height:20em;-o-object-fit:cover;object-fit:cover}iframe{border:none;width:100%;aspect-ratio:16/9}@media (max-width: 700px){a.card-attachment{flex-direction:column}a.card-attachment img{width:100%}}\n"]
|
|
377
378
|
},] }
|
|
378
379
|
];
|
|
379
380
|
BantaAttachmentComponent.ctorParameters = () => [
|
|
@@ -444,7 +445,7 @@ BantaAttachmentsComponent.decorators = [
|
|
|
444
445
|
{ type: Component, args: [{
|
|
445
446
|
selector: 'banta-attachments',
|
|
446
447
|
template: "<ng-container *ngIf=\"attachments?.length > 0\">\r\n <banta-lightbox #lightbox></banta-lightbox>\r\n <div class=\"block-attachments\">\r\n <ng-container *ngFor=\"let attachment of blockAttachments; trackBy: attachmentId\">\r\n <banta-attachment \r\n [attachment]=\"attachment\"\r\n [editing]=\"editing\"\r\n (loaded)=\"markAttachmentLoaded(attachment)\"\r\n (removed)=\"removeAttachment(attachment)\"\r\n (activated)=\"showLightbox(attachment)\"\r\n ></banta-attachment>\r\n </ng-container>\r\n </div>\r\n\r\n <div \r\n class=\"inline-attachments\" \r\n [class.single]=\"attachments?.length === 1\" \r\n *ngIf=\"attachments && attachments?.length > 0\"\r\n >\r\n <ng-container *ngFor=\"let attachment of inlineAttachments; trackBy: attachmentId\">\r\n <banta-attachment \r\n [attachment]=\"attachment\"\r\n [editing]=\"editing\"\r\n (loaded)=\"markAttachmentLoaded(attachment)\"\r\n (removed)=\"removeAttachment(attachment)\"\r\n (activated)=\"showLightbox(attachment)\"\r\n ></banta-attachment>\r\n </ng-container>\r\n </div>\r\n</ng-container>",
|
|
447
|
-
styles: [".block-attachments{display:flex;flex-direction:column}.block-attachments banta-attachment{width:100%}.inline-attachments{flex-direction:row;margin-top:15px;display:flex;gap:20px;flex-wrap:wrap}"]
|
|
448
|
+
styles: [".block-attachments{display:flex;flex-direction:column}.block-attachments banta-attachment{width:100%}.inline-attachments{flex-direction:row;margin-top:15px;display:flex;grid-gap:20px;gap:20px;flex-wrap:wrap}\n"]
|
|
448
449
|
},] }
|
|
449
450
|
];
|
|
450
451
|
BantaAttachmentsComponent.propDecorators = {
|
|
@@ -455,7 +456,7 @@ BantaAttachmentsComponent.propDecorators = {
|
|
|
455
456
|
loaded: [{ type: Output }]
|
|
456
457
|
};
|
|
457
458
|
|
|
458
|
-
const COMPONENTS = [
|
|
459
|
+
const COMPONENTS$3 = [
|
|
459
460
|
TimestampComponent,
|
|
460
461
|
LightboxComponent,
|
|
461
462
|
BantaMarkdownToHtmlPipe,
|
|
@@ -468,14 +469,14 @@ class BantaCommonModule {
|
|
|
468
469
|
}
|
|
469
470
|
BantaCommonModule.decorators = [
|
|
470
471
|
{ type: NgModule, args: [{
|
|
471
|
-
declarations: COMPONENTS,
|
|
472
|
+
declarations: COMPONENTS$3,
|
|
472
473
|
imports: [
|
|
473
474
|
CommonModule,
|
|
474
475
|
MatIconModule,
|
|
475
476
|
MatProgressSpinnerModule,
|
|
476
477
|
MatButtonModule
|
|
477
478
|
],
|
|
478
|
-
exports: COMPONENTS
|
|
479
|
+
exports: COMPONENTS$3
|
|
479
480
|
},] }
|
|
480
481
|
];
|
|
481
482
|
|
|
@@ -7059,7 +7060,7 @@ EmojiSelectorPanelComponent.decorators = [
|
|
|
7059
7060
|
{ type: Component, args: [{
|
|
7060
7061
|
selector: 'emoji-selector-panel',
|
|
7061
7062
|
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>",
|
|
7062
|
-
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 - 5px)}.selector{display:flex;flex-direction:column}.categories a{opacity:.25;transition
|
|
7063
|
+
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 - 5px)}.selector{display:flex;flex-direction:column}.categories a{opacity:.25;transition:.4s opacity 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}}:host-context(.banta-mobile) .selector{flex-direction:row;height:27em}:host-context(.banta-mobile) .emoji-list{height:auto}\n"]
|
|
7063
7064
|
},] }
|
|
7064
7065
|
];
|
|
7065
7066
|
EmojiSelectorPanelComponent.ctorParameters = () => [
|
|
@@ -7173,7 +7174,7 @@ EmojiSelectorButtonComponent.propDecorators = {
|
|
|
7173
7174
|
originY: [{ type: Input }]
|
|
7174
7175
|
};
|
|
7175
7176
|
|
|
7176
|
-
const COMPONENTS$
|
|
7177
|
+
const COMPONENTS$2 = [
|
|
7177
7178
|
EmojiSelectorPanelComponent,
|
|
7178
7179
|
EmojiSelectorButtonComponent
|
|
7179
7180
|
];
|
|
@@ -7181,7 +7182,7 @@ class EmojiModule {
|
|
|
7181
7182
|
}
|
|
7182
7183
|
EmojiModule.decorators = [
|
|
7183
7184
|
{ type: NgModule, args: [{
|
|
7184
|
-
declarations: COMPONENTS$
|
|
7185
|
+
declarations: COMPONENTS$2,
|
|
7185
7186
|
imports: [
|
|
7186
7187
|
CommonModule,
|
|
7187
7188
|
FormsModule,
|
|
@@ -7192,64 +7193,10 @@ EmojiModule.decorators = [
|
|
|
7192
7193
|
OverlayModule,
|
|
7193
7194
|
PortalModule
|
|
7194
7195
|
],
|
|
7195
|
-
exports: COMPONENTS$
|
|
7196
|
+
exports: COMPONENTS$2
|
|
7196
7197
|
},] }
|
|
7197
7198
|
];
|
|
7198
7199
|
|
|
7199
|
-
class ChatMessageComponent {
|
|
7200
|
-
constructor() {
|
|
7201
|
-
this._selected = new Subject();
|
|
7202
|
-
this._reported = new Subject();
|
|
7203
|
-
this._upvoted = new Subject();
|
|
7204
|
-
this._userSelected = new Subject();
|
|
7205
|
-
}
|
|
7206
|
-
get userSelected() {
|
|
7207
|
-
return this._userSelected;
|
|
7208
|
-
}
|
|
7209
|
-
get selected() {
|
|
7210
|
-
return this._selected;
|
|
7211
|
-
}
|
|
7212
|
-
get reported() {
|
|
7213
|
-
return this._reported;
|
|
7214
|
-
}
|
|
7215
|
-
get upvoted() {
|
|
7216
|
-
return this._upvoted;
|
|
7217
|
-
}
|
|
7218
|
-
avatarForUser(user) {
|
|
7219
|
-
if (user && user.avatarUrl) {
|
|
7220
|
-
let url = user.avatarUrl;
|
|
7221
|
-
return `url(${url})`;
|
|
7222
|
-
}
|
|
7223
|
-
return null;
|
|
7224
|
-
}
|
|
7225
|
-
upvote() {
|
|
7226
|
-
this._upvoted.next();
|
|
7227
|
-
}
|
|
7228
|
-
report() {
|
|
7229
|
-
this._reported.next();
|
|
7230
|
-
}
|
|
7231
|
-
select() {
|
|
7232
|
-
this._selected.next();
|
|
7233
|
-
}
|
|
7234
|
-
selectUser() {
|
|
7235
|
-
this._userSelected.next();
|
|
7236
|
-
}
|
|
7237
|
-
}
|
|
7238
|
-
ChatMessageComponent.decorators = [
|
|
7239
|
-
{ type: Component, args: [{
|
|
7240
|
-
selector: 'banta-chat-message',
|
|
7241
|
-
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 <mat-icon [inline]=\"true\">star</mat-icon> {{message.likes}}\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>",
|
|
7242
|
-
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}"]
|
|
7243
|
-
},] }
|
|
7244
|
-
];
|
|
7245
|
-
ChatMessageComponent.propDecorators = {
|
|
7246
|
-
message: [{ type: Input }],
|
|
7247
|
-
userSelected: [{ type: Output }],
|
|
7248
|
-
selected: [{ type: Output }],
|
|
7249
|
-
reported: [{ type: Output }],
|
|
7250
|
-
upvoted: [{ type: Output }]
|
|
7251
|
-
};
|
|
7252
|
-
|
|
7253
7200
|
class ChatBackendBase {
|
|
7254
7201
|
constructor() {
|
|
7255
7202
|
this._userChanged = new BehaviorSubject(null);
|
|
@@ -7280,97 +7227,364 @@ class ChatBackendBase {
|
|
|
7280
7227
|
}
|
|
7281
7228
|
}
|
|
7282
7229
|
|
|
7283
|
-
|
|
7284
|
-
|
|
7230
|
+
/**
|
|
7231
|
+
* Unified chat and comments component
|
|
7232
|
+
*/
|
|
7233
|
+
class BantaComponent {
|
|
7234
|
+
constructor(backend, matDialog) {
|
|
7285
7235
|
this.backend = backend;
|
|
7286
|
-
this.
|
|
7287
|
-
this.
|
|
7288
|
-
this.
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7236
|
+
this.matDialog = matDialog;
|
|
7237
|
+
this._subs = new Subscription();
|
|
7238
|
+
this.auxOpen = false;
|
|
7239
|
+
this.auxTitle = 'Notifications';
|
|
7240
|
+
this.auxMode = 'notifications';
|
|
7241
|
+
this.mobileFocus = null;
|
|
7242
|
+
this.newNotifications = false;
|
|
7243
|
+
this.chatLabel = 'Chat';
|
|
7244
|
+
this.commentsLabel = 'Comments';
|
|
7245
|
+
this._signInSelected = new Subject();
|
|
7246
|
+
this.pointOpen = null;
|
|
7247
|
+
this.pointSubChat = null;
|
|
7248
|
+
this.newPointSubMessage = {};
|
|
7249
|
+
this.genericAvatarUrl = 'https://gravatar.com/avatar/915c804e0be607a4ad766ddadea5c48a?s=512&d=https://codepen.io/assets/avatars/user-avatar-512x512-6e240cf350d2f1cc07c2bed234c3a3bb5f1b237023c204c782622e80d6b212ba.png';
|
|
7292
7250
|
}
|
|
7293
|
-
|
|
7294
|
-
|
|
7251
|
+
ngOnInit() {
|
|
7252
|
+
this._subs.add(this.backend.userChanged.subscribe(user => this.currentUser = user));
|
|
7253
|
+
this._subs.add(this.backend.notificationsChanged.subscribe(notifs => this.notifications = notifs));
|
|
7254
|
+
this._subs.add(this.backend.newNotification.subscribe(notif => {
|
|
7255
|
+
this.newNotifications = true;
|
|
7256
|
+
}));
|
|
7295
7257
|
}
|
|
7296
|
-
|
|
7297
|
-
return this
|
|
7258
|
+
sendPointSubMessage() {
|
|
7259
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7260
|
+
let text = (this.newPointSubMessage.message || '').trim();
|
|
7261
|
+
this.newPointSubMessage.message = '';
|
|
7262
|
+
if (text === '')
|
|
7263
|
+
return;
|
|
7264
|
+
let message = {
|
|
7265
|
+
user: null,
|
|
7266
|
+
sentAt: Date.now(),
|
|
7267
|
+
likes: 0,
|
|
7268
|
+
message: text
|
|
7269
|
+
};
|
|
7270
|
+
try {
|
|
7271
|
+
yield this.pointSubChat.send(message);
|
|
7272
|
+
}
|
|
7273
|
+
catch (e) {
|
|
7274
|
+
console.error(`Failed to send point sub-message:`);
|
|
7275
|
+
console.error(e);
|
|
7276
|
+
}
|
|
7277
|
+
});
|
|
7298
7278
|
}
|
|
7299
|
-
|
|
7300
|
-
return this
|
|
7279
|
+
goToMessage(message) {
|
|
7280
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7281
|
+
let targetMessage = message;
|
|
7282
|
+
if (message.parentMessageId) {
|
|
7283
|
+
// jump to the parent message thread...
|
|
7284
|
+
let parentMessage;
|
|
7285
|
+
try {
|
|
7286
|
+
parentMessage = yield this.backend.getMessage(message.topicId, message.parentMessageId);
|
|
7287
|
+
}
|
|
7288
|
+
catch (e) {
|
|
7289
|
+
console.error(`Received exception while fetching parent message:`);
|
|
7290
|
+
console.error(e);
|
|
7291
|
+
}
|
|
7292
|
+
if (!parentMessage) {
|
|
7293
|
+
console.error(`Failed to look up parent message ${message.topicId}/${message.parentMessageId}`);
|
|
7294
|
+
console.error(`Original message was:`);
|
|
7295
|
+
console.dir(targetMessage);
|
|
7296
|
+
return;
|
|
7297
|
+
}
|
|
7298
|
+
message = parentMessage;
|
|
7299
|
+
}
|
|
7300
|
+
let viewType = this.getViewType(message);
|
|
7301
|
+
if (viewType === 'comment') {
|
|
7302
|
+
if (this.pointSubChat) {
|
|
7303
|
+
if (this.pointSubChat.close)
|
|
7304
|
+
this.pointSubChat.close();
|
|
7305
|
+
this.pointSubChat = null;
|
|
7306
|
+
}
|
|
7307
|
+
this.mobileFocus = 'points';
|
|
7308
|
+
this.pointOpen = message;
|
|
7309
|
+
this.pointSubChat = yield this.backend.getSourceForThread(message.topicId, message.id);
|
|
7310
|
+
this.pointOpen = yield this.backend.refreshMessage(message);
|
|
7311
|
+
this.newPointSubMessage = {};
|
|
7312
|
+
}
|
|
7313
|
+
else if (viewType === 'chat') {
|
|
7314
|
+
this.mobileFocus = 'firehose';
|
|
7315
|
+
this.firehose.jumpToMessage(message);
|
|
7316
|
+
}
|
|
7317
|
+
});
|
|
7301
7318
|
}
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
if (this.
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
return;
|
|
7309
|
-
}
|
|
7310
|
-
if (this.unsubscribe)
|
|
7311
|
-
this.unsubscribe();
|
|
7312
|
-
if (value) {
|
|
7313
|
-
this.unsubscribe = this.backend.watchMessage(value, message => this.message = message);
|
|
7319
|
+
pointUnfocus() {
|
|
7320
|
+
this.pointOpen = null;
|
|
7321
|
+
if (this.pointSubChat) {
|
|
7322
|
+
if (this.pointSubChat.close)
|
|
7323
|
+
this.pointSubChat.close();
|
|
7324
|
+
this.pointSubChat = null;
|
|
7314
7325
|
}
|
|
7315
7326
|
}
|
|
7316
|
-
|
|
7317
|
-
this.
|
|
7327
|
+
ngOnDestroy() {
|
|
7328
|
+
this._subs.unsubscribe();
|
|
7318
7329
|
}
|
|
7319
|
-
|
|
7320
|
-
this.
|
|
7330
|
+
showAux(title, mode) {
|
|
7331
|
+
this.auxOpen = true;
|
|
7332
|
+
this.auxTitle = title;
|
|
7333
|
+
this.auxMode = mode;
|
|
7334
|
+
this.mobileFocus = 'aux';
|
|
7321
7335
|
}
|
|
7322
|
-
|
|
7323
|
-
this.
|
|
7336
|
+
showNotifications() {
|
|
7337
|
+
this.showAux('Notifications', 'notifications');
|
|
7324
7338
|
}
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
{ type: Component, args: [{
|
|
7328
|
-
selector: 'banta-live-chat-message',
|
|
7329
|
-
template: `
|
|
7330
|
-
<banta-chat-message
|
|
7331
|
-
*ngIf="message"
|
|
7332
|
-
[message]="message"
|
|
7333
|
-
(upvoted)="upvote()"
|
|
7334
|
-
(reported)="report()"
|
|
7335
|
-
(selected)="select()"
|
|
7336
|
-
></banta-chat-message>
|
|
7337
|
-
`,
|
|
7338
|
-
styles: [``]
|
|
7339
|
-
},] }
|
|
7340
|
-
];
|
|
7341
|
-
LiveChatMessageComponent.ctorParameters = () => [
|
|
7342
|
-
{ type: ChatBackendBase }
|
|
7343
|
-
];
|
|
7344
|
-
LiveChatMessageComponent.propDecorators = {
|
|
7345
|
-
upvoted: [{ type: Output }],
|
|
7346
|
-
reported: [{ type: Output }],
|
|
7347
|
-
selected: [{ type: Output }],
|
|
7348
|
-
message: [{ type: Input }]
|
|
7349
|
-
};
|
|
7350
|
-
|
|
7351
|
-
class ChatViewComponent {
|
|
7352
|
-
constructor(backend, elementRef) {
|
|
7353
|
-
this.backend = backend;
|
|
7354
|
-
this.elementRef = elementRef;
|
|
7355
|
-
this._sourceSubs = new Subscription();
|
|
7356
|
-
this._selected = new Subject();
|
|
7357
|
-
this._selected$ = this._selected.asObservable();
|
|
7358
|
-
this._reported = new Subject();
|
|
7359
|
-
this._reported$ = this._reported.asObservable();
|
|
7360
|
-
this._upvoted = new Subject();
|
|
7361
|
-
this._upvoted$ = this._upvoted.asObservable();
|
|
7362
|
-
this._userSelected = new Subject();
|
|
7363
|
-
this._userSelected$ = this._userSelected.asObservable();
|
|
7364
|
-
this._received = new Subject();
|
|
7365
|
-
this._received$ = this._received.asObservable();
|
|
7366
|
-
this.messages = [];
|
|
7367
|
-
this.maxMessages = 200;
|
|
7368
|
-
this.emptyLabel = 'Be the first to chat';
|
|
7339
|
+
get topicID() {
|
|
7340
|
+
return this._topicID;
|
|
7369
7341
|
}
|
|
7370
|
-
|
|
7371
|
-
|
|
7342
|
+
set topicID(value) {
|
|
7343
|
+
this._topicID = value;
|
|
7344
|
+
this.close();
|
|
7345
|
+
this.connectToTopic(this._topicID);
|
|
7372
7346
|
}
|
|
7373
|
-
|
|
7347
|
+
connectToTopic(id) {
|
|
7348
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7349
|
+
this.firehoseSource = yield this.backend.getSourceForTopic(`${id}_firehose`);
|
|
7350
|
+
this.pointSource = yield this.backend.getSourceForTopic(`${id}_thepoint`);
|
|
7351
|
+
});
|
|
7352
|
+
}
|
|
7353
|
+
get signInSelected() {
|
|
7354
|
+
return this._signInSelected;
|
|
7355
|
+
}
|
|
7356
|
+
showSignIn() {
|
|
7357
|
+
this._signInSelected.next();
|
|
7358
|
+
}
|
|
7359
|
+
close() {
|
|
7360
|
+
if (this.firehoseSource) {
|
|
7361
|
+
if (this.firehoseSource.close)
|
|
7362
|
+
this.firehoseSource.close();
|
|
7363
|
+
this.firehoseSource = null;
|
|
7364
|
+
}
|
|
7365
|
+
if (this.pointSource) {
|
|
7366
|
+
if (this.pointSource.close)
|
|
7367
|
+
this.pointSource.close();
|
|
7368
|
+
this.pointSource = null;
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7371
|
+
get hasPoint() {
|
|
7372
|
+
return this.pointOpen != null;
|
|
7373
|
+
}
|
|
7374
|
+
closeAux() {
|
|
7375
|
+
this.auxOpen = false;
|
|
7376
|
+
this.mobileFocus = 'firehose';
|
|
7377
|
+
}
|
|
7378
|
+
getViewType(message) {
|
|
7379
|
+
if (message.topicId.endsWith('_firehose'))
|
|
7380
|
+
return 'chat';
|
|
7381
|
+
else if (message.topicId.endsWith('_thepoint'))
|
|
7382
|
+
return 'comment';
|
|
7383
|
+
return 'comment';
|
|
7384
|
+
}
|
|
7385
|
+
upvoteMessage(message) {
|
|
7386
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7387
|
+
// TODO
|
|
7388
|
+
//await this.backend.likeMessage(message.id);
|
|
7389
|
+
});
|
|
7390
|
+
}
|
|
7391
|
+
showProfile(user) {
|
|
7392
|
+
this.profileUser = user;
|
|
7393
|
+
this.showAux(`@${user.username}'s Profile`, 'profile');
|
|
7394
|
+
}
|
|
7395
|
+
sendReport(message) {
|
|
7396
|
+
this.auxOpen = false;
|
|
7397
|
+
alert('would send report');
|
|
7398
|
+
}
|
|
7399
|
+
reportMessage(message) {
|
|
7400
|
+
this.reportedMessage = message;
|
|
7401
|
+
this.showAux(`Report message from @${message.user.username}`, 'report');
|
|
7402
|
+
}
|
|
7403
|
+
}
|
|
7404
|
+
BantaComponent.decorators = [
|
|
7405
|
+
{ type: Component, args: [{
|
|
7406
|
+
selector: `banta`,
|
|
7407
|
+
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 \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>",
|
|
7408
|
+
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;display:block;width:-moz-fit-content;width:fit-content;position:relative;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}header:after{content:\"\";border:1px solid;border-color:#ccc;height:0px;width:100%;display:block;position:relative;z-index:0}.points{width:33%;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:initial}: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:.2s width ease-in,.2s max-width ease-in;position:relative}.points .points-section{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition:.2s opacity ease-in;z-index:2}.points .point-focus{position:absolute;width:100%;bottom:0;top:1.75em;right:0;left:0;padding:.5em;opacity:0;transition:.2s opacity ease-in;flex-grow:1;display:flex;flex-direction:column}.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;background:black;color:#fff;border:1px solid #333;min-height:6em;width:100%}form input[type=text]{background:black;color:#fff;border:1px solid #333;width:100%;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:0px;min-width:0px;overflow-x:hidden;transition:.4s width ease-out,.4s min-width 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}:host.point-focus .points{width:100%;max-width:100%}.aux{width:100%;min-width:0;min-width:initial;max-width:100%}.points,.firehose,.aux{position:absolute;top:2em;left:0;right:0;bottom:0;z-index:0;background:black}.points.focus,.firehose.focus,.aux.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}\n"]
|
|
7409
|
+
},] }
|
|
7410
|
+
];
|
|
7411
|
+
BantaComponent.ctorParameters = () => [
|
|
7412
|
+
{ type: ChatBackendBase },
|
|
7413
|
+
{ type: MatDialog }
|
|
7414
|
+
];
|
|
7415
|
+
BantaComponent.propDecorators = {
|
|
7416
|
+
firehose: [{ type: ViewChild, args: ['firehose', { static: true },] }],
|
|
7417
|
+
topicID: [{ type: Input }],
|
|
7418
|
+
chatLabel: [{ type: Input }],
|
|
7419
|
+
commentsLabel: [{ type: Input }],
|
|
7420
|
+
signInSelected: [{ type: Output }],
|
|
7421
|
+
hasPoint: [{ type: HostBinding, args: ['class.point-focus',] }]
|
|
7422
|
+
};
|
|
7423
|
+
|
|
7424
|
+
class BantaLogoComponent {
|
|
7425
|
+
}
|
|
7426
|
+
BantaLogoComponent.decorators = [
|
|
7427
|
+
{ type: Component, args: [{
|
|
7428
|
+
selector: 'banta-logo',
|
|
7429
|
+
template: `banta`,
|
|
7430
|
+
styles: [`
|
|
7431
|
+
:host {
|
|
7432
|
+
font-family: 'Odibee Sans', sans-serif;
|
|
7433
|
+
font-size: 40pt;
|
|
7434
|
+
}
|
|
7435
|
+
|
|
7436
|
+
:host.small {
|
|
7437
|
+
font-size: 30pt;
|
|
7438
|
+
}
|
|
7439
|
+
`]
|
|
7440
|
+
},] }
|
|
7441
|
+
];
|
|
7442
|
+
|
|
7443
|
+
class ChatMessageComponent {
|
|
7444
|
+
constructor() {
|
|
7445
|
+
this._selected = new Subject();
|
|
7446
|
+
this._reported = new Subject();
|
|
7447
|
+
this._upvoted = new Subject();
|
|
7448
|
+
this._userSelected = new Subject();
|
|
7449
|
+
}
|
|
7450
|
+
get userSelected() {
|
|
7451
|
+
return this._userSelected;
|
|
7452
|
+
}
|
|
7453
|
+
get selected() {
|
|
7454
|
+
return this._selected;
|
|
7455
|
+
}
|
|
7456
|
+
get reported() {
|
|
7457
|
+
return this._reported;
|
|
7458
|
+
}
|
|
7459
|
+
get upvoted() {
|
|
7460
|
+
return this._upvoted;
|
|
7461
|
+
}
|
|
7462
|
+
avatarForUser(user) {
|
|
7463
|
+
if (user && user.avatarUrl) {
|
|
7464
|
+
let url = user.avatarUrl;
|
|
7465
|
+
return `url(${url})`;
|
|
7466
|
+
}
|
|
7467
|
+
return null;
|
|
7468
|
+
}
|
|
7469
|
+
upvote() {
|
|
7470
|
+
this._upvoted.next();
|
|
7471
|
+
}
|
|
7472
|
+
report() {
|
|
7473
|
+
this._reported.next();
|
|
7474
|
+
}
|
|
7475
|
+
select() {
|
|
7476
|
+
this._selected.next();
|
|
7477
|
+
}
|
|
7478
|
+
selectUser() {
|
|
7479
|
+
this._userSelected.next();
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
ChatMessageComponent.decorators = [
|
|
7483
|
+
{ type: Component, args: [{
|
|
7484
|
+
selector: 'banta-chat-message',
|
|
7485
|
+
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 <mat-icon [inline]=\"true\">star</mat-icon> {{message.likes}}\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>",
|
|
7486
|
+
styles: [":host{display:flex;flex-direction:row;align-items:center;padding:0 1em;background-color:#fff;color:#000;transition:.4s background-color 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:normal;text-align:right;margin-right:.25em;flex-shrink:0;display:flex;align-items:center}:host .user .avatar{background-position:center;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:.4s opacity 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}\n"]
|
|
7487
|
+
},] }
|
|
7488
|
+
];
|
|
7489
|
+
ChatMessageComponent.propDecorators = {
|
|
7490
|
+
message: [{ type: Input }],
|
|
7491
|
+
userSelected: [{ type: Output }],
|
|
7492
|
+
selected: [{ type: Output }],
|
|
7493
|
+
reported: [{ type: Output }],
|
|
7494
|
+
upvoted: [{ type: Output }]
|
|
7495
|
+
};
|
|
7496
|
+
|
|
7497
|
+
class LiveChatMessageComponent {
|
|
7498
|
+
constructor(backend) {
|
|
7499
|
+
this.backend = backend;
|
|
7500
|
+
this._upvoted = new Subject();
|
|
7501
|
+
this._reported = new Subject();
|
|
7502
|
+
this._selected = new Subject();
|
|
7503
|
+
}
|
|
7504
|
+
get upvoted() {
|
|
7505
|
+
return this._upvoted;
|
|
7506
|
+
}
|
|
7507
|
+
get reported() {
|
|
7508
|
+
return this._reported;
|
|
7509
|
+
}
|
|
7510
|
+
get selected() {
|
|
7511
|
+
return this._selected;
|
|
7512
|
+
}
|
|
7513
|
+
get message() {
|
|
7514
|
+
return this._message;
|
|
7515
|
+
}
|
|
7516
|
+
set message(value) {
|
|
7517
|
+
let originalId = null;
|
|
7518
|
+
if (this._message)
|
|
7519
|
+
originalId = this._message.id;
|
|
7520
|
+
this._message = value;
|
|
7521
|
+
if (value && originalId === value.id) {
|
|
7522
|
+
return;
|
|
7523
|
+
}
|
|
7524
|
+
if (this.unsubscribe)
|
|
7525
|
+
this.unsubscribe();
|
|
7526
|
+
if (value) {
|
|
7527
|
+
this.unsubscribe = this.backend.watchMessage(value, message => this.message = message);
|
|
7528
|
+
}
|
|
7529
|
+
}
|
|
7530
|
+
report() {
|
|
7531
|
+
this._reported.next();
|
|
7532
|
+
}
|
|
7533
|
+
upvote() {
|
|
7534
|
+
this._upvoted.next();
|
|
7535
|
+
}
|
|
7536
|
+
select() {
|
|
7537
|
+
this._selected.next();
|
|
7538
|
+
}
|
|
7539
|
+
}
|
|
7540
|
+
LiveChatMessageComponent.decorators = [
|
|
7541
|
+
{ type: Component, args: [{
|
|
7542
|
+
selector: 'banta-live-chat-message',
|
|
7543
|
+
template: `
|
|
7544
|
+
<banta-chat-message
|
|
7545
|
+
*ngIf="message"
|
|
7546
|
+
[message]="message"
|
|
7547
|
+
(upvoted)="upvote()"
|
|
7548
|
+
(reported)="report()"
|
|
7549
|
+
(selected)="select()"
|
|
7550
|
+
></banta-chat-message>
|
|
7551
|
+
`,
|
|
7552
|
+
styles: [``]
|
|
7553
|
+
},] }
|
|
7554
|
+
];
|
|
7555
|
+
LiveChatMessageComponent.ctorParameters = () => [
|
|
7556
|
+
{ type: ChatBackendBase }
|
|
7557
|
+
];
|
|
7558
|
+
LiveChatMessageComponent.propDecorators = {
|
|
7559
|
+
upvoted: [{ type: Output }],
|
|
7560
|
+
reported: [{ type: Output }],
|
|
7561
|
+
selected: [{ type: Output }],
|
|
7562
|
+
message: [{ type: Input }]
|
|
7563
|
+
};
|
|
7564
|
+
|
|
7565
|
+
class ChatViewComponent {
|
|
7566
|
+
constructor(backend, elementRef) {
|
|
7567
|
+
this.backend = backend;
|
|
7568
|
+
this.elementRef = elementRef;
|
|
7569
|
+
this._sourceSubs = new Subscription();
|
|
7570
|
+
this._selected = new Subject();
|
|
7571
|
+
this._selected$ = this._selected.asObservable();
|
|
7572
|
+
this._reported = new Subject();
|
|
7573
|
+
this._reported$ = this._reported.asObservable();
|
|
7574
|
+
this._upvoted = new Subject();
|
|
7575
|
+
this._upvoted$ = this._upvoted.asObservable();
|
|
7576
|
+
this._userSelected = new Subject();
|
|
7577
|
+
this._userSelected$ = this._userSelected.asObservable();
|
|
7578
|
+
this._received = new Subject();
|
|
7579
|
+
this._received$ = this._received.asObservable();
|
|
7580
|
+
this.messages = [];
|
|
7581
|
+
this.maxMessages = 200;
|
|
7582
|
+
this.emptyLabel = 'Be the first to chat';
|
|
7583
|
+
}
|
|
7584
|
+
get source() {
|
|
7585
|
+
return this._source;
|
|
7586
|
+
}
|
|
7587
|
+
get selected() { return this._selected$; }
|
|
7374
7588
|
get userSelected() { return this._userSelected$; }
|
|
7375
7589
|
get reported() { return this._reported$; }
|
|
7376
7590
|
get upvoted() { return this._upvoted$; }
|
|
@@ -7492,7 +7706,7 @@ ChatViewComponent.decorators = [
|
|
|
7492
7706
|
{ type: Component, args: [{
|
|
7493
7707
|
selector: 'banta-chat-view',
|
|
7494
7708
|
template: "<div class=\"message-container\" #messageContainer>\r\n <ng-content select=\"[data-before]\"></ng-content>\r\n \r\n <div class=\"empty\" *ngIf=\"messages.length === 0\">\r\n {{emptyLabel}}\r\n </div>\r\n \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>",
|
|
7495
|
-
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
|
|
7709
|
+
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:white;padding:.5em 1em .5em .5em}.message-container.no-scroll{height:auto;overflow-y:visible}:host-context(.mat-dark-theme) .message-container{color:#fff;background:black}banta-chat-message.flash{animation:flash;animation-duration:2.5s;animation-iteration-count: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)}}.empty{text-align:center;margin:2em;color:#888;font-size:150%}\n"]
|
|
7496
7710
|
},] }
|
|
7497
7711
|
];
|
|
7498
7712
|
ChatViewComponent.ctorParameters = () => [
|
|
@@ -7654,8 +7868,8 @@ class BantaChatComponent {
|
|
|
7654
7868
|
BantaChatComponent.decorators = [
|
|
7655
7869
|
{ type: Component, args: [{
|
|
7656
7870
|
selector: 'banta-chat',
|
|
7657
|
-
template: "<banta-chat-view \r\n #chatView\r\n [source]=\"source\"\r\n [emptyLabel]=\"emptyLabel\"\r\n (upvoted)=\"upvote($event)\"\r\n (reported)=\"report($event)\"\r\n (selected)=\"select($event)\"\r\n (received)=\"onReceived($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 #input\r\n type=\"text\"\r\n name=\"message\" \r\n autocomplete=\"off\"\r\n [placeholder]=\"messageFieldPlaceholder\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [(ngModel)]=\"newMessage.message\" />\r\n \r\n <emoji-selector-button\r\n (selected)=\"insertEmoji($event)\"\r\n overlayY=\"bottom\"\r\n overlayX=\"end\"\r\n originY=\"top\"\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>",
|
|
7658
|
-
styles: [":host{flex-direction:column;border-radius:5px;padding:10px;font-size:10pt;min-height:1px}.entry-container
|
|
7871
|
+
template: "<banta-chat-view \r\n #chatView\r\n [source]=\"source\"\r\n [emptyLabel]=\"emptyLabel\"\r\n (upvoted)=\"upvote($event)\"\r\n (reported)=\"report($event)\"\r\n (selected)=\"select($event)\"\r\n (received)=\"onReceived($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 #input\r\n type=\"text\"\r\n name=\"message\" \r\n autocomplete=\"off\"\r\n enterkeyhint=\"send\"\r\n [placeholder]=\"messageFieldPlaceholder\"\r\n (keydown)=\"onKeyDown($event)\"\r\n [(ngModel)]=\"newMessage.message\" />\r\n \r\n <emoji-selector-button\r\n (selected)=\"insertEmoji($event)\"\r\n overlayY=\"bottom\"\r\n overlayX=\"end\"\r\n originY=\"top\"\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>",
|
|
7872
|
+
styles: [":host{display:flex;flex-direction:column;border-radius:5px;padding:10px;flex-grow:1;font-size:10pt;min-height:1px}.entry-container{display:flex;flex-direction:row;flex-grow:1;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:hover,.entry-container input:-webkit-autofill:focus{outline:1px solid #9da302;-webkit-text-fill-color:#9da302;-webkit-box-shadow:0 0 0px 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:initial}form{display:flex;padding:.5em 0;align-items:center}form textarea{font-size:14pt;background:black;color:#fff;border:1px solid #333;min-height:6em;width:100%}form input[type=text]{background:white;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:black;color:#fff;border:1px solid #333}\n"]
|
|
7659
7873
|
},] }
|
|
7660
7874
|
];
|
|
7661
7875
|
BantaChatComponent.ctorParameters = () => [
|
|
@@ -7681,7 +7895,7 @@ BantaChatComponent.propDecorators = {
|
|
|
7681
7895
|
inputElementRef: [{ type: ViewChild, args: ['input',] }]
|
|
7682
7896
|
};
|
|
7683
7897
|
|
|
7684
|
-
const COMPONENTS$
|
|
7898
|
+
const COMPONENTS$1 = [
|
|
7685
7899
|
ChatMessageComponent,
|
|
7686
7900
|
LiveChatMessageComponent,
|
|
7687
7901
|
ChatViewComponent,
|
|
@@ -7691,7 +7905,7 @@ class ChatModule {
|
|
|
7691
7905
|
}
|
|
7692
7906
|
ChatModule.decorators = [
|
|
7693
7907
|
{ type: NgModule, args: [{
|
|
7694
|
-
declarations: COMPONENTS$
|
|
7908
|
+
declarations: COMPONENTS$1,
|
|
7695
7909
|
imports: [
|
|
7696
7910
|
CommonModule,
|
|
7697
7911
|
FormsModule,
|
|
@@ -7699,220 +7913,7 @@ ChatModule.decorators = [
|
|
|
7699
7913
|
MatButtonModule,
|
|
7700
7914
|
EmojiModule
|
|
7701
7915
|
],
|
|
7702
|
-
exports: COMPONENTS$
|
|
7703
|
-
},] }
|
|
7704
|
-
];
|
|
7705
|
-
|
|
7706
|
-
/**
|
|
7707
|
-
* Unified chat and comments component
|
|
7708
|
-
*/
|
|
7709
|
-
class BantaComponent {
|
|
7710
|
-
constructor(backend, matDialog) {
|
|
7711
|
-
this.backend = backend;
|
|
7712
|
-
this.matDialog = matDialog;
|
|
7713
|
-
this._subs = new Subscription();
|
|
7714
|
-
this.auxOpen = false;
|
|
7715
|
-
this.auxTitle = 'Notifications';
|
|
7716
|
-
this.auxMode = 'notifications';
|
|
7717
|
-
this.mobileFocus = null;
|
|
7718
|
-
this.newNotifications = false;
|
|
7719
|
-
this.chatLabel = 'Chat';
|
|
7720
|
-
this.commentsLabel = 'Comments';
|
|
7721
|
-
this._signInSelected = new Subject();
|
|
7722
|
-
this.pointOpen = null;
|
|
7723
|
-
this.pointSubChat = null;
|
|
7724
|
-
this.newPointSubMessage = {};
|
|
7725
|
-
this.genericAvatarUrl = 'https://gravatar.com/avatar/915c804e0be607a4ad766ddadea5c48a?s=512&d=https://codepen.io/assets/avatars/user-avatar-512x512-6e240cf350d2f1cc07c2bed234c3a3bb5f1b237023c204c782622e80d6b212ba.png';
|
|
7726
|
-
}
|
|
7727
|
-
ngOnInit() {
|
|
7728
|
-
this._subs.add(this.backend.userChanged.subscribe(user => this.currentUser = user));
|
|
7729
|
-
this._subs.add(this.backend.notificationsChanged.subscribe(notifs => this.notifications = notifs));
|
|
7730
|
-
this._subs.add(this.backend.newNotification.subscribe(notif => {
|
|
7731
|
-
this.newNotifications = true;
|
|
7732
|
-
}));
|
|
7733
|
-
}
|
|
7734
|
-
sendPointSubMessage() {
|
|
7735
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7736
|
-
let text = (this.newPointSubMessage.message || '').trim();
|
|
7737
|
-
this.newPointSubMessage.message = '';
|
|
7738
|
-
if (text === '')
|
|
7739
|
-
return;
|
|
7740
|
-
let message = {
|
|
7741
|
-
user: null,
|
|
7742
|
-
sentAt: Date.now(),
|
|
7743
|
-
likes: 0,
|
|
7744
|
-
message: text
|
|
7745
|
-
};
|
|
7746
|
-
try {
|
|
7747
|
-
yield this.pointSubChat.send(message);
|
|
7748
|
-
}
|
|
7749
|
-
catch (e) {
|
|
7750
|
-
console.error(`Failed to send point sub-message:`);
|
|
7751
|
-
console.error(e);
|
|
7752
|
-
}
|
|
7753
|
-
});
|
|
7754
|
-
}
|
|
7755
|
-
goToMessage(message) {
|
|
7756
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7757
|
-
let targetMessage = message;
|
|
7758
|
-
if (message.parentMessageId) {
|
|
7759
|
-
// jump to the parent message thread...
|
|
7760
|
-
let parentMessage;
|
|
7761
|
-
try {
|
|
7762
|
-
parentMessage = yield this.backend.getMessage(message.topicId, message.parentMessageId);
|
|
7763
|
-
}
|
|
7764
|
-
catch (e) {
|
|
7765
|
-
console.error(`Received exception while fetching parent message:`);
|
|
7766
|
-
console.error(e);
|
|
7767
|
-
}
|
|
7768
|
-
if (!parentMessage) {
|
|
7769
|
-
console.error(`Failed to look up parent message ${message.topicId}/${message.parentMessageId}`);
|
|
7770
|
-
console.error(`Original message was:`);
|
|
7771
|
-
console.dir(targetMessage);
|
|
7772
|
-
return;
|
|
7773
|
-
}
|
|
7774
|
-
message = parentMessage;
|
|
7775
|
-
}
|
|
7776
|
-
let viewType = this.getViewType(message);
|
|
7777
|
-
if (viewType === 'comment') {
|
|
7778
|
-
if (this.pointSubChat) {
|
|
7779
|
-
if (this.pointSubChat.close)
|
|
7780
|
-
this.pointSubChat.close();
|
|
7781
|
-
this.pointSubChat = null;
|
|
7782
|
-
}
|
|
7783
|
-
this.mobileFocus = 'points';
|
|
7784
|
-
this.pointOpen = message;
|
|
7785
|
-
this.pointSubChat = yield this.backend.getSourceForThread(message.topicId, message.id);
|
|
7786
|
-
this.pointOpen = yield this.backend.refreshMessage(message);
|
|
7787
|
-
this.newPointSubMessage = {};
|
|
7788
|
-
}
|
|
7789
|
-
else if (viewType === 'chat') {
|
|
7790
|
-
this.mobileFocus = 'firehose';
|
|
7791
|
-
this.firehose.jumpToMessage(message);
|
|
7792
|
-
}
|
|
7793
|
-
});
|
|
7794
|
-
}
|
|
7795
|
-
pointUnfocus() {
|
|
7796
|
-
this.pointOpen = null;
|
|
7797
|
-
if (this.pointSubChat) {
|
|
7798
|
-
if (this.pointSubChat.close)
|
|
7799
|
-
this.pointSubChat.close();
|
|
7800
|
-
this.pointSubChat = null;
|
|
7801
|
-
}
|
|
7802
|
-
}
|
|
7803
|
-
ngOnDestroy() {
|
|
7804
|
-
this._subs.unsubscribe();
|
|
7805
|
-
}
|
|
7806
|
-
showAux(title, mode) {
|
|
7807
|
-
this.auxOpen = true;
|
|
7808
|
-
this.auxTitle = title;
|
|
7809
|
-
this.auxMode = mode;
|
|
7810
|
-
this.mobileFocus = 'aux';
|
|
7811
|
-
}
|
|
7812
|
-
showNotifications() {
|
|
7813
|
-
this.showAux('Notifications', 'notifications');
|
|
7814
|
-
}
|
|
7815
|
-
get topicID() {
|
|
7816
|
-
return this._topicID;
|
|
7817
|
-
}
|
|
7818
|
-
set topicID(value) {
|
|
7819
|
-
this._topicID = value;
|
|
7820
|
-
this.close();
|
|
7821
|
-
this.connectToTopic(this._topicID);
|
|
7822
|
-
}
|
|
7823
|
-
connectToTopic(id) {
|
|
7824
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7825
|
-
this.firehoseSource = yield this.backend.getSourceForTopic(`${id}_firehose`);
|
|
7826
|
-
this.pointSource = yield this.backend.getSourceForTopic(`${id}_thepoint`);
|
|
7827
|
-
});
|
|
7828
|
-
}
|
|
7829
|
-
get signInSelected() {
|
|
7830
|
-
return this._signInSelected;
|
|
7831
|
-
}
|
|
7832
|
-
showSignIn() {
|
|
7833
|
-
this._signInSelected.next();
|
|
7834
|
-
}
|
|
7835
|
-
close() {
|
|
7836
|
-
if (this.firehoseSource) {
|
|
7837
|
-
if (this.firehoseSource.close)
|
|
7838
|
-
this.firehoseSource.close();
|
|
7839
|
-
this.firehoseSource = null;
|
|
7840
|
-
}
|
|
7841
|
-
if (this.pointSource) {
|
|
7842
|
-
if (this.pointSource.close)
|
|
7843
|
-
this.pointSource.close();
|
|
7844
|
-
this.pointSource = null;
|
|
7845
|
-
}
|
|
7846
|
-
}
|
|
7847
|
-
get hasPoint() {
|
|
7848
|
-
return this.pointOpen != null;
|
|
7849
|
-
}
|
|
7850
|
-
closeAux() {
|
|
7851
|
-
this.auxOpen = false;
|
|
7852
|
-
this.mobileFocus = 'firehose';
|
|
7853
|
-
}
|
|
7854
|
-
getViewType(message) {
|
|
7855
|
-
if (message.topicId.endsWith('_firehose'))
|
|
7856
|
-
return 'chat';
|
|
7857
|
-
else if (message.topicId.endsWith('_thepoint'))
|
|
7858
|
-
return 'comment';
|
|
7859
|
-
return 'comment';
|
|
7860
|
-
}
|
|
7861
|
-
upvoteMessage(message) {
|
|
7862
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
7863
|
-
// TODO
|
|
7864
|
-
//await this.backend.likeMessage(message.id);
|
|
7865
|
-
});
|
|
7866
|
-
}
|
|
7867
|
-
showProfile(user) {
|
|
7868
|
-
this.profileUser = user;
|
|
7869
|
-
this.showAux(`@${user.username}'s Profile`, 'profile');
|
|
7870
|
-
}
|
|
7871
|
-
sendReport(message) {
|
|
7872
|
-
this.auxOpen = false;
|
|
7873
|
-
alert('would send report');
|
|
7874
|
-
}
|
|
7875
|
-
reportMessage(message) {
|
|
7876
|
-
this.reportedMessage = message;
|
|
7877
|
-
this.showAux(`Report message from @${message.user.username}`, 'report');
|
|
7878
|
-
}
|
|
7879
|
-
}
|
|
7880
|
-
BantaComponent.decorators = [
|
|
7881
|
-
{ type: Component, args: [{
|
|
7882
|
-
selector: `banta`,
|
|
7883
|
-
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 \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>",
|
|
7884
|
-
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}"]
|
|
7885
|
-
},] }
|
|
7886
|
-
];
|
|
7887
|
-
BantaComponent.ctorParameters = () => [
|
|
7888
|
-
{ type: ChatBackendBase },
|
|
7889
|
-
{ type: MatDialog }
|
|
7890
|
-
];
|
|
7891
|
-
BantaComponent.propDecorators = {
|
|
7892
|
-
firehose: [{ type: ViewChild, args: ['firehose', { static: true },] }],
|
|
7893
|
-
topicID: [{ type: Input }],
|
|
7894
|
-
chatLabel: [{ type: Input }],
|
|
7895
|
-
commentsLabel: [{ type: Input }],
|
|
7896
|
-
signInSelected: [{ type: Output }],
|
|
7897
|
-
hasPoint: [{ type: HostBinding, args: ['class.point-focus',] }]
|
|
7898
|
-
};
|
|
7899
|
-
|
|
7900
|
-
class BantaLogoComponent {
|
|
7901
|
-
}
|
|
7902
|
-
BantaLogoComponent.decorators = [
|
|
7903
|
-
{ type: Component, args: [{
|
|
7904
|
-
selector: 'banta-logo',
|
|
7905
|
-
template: `banta`,
|
|
7906
|
-
styles: [`
|
|
7907
|
-
:host {
|
|
7908
|
-
font-family: 'Odibee Sans', sans-serif;
|
|
7909
|
-
font-size: 40pt;
|
|
7910
|
-
}
|
|
7911
|
-
|
|
7912
|
-
:host.small {
|
|
7913
|
-
font-size: 30pt;
|
|
7914
|
-
}
|
|
7915
|
-
`]
|
|
7916
|
+
exports: COMPONENTS$1
|
|
7916
7917
|
},] }
|
|
7917
7918
|
];
|
|
7918
7919
|
|
|
@@ -8136,7 +8137,7 @@ CommentComponent.decorators = [
|
|
|
8136
8137
|
{ type: Component, args: [{
|
|
8137
8138
|
selector: 'banta-comment',
|
|
8138
8139
|
template: "\r\n<mat-menu #pointItemMenu=\"matMenu\">\r\n <button mat-menu-item (click)=\"share()\">\r\n <mat-icon>share</mat-icon>\r\n Share\r\n </button>\r\n <button *ngIf=\"!mine\" mat-menu-item (click)=\"report()\">\r\n <mat-icon>warning</mat-icon>\r\n Report\r\n </button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canEdit\" mat-menu-item (click)=\"startEdit()\">\r\n <mat-icon>edit</mat-icon>\r\n Edit\r\n </button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canDelete\" mat-menu-item (click)=\"delete()\">\r\n <mat-icon>delete</mat-icon>\r\n Delete\r\n </button>\r\n\r\n <button *ngFor=\"let menuItem of customMenuItems\" mat-menu-item (click)=\"menuItem.action(message)\">\r\n <mat-icon>{{menuItem.icon}}</mat-icon>\r\n {{menuItem.label}}\r\n </button>\r\n\r\n</mat-menu>\r\n\r\n<div class=\"message-content\">\r\n <div class=\"user\">\r\n <div class=\"user-1\">\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 <div class=\"user-identity\">\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>\r\n <div class=\"user-2\">\r\n <span class=\"user-tag\" *ngIf=\"message.user.tag\">{{message.user.tag}}</span>\r\n <banta-timestamp [value]=\"message.sentAt\"></banta-timestamp>\r\n <span class=\"spacer\"></span>\r\n </div>\r\n </div>\r\n <div class=\"content\" *ngIf=\"!editing\">\r\n <span class=\"banta-message-content\" [innerHTML]=\"message.message | mentionLinker: message.mentionLinks | markdownToHtml\"></span>\r\n <banta-attachments \r\n [attachments]=\"message.attachments\"\r\n (loaded)=\"markAttachmentsLoaded()\"\r\n ></banta-attachments>\r\n <ul class=\"message-facts\">\r\n <li *ngIf=\"message.edits?.length > 0\">(Edited)</li>\r\n </ul>\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\" [maxlength]=\"maxLength\"></textarea>\r\n </mat-form-field>\r\n </div>\r\n <button mat-raised-button (click)=\"saveEdit()\">Save</button> \r\n <button mat-button (click)=\"endEditing()\">Cancel</button>\r\n </div>\r\n\r\n\r\n <div class=\"actions\">\r\n <div class=\"spacer\"></div>\r\n <div class=\"counted-action\" *ngIf=\"showReplyAction\">\r\n <button mat-button [matTooltip]=\"replyCount > 0 ? 'Replies' : 'Reply'\" matTooltipPosition=\"below\" (click)=\"select()\">\r\n <mat-icon [inline]=\"true\">comment</mat-icon>\r\n <span class=\"count-indicator\">\r\n {{replyCount > 0 ? 'Replies' : 'Reply'}}\r\n {{replyCount > 0 ? '(' + replyCount + ')' : ''}}\r\n </span>\r\n </button>\r\n </div>\r\n <div class=\"counted-action\" [class.active]=\"message.userState?.liked\">\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-button \r\n [matTooltip]=\"permissions?.canLike ? upvoting ? 'Please wait...' : 'Like' : permissions?.canLikeErrorMessage\" \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 <span class=\"count-indicator\" *ngIf=\"message.likes > 0\">\r\n {{message.likes}}\r\n </span>\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",
|
|
8139
|
-
styles: ["
|
|
8140
|
+
styles: ["@keyframes comment-appear{0%{transform:translate(6em)}to{transform:translate(0)}}:host{display:flex;flex-direction:column;position:relative;padding:.5em;visibility:hidden}:host.new{visibility:visible;animation-name:comment-appear;animation-duration:.25s;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 .message-content .attachments-row{margin-top:15px;display:flex;grid-gap:10px;gap:10px}:host .message-content .attachments-row img{border-radius:10px;width:300px;max-width:100%;max-height:20em;-o-object-fit:cover;object-fit:cover}:host.abbreviated .message-content .content{text-overflow:ellipsis;overflow-y:hidden}:host .actions{display:flex;padding-right:10px;margin-left:60px;align-items:center}:host .actions button{color:#666;flex-shrink:0}banta-timestamp{color:#666;font-size:10pt;flex-shrink:0;margin-left:1em;text-align:right}.user{position:relative;margin:1em 0 0;display:flex;align-items:center;flex-wrap:wrap}.user .user-1,.user .user-2{display:flex;flex-wrap:nowrap;align-items:center;min-width:0}.user .user-2{margin:1em 0}.user .user-identity{display:flex;flex-direction:column;min-width:0}.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:-moz-fit-content;width:fit-content;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex-shrink:1;flex-grow:0;min-width:0}.user .display-name.username.username.username,.user .username.username.username.username{color:#666}.avatar{height:48px;width:48px;background-position:center;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 button,.counted-action.active .count-indicator{color:#00a5ff}.counted-action button .count-indicator{margin-left:.5em}.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}.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}ul.message-facts li{margin-top:.5em}ul.message-facts li:first-child{border-left:1px solid transparent;margin-left:0;padding-left:0}@media (max-width: 400px){.avatar{height:32px;width:32px}:host .actions{margin-left:0;margin-top:.5em}:host .message-content .content{margin-left:44px;margin-right:.5em}}:host-context(.banta-mobile) .avatar{height:32px;width:32px}:host-context(.banta-mobile) :host .actions{margin-left:0;margin-top:.5em}:host-context(.banta-mobile) :host .message-content .content{margin-left:44px;margin-right:.5em}.card-attachment a{display:flex;align-items:flex-start;grid-gap:1em;gap:1em;width:100%;border:1px solid #666;border-radius:4px;padding:1em;box-sizing:border-box;background-color:#191919}.card-attachment a img{width:300px;aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover;border-radius:10px}.card-attachment a h1{margin:0;font-size:30px}\n"]
|
|
8140
8141
|
},] }
|
|
8141
8142
|
];
|
|
8142
8143
|
CommentComponent.ctorParameters = () => [
|
|
@@ -8496,7 +8497,7 @@ CommentViewComponent.decorators = [
|
|
|
8496
8497
|
{ type: Component, args: [{
|
|
8497
8498
|
selector: 'banta-comment-view',
|
|
8498
8499
|
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]=\"!newestLast && (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 <a mat-button class=\"nav\" [class.visible]=\"newestLast && hasMore && !isLoadingMore\" href=\"javascript:;\" (click)=\"showMore()\">Show earlier</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 [customMenuItems]=\"customMenuItems\"\r\n [message]=\"message\"\r\n [mine]=\"currentUser?.id === message.user?.id\"\r\n [permissions]=\"source?.permissions\"\r\n [showReplyAction]=\"allowReplies\"\r\n [editing]=\"message.transientState.editing\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (click)=\"isViewingMore = true\"\r\n (editStarted)=\"startEditing(message)\"\r\n (deleted)=\"deleteMessage(message)\"\r\n (editEnded)=\"message.transientState.editing = false\"\r\n (edited)=\"saveEdit(message, $event)\"\r\n (userSelected)=\"selectMessageUser(message)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(message)\"\r\n (unliked)=\"unlikeMessage(message)\"\r\n (reported)=\"reportMessage(message)\"\r\n (selected)=\"selectMessage(message)\"\r\n (shared)=\"sharedMessage($event)\"\r\n ></banta-comment>\r\n <div class=\"inline-replies-container\" *ngIf=\"selectedMessage === message\">\r\n <ng-content select=\".inline-replies\"></ng-content>\r\n </div>\r\n </ng-container>\r\n\r\n <a mat-button class=\"nav\" [class.visible]=\"newestLast && (isViewingMore || customSortEnabled)\" href=\"javascript:;\" (click)=\"showNew()\">\r\n <mat-icon>file_download</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 <a mat-button class=\"nav\" [class.visible]=\"!newestLast && 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]):not(.inline-replies)\"></ng-content>\r\n</div>\r\n",
|
|
8499
|
-
styles: [":host{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition
|
|
8500
|
+
styles: [":host{flex-grow:1;display:flex;flex-direction:column;opacity:1;transition:.2s opacity ease-in}.message-container{flex-grow:1;overflow-x:hidden;color:#111;background:white;padding:.5em 1em 3em .5em;opacity:1;transition:.5s opacity 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:#111111}.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:.4s opacity ease-in-out;pointer-events:none;border-radius:2em;background:#222}a.nav.visible{opacity:1;pointer-events:initial}.loading-more{padding:2em;text-align:center;margin:0 auto;width:-moz-fit-content;width:fit-content}@media (max-width: 400px){.message-container{padding:0 0 3em}}\n"]
|
|
8500
8501
|
},] }
|
|
8501
8502
|
];
|
|
8502
8503
|
CommentViewComponent.ctorParameters = () => [
|
|
@@ -9156,7 +9157,7 @@ BantaCommentsComponent.decorators = [
|
|
|
9156
9157
|
{ type: Component, args: [{
|
|
9157
9158
|
selector: 'banta-comments',
|
|
9158
9159
|
template: "<ng-container *ngIf=\"loading\">\r\n <div class=\"loading-screen\" [class.visible]=\"showLoadingScreen\">\r\n <h1>Loading...</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 && !useInlineReplies\">\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 [maxLength]=\"maxCommentLength\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (editStarted)=\"startEditing(selectedMessage)\"\r\n (editEnded)=\"selectedMessage.transientState.editing = false\"\r\n (edited)=\"saveEdit(selectedMessage, $event)\"\r\n (userSelected)=\"selectMessageUser(selectedMessage)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(source, selectedMessage)\"\r\n (unliked)=\"unlikeMessage(source, selectedMessage)\"\r\n (reported)=\"reportMessage(selectedMessage)\"\r\n (selected)=\"toggleSelectedMessage(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 class=\"replies\"\r\n #threadView\r\n [source]=\"selectedMessageThread\"\r\n [allowReplies]=\"false\"\r\n [fixedHeight]=\"false\"\r\n [showEmptyState]=\"false\"\r\n [newestLast]=\"true\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (liked)=\"likeMessage(selectedMessageThread, $event)\"\r\n (unliked)=\"unlikeMessage(selectedMessageThread, $event)\"\r\n (messageEdited)=\"editMessage(selectedMessageThread, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n [customMenuItems]=\"customMenuItems\"\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 [maxLength]=\"maxCommentLength\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [signInLabel]=\"signInLabel\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\r\n [submit]=\"sendReply\"\r\n [allowAttachments]=\"allowAttachments\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"sendReplyOptionsTemplate\"></ng-container>\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 && !useInlineReplies\">\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 [maxLength]=\"maxCommentLength\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n (signInSelected)=\"showSignIn()\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [submit]=\"sendMessage\"\r\n [allowAttachments]=\"allowAttachments\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n >\r\n \r\n </banta-comment-field>\r\n\r\n <banta-comment-sort\r\n [(sort)]=\"sortOrder\"></banta-comment-sort>\r\n\r\n <div class=\"loading-comment\" *ngIf=\"loadingSharedComment\">\r\n <h1>Loading the comment you linked to...</h1>\r\n <mat-spinner [diameter]=\"300\" [strokeWidth]=\"2\"></mat-spinner>\r\n <p>\r\n If there are a lot of comments, this might take awhile!\r\n </p>\r\n </div>\r\n <div class=\"loading-comment\" *ngIf=\"!loadingSharedComment && lastSharedCommentID\">\r\n <ng-container *ngIf=\"sharedCommentMissing\">\r\n\r\n <a class=\"close\" mat-icon-button matTooltip=\"Close this notice\" href=\"javascript:;\" (click)=\"lastSharedCommentID = null\">\r\n <mat-icon>close</mat-icon>\r\n </a>\r\n\r\n <h1>\r\n <mat-icon>error</mat-icon>\r\n Uh oh!\r\n </h1>\r\n\r\n <p>The comment you linked to can't be found! It may have been removed.</p>\r\n </ng-container>\r\n <ng-container *ngIf=\"!sharedCommentMissing\">\r\n <a class=\"close\" mat-icon-button matTooltip=\"Close this notice\" href=\"javascript:;\" (click)=\"lastSharedCommentID = null\">\r\n <mat-icon>close</mat-icon>\r\n </a>\r\n <button mat-button (click)=\"navigateToSharedComment(lastSharedCommentID)\">\r\n <mat-icon>move_down</mat-icon> Jump to shared comment\r\n </button>\r\n </ng-container>\r\n </div>\r\n\r\n <banta-comment-view\r\n #commentView\r\n [class.faded]=\"selectedMessage && !useInlineReplies\"\r\n [source]=\"source\"\r\n [fixedHeight]=\"fixedHeight\"\r\n [maxMessages]=\"maxMessages\"\r\n [maxVisibleMessages]=\"maxVisibleMessages\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n [customMenuItems]=\"customMenuItems\"\r\n (userSelected)=\"selectMessageUser($event)\"\r\n (sortOrderChanged)=\"sortOrder = $event\"\r\n (selected)=\"toggleSelectedMessage($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 [selectedMessage]=\"selectedMessage\"\r\n (deleted)=\"deleteMessage($event)\"\r\n >\r\n <div class=\"inline-replies\">\r\n <div class=\"focused\" [class.visible]=\"selectedMessageVisible\" *ngIf=\"selectedMessage\">\r\n <div class=\"replies\">\r\n \r\n <ng-container *ngIf=\"!selectedMessageThread\">\r\n <div class=\"loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n </ng-container>\r\n \r\n <ng-container *ngIf=\"selectedMessageThread\">\r\n <banta-comment-view\r\n [source]=\"selectedMessageThread\"\r\n [allowReplies]=\"false\"\r\n [fixedHeight]=\"false\"\r\n [showEmptyState]=\"false\"\r\n [newestLast]=\"true\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (liked)=\"likeMessage(selectedMessageThread, $event)\"\r\n (unliked)=\"unlikeMessage(selectedMessageThread, $event)\"\r\n (messageEdited)=\"editMessage(selectedMessageThread, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n \r\n <banta-comment-field\r\n [sendLabel]=\"replyLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n (signInSelected)=\"showSignIn()\"\r\n [maxLength]=\"maxCommentLength\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n [source]=\"selectedMessageThread\"\r\n [canComment]=\"source?.permissions?.canPost\"\r\n [signInLabel]=\"signInLabel\"\r\n [permissionDeniedLabel]=\"source?.permissions?.canPostErrorMessage || permissionDeniedLabel\"\r\n (permissionDeniedError)=\"handlePermissionDenied($event)\"\r\n [shouldInterceptMessageSend]=\"shouldInterceptMessageSend\"\r\n [user]=\"user\"\r\n [label]=\"postReplyLabel\"\r\n [submit]=\"sendReply\"\r\n [allowAttachments]=\"allowAttachments\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"sendReplyOptionsTemplate\"></ng-container>\r\n </banta-comment-field>\r\n </ng-container>\r\n </div>\r\n </div> \r\n </div>\r\n </banta-comment-view>\r\n </div>\r\n</ng-container>\r\n",
|
|
9159
|
-
styles: [":host{display:flex;flex-direction:column}
|
|
9160
|
+
styles: [":host{display:flex;flex-direction:column}@keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}.focused{animation-name:select-comment;animation-duration:.4s;animation-fill-mode:both}.focused .replies{margin-top:1em;margin-left:2em;border-left:2px solid #333;padding-left:2em}banta-comment-view{opacity:1;transition:.4s opacity ease-in-out}banta-comment-view.faded{opacity:.25}.loading{display:block;width:-moz-fit-content;width:fit-content;margin:0 auto;min-height:16em}.main.hidden{display:none}.loading-screen{text-align:center;opacity:0;transition:.25s ease-in-out opacity}.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:.25s ease-in-out opacity;width:500px;max-width:100%;margin:0 auto}.loading-screen .loading-message.visible{opacity:1}banta-comment-sort{margin:0 0 0 auto;width:-moz-fit-content;width:fit-content;display:block}.inline-replies{margin-left:4em}@media (max-width: 500px){.focused .replies{margin-left:0}.inline-replies{margin-left:1em}.focused .replies{padding-left:.5em}banta-comment-sort{margin:0;width:100%}}:host-context(.banta-mobile) .focused .replies{margin-left:0}:host-context(.banta-mobile) .inline-replies{margin-left:1em}:host-context(.banta-mobile) .focused .replies{padding-left:.5em}:host-context(.banta-mobile) banta-comment-sort{margin:0;width:100%}.loading-comment{z-index:100;border:1px solid #333;background:black;color:#fff;padding:1em;border-radius:4px;text-align:center;position:relative}.loading-comment a.close{position:absolute;top:1em;right:1em}.loading-comment h1{font-weight:100;text-align:center}.loading-comment mat-spinner{margin:0 auto}\n"]
|
|
9160
9161
|
},] }
|
|
9161
9162
|
];
|
|
9162
9163
|
BantaCommentsComponent.ctorParameters = () => [
|
|
@@ -9584,7 +9585,7 @@ CommentFieldComponent.decorators = [
|
|
|
9584
9585
|
{ type: Component, args: [{
|
|
9585
9586
|
selector: 'banta-comment-field',
|
|
9586
9587
|
template: "<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n <div class=\"avatar-container\">\r\n <a href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"showEditAvatar()\"\r\n [style.background-image]=\"'url(' + userAvatarUrl + ')'\"\r\n ></a>\r\n </div>\r\n <div class=\"text-container\">\r\n <div class=\"field-container\">\r\n <div class=\"field-row\">\r\n <mat-form-field class=\"message-field\" appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>{{label}}</mat-label>\r\n <textarea\r\n #textarea\r\n name=\"message\"\r\n attachmentScraper\r\n [(attachments)]=\"chatMessageAttachments\"\r\n [placeholder]=\"placeholder\"\r\n matInput\r\n cdkTextareaAutosize\r\n [maxlength]=\"maxLength\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (blur)=\"onBlur()\"\r\n [disabled]=\"sending\"\r\n [(ngModel)]=\"text\"\r\n autocomplete=\"off\"\r\n ></textarea>\r\n </mat-form-field>\r\n <div class=\"options-line\">\r\n <mat-spinner *ngIf=\"sending\" class=\"icon loading\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n <div *ngIf=\"sendError\" class=\"error-message\" [class.expanded]=\"expandError\" [matTooltip]=\"sendError.message\" (click)=\"alertError()\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <div *ngIf=\"!sendError && transientMessage\" class=\"transient-message\" [class.expanded]=\"true\" [matTooltip]=\"transientMessage\" (click)=\"alertError()\">\r\n <mat-spinner [inline]=\"true\" [diameter]=\"15\"></mat-spinner>\r\n {{transientMessage}}\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div class=\"custom\">\r\n <ng-content></ng-content>\r\n </div>\r\n <banta-attachment-button \r\n *ngIf=\"allowAttachments\"\r\n (addedAttachment)=\"addedAttachment($event)\"\r\n (attachmentError)=\"attachmentError($event)\"\r\n ></banta-attachment-button>\r\n <emoji-selector-button (selected)=\"insertEmoji($event)\"></emoji-selector-button>\r\n </div>\r\n \r\n </div>\r\n <div #autocompleteContainer class=\"autocomplete-container\">\r\n <div #autocomplete class=\"autocomplete\" [class.visible]=\"autocompleteVisible\">\r\n\r\n <div>\r\n <strong>{{completionPrefix}}</strong>...\r\n </div>\r\n <a\r\n mat-button\r\n *ngFor=\"let option of autocompleteOptions; index as index\"\r\n (click)=\"activateAutoComplete(option)\"\r\n [class.active]=\"autoCompleteSelected === index\"\r\n >\r\n {{option.label}}\r\n </a>\r\n </div>\r\n </div>\r\n\r\n <banta-attachments \r\n [attachments]=\"chatMessageAttachments\"\r\n [editing]=\"true\"\r\n (remove)=\"removeAttachment($event)\"\r\n ></banta-attachments>\r\n </div>\r\n </div>\r\n <div class=\"actions\">\r\n <ng-container *ngIf=\"!user\">\r\n <button\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"showSignIn()\"\r\n >{{signInLabel}}</button>\r\n </ng-container>\r\n <ng-container *ngIf=\"user\">\r\n <button\r\n mat-raised-button\r\n class=\"send\"\r\n color=\"primary\"\r\n [disabled]=\"!sendButtonEnabled\"\r\n >\r\n <ng-container *ngIf=\"canComment\">\r\n <mat-icon *ngIf=\"!sending\">chevron_right</mat-icon>\r\n <mat-spinner *ngIf=\"sending\" class=\"icon\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n </ng-container>\r\n <span class=\"label\">\r\n <ng-container *ngIf=\"!canComment\">\r\n {{permissionDeniedLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"canComment\">\r\n <ng-container *ngIf=\"!sending\">\r\n {{sendLabel}}\r\n </ng-container>\r\n <ng-container *ngIf=\"sending\">\r\n {{sendingLabel}}\r\n </ng-container>\r\n </ng-container>\r\n </span>\r\n </button>\r\n </ng-container>\r\n </div>\r\n</form>",
|
|
9587
|
-
styles: ["
|
|
9588
|
+
styles: ["@keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}:host{margin:0 2em 0 0;display:block;animation-name:comment-field-appear;animation-duration:.8s;animation-delay:.4s;animation-fill-mode:both;position:relative;z-index:20}.avatar-container{width:calc(48px + 1.75em);display:flex;justify-content:flex-end;flex-shrink:0}.avatar-container .avatar{width:48px;height:48px;background:black;border-radius:100%;background-size:cover;background-repeat:no-repeat;background-position:center;margin-top:.75em;margin-right:.75em}form{display:flex;padding:.5em;align-items:center}form .text-container{position:relative;display:flex;flex-grow:1;min-width:0}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .options-line{display:flex;align-items:center}form .text-container .options-line>*{flex-shrink:0}form .text-container .options-line .transient-message{display:flex;flex-direction:row;align-items:center;grid-gap:.5em;gap:.5em}form .text-container .options-line .error-message{left:.5em;bottom:.5em;color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:2s max-width ease-in-out;text-overflow:ellipsis;overflow:hidden;flex-shrink:1}form .text-container .options-line .error-message.expanded,form .text-container .options-line .error-message:hover{max-width:100%}form .text-container .options-line .error-message mat-icon{vertical-align:middle}form input[type=text]{background:black;color:#fff;border:1px solid #333;width:100%;height:1em}form .actions{margin-left:1em;flex-shrink:0}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start;min-width:0}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column;min-width:0}form.new-message mat-form-field{width:100%}form.new-message mat-form-field ::ng-deep .mat-form-field-wrapper{padding-bottom:0}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{width:calc(100% - 2em);position:relative;pointer-events:none;top:-2em}.autocomplete{visibility:hidden;pointer-events:none;position:absolute;background:#333;padding:.5em;display:flex;flex-direction:column;z-index:100}.autocomplete.visible{visibility:visible;pointer-events:initial}.autocomplete a{width:100%;text-align:left}.autocomplete a.active{background:#555}.image-attachments-container{display:flex;grid-gap:20px;gap:20px}.image-attachments-container .image-attachment{width:300px;position:relative;text-align:center}.image-attachments-container .image-attachment.with-border{outline:1px solid #333;padding:1em 0}.image-attachments-container .image-attachment mat-spinner{display:block;margin:0 auto .5em;width:-moz-fit-content;width:fit-content}.image-attachments-container .image-attachment mat-icon.error{display:block;font-size:48px;width:48px;height:48px;margin:0 auto .5em}.image-attachments-container .image-attachment .error{color:#b76363}.image-attachments-container .image-attachment img{width:300px;border-radius:10px}.image-attachments-container .image-attachment .remove-img{position:absolute;right:10px;top:10px;margin:0}.field-row{position:relative}.card-attachment{position:relative}.card-attachment a{display:flex;align-items:flex-start;grid-gap:1em;gap:1em;width:100%;border:1px solid #666;border-radius:4px;padding:2em;box-sizing:border-box;background-color:#191919}.card-attachment a img{width:300px;aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover;border-radius:10px}.card-attachment a h1{margin:0;font-size:30px}.card-attachment .remove-img{position:absolute;right:10px;top:10px;margin:0}@media (max-width: 500px){:host{margin:0}.avatar-container{width:auto;flex-shrink:0}.avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}:host:not(.can-comment) mat-form-field.message-field{display:none}:host:not(.can-comment) .text-container{display:none}:host.can-comment button.send .label{display:none}button.send{min-width:auto;margin-top:1.5em}}:host-context(.banta-mobile) :host{margin:0}:host-context(.banta-mobile) .avatar-container{width:auto;flex-shrink:0}:host-context(.banta-mobile) .avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}:host-context(.banta-mobile) :host:not(.can-comment) mat-form-field.message-field{display:none}:host-context(.banta-mobile) :host:not(.can-comment) .text-container{display:none}:host-context(.banta-mobile) :host.can-comment button.send .label{display:none}:host-context(.banta-mobile) button.send{min-width:auto;margin-top:1.5em}\n"]
|
|
9588
9589
|
},] }
|
|
9589
9590
|
];
|
|
9590
9591
|
CommentFieldComponent.ctorParameters = () => [
|
|
@@ -9640,7 +9641,7 @@ CommentSortComponent.decorators = [
|
|
|
9640
9641
|
{ type: Component, args: [{
|
|
9641
9642
|
selector: 'banta-comment-sort',
|
|
9642
9643
|
template: "<mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>Sort by</mat-label>\r\n <mat-select [(value)]=\"sort\" >\r\n <mat-option [value]=\"commentsOrder.NEWEST\">Newest</mat-option>\r\n <mat-option [value]=\"commentsOrder.OLDEST\">Oldest</mat-option>\r\n <mat-option [value]=\"commentsOrder.LIKES\">Likes</mat-option>\r\n </mat-select>\r\n</mat-form-field>",
|
|
9643
|
-
styles: ["mat-form-field{width:100%}"]
|
|
9644
|
+
styles: ["mat-form-field{width:100%}\n"]
|
|
9644
9645
|
},] }
|
|
9645
9646
|
];
|
|
9646
9647
|
CommentSortComponent.propDecorators = {
|
|
@@ -9702,7 +9703,7 @@ AttachmentButtonComponent.decorators = [
|
|
|
9702
9703
|
{ type: Component, args: [{
|
|
9703
9704
|
selector: 'banta-attachment-button',
|
|
9704
9705
|
template: "<button matTooltip=\"Add an image or gif\" #button type=\"button\" mat-icon-button (click)=\"show()\">\r\n\t<mat-icon>image</mat-icon>\r\n</button>\r\n<input style=\"display: none;\" #fileUpload [multiple]=\"false\" (change)=\"fileChange($event)\" type=\"file\" >",
|
|
9705
|
-
styles: ["button{color:#666}"]
|
|
9706
|
+
styles: ["button{color:#666}\n"]
|
|
9706
9707
|
},] }
|
|
9707
9708
|
];
|
|
9708
9709
|
AttachmentButtonComponent.ctorParameters = () => [
|
|
@@ -9819,7 +9820,7 @@ AttachmentScraperDirective.propDecorators = {
|
|
|
9819
9820
|
attachmentsChange: [{ type: Output }]
|
|
9820
9821
|
};
|
|
9821
9822
|
|
|
9822
|
-
const COMPONENTS
|
|
9823
|
+
const COMPONENTS = [
|
|
9823
9824
|
CommentComponent,
|
|
9824
9825
|
CommentViewComponent,
|
|
9825
9826
|
BantaCommentsComponent,
|
|
@@ -9834,7 +9835,7 @@ class CommentsModule {
|
|
|
9834
9835
|
}
|
|
9835
9836
|
CommentsModule.decorators = [
|
|
9836
9837
|
{ type: NgModule, args: [{
|
|
9837
|
-
declarations: COMPONENTS
|
|
9838
|
+
declarations: COMPONENTS,
|
|
9838
9839
|
imports: [
|
|
9839
9840
|
CommonModule,
|
|
9840
9841
|
TextFieldModule,
|
|
@@ -9852,7 +9853,7 @@ CommentsModule.decorators = [
|
|
|
9852
9853
|
OverlayModule,
|
|
9853
9854
|
PortalModule
|
|
9854
9855
|
],
|
|
9855
|
-
exports: COMPONENTS
|
|
9856
|
+
exports: COMPONENTS
|
|
9856
9857
|
},] }
|
|
9857
9858
|
];
|
|
9858
9859
|
|
|
@@ -10046,16 +10047,10 @@ class ChatSource extends SocketRPC {
|
|
|
10046
10047
|
}
|
|
10047
10048
|
}
|
|
10048
10049
|
__decorate([
|
|
10049
|
-
RpcEvent()
|
|
10050
|
-
__metadata("design:type", Function),
|
|
10051
|
-
__metadata("design:paramtypes", [Object]),
|
|
10052
|
-
__metadata("design:returntype", void 0)
|
|
10050
|
+
RpcEvent()
|
|
10053
10051
|
], ChatSource.prototype, "onPermissions", null);
|
|
10054
10052
|
__decorate([
|
|
10055
|
-
RpcEvent()
|
|
10056
|
-
__metadata("design:type", Function),
|
|
10057
|
-
__metadata("design:paramtypes", [Object]),
|
|
10058
|
-
__metadata("design:returntype", void 0)
|
|
10053
|
+
RpcEvent()
|
|
10059
10054
|
], ChatSource.prototype, "onChatMessage", null);
|
|
10060
10055
|
|
|
10061
10056
|
const BANTA_SDK_OPTIONS = 'BANTA_SDK_OPTIONS';
|