/* eslint-disable max-len */ "use strict"; import React, { Component } from "react"; import ReactDOM from "react-dom"; import defaultOptions from "../../defaultOptions"; import Bridge from "./Bridge"; import EditableList from "./EditableList"; import bridge, { BridgeInfo, BridgeTimedOutError } from "../../lib/bridge"; import logger from "../../lib/logger"; import options, { Options } from "../../lib/options"; import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils"; import { ReceiverSelectorType } from "../../background/receiverSelector"; const _ = browser.i18n.getMessage; // macOS styles browser.runtime.getPlatformInfo() .then(platformInfo => { const link = document.createElement("link"); link.rel = "stylesheet"; switch (platformInfo.os) { case "mac": { link.href = "styles/mac.css"; break; } } if (link.href) { document.head.appendChild(link); } }); function getInputValue(input: HTMLInputElement) { switch (input.type) { case "checkbox": return input.checked; case "number": return parseFloat(input.value); default: return input.value; } } interface OptionsAppProps {} interface OptionsAppState { hasLoaded: boolean; bridgeLoading: boolean; bridgeLoadingTimedOut: boolean; isFormValid: boolean; hasSaved: boolean; options?: Options; bridgeInfo?: BridgeInfo; platform?: string; } class OptionsApp extends Component< OptionsAppProps, OptionsAppState> { private form: (HTMLFormElement | null) = null; state: OptionsAppState = { hasLoaded: false , bridgeLoading: true , bridgeLoadingTimedOut: false , isFormValid: true , hasSaved: false }; constructor(props: OptionsAppProps) { super(props); this.handleReset = this.handleReset.bind(this); this.handleFormSubmit = this.handleFormSubmit.bind(this); this.handleFormChange = this.handleFormChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this); this.handleWhitelistChange = this.handleWhitelistChange.bind(this); this.handleReceiverSelectorTypeChange = this.handleReceiverSelectorTypeChange.bind(this); this.getWhitelistItemPatternError = this.getWhitelistItemPatternError.bind(this); } public async componentDidMount() { this.setState({ hasLoaded: true , options: await options.getAll() , platform: (await browser.runtime.getPlatformInfo()).os }); // Update options data if changed whilst page is open options.addEventListener("changed", async () => { this.setState({ options: await options.getAll() }); }); try { const bridgeInfo = await bridge.getInfo(); this.setState({ bridgeInfo , bridgeLoading: false }); } catch (err) { logger.error("Failed to fetch bridge/platform info."); if (err instanceof BridgeTimedOutError) { this.setState({ bridgeLoading: false , bridgeLoadingTimedOut: true }); } else { this.setState({ bridgeLoading: false }); } } } public render() { if (!this.state.hasLoaded) { return; } return (
{ this.form = form; }} onSubmit={ this.handleFormSubmit } onChange={ this.handleFormChange }>

{ _("optionsMediaCategoryName") }

{ _("optionsMediaCategoryDescription") }


{ _("optionsMirroringCategoryName") }

{ _("optionsMirroringCategoryDescription") }

{ _("optionsReceiverSelectorCategoryName") }

{ _("optionsReceiverSelectorCategoryDescription") }

{ this.state.platform === "mac" && }

{ _("optionsUserAgentWhitelistCategoryName") }

{ _("optionsUserAgentWhitelistCategoryDescription") }

{ _("optionsUserAgentWhitelistContent") }
{ this.state.options?.userAgentWhitelist && }
{ this.state.hasSaved && _("optionsSaved") }
); } private handleReset() { this.setState({ options: { ...defaultOptions } }); } private async handleFormSubmit(ev: React.FormEvent) { ev.preventDefault(); this.form?.reportValidity(); try { if (this.state.options) { await options.setAll(this.state.options); this.setState({ hasSaved: true }, () => { window.setTimeout(() => { this.setState({ hasSaved: false }); }, 1000); }); } } catch (err) { logger.error("Failed to save options"); } } private handleFormChange(ev: React.FormEvent) { ev.preventDefault(); const isFormValid = this.form?.checkValidity(); if (isFormValid !== undefined) { this.setState({ isFormValid }); } } private handleInputChange(ev: React.ChangeEvent) { this.setState(currentState => { if (currentState.options) { currentState.options[ev.target.name] = getInputValue(ev.target); } return currentState; }); } private handleReceiverSelectorTypeChange( ev: React.ChangeEvent) { this.setState(currentState => { if (currentState.options) { currentState.options[ev.target.name] = parseInt(ev.target.value); } return currentState; }); } private handleWhitelistChange(whitelist: string[]) { this.setState(currentState => { if (currentState.options) { currentState.options.userAgentWhitelist = whitelist; } return currentState; }); } private getWhitelistItemPatternError(info: string): string { return _("optionsUserAgentWhitelistInvalidMatchPattern", info); } } ReactDOM.render( , document.querySelector("#root"));