Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

244 lines
7.1 KiB

/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, ViewChild } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogModel, DialogService, disabled$, StatefulComponent, Types, value$ } from '@app/framework';
import { AppsState, AssetDto, computeEditorUrl } from '@app/shared';
@Component({
selector: 'sqx-iframe-editor[context][formField][formIndex][formValue][formControlBinding]',
styleUrls: ['./iframe-editor.component.scss'],
templateUrl: './iframe-editor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class IFrameEditorComponent extends StatefulComponent<{}> implements OnChanges, OnDestroy {
private value: any;
private isInitialized = false;
private isDisabled = false;
private assetsCorrelationId: any;
@ViewChild('iframe', { static: false })
public iframe!: ElementRef<HTMLIFrameElement>;
@Input()
public context: any = {};
@Input()
public formValue!: any;
@Input()
public formField = '';
@Input()
public formIndex?: number | null;
@Input()
public language?: string | null;
@Input()
public formControlBinding!: AbstractControl;
@Input()
public set disabled(value: boolean | undefined | null) {
this.updatedisabled(value === true);
}
@Input()
public set url(value: string | undefined | null) {
this.computedUrl = computeEditorUrl(value, this.appsState.snapshot.selectedSettings);
}
public computedUrl = '';
public assetsDialog = new DialogModel();
constructor(changeDetector: ChangeDetectorRef,
private readonly appsState: AppsState,
private readonly dialogs: DialogService,
private readonly renderer: Renderer2,
private readonly router: Router,
) {
super(changeDetector, {});
}
public ngOnDestroy() {
super.ngOnDestroy();
}
public ngOnChanges(changes: SimpleChanges) {
if (changes['formValue']) {
this.sendFormValue();
}
if (changes['language']) {
this.sendLanguage();
}
if (changes['formIndex']) {
this.sendMoved();
}
if (changes['formControlBinding']) {
this.unsubscribeAll();
const control = this.formControlBinding;
if (control) {
this.own(value$(control)
.subscribe(value => {
this.updateValue(value);
}));
this.own(disabled$(control)
.subscribe(isDisabled => {
this.updatedisabled(isDisabled);
}));
}
}
}
@HostListener('window:message', ['$event'])
public onWindowMessage(event: MessageEvent) {
if (event.source === this.iframe.nativeElement.contentWindow) {
const { type } = event.data;
if (type === 'started') {
this.isInitialized = true;
this.sendInit();
this.sendFormValue();
this.sendLanguage();
this.sendDisabled();
this.sendMoved();
this.sendValue();
} else if (type === 'resize') {
const { height } = event.data;
this.renderer.setStyle(this.iframe.nativeElement, 'height', `${height}px`);
} else if (type === 'navigate') {
const { url } = event.data;
this.router.navigateByUrl(url);
} else if (type === 'valueChanged') {
const { value } = event.data;
if (!Types.equals(this.value, value)) {
this.value = value;
this.formControlBinding?.reset(value);
}
} else if (type === 'touched') {
this.formControlBinding?.markAsTouched();
} else if (type === 'notifyInfo') {
const { text } = event.data;
if (Types.isString(text)) {
this.dialogs.notifyInfo(text);
}
} else if (type === 'notifyError') {
const { text } = event.data;
if (Types.isString(text)) {
this.dialogs.notifyError(text);
}
} else if (type === 'confirm') {
const { text, title, correlationId } = event.data;
if (Types.isString(text) && Types.isString(title) && correlationId) {
this.dialogs.confirm(title, text).subscribe(result => {
this.sendMessage('confirmResult', { correlationId, result });
});
}
} else if (type === 'pickAssets') {
const { correlationId } = event.data;
if (correlationId) {
this.assetsCorrelationId = correlationId;
this.assetsDialog.show();
}
}
this.detectChanges();
}
}
public pickAssets(assets: ReadonlyArray<AssetDto>) {
if (this.assetsCorrelationId) {
this.sendMessage('pickAssetsResult', { correlationId: this.assetsCorrelationId, result: assets });
this.assetsCorrelationId = null;
}
this.assetsDialog.hide();
}
public updateValue(obj: any) {
if (!Types.equals(obj, this.value)) {
this.value = obj;
this.sendValue();
}
}
public updatedisabled(isDisabled: boolean) {
if (isDisabled !== this.isDisabled) {
this.isDisabled === isDisabled;
this.sendDisabled();
}
}
public reset() {
this.sendInit();
}
private sendInit() {
this.sendMessage('init', { context: { ...this.context || {}, field: this.formField } });
}
private sendValue() {
this.sendMessage('valueChanged', { value: this.value });
}
private sendDisabled() {
this.sendMessage('disabled', { isDisabled: this.isDisabled });
}
private sendFormValue() {
if (this.formValue) {
this.sendMessage('formValueChanged', { formValue: this.formValue });
}
}
private sendLanguage() {
if (this.language) {
this.sendMessage('languageChanged', { language: this.language });
}
}
private sendMoved() {
if (Types.isNumber(this.formIndex)) {
this.sendMessage('moved', { index: this.formIndex });
}
}
private sendMessage(type: string, payload: any) {
if (!this.iframe?.nativeElement) {
return;
}
const iframe = this.iframe.nativeElement;
if (this.isInitialized && iframe.contentWindow && Types.isFunction(iframe.contentWindow.postMessage)) {
const message = { type, ...payload };
iframe.contentWindow.postMessage(message, '*');
}
}
}