import {Event, FrameEventDispatcher} from "@enhavo/app/frame/FrameEventDispatcher";
import {Frame} from '@enhavo/app/frame/Frame';
import generateId from "uuid/v4";
export class FrameStack
{
private frames: Frame[] = [];
constructor(
private eventDispatcher: FrameEventDispatcher
) {
}
public async setFrames(options: object[])
{
for (let frame of this.frames) {
await this.removeFrame(frame, true);
}
for (let frameOptions of options) {
await this.addFrame(frameOptions);
}
}
public async updateFrames(frames: Frame[]|object[])
{
for (let updateFrame of frames) {
let found = false;
for (let frame of this.frames) {
if ((updateFrame as Frame).id == frame.id) {
Object.assign(frame, updateFrame);
found = true;
break;
}
}
if (found === false) {
await this.addFrame(updateFrame);
}
}
for (let frame of this.frames) {
let found = false;
for (let updateFrame of frames) {
if ((updateFrame as Frame).id == frame.id) {
found = true;
break;
}
}
if (found === false) {
await this.removeFrame(frame);
}
}
}
public async addFrame(options: object): Promise
{
if (options['key'] !== undefined && options['parent'] !== undefined) {
for (let frame of this.frames) {
if (frame.key == options['key'] && frame.keepAlive) {
this.activateKeepAliveFrame(frame, options)
this.eventDispatcher.dispatch(new FrameAdded(frame));
return;
} else if (frame.parent == options['parent'] && frame.key == options['key']) {
await this.removeFrame(frame);
//options.width = frame.width;
break;
}
}
}
let frame = this.createFrame(options);
if (options['wait'] === false) {
frame.loaded = true;
}
this.frames.push(frame);
this.eventDispatcher.dispatch(new FrameAdded(frame));
return frame;
}
private activateKeepAliveFrame(frame: Frame, options: object): void
{
frame.parent = options['parent'];
frame.display = true;
frame.minimize = false;
frame.label = options['label'] ? options['label'] : frame.label;
frame.parameters = options['parameters'];
frame.minimize = false;
frame.position = options['position'];
}
private createFrame(options: object): Frame
{
const frame = new Frame();
Object.assign(frame, options);
if (!frame.id) {
frame.id = this.generateId();
}
const self = this;
return new Proxy(frame, {
set(target, prop, value) {
target[prop] = value;
self.eventDispatcher.dispatch(new FrameUpdated(frame));
return true;
},
});
}
public async clearFrames(force: boolean = false): Promise
{
for (let frame of this.frames) {
let success = await this.removeFrame(frame, force);
if (success === false) {
return false;
}
}
return true;
}
public getFrames(parentId: string = undefined): Frame[]
{
let frames = [];
for (let frame of this.frames) {
if (!frame.removed && frame.display) {
if ((parentId != undefined && frame.parent == parentId) || parentId == undefined) {
frames.push(frame);
}
}
}
return frames;
}
public getFrame(id: string): Frame
{
for (let frame of this.getFrames()) {
if(frame.id == id) {
return frame;
}
}
return null;
}
public async removeFrame(frame: Frame, force = false): Promise
{
let success: boolean = true;
if (frame.keepAlive) {
frame.display = false;
} else if (frame.closeable || force) {
frame.removed = true;
} else if (!frame.closeable) {
success = await this.eventDispatcher.request(new FrameRemoveRequest(frame)) as boolean;
if (success) {
frame.removed = true
} else {
success = false;
}
}
/**
* We can't delete frame with splice, because the vue components will unmount and mount again because we
* provide a key in v-for and this will reload the iframe, to fix this issue, the best practise is to delete only
* the last element. Other elements will just hide until it is the last of the array.
*/
while (this.frames.length > 0 && this.frames[this.frames.length-1].removed) {
this.frames.pop();
}
this.eventDispatcher.dispatch(new FrameRemoved(frame));
return success;
}
public getRenderFrames()
{
return this.frames;
}
private generateId(): string
{
return generateId();
}
}
export class FrameRemoveRequest extends Event
{
constructor(
public frame: Frame
)
{
super('frame_remove_request');
}
}
export class FrameAdded extends Event
{
constructor(
public frame: Frame
)
{
super('frame_added');
}
}
export class FrameRemoved extends Event
{
constructor(
public frame: Frame
)
{
super('frame_removed');
}
}
export class FrameUpdated extends Event
{
constructor(
public frame: Frame
)
{
super('frame_updated');
}
}