@banta/sdk 4.3.3 → 4.4.2
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/banta-sdk.metadata.json +1 -1
- package/bundles/banta-sdk.umd.js +581 -27
- package/bundles/banta-sdk.umd.js.map +1 -1
- package/bundles/banta-sdk.umd.min.js +1 -1
- package/bundles/banta-sdk.umd.min.js.map +1 -1
- package/esm2015/lib/attachment-scraper.js +2 -0
- package/esm2015/lib/banta-sdk.module.js +23 -1
- package/esm2015/lib/chat-backend-base.js +15 -1
- package/esm2015/lib/chat-backend.js +19 -1
- package/esm2015/lib/comments/banta-comments/banta-comments.component.js +1 -1
- package/esm2015/lib/comments/comment/comment.component.js +5 -12
- package/esm2015/lib/comments/comment-field/comment-field.component.js +89 -7
- package/esm2015/lib/common/attachment/attachment.component.js +81 -0
- package/esm2015/lib/common/attachments/attachments.component.js +47 -0
- package/esm2015/lib/common/common.module.js +13 -3
- package/esm2015/lib/common/index.js +4 -1
- package/esm2015/lib/common/trust-resource-url.pipe.js +21 -0
- package/esm2015/lib/giphy-attachments.js +20 -0
- package/esm2015/lib/index.js +6 -1
- package/esm2015/lib/tweet-attachments.js +16 -0
- package/esm2015/lib/url-attachments.js +46 -0
- package/esm2015/lib/youtube-attachments.js +25 -0
- package/fesm2015/banta-sdk.js +395 -22
- package/fesm2015/banta-sdk.js.map +1 -1
- package/lib/attachment-scraper.d.ts +15 -0
- package/lib/banta-sdk.module.d.ts +2 -0
- package/lib/chat-backend-base.d.ts +10 -1
- package/lib/chat-backend.d.ts +2 -1
- package/lib/comments/comment/comment.component.d.ts +1 -4
- package/lib/comments/comment-field/comment-field.component.d.ts +11 -2
- package/lib/common/attachment/attachment.component.d.ts +22 -0
- package/lib/common/attachments/attachments.component.d.ts +15 -0
- package/lib/common/index.d.ts +3 -0
- package/lib/common/trust-resource-url.pipe.d.ts +7 -0
- package/lib/giphy-attachments.d.ts +5 -0
- package/lib/index.d.ts +5 -0
- package/lib/tweet-attachments.d.ts +5 -0
- package/lib/url-attachments.d.ts +11 -0
- package/lib/youtube-attachments.d.ts +5 -0
- package/package.json +1 -1
package/fesm2015/banta-sdk.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Observable, Subject, BehaviorSubject, Subscription } from 'rxjs';
|
|
2
2
|
import { publish } from 'rxjs/operators';
|
|
3
|
-
import { Component, Input, ViewChild, Pipe,
|
|
3
|
+
import { Component, Input, ViewChild, Pipe, Output, HostBinding, NgModule, ElementRef, Directive, NgZone, ContentChild, TemplateRef, Injectable, Inject } from '@angular/core';
|
|
4
4
|
import { marked, Renderer } from 'marked';
|
|
5
5
|
import { sanitize } 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
|
+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
10
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
9
11
|
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
10
12
|
import { PortalModule } from '@angular/cdk/portal';
|
|
11
|
-
import { MatButtonModule } from '@angular/material/button';
|
|
12
13
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
13
14
|
import { MatInputModule } from '@angular/material/input';
|
|
14
15
|
import { FormsModule } from '@angular/forms';
|
|
@@ -18,7 +19,6 @@ import { CommentsOrder, CDNProvider, SocketRPC, RpcEvent, DurableSocket } from '
|
|
|
18
19
|
import { ActivatedRoute } from '@angular/router';
|
|
19
20
|
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
|
20
21
|
import { MatMenuModule } from '@angular/material/menu';
|
|
21
|
-
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
22
22
|
import { TextFieldModule } from '@angular/cdk/text-field';
|
|
23
23
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
24
24
|
import { MatSelectModule } from '@angular/material/select';
|
|
@@ -222,10 +222,155 @@ BantaMarkdownToHtmlPipe.ctorParameters = () => [
|
|
|
222
222
|
{ type: DomSanitizer }
|
|
223
223
|
];
|
|
224
224
|
|
|
225
|
+
class BantaTrustResourceUrlPipe {
|
|
226
|
+
constructor(sanitizer) {
|
|
227
|
+
this.sanitizer = sanitizer;
|
|
228
|
+
}
|
|
229
|
+
transform(value) {
|
|
230
|
+
if (!value)
|
|
231
|
+
return undefined;
|
|
232
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(value);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
BantaTrustResourceUrlPipe.decorators = [
|
|
236
|
+
{ type: Pipe, args: [{
|
|
237
|
+
name: 'trustResourceUrl'
|
|
238
|
+
},] }
|
|
239
|
+
];
|
|
240
|
+
BantaTrustResourceUrlPipe.ctorParameters = () => [
|
|
241
|
+
{ type: DomSanitizer }
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
class BantaAttachmentComponent {
|
|
245
|
+
constructor() {
|
|
246
|
+
this.loading = false;
|
|
247
|
+
this.editing = false;
|
|
248
|
+
this.loadingMessage = 'Please wait...';
|
|
249
|
+
this.error = false;
|
|
250
|
+
this.errorMessage = 'An error has occurred';
|
|
251
|
+
this.removed = new Subject();
|
|
252
|
+
this.activated = new Subject();
|
|
253
|
+
}
|
|
254
|
+
ngOnInit() {
|
|
255
|
+
if (typeof window !== 'undefined') {
|
|
256
|
+
setTimeout(() => {
|
|
257
|
+
if (!window['twttr'])
|
|
258
|
+
return;
|
|
259
|
+
window['twttr'].widgets.load();
|
|
260
|
+
}, 100);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
activate() {
|
|
264
|
+
this.activated.next();
|
|
265
|
+
}
|
|
266
|
+
remove() {
|
|
267
|
+
this.removed.next();
|
|
268
|
+
}
|
|
269
|
+
get isError() {
|
|
270
|
+
var _a, _b;
|
|
271
|
+
return this.error || ((_b = (_a = this.attachment) === null || _a === void 0 ? void 0 : _a.transientState) === null || _b === void 0 ? void 0 : _b.error);
|
|
272
|
+
}
|
|
273
|
+
get theErrorMessage() {
|
|
274
|
+
var _a, _b;
|
|
275
|
+
return this.errorMessage || ((_b = (_a = this.attachment) === null || _a === void 0 ? void 0 : _a.transientState) === null || _b === void 0 ? void 0 : _b.errorMessage);
|
|
276
|
+
}
|
|
277
|
+
get isLoading() {
|
|
278
|
+
var _a;
|
|
279
|
+
return this.loading || !this.attachment || ((_a = this.attachment.transientState) === null || _a === void 0 ? void 0 : _a.loading) || !this.attachment.url;
|
|
280
|
+
}
|
|
281
|
+
get isImageAttachment() {
|
|
282
|
+
if (this.attachment.type.startsWith('image/'))
|
|
283
|
+
return true;
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
get hasFrame() {
|
|
287
|
+
if (!this.attachment)
|
|
288
|
+
return false;
|
|
289
|
+
return this.attachment.type === 'iframe' || (this.attachment.type === 'card'
|
|
290
|
+
&& this.attachment.card.player);
|
|
291
|
+
}
|
|
292
|
+
get frameUrl() {
|
|
293
|
+
if (!this.attachment)
|
|
294
|
+
return undefined;
|
|
295
|
+
if (this.attachment.type === 'iframe') {
|
|
296
|
+
return this.attachment.url;
|
|
297
|
+
}
|
|
298
|
+
else if (this.attachment.type === 'card') {
|
|
299
|
+
return this.attachment.card.player;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
BantaAttachmentComponent.decorators = [
|
|
304
|
+
{ type: Component, args: [{
|
|
305
|
+
selector: 'banta-attachment',
|
|
306
|
+
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\" [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>\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=\"https://twitter.com/seldo/status/1562553608083714050?ref_src=twsrc%5Etfw\"></a>\r\n </blockquote>\r\n </ng-container>\r\n</ng-container>",
|
|
307
|
+
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:-webkit-fit-content;width:-moz-fit-content;width:fit-content}a.card{display:flex;align-items:flex-start;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 img{width:250px;aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover;border-radius:10px}a.card.has-image h1{font-size:22px}a.card h1{min-width:0;margin:0 0 .5em;font-size:26px}a.card cite{min-width:0;opacity:.75;margin-top:1em;display:block;font-size:90%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}a.card .description{min-width:0}.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:-webkit-fit-content;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}"]
|
|
308
|
+
},] }
|
|
309
|
+
];
|
|
310
|
+
BantaAttachmentComponent.ctorParameters = () => [];
|
|
311
|
+
BantaAttachmentComponent.propDecorators = {
|
|
312
|
+
attachment: [{ type: Input }],
|
|
313
|
+
loading: [{ type: Input }],
|
|
314
|
+
editing: [{ type: Input }],
|
|
315
|
+
loadingMessage: [{ type: Input }],
|
|
316
|
+
error: [{ type: Input }],
|
|
317
|
+
errorMessage: [{ type: Input }],
|
|
318
|
+
removed: [{ type: Output }],
|
|
319
|
+
activated: [{ type: Output }],
|
|
320
|
+
isLoading: [{ type: HostBinding, args: ['class.loading',] }]
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
class BantaAttachmentsComponent {
|
|
324
|
+
constructor() {
|
|
325
|
+
this.editing = false;
|
|
326
|
+
this.remove = new Subject();
|
|
327
|
+
}
|
|
328
|
+
removeAttachment(attachment) {
|
|
329
|
+
this.remove.next(attachment);
|
|
330
|
+
}
|
|
331
|
+
isImageAttachment(attachment) {
|
|
332
|
+
if (attachment.type.startsWith('image/'))
|
|
333
|
+
return true;
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
isCardAttachment(attachment) {
|
|
337
|
+
if (['card'].includes(attachment.type))
|
|
338
|
+
return true;
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
showLightbox(image) {
|
|
342
|
+
this.lightbox.open(image.url, this.attachments
|
|
343
|
+
.filter(x => x.type === 'image/png')
|
|
344
|
+
.map(x => x.url));
|
|
345
|
+
}
|
|
346
|
+
get inlineAttachments() {
|
|
347
|
+
return this.attachments.filter(x => x.type !== 'card' && (x.style === 'inline' || !x.style));
|
|
348
|
+
}
|
|
349
|
+
get blockAttachments() {
|
|
350
|
+
return this.attachments.filter(x => x.style === 'block' || x.type === 'card');
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
BantaAttachmentsComponent.decorators = [
|
|
354
|
+
{ type: Component, args: [{
|
|
355
|
+
selector: 'banta-attachments',
|
|
356
|
+
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\">\r\n <banta-attachment \r\n [attachment]=\"attachment\"\r\n [editing]=\"editing\"\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\">\r\n <banta-attachment \r\n [attachment]=\"attachment\"\r\n [editing]=\"editing\"\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>",
|
|
357
|
+
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}"]
|
|
358
|
+
},] }
|
|
359
|
+
];
|
|
360
|
+
BantaAttachmentsComponent.propDecorators = {
|
|
361
|
+
attachments: [{ type: Input }],
|
|
362
|
+
editing: [{ type: Input }],
|
|
363
|
+
lightbox: [{ type: ViewChild, args: ['lightbox',] }],
|
|
364
|
+
remove: [{ type: Output }]
|
|
365
|
+
};
|
|
366
|
+
|
|
225
367
|
const COMPONENTS = [
|
|
226
368
|
TimestampComponent,
|
|
227
369
|
LightboxComponent,
|
|
228
|
-
BantaMarkdownToHtmlPipe
|
|
370
|
+
BantaMarkdownToHtmlPipe,
|
|
371
|
+
BantaTrustResourceUrlPipe,
|
|
372
|
+
BantaAttachmentComponent,
|
|
373
|
+
BantaAttachmentsComponent
|
|
229
374
|
];
|
|
230
375
|
class BantaCommonModule {
|
|
231
376
|
}
|
|
@@ -234,7 +379,9 @@ BantaCommonModule.decorators = [
|
|
|
234
379
|
declarations: COMPONENTS,
|
|
235
380
|
imports: [
|
|
236
381
|
CommonModule,
|
|
237
|
-
MatIconModule
|
|
382
|
+
MatIconModule,
|
|
383
|
+
MatProgressSpinnerModule,
|
|
384
|
+
MatButtonModule
|
|
238
385
|
],
|
|
239
386
|
exports: COMPONENTS
|
|
240
387
|
},] }
|
|
@@ -7006,6 +7153,8 @@ ChatMessageComponent.propDecorators = {
|
|
|
7006
7153
|
class ChatBackendBase {
|
|
7007
7154
|
constructor() {
|
|
7008
7155
|
this._userChanged = new BehaviorSubject(null);
|
|
7156
|
+
this._attachmentScrapers = [];
|
|
7157
|
+
this._attachmentResolvers = [];
|
|
7009
7158
|
}
|
|
7010
7159
|
get userChanged() {
|
|
7011
7160
|
return this._userChanged;
|
|
@@ -7017,6 +7166,18 @@ class ChatBackendBase {
|
|
|
7017
7166
|
get user() {
|
|
7018
7167
|
return this._user;
|
|
7019
7168
|
}
|
|
7169
|
+
registerAttachmentScraper(scraper) {
|
|
7170
|
+
this._attachmentScrapers.push(scraper);
|
|
7171
|
+
}
|
|
7172
|
+
registerAttachmentResolver(resolver) {
|
|
7173
|
+
this._attachmentResolvers.push(resolver);
|
|
7174
|
+
}
|
|
7175
|
+
get attachmentScrapers() {
|
|
7176
|
+
return this._attachmentScrapers.slice();
|
|
7177
|
+
}
|
|
7178
|
+
get attachmentResolvers() {
|
|
7179
|
+
return this._attachmentResolvers.slice();
|
|
7180
|
+
}
|
|
7020
7181
|
}
|
|
7021
7182
|
|
|
7022
7183
|
class LiveChatMessageComponent {
|
|
@@ -7789,11 +7950,6 @@ class CommentComponent {
|
|
|
7789
7950
|
this._avatarSelected.next(user);
|
|
7790
7951
|
this.selectUser();
|
|
7791
7952
|
}
|
|
7792
|
-
showLightbox(image) {
|
|
7793
|
-
this.lightbox.open(image.url, this.message.attachments
|
|
7794
|
-
.filter(x => x.type === 'image/png')
|
|
7795
|
-
.map(x => x.url));
|
|
7796
|
-
}
|
|
7797
7953
|
avatarForUser(user) {
|
|
7798
7954
|
let url = this.genericAvatarUrl;
|
|
7799
7955
|
if (user && user.avatarUrl) {
|
|
@@ -7809,8 +7965,8 @@ class CommentComponent {
|
|
|
7809
7965
|
CommentComponent.decorators = [
|
|
7810
7966
|
{ type: Component, args: [{
|
|
7811
7967
|
selector: 'banta-comment',
|
|
7812
|
-
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</mat-menu>\r\n\r\n<div class=\"message-content\">\r\n <div class=\"user\">\r\n <a\r\n
|
|
7813
|
-
styles: ["@-webkit-keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}@keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}:host{display:flex;flex-direction:column;position:relative;padding:.5em;visibility:hidden}:host.new{visibility:visible;-webkit-animation-name:comment-appear;animation-name:comment-appear;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}:host.highlighted{background:#00223a;outline:2px solid #003277}:host.visible{visibility:visible}:host:hover{background:#eee}:host .message-content .content{margin-left:60px;margin-right:.5em}:host .message-content .attachments-row{margin-top:15px;display:flex;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,banta-timestamp{color:#666;flex-shrink:0}banta-timestamp{font-size:10pt;margin-left:1em}.user{position:relative;margin:1em 0 0;display:flex;align-items:center}.user .display-name,.user .username{z-index:1;position:relative;padding:0 0 0 1em;font-size:10pt;color:#000;margin:0 auto 0 0;display:block;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex-shrink:1;flex-grow:0}.user .display-name.username.username.username,.user .username.username.username.username{color:#666}.avatar{height:48px;width:48px;background-position:50%;background-size:cover;background-color:#333;border-radius:100%;flex-shrink:0;flex-grow:0}.counted-action{display:flex;align-items:center}.counted-action.active .count-indicator,.counted-action.active button{color:#00a5ff}.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}.user-tag,: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;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;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}"]
|
|
7968
|
+
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</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 | markdownToHtml\"></span>\r\n <banta-attachments [attachments]=\"message.attachments\"></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\"></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 [disabled]=\"!permissions?.canLike\" \r\n [matTooltip]=\"upvoting ? 'Please wait...' : 'Like'\" \r\n matTooltipPosition=\"below\" \r\n (click)=\"message.userState?.liked ? unlike() : like()\" \r\n >\r\n <mat-icon [inline]=\"true\">thumb_up</mat-icon>\r\n <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",
|
|
7969
|
+
styles: ["@-webkit-keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}@keyframes comment-appear{0%{transform:translate(100vw)}to{transform:translate(0)}}:host{display:flex;flex-direction:column;position:relative;padding:.5em;visibility:hidden}:host.new{visibility:visible;-webkit-animation-name:comment-appear;animation-name:comment-appear;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}:host.highlighted{background:#00223a;outline:2px solid #003277}:host.visible{visibility:visible}:host:hover{background:#eee}:host .message-content .content{margin-left:60px;margin-right:.5em}:host .message-content .attachments-row{margin-top:15px;display:flex;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,banta-timestamp{color:#666;flex-shrink:0}banta-timestamp{font-size:10pt;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:-webkit-fit-content;width:-moz-fit-content;width:fit-content;max-width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex-shrink:1;flex-grow:0;min-width:0}.user .display-name.username.username.username,.user .username.username.username.username{color:#666}.avatar{height:48px;width:48px;background-position:50%;background-size:cover;background-color:#333;border-radius:100%;flex-shrink:0;flex-grow:0}.counted-action{display:flex;align-items:center}.counted-action.active .count-indicator,.counted-action.active button{color:#00a5ff}.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}.user-tag,: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;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;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;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}"]
|
|
7814
7970
|
},] }
|
|
7815
7971
|
];
|
|
7816
7972
|
CommentComponent.propDecorators = {
|
|
@@ -7835,8 +7991,7 @@ CommentComponent.propDecorators = {
|
|
|
7835
7991
|
editEnded: [{ type: Output }],
|
|
7836
7992
|
shared: [{ type: Output }],
|
|
7837
7993
|
genericAvatarUrl: [{ type: Input }],
|
|
7838
|
-
commentId: [{ type: HostBinding, args: ['attr.data-comment-id',] }]
|
|
7839
|
-
lightbox: [{ type: ViewChild, args: ['lightbox',] }]
|
|
7994
|
+
commentId: [{ type: HostBinding, args: ['attr.data-comment-id',] }]
|
|
7840
7995
|
};
|
|
7841
7996
|
|
|
7842
7997
|
class CommentViewComponent {
|
|
@@ -8580,7 +8735,7 @@ BantaCommentsComponent.decorators = [
|
|
|
8580
8735
|
{ type: Component, args: [{
|
|
8581
8736
|
selector: 'banta-comments',
|
|
8582
8737
|
template: "<ng-container *ngIf=\"loading\">\r\n <div class=\"loading-screen\" [class.visible]=\"showLoadingScreen\">\r\n <h1>Loading Comments</h1>\r\n <div>\r\n <mat-spinner [diameter]=\"300\" [strokeWidth]=\"2\"></mat-spinner>\r\n </div>\r\n\r\n <p class=\"loading-message\" [class.visible]=\"loadingMessageVisible\">{{loadingMessage}}</p>\r\n </div>\r\n</ng-container>\r\n<ng-container *ngIf=\"!loading\">\r\n <div class=\"focused\" [class.visible]=\"selectedMessageVisible\" *ngIf=\"selectedMessage && !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 [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (editStarted)=\"startEditing(selectedMessage)\"\r\n (editEnded)=\"selectedMessage.transientState.editing = false\"\r\n (edited)=\"saveEdit(selectedMessage, $event)\"\r\n (userSelected)=\"selectMessageUser(selectedMessage)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (liked)=\"likeMessage(source, selectedMessage)\"\r\n (unliked)=\"unlikeMessage(source, selectedMessage)\"\r\n (reported)=\"reportMessage(selectedMessage)\"\r\n (selected)=\"selectMessage(selectedMessage)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage(selectedMessage)\"\r\n ></banta-comment>\r\n\r\n <div class=\"replies\">\r\n\r\n <ng-container *ngIf=\"!selectedMessageThread\">\r\n <div class=\"loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"selectedMessageThread\">\r\n <banta-comment-view\r\n [source]=\"selectedMessageThread\"\r\n [allowReplies]=\"false\"\r\n [fixedHeight]=\"false\"\r\n [showEmptyState]=\"false\"\r\n [newestLast]=\"true\"\r\n [genericAvatarUrl]=\"genericAvatarUrl\"\r\n (liked)=\"likeMessage(selectedMessageThread, $event)\"\r\n (unliked)=\"unlikeMessage(selectedMessageThread, $event)\"\r\n (messageEdited)=\"editMessage(selectedMessageThread, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n (deleted)=\"deleteMessage($event)\"\r\n ></banta-comment-view>\r\n\r\n <banta-comment-field\r\n [sendLabel]=\"replyLabel\"\r\n [sendingLabel]=\"sendingLabel\"\r\n [hashtags]=\"hashtags\"\r\n [participants]=\"participants\"\r\n (signInSelected)=\"showSignIn()\"\r\n (editAvatarSelected)=\"showEditAvatar()\"\r\n [source]=\"selectedMessageThread\"\r\n [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 <banta-comment-view\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 (userSelected)=\"selectMessageUser($event)\"\r\n (sortOrderChanged)=\"sortOrder = $event\"\r\n (selected)=\"selectMessage($event)\"\r\n (liked)=\"likeMessage(source, $event)\"\r\n (unliked)=\"unlikeMessage(source, $event)\"\r\n (messageEdited)=\"editMessage(source, $event.message, $event.newMessage)\"\r\n (reported)=\"reportMessage($event)\"\r\n (usernameSelected)=\"selectUsername($event)\"\r\n (avatarSelected)=\"selectAvatar($event)\"\r\n (shared)=\"shareMessage($event)\"\r\n [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",
|
|
8583
|
-
styles: [":host{display:flex;flex-direction:column}@-webkit-keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}@keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}.focused{-webkit-animation-name:select-comment;animation-name:select-comment;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.focused .replies{margin-top:1em;margin-left:2em;border-left:2px solid #333;padding-left:2em}banta-comment-view{opacity:1;transition:opacity .4s ease-in-out}banta-comment-view.faded{opacity:.25}.loading{display:block;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto;min-height:16em}.main.hidden{display:none}.loading-screen{text-align:center;opacity:0;transition:opacity .25s ease-in-out}.loading-screen.visible{opacity:1}.loading-screen h1{font-weight:100}.loading-screen mat-spinner{margin:5em auto}.loading-screen .loading-message{opacity:0;transition:opacity .25s ease-in-out;width:500px;max-width:100%;margin:0 auto}.loading-screen .loading-message.visible{opacity:1}banta-comment-sort{margin:0 0 0 auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;display:block}.inline-replies{margin-left:4em}@media (max-width:500px){.focused .replies{margin-left:0}banta-comment-sort{margin:0;width:100%}}:host-context(.banta-mobile) .focused .replies{margin-left:0}:host-context(.banta-mobile) banta-comment-sort{margin:0;width:100%}"]
|
|
8738
|
+
styles: [":host{display:flex;flex-direction:column}@-webkit-keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}@keyframes select-comment{0%{transform:scale(1.15)}to{transform:scale(1)}}.focused{-webkit-animation-name:select-comment;animation-name:select-comment;-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.focused .replies{margin-top:1em;margin-left:2em;border-left:2px solid #333;padding-left:2em}banta-comment-view{opacity:1;transition:opacity .4s ease-in-out}banta-comment-view.faded{opacity:.25}.loading{display:block;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto;min-height:16em}.main.hidden{display:none}.loading-screen{text-align:center;opacity:0;transition:opacity .25s ease-in-out}.loading-screen.visible{opacity:1}.loading-screen h1{font-weight:100}.loading-screen mat-spinner{margin:5em auto}.loading-screen .loading-message{opacity:0;transition:opacity .25s ease-in-out;width:500px;max-width:100%;margin:0 auto}.loading-screen .loading-message.visible{opacity:1}banta-comment-sort{margin:0 0 0 auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;display:block}.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%}"]
|
|
8584
8739
|
},] }
|
|
8585
8740
|
];
|
|
8586
8741
|
BantaCommentsComponent.ctorParameters = () => [
|
|
@@ -8694,14 +8849,17 @@ LiveCommentComponent.propDecorators = {
|
|
|
8694
8849
|
};
|
|
8695
8850
|
|
|
8696
8851
|
class CommentFieldComponent {
|
|
8697
|
-
constructor() {
|
|
8852
|
+
constructor(chatBackend) {
|
|
8853
|
+
this.chatBackend = chatBackend;
|
|
8698
8854
|
this.canComment = true;
|
|
8699
8855
|
this.allowAttachments = false;
|
|
8700
8856
|
this.signInSelected = new Subject();
|
|
8701
8857
|
this.editAvatarSelected = new Subject();
|
|
8702
8858
|
this.sending = false;
|
|
8703
8859
|
this.expandError = false;
|
|
8704
|
-
this.
|
|
8860
|
+
this._text = '';
|
|
8861
|
+
this.attachmentScrapeDebounce = 1500;
|
|
8862
|
+
this.attachmentFragments = new Map();
|
|
8705
8863
|
this.sendLabel = 'Send';
|
|
8706
8864
|
this.sendingLabel = 'Sending';
|
|
8707
8865
|
this.label = 'Post a comment';
|
|
@@ -8717,6 +8875,79 @@ class CommentFieldComponent {
|
|
|
8717
8875
|
this.autoCompleteSelected = 0;
|
|
8718
8876
|
this.chatMessageAttachments = [];
|
|
8719
8877
|
}
|
|
8878
|
+
get text() {
|
|
8879
|
+
return this._text;
|
|
8880
|
+
}
|
|
8881
|
+
set text(value) {
|
|
8882
|
+
this._text = value;
|
|
8883
|
+
clearTimeout(this.attachmentScrapeTimeout);
|
|
8884
|
+
this.attachmentScrapeTimeout = setTimeout(() => this.scrapeAttachments(), this.attachmentScrapeDebounce);
|
|
8885
|
+
}
|
|
8886
|
+
scrapeAttachments() {
|
|
8887
|
+
let message = {
|
|
8888
|
+
likes: 0,
|
|
8889
|
+
message: this._text,
|
|
8890
|
+
sentAt: undefined,
|
|
8891
|
+
user: this.user,
|
|
8892
|
+
attachments: this.chatMessageAttachments
|
|
8893
|
+
};
|
|
8894
|
+
let foundFragments = [];
|
|
8895
|
+
for (let scraper of this.chatBackend.attachmentScrapers) {
|
|
8896
|
+
let fragments = scraper.findFragments(message);
|
|
8897
|
+
if (!fragments) {
|
|
8898
|
+
console.error(`Attachment fragment scraper ${scraper.constructor.name} is implemented incorrectly: Returned null instead of array`);
|
|
8899
|
+
continue;
|
|
8900
|
+
}
|
|
8901
|
+
for (let fragment of fragments) {
|
|
8902
|
+
foundFragments.push(fragment.text);
|
|
8903
|
+
if (!this.attachmentFragments.has(fragment.text)) {
|
|
8904
|
+
console.log(`Scraped new fragment:`);
|
|
8905
|
+
console.dir(fragment);
|
|
8906
|
+
this.attachmentFragments.set(fragment.text, {
|
|
8907
|
+
fragment,
|
|
8908
|
+
resolution: undefined
|
|
8909
|
+
});
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
// Remove fragments that are no longer in the message.
|
|
8914
|
+
let removedFragments = [];
|
|
8915
|
+
for (let [key] of this.attachmentFragments) {
|
|
8916
|
+
if (!foundFragments.includes(key))
|
|
8917
|
+
removedFragments.push(key);
|
|
8918
|
+
}
|
|
8919
|
+
for (let removedFragment of removedFragments) {
|
|
8920
|
+
console.log(`Removed fragment: ${removedFragment}`);
|
|
8921
|
+
this.attachmentFragments.delete(removedFragment);
|
|
8922
|
+
}
|
|
8923
|
+
// Process any fragments that are not yet resolved (or being
|
|
8924
|
+
// resolved)
|
|
8925
|
+
for (let [key, state] of this.attachmentFragments) {
|
|
8926
|
+
if (state.resolution)
|
|
8927
|
+
continue;
|
|
8928
|
+
state.resolution = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
8929
|
+
console.log(`Resolving fragment ${key}`);
|
|
8930
|
+
for (let resolver of this.chatBackend.attachmentResolvers) {
|
|
8931
|
+
console.log(`- Trying resolver ${resolver.constructor.name}...`);
|
|
8932
|
+
try {
|
|
8933
|
+
let attachment = yield resolver.resolveFragment(message, state.fragment);
|
|
8934
|
+
if (attachment) {
|
|
8935
|
+
console.log(`Resolved fragment ${key} into attachment:`);
|
|
8936
|
+
console.dir(attachment);
|
|
8937
|
+
this.chatMessageAttachments.push(attachment);
|
|
8938
|
+
resolve(attachment);
|
|
8939
|
+
break;
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
catch (e) {
|
|
8943
|
+
console.error(`Caught error during attachment resolver ${resolver.constructor.name}:`);
|
|
8944
|
+
console.error(e);
|
|
8945
|
+
continue;
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
}));
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
8720
8951
|
get userAvatarUrl() {
|
|
8721
8952
|
var _a;
|
|
8722
8953
|
return ((_a = this.user) === null || _a === void 0 ? void 0 : _a.avatarUrl) || this.genericAvatarUrl;
|
|
@@ -8944,8 +9175,10 @@ class CommentFieldComponent {
|
|
|
8944
9175
|
this.chatMessageAttachments = this.chatMessageAttachments.filter(x => x !== attachment);
|
|
8945
9176
|
}, 3000);
|
|
8946
9177
|
}
|
|
8947
|
-
removeAttachment(
|
|
8948
|
-
this.chatMessageAttachments.
|
|
9178
|
+
removeAttachment(attachment) {
|
|
9179
|
+
let index = this.chatMessageAttachments.indexOf(attachment);
|
|
9180
|
+
if (index >= 0)
|
|
9181
|
+
this.chatMessageAttachments.splice(index, 1);
|
|
8949
9182
|
}
|
|
8950
9183
|
alertError() {
|
|
8951
9184
|
if (!this.sendError)
|
|
@@ -8956,10 +9189,13 @@ class CommentFieldComponent {
|
|
|
8956
9189
|
CommentFieldComponent.decorators = [
|
|
8957
9190
|
{ type: Component, args: [{
|
|
8958
9191
|
selector: 'banta-comment-field',
|
|
8959
|
-
template: "<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n <div class=\"avatar-container\">\r\n <a href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"showEditAvatar()\"\r\n [style.background-image]=\"'url(' + userAvatarUrl + ')'\"\r\n ></a>\r\n </div>\r\n <div class=\"text-container\">\r\n <div class=\"field-container\">\r\n <div class=\"field-row\">\r\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>{{label}}</mat-label>\r\n <textarea\r\n #textarea\r\n name=\"message\"\r\n [placeholder]=\"placeholder\"\r\n matInput\r\n cdkTextareaAutosize\r\n [maxlength]=\"maxLength\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (blur)=\"onBlur()\"\r\n [disabled]=\"sending\"\r\n [(ngModel)]=\"text\"></textarea>\r\n </mat-form-field>\r\n <div class=\"options-line\">\r\n <mat-spinner *ngIf=\"sending\" class=\"icon loading\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n <div *ngIf=\"sendError\" class=\"error-message\" [class.expanded]=\"expandError\" [matTooltip]=\"sendError.message\" (click)=\"alertError()\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div class=\"custom\">\r\n <ng-content></ng-content>\r\n </div>\r\n <banta-attachment-button \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
|
|
8960
|
-
styles: ["@-webkit-keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}:host{margin:0 2em 0 0;display:block;-webkit-animation-name:comment-field-appear;animation-name:comment-field-appear;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-delay:.4s;animation-delay:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both;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:#000;border-radius:100%;background-size:cover;background-repeat:no-repeat;background-position:50%;margin-top:.75em;margin-right:.75em}form{display:flex;padding:.5em;align-items:center}form .text-container{position:relative;display:flex;flex-grow:1;min-width:0}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .options-line{display:flex;align-items:center}form .text-container .options-line>*{flex-shrink:0}form .text-container .options-line .error-message{left:.5em;bottom:.5em;color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:max-width 2s ease-in-out;text-overflow:ellipsis;overflow:hidden;flex-shrink:1}form .text-container .options-line .error-message.expanded,form .text-container .options-line .error-message:hover{max-width:100%}form .text-container .options-line .error-message mat-icon{vertical-align:middle}form input[type=text]{background:#000;color:#fff;border:1px solid #333;width:100%;height:1em}form .actions{margin-left:1em;flex-shrink:0}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start;min-width:0}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column;min-width:0}form.new-message mat-form-field{width:100%}form.new-message mat-form-field ::ng-deep .mat-form-field-wrapper{padding-bottom:0}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{width:calc(100% - 2em);position:relative;pointer-events:none;top:-2em}.autocomplete{visibility:hidden;pointer-events:none;position:absolute;background:#333;padding:.5em;display:flex;flex-direction:column;z-index:100}.autocomplete.visible{visibility:visible;pointer-events:auto}.autocomplete a{width:100%;text-align:left}.autocomplete a.active{background:#555}@media (max-width:500px){:host{margin:0}.avatar-container{width:auto;flex-shrink:0}.avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}button.send{min-width:auto;margin-top:1.5em}button.send .label{display:none}}: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) button.send{min-width:auto;margin-top:1.5em}:host-context(.banta-mobile) button.send .label{display:none}.
|
|
9192
|
+
template: "<form class=\"new-message\" (submit)=\"sendMessage()\">\r\n <div class=\"avatar-container\">\r\n <a href=\"javascript:;\"\r\n class=\"avatar\"\r\n (click)=\"showEditAvatar()\"\r\n [style.background-image]=\"'url(' + userAvatarUrl + ')'\"\r\n ></a>\r\n </div>\r\n <div class=\"text-container\">\r\n <div class=\"field-container\">\r\n <div class=\"field-row\">\r\n <mat-form-field appearance=\"outline\" floatLabel=\"always\">\r\n <mat-label>{{label}}</mat-label>\r\n <textarea\r\n #textarea\r\n name=\"message\"\r\n [placeholder]=\"placeholder\"\r\n matInput\r\n cdkTextareaAutosize\r\n [maxlength]=\"maxLength\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (blur)=\"onBlur()\"\r\n [disabled]=\"sending\"\r\n [(ngModel)]=\"text\"></textarea>\r\n </mat-form-field>\r\n <div class=\"options-line\">\r\n <mat-spinner *ngIf=\"sending\" class=\"icon loading\" diameter=\"18\" strokeWidth=\"2\"></mat-spinner>\r\n <div *ngIf=\"sendError\" class=\"error-message\" [class.expanded]=\"expandError\" [matTooltip]=\"sendError.message\" (click)=\"alertError()\">\r\n <mat-icon *ngIf=\"sendError\">error</mat-icon>\r\n {{sendError.message}}\r\n </div>\r\n <div class=\"spacer\"></div>\r\n <div class=\"custom\">\r\n <ng-content></ng-content>\r\n </div>\r\n <banta-attachment-button \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>",
|
|
9193
|
+
styles: ["@-webkit-keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}@keyframes comment-field-appear{0%{transform:translateY(128px);opacity:0}to{transform:translate(0);opacity:1}}:host{margin:0 2em 0 0;display:block;-webkit-animation-name:comment-field-appear;animation-name:comment-field-appear;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-delay:.4s;animation-delay:.4s;-webkit-animation-fill-mode:both;animation-fill-mode:both;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:#000;border-radius:100%;background-size:cover;background-repeat:no-repeat;background-position:50%;margin-top:.75em;margin-right:.75em}form{display:flex;padding:.5em;align-items:center}form .text-container{position:relative;display:flex;flex-grow:1;min-width:0}form .text-container textarea{font-size:14pt;width:100%}form .text-container textarea[disabled]{opacity:.5}form .text-container mat-spinner.loading{position:absolute;left:.5em;bottom:.5em}form .text-container .options-line{display:flex;align-items:center}form .text-container .options-line>*{flex-shrink:0}form .text-container .options-line .error-message{left:.5em;bottom:.5em;color:#683333;overflow-x:hidden;max-width:1.5em;white-space:nowrap;transition:max-width 2s ease-in-out;text-overflow:ellipsis;overflow:hidden;flex-shrink:1}form .text-container .options-line .error-message.expanded,form .text-container .options-line .error-message:hover{max-width:100%}form .text-container .options-line .error-message mat-icon{vertical-align:middle}form input[type=text]{background:#000;color:#fff;border:1px solid #333;width:100%;height:1em}form .actions{margin-left:1em;flex-shrink:0}form button{display:block;margin:0 0 0 auto}form.new-message{display:flex;align-items:flex-start;min-width:0}form.new-message .field-container{flex-grow:1;display:flex;flex-direction:column;min-width:0}form.new-message mat-form-field{width:100%}form.new-message mat-form-field ::ng-deep .mat-form-field-wrapper{padding-bottom:0}form.new-message button{margin:1.25em 0 0}button.send{min-width:9em}textarea{max-height:7em}.autocomplete-container{width:calc(100% - 2em);position:relative;pointer-events:none;top:-2em}.autocomplete{visibility:hidden;pointer-events:none;position:absolute;background:#333;padding:.5em;display:flex;flex-direction:column;z-index:100}.autocomplete.visible{visibility:visible;pointer-events:auto}.autocomplete a{width:100%;text-align:left}.autocomplete a.active{background:#555}@media (max-width:500px){:host{margin:0}.avatar-container{width:auto;flex-shrink:0}.avatar-container .avatar{width:32px;height:32px;margin-top:1.5em}button.send{min-width:auto;margin-top:1.5em}button.send .label{display:none}}: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) button.send{min-width:auto;margin-top:1.5em}:host-context(.banta-mobile) button.send .label{display:none}.image-attachments-container{display:flex;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:-webkit-fit-content;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}.card-attachment,.field-row{position:relative}.card-attachment a{display:flex;align-items:flex-start;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}"]
|
|
8961
9194
|
},] }
|
|
8962
9195
|
];
|
|
9196
|
+
CommentFieldComponent.ctorParameters = () => [
|
|
9197
|
+
{ type: ChatBackendBase }
|
|
9198
|
+
];
|
|
8963
9199
|
CommentFieldComponent.propDecorators = {
|
|
8964
9200
|
source: [{ type: Input }],
|
|
8965
9201
|
user: [{ type: Input }],
|
|
@@ -9340,6 +9576,24 @@ class ChatBackend extends ChatBackendBase {
|
|
|
9340
9576
|
watchMessage(message, handler) {
|
|
9341
9577
|
throw new Error("Method not implemented.");
|
|
9342
9578
|
}
|
|
9579
|
+
getCardForUrl(url) {
|
|
9580
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9581
|
+
let response = yield fetch(`${this.serviceUrl}/urls`, {
|
|
9582
|
+
method: 'POST',
|
|
9583
|
+
headers: {
|
|
9584
|
+
'Content-Type': 'application/json'
|
|
9585
|
+
},
|
|
9586
|
+
body: JSON.stringify({
|
|
9587
|
+
url
|
|
9588
|
+
})
|
|
9589
|
+
});
|
|
9590
|
+
if (response.status == 404)
|
|
9591
|
+
return null;
|
|
9592
|
+
if (response.status >= 400)
|
|
9593
|
+
throw new Error(`Failed to retrieve URL card: ${response.status}. Body: '${yield response.text()}'`);
|
|
9594
|
+
return yield response.json();
|
|
9595
|
+
});
|
|
9596
|
+
}
|
|
9343
9597
|
}
|
|
9344
9598
|
ChatBackend.decorators = [
|
|
9345
9599
|
{ type: Injectable }
|
|
@@ -9348,7 +9602,123 @@ ChatBackend.ctorParameters = () => [
|
|
|
9348
9602
|
{ type: undefined, decorators: [{ type: Inject, args: [BANTA_SDK_OPTIONS,] }] }
|
|
9349
9603
|
];
|
|
9350
9604
|
|
|
9605
|
+
const URL_REGEX = new RegExp('(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?', 'ig');
|
|
9606
|
+
class UrlAttachmentScraper {
|
|
9607
|
+
findFragments(message) {
|
|
9608
|
+
var _a;
|
|
9609
|
+
// If a message already has a URL attachment, don't add another one.
|
|
9610
|
+
if (message.attachments && message.attachments.filter(x => x.type === 'url').length > 0)
|
|
9611
|
+
return null;
|
|
9612
|
+
return (Array.from((_a = message.message.match(URL_REGEX)) !== null && _a !== void 0 ? _a : []))
|
|
9613
|
+
.reduce((a, item) => (a.includes(item) ? undefined : a.push(item), a), [])
|
|
9614
|
+
.map(url => ({
|
|
9615
|
+
text: url,
|
|
9616
|
+
offset: message.message.indexOf(url),
|
|
9617
|
+
type: 'url'
|
|
9618
|
+
}));
|
|
9619
|
+
}
|
|
9620
|
+
}
|
|
9621
|
+
class UrlAttachmentResolver {
|
|
9622
|
+
constructor(backend) {
|
|
9623
|
+
this.backend = backend;
|
|
9624
|
+
}
|
|
9625
|
+
resolveFragment(message, fragment) {
|
|
9626
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9627
|
+
if (fragment.type !== 'url')
|
|
9628
|
+
return null;
|
|
9629
|
+
let urlCard = yield this.backend.getCardForUrl(fragment.text);
|
|
9630
|
+
if (urlCard) {
|
|
9631
|
+
return {
|
|
9632
|
+
type: 'card',
|
|
9633
|
+
url: fragment.text,
|
|
9634
|
+
card: urlCard,
|
|
9635
|
+
style: 'block'
|
|
9636
|
+
};
|
|
9637
|
+
}
|
|
9638
|
+
});
|
|
9639
|
+
}
|
|
9640
|
+
}
|
|
9641
|
+
UrlAttachmentResolver.decorators = [
|
|
9642
|
+
{ type: Injectable }
|
|
9643
|
+
];
|
|
9644
|
+
UrlAttachmentResolver.ctorParameters = () => [
|
|
9645
|
+
{ type: ChatBackendBase }
|
|
9646
|
+
];
|
|
9647
|
+
|
|
9648
|
+
class YouTubeAttachmentResolver {
|
|
9649
|
+
resolveFragment(message, fragment) {
|
|
9650
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9651
|
+
if (fragment.type !== 'url')
|
|
9652
|
+
return null;
|
|
9653
|
+
let videoId;
|
|
9654
|
+
if (fragment.text.match(/https?:\/\/(www\.)?youtube.com\/watch\?v=/)) {
|
|
9655
|
+
let match = /watch\?v=([^&]+)/.exec(fragment.text);
|
|
9656
|
+
if (match) {
|
|
9657
|
+
videoId = match[1];
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
if (videoId) {
|
|
9661
|
+
return {
|
|
9662
|
+
type: 'iframe',
|
|
9663
|
+
url: `https://www.youtube.com/embed/${videoId}`,
|
|
9664
|
+
style: 'block'
|
|
9665
|
+
};
|
|
9666
|
+
}
|
|
9667
|
+
return null;
|
|
9668
|
+
});
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9671
|
+
|
|
9672
|
+
class GiphyAttachmentResolver {
|
|
9673
|
+
resolveFragment(message, fragment) {
|
|
9674
|
+
var _a;
|
|
9675
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9676
|
+
if (fragment.type === 'url' && fragment.text.startsWith('https://giphy.com/gifs')) {
|
|
9677
|
+
let gifId = (_a = /[^-\/]+$/.exec(fragment.text)) === null || _a === void 0 ? void 0 : _a.toString();
|
|
9678
|
+
if (!gifId)
|
|
9679
|
+
return null;
|
|
9680
|
+
return {
|
|
9681
|
+
type: 'iframe',
|
|
9682
|
+
url: `https://giphy.com/embed/${gifId}`,
|
|
9683
|
+
style: 'inline'
|
|
9684
|
+
};
|
|
9685
|
+
}
|
|
9686
|
+
return null;
|
|
9687
|
+
});
|
|
9688
|
+
}
|
|
9689
|
+
}
|
|
9690
|
+
|
|
9691
|
+
class TweetAttachmentResolver {
|
|
9692
|
+
resolveFragment(message, fragment) {
|
|
9693
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9694
|
+
if (fragment.type === 'url' && fragment.text.startsWith('https://twitter.com/')) {
|
|
9695
|
+
return {
|
|
9696
|
+
type: 'tweet',
|
|
9697
|
+
url: fragment.text,
|
|
9698
|
+
style: 'block'
|
|
9699
|
+
};
|
|
9700
|
+
}
|
|
9701
|
+
return null;
|
|
9702
|
+
});
|
|
9703
|
+
}
|
|
9704
|
+
}
|
|
9705
|
+
|
|
9351
9706
|
class BantaSdkModule {
|
|
9707
|
+
constructor(chatBackend) {
|
|
9708
|
+
if (typeof window !== 'undefined') {
|
|
9709
|
+
if (!document.querySelector('script[src="https://platform.twitter.com/widgets.js"]')) {
|
|
9710
|
+
let script = document.createElement('script');
|
|
9711
|
+
script.src = 'https://platform.twitter.com/widgets.js';
|
|
9712
|
+
script.async = true;
|
|
9713
|
+
document.body.appendChild(script);
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
chatBackend.registerAttachmentScraper(new UrlAttachmentScraper());
|
|
9717
|
+
chatBackend.registerAttachmentResolver(new GiphyAttachmentResolver());
|
|
9718
|
+
chatBackend.registerAttachmentResolver(new YouTubeAttachmentResolver());
|
|
9719
|
+
chatBackend.registerAttachmentResolver(new TweetAttachmentResolver());
|
|
9720
|
+
chatBackend.registerAttachmentResolver(new UrlAttachmentResolver(chatBackend));
|
|
9721
|
+
}
|
|
9352
9722
|
static configure(options) {
|
|
9353
9723
|
return {
|
|
9354
9724
|
ngModule: BantaSdkModule,
|
|
@@ -9396,6 +9766,9 @@ BantaSdkModule.decorators = [
|
|
|
9396
9766
|
CommentsModule
|
|
9397
9767
|
]
|
|
9398
9768
|
},] }
|
|
9769
|
+
];
|
|
9770
|
+
BantaSdkModule.ctorParameters = () => [
|
|
9771
|
+
{ type: ChatBackendBase }
|
|
9399
9772
|
];
|
|
9400
9773
|
|
|
9401
9774
|
/*
|
|
@@ -9406,5 +9779,5 @@ BantaSdkModule.decorators = [
|
|
|
9406
9779
|
* Generated bundle index. Do not edit.
|
|
9407
9780
|
*/
|
|
9408
9781
|
|
|
9409
|
-
export { AttachmentButtonComponent, BANTA_SDK_OPTIONS, BantaChatComponent, BantaCommentsComponent, BantaCommonModule, BantaComponent, BantaLogoComponent, BantaMarkdownToHtmlPipe, BantaReplySendOptionsDirective, BantaSdkModule, ChatBackend, ChatBackendBase, ChatMessageComponent, ChatModule, ChatSource, ChatViewComponent, CommentComponent, CommentFieldComponent, CommentSortComponent, CommentViewComponent, CommentsModule, EMOJIS, EmojiModule, EmojiSelectorButtonComponent, EmojiSelectorPanelComponent, LightboxComponent, LiveChatMessageComponent, LiveCommentComponent, LiveMessageComponent, TimestampComponent, lazyConnection };
|
|
9782
|
+
export { AttachmentButtonComponent, BANTA_SDK_OPTIONS, BantaAttachmentComponent, BantaAttachmentsComponent, BantaChatComponent, BantaCommentsComponent, BantaCommonModule, BantaComponent, BantaLogoComponent, BantaMarkdownToHtmlPipe, BantaReplySendOptionsDirective, BantaSdkModule, BantaTrustResourceUrlPipe, ChatBackend, ChatBackendBase, ChatMessageComponent, ChatModule, ChatSource, ChatViewComponent, CommentComponent, CommentFieldComponent, CommentSortComponent, CommentViewComponent, CommentsModule, EMOJIS, EmojiModule, EmojiSelectorButtonComponent, EmojiSelectorPanelComponent, GiphyAttachmentResolver, LightboxComponent, LiveChatMessageComponent, LiveCommentComponent, LiveMessageComponent, TimestampComponent, TweetAttachmentResolver, UrlAttachmentResolver, UrlAttachmentScraper, YouTubeAttachmentResolver, lazyConnection };
|
|
9410
9783
|
//# sourceMappingURL=banta-sdk.js.map
|