From 86d352f5497d03577d3186103fa58176e22c37b7 Mon Sep 17 00:00:00 2001 From: _Bastler <_Bastler@bstly.de> Date: Thu, 18 Nov 2021 17:48:28 +0100 Subject: [PATCH] update clipboard, fix timeslots --- src/app/app.module.ts | 4 +- .../account/domains/domains.component.ts | 60 ++++++------- src/app/pages/jitsi/jitsi.component.ts | 22 ++--- .../partey/timeslots/timeslots.compontent.ts | 19 ++--- src/app/pages/register/register.component.ts | 85 +++++++++---------- .../urlshortener/urlshortener.component.ts | 10 +-- .../binary/pgp/profilefield.pgp-blob.ts | 31 +++---- 7 files changed, 103 insertions(+), 128 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 68a91d6..23e9b6f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,7 +8,7 @@ import { HttpClientModule, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTER import { MaterialModule } from './material/material.module'; import { QrCodeModule } from 'ng-qrcode'; import { DatePipe } from '@angular/common'; - +import { ClipboardModule } from '@angular/cdk/clipboard'; import { AutofocusDirective } from './material/autofocus'; @@ -125,6 +125,7 @@ export class XhrInterceptor implements HttpInterceptor { ], imports: [ BrowserModule, + ClipboardModule, AppRoutingModule, BrowserAnimationsModule, MaterialModule, @@ -132,6 +133,7 @@ export class XhrInterceptor implements HttpInterceptor { FormsModule, ReactiveFormsModule, QrCodeModule, + ], exports: [ MaterialModule ], providers: [ { provide: APP_INITIALIZER, useFactory: init_app, deps: [ I18nService ], multi: true }, { provide: HTTP_INTERCEPTORS, useClass: XhrInterceptor, multi: true }, DatePipe, diff --git a/src/app/pages/account/domains/domains.component.ts b/src/app/pages/account/domains/domains.component.ts index 5e32728..939abed 100644 --- a/src/app/pages/account/domains/domains.component.ts +++ b/src/app/pages/account/domains/domains.component.ts @@ -1,16 +1,17 @@ -import {Component, OnInit, ViewChild} from '@angular/core'; -import {I18nService} from '../../../services/i18n.service'; -import {Sort} from '@angular/material/sort'; -import {UserDomainService} from '../../../services/userdomain.service'; -import {FormBuilder, FormGroup, Validators, NgForm} from '@angular/forms'; -import {MatDialog} from '@angular/material/dialog'; -import {ConfirmDialog} from '../../../ui/confirm/confirm.component'; -import {MatSnackBar} from '@angular/material/snack-bar'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { I18nService } from '../../../services/i18n.service'; +import { Sort } from '@angular/material/sort'; +import { UserDomainService } from '../../../services/userdomain.service'; +import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { ConfirmDialog } from '../../../ui/confirm/confirm.component'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Clipboard } from '@angular/cdk/clipboard'; @Component({ selector: 'app-account-domains', templateUrl: './domains.component.html', - styleUrls: ['./domains.component.scss'] + styleUrls: [ './domains.component.scss' ] }) export class DomainsComponent implements OnInit { @@ -23,19 +24,20 @@ export class DomainsComponent implements OnInit { success: boolean; working: boolean; - domainsColumns = ["domain", "secret", "validated", "delete"]; - visibilities = ["PRIVATE", "PROTECTED", "PUBLIC"]; + domainsColumns = [ "domain", "secret", "validated", "delete" ]; + visibilities = [ "PRIVATE", "PROTECTED", "PUBLIC" ]; constructor( private formBuilder: FormBuilder, private userDomainService: UserDomainService, private i18n: I18nService, private snackBar: MatSnackBar, - public dialog: MatDialog) {} + public dialog: MatDialog, + private clipboard: Clipboard) { } ngOnInit(): void { this.form = this.formBuilder.group({ - domain: ['', Validators.required], + domain: [ '', Validators.required ], // visibility: ['', Validators.required], }); @@ -53,15 +55,15 @@ export class DomainsComponent implements OnInit { this.working = false; }, (error) => { this.working = false; - if(error.status == 409) { + if (error.status == 409) { let errors = {}; - for(let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; + for (let code of error.error) { + errors[ code.field ] = errors[ code.field ] || {}; + errors[ code.field ][ code.code ] = true; } - for(let code in errors) { - this.form.get(code).setErrors(errors[code]); + for (let code in errors) { + this.form.get(code).setErrors(errors[ code ]); } } }) @@ -83,12 +85,12 @@ export class DomainsComponent implements OnInit { const dialogRef = this.dialog.open(ConfirmDialog, { data: { 'label': 'user.domains.confirmDelete', - 'args': [domain.domain] + 'args': [ domain.domain ] } }) dialogRef.afterClosed().subscribe(result => { - if(result) { + if (result) { this.userDomainService.delete(domain.id).subscribe((result: any) => { this.update(); }) @@ -97,13 +99,7 @@ export class DomainsComponent implements OnInit { } copySecret(domain: any) { - const selBox = document.createElement('textarea'); - selBox.value = domain.secret; - document.body.appendChild(selBox); - selBox.focus(); - selBox.select(); - document.execCommand('copy'); - document.body.removeChild(selBox); + this.clipboard.copy(domain.secret); this.snackBar.open(this.i18n.get("user.domains.secret.copied", []), this.i18n.get("close", []), { duration: 3000 }); @@ -111,14 +107,14 @@ export class DomainsComponent implements OnInit { sortData(sort: Sort) { const data = this.domains.slice(); - if(!sort.active || sort.direction === '') { + if (!sort.active || sort.direction === '') { this.domains = data; return; } this.domains = data.sort((a, b) => { const isAsc = sort.direction === 'asc'; - switch(sort.active) { + switch (sort.active) { case 'domain': return this.compare(a.domain, b.domain, isAsc); case 'validated': return this.compare(a.validated, b.validated, isAsc); default: return 0; @@ -126,9 +122,9 @@ export class DomainsComponent implements OnInit { }); } - compare(a: number | string , b: number | string , isAsc: boolean) { + compare(a: number | string, b: number | string, isAsc: boolean) { if (typeof a === 'string' && typeof b === 'string') { - return a.localeCompare(b,undefined, { sensitivity: 'accent' } ) * (isAsc ? 1 : -1); + return a.localeCompare(b, undefined, { sensitivity: 'accent' }) * (isAsc ? 1 : -1); } return (a < b ? -1 : 1) * (isAsc ? 1 : -1); } diff --git a/src/app/pages/jitsi/jitsi.component.ts b/src/app/pages/jitsi/jitsi.component.ts index 2b8acf1..c8ab9dd 100644 --- a/src/app/pages/jitsi/jitsi.component.ts +++ b/src/app/pages/jitsi/jitsi.component.ts @@ -5,10 +5,10 @@ import { FormBuilder, FormGroup, Validators, NgForm } from '@angular/forms'; import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { DatePipe } from '@angular/common'; import { PageEvent } from '@angular/material/paginator'; +import { Clipboard } from '@angular/cdk/clipboard'; import { QuotaService } from '../../services/quota.service'; import { JitsiService } from '../../services/jitsi.service'; -import { UrlShortenerService } from '../../services/urlshortener.service'; import { ConfirmDialog } from '../../ui/confirm/confirm.component'; import { I18nService } from './../../services/i18n.service'; @@ -39,7 +39,8 @@ export class JitsiComponent implements OnInit { private jitsiService: JitsiService, private snackBar: MatSnackBar, private i18n: I18nService, - public dialog: MatDialog) { } + public dialog: MatDialog, + private clipboard: Clipboard) { } ngOnInit(): void { this.datetimeformat = this.i18n.get('format.datetime', []); @@ -157,13 +158,7 @@ export class JitsiComponent implements OnInit { } copyRoomUrlToClipboard(jitsiRoom: any) { - const selBox = document.createElement('textarea'); - selBox.value = jitsiRoom.url; - document.body.appendChild(selBox); - selBox.focus(); - selBox.select(); - document.execCommand('copy'); - document.body.removeChild(selBox); + this.clipboard.copy(jitsiRoom.url); this.snackBar.open(this.i18n.get("jitsi.rooms.clipboard.copied", []), this.i18n.get("close", []), { duration: 3000 }); @@ -259,6 +254,7 @@ export class JitsiShareDialog { constructor( private i18n: I18nService, private snackBar: MatSnackBar, + private clipboard: Clipboard, private datePipe: DatePipe, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) { @@ -279,13 +275,7 @@ export class JitsiShareDialog { } copyToClipboard(text) { - const selBox = document.createElement('textarea'); - selBox.value = text; - document.body.appendChild(selBox); - selBox.focus(); - selBox.select(); - document.execCommand('copy'); - document.body.removeChild(selBox); + this.clipboard.copy(text); this.snackBar.open(this.i18n.get("jitsi.share.clipboard.copied", []), this.i18n.get("close", []), { duration: 3000 }); diff --git a/src/app/pages/partey/timeslots/timeslots.compontent.ts b/src/app/pages/partey/timeslots/timeslots.compontent.ts index 7729503..bc02a1d 100644 --- a/src/app/pages/partey/timeslots/timeslots.compontent.ts +++ b/src/app/pages/partey/timeslots/timeslots.compontent.ts @@ -7,6 +7,7 @@ import { DatePipe } from '@angular/common'; import { FormControl } from '@angular/forms'; import { debounceTime } from 'rxjs/operators'; import { PageEvent } from '@angular/material/paginator'; +import { Clipboard } from '@angular/cdk/clipboard'; import { ParteyTimeslotsService } from '../../../services/partey.service'; import { ConfirmDialog } from '../../../ui/confirm/confirm.component'; @@ -49,7 +50,8 @@ export class ParteyTimeslotsComponent implements OnInit { private i18n: I18nService, private datePipe: DatePipe, private snackBar: MatSnackBar, - public dialog: MatDialog) { } + public dialog: MatDialog, + private clipboard: Clipboard) { } ngOnInit(): void { @@ -182,13 +184,7 @@ export class ParteyTimeslotsComponent implements OnInit { } copySecretToClipboard(secret) { - const selBox = document.createElement('textarea'); - selBox.value = secret; - document.body.appendChild(selBox); - selBox.focus(); - selBox.select(); - document.execCommand('copy'); - document.body.removeChild(selBox); + this.clipboard.copy(secret); this.snackBar.open(this.i18n.get("partey.timeslots.secret.copied", []), this.i18n.get("close", []), { duration: 3000 }); @@ -209,7 +205,7 @@ export class ParteyTimeslotDialog { timeslot; visibilities = [ "PRIVATE", "PROTECTED", "PUBLIC" ]; - types = [ "VIDEO", "AUDIO" ]; + types = [ "VIDEO", "AUDIO", "AUDIO_STREAM", "VIDEO_STREAM" ]; constructor( private parteyTimeslotsService: ParteyTimeslotsService, @@ -226,12 +222,11 @@ export class ParteyTimeslotDialog { ends: [ '', Validators.required ], title: [ '', Validators.nullValidator ], description: [ '', Validators.nullValidator ], - stream: [ '', this.timeslot.type == 'VIDEO' ? Validators.required : Validators.nullValidator ], + stream: [ '', this.timeslot.type == 'VIDEO_STREAM' ? Validators.required : Validators.nullValidator ], + share: [ '', (this.timeslot.type == 'VIDEO' || this.timeslot.type == 'AUDIO') ? Validators.required : Validators.nullValidator ], }); } - - create(timeslot) { this.parteyTimeslotsService.create(timeslot).subscribe((result: any) => { this.dialogRef.close(timeslot); diff --git a/src/app/pages/register/register.component.ts b/src/app/pages/register/register.component.ts index bd03ef2..49bc5e7 100644 --- a/src/app/pages/register/register.component.ts +++ b/src/app/pages/register/register.component.ts @@ -1,24 +1,25 @@ -import {Component, OnInit, Inject, ViewChild, ElementRef} from '@angular/core'; -import {FormBuilder, FormGroup, Validators} from '@angular/forms'; -import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; -import {Router} from '@angular/router'; -import {MatSnackBar} from '@angular/material/snack-bar'; +import { Component, OnInit, Inject, ViewChild, ElementRef } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Router } from '@angular/router'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Clipboard } from '@angular/cdk/clipboard'; -import {UserService} from './../../services/user.service'; -import {ItemService} from './../../services/item.service'; -import {I18nService} from './../../services/i18n.service'; -import {MatchingValidator} from './../../utils/matching.validator'; -import {PermissionService} from './../../services/permission.service'; -import {QuotaService} from './../../services/quota.service'; +import { UserService } from './../../services/user.service'; +import { ItemService } from './../../services/item.service'; +import { I18nService } from './../../services/i18n.service'; +import { MatchingValidator } from './../../utils/matching.validator'; +import { PermissionService } from './../../services/permission.service'; +import { QuotaService } from './../../services/quota.service'; -import {uniqueNamesGenerator, Config, adjectives, colors, animals} from 'unique-names-generator'; +import { uniqueNamesGenerator, Config, adjectives, colors, animals } from 'unique-names-generator'; var openpgp = require('openpgp'); @Component({ selector: 'app-register', templateUrl: './register.component.html', - styleUrls: ['./register.component.scss'] + styleUrls: [ './register.component.scss' ] }) export class RegisterComponent implements OnInit { @@ -50,11 +51,11 @@ export class RegisterComponent implements OnInit { async ngOnInit() { this.form = this.formBuilder.group({ - username: ['', Validators.required], - email: ['', Validators.email], - primaryEmail: [false, Validators.nullValidator], - password: ['', Validators.nullValidator], - password2: ['', Validators.required] + username: [ '', Validators.required ], + email: [ '', Validators.email ], + primaryEmail: [ false, Validators.nullValidator ], + password: [ '', Validators.nullValidator ], + password2: [ '', Validators.required ] }, { validator: MatchingValidator('password', 'password2') }); @@ -76,8 +77,8 @@ export class RegisterComponent implements OnInit { let mailControl = this.form.get('email'); mailControl.clearAsyncValidators(); mailControl.clearValidators(); - if(this.model.primaryEmail) { - mailControl.setValidators([Validators.email, Validators.required]); + if (this.model.primaryEmail) { + mailControl.setValidators([ Validators.email, Validators.required ]); } mailControl.updateValueAndValidity(); } @@ -85,7 +86,7 @@ export class RegisterComponent implements OnInit { genUsername() { const config: Config = { - dictionaries: [adjectives, colors, animals], + dictionaries: [ adjectives, colors, animals ], separator: "", style: "capital", length: 3 @@ -97,10 +98,10 @@ export class RegisterComponent implements OnInit { register() { this.missingToken = false; this.lockedToken = false; - if(this.form.valid && !this.working) { + if (this.form.valid && !this.working) { this.working = true; let pgpOption = { - userIds: [{name: this.model.username, email: this.model.username + "@we.bstly.de"}], + userIds: [ { name: this.model.username, email: this.model.username + "@we.bstly.de" } ], curve: "ed25519", } @@ -110,12 +111,12 @@ export class RegisterComponent implements OnInit { pubKey = key.publicKeyArmored; this.model.profileFields = [ - {"name": "publicKey", "type": "BLOB", "visibility": "PROTECTED", "blob": pubKey} + { "name": "publicKey", "type": "BLOB", "visibility": "PROTECTED", "blob": pubKey } ] - if(this.model.primaryEmail) { - this.model.profileFields.push({"name": "email", "type": "EMAIL", "visibility": "PRIVATE", "value": this.model.email}); - this.model.profileFields.push({"name": "primaryEmail", "type": "BOOL", "visibility": "PRIVATE", "value": this.model.primaryEmail}); + if (this.model.primaryEmail) { + this.model.profileFields.push({ "name": "email", "type": "EMAIL", "visibility": "PRIVATE", "value": this.model.email }); + this.model.profileFields.push({ "name": "primaryEmail", "type": "BOOL", "visibility": "PRIVATE", "value": this.model.primaryEmail }); } this.userService.register(this.model).subscribe((result: any) => { @@ -128,7 +129,7 @@ export class RegisterComponent implements OnInit { }); dialogRef.afterClosed().subscribe(result => { - if(result) { + if (result) { this.success = true; } }); @@ -136,19 +137,19 @@ export class RegisterComponent implements OnInit { this.working = false; }, (error) => { this.working = false; - if(error.status == 401) { + if (error.status == 401) { this.missingToken = true; - } if(error.status == 423) { + } if (error.status == 423) { this.lockedToken = true; - } else if(error.status == 409) { + } else if (error.status == 409) { let errors = {}; - for(let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; + for (let code of error.error) { + errors[ code.field ] = errors[ code.field ] || {}; + errors[ code.field ][ code.code ] = true; } - for(let code in errors) { - this.form.get(code).setErrors(errors[code]); + for (let code in errors) { + this.form.get(code).setErrors(errors[ code ]); } } }) @@ -162,17 +163,18 @@ export class RegisterComponent implements OnInit { @Component({ selector: 'app-register-dialog', templateUrl: 'register.dialog.html', - styleUrls: ['./register.dialog.scss'] + styleUrls: [ './register.dialog.scss' ] }) export class RegisterDialog { public downloaded: boolean = false; - @ViewChild("downloadKey", {read: ElementRef}) downloadKey: ElementRef; + @ViewChild("downloadKey", { read: ElementRef }) downloadKey: ElementRef; constructor(private router: Router, - private i18n : I18nService, + private i18n: I18nService, private snackBar: MatSnackBar, + private clipboard: Clipboard, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) { } @@ -187,10 +189,7 @@ export class RegisterDialog { } copyKey(inputElement) { - inputElement.select(); - document.execCommand('copy'); - inputElement.setSelectionRange(0, 0); - this.downloaded = true; + this.clipboard.copy(inputElement.value); this.snackBar.open(this.i18n.get("pgp.privateKey.copied", []), this.i18n.get("close", []), { duration: 3000 }); diff --git a/src/app/pages/urlshortener/urlshortener.component.ts b/src/app/pages/urlshortener/urlshortener.component.ts index b8aa04d..e1eeb37 100644 --- a/src/app/pages/urlshortener/urlshortener.component.ts +++ b/src/app/pages/urlshortener/urlshortener.component.ts @@ -5,6 +5,7 @@ import { FormBuilder, FormGroup, Validators, NgForm, FormControl } from '@angula import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { PageEvent } from '@angular/material/paginator'; import { ActivatedRoute } from '@angular/router'; +import { Clipboard } from '@angular/cdk/clipboard'; import { MatchingValidator } from './../../utils/matching.validator'; import { QuotaService } from '../../services/quota.service'; @@ -268,6 +269,7 @@ export class UrlShortenerShareDialog { constructor( private i18n: I18nService, private snackBar: MatSnackBar, + private clipboard: Clipboard, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) { this.shortenedUrl = data; @@ -279,13 +281,7 @@ export class UrlShortenerShareDialog { } copyToClipboard(text) { - const selBox = document.createElement('textarea'); - selBox.value = text; - document.body.appendChild(selBox); - selBox.focus(); - selBox.select(); - document.execCommand('copy'); - document.body.removeChild(selBox); + this.clipboard.copy(text); this.snackBar.open(this.i18n.get("urlshortener.share.clipboard.copied", []), this.i18n.get("close", []), { duration: 3000 }); diff --git a/src/app/ui/profilefields/binary/pgp/profilefield.pgp-blob.ts b/src/app/ui/profilefields/binary/pgp/profilefield.pgp-blob.ts index 2ea2d98..ecbdcfa 100644 --- a/src/app/ui/profilefields/binary/pgp/profilefield.pgp-blob.ts +++ b/src/app/ui/profilefields/binary/pgp/profilefield.pgp-blob.ts @@ -1,17 +1,16 @@ -import {Component, OnInit, ElementRef, ViewChild} from '@angular/core'; -import {MatDialogRef} from '@angular/material/dialog'; -import {MatSnackBar} from '@angular/material/snack-bar'; - -import {AuthService} from '../../../../services/auth.service'; -import {I18nService} from '../../../../services/i18n.service'; - +import { Component, OnInit, ElementRef, ViewChild } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Clipboard } from '@angular/cdk/clipboard'; +import { AuthService } from '../../../../services/auth.service'; +import { I18nService } from '../../../../services/i18n.service'; var openpgp = require('openpgp'); @Component({ templateUrl: './profilefield.pgp-blob.html', - styleUrls: ['./profilefield.pgp-blob.scss'] + styleUrls: [ './profilefield.pgp-blob.scss' ] }) export class ProfileFieldPgpBlob implements OnInit { @@ -19,23 +18,24 @@ export class ProfileFieldPgpBlob implements OnInit { data: any; - @ViewChild("downloadKey", {read: ElementRef}) downloadKey: ElementRef; + @ViewChild("downloadKey", { read: ElementRef }) downloadKey: ElementRef; constructor( public dialogRef: MatDialogRef, - private i18n : I18nService, + private i18n: I18nService, private authService: AuthService, - private snackBar: MatSnackBar) { + private snackBar: MatSnackBar, + private clipboard: Clipboard) { this.data = {}; } ngOnInit(): void { this.authService.auth.subscribe((auth: any) => { - if(!auth.authenticated) { + if (!auth.authenticated) { return; } let pgpOption = { - userIds: [{name: auth.principal.username, email: auth.principal.username + "@we.bstly.de"}], + userIds: [ { name: auth.principal.username, email: auth.principal.username + "@we.bstly.de" } ], curve: "ed25519", } @@ -56,10 +56,7 @@ export class ProfileFieldPgpBlob implements OnInit { } copyKey(inputElement) { - inputElement.select(); - document.execCommand('copy'); - inputElement.setSelectionRange(0, 0); - this.downloaded = true; + this.clipboard.copy(inputElement.value); this.snackBar.open(this.i18n.get("pgp.privateKey.copied", []), this.i18n.get("close", []), { duration: 3000 });