mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-10 17:49:58 +00:00
195 lines
5.6 KiB
TypeScript
195 lines
5.6 KiB
TypeScript
"use strict";
|
|
|
|
import ReceiverSelector, {
|
|
ReceiverSelectorEvents
|
|
, ReceiverSelectorMediaType } from "./ReceiverSelector";
|
|
|
|
import options from "../lib/options";
|
|
|
|
import { TypedEventTarget } from "../lib/typedEvents";
|
|
import { getWindowCenteredProps } from "../lib/utils";
|
|
import { Message, Receiver } from "../types";
|
|
|
|
|
|
export default class PopupReceiverSelector
|
|
extends TypedEventTarget<ReceiverSelectorEvents>
|
|
implements ReceiverSelector {
|
|
|
|
private windowId: number;
|
|
private openerWindowId: number;
|
|
|
|
private messagePort: browser.runtime.Port;
|
|
private messagePortDisconnected: boolean;
|
|
|
|
private receivers: Receiver[];
|
|
private defaultMediaType: ReceiverSelectorMediaType;
|
|
private availableMediaTypes: ReceiverSelectorMediaType;
|
|
|
|
private wasReceiverSelected: boolean = false;
|
|
|
|
private _isOpen: boolean = false;
|
|
|
|
|
|
constructor () {
|
|
super();
|
|
|
|
// Bind methods to pass to addListener
|
|
this.onPopupMessage = this.onPopupMessage.bind(this);
|
|
this.onWindowsRemoved = this.onWindowsRemoved.bind(this);
|
|
this.onWindowsFocusChanged = this.onWindowsFocusChanged.bind(this);
|
|
|
|
browser.windows.onRemoved.addListener(this.onWindowsRemoved);
|
|
|
|
/**
|
|
* Handle incoming message channel connection from popup
|
|
* window script.
|
|
*/
|
|
browser.runtime.onConnect.addListener(port => {
|
|
if (port.name !== "popup") {
|
|
return;
|
|
}
|
|
|
|
// Disconnect existing port
|
|
if (this.messagePort) {
|
|
this.messagePort.disconnect();
|
|
}
|
|
|
|
this.messagePort = port;
|
|
this.messagePort.onMessage.addListener(this.onPopupMessage);
|
|
this.messagePort.onDisconnect.addListener(() => {
|
|
this.messagePortDisconnected = true;
|
|
});
|
|
|
|
this.messagePort.postMessage({
|
|
subject: "popup:/populateReceiverList"
|
|
, data: {
|
|
receivers: this.receivers
|
|
, defaultMediaType: this.defaultMediaType
|
|
, availableMediaTypes: this.availableMediaTypes
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
get isOpen () {
|
|
return this._isOpen;
|
|
}
|
|
|
|
public async open (
|
|
receivers: Receiver[]
|
|
, defaultMediaType: ReceiverSelectorMediaType
|
|
, availableMediaTypes: ReceiverSelectorMediaType): Promise<void> {
|
|
|
|
// If popup already exists, close it
|
|
if (this.windowId) {
|
|
await browser.windows.remove(this.windowId);
|
|
}
|
|
|
|
this.receivers = receivers;
|
|
this.defaultMediaType = defaultMediaType;
|
|
this.availableMediaTypes = availableMediaTypes;
|
|
|
|
// Current window to base centered position on
|
|
const openerWindow = await browser.windows.getCurrent();
|
|
const centeredProps = getWindowCenteredProps(openerWindow, 350, 200);
|
|
|
|
const popup = await browser.windows.create({
|
|
url: "ui/popup/index.html"
|
|
, type: "popup"
|
|
, ...centeredProps
|
|
});
|
|
|
|
this._isOpen = true;
|
|
|
|
this.windowId = popup.id;
|
|
this.openerWindowId = openerWindow.id;
|
|
|
|
// Size/position not set correctly on creation (bug?)
|
|
await browser.windows.update(this.windowId, {
|
|
...centeredProps
|
|
});
|
|
|
|
|
|
const closeIfFocusLost = await options.get(
|
|
"receiverSelectorCloseIfFocusLost");
|
|
|
|
if (closeIfFocusLost) {
|
|
// Add focus listener
|
|
browser.windows.onFocusChanged.addListener(
|
|
this.onWindowsFocusChanged);
|
|
}
|
|
}
|
|
|
|
public async close (): Promise<void> {
|
|
if (this.windowId) {
|
|
await browser.windows.remove(this.windowId);
|
|
}
|
|
|
|
this._isOpen = false;
|
|
|
|
if (this.messagePort && !this.messagePortDisconnected) {
|
|
this.messagePort.disconnect();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles popup messages.
|
|
*/
|
|
private onPopupMessage (message: Message) {
|
|
switch (message.subject) {
|
|
case "receiverSelector:/selected": {
|
|
this.wasReceiverSelected = true;
|
|
this.dispatchEvent(new CustomEvent("selected", {
|
|
detail: message.data
|
|
}));
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles cancellation state where the popup window is closed
|
|
* before a receiver is selected.
|
|
*/
|
|
private onWindowsRemoved (windowId: number) {
|
|
// Only care about popup window
|
|
if (windowId !== this.windowId) {
|
|
return;
|
|
}
|
|
|
|
browser.windows.onFocusChanged.removeListener(
|
|
this.onWindowsFocusChanged);
|
|
|
|
if (!this.wasReceiverSelected) {
|
|
this.dispatchEvent(new CustomEvent("cancelled"));
|
|
}
|
|
|
|
// Cleanup
|
|
this.windowId = null;
|
|
this.openerWindowId = null;
|
|
this.messagePort = null;
|
|
this.receivers = null;
|
|
this.defaultMediaType = null;
|
|
this.wasReceiverSelected = false;
|
|
}
|
|
|
|
/**
|
|
* Closes popup window if another browser window is brought
|
|
* into focus. Doesn't apply if no window is focused
|
|
* `WINDOW_ID_NONE` or if the popup window is re-focused.
|
|
*/
|
|
private onWindowsFocusChanged (windowId: number) {
|
|
if (windowId !== browser.windows.WINDOW_ID_NONE
|
|
&& windowId !== this.windowId) {
|
|
|
|
// Only run once
|
|
browser.windows.onFocusChanged.removeListener(
|
|
this.onWindowsFocusChanged);
|
|
|
|
browser.windows.remove(this.windowId);
|
|
}
|
|
}
|
|
}
|