extension: Add log level option

This commit is contained in:
relrelb 2021-09-25 13:02:01 +03:00 committed by relrelb
parent 1d324e81b0
commit d5b223c1b3
9 changed files with 126 additions and 48 deletions

View File

@ -47,13 +47,15 @@ body {
margin-top: 24px; margin-top: 24px;
} }
.option input { .option input,
.option select {
position: absolute; position: absolute;
right: 0;
}
.option.checkbox input {
width: 40px; width: 40px;
height: 20px; height: 20px;
top: 0;
bottom: 0;
right: 0;
margin: auto; margin: auto;
cursor: pointer; cursor: pointer;
z-index: 1; z-index: 1;
@ -65,8 +67,8 @@ body {
padding-right: 40px; padding-right: 40px;
} }
.option label::before, .option.checkbox label::before,
.option label::after { .option.checkbox label::after {
content: ""; content: "";
position: absolute; position: absolute;
border-radius: 10px; border-radius: 10px;
@ -76,25 +78,25 @@ body {
transition: background 0.2s, right 0.2s; transition: background 0.2s, right 0.2s;
} }
.option label::before { .option.checkbox label::before {
height: 20px; height: 20px;
width: 40px; width: 40px;
right: 0; right: 0;
background: gray; background: gray;
} }
.option label::after { .option.checkbox label::after {
height: 18px; height: 18px;
width: 18px; width: 18px;
right: 21px; right: 21px;
background: silver; background: silver;
} }
.option input:checked + label::before { .option.checkbox input:checked + label::before {
background: var(--ruffle-dark-orange); background: var(--ruffle-dark-orange);
} }
.option input:checked + label::after { .option.checkbox input:checked + label::after {
background: var(--ruffle-orange); background: var(--ruffle-orange);
right: 1px; right: 1px;
} }

View File

@ -19,18 +19,26 @@
</a> </a>
</div> </div>
<div class="container"> <div class="container">
<div class="option"> <div class="option checkbox">
<input type="checkbox" id="ruffle_enable" /> <input type="checkbox" id="ruffle_enable" />
<label for="ruffle_enable">Play Flash content in Ruffle</label> <label for="ruffle_enable">Play Flash content in Ruffle</label>
</div> </div>
<div class="option"> <div class="option checkbox">
<input type="checkbox" id="ignore_optout" /> <input type="checkbox" id="ignore_optout" />
<label for="ignore_optout">Ignore website compatibility warnings</label> <label for="ignore_optout">Ignore website compatibility warnings</label>
</div> </div>
<div class="option"> <div class="option checkbox">
<input type="checkbox" id="warn_on_unsupported_content" /> <input type="checkbox" id="warn_on_unsupported_content" />
<label for="warn_on_unsupported_content">Warn on unsupported content</label> <label for="warn_on_unsupported_content">Warn on unsupported content</label>
</div> </div>
<div class="option select">
<select id="log_level">
<option value="info">Info</option>
<option value="warn">Warning</option>
<option value="error">Error</option>
</select>
<label for="log_level">Log level</label>
</div>
</div> </div>
<script src="dist/options.js"></script> <script src="dist/options.js"></script>
</body> </body>

View File

@ -23,11 +23,11 @@
<span id="status-text">Ruffle is running.</span> <span id="status-text">Ruffle is running.</span>
</div> </div>
<div class="container"> <div class="container">
<div class="option"> <div class="option checkbox">
<input type="checkbox" id="ruffle_enable" /> <input type="checkbox" id="ruffle_enable" />
<label for="ruffle_enable">Play Flash content in Ruffle</label> <label for="ruffle_enable">Play Flash content in Ruffle</label>
</div> </div>
<div class="option"> <div class="option checkbox">
<input type="checkbox" id="ignore_optout" /> <input type="checkbox" id="ignore_optout" />
<label for="ignore_optout">Ignore website compatibility warnings</label> <label for="ignore_optout">Ignore website compatibility warnings</label>
</div> </div>

View File

@ -1,57 +1,122 @@
import * as utils from "./utils"; import * as utils from "./utils";
import type { LogLevel } from "ruffle-core";
export interface Options { export interface Options {
ruffleEnable: boolean; ruffleEnable: boolean;
ignoreOptout: boolean; ignoreOptout: boolean;
warnOnUnsupportedContent: boolean; warnOnUnsupportedContent: boolean;
logLevel: LogLevel;
} }
function getBooleanElements() { interface OptionElement<T> {
readonly input: Element;
readonly label: HTMLLabelElement;
value: T;
}
class CheckboxOption implements OptionElement<boolean> {
private checkbox: HTMLInputElement;
readonly label: HTMLLabelElement;
constructor(checkbox: HTMLInputElement, label: HTMLLabelElement) {
this.checkbox = checkbox;
this.label = label;
}
get input() {
return this.checkbox;
}
get value() {
return this.checkbox.checked;
}
set value(value: boolean) {
this.checkbox.checked = value;
}
}
class SelectOption implements OptionElement<string> {
private select: HTMLSelectElement;
readonly label: HTMLLabelElement;
constructor(select: HTMLSelectElement, label: HTMLLabelElement) {
this.select = select;
this.label = label;
}
get input() {
return this.select;
}
get value() {
const index = this.select.selectedIndex;
const option = this.select.options[index];
return option.value;
}
set value(value: string) {
const options = Array.from(this.select.options);
const index = options.findIndex((option) => option.value === value);
this.select.selectedIndex = index;
}
}
function getElement(option: Element): OptionElement<unknown> {
const [label] = option.getElementsByTagName("label");
const [checkbox] = option.getElementsByTagName("input");
if (checkbox && checkbox.type === "checkbox") {
return new CheckboxOption(checkbox, label);
}
const [select] = option.getElementsByTagName("select");
if (select) {
return new SelectOption(select, label);
}
throw new Error("Unknown option element");
}
function findOptionElements() {
const camelize = (s: string) => const camelize = (s: string) =>
s.replace(/[^a-z\d](.)/gi, (_, char) => char.toUpperCase()); s.replace(/[^a-z\d](.)/gi, (_, char) => char.toUpperCase());
const elements = new Map< const elements = new Map<keyof Options, OptionElement<unknown>>();
keyof Options,
{ option: Element; checkbox: HTMLInputElement; label: HTMLLabelElement }
>();
for (const option of document.getElementsByClassName("option")) { for (const option of document.getElementsByClassName("option")) {
const [checkbox] = option.getElementsByTagName("input"); const element = getElement(option);
if (checkbox.type !== "checkbox") { const key = camelize(element.input.id) as keyof Options;
continue; elements.set(key, element);
}
const [label] = option.getElementsByTagName("label");
const key = camelize(checkbox.id) as keyof Options;
elements.set(key, { option, checkbox, label });
} }
return elements; return elements;
} }
export async function bindBooleanOptions( export async function bindOptions(
onChange?: (options: Options) => void onChange?: (options: Options) => void
): Promise<void> { ): Promise<void> {
const elements = getBooleanElements(); const elements = findOptionElements();
const options = await utils.getOptions(Array.from(elements.keys())); const options = await utils.getOptions(Array.from(elements.keys()));
for (const [key, { checkbox, label }] of elements.entries()) { for (const [key, element] of elements.entries()) {
// Bind initial value. // Bind initial value.
checkbox.checked = options[key]; element.value = options[key];
// Prevent transition on load. // Prevent transition on load.
// Method from https://stackoverflow.com/questions/11131875. // Method from https://stackoverflow.com/questions/11131875.
label.classList.add("notransition"); element.label.classList.add("notransition");
label.offsetHeight; // Trigger a reflow, flushing the CSS changes. element.label.offsetHeight; // Trigger a reflow, flushing the CSS changes.
label.classList.remove("notransition"); element.label.classList.remove("notransition");
// Localize label. // Localize label.
const message = utils.i18n.getMessage(`settings_${checkbox.id}`); const message = utils.i18n.getMessage(`settings_${element.input.id}`);
if (message) { if (message) {
label.textContent = message; element.label.textContent = message;
} }
// Listen for user input. // Listen for user input.
checkbox.addEventListener("change", () => { element.input.addEventListener("change", () => {
const value = checkbox.checked; const value = element.value;
options[key] = value; options[key] = value as never;
utils.storage.sync.set({ [key]: value }); utils.storage.sync.set({ [key]: value });
}); });
} }
@ -67,8 +132,8 @@ export async function bindBooleanOptions(
if (!element) { if (!element) {
continue; continue;
} }
element.checkbox.checked = option.newValue; element.value = option.newValue;
options[key as keyof Options] = option.newValue; options[key as keyof Options] = option.newValue as never;
} }
if (onChange) { if (onChange) {

View File

@ -110,6 +110,7 @@ function isXMLDocument(): boolean {
"ruffleEnable", "ruffleEnable",
"ignoreOptout", "ignoreOptout",
"warnOnUnsupportedContent", "warnOnUnsupportedContent",
"logLevel",
]); ]);
const pageOptout = checkPageOptout(); const pageOptout = checkPageOptout();
const shouldLoad = const shouldLoad =
@ -175,6 +176,7 @@ function isXMLDocument(): boolean {
type: "load", type: "load",
config: { config: {
warnOnUnsupportedContent: options.warnOnUnsupportedContent, warnOnUnsupportedContent: options.warnOnUnsupportedContent,
logLevel: options.logLevel,
}, },
}); });
})(); })();

