mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-13 02:49:58 +00:00
Add lib/options module for typed/easier options storage access
This commit is contained in:
@@ -10,10 +10,13 @@ export interface Options {
|
|||||||
mirroringAppId: string;
|
mirroringAppId: string;
|
||||||
userAgentWhitelistEnabled: boolean;
|
userAgentWhitelistEnabled: boolean;
|
||||||
userAgentWhitelist: string[];
|
userAgentWhitelist: string[];
|
||||||
|
|
||||||
|
[key: string]: Options[keyof Options];
|
||||||
}
|
}
|
||||||
|
|
||||||
const options: Options = {
|
const options: Options = {
|
||||||
mediaEnabled: true
|
bridgeApplicationName: APPLICATION_NAME
|
||||||
|
, mediaEnabled: true
|
||||||
, mediaSyncElement: false
|
, mediaSyncElement: false
|
||||||
, mediaStopOnUnload: false
|
, mediaStopOnUnload: false
|
||||||
, localMediaEnabled: true
|
, localMediaEnabled: true
|
||||||
|
|||||||
54
ext/src/lib/options.ts
Normal file
54
ext/src/lib/options.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { Options } from "../defaultOptions";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches `options` key from storage and returns it as
|
||||||
|
* Options interface type.
|
||||||
|
*/
|
||||||
|
async function getAll (): Promise<Options> {
|
||||||
|
const { options }: { options: Options } =
|
||||||
|
await browser.storage.sync.get("options");
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes Options object and sets to `options` storage key.
|
||||||
|
* Returns storage promise.
|
||||||
|
*/
|
||||||
|
async function setAll (options: Options): Promise<void> {
|
||||||
|
return browser.storage.sync.set({ options });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets specific option from storage and returns it as its
|
||||||
|
* type from Options interface type.
|
||||||
|
*/
|
||||||
|
async function get<T extends keyof Options> (name: T): Promise<Options[T]> {
|
||||||
|
const options = await getAll();
|
||||||
|
|
||||||
|
if (options.hasOwnProperty(name)) {
|
||||||
|
return options[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets specific option to storage. Returns storage
|
||||||
|
* promise.
|
||||||
|
*/
|
||||||
|
async function set<T extends keyof Options> (
|
||||||
|
name: T
|
||||||
|
, value: Options[T]): Promise<void> {
|
||||||
|
|
||||||
|
const options = await getAll();
|
||||||
|
options[name] = value;
|
||||||
|
return setAll(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
get, getAll
|
||||||
|
, set, setAll
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import semver from "semver";
|
|||||||
import defaultOptions, { Options } from "./defaultOptions";
|
import defaultOptions, { Options } from "./defaultOptions";
|
||||||
import getBridgeInfo from "./lib/getBridgeInfo";
|
import getBridgeInfo from "./lib/getBridgeInfo";
|
||||||
import messageRouter from "./lib/messageRouter";
|
import messageRouter from "./lib/messageRouter";
|
||||||
|
import options from "./lib/options";
|
||||||
import nativeMessaging from "./lib/nativeMessaging";
|
import nativeMessaging from "./lib/nativeMessaging";
|
||||||
|
|
||||||
import { getChromeUserAgent } from "./lib/userAgents";
|
import { getChromeUserAgent } from "./lib/userAgents";
|
||||||
@@ -29,17 +30,13 @@ browser.runtime.onInstalled.addListener(async details => {
|
|||||||
switch (details.reason) {
|
switch (details.reason) {
|
||||||
// Set default options
|
// Set default options
|
||||||
case "install": {
|
case "install": {
|
||||||
await browser.storage.sync.set({
|
await options.setAll(defaultOptions);
|
||||||
options: defaultOptions
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set newly added options
|
// Set newly added options
|
||||||
case "update": {
|
case "update": {
|
||||||
const { options: existingOptions }
|
const existingOptions = await options.getAll();
|
||||||
= await browser.storage.sync.get("options");
|
|
||||||
|
|
||||||
const newOptions: Partial<Options> = {};
|
const newOptions: Partial<Options> = {};
|
||||||
|
|
||||||
// Find options not already in storage
|
// Find options not already in storage
|
||||||
@@ -50,11 +47,9 @@ browser.runtime.onInstalled.addListener(async details => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update storage with default values of new options
|
// Update storage with default values of new options
|
||||||
await browser.storage.sync.set({
|
options.setAll({
|
||||||
options: {
|
|
||||||
...existingOptions
|
...existingOptions
|
||||||
, ...newOptions
|
, ...newOptions
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -87,17 +82,17 @@ const mediaCastTargetUrlPatterns = new Set([
|
|||||||
const LOCAL_MEDIA_URL_PATTERN = "file://*/*";
|
const LOCAL_MEDIA_URL_PATTERN = "file://*/*";
|
||||||
|
|
||||||
async function createMenus () {
|
async function createMenus () {
|
||||||
const { options } = await browser.storage.sync.get("options");
|
const opts = await options.getAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If options aren't set or menus have already been
|
* If options aren't set or menus have already been
|
||||||
* created, return.
|
* created, return.
|
||||||
*/
|
*/
|
||||||
if (!options || mirrorCastMenuId || mediaCastMenuId) {
|
if (!opts || mirrorCastMenuId || mediaCastMenuId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.localMediaEnabled) {
|
if (opts.localMediaEnabled) {
|
||||||
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
|
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +102,7 @@ async function createMenus () {
|
|||||||
, id: "contextCastMedia"
|
, id: "contextCastMedia"
|
||||||
, targetUrlPatterns: Array.from(mediaCastTargetUrlPatterns)
|
, targetUrlPatterns: Array.from(mediaCastTargetUrlPatterns)
|
||||||
, title: _("contextCast")
|
, title: _("contextCast")
|
||||||
, visible: options.mediaEnabled
|
, visible: opts.mediaEnabled
|
||||||
});
|
});
|
||||||
|
|
||||||
// Screen/Tab mirroring "Cast..." context menu item
|
// Screen/Tab mirroring "Cast..." context menu item
|
||||||
@@ -115,7 +110,7 @@ async function createMenus () {
|
|||||||
contexts: [ "browser_action", "page", "tools_menu" ]
|
contexts: [ "browser_action", "page", "tools_menu" ]
|
||||||
, id: "contextCast"
|
, id: "contextCast"
|
||||||
, title: _("contextCast")
|
, title: _("contextCast")
|
||||||
, visible: options.mirroringEnabled
|
, visible: opts.mirroringEnabled
|
||||||
|
|
||||||
// Mirroring doesn't work from local files
|
// Mirroring doesn't work from local files
|
||||||
, documentUrlPatterns: [
|
, documentUrlPatterns: [
|
||||||
@@ -317,7 +312,6 @@ let currentUAString: string;
|
|||||||
async function onBeforeSendHeaders (
|
async function onBeforeSendHeaders (
|
||||||
details: { requestHeaders?: browser.webRequest.HttpHeaders }) {
|
details: { requestHeaders?: browser.webRequest.HttpHeaders }) {
|
||||||
|
|
||||||
const { options } = await browser.storage.sync.get("options");
|
|
||||||
const { os } = await browser.runtime.getPlatformInfo();
|
const { os } = await browser.runtime.getPlatformInfo();
|
||||||
|
|
||||||
// Create Chrome UA from platform info on first run
|
// Create Chrome UA from platform info on first run
|
||||||
@@ -353,10 +347,10 @@ async function onBeforeSendHeaders (
|
|||||||
* Updates any extension state based on options changes.
|
* Updates any extension state based on options changes.
|
||||||
*/
|
*/
|
||||||
async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
|
async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
|
||||||
const { options } = await browser.storage.sync.get("options");
|
const opts = await options.getAll();
|
||||||
|
|
||||||
// If options aren't set yet, return
|
// If options aren't set yet, return
|
||||||
if (!options) {
|
if (!opts) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,8 +361,8 @@ async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
|
|||||||
function register_userAgentWhitelist () {
|
function register_userAgentWhitelist () {
|
||||||
browser.webRequest.onBeforeSendHeaders.addListener(
|
browser.webRequest.onBeforeSendHeaders.addListener(
|
||||||
onBeforeSendHeaders
|
onBeforeSendHeaders
|
||||||
, { urls: options.userAgentWhitelistEnabled
|
, { urls: opts.userAgentWhitelistEnabled
|
||||||
? options.userAgentWhitelist
|
? opts.userAgentWhitelist
|
||||||
: [] }
|
: [] }
|
||||||
, [ "blocking", "requestHeaders" ]);
|
, [ "blocking", "requestHeaders" ]);
|
||||||
}
|
}
|
||||||
@@ -394,18 +388,18 @@ async function onOptionsUpdated (alteredOptions?: Array<(keyof Options)>) {
|
|||||||
|
|
||||||
if (alteredOptions.includes("mirroringEnabled")) {
|
if (alteredOptions.includes("mirroringEnabled")) {
|
||||||
browser.menus.update(mirrorCastMenuId, {
|
browser.menus.update(mirrorCastMenuId, {
|
||||||
visible: options.mirroringEnabled
|
visible: opts.mirroringEnabled
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alteredOptions.includes("mediaEnabled")) {
|
if (alteredOptions.includes("mediaEnabled")) {
|
||||||
browser.menus.update(mediaCastMenuId, {
|
browser.menus.update(mediaCastMenuId, {
|
||||||
visible: options.mediaEnabled
|
visible: opts.mediaEnabled
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alteredOptions.includes("localMediaEnabled")) {
|
if (alteredOptions.includes("localMediaEnabled")) {
|
||||||
if (options.localMediaEnabled) {
|
if (opts.localMediaEnabled) {
|
||||||
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
|
mediaCastTargetUrlPatterns.add(LOCAL_MEDIA_URL_PATTERN);
|
||||||
} else {
|
} else {
|
||||||
mediaCastTargetUrlPatterns.delete(LOCAL_MEDIA_URL_PATTERN);
|
mediaCastTargetUrlPatterns.delete(LOCAL_MEDIA_URL_PATTERN);
|
||||||
@@ -448,7 +442,7 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|
|||||||
|| info.menuItemId === mediaCastMenuId) {
|
|| info.menuItemId === mediaCastMenuId) {
|
||||||
|
|
||||||
const { frameId } = info;
|
const { frameId } = info;
|
||||||
const { options } = await browser.storage.sync.get("options");
|
const mirroringAppId = await options.get("mirroringAppId");
|
||||||
|
|
||||||
// Load cast setup script
|
// Load cast setup script
|
||||||
await browser.tabs.executeScript(tab.id, {
|
await browser.tabs.executeScript(tab.id, {
|
||||||
@@ -466,7 +460,7 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|
|||||||
var selectedMedia = ${info.pageUrl
|
var selectedMedia = ${info.pageUrl
|
||||||
? ReceiverSelectorMediaType.Tab
|
? ReceiverSelectorMediaType.Tab
|
||||||
: ReceiverSelectorMediaType.Screen};
|
: ReceiverSelectorMediaType.Screen};
|
||||||
var FX_CAST_RECEIVER_APP_ID = "${options.mirroringAppId}";
|
var FX_CAST_RECEIVER_APP_ID = "${mirroringAppId}";
|
||||||
`
|
`
|
||||||
, frameId
|
, frameId
|
||||||
});
|
});
|
||||||
@@ -513,16 +507,13 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|
|||||||
|
|
||||||
if (info.parentMenuItemId === whitelistMenuId) {
|
if (info.parentMenuItemId === whitelistMenuId) {
|
||||||
const matchPattern = whitelistMenuMap.get(info.menuItemId);
|
const matchPattern = whitelistMenuMap.get(info.menuItemId);
|
||||||
const options: Options =
|
const userAgentWhitelist = await options.get("userAgentWhitelist");
|
||||||
(await browser.storage.sync.get("options")).options;
|
|
||||||
|
|
||||||
// Add to whitelist
|
// Add to whitelist
|
||||||
options.userAgentWhitelist.push(matchPattern);
|
userAgentWhitelist.push(matchPattern);
|
||||||
|
|
||||||
// Update options
|
// Update options
|
||||||
await browser.storage.sync.set({
|
await options.set("userAgentWhitelist", userAgentWhitelist)
|
||||||
options
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Bridge from "./Bridge";
|
|||||||
import EditableList from "./EditableList";
|
import EditableList from "./EditableList";
|
||||||
|
|
||||||
import getBridgeInfo, { BridgeInfo } from "../../lib/getBridgeInfo";
|
import getBridgeInfo, { BridgeInfo } from "../../lib/getBridgeInfo";
|
||||||
|
import options from "../../lib/options";
|
||||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils";
|
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/utils";
|
||||||
|
|
||||||
|
|
||||||
@@ -77,11 +78,9 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async componentDidMount () {
|
public async componentDidMount () {
|
||||||
const { options } = await browser.storage.sync.get("options");
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
hasLoaded: true
|
hasLoaded: true
|
||||||
, options
|
, options: await options.getAll()
|
||||||
});
|
});
|
||||||
|
|
||||||
const bridgeInfo = await getBridgeInfo();
|
const bridgeInfo = await getBridgeInfo();
|
||||||
@@ -259,14 +258,6 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set stored option values to current state
|
|
||||||
*/
|
|
||||||
private setStorage () {
|
|
||||||
return browser.storage.sync.set({
|
|
||||||
options: this.state.options
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleReset () {
|
private handleReset () {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -280,15 +271,12 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
|||||||
this.form.reportValidity();
|
this.form.reportValidity();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { options: oldOptions }
|
const oldOpts = await options.getAll();
|
||||||
= await browser.storage.sync.get("options");
|
await options.setAll(this.state.options);
|
||||||
await this.setStorage();
|
|
||||||
const { options } = await browser.storage.sync.get("options");
|
|
||||||
|
|
||||||
const alteredOptions = [];
|
const alteredOptions = [];
|
||||||
|
for (const [ key, val ] of Object.entries(this.state.options)) {
|
||||||
for (const [ key, val ] of Object.entries(options)) {
|
const oldVal = oldOpts[key];
|
||||||
const oldVal = oldOptions[key];
|
|
||||||
if (oldVal !== val) {
|
if (oldVal !== val) {
|
||||||
alteredOptions.push(key);
|
alteredOptions.push(key);
|
||||||
}
|
}
|
||||||
@@ -325,16 +313,16 @@ class OptionsApp extends Component<{}, OptionsAppState> {
|
|||||||
private handleInputChange (ev: React.ChangeEvent<HTMLInputElement>) {
|
private handleInputChange (ev: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const { target } = ev;
|
const { target } = ev;
|
||||||
|
|
||||||
this.setState(({ options }) => {
|
this.setState(currentState => {
|
||||||
options[target.name as keyof Options] = getInputValue(target);
|
currentState.options[target.name] = getInputValue(target);
|
||||||
return { options };
|
return currentState;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWhitelistChange (whitelist: string[]) {
|
private handleWhitelistChange (whitelist: string[]) {
|
||||||
this.setState(({ options }) => {
|
this.setState(currentState => {
|
||||||
options.userAgentWhitelist = whitelist;
|
currentState.options.userAgentWhitelist = whitelist;
|
||||||
return { options };
|
return currentState;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user