Show Jitsi iFrame in Dialog

Replace the external link button with a (real) Dialog containing the
jitsi iFrame.
The dialog can be hidden but not entirly closed.
Replace all dialogService.closeAll() functions by closing the specific
dialog rather than all of them.
This commit is contained in:
Sean 2020-06-04 16:29:35 +02:00
parent d7408b40f9
commit 3ca4714812
13 changed files with 164 additions and 66 deletions

View File

@ -11,7 +11,7 @@ import {
TemplateRef
} from '@angular/core';
import { FormBuilder, NgControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatFormFieldControl } from '@angular/material/form-field';
import { Observable } from 'rxjs';
@ -36,6 +36,8 @@ export class AttachmentControlComponent extends BaseFormControlComponent<ViewMed
@Output()
public errorHandler: EventEmitter<string> = new EventEmitter();
private dialogRef: MatDialogRef<any>;
/**
* The file list that is necessary for the `SearchValueSelector`
*/
@ -74,7 +76,7 @@ export class AttachmentControlComponent extends BaseFormControlComponent<ViewMed
* @param dialog the dialog to open
*/
public openUploadDialog(dialog: TemplateRef<string>): void {
this.dialogService.open(dialog, { ...mediumDialogSettings, disableClose: false });
this.dialogRef = this.dialogService.open(dialog, { ...mediumDialogSettings, disableClose: false });
}
/**
@ -85,7 +87,7 @@ export class AttachmentControlComponent extends BaseFormControlComponent<ViewMed
public uploadSuccess(fileIDs: number[]): void {
const newValues = [...this.contentForm.value, ...fileIDs];
this.updateForm(newValues);
this.dialogService.closeAll();
this.dialogRef.close();
}
/**

View File

@ -1,4 +1,26 @@
<div class="jitsi-integration">
<!-- iFrame Dialog -->
<ng-template #conferenceDialog>
<div class="jitsi-iframe-wrapper" #jitsi></div>
<div mat-dialog-actions>
<button
type="button"
mat-button
color="primary"
(click)="openExternal()"
matTooltip="{{ 'Open Jitsi in new tab' | translate }}"
>
<mat-icon>open_in_new</mat-icon>
</button>
<button class="minimize-jitsi-dialog-button" type="button" mat-button color="primary" (click)="toggleConferenceDialog()">
<span>{{ 'Minimize' | translate }}</span>
<mat-icon>fullscreen_exit</mat-icon>
</button>
</div>
</ng-template>
<!-- Audio-Conference-bar -->
<div
class="jitsi-bar"
[ngClass]="{
@ -67,7 +89,9 @@
<div class="content">
<!-- The "somewhere else active" warning -->
<div class="disconnected" *ngIf="isJitsiActiveInAnotherTab && !isJitsiActive">
<span>{{ 'The audio conference is already running in your OpenSlides session.' | translate }}</span>
<span>{{
'The audio conference is already running in your OpenSlides session.' | translate
}}</span>
<button mat-button color="warn" (click)="forceStart()">
<span>{{ 'Reenter to audio conference' | translate }}</span>
</button>
@ -77,9 +101,6 @@
<span>{{ 'disconnected' | translate }}</span>
</div>
<!-- Hidden jitsy container -->
<div [ngStyle]="{ display: 'none' }" #jitsi></div>
<!-- user list -->
<div class="room-members" *ngIf="isJitsiActive">
<div class="member-list">
@ -128,17 +149,17 @@
</button>
</div>
<!-- Open in new tab -->
<!-- open dialog -->
<button
mat-icon-button
class="open-jitsi-in-tab"
color="accent"
(click)="openExternal()"
matTooltip="{{ 'Open Jitsi Meet in new tab' | translate }}"
[disabled]="isRoomPasswordProtected"
(click)="toggleConferenceDialog()"
[disabled]="!isJitsiActive"
matTooltip="{{ 'Show / Hide Jitsi' | translate }}"
>
<mat-icon>
open_in_new
fullscreen
</mat-icon>
</button>
</div>

View File

@ -1,3 +1,18 @@
.jitsi-dialog-hide {
display: none;
}
.jitsi-iframe-wrapper {
height: 70vh;
}
.minimize-jitsi-dialog-button {
margin-left: auto !important;
span {
line-height: initial;
}
}
.jitsi-integration {
.cast-shadow {
box-shadow: -3px -3px 10px 0px rgba(0, 0, 0, 0.2) !important;

View File

@ -1,4 +1,14 @@
import { Component, ElementRef, HostListener, OnDestroy, ViewChild } from '@angular/core';
import {
Component,
ElementRef,
HostListener,
OnDestroy,
OnInit,
TemplateRef,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Title } from '@angular/platform-browser';
import { StorageMap } from '@ngx-pwa/local-storage';
@ -11,6 +21,7 @@ import { OperatorService } from 'app/core/core-services/operator.service';
import { Deferred } from 'app/core/promises/deferred';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service';
import { largeDialogSettings } from 'app/shared/utils/dialog-settings';
declare var JitsiMeetExternalAPI: any;
@ -47,9 +58,10 @@ interface ConferenceMember {
@Component({
selector: 'os-jitsi',
templateUrl: './jitsi.component.html',
styleUrls: ['./jitsi.component.scss']
styleUrls: ['./jitsi.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class JitsiComponent extends BaseComponent implements OnDestroy {
export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
public enableJitsi: boolean;
private autoconnect: boolean;
private roomName: string;
@ -65,6 +77,11 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
@ViewChild('jitsi')
private jitsiNode: ElementRef;
@ViewChild('conferenceDialog', { static: true })
public conferenceDialog: TemplateRef<string>;
private confDialogRef: MatDialogRef<any>;
// JitsiMeet api object
private api: any | null;
@ -96,7 +113,7 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
}
private configOverwrite = {
startAudioOnly: true,
startAudioOnly: false,
// allows jitsi on mobile devices
disableDeepLinking: true,
startWithAudioMuted: true,
@ -111,15 +128,12 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
};
private interfaceConfigOverwrite = {
filmStripOnly: true,
INITIAL_TOOLBAR_TIMEOUT: 2000,
TOOLBAR_TIMEOUT: 400,
SHOW_JITSI_WATERMARK: false,
SHOW_WATERMARK_FOR_GUESTS: false,
DISABLE_VIDEO_BACKGROUND: true,
SHOW_JITSI_WATERMARK: true,
SHOW_WATERMARK_FOR_GUESTS: true,
INVITATION_POWERED_BY: false,
DISABLE_JOIN_LEAVE_NOTIFICATIONS: true,
TOOLBAR_BUTTONS: [],
SETTINGS_SECTIONS: []
DISABLE_PRESENCE_STATUS: true
};
public constructor(
@ -129,9 +143,18 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
private storageMap: StorageMap,
private userRepo: UserRepositoryService,
private constantsService: ConstantsService,
private configService: ConfigService
private configService: ConfigService,
private dialog: MatDialog
) {
super(titleService, translate);
}
public ngOnInit(): void {
this.confDialogRef = this.dialog.open(this.conferenceDialog, {
...largeDialogSettings,
panelClass: 'jitsi-dialog-hide',
hasBackdrop: false
});
this.setUp();
}
@ -307,6 +330,7 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
await this.deleteJitsiLock();
this.api.dispose();
this.api = undefined;
this.hideJitsiDialog();
}
this.isJoined = false;
this.isPasswortSet = false;
@ -330,6 +354,24 @@ export class JitsiComponent extends BaseComponent implements OnDestroy {
return `https://${this.jitsiDomain}/${this.roomName}`;
}
public toggleConferenceDialog(): void {
// there is no good way to detect the current classes in MatDialogRef or conferenceDialog.
// searching the global cdk-overlay-pane is the only thing which works
const pane = document.querySelector('.cdk-overlay-pane') as HTMLElement;
if (pane.classList.contains('jitsi-dialog-hide')) {
this.confDialogRef.removePanelClass('jitsi-dialog-hide');
} else {
this.confDialogRef.addPanelClass('jitsi-dialog-hide');
}
}
private hideJitsiDialog(): void {
const pane = document.querySelector('.cdk-overlay-pane') as HTMLElement;
if (!pane.classList.contains('jitsi-dialog-hide')) {
this.confDialogRef.addPanelClass('jitsi-dialog-hide');
}
}
public openExternal(): void {
this.stopJitsi();
window.open(this.getJitsiMeetUrl(), '_blank');

View File

@ -9,7 +9,7 @@ import {
ViewEncapsulation
} from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
@ -59,6 +59,8 @@ export class MediafileListComponent extends BaseListViewComponent<ViewMediafile>
*/
public fileToEdit: ViewMediafile;
private dialogRef: MatDialogRef<any>;
public newDirectoryForm: FormGroup;
public moveForm: FormGroup;
public directoryBehaviorSubject: BehaviorSubject<ViewMediafile[]>;
@ -334,9 +336,9 @@ export class MediafileListComponent extends BaseListViewComponent<ViewMediafile>
access_groups_id: [file.access_groups_id]
});
const dialogRef = this.dialog.open(this.fileEditDialog, infoDialogSettings);
this.dialogRef = this.dialog.open(this.fileEditDialog, infoDialogSettings);
dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
this.dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
if (event.key === 'Enter' && event.shiftKey && this.fileEditForm.valid) {
this.onSaveEditedFile(this.fileEditForm.value);
}
@ -349,7 +351,7 @@ export class MediafileListComponent extends BaseListViewComponent<ViewMediafile>
*/
public onSaveEditedFile(value: Partial<Mediafile>): void {
this.repo.update(value, this.fileToEdit).then(() => {
this.dialog.closeAll();
this.dialogRef.close();
}, this.raiseError);
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableDataSource } from '@angular/material/table';
import { Title } from '@angular/platform-browser';
@ -53,6 +53,8 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit
@ViewChild('editDialog', { static: true })
private editDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
/**
* helper for permission checks
*
@ -159,7 +161,7 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit
*/
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Enter') {
this.save();
@ -172,7 +174,7 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit
public save(): void {
this.repo
.update(this.editForm.value, this.selectedCategory)
.then(() => this.dialog.closeAll())
.then(() => this.dialogRef.close())
.catch(this.raiseError);
}
@ -185,7 +187,7 @@ export class CategoryDetailComponent extends BaseViewComponent implements OnInit
name: [this.selectedCategory.name, Validators.required]
});
this.dialog.open(this.editDialog, infoDialogSettings);
this.dialogRef = this.dialog.open(this.editDialog, infoDialogSettings);
}
/**

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@ -26,6 +26,8 @@ export class CategoryListComponent extends BaseListViewComponent<ViewCategory> i
@ViewChild('newCategoryDialog', { static: true })
private newCategoryDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
/**
* Holds the create form
*/
@ -101,8 +103,8 @@ export class CategoryListComponent extends BaseListViewComponent<ViewCategory> i
*/
public onPlusButton(): void {
this.createForm.reset();
const dialogRef = this.dialog.open(this.newCategoryDialog, infoDialogSettings);
dialogRef.afterClosed().subscribe(res => {
this.dialogRef = this.dialog.open(this.newCategoryDialog, infoDialogSettings);
this.dialogRef.afterClosed().subscribe(res => {
if (res) {
this.save();
}
@ -127,10 +129,10 @@ export class CategoryListComponent extends BaseListViewComponent<ViewCategory> i
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter') {
this.save();
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
@ -96,6 +96,8 @@ export class MotionBlockDetailComponent extends BaseListViewComponent<ViewMotion
@ViewChild('editDialog', { static: true })
private editDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
/**
* Constructor for motion block details
*
@ -197,7 +199,7 @@ export class MotionBlockDetailComponent extends BaseListViewComponent<ViewMotion
*/
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
}
@ -219,7 +221,7 @@ export class MotionBlockDetailComponent extends BaseListViewComponent<ViewMotion
public saveBlock(): void {
this.repo
.update(this.blockEditForm.value as MotionBlock, this.block)
.then(() => this.dialog.closeAll())
.then(() => this.dialogRef.close())
.catch(this.raiseError);
}
@ -232,9 +234,9 @@ export class MotionBlockDetailComponent extends BaseListViewComponent<ViewMotion
internal: [this.block.internal]
});
const dialogRef = this.dialog.open(this.editDialog, infoDialogSettings);
this.dialogRef = this.dialog.open(this.editDialog, infoDialogSettings);
dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
this.dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
if (event.key === 'Enter' && event.shiftKey) {
this.saveBlock();
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@ -31,6 +31,8 @@ export class MotionBlockListComponent extends BaseListViewComponent<ViewMotionBl
@ViewChild('newMotionBlockDialog', { static: true })
private newMotionBlockDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
/**
* Holds the create form
*/
@ -136,8 +138,8 @@ export class MotionBlockListComponent extends BaseListViewComponent<ViewMotionBl
*/
public onPlusButton(): void {
this.resetForm();
const dialogRef = this.dialog.open(this.newMotionBlockDialog, infoDialogSettings);
dialogRef.afterClosed().subscribe(res => {
this.dialogRef = this.dialog.open(this.newMotionBlockDialog, infoDialogSettings);
this.dialogRef.afterClosed().subscribe(res => {
if (res) {
this.save();
}
@ -167,11 +169,11 @@ export class MotionBlockListComponent extends BaseListViewComponent<ViewMotionBl
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' && event.shiftKey) {
this.save();
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Escape') {
this.resetForm();
this.dialog.closeAll();
this.dialogRef.close();
}
}
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@ -28,6 +28,8 @@ export class MotionCommentSectionListComponent extends BaseViewComponent impleme
@ViewChild('motionCommentDialog', { static: true })
private motionCommentDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
public currentComment: ViewMotionCommentSection | null;
/**
@ -90,10 +92,10 @@ export class MotionCommentSectionListComponent extends BaseViewComponent impleme
public onKeyDown(event: KeyboardEvent, viewSection?: ViewMotionCommentSection): void {
if (event.key === 'Enter' && event.shiftKey) {
this.save();
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
}
@ -107,8 +109,8 @@ export class MotionCommentSectionListComponent extends BaseViewComponent impleme
read_groups_id: commentSection ? commentSection.read_groups_id : [],
write_groups_id: commentSection ? commentSection.write_groups_id : []
});
const dialogRef = this.dialog.open(this.motionCommentDialog, infoDialogSettings);
dialogRef.afterClosed().subscribe(res => {
this.dialogRef = this.dialog.open(this.motionCommentDialog, infoDialogSettings);
this.dialogRef.afterClosed().subscribe(res => {
if (res) {
this.save();
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@ -26,6 +26,8 @@ export class StatuteParagraphListComponent extends BaseViewComponent implements
@ViewChild('statuteParagraphDialog', { static: true })
private statuteParagraphDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
private currentStatuteParagraph: ViewStatuteParagraph | null;
/**
@ -92,8 +94,8 @@ export class StatuteParagraphListComponent extends BaseViewComponent implements
text: paragraph.text
});
}
const dialogRef = this.dialog.open(this.statuteParagraphDialog, largeDialogSettings);
dialogRef.afterClosed().subscribe(res => {
this.dialogRef = this.dialog.open(this.statuteParagraphDialog, largeDialogSettings);
this.dialogRef.afterClosed().subscribe(res => {
if (res) {
this.save();
}
@ -146,10 +148,10 @@ export class StatuteParagraphListComponent extends BaseViewComponent implements
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' && event.shiftKey) {
this.save();
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@ -31,6 +31,8 @@ export class TagListComponent extends BaseListViewComponent<ViewTag> implements
@ViewChild('tagDialog', { static: true })
private tagDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
public tagForm: FormGroup = this.formBuilder.group({
name: ['', [Validators.required]]
});
@ -95,8 +97,8 @@ export class TagListComponent extends BaseListViewComponent<ViewTag> implements
this.currentTag = tag;
this.tagForm.reset();
this.tagForm.get('name').setValue(this.currentTag ? this.currentTag.name : '');
const dialogRef = this.dialog.open(this.tagDialog, infoDialogSettings);
dialogRef.afterClosed().subscribe(res => {
this.dialogRef = this.dialog.open(this.tagDialog, infoDialogSettings);
this.dialogRef.afterClosed().subscribe(res => {
if (res) {
this.save();
}
@ -138,10 +140,10 @@ export class TagListComponent extends BaseListViewComponent<ViewTag> implements
public onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' && event.shiftKey) {
this.save();
this.dialog.closeAll();
this.dialogRef.close();
}
if (event.key === 'Escape') {
this.dialog.closeAll();
this.dialogRef.close();
}
}
}

View File

@ -1,6 +1,6 @@
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTableDataSource } from '@angular/material/table';
import { Title } from '@angular/platform-browser';
@ -58,6 +58,8 @@ export class GroupListComponent extends BaseViewComponent implements OnInit {
@ViewChild('groupEditDialog', { static: true })
public groupEditDialog: TemplateRef<string>;
private dialogRef: MatDialogRef<any>;
public get appPermissions(): AppPermissions[] {
return this.repo.appPermissions;
}
@ -98,9 +100,9 @@ export class GroupListComponent extends BaseViewComponent implements OnInit {
name: [name, Validators.required]
});
const dialogRef = this.dialog.open(this.groupEditDialog, infoDialogSettings);
this.dialogRef = this.dialog.open(this.groupEditDialog, infoDialogSettings);
dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
this.dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => {
if (event.key === 'Enter' && event.shiftKey && this.groupForm.valid) {
this.saveGroup(this.groupForm.value);
}
@ -141,7 +143,7 @@ export class GroupListComponent extends BaseViewComponent implements OnInit {
* Cancel the editing
*/
public cancelEditing(): void {
this.dialog.closeAll();
this.dialogRef.close();
this.newGroup = false;
this.editGroup = false;
this.selectedGroup = null;