mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Re-work whitelist feature to allow per-site UA configuration
This commit is contained in:
@@ -35,17 +35,43 @@ Missing/outdated strings:
|
|||||||
- `optionsMirroringCategoryDescription`
|
- `optionsMirroringCategoryDescription`
|
||||||
- `optionsMirroringEnabled`
|
- `optionsMirroringEnabled`
|
||||||
- `optionsMirroringAppId`
|
- `optionsMirroringAppId`
|
||||||
- `popupWhitelistNotWhitelisted`
|
|
||||||
- `popupWhitelistAddToWhitelist`
|
|
||||||
- `popupMediaTypeAppNotFound`
|
|
||||||
- `optionsBridgeCompatible`
|
- `optionsBridgeCompatible`
|
||||||
- `optionsBridgeLikelyCompatible`
|
- `optionsBridgeLikelyCompatible`
|
||||||
- `optionsBridgeIncompatible`
|
- `optionsBridgeIncompatible`
|
||||||
|
- `optionsSiteWhitelistCategoryName`
|
||||||
|
- `optionsSiteWhitelistCategoryDescription`
|
||||||
|
- `optionsSiteWhitelistEnabled`
|
||||||
|
- `optionsSiteWhitelistEnabledDescription`
|
||||||
|
- `optionsSiteWhitelistContent`
|
||||||
|
- `optionsSiteWhitelistBasicView`
|
||||||
|
- `optionsSiteWhitelistRawView`
|
||||||
|
- `optionsSiteWhitelistSaveRaw`
|
||||||
|
- `optionsSiteWhitelistAddItem`
|
||||||
|
- `optionsSiteWhitelistUserAgent`
|
||||||
|
- `optionsSiteWhitelistEditItem`
|
||||||
|
- `optionsSiteWhitelistRemoveItem`
|
||||||
|
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||||
|
- `popupWhitelistNotWhitelisted`
|
||||||
|
- `popupWhitelistAddToWhitelist`
|
||||||
|
- `popupMediaTypeAppNotFound`
|
||||||
- `popupCastMenuTitle`
|
- `popupCastMenuTitle`
|
||||||
- `popupStopMenuTitle`
|
- `popupStopMenuTitle`
|
||||||
|
|
||||||
- `es`
|
- `es`
|
||||||
|
|
||||||
|
- `optionsSiteWhitelistCategoryName`
|
||||||
|
- `optionsSiteWhitelistCategoryDescription`
|
||||||
|
- `optionsSiteWhitelistEnabled`
|
||||||
|
- `optionsSiteWhitelistEnabledDescription`
|
||||||
|
- `optionsSiteWhitelistContent`
|
||||||
|
- `optionsSiteWhitelistBasicView`
|
||||||
|
- `optionsSiteWhitelistRawView`
|
||||||
|
- `optionsSiteWhitelistSaveRaw`
|
||||||
|
- `optionsSiteWhitelistAddItem`
|
||||||
|
- `optionsSiteWhitelistUserAgent`
|
||||||
|
- `optionsSiteWhitelistEditItem`
|
||||||
|
- `optionsSiteWhitelistRemoveItem`
|
||||||
|
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||||
- `popupWhitelistNotWhitelisted`
|
- `popupWhitelistNotWhitelisted`
|
||||||
- `popupWhitelistAddToWhitelist`
|
- `popupWhitelistAddToWhitelist`
|
||||||
- `popupCastMenuTitle`
|
- `popupCastMenuTitle`
|
||||||
@@ -54,23 +80,47 @@ Missing/outdated strings:
|
|||||||
- `nl`
|
- `nl`
|
||||||
|
|
||||||
- `optionsBridgeBackupEnabled`
|
- `optionsBridgeBackupEnabled`
|
||||||
- `optionsUserAgentWhitelistRestrictedEnabled`
|
- `optionsBridgeCompatible`
|
||||||
- `optionsUserAgentWhitelistRestrictedEnabledDescription`
|
- `optionsBridgeLikelyCompatible`
|
||||||
|
- `optionsBridgeIncompatible`
|
||||||
- `optionsOptionRecommended`
|
- `optionsOptionRecommended`
|
||||||
- `optionsMirroringCategoryName`
|
- `optionsMirroringCategoryName`
|
||||||
- `optionsMirroringCategoryDescription`
|
- `optionsMirroringCategoryDescription`
|
||||||
- `optionsMirroringEnabled`
|
- `optionsMirroringEnabled`
|
||||||
- `optionsMirroringAppId`
|
- `optionsMirroringAppId`
|
||||||
|
- `optionsSiteWhitelistCategoryName`
|
||||||
|
- `optionsSiteWhitelistCategoryDescription`
|
||||||
|
- `optionsSiteWhitelistEnabled`
|
||||||
|
- `optionsSiteWhitelistEnabledDescription`
|
||||||
|
- `optionsSiteWhitelistContent`
|
||||||
|
- `optionsSiteWhitelistBasicView`
|
||||||
|
- `optionsSiteWhitelistRawView`
|
||||||
|
- `optionsSiteWhitelistSaveRaw`
|
||||||
|
- `optionsSiteWhitelistAddItem`
|
||||||
|
- `optionsSiteWhitelistUserAgent`
|
||||||
|
- `optionsSiteWhitelistEditItem`
|
||||||
|
- `optionsSiteWhitelistRemoveItem`
|
||||||
|
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||||
- `popupWhitelistNotWhitelisted`
|
- `popupWhitelistNotWhitelisted`
|
||||||
- `popupWhitelistAddToWhitelist`
|
- `popupWhitelistAddToWhitelist`
|
||||||
- `popupMediaTypeAppNotFound`
|
- `popupMediaTypeAppNotFound`
|
||||||
- `optionsBridgeCompatible`
|
|
||||||
- `optionsBridgeLikelyCompatible`
|
|
||||||
- `optionsBridgeIncompatible`
|
|
||||||
- `popupCastMenuTitle`
|
- `popupCastMenuTitle`
|
||||||
- `popupStopMenuTitle`
|
- `popupStopMenuTitle`
|
||||||
|
|
||||||
- `no`
|
- `no`
|
||||||
|
- `optionsSiteWhitelistCategoryName`
|
||||||
|
- `optionsSiteWhitelistCategoryDescription`
|
||||||
|
- `optionsSiteWhitelistEnabled`
|
||||||
|
- `optionsSiteWhitelistEnabledDescription`
|
||||||
|
- `optionsSiteWhitelistContent`
|
||||||
|
- `optionsSiteWhitelistBasicView`
|
||||||
|
- `optionsSiteWhitelistRawView`
|
||||||
|
- `optionsSiteWhitelistSaveRaw`
|
||||||
|
- `optionsSiteWhitelistAddItem`
|
||||||
|
- `optionsSiteWhitelistUserAgent`
|
||||||
|
- `optionsSiteWhitelistEditItem`
|
||||||
|
- `optionsSiteWhitelistRemoveItem`
|
||||||
|
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||||
- `popupWhitelistNotWhitelisted`
|
- `popupWhitelistNotWhitelisted`
|
||||||
- `popupWhitelistAddToWhitelist`
|
- `popupWhitelistAddToWhitelist`
|
||||||
- `popupCastMenuTitle`
|
- `popupCastMenuTitle`
|
||||||
|
|||||||
@@ -259,55 +259,55 @@
|
|||||||
"description": "Receiver selector close if focus lost option checkbox label."
|
"description": "Receiver selector close if focus lost option checkbox label."
|
||||||
},
|
},
|
||||||
|
|
||||||
"optionsUserAgentWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "Useragent-Whitelist",
|
"message": "Useragent-Whitelist",
|
||||||
"description": "Options page whitelist category title."
|
"description": "Options page whitelist category title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryDescription": {
|
"optionsSiteWhitelistCategoryDescription": {
|
||||||
"message": "Seiten auf denen der Useragent aus Kompatibilitätsgründen mit einer Chrome-Version ersetzt wird. Suchmuster müssen gültig sein.",
|
"message": "Seiten auf denen der Useragent aus Kompatibilitätsgründen mit einer Chrome-Version ersetzt wird. Suchmuster müssen gültig sein.",
|
||||||
"description": "Options page whitelist category description."
|
"description": "Options page whitelist category description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEnabled": {
|
"optionsSiteWhitelistEnabled": {
|
||||||
"message": "Webseiten-Whitelist aktivieren",
|
"message": "Webseiten-Whitelist aktivieren",
|
||||||
"description": "Whitelist enabled checkbox label."
|
"description": "Whitelist enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
"optionsSiteWhitelistRestrictedEnabled": {
|
||||||
"message": "Eingeschränkten Modus aktivieren",
|
"message": "Eingeschränkten Modus aktivieren",
|
||||||
"description": "Whitelist restricted mode enabled checkbox label."
|
"description": "Whitelist restricted mode enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||||
"message": "Whitelist-Einschränkungen auch auf Seiten anwenden, die unabhängig vom aktuellen Useragent versuchen Stream-Funktionen zu laden.",
|
"message": "Whitelist-Einschränkungen auch auf Seiten anwenden, die unabhängig vom aktuellen Useragent versuchen Stream-Funktionen zu laden.",
|
||||||
"description": "Whitelist restricted mode enabled description."
|
"description": "Whitelist restricted mode enabled description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistContent": {
|
"optionsSiteWhitelistContent": {
|
||||||
"message": "Suchmuster:",
|
"message": "Suchmuster:",
|
||||||
"description": "Match patterns editor widget label."
|
"description": "Match patterns editor widget label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistBasicView": {
|
"optionsSiteWhitelistBasicView": {
|
||||||
"message": "Einfache Ansicht",
|
"message": "Einfache Ansicht",
|
||||||
"description": "Switch to basic view button title."
|
"description": "Switch to basic view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRawView": {
|
"optionsSiteWhitelistRawView": {
|
||||||
"message": "Rohdatenansicht",
|
"message": "Rohdatenansicht",
|
||||||
"description": "Switch to raw view button title."
|
"description": "Switch to raw view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistSaveRaw": {
|
"optionsSiteWhitelistSaveRaw": {
|
||||||
"message": "Rohdaten speichern",
|
"message": "Rohdaten speichern",
|
||||||
"description": "Save raw view edits button title."
|
"description": "Save raw view edits button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistAddItem": {
|
"optionsSiteWhitelistAddItem": {
|
||||||
"message": "Eintrag hinzufügen",
|
"message": "Eintrag hinzufügen",
|
||||||
"description": "Add new whitelist item button title."
|
"description": "Add new whitelist item button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEditItem": {
|
"optionsSiteWhitelistEditItem": {
|
||||||
"message": "Bearbeiten",
|
"message": "Bearbeiten",
|
||||||
"description": "Edit whitelist item button title. Displayed on each item."
|
"description": "Edit whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRemoveItem": {
|
"optionsSiteWhitelistRemoveItem": {
|
||||||
"message": "Entfernen",
|
"message": "Entfernen",
|
||||||
"description": "Remove whitelist item button title. Displayed on each item."
|
"description": "Remove whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||||
"message": "Ungültiges Suchmuster $matchPattern$",
|
"message": "Ungültiges Suchmuster $matchPattern$",
|
||||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -302,55 +302,55 @@
|
|||||||
"description": "Receiver selector close if focus lost option checkbox label."
|
"description": "Receiver selector close if focus lost option checkbox label."
|
||||||
},
|
},
|
||||||
|
|
||||||
"optionsUserAgentWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "User agent whitelist",
|
"message": "Site whitelist",
|
||||||
"description": "Options page whitelist category title."
|
"description": "Options page whitelist category title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryDescription": {
|
"optionsSiteWhitelistCategoryDescription": {
|
||||||
"message": "Sites for which to replace the user agent with a Chrome version for compatibility. Must be valid match patterns.",
|
"message": "Site where cast functionality will be enabled and the user agent string will be replaced with a Chrome version for compatibility.",
|
||||||
"description": "Options page whitelist category description."
|
"description": "Options page whitelist category description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEnabled": {
|
"optionsSiteWhitelistEnabled": {
|
||||||
"message": "Enable site whitelist",
|
"message": "Enable site whitelist",
|
||||||
"description": "Whitelist enabled checkbox label."
|
"description": "Whitelist enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
"optionsSiteWhitelistEnabledDescription": {
|
||||||
"message": "Enable restricted mode",
|
"message": "Disabling this option will enable cast functionality on any site, but the user agent string will not be replaced.",
|
||||||
"description": "Whitelist restricted mode enabled checkbox label."
|
|
||||||
},
|
|
||||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
|
||||||
"message": "Also apply whitelist restrictions to sites attempting to load cast functionality regardless of the current user agent.",
|
|
||||||
"description": "Whitelist restricted mode enabled description."
|
"description": "Whitelist restricted mode enabled description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistContent": {
|
"optionsSiteWhitelistContent": {
|
||||||
"message": "Match patterns:",
|
"message": "Match patterns:",
|
||||||
"description": "Match patterns editor widget label."
|
"description": "Match patterns editor widget label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistBasicView": {
|
"optionsSiteWhitelistBasicView": {
|
||||||
"message": "Basic View",
|
"message": "Basic View",
|
||||||
"description": "Switch to basic view button title."
|
"description": "Switch to basic view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRawView": {
|
"optionsSiteWhitelistRawView": {
|
||||||
"message": "Raw View",
|
"message": "Raw View",
|
||||||
"description": "Switch to raw view button title."
|
"description": "Switch to raw view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistSaveRaw": {
|
"optionsSiteWhitelistSaveRaw": {
|
||||||
"message": "Save Raw",
|
"message": "Save Raw",
|
||||||
"description": "Save raw view edits button title."
|
"description": "Save raw view edits button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistAddItem": {
|
"optionsSiteWhitelistAddItem": {
|
||||||
"message": "Add Item",
|
"message": "Add Item",
|
||||||
"description": "Add new whitelist item button title."
|
"description": "Add new whitelist item button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEditItem": {
|
"optionsSiteWhitelistUserAgent": {
|
||||||
|
"message": "Enable UA",
|
||||||
|
"description": "Whitelist item user agent checkbox title."
|
||||||
|
},
|
||||||
|
"optionsSiteWhitelistEditItem": {
|
||||||
"message": "Edit",
|
"message": "Edit",
|
||||||
"description": "Edit whitelist item button title. Displayed on each item."
|
"description": "Edit whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRemoveItem": {
|
"optionsSiteWhitelistRemoveItem": {
|
||||||
"message": "Remove",
|
"message": "Remove",
|
||||||
"description": "Remove whitelist item button title. Displayed on each item."
|
"description": "Remove whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||||
"message": "Invalid match pattern $matchPattern$",
|
"message": "Invalid match pattern $matchPattern$",
|
||||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -275,55 +275,55 @@
|
|||||||
"description": "Receiver selector close if focus lost option checkbox label."
|
"description": "Receiver selector close if focus lost option checkbox label."
|
||||||
},
|
},
|
||||||
|
|
||||||
"optionsUserAgentWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "Lista blanca de agentes de usuario",
|
"message": "Lista blanca de agentes de usuario",
|
||||||
"description": "Options page whitelist category title."
|
"description": "Options page whitelist category title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryDescription": {
|
"optionsSiteWhitelistCategoryDescription": {
|
||||||
"message": "Sitios en los cuales reemplazar el agente de usuario con una versión de Chrome para compatibilidad. Deben ser patrones de coincidencia válidos.",
|
"message": "Sitios en los cuales reemplazar el agente de usuario con una versión de Chrome para compatibilidad. Deben ser patrones de coincidencia válidos.",
|
||||||
"description": "Options page whitelist category description."
|
"description": "Options page whitelist category description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEnabled": {
|
"optionsSiteWhitelistEnabled": {
|
||||||
"message": "Activar lista blanca de sitios",
|
"message": "Activar lista blanca de sitios",
|
||||||
"description": "Whitelist enabled checkbox label."
|
"description": "Whitelist enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
"optionsSiteWhitelistRestrictedEnabled": {
|
||||||
"message": "Activar modo restringido",
|
"message": "Activar modo restringido",
|
||||||
"description": "Whitelist restricted mode enabled checkbox label."
|
"description": "Whitelist restricted mode enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||||
"message": "También aplica restricciones de la lista blanca a sitios intentando cargar la funcionalidad de transmisión sin importar el agente de usuario actual.",
|
"message": "También aplica restricciones de la lista blanca a sitios intentando cargar la funcionalidad de transmisión sin importar el agente de usuario actual.",
|
||||||
"description": "Whitelist restricted mode enabled description."
|
"description": "Whitelist restricted mode enabled description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistContent": {
|
"optionsSiteWhitelistContent": {
|
||||||
"message": "Patrones de coincidencia:",
|
"message": "Patrones de coincidencia:",
|
||||||
"description": "Match patterns editor widget label."
|
"description": "Match patterns editor widget label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistBasicView": {
|
"optionsSiteWhitelistBasicView": {
|
||||||
"message": "Vista básica",
|
"message": "Vista básica",
|
||||||
"description": "Switch to basic view button title."
|
"description": "Switch to basic view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRawView": {
|
"optionsSiteWhitelistRawView": {
|
||||||
"message": "Vista en bruto",
|
"message": "Vista en bruto",
|
||||||
"description": "Switch to raw view button title."
|
"description": "Switch to raw view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistSaveRaw": {
|
"optionsSiteWhitelistSaveRaw": {
|
||||||
"message": "Guardar archivo en bruto",
|
"message": "Guardar archivo en bruto",
|
||||||
"description": "Save raw view edits button title."
|
"description": "Save raw view edits button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistAddItem": {
|
"optionsSiteWhitelistAddItem": {
|
||||||
"message": "Añadir elemento",
|
"message": "Añadir elemento",
|
||||||
"description": "Add new whitelist item button title."
|
"description": "Add new whitelist item button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEditItem": {
|
"optionsSiteWhitelistEditItem": {
|
||||||
"message": "Editar",
|
"message": "Editar",
|
||||||
"description": "Edit whitelist item button title. Displayed on each item."
|
"description": "Edit whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRemoveItem": {
|
"optionsSiteWhitelistRemoveItem": {
|
||||||
"message": "Eliminar",
|
"message": "Eliminar",
|
||||||
"description": "Remove whitelist item button title. Displayed on each item."
|
"description": "Remove whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||||
"message": "Patrón de coincidencia $matchPattern$ inválido",
|
"message": "Patrón de coincidencia $matchPattern$ inválido",
|
||||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -243,47 +243,47 @@
|
|||||||
"message": "Sluit na het verliezen van de focus",
|
"message": "Sluit na het verliezen van de focus",
|
||||||
"description": "Receiver selector close if focus lost option checkbox label."
|
"description": "Receiver selector close if focus lost option checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "Gebruikersagent - Whitelist",
|
"message": "Gebruikersagent - Whitelist",
|
||||||
"description": "Options page whitelist category title."
|
"description": "Options page whitelist category title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryDescription": {
|
"optionsSiteWhitelistCategoryDescription": {
|
||||||
"message": "Websites waarvan de gebruikersagent omwille van compatibiliteit moet worden ingesteld op Chrome. De patronen moeten geldig zijn.",
|
"message": "Websites waarvan de gebruikersagent omwille van compatibiliteit moet worden ingesteld op Chrome. De patronen moeten geldig zijn.",
|
||||||
"description": "Options page whitelist category description."
|
"description": "Options page whitelist category description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEnabled": {
|
"optionsSiteWhitelistEnabled": {
|
||||||
"message": "Whitelist ingeschakeld",
|
"message": "Whitelist ingeschakeld",
|
||||||
"description": "Whitelist enabled checkbox label."
|
"description": "Whitelist enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistContent": {
|
"optionsSiteWhitelistContent": {
|
||||||
"message": "Patronen:",
|
"message": "Patronen:",
|
||||||
"description": "Match patterns editor widget label."
|
"description": "Match patterns editor widget label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistBasicView": {
|
"optionsSiteWhitelistBasicView": {
|
||||||
"message": "Basisweergave",
|
"message": "Basisweergave",
|
||||||
"description": "Switch to basic view button title."
|
"description": "Switch to basic view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRawView": {
|
"optionsSiteWhitelistRawView": {
|
||||||
"message": "Ruwe weergave",
|
"message": "Ruwe weergave",
|
||||||
"description": "Switch to raw view button title."
|
"description": "Switch to raw view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistSaveRaw": {
|
"optionsSiteWhitelistSaveRaw": {
|
||||||
"message": "Ruwe weergave opslaan",
|
"message": "Ruwe weergave opslaan",
|
||||||
"description": "Save raw view edits button title."
|
"description": "Save raw view edits button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistAddItem": {
|
"optionsSiteWhitelistAddItem": {
|
||||||
"message": "Voeg toe",
|
"message": "Voeg toe",
|
||||||
"description": "Add new whitelist item button title."
|
"description": "Add new whitelist item button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEditItem": {
|
"optionsSiteWhitelistEditItem": {
|
||||||
"message": "Bewerken",
|
"message": "Bewerken",
|
||||||
"description": "Edit whitelist item button title. Displayed on each item."
|
"description": "Edit whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRemoveItem": {
|
"optionsSiteWhitelistRemoveItem": {
|
||||||
"message": "Verwijderen",
|
"message": "Verwijderen",
|
||||||
"description": "Remove whitelist item button title. Displayed on each item."
|
"description": "Remove whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||||
"message": "Ongeldig patroon $matchPattern$",
|
"message": "Ongeldig patroon $matchPattern$",
|
||||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -263,55 +263,55 @@
|
|||||||
"description": "Receiver selector close if focus lost option checkbox label."
|
"description": "Receiver selector close if focus lost option checkbox label."
|
||||||
},
|
},
|
||||||
|
|
||||||
"optionsUserAgentWhitelistCategoryName": {
|
"optionsSiteWhitelistCategoryName": {
|
||||||
"message": "Brukeragent whitelist",
|
"message": "Brukeragent whitelist",
|
||||||
"description": "Options page whitelist category title."
|
"description": "Options page whitelist category title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistCategoryDescription": {
|
"optionsSiteWhitelistCategoryDescription": {
|
||||||
"message": "Sider hvor man kan erstatte brukeragent med en Chrome-versjon for kompatibilitet. Må være et gjenkjennbart mønster.",
|
"message": "Sider hvor man kan erstatte brukeragent med en Chrome-versjon for kompatibilitet. Må være et gjenkjennbart mønster.",
|
||||||
"description": "Options page whitelist category description."
|
"description": "Options page whitelist category description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEnabled": {
|
"optionsSiteWhitelistEnabled": {
|
||||||
"message": "Skru på whitelist",
|
"message": "Skru på whitelist",
|
||||||
"description": "Whitelist enabled checkbox label."
|
"description": "Whitelist enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
"optionsSiteWhitelistRestrictedEnabled": {
|
||||||
"message": "Skru på ",
|
"message": "Skru på ",
|
||||||
"description": "Whitelist restricted mode enabled checkbox label."
|
"description": "Whitelist restricted mode enabled checkbox label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||||
"message": "Legg også til whitelist-begrensninger til side smo prøvde å laste cast-funksjonalitet uavhengig av nåværende brukeragent.",
|
"message": "Legg også til whitelist-begrensninger til side smo prøvde å laste cast-funksjonalitet uavhengig av nåværende brukeragent.",
|
||||||
"description": "Whitelist restricted mode enabled description."
|
"description": "Whitelist restricted mode enabled description."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistContent": {
|
"optionsSiteWhitelistContent": {
|
||||||
"message": "Match mønster",
|
"message": "Match mønster",
|
||||||
"description": "Match patterns editor widget label."
|
"description": "Match patterns editor widget label."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistBasicView": {
|
"optionsSiteWhitelistBasicView": {
|
||||||
"message": "Standard visning",
|
"message": "Standard visning",
|
||||||
"description": "Switch to basic view button title."
|
"description": "Switch to basic view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRawView": {
|
"optionsSiteWhitelistRawView": {
|
||||||
"message": "Rå visning",
|
"message": "Rå visning",
|
||||||
"description": "Switch to raw view button title."
|
"description": "Switch to raw view button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistSaveRaw": {
|
"optionsSiteWhitelistSaveRaw": {
|
||||||
"message": "Lagre rå",
|
"message": "Lagre rå",
|
||||||
"description": "Save raw view edits button title."
|
"description": "Save raw view edits button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistAddItem": {
|
"optionsSiteWhitelistAddItem": {
|
||||||
"message": "Legg til",
|
"message": "Legg til",
|
||||||
"description": "Add new whitelist item button title."
|
"description": "Add new whitelist item button title."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistEditItem": {
|
"optionsSiteWhitelistEditItem": {
|
||||||
"message": "Rediger",
|
"message": "Rediger",
|
||||||
"description": "Edit whitelist item button title. Displayed on each item."
|
"description": "Edit whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistRemoveItem": {
|
"optionsSiteWhitelistRemoveItem": {
|
||||||
"message": "Fjern",
|
"message": "Fjern",
|
||||||
"description": "Remove whitelist item button title. Displayed on each item."
|
"description": "Remove whitelist item button title. Displayed on each item."
|
||||||
},
|
},
|
||||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||||
"message": "Ugyldig mønster $matchPattern$",
|
"message": "Ugyldig mønster $matchPattern$",
|
||||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ async function onMenuClicked(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const whitelist = await options.get("userAgentWhitelist");
|
const whitelist = await options.get("siteWhitelist");
|
||||||
if (!whitelist.includes(pattern)) {
|
if (!whitelist.find(item => item.pattern === pattern)) {
|
||||||
// Add to whitelist and update options
|
// Add to whitelist and update options
|
||||||
whitelist.push(pattern);
|
whitelist.push({ pattern });
|
||||||
await options.set("userAgentWhitelist", whitelist);
|
await options.set("siteWhitelist", whitelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ type OnBeforeRequestDetails = Parameters<
|
|||||||
frameAncestors?: Array<{ url: string; frameId: number }>;
|
frameAncestors?: Array<{ url: string; frameId: number }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface WhitelistItemData {
|
||||||
|
pattern: string;
|
||||||
|
isUserAgentDisabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const originUrlCache: string[] = [];
|
const originUrlCache: string[] = [];
|
||||||
|
|
||||||
let platform: string;
|
let platform: string;
|
||||||
@@ -47,18 +52,18 @@ export async function initWhitelist() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register on first run
|
// Register on first run
|
||||||
await registerUserAgentWhitelist();
|
await registerSiteWhitelist();
|
||||||
|
|
||||||
// Re-register when options change
|
// Re-register when options change
|
||||||
options.addEventListener("changed", ev => {
|
options.addEventListener("changed", ev => {
|
||||||
const alteredOpts = ev.detail;
|
const alteredOpts = ev.detail;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
alteredOpts.includes("userAgentWhitelist") ||
|
alteredOpts.includes("siteWhitelist") ||
|
||||||
alteredOpts.includes("userAgentWhitelistEnabled")
|
alteredOpts.includes("siteWhitelistEnabled")
|
||||||
) {
|
) {
|
||||||
unregisterUserAgentWhitelist();
|
unregisterSiteWhitelist();
|
||||||
registerUserAgentWhitelist();
|
registerSiteWhitelist();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -189,9 +194,8 @@ async function onBeforeCastSDKRequest(details: OnBeforeRequestDetails) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function registerUserAgentWhitelist() {
|
async function registerSiteWhitelist() {
|
||||||
const { userAgentWhitelist, userAgentWhitelistEnabled } =
|
const { siteWhitelist, siteWhitelistEnabled } = await options.getAll();
|
||||||
await options.getAll();
|
|
||||||
|
|
||||||
browser.webRequest.onBeforeRequest.addListener(
|
browser.webRequest.onBeforeRequest.addListener(
|
||||||
onBeforeCastSDKRequest,
|
onBeforeCastSDKRequest,
|
||||||
@@ -199,13 +203,18 @@ async function registerUserAgentWhitelist() {
|
|||||||
["blocking"]
|
["blocking"]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!userAgentWhitelistEnabled || !userAgentWhitelist.length) {
|
if (!siteWhitelistEnabled || !siteWhitelist.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.webRequest.onBeforeSendHeaders.addListener(
|
browser.webRequest.onBeforeSendHeaders.addListener(
|
||||||
onWhitelistedBeforeSendHeaders,
|
onWhitelistedBeforeSendHeaders,
|
||||||
{ urls: userAgentWhitelist },
|
{
|
||||||
|
// Filter for items with UA enabled
|
||||||
|
urls: siteWhitelist.flatMap(item =>
|
||||||
|
!item.isUserAgentDisabled ? [item.pattern] : []
|
||||||
|
)
|
||||||
|
},
|
||||||
["blocking", "requestHeaders"]
|
["blocking", "requestHeaders"]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -216,7 +225,7 @@ async function registerUserAgentWhitelist() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unregisterUserAgentWhitelist() {
|
function unregisterSiteWhitelist() {
|
||||||
originUrlCache.length = 0;
|
originUrlCache.length = 0;
|
||||||
|
|
||||||
browser.webRequest.onBeforeSendHeaders.removeListener(
|
browser.webRequest.onBeforeSendHeaders.removeListener(
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export default {
|
|||||||
mirroringAppId: MIRRORING_APP_ID,
|
mirroringAppId: MIRRORING_APP_ID,
|
||||||
receiverSelectorCloseIfFocusLost: true,
|
receiverSelectorCloseIfFocusLost: true,
|
||||||
receiverSelectorWaitForConnection: true,
|
receiverSelectorWaitForConnection: true,
|
||||||
userAgentWhitelistEnabled: true,
|
siteWhitelistEnabled: true,
|
||||||
userAgentWhitelistRestrictedEnabled: true,
|
siteWhitelist: [{ pattern: "https://www.netflix.com/*" }]
|
||||||
userAgentWhitelist: ["https://www.netflix.com/*"]
|
|
||||||
} as Options;
|
} as Options;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import defaultOptions from "../defaultOptions";
|
import defaultOptions from "../defaultOptions";
|
||||||
|
import type { WhitelistItemData } from "../background/whitelist";
|
||||||
|
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|
||||||
@@ -25,9 +26,8 @@ export interface Options {
|
|||||||
mirroringAppId: string;
|
mirroringAppId: string;
|
||||||
receiverSelectorCloseIfFocusLost: boolean;
|
receiverSelectorCloseIfFocusLost: boolean;
|
||||||
receiverSelectorWaitForConnection: boolean;
|
receiverSelectorWaitForConnection: boolean;
|
||||||
userAgentWhitelistEnabled: boolean;
|
siteWhitelistEnabled: boolean;
|
||||||
userAgentWhitelistRestrictedEnabled: boolean;
|
siteWhitelist: WhitelistItemData[];
|
||||||
userAgentWhitelist: string[];
|
|
||||||
|
|
||||||
[key: string]: Options[keyof Options];
|
[key: string]: Options[keyof Options];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,316 +0,0 @@
|
|||||||
/* eslint-disable max-len */
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
import React, { Component } from "react";
|
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
|
||||||
|
|
||||||
|
|
||||||
interface EditableListProps {
|
|
||||||
data: string[];
|
|
||||||
itemPattern: RegExp;
|
|
||||||
onChange (data: string[]): void;
|
|
||||||
itemPatternError (err?: string): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EditableListState {
|
|
||||||
addingNewItem: boolean;
|
|
||||||
rawView: boolean;
|
|
||||||
rawViewValue: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class EditableList extends Component<
|
|
||||||
EditableListProps, EditableListState> {
|
|
||||||
|
|
||||||
private rawViewTextArea: (HTMLTextAreaElement | null) = null;
|
|
||||||
|
|
||||||
constructor(props: EditableListProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
addingNewItem: false
|
|
||||||
, rawView: false
|
|
||||||
, rawViewValue: ""
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleItemRemove = this.handleItemRemove.bind(this);
|
|
||||||
this.handleItemEdit = this.handleItemEdit.bind(this);
|
|
||||||
this.handleSwitchView = this.handleSwitchView.bind(this);
|
|
||||||
this.handleSaveRaw = this.handleSaveRaw.bind(this);
|
|
||||||
this.handleRawViewTextAreaChange = this.handleRawViewTextAreaChange.bind(this);
|
|
||||||
this.handleAddItem = this.handleAddItem.bind(this);
|
|
||||||
this.handleNewItemRemove = this.handleNewItemRemove.bind(this);
|
|
||||||
this.handleNewItemEdit = this.handleNewItemEdit.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
return (
|
|
||||||
<div className="editable-list">
|
|
||||||
{ this.state.rawView
|
|
||||||
? (
|
|
||||||
<textarea className="editable-list__raw-view"
|
|
||||||
rows={ Math.min(this.props.data.length, 10) }
|
|
||||||
value={ this.state.rawViewValue }
|
|
||||||
onChange={ this.handleRawViewTextAreaChange }
|
|
||||||
ref={ el => { this.rawViewTextArea = el; }}>
|
|
||||||
</textarea>
|
|
||||||
) : (
|
|
||||||
<ul className="editable-list__items">
|
|
||||||
{ this.props.data.map((item, i) =>
|
|
||||||
<EditableListItem text={ item }
|
|
||||||
itemPattern={ this.props.itemPattern }
|
|
||||||
itemPatternError={ this.props.itemPatternError }
|
|
||||||
onRemove={ this.handleItemRemove }
|
|
||||||
onEdit={ this.handleItemEdit }
|
|
||||||
key={ i } /> )}
|
|
||||||
|
|
||||||
{ this.state.addingNewItem &&
|
|
||||||
<EditableListItem text=""
|
|
||||||
itemPattern={ this.props.itemPattern }
|
|
||||||
itemPatternError={ this.props.itemPatternError }
|
|
||||||
onRemove={ this.handleNewItemRemove }
|
|
||||||
onEdit={ this.handleNewItemEdit }
|
|
||||||
editing={ true } /> }
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
<hr />
|
|
||||||
<div className="editable-list__view-actions">
|
|
||||||
{ !this.state.rawView &&
|
|
||||||
<button className="editable-list__add-button ghost"
|
|
||||||
title={ _("optionsUserAgentWhitelistAddItem") }
|
|
||||||
onClick={ this.handleAddItem }
|
|
||||||
type="button">
|
|
||||||
<img src="assets/photon_new.svg" alt="icon, add" />
|
|
||||||
</button> }
|
|
||||||
|
|
||||||
{ this.state.rawView &&
|
|
||||||
<button className="editable-list__save-raw-button"
|
|
||||||
onClick={ this.handleSaveRaw }
|
|
||||||
type="button">
|
|
||||||
{ _("optionsUserAgentWhitelistSaveRaw") }
|
|
||||||
</button> }
|
|
||||||
|
|
||||||
<button className="editable-list__view-button"
|
|
||||||
onClick={ this.handleSwitchView }
|
|
||||||
type="button">
|
|
||||||
{ this.state.rawView
|
|
||||||
? _("optionsUserAgentWhitelistBasicView")
|
|
||||||
: _("optionsUserAgentWhitelistRawView") }
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleItemRemove(item: string) {
|
|
||||||
const newItems = new Set(this.props.data);
|
|
||||||
newItems.delete(item);
|
|
||||||
|
|
||||||
this.props.onChange([ ...newItems ]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleItemEdit(item: string, newValue: string) {
|
|
||||||
this.props.onChange(this.props.data.map(
|
|
||||||
currentItem => currentItem === item
|
|
||||||
? newValue
|
|
||||||
: currentItem));
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleSwitchView() {
|
|
||||||
this.setState(currentState => {
|
|
||||||
if (currentState.rawView) {
|
|
||||||
return {
|
|
||||||
rawView: false
|
|
||||||
, rawViewValue: ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
rawView: true
|
|
||||||
, rawViewValue: this.props.data.join("\n")
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleSaveRaw() {
|
|
||||||
this.setState(currentState => {
|
|
||||||
const newItems = currentState.rawViewValue.split("\n")
|
|
||||||
.filter(item => item !== "");
|
|
||||||
|
|
||||||
if ("itemPattern" in this.props) {
|
|
||||||
for (const item of newItems) {
|
|
||||||
if (!this.props.itemPattern.test(item)) {
|
|
||||||
this.rawViewTextArea?.setCustomValidity(
|
|
||||||
this.props.itemPatternError(item));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rawViewTextArea?.setCustomValidity("");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onChange(newItems);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleRawViewTextAreaChange(ev: React.ChangeEvent<HTMLTextAreaElement>) {
|
|
||||||
if (!this.rawViewTextArea) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.rawViewTextArea.scrollHeight > this.rawViewTextArea.clientHeight) {
|
|
||||||
this.rawViewTextArea.style.height = `${this.rawViewTextArea.scrollHeight}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
rawViewValue: ev.target.value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleAddItem() {
|
|
||||||
this.setState({
|
|
||||||
addingNewItem: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleNewItemRemove() {
|
|
||||||
this.setState({
|
|
||||||
addingNewItem: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleNewItemEdit(_item: string, newItem: string) {
|
|
||||||
this.setState({
|
|
||||||
addingNewItem: false
|
|
||||||
}, () => {
|
|
||||||
this.props.onChange([ ...this.props.data, newItem ]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface EditableListItemProps {
|
|
||||||
text: string;
|
|
||||||
itemPattern: RegExp;
|
|
||||||
editing?: boolean;
|
|
||||||
itemPatternError (err?: string): string;
|
|
||||||
onRemove (item: string): void;
|
|
||||||
onEdit (item: string, newValue: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EditableListItemState {
|
|
||||||
editing: boolean;
|
|
||||||
editValue: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class EditableListItem extends Component<
|
|
||||||
EditableListItemProps, EditableListItemState> {
|
|
||||||
|
|
||||||
private input: (HTMLInputElement | null) = null;
|
|
||||||
|
|
||||||
constructor(props: EditableListItemProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
editing: this.props.editing || false
|
|
||||||
, editValue: ""
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleRemove = this.handleRemove.bind(this);
|
|
||||||
this.handleEditBegin = this.handleEditBegin.bind(this);
|
|
||||||
this.handleEditEnd = this.handleEditEnd.bind(this);
|
|
||||||
this.handleInputChange = this.handleInputChange.bind(this);
|
|
||||||
this.handleInputKeyPress = this.handleInputKeyPress.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const selected = this.state.editing
|
|
||||||
? "editable-list__item--selected" : "";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li className={`editable-list__item ${selected}`}>
|
|
||||||
<div className="editable-list__title"
|
|
||||||
onDoubleClick={ this.handleEditBegin }>
|
|
||||||
|
|
||||||
{ this.state.editing
|
|
||||||
? <input className="editable-list__edit-field"
|
|
||||||
type="text"
|
|
||||||
ref={ input => this.input = input }
|
|
||||||
value={ this.state.editValue }
|
|
||||||
onBlur={ this.handleEditEnd }
|
|
||||||
onChange={ this.handleInputChange }
|
|
||||||
onKeyPress={ this.handleInputKeyPress }/>
|
|
||||||
: this.props.text }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button className="editable-list__edit-button ghost"
|
|
||||||
title={ _("optionsUserAgentWhitelistEditItem") }
|
|
||||||
onClick={ this.handleEditBegin }
|
|
||||||
type="button">
|
|
||||||
<img src="assets/photon_edit.svg" alt="icon, edit" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button className="editable-list__remove-button ghost"
|
|
||||||
title={ _("optionsUserAgentWhitelistRemoveItem") }
|
|
||||||
onClick={ this.handleRemove }
|
|
||||||
type="button">
|
|
||||||
<img src="assets/photon_delete.svg" alt="icon, remove" />
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopEditing(input: HTMLInputElement) {
|
|
||||||
if (this.props.editing
|
|
||||||
&& !this.props.itemPattern.test(this.state.editValue)) {
|
|
||||||
input.setCustomValidity(this.props.itemPatternError());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!input.validity.valid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onEdit(this.props.text, this.state.editValue);
|
|
||||||
this.setState({
|
|
||||||
editing: false
|
|
||||||
, editValue: ""
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleRemove() {
|
|
||||||
this.props.onRemove(this.props.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleEditBegin() {
|
|
||||||
if (!this.state.editing) {
|
|
||||||
this.setState({
|
|
||||||
editing: true
|
|
||||||
, editValue: this.props.text
|
|
||||||
}, () => {
|
|
||||||
this.input?.focus();
|
|
||||||
this.input?.select();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleEditEnd(ev: React.FocusEvent<HTMLInputElement>) {
|
|
||||||
this.stopEditing(ev.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleInputChange(ev: React.ChangeEvent<HTMLInputElement>) {
|
|
||||||
this.setState({
|
|
||||||
editValue: ev.target.value
|
|
||||||
});
|
|
||||||
|
|
||||||
// If invalid, set custom error from parent
|
|
||||||
ev.target.setCustomValidity(!this.props.itemPattern.test(ev.target.value)
|
|
||||||
? this.props.itemPatternError()
|
|
||||||
: "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleInputKeyPress(ev: React.KeyboardEvent<HTMLInputElement>) {
|
|
||||||
if (ev.key === "Enter") {
|
|
||||||
this.stopEditing(ev.target as HTMLInputElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
225
ext/src/ui/options/Whitelist.tsx
Normal file
225
ext/src/ui/options/Whitelist.tsx
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/* eslint-disable max-len */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import React, { Component } from "react";
|
||||||
|
|
||||||
|
import type { WhitelistItemData } from "../../background/whitelist";
|
||||||
|
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
||||||
|
|
||||||
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
|
interface WhitelistProps {
|
||||||
|
items: WhitelistItemData[];
|
||||||
|
onChange: (items: WhitelistItemData[]) => void;
|
||||||
|
}
|
||||||
|
interface WhitelistState {
|
||||||
|
addingNewItem: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Editable list component for site whitelist. */
|
||||||
|
export default class Whitelist extends Component<
|
||||||
|
WhitelistProps,
|
||||||
|
WhitelistState
|
||||||
|
> {
|
||||||
|
state: WhitelistState = {
|
||||||
|
addingNewItem: false
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="whitelist">
|
||||||
|
<ul className="whitelist__items">
|
||||||
|
{this.props.items.map((item, i) => (
|
||||||
|
<WhitelistItem
|
||||||
|
value={item}
|
||||||
|
onEdit={(oldValue, newValue) => {
|
||||||
|
// Replace item
|
||||||
|
this.props.onChange(
|
||||||
|
this.props.items.map(item =>
|
||||||
|
item.pattern === oldValue?.pattern
|
||||||
|
? newValue
|
||||||
|
: item
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
onRemove={value => {
|
||||||
|
// Remove item
|
||||||
|
this.props.onChange(
|
||||||
|
this.props.items.filter(
|
||||||
|
item => item.pattern !== value?.pattern
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
key={i}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{this.state.addingNewItem && (
|
||||||
|
<WhitelistItem
|
||||||
|
isEditing={true}
|
||||||
|
onEdit={(__, newValue) => {
|
||||||
|
// Add new item
|
||||||
|
this.setState({ addingNewItem: false }, () => {
|
||||||
|
this.props.onChange([
|
||||||
|
...this.props.items,
|
||||||
|
newValue
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onRemove={() => {
|
||||||
|
// Cancel adding new item
|
||||||
|
this.setState({ addingNewItem: false });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<div className="whitelist__view-actions">
|
||||||
|
<button
|
||||||
|
className="whitelist__add-button ghost"
|
||||||
|
title={_("optionsSiteWhitelistAddItem")}
|
||||||
|
onClick={() => this.setState({ addingNewItem: true })}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<img src="assets/photon_new.svg" alt="icon, add" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WhitelistItemProps {
|
||||||
|
value?: WhitelistItemData;
|
||||||
|
/** Initial editing state */
|
||||||
|
isEditing?: boolean;
|
||||||
|
onEdit: (
|
||||||
|
oldValue: WhitelistItemData | undefined,
|
||||||
|
newValue: WhitelistItemData
|
||||||
|
) => void;
|
||||||
|
onRemove: (value?: WhitelistItemData) => void;
|
||||||
|
}
|
||||||
|
interface WhitelistItemState {
|
||||||
|
isEditing: boolean;
|
||||||
|
editValue?: WhitelistItemData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Editable item component for whitelist. */
|
||||||
|
class WhitelistItem extends Component<WhitelistItemProps, WhitelistItemState> {
|
||||||
|
private inputElement: HTMLInputElement | null = null;
|
||||||
|
|
||||||
|
constructor(props: WhitelistItemProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = { isEditing: props.isEditing ?? false };
|
||||||
|
|
||||||
|
this.beginEditing = this.beginEditing.bind(this);
|
||||||
|
this.finishEditing = this.finishEditing.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets editing state and focuses input field. */
|
||||||
|
private beginEditing() {
|
||||||
|
if (this.state.isEditing) return;
|
||||||
|
|
||||||
|
this.setState(
|
||||||
|
{
|
||||||
|
isEditing: true,
|
||||||
|
editValue: this.props.value
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.inputElement?.focus();
|
||||||
|
this.inputElement?.select();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks input validity and sends edit update. */
|
||||||
|
private finishEditing() {
|
||||||
|
if (!this.state.isEditing || !this.state.editValue) return;
|
||||||
|
|
||||||
|
if (this.inputElement?.validity.valid) {
|
||||||
|
this.props.onEdit(this.props.value, this.state.editValue);
|
||||||
|
this.setState({
|
||||||
|
isEditing: false,
|
||||||
|
editValue: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const selectedClassName = this.state.isEditing
|
||||||
|
? "whitelist__item--selected"
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className={`whitelist__item ${selectedClassName}`}>
|
||||||
|
<div
|
||||||
|
className="whitelist__title"
|
||||||
|
onDoubleClick={this.beginEditing}
|
||||||
|
>
|
||||||
|
{this.state.isEditing ? (
|
||||||
|
<input
|
||||||
|
ref={el => (this.inputElement = el)}
|
||||||
|
type="text"
|
||||||
|
className="whitelist__input-pattern"
|
||||||
|
value={this.state.editValue?.pattern}
|
||||||
|
pattern={REMOTE_MATCH_PATTERN_REGEX.source}
|
||||||
|
onChange={ev => {
|
||||||
|
this.setState(prevState => ({
|
||||||
|
editValue: {
|
||||||
|
...prevState.editValue,
|
||||||
|
pattern: ev.target.value
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
onBlur={this.finishEditing}
|
||||||
|
onKeyPress={ev => {
|
||||||
|
if (ev.key === "Enter") {
|
||||||
|
this.finishEditing();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
this.props.value?.pattern
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="whitelist__user-agent">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={!this.props.value?.isUserAgentDisabled}
|
||||||
|
onChange={ev => {
|
||||||
|
if (!this.props.value) return;
|
||||||
|
this.props.onEdit(this.props.value, {
|
||||||
|
...this.props.value,
|
||||||
|
isUserAgentDisabled: !ev.target.checked
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{_("optionsSiteWhitelistUserAgent")}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="whitelist__edit-button ghost"
|
||||||
|
title={_("optionsSiteWhitelistEditItem")}
|
||||||
|
onClick={this.beginEditing}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<img src="assets/photon_edit.svg" alt="icon, edit" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="whitelist__remove-button ghost"
|
||||||
|
title={_("optionsSiteWhitelistRemoveItem")}
|
||||||
|
onClick={() => {
|
||||||
|
this.props.onRemove(this.props.value);
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<img src="assets/photon_delete.svg" alt="icon, remove" />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,14 +5,14 @@ import React, { Component } from "react";
|
|||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
|
||||||
import defaultOptions from "../../defaultOptions";
|
import defaultOptions from "../../defaultOptions";
|
||||||
|
import type { WhitelistItemData } from "../../background/whitelist";
|
||||||
|
|
||||||
import Bridge from "./Bridge";
|
import Bridge from "./Bridge";
|
||||||
import EditableList from "./EditableList";
|
import Whitelist from "./Whitelist";
|
||||||
|
|
||||||
import bridge, { BridgeInfo, BridgeTimedOutError } from "../../lib/bridge";
|
import bridge, { BridgeInfo, BridgeTimedOutError } from "../../lib/bridge";
|
||||||
import logger from "../../lib/logger";
|
import logger from "../../lib/logger";
|
||||||
import options, { Options } from "../../lib/options";
|
import options, { Options } from "../../lib/options";
|
||||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
@@ -77,9 +77,6 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
|||||||
this.handleFormChange = this.handleFormChange.bind(this);
|
this.handleFormChange = this.handleFormChange.bind(this);
|
||||||
this.handleInputChange = this.handleInputChange.bind(this);
|
this.handleInputChange = this.handleInputChange.bind(this);
|
||||||
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
||||||
|
|
||||||
this.getWhitelistItemPatternError =
|
|
||||||
this.getWhitelistItemPatternError.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
@@ -333,77 +330,43 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
|||||||
|
|
||||||
<fieldset className="category">
|
<fieldset className="category">
|
||||||
<legend className="category__name">
|
<legend className="category__name">
|
||||||
<h2>
|
<h2>{_("optionsSiteWhitelistCategoryName")}</h2>
|
||||||
{_("optionsUserAgentWhitelistCategoryName")}
|
|
||||||
</h2>
|
|
||||||
</legend>
|
</legend>
|
||||||
<p className="category__description">
|
<p className="category__description">
|
||||||
{_("optionsUserAgentWhitelistCategoryDescription")}
|
{_("optionsSiteWhitelistCategoryDescription")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input
|
<input
|
||||||
name="userAgentWhitelistEnabled"
|
name="siteWhitelistEnabled"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={
|
checked={
|
||||||
this.state.options
|
this.state.options?.siteWhitelistEnabled
|
||||||
?.userAgentWhitelistEnabled
|
|
||||||
}
|
}
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{_("optionsUserAgentWhitelistEnabled")}
|
{_("optionsSiteWhitelistEnabled")}
|
||||||
<span className="option__recommended">
|
|
||||||
{_("optionsOptionRecommended")}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label className="option option--inline">
|
|
||||||
<div className="option__control">
|
|
||||||
<input
|
|
||||||
name="userAgentWhitelistRestrictedEnabled"
|
|
||||||
type="checkbox"
|
|
||||||
checked={
|
|
||||||
this.state.options
|
|
||||||
?.userAgentWhitelistRestrictedEnabled
|
|
||||||
}
|
|
||||||
onChange={this.handleInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="option__label">
|
|
||||||
{_(
|
|
||||||
"optionsUserAgentWhitelistRestrictedEnabled"
|
|
||||||
)}
|
|
||||||
<span className="option__recommended">
|
<span className="option__recommended">
|
||||||
{_("optionsOptionRecommended")}
|
{_("optionsOptionRecommended")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{_(
|
{_("optionsSiteWhitelistEnabledDescription")}
|
||||||
"optionsUserAgentWhitelistRestrictedEnabledDescription"
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{_("optionsUserAgentWhitelistContent")}
|
{_("optionsSiteWhitelistContent")}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
{this.state.options?.userAgentWhitelist && (
|
{this.state.options?.userAgentWhitelist && (
|
||||||
<EditableList
|
<Whitelist
|
||||||
data={
|
items={this.state.options.siteWhitelist}
|
||||||
this.state.options
|
|
||||||
.userAgentWhitelist
|
|
||||||
}
|
|
||||||
onChange={this.handleWhitelistChange}
|
onChange={this.handleWhitelistChange}
|
||||||
itemPattern={REMOTE_MATCH_PATTERN_REGEX}
|
|
||||||
itemPatternError={
|
|
||||||
this.getWhitelistItemPatternError
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -485,22 +448,15 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWhitelistChange(whitelist: string[]) {
|
private handleWhitelistChange(whitelist: WhitelistItemData[]) {
|
||||||
this.setState(currentState => {
|
this.setState(currentState => {
|
||||||
if (currentState.options) {
|
if (currentState.options) {
|
||||||
currentState.options.userAgentWhitelist = whitelist;
|
currentState.options.siteWhitelist = whitelist;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentState;
|
return currentState;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getWhitelistItemPatternError(info: string): string {
|
|
||||||
return _("optionsUserAgentWhitelistInvalidMatchPattern", info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReactDOM.render(<OptionsApp />, document.querySelector("#root"));
|
||||||
ReactDOM.render(
|
|
||||||
<OptionsApp />
|
|
||||||
, document.querySelector("#root"));
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ button.ghost:not(:hover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.editable-list {
|
.whitelist {
|
||||||
background-color: var(--box-background);
|
background-color: var(--box-background);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
color: var(--box-color);
|
color: var(--box-color);
|
||||||
@@ -324,22 +324,18 @@ button.ghost:not(:hover) {
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__view-actions {
|
.whitelist__view-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__save-raw-button {
|
.whitelist hr {
|
||||||
margin-inline-end: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editable-list hr {
|
|
||||||
border: initial;
|
border: initial;
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__items {
|
.whitelist__items {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: initial;
|
margin: initial;
|
||||||
@@ -348,22 +344,22 @@ button.ghost:not(:hover) {
|
|||||||
width: calc(100% + 10px);
|
width: calc(100% + 10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__item {
|
.whitelist__item {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__item:nth-child(odd) {
|
.whitelist__item:nth-child(odd) {
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__item--selected {
|
.whitelist__item--selected {
|
||||||
background-color: var(--blue-50-a30) !important;
|
background-color: var(--blue-50-a30) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__title {
|
.whitelist__title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -372,28 +368,24 @@ button.ghost:not(:hover) {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__item:not(.editable-list__item--selected) > .editable-list__title {
|
.whitelist__item:not(.whitelist__item--selected) > .whitelist__title {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__title + button {
|
.whitelist__title + button {
|
||||||
margin-inline-end: 5px;
|
margin-inline-end: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__edit-field {
|
.whitelist__input-pattern {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
margin-inline-end: 1em;
|
margin-inline-end: 1em;
|
||||||
width: -moz-available;
|
width: -moz-available;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable-list__raw-view {
|
.whitelist__user-agent {
|
||||||
max-height: 300px;
|
margin-inline-end: 5px;
|
||||||
overflow-y: auto;
|
|
||||||
resize: vertical;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
.whitelist__add-button {
|
||||||
.editable-list__add-button {
|
|
||||||
margin-inline-end: auto;
|
margin-inline-end: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +402,7 @@ button.ghost:not(:hover) {
|
|||||||
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.editable-list__item:nth-child(odd) {
|
.whitelist__item:nth-child(odd) {
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import React, { Component } from "react";
|
|||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
|
|
||||||
import { menuIdPopupCast, menuIdPopupStop } from "../../background/menus";
|
import { menuIdPopupCast, menuIdPopupStop } from "../../background/menus";
|
||||||
|
import type { ReceiverSelectorPageInfo } from "../../background/ReceiverSelector";
|
||||||
|
import type { WhitelistItemData } from "../../background/whitelist";
|
||||||
|
|
||||||
import knownApps, { KnownApp } from "../../cast/knownApps";
|
import knownApps, { KnownApp } from "../../cast/knownApps";
|
||||||
import options from "../../lib/options";
|
import options from "../../lib/options";
|
||||||
@@ -20,7 +22,6 @@ import {
|
|||||||
ReceiverSelectorMediaType
|
ReceiverSelectorMediaType
|
||||||
} from "../../types";
|
} from "../../types";
|
||||||
|
|
||||||
import { ReceiverSelectorPageInfo } from "../../background/ReceiverSelector";
|
|
||||||
import { Capability } from "../../cast/sdk/enums";
|
import { Capability } from "../../cast/sdk/enums";
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
@@ -92,8 +93,8 @@ interface PopupAppState {
|
|||||||
|
|
||||||
// Options
|
// Options
|
||||||
mirroringEnabled: boolean;
|
mirroringEnabled: boolean;
|
||||||
userAgentWhitelistEnabled: boolean;
|
siteWhitelistEnabled: boolean;
|
||||||
userAgentWhitelist: string[];
|
siteWhitelist: WhitelistItemData[];
|
||||||
}
|
}
|
||||||
|
|
||||||
class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||||
@@ -114,8 +115,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
isPageWhitelisted: false,
|
isPageWhitelisted: false,
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
mirroringEnabled: false,
|
mirroringEnabled: false,
|
||||||
userAgentWhitelistEnabled: true,
|
siteWhitelistEnabled: true,
|
||||||
userAgentWhitelist: []
|
siteWhitelist: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store window ref
|
// Store window ref
|
||||||
@@ -229,8 +230,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
|
|
||||||
// Check if target page URL is whitelisted.
|
// Check if target page URL is whitelisted.
|
||||||
if (this.state.pageInfo) {
|
if (this.state.pageInfo) {
|
||||||
for (const patternString of this.state.userAgentWhitelist) {
|
for (const item of this.state.siteWhitelist) {
|
||||||
const pattern = new RemoteMatchPattern(patternString);
|
const pattern = new RemoteMatchPattern(item.pattern);
|
||||||
if (pattern.matches(this.state.pageInfo.url)) {
|
if (pattern.matches(this.state.pageInfo.url)) {
|
||||||
isPageWhitelisted = true;
|
isPageWhitelisted = true;
|
||||||
break;
|
break;
|
||||||
@@ -249,10 +250,10 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const whitelist = await options.get("userAgentWhitelist");
|
const whitelist = await options.get("siteWhitelist");
|
||||||
if (!whitelist.includes(app.matches)) {
|
if (!whitelist.find(item => item.pattern === app.matches)) {
|
||||||
whitelist.push(app.matches);
|
whitelist.push({ pattern: app.matches });
|
||||||
await options.set("userAgentWhitelist", whitelist);
|
await options.set("siteWhitelist", whitelist);
|
||||||
|
|
||||||
await browser.tabs.reload(pageInfo.tabId);
|
await browser.tabs.reload(pageInfo.tabId);
|
||||||
window.close();
|
window.close();
|
||||||
@@ -382,8 +383,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
options.getAll().then(opts => {
|
options.getAll().then(opts => {
|
||||||
this.setState({
|
this.setState({
|
||||||
mirroringEnabled: opts.mirroringEnabled,
|
mirroringEnabled: opts.mirroringEnabled,
|
||||||
userAgentWhitelistEnabled: opts.userAgentWhitelistEnabled,
|
siteWhitelistEnabled: opts.siteWhitelistEnabled,
|
||||||
userAgentWhitelist: opts.userAgentWhitelist
|
siteWhitelist: opts.siteWhitelist
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -429,9 +430,9 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
// If we don't know the app
|
// If we don't know the app
|
||||||
!this.state.knownApp ||
|
!this.state.knownApp ||
|
||||||
// If the whitelist is disabled
|
// If the whitelist is disabled
|
||||||
!this.state.userAgentWhitelistEnabled ||
|
!this.state.siteWhitelistEnabled ||
|
||||||
// If the whitelist is enabled, and the page is whitelisted
|
// If the whitelist is enabled, and the page is whitelisted
|
||||||
(this.state.userAgentWhitelistEnabled &&
|
(this.state.siteWhitelistEnabled &&
|
||||||
this.state.isPageWhitelisted) ||
|
this.state.isPageWhitelisted) ||
|
||||||
// If an app is already loaded on the page
|
// If an app is already loaded on the page
|
||||||
!!(
|
!!(
|
||||||
|
|||||||
Reference in New Issue
Block a user