Merge pull request #5394 from tsiegleauq/jitsi-iframe-dialog

Show Jitsi iFrame in Dialog
This commit is contained in:
Emanuel Schütze 2020-06-04 16:37:01 +02:00 committed by GitHub
commit 3109337004
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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;