@banta/sdk 4.3.2 → 4.4.1
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/bundles/banta-sdk.umd.js +574 -117
- 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 +87 -0
- package/esm2015/lib/banta-sdk.module.js +6 -2
- package/esm2015/lib/chat-backend-base.js +20 -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 +9 -12
- package/esm2015/lib/comments/comment-field/comment-field.component.js +89 -7
- package/esm2015/lib/comments/comments.module.js +6 -2
- package/esm2015/lib/common/attachment/attachment.component.js +55 -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/emoji/emoji-selector-button.component.js +56 -105
- package/esm2015/lib/emoji/emoji.module.js +6 -2
- package/fesm2015/banta-sdk.js +404 -127
- package/fesm2015/banta-sdk.js.map +1 -1
- package/lib/attachment-scraper.d.ts +30 -0
- package/lib/chat-backend-base.d.ts +9 -0
- package/lib/chat-backend.d.ts +2 -1
- package/lib/comments/comment/comment.component.d.ts +2 -4
- package/lib/comments/comment-field/comment-field.component.d.ts +11 -2
- package/lib/common/attachment/attachment.component.d.ts +18 -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/emoji/emoji-selector-button.component.d.ts +13 -14
- package/package.json +1 -1
package/fesm2015/banta-sdk.js
CHANGED
|
@@ -1,12 +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, Injectable, Directive, NgZone, ContentChild, TemplateRef, 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';
|
|
9
10
|
import { MatButtonModule } from '@angular/material/button';
|
|
11
|
+
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
12
|
+
import { PortalModule } from '@angular/cdk/portal';
|
|
10
13
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
11
14
|
import { MatInputModule } from '@angular/material/input';
|
|
12
15
|
import { FormsModule } from '@angular/forms';
|
|
@@ -16,7 +19,6 @@ import { CommentsOrder, CDNProvider, SocketRPC, RpcEvent, DurableSocket } from '
|
|
|
16
19
|
import { ActivatedRoute } from '@angular/router';
|
|
17
20
|
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
|
18
21
|
import { MatMenuModule } from '@angular/material/menu';
|
|
19
|
-
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
20
22
|
import { TextFieldModule } from '@angular/cdk/text-field';
|
|
21
23
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
22
24
|
import { MatSelectModule } from '@angular/material/select';
|
|
@@ -220,10 +222,129 @@ BantaMarkdownToHtmlPipe.ctorParameters = () => [
|
|
|
220
222
|
{ type: DomSanitizer }
|
|
221
223
|
];
|
|
222
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
|
+
activate() {
|
|
255
|
+
this.activated.next();
|
|
256
|
+
}
|
|
257
|
+
remove() {
|
|
258
|
+
this.removed.next();
|
|
259
|
+
}
|
|
260
|
+
get isError() {
|
|
261
|
+
var _a, _b;
|
|
262
|
+
return this.error || ((_b = (_a = this.attachment) === null || _a === void 0 ? void 0 : _a.transientState) === null || _b === void 0 ? void 0 : _b.error);
|
|
263
|
+
}
|
|
264
|
+
get theErrorMessage() {
|
|
265
|
+
var _a, _b;
|
|
266
|
+
return this.errorMessage || ((_b = (_a = this.attachment) === null || _a === void 0 ? void 0 : _a.transientState) === null || _b === void 0 ? void 0 : _b.errorMessage);
|
|
267
|
+
}
|
|
268
|
+
get isLoading() {
|
|
269
|
+
var _a;
|
|
270
|
+
return this.loading || !this.attachment || ((_a = this.attachment.transientState) === null || _a === void 0 ? void 0 : _a.loading) || !this.attachment.url;
|
|
271
|
+
}
|
|
272
|
+
get isImageAttachment() {
|
|
273
|
+
if (this.attachment.type.startsWith('image/'))
|
|
274
|
+
return true;
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
BantaAttachmentComponent.decorators = [
|
|
279
|
+
{ type: Component, args: [{
|
|
280
|
+
selector: 'banta-attachment',
|
|
281
|
+
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 \r\n *ngIf=\"attachment.type === 'iframe'\" \r\n sandbox=\"allow-scripts allow-popups allow-same-origin allow-presentation\" \r\n [src]=\"attachment.url | trustResourceUrl\"></iframe>\r\n <a *ngIf=\"attachment.type === 'card'\" class=\"card\" [href]=\"attachment.url\" target=\"_blank\">\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 {{attachment.card.description}}\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 </ng-container>\r\n</ng-container>",
|
|
282
|
+
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}a.card img{width:300px;aspect-ratio:16/9;-o-object-fit:cover;object-fit:cover;border-radius:10px}a.card h1{margin:0;font-size:30px}.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}"]
|
|
283
|
+
},] }
|
|
284
|
+
];
|
|
285
|
+
BantaAttachmentComponent.propDecorators = {
|
|
286
|
+
attachment: [{ type: Input }],
|
|
287
|
+
loading: [{ type: Input }],
|
|
288
|
+
editing: [{ type: Input }],
|
|
289
|
+
loadingMessage: [{ type: Input }],
|
|
290
|
+
error: [{ type: Input }],
|
|
291
|
+
errorMessage: [{ type: Input }],
|
|
292
|
+
removed: [{ type: Output }],
|
|
293
|
+
activated: [{ type: Output }],
|
|
294
|
+
isLoading: [{ type: HostBinding, args: ['class.loading',] }]
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
class BantaAttachmentsComponent {
|
|
298
|
+
constructor() {
|
|
299
|
+
this.editing = false;
|
|
300
|
+
this.remove = new Subject();
|
|
301
|
+
}
|
|
302
|
+
removeAttachment(attachment) {
|
|
303
|
+
this.remove.next(attachment);
|
|
304
|
+
}
|
|
305
|
+
isImageAttachment(attachment) {
|
|
306
|
+
if (attachment.type.startsWith('image/'))
|
|
307
|
+
return true;
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
isCardAttachment(attachment) {
|
|
311
|
+
if (['card'].includes(attachment.type))
|
|
312
|
+
return true;
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
showLightbox(image) {
|
|
316
|
+
this.lightbox.open(image.url, this.attachments
|
|
317
|
+
.filter(x => x.type === 'image/png')
|
|
318
|
+
.map(x => x.url));
|
|
319
|
+
}
|
|
320
|
+
get inlineAttachments() {
|
|
321
|
+
return this.attachments.filter(x => x.type !== 'card' && (x.style === 'inline' || !x.style));
|
|
322
|
+
}
|
|
323
|
+
get blockAttachments() {
|
|
324
|
+
return this.attachments.filter(x => x.style === 'block' || x.type === 'card');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
BantaAttachmentsComponent.decorators = [
|
|
328
|
+
{ type: Component, args: [{
|
|
329
|
+
selector: 'banta-attachments',
|
|
330
|
+
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>",
|
|
331
|
+
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}"]
|
|
332
|
+
},] }
|
|
333
|
+
];
|
|
334
|
+
BantaAttachmentsComponent.propDecorators = {
|
|
335
|
+
attachments: [{ type: Input }],
|
|
336
|
+
editing: [{ type: Input }],
|
|
337
|
+
lightbox: [{ type: ViewChild, args: ['lightbox',] }],
|
|
338
|
+
remove: [{ type: Output }]
|
|
339
|
+
};
|
|
340
|
+
|
|
223
341
|
const COMPONENTS = [
|
|
224
342
|
TimestampComponent,
|
|
225
343
|
LightboxComponent,
|
|
226
|
-
BantaMarkdownToHtmlPipe
|
|
344
|
+
BantaMarkdownToHtmlPipe,
|
|
345
|
+
BantaTrustResourceUrlPipe,
|
|
346
|
+
BantaAttachmentComponent,
|
|
347
|
+
BantaAttachmentsComponent
|
|
227
348
|
];
|
|
228
349
|
class BantaCommonModule {
|
|
229
350
|
}
|
|
@@ -232,7 +353,9 @@ BantaCommonModule.decorators = [
|
|
|
232
353
|
declarations: COMPONENTS,
|
|
233
354
|
imports: [
|
|
234
355
|
CommonModule,
|
|
235
|
-
MatIconModule
|
|
356
|
+
MatIconModule,
|
|
357
|
+
MatProgressSpinnerModule,
|
|
358
|
+
MatButtonModule
|
|
236
359
|
],
|
|
237
360
|
exports: COMPONENTS
|
|
238
361
|
},] }
|
|
@@ -6830,100 +6953,63 @@ EmojiSelectorPanelComponent.propDecorators = {
|
|
|
6830
6953
|
|
|
6831
6954
|
/// <reference types="@types/resize-observer-browser" />
|
|
6832
6955
|
class EmojiSelectorButtonComponent {
|
|
6833
|
-
constructor(elementRef) {
|
|
6956
|
+
constructor(elementRef, overlay) {
|
|
6834
6957
|
this.elementRef = elementRef;
|
|
6958
|
+
this.overlay = overlay;
|
|
6835
6959
|
this._selected = new Subject();
|
|
6836
6960
|
this.showEmojiPanel = false;
|
|
6837
6961
|
}
|
|
6838
6962
|
get selected() {
|
|
6839
6963
|
return this._selected;
|
|
6840
6964
|
}
|
|
6841
|
-
|
|
6842
|
-
this.
|
|
6843
|
-
this.panelElement.nativeElement.remove();
|
|
6965
|
+
get isOpen() {
|
|
6966
|
+
return this.overlayRef;
|
|
6844
6967
|
}
|
|
6845
|
-
|
|
6846
|
-
|
|
6968
|
+
/**
|
|
6969
|
+
* Insert the given emoji.
|
|
6970
|
+
* @param str
|
|
6971
|
+
*/
|
|
6972
|
+
insert(str) {
|
|
6973
|
+
this._selected.next(str);
|
|
6847
6974
|
}
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
root.appendChild(this.panelElement.nativeElement);
|
|
6854
|
-
}
|
|
6855
|
-
removeListener() {
|
|
6856
|
-
document.removeEventListener('click', this.clickListener);
|
|
6857
|
-
window.removeEventListener('resize', this.resizeListener);
|
|
6858
|
-
}
|
|
6859
|
-
place() {
|
|
6860
|
-
// Not currently used as it can't be easily done handling all
|
|
6861
|
-
// scrolling corner cases.
|
|
6862
|
-
this.putPanelAtRoot();
|
|
6863
|
-
let pos = this.buttonElement.nativeElement.getBoundingClientRect();
|
|
6864
|
-
let size = this.panelElement.nativeElement.getBoundingClientRect();
|
|
6865
|
-
let left = window.scrollX + pos.left + pos.width - size.width;
|
|
6866
|
-
if (left < 0)
|
|
6867
|
-
left = (window.scrollX + window.innerWidth) / 2 - size.width / 2;
|
|
6868
|
-
let scrollY = window.scrollY;
|
|
6869
|
-
if (document.fullscreenElement) {
|
|
6975
|
+
close() {
|
|
6976
|
+
if (this.overlayRef) {
|
|
6977
|
+
this.overlayRef.dispose();
|
|
6978
|
+
this.overlayRef = null;
|
|
6979
|
+
return;
|
|
6870
6980
|
}
|
|
6871
|
-
Object.assign(this.panelElement.nativeElement.style, {
|
|
6872
|
-
top: `${window.scrollY + pos.top + pos.height}px`,
|
|
6873
|
-
left: `${Math.max(0, left)}px`
|
|
6874
|
-
});
|
|
6875
6981
|
}
|
|
6876
6982
|
show() {
|
|
6877
|
-
if (this.
|
|
6878
|
-
this.
|
|
6879
|
-
return;
|
|
6983
|
+
if (this.isOpen) {
|
|
6984
|
+
this.close();
|
|
6880
6985
|
}
|
|
6881
|
-
this.
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
let commentField = this.elementRef.nativeElement.closest(`banta-comment-field`);
|
|
6891
|
-
if (commentField) {
|
|
6892
|
-
let size = commentField.getBoundingClientRect();
|
|
6893
|
-
this.width = size.width;
|
|
6894
|
-
edgeOffset = window.innerWidth - size.right;
|
|
6895
|
-
}
|
|
6896
|
-
let buttonRect = this.buttonElement.nativeElement.getBoundingClientRect();
|
|
6897
|
-
let buttonRight = window.innerWidth - buttonRect.right - edgeOffset - 10;
|
|
6898
|
-
if (this.width < 700) {
|
|
6899
|
-
this.panelElement.nativeElement.style.right = `${-buttonRight}px`;
|
|
6900
|
-
}
|
|
6901
|
-
else {
|
|
6902
|
-
this.panelElement.nativeElement.style.right = '';
|
|
6903
|
-
}
|
|
6904
|
-
this.panelElement.nativeElement.style.maxWidth = `${this.width - 15}px`;
|
|
6905
|
-
};
|
|
6906
|
-
this.resizeListener = onResize;
|
|
6907
|
-
onResize();
|
|
6908
|
-
this.clickListener = (ev) => {
|
|
6909
|
-
let parent = ev.target;
|
|
6910
|
-
let isInDialog = false;
|
|
6911
|
-
while (parent) {
|
|
6912
|
-
if (parent.matches('emoji-selector-panel'))
|
|
6913
|
-
isInDialog = true;
|
|
6914
|
-
parent = parent.parentElement;
|
|
6986
|
+
this.overlayRef = this.overlay.create({
|
|
6987
|
+
positionStrategy: this.overlay.position()
|
|
6988
|
+
.flexibleConnectedTo(this.elementRef)
|
|
6989
|
+
.withPositions([
|
|
6990
|
+
{
|
|
6991
|
+
originX: 'end',
|
|
6992
|
+
originY: 'bottom',
|
|
6993
|
+
overlayX: 'end',
|
|
6994
|
+
overlayY: 'top'
|
|
6915
6995
|
}
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6996
|
+
])
|
|
6997
|
+
.withFlexibleDimensions(true),
|
|
6998
|
+
hasBackdrop: true,
|
|
6999
|
+
disposeOnNavigation: true,
|
|
7000
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition({
|
|
7001
|
+
autoClose: true
|
|
7002
|
+
})
|
|
6923
7003
|
});
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
7004
|
+
this.overlayRef.backdropClick().subscribe(() => {
|
|
7005
|
+
this.close();
|
|
7006
|
+
});
|
|
7007
|
+
this.overlayRef.keydownEvents().subscribe(event => {
|
|
7008
|
+
if (event.key === 'Escape') {
|
|
7009
|
+
this.close();
|
|
7010
|
+
}
|
|
7011
|
+
});
|
|
7012
|
+
this.overlayRef.attach(this.selectorPanelTemplate);
|
|
6927
7013
|
}
|
|
6928
7014
|
}
|
|
6929
7015
|
EmojiSelectorButtonComponent.decorators = [
|
|
@@ -6933,11 +7019,12 @@ EmojiSelectorButtonComponent.decorators = [
|
|
|
6933
7019
|
<button #button type="button" mat-icon-button (click)="show()">
|
|
6934
7020
|
<mat-icon>emoji_emotions</mat-icon>
|
|
6935
7021
|
</button>
|
|
6936
|
-
<
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
7022
|
+
<ng-template cdkPortal #selectorPanelTemplate="cdkPortal">
|
|
7023
|
+
<emoji-selector-panel
|
|
7024
|
+
#panel
|
|
7025
|
+
(selected)="insert($event)"
|
|
7026
|
+
></emoji-selector-panel>
|
|
7027
|
+
</ng-template>
|
|
6941
7028
|
`,
|
|
6942
7029
|
styles: [`
|
|
6943
7030
|
:host {
|
|
@@ -6945,20 +7032,6 @@ EmojiSelectorButtonComponent.decorators = [
|
|
|
6945
7032
|
position: relative;
|
|
6946
7033
|
}
|
|
6947
7034
|
|
|
6948
|
-
emoji-selector-panel {
|
|
6949
|
-
position: absolute;
|
|
6950
|
-
top: 2.5em;
|
|
6951
|
-
right: 0;
|
|
6952
|
-
opacity: 0;
|
|
6953
|
-
pointer-events: none;
|
|
6954
|
-
z-index: 10;
|
|
6955
|
-
}
|
|
6956
|
-
|
|
6957
|
-
emoji-selector-panel.visible {
|
|
6958
|
-
pointer-events: initial;
|
|
6959
|
-
opacity: 1;
|
|
6960
|
-
}
|
|
6961
|
-
|
|
6962
7035
|
button {
|
|
6963
7036
|
color: #666
|
|
6964
7037
|
}
|
|
@@ -6966,13 +7039,12 @@ EmojiSelectorButtonComponent.decorators = [
|
|
|
6966
7039
|
},] }
|
|
6967
7040
|
];
|
|
6968
7041
|
EmojiSelectorButtonComponent.ctorParameters = () => [
|
|
6969
|
-
{ type: ElementRef }
|
|
7042
|
+
{ type: ElementRef },
|
|
7043
|
+
{ type: Overlay }
|
|
6970
7044
|
];
|
|
6971
7045
|
EmojiSelectorButtonComponent.propDecorators = {
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
buttonElement: [{ type: ViewChild, args: ['button', { read: ElementRef },] }],
|
|
6975
|
-
widthConstrained: [{ type: HostBinding, args: ['class.width-constrained',] }]
|
|
7046
|
+
selectorPanelTemplate: [{ type: ViewChild, args: ['selectorPanelTemplate',] }],
|
|
7047
|
+
selected: [{ type: Output }]
|
|
6976
7048
|
};
|
|
6977
7049
|
|
|
6978
7050
|
const COMPONENTS$1 = [
|
|
@@ -6990,7 +7062,9 @@ EmojiModule.decorators = [
|
|
|
6990
7062
|
MatIconModule,
|
|
6991
7063
|
MatButtonModule,
|
|
6992
7064
|
MatFormFieldModule,
|
|
6993
|
-
MatInputModule
|
|
7065
|
+
MatInputModule,
|
|
7066
|
+
OverlayModule,
|
|
7067
|
+
PortalModule
|
|
6994
7068
|
],
|
|
6995
7069
|
exports: COMPONENTS$1
|
|
6996
7070
|
},] }
|
|
@@ -7050,9 +7124,99 @@ ChatMessageComponent.propDecorators = {
|
|
|
7050
7124
|
upvoted: [{ type: Output }]
|
|
7051
7125
|
};
|
|
7052
7126
|
|
|
7127
|
+
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');
|
|
7128
|
+
class UrlAttachmentScraper {
|
|
7129
|
+
findFragments(message) {
|
|
7130
|
+
var _a;
|
|
7131
|
+
// If a message already has a URL attachment, don't add another one.
|
|
7132
|
+
if (message.attachments && message.attachments.filter(x => x.type === 'url').length > 0)
|
|
7133
|
+
return null;
|
|
7134
|
+
return (Array.from((_a = message.message.match(URL_REGEX)) !== null && _a !== void 0 ? _a : []))
|
|
7135
|
+
.reduce((a, item) => (a.includes(item) ? undefined : a.push(item), a), [])
|
|
7136
|
+
.map(url => ({
|
|
7137
|
+
text: url,
|
|
7138
|
+
offset: message.message.indexOf(url),
|
|
7139
|
+
type: 'url'
|
|
7140
|
+
}));
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
class GiphyAttachmentResolver {
|
|
7144
|
+
resolveFragment(message, fragment) {
|
|
7145
|
+
var _a;
|
|
7146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7147
|
+
if (fragment.type === 'url' && fragment.text.startsWith('https://giphy.com/gifs')) {
|
|
7148
|
+
let gifId = (_a = /[^-\/]+$/.exec(fragment.text)) === null || _a === void 0 ? void 0 : _a.toString();
|
|
7149
|
+
if (!gifId)
|
|
7150
|
+
return null;
|
|
7151
|
+
return {
|
|
7152
|
+
type: 'iframe',
|
|
7153
|
+
url: `https://giphy.com/embed/${gifId}`,
|
|
7154
|
+
style: 'inline'
|
|
7155
|
+
};
|
|
7156
|
+
}
|
|
7157
|
+
return null;
|
|
7158
|
+
});
|
|
7159
|
+
}
|
|
7160
|
+
}
|
|
7161
|
+
class YouTubeAttachmentResolver {
|
|
7162
|
+
resolveFragment(message, fragment) {
|
|
7163
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7164
|
+
if (fragment.type !== 'url')
|
|
7165
|
+
return null;
|
|
7166
|
+
let videoId;
|
|
7167
|
+
if (fragment.text.match(/https?:\/\/(www\.)?youtube.com\/watch\?v=/)) {
|
|
7168
|
+
let match = /watch\?v=([^&]+)/.exec(fragment.text);
|
|
7169
|
+
if (match) {
|
|
7170
|
+
videoId = match[1];
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7173
|
+
if (videoId) {
|
|
7174
|
+
return {
|
|
7175
|
+
type: 'iframe',
|
|
7176
|
+
url: `https://www.youtube.com/embed/${videoId}`,
|
|
7177
|
+
style: 'block'
|
|
7178
|
+
};
|
|
7179
|
+
}
|
|
7180
|
+
return null;
|
|
7181
|
+
});
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
class UrlAttachmentResolver {
|
|
7185
|
+
constructor(backend) {
|
|
7186
|
+
this.backend = backend;
|
|
7187
|
+
}
|
|
7188
|
+
resolveFragment(message, fragment) {
|
|
7189
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
7190
|
+
if (fragment.type !== 'url')
|
|
7191
|
+
return null;
|
|
7192
|
+
let urlCard = yield this.backend.getCardForUrl(fragment.text);
|
|
7193
|
+
if (urlCard) {
|
|
7194
|
+
return {
|
|
7195
|
+
type: 'card',
|
|
7196
|
+
url: fragment.text,
|
|
7197
|
+
card: urlCard,
|
|
7198
|
+
style: 'block'
|
|
7199
|
+
};
|
|
7200
|
+
}
|
|
7201
|
+
});
|
|
7202
|
+
}
|
|
7203
|
+
}
|
|
7204
|
+
UrlAttachmentResolver.decorators = [
|
|
7205
|
+
{ type: Injectable }
|
|
7206
|
+
];
|
|
7207
|
+
UrlAttachmentResolver.ctorParameters = () => [
|
|
7208
|
+
{ type: ChatBackendBase }
|
|
7209
|
+
];
|
|
7210
|
+
|
|
7053
7211
|
class ChatBackendBase {
|
|
7054
7212
|
constructor() {
|
|
7055
7213
|
this._userChanged = new BehaviorSubject(null);
|
|
7214
|
+
this._attachmentScrapers = [];
|
|
7215
|
+
this._attachmentResolvers = [];
|
|
7216
|
+
this.registerAttachmentScraper(new UrlAttachmentScraper());
|
|
7217
|
+
this.registerAttachmentResolver(new GiphyAttachmentResolver());
|
|
7218
|
+
this.registerAttachmentResolver(new YouTubeAttachmentResolver());
|
|
7219
|
+
this.registerAttachmentResolver(new UrlAttachmentResolver(this));
|
|
7056
7220
|
}
|
|
7057
7221
|
get userChanged() {
|
|
7058
7222
|
return this._userChanged;
|
|
@@ -7064,6 +7228,18 @@ class ChatBackendBase {
|
|
|
7064
7228
|
get user() {
|
|
7065
7229
|
return this._user;
|
|
7066
7230
|
}
|
|
7231
|
+
registerAttachmentScraper(scraper) {
|
|
7232
|
+
this._attachmentScrapers.push(scraper);
|
|
7233
|
+
}
|
|
7234
|
+
registerAttachmentResolver(resolver) {
|
|
7235
|
+
this._attachmentResolvers.push(resolver);
|
|
7236
|
+
}
|
|
7237
|
+
get attachmentScrapers() {
|
|
7238
|
+
return this._attachmentScrapers.slice();
|
|
7239
|
+
}
|
|
7240
|
+
get attachmentResolvers() {
|
|
7241
|
+
return this._attachmentResolvers.slice();
|
|
7242
|
+
}
|
|
7067
7243
|
}
|
|
7068
7244
|
|
|
7069
7245
|
class LiveChatMessageComponent {
|
|
@@ -7836,11 +8012,6 @@ class CommentComponent {
|
|
|
7836
8012
|
this._avatarSelected.next(user);
|
|
7837
8013
|
this.selectUser();
|
|
7838
8014
|
}
|
|
7839
|
-
showLightbox(image) {
|
|
7840
|
-
this.lightbox.open(image.url, this.message.attachments
|
|
7841
|
-
.filter(x => x.type === 'image/png')
|
|
7842
|
-
.map(x => x.url));
|
|
7843
|
-
}
|
|
7844
8015
|
avatarForUser(user) {
|
|
7845
8016
|
let url = this.genericAvatarUrl;
|
|
7846
8017
|
if (user && user.avatarUrl) {
|
|
@@ -7848,12 +8019,16 @@ class CommentComponent {
|
|
|
7848
8019
|
}
|
|
7849
8020
|
return `url(${url})`;
|
|
7850
8021
|
}
|
|
8022
|
+
get replyCount() {
|
|
8023
|
+
var _a;
|
|
8024
|
+
return ((_a = this.message.submessages) === null || _a === void 0 ? void 0 : _a.length) || this.message.submessageCount || 0;
|
|
8025
|
+
}
|
|
7851
8026
|
}
|
|
7852
8027
|
CommentComponent.decorators = [
|
|
7853
8028
|
{ type: Component, args: [{
|
|
7854
8029
|
selector: 'banta-comment',
|
|
7855
|
-
template: "\r\n<mat-menu #pointItemMenu=\"matMenu\">\r\n <button *ngIf=\"!mine\" mat-menu-item (click)=\"report()\">Report</button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canEdit\" mat-menu-item (click)=\"startEdit()\">Edit</button>\r\n <button *ngIf=\"mine\" [disabled]=\"!permissions?.canDelete\" mat-menu-item (click)=\"delete()\">Delete</button>\r\n</mat-menu>\r\n\r\n<div class=\"message-content\">\r\n <div class=\"user\">\r\n <a\r\n
|
|
7856
|
-
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{color:#666;flex-shrink:0}
|
|
8030
|
+
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",
|
|
8031
|
+
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}"]
|
|
7857
8032
|
},] }
|
|
7858
8033
|
];
|
|
7859
8034
|
CommentComponent.propDecorators = {
|
|
@@ -7878,8 +8053,7 @@ CommentComponent.propDecorators = {
|
|
|
7878
8053
|
editEnded: [{ type: Output }],
|
|
7879
8054
|
shared: [{ type: Output }],
|
|
7880
8055
|
genericAvatarUrl: [{ type: Input }],
|
|
7881
|
-
commentId: [{ type: HostBinding, args: ['attr.data-comment-id',] }]
|
|
7882
|
-
lightbox: [{ type: ViewChild, args: ['lightbox',] }]
|
|
8056
|
+
commentId: [{ type: HostBinding, args: ['attr.data-comment-id',] }]
|
|
7883
8057
|
};
|
|
7884
8058
|
|
|
7885
8059
|
class CommentViewComponent {
|
|
@@ -8623,7 +8797,7 @@ BantaCommentsComponent.decorators = [
|
|
|
8623
8797
|
{ type: Component, args: [{
|
|
8624
8798
|
selector: 'banta-comments',
|
|
8625
8799
|
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",
|
|
8626
|
-
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%}"]
|
|
8800
|
+
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%}"]
|
|
8627
8801
|
},] }
|
|
8628
8802
|
];
|
|
8629
8803
|
BantaCommentsComponent.ctorParameters = () => [
|
|
@@ -8737,14 +8911,17 @@ LiveCommentComponent.propDecorators = {
|
|
|
8737
8911
|
};
|
|
8738
8912
|
|
|
8739
8913
|
class CommentFieldComponent {
|
|
8740
|
-
constructor() {
|
|
8914
|
+
constructor(chatBackend) {
|
|
8915
|
+
this.chatBackend = chatBackend;
|
|
8741
8916
|
this.canComment = true;
|
|
8742
8917
|
this.allowAttachments = false;
|
|
8743
8918
|
this.signInSelected = new Subject();
|
|
8744
8919
|
this.editAvatarSelected = new Subject();
|
|
8745
8920
|
this.sending = false;
|
|
8746
8921
|
this.expandError = false;
|
|
8747
|
-
this.
|
|
8922
|
+
this._text = '';
|
|
8923
|
+
this.attachmentScrapeDebounce = 1500;
|
|
8924
|
+
this.attachmentFragments = new Map();
|
|
8748
8925
|
this.sendLabel = 'Send';
|
|
8749
8926
|
this.sendingLabel = 'Sending';
|
|
8750
8927
|
this.label = 'Post a comment';
|
|
@@ -8760,6 +8937,79 @@ class CommentFieldComponent {
|
|
|
8760
8937
|
this.autoCompleteSelected = 0;
|
|
8761
8938
|
this.chatMessageAttachments = [];
|
|
8762
8939
|
}
|
|
8940
|
+
get text() {
|
|
8941
|
+
return this._text;
|
|
8942
|
+
}
|
|
8943
|
+
set text(value) {
|
|
8944
|
+
this._text = value;
|
|
8945
|
+
clearTimeout(this.attachmentScrapeTimeout);
|
|
8946
|
+
this.attachmentScrapeTimeout = setTimeout(() => this.scrapeAttachments(), this.attachmentScrapeDebounce);
|
|
8947
|
+
}
|
|
8948
|
+
scrapeAttachments() {
|
|
8949
|
+
let message = {
|
|
8950
|
+
likes: 0,
|
|
8951
|
+
message: this._text,
|
|
8952
|
+
sentAt: undefined,
|
|
8953
|
+
user: this.user,
|
|
8954
|
+
attachments: this.chatMessageAttachments
|
|
8955
|
+
};
|
|
8956
|
+
let foundFragments = [];
|
|
8957
|
+
for (let scraper of this.chatBackend.attachmentScrapers) {
|
|
8958
|
+
let fragments = scraper.findFragments(message);
|
|
8959
|
+
if (!fragments) {
|
|
8960
|
+
console.error(`Attachment fragment scraper ${scraper.constructor.name} is implemented incorrectly: Returned null instead of array`);
|
|
8961
|
+
continue;
|
|
8962
|
+
}
|
|
8963
|
+
for (let fragment of fragments) {
|
|
8964
|
+
foundFragments.push(fragment.text);
|
|
8965
|
+
if (!this.attachmentFragments.has(fragment.text)) {
|
|
8966
|
+
console.log(`Scraped new fragment:`);
|
|
8967
|
+
console.dir(fragment);
|
|
8968
|
+
this.attachmentFragments.set(fragment.text, {
|
|
8969
|
+
fragment,
|
|
8970
|
+
resolution: undefined
|
|
8971
|
+
});
|
|
8972
|
+
}
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8975
|
+
// Remove fragments that are no longer in the message.
|
|
8976
|
+
let removedFragments = [];
|
|
8977
|
+
for (let [key] of this.attachmentFragments) {
|
|
8978
|
+
if (!foundFragments.includes(key))
|
|
8979
|
+
removedFragments.push(key);
|
|
8980
|
+
}
|
|
8981
|
+
for (let removedFragment of removedFragments) {
|
|
8982
|
+
console.log(`Removed fragment: ${removedFragment}`);
|
|
8983
|
+
this.attachmentFragments.delete(removedFragment);
|
|
8984
|
+
}
|
|
8985
|
+
// Process any fragments that are not yet resolved (or being
|
|
8986
|
+
// resolved)
|
|
8987
|
+
for (let [key, state] of this.attachmentFragments) {
|
|
8988
|
+
if (state.resolution)
|
|
8989
|
+
continue;
|
|
8990
|
+
state.resolution = new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
8991
|
+
console.log(`Resolving fragment ${key}`);
|
|
8992
|
+
for (let resolver of this.chatBackend.attachmentResolvers) {
|
|
8993
|
+
console.log(`- Trying resolver ${resolver.constructor.name}...`);
|
|
8994
|
+
try {
|
|
8995
|
+
let attachment = yield resolver.resolveFragment(message, state.fragment);
|
|
8996
|
+
if (attachment) {
|
|
8997
|
+
console.log(`Resolved fragment ${key} into attachment:`);
|
|
8998
|
+
console.dir(attachment);
|
|
8999
|
+
this.chatMessageAttachments.push(attachment);
|
|
9000
|
+
resolve(attachment);
|
|
9001
|
+
break;
|
|
9002
|
+
}
|
|
9003
|
+
}
|
|
9004
|
+
catch (e) {
|
|
9005
|
+
console.error(`Caught error during attachment resolver ${resolver.constructor.name}:`);
|
|
9006
|
+
console.error(e);
|
|
9007
|
+
continue;
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
}));
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
8763
9013
|
get userAvatarUrl() {
|
|
8764
9014
|
var _a;
|
|
8765
9015
|
return ((_a = this.user) === null || _a === void 0 ? void 0 : _a.avatarUrl) || this.genericAvatarUrl;
|
|
@@ -8987,8 +9237,10 @@ class CommentFieldComponent {
|
|
|
8987
9237
|
this.chatMessageAttachments = this.chatMessageAttachments.filter(x => x !== attachment);
|
|
8988
9238
|
}, 3000);
|
|
8989
9239
|
}
|
|
8990
|
-
removeAttachment(
|
|
8991
|
-
this.chatMessageAttachments.
|
|
9240
|
+
removeAttachment(attachment) {
|
|
9241
|
+
let index = this.chatMessageAttachments.indexOf(attachment);
|
|
9242
|
+
if (index >= 0)
|
|
9243
|
+
this.chatMessageAttachments.splice(index, 1);
|
|
8992
9244
|
}
|
|
8993
9245
|
alertError() {
|
|
8994
9246
|
if (!this.sendError)
|
|
@@ -8999,10 +9251,13 @@ class CommentFieldComponent {
|
|
|
8999
9251
|
CommentFieldComponent.decorators = [
|
|
9000
9252
|
{ type: Component, args: [{
|
|
9001
9253
|
selector: 'banta-comment-field',
|
|
9002
|
-
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
|
|
9003
|
-
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}.
|
|
9254
|
+
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>",
|
|
9255
|
+
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}"]
|
|
9004
9256
|
},] }
|
|
9005
9257
|
];
|
|
9258
|
+
CommentFieldComponent.ctorParameters = () => [
|
|
9259
|
+
{ type: ChatBackendBase }
|
|
9260
|
+
];
|
|
9006
9261
|
CommentFieldComponent.propDecorators = {
|
|
9007
9262
|
source: [{ type: Input }],
|
|
9008
9263
|
user: [{ type: Input }],
|
|
@@ -9154,7 +9409,9 @@ CommentsModule.decorators = [
|
|
|
9154
9409
|
BantaCommonModule,
|
|
9155
9410
|
EmojiModule,
|
|
9156
9411
|
MatTooltipModule,
|
|
9157
|
-
MatSelectModule
|
|
9412
|
+
MatSelectModule,
|
|
9413
|
+
OverlayModule,
|
|
9414
|
+
PortalModule
|
|
9158
9415
|
],
|
|
9159
9416
|
exports: COMPONENTS$3
|
|
9160
9417
|
},] }
|
|
@@ -9381,6 +9638,24 @@ class ChatBackend extends ChatBackendBase {
|
|
|
9381
9638
|
watchMessage(message, handler) {
|
|
9382
9639
|
throw new Error("Method not implemented.");
|
|
9383
9640
|
}
|
|
9641
|
+
getCardForUrl(url) {
|
|
9642
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9643
|
+
let response = yield fetch(`${this.serviceUrl}/urls`, {
|
|
9644
|
+
method: 'POST',
|
|
9645
|
+
headers: {
|
|
9646
|
+
'Content-Type': 'application/json'
|
|
9647
|
+
},
|
|
9648
|
+
body: JSON.stringify({
|
|
9649
|
+
url
|
|
9650
|
+
})
|
|
9651
|
+
});
|
|
9652
|
+
if (response.status == 404)
|
|
9653
|
+
return null;
|
|
9654
|
+
if (response.status >= 400)
|
|
9655
|
+
throw new Error(`Failed to retrieve URL card: ${response.status}. Body: '${yield response.text()}'`);
|
|
9656
|
+
return yield response.json();
|
|
9657
|
+
});
|
|
9658
|
+
}
|
|
9384
9659
|
}
|
|
9385
9660
|
ChatBackend.decorators = [
|
|
9386
9661
|
{ type: Injectable }
|
|
@@ -9420,7 +9695,9 @@ BantaSdkModule.decorators = [
|
|
|
9420
9695
|
MatFormFieldModule,
|
|
9421
9696
|
MatInputModule,
|
|
9422
9697
|
MatProgressSpinnerModule,
|
|
9423
|
-
MatSnackBarModule
|
|
9698
|
+
MatSnackBarModule,
|
|
9699
|
+
OverlayModule,
|
|
9700
|
+
PortalModule
|
|
9424
9701
|
],
|
|
9425
9702
|
declarations: [
|
|
9426
9703
|
BantaComponent,
|
|
@@ -9445,5 +9722,5 @@ BantaSdkModule.decorators = [
|
|
|
9445
9722
|
* Generated bundle index. Do not edit.
|
|
9446
9723
|
*/
|
|
9447
9724
|
|
|
9448
|
-
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 };
|
|
9725
|
+
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, LightboxComponent, LiveChatMessageComponent, LiveCommentComponent, LiveMessageComponent, TimestampComponent, lazyConnection };
|
|
9449
9726
|
//# sourceMappingURL=banta-sdk.js.map
|