View File

@ -1,7 +1,7 @@
import * as utils from "./utils"; import * as utils from "./utils";
import { bindBooleanOptions } from "./common"; import { bindOptions } from "./common";
window.addEventListener("DOMContentLoaded", () => { window.addEventListener("DOMContentLoaded", () => {
document.title = utils.i18n.getMessage("settings_page"); document.title = utils.i18n.getMessage("settings_page");
bindBooleanOptions(); bindOptions();
}); });

View File

@ -1,5 +1,5 @@
import * as utils from "./utils"; import * as utils from "./utils";
import { PublicAPI, SourceAPI, Letterbox, LogLevel } from "ruffle-core"; import { PublicAPI, SourceAPI, Letterbox } from "ruffle-core";
const api = PublicAPI.negotiate( const api = PublicAPI.negotiate(
window.RufflePlayer!, window.RufflePlayer!,
@ -30,8 +30,7 @@ window.addEventListener("DOMContentLoaded", async () => {
const config = { const config = {
letterbox: Letterbox.On, letterbox: Letterbox.On,
logLevel: LogLevel.Warn, ...(await utils.getOptions(["warnOnUnsupportedContent", "logLevel"])),
...(await utils.getOptions(["warnOnUnsupportedContent"])),
}; };
player.load({ url: swfUrl, base: swfUrl, ...config }); player.load({ url: swfUrl, base: swfUrl, ...config });
}); });

View File

@ -1,5 +1,5 @@
import * as utils from "./utils"; import * as utils from "./utils";
import { Options, bindBooleanOptions } from "./common"; import { Options, bindOptions } from "./common";
let activeTab: chrome.tabs.Tab | browser.tabs.Tab; let activeTab: chrome.tabs.Tab | browser.tabs.Tab;
let savedOptions: Options; let savedOptions: Options;
@ -114,7 +114,7 @@ function displayTabStatus() {
} }
window.addEventListener("DOMContentLoaded", () => { window.addEventListener("DOMContentLoaded", () => {
bindBooleanOptions((options) => { bindOptions((options) => {
savedOptions = options; savedOptions = options;
optionsChanged(); optionsChanged();
}); });

View File

@ -1,9 +1,11 @@
import { Options } from "./common"; import { Options } from "./common";
import { LogLevel } from "ruffle-core";
const DEFAULT_OPTIONS: Options = { const DEFAULT_OPTIONS: Options = {
ruffleEnable: true, ruffleEnable: true,
ignoreOptout: false, ignoreOptout: false,
warnOnUnsupportedContent: true, warnOnUnsupportedContent: true,
logLevel: LogLevel.Error,
}; };
export let i18n: { export let i18n: {