Files

1180 lines
34 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2017; Licensed under the Apache License, Version 2.0: https://www.apache.org/licenses/LICENSE-2.0
if (typeof globalThis.browser === "undefined" && typeof chrome !== "undefined") {
globalThis.browser = {
...chrome,
runtime: {
...chrome.runtime,
sendMessage: function(message) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(message, response => {
const err = chrome.runtime.lastError;
// Chrome sets lastError when a message intentionally has no direct response.
// Firefox-style Nazeka code often uses async side-channel replies instead.
if (err) {
console.warn("Nazeka sendMessage warning:", err.message);
resolve(undefined);
} else {
resolve(response);
}
});
});
},
getPlatformInfo: function() {
return new Promise((resolve, reject) => {
chrome.runtime.getPlatformInfo(info => {
const err = chrome.runtime.lastError;
if (err) reject(err);
else resolve(info);
});
});
},
getURL: chrome.runtime.getURL.bind(chrome.runtime),
onMessage: {
addListener: function(listener) {
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
try {
const result = listener(message, sender);
if (result && typeof result.then === "function") {
result.then(sendResponse).catch(error => {
console.error("Nazeka message listener error:", error);
sendResponse(undefined);
});
return true;
}
if (result !== undefined) {
sendResponse(result);
}
return false;
} catch (error) {
console.error("Nazeka message listener exception:", error);
sendResponse(undefined);
return false;
}
});
}
}
},
storage: {
...chrome.storage,
local: {
...chrome.storage.local,
get: function(keys) {
return new Promise((resolve, reject) => {
chrome.storage.local.get(keys, result => {
const err = chrome.runtime.lastError;
if (err) reject(err);
else resolve(result);
});
});
},
set: function(items) {
return new Promise((resolve, reject) => {
chrome.storage.local.set(items, () => {
const err = chrome.runtime.lastError;
if (err) reject(err);
else resolve();
});
});
},
remove: function(keys) {
return new Promise((resolve, reject) => {
chrome.storage.local.remove(keys, () => {
const err = chrome.runtime.lastError;
if (err) reject(err);
else resolve();
});
});
}
},
onChanged: chrome.storage.onChanged
},
tabs: chrome.tabs ? {
...chrome.tabs,
getCurrent: function() {
return new Promise((resolve, reject) => {
chrome.tabs.getCurrent(tab => {
const err = chrome.runtime.lastError;
if (err) reject(err);
else resolve(tab);
});
});
},
sendMessage: function(tabId, message) {
return new Promise((resolve, reject) => {
chrome.tabs.sendMessage(tabId, message, response => {
const err = chrome.runtime.lastError;
if (err) {
console.warn("Nazeka tabs.sendMessage warning:", err.message);
resolve(undefined);
} else {
resolve(response);
}
});
});
},
create: chrome.tabs.create.bind(chrome.tabs)
} : undefined,
windows: chrome.windows ? {
...chrome.windows,
create: chrome.windows.create.bind(chrome.windows)
} : undefined,
extension: {
...chrome.extension,
getURL: chrome.runtime.getURL.bind(chrome.runtime)
},
browserAction: chrome.browserAction || undefined,
contextMenus: chrome.contextMenus || undefined
};
}
function storageGet(key) {
return new Promise((resolve, reject) => {
browser.storage.local.get(key, result => {
if (browser.runtime.lastError) {
reject(browser.runtime.lastError);
} else {
resolve(result);
}
});
});
}
function storageSet(value) {
return new Promise((resolve, reject) => {
browser.storage.local.set(value, () => {
if (browser.runtime.lastError) {
reject(browser.runtime.lastError);
} else {
resolve();
}
});
});
}
'use strict';
let platform = "win";
async function get_real_platform()
{
let my_platform = undefined;
try {
my_platform = await browser.runtime.sendMessage({type:"platform"});
if(my_platform)
my_platform = my_platform["response"];
}catch(err){}
while(my_platform == "")
{
try {
my_platform = await browser.runtime.sendMessage({type:"platform"});
if(my_platform)
my_platform = my_platform["response"];
}catch(err){}
}
platform = my_platform;
}
let settings = [];
function defaults()
{
// behavior
settings.push({
kind: "dummy",
label: "Behavior"
});
settings.push({
id: "enabled",
kind: "checkbox",
default: true,
label: "Enabled"
});
settings.push({
id: "kanji_mode",
kind: "checkbox",
default: true,
label: "Individual kanji information mode"
});
settings.push({
id: "compact",
kind: "checkbox",
default: true,
label: "Compact"
});
settings.push({
id: "showoriginal",
kind: "checkbox",
default: true,
label: "Show original text"
});
settings.push({
id: "space_saver",
kind: "checkbox",
default: false,
label: "Space saver (removes extra formatting from readings and other spellings)"
});
settings.push({
id: "hide_deconj",
kind: "checkbox",
default: false,
label: "Hide deconjugations"
});
settings.push({
id: "popup_follows_mouse",
kind: "checkbox",
default: true,
label: "Popup follows mouse (even if it doesn't update)"
});
settings.push({
id: "length",
kind: "number",
min: 6,
max: 100,
step: 1,
default: 25,
label: "Search length (characters) (default 25, sane values are from 25 to 50)"
});
settings.push({
id: "lookuprate",
kind: "number",
min: 1,
max: 1000,
step: 1,
default: 8,
label: "Lookup throttle (milliseconds)"
});
settings.push({
id: "alternatives_mode",
kind: "combobox",
options: ["Longest match only", "Longest and second longest match", "Longest and shortest match", "All matches"],
default: 3,
label: "Matching mode"
});
settings.push({
id: "strict_alternatives",
kind: "checkbox",
default: true,
label: "Strict matching for alternative matches"
});
settings.push({
id: "definitions_mode",
kind: "combobox",
options: ["From jmdict then json", "From json then jmdict", "From json; otherwise jmdict", "From json dictionary only", "None"],
default: 0,
label: "Where to look for definitions (does not affect jmdict readings)"
});
settings.push({
id: "normal_definitions_in_mining",
kind: "checkbox",
default: false,
label: "Force \"From jmdict then json\" definitions mode when mining UI is open"
});
settings.push({
id: "strict_epwing",
kind: "checkbox",
default: true,
label: "Strict matching for json dictionary matches"
});
settings.push({
id: "json_newlines_replace",
kind: "checkbox",
default: false,
label: "Replace json dictionary linebreaks with this character (blank for newlines)"
});
settings.push({
id: "json_newlines_character",
kind: "text",
default: " ⬥ ",
label: "Character to replace json dictionary linebreaks with"
});
settings.push({
id: "json_ignore_entries",
kind: "text",
default: "一,二,三,四,五,六,七,八,九,〇",
label: "Ignore json dictionary entries with these spellings"
});
settings.push({
id: "popup_requires_key",
kind: "combobox",
options: ["None", "Ctrl", "Shift"],
default: 0,
label: "Popup requires key"
});
settings.push({
id: "strip_spaces",
kind: "checkbox",
default: true,
label: "Strip spaces (for when spaces find their way into Japanese text and it breaks word searching)"
});
settings.push({
id: "ignore_linebreaks",
kind: "checkbox",
default: true,
label: "Ignore hard line breaks (disable for text with preformatted linebreaks)"
});
settings.push({
id: "ignore_divs",
kind: "checkbox",
default: false,
label: "Search out from within block-like elements like divs (enable only for very poorly-constructed web pages; usually causes performance problems)"
});
settings.push({
id: "live_mining",
kind: "checkbox",
default: false,
label: "Enable live mining (configured via the button below under \"Other\")"
});
settings.push({
id: "ankiconnect_force_sync",
kind: "checkbox",
default: false,
label: "Force Anki to sync to AnkiWeb after each mined card"
});
settings.push({
id: "use_selection",
kind: "checkbox",
default: false,
label: "Use text selection to limit lookup length and force context"
});
settings.push({
id: "only_selection",
kind: "checkbox",
default: false,
label: "Only look up text when mousing over selection (only when something is selected, setting ignored otherwise)"
});
settings.push({
id: "freqlist_mode",
kind: "combobox",
options: ["None", "Visual Novels", "Narou", "Novels"],
default: 1,
label: "Frequency data source"
});
// display
settings.push({
kind: "dummy",
label: "Display"
});
settings.push({
id: "scale",
kind: "number",
min: 0.1,
max: 64,
step: 0.1,
default: 1,
label: "Lookup popup scale"
});
settings.push({
id: "xoffset",
kind: "number",
min: 1,
max: 200,
step: 1,
default: 5,
label: "Popup offset, horizontal (pixels, default is 5)"
});
settings.push({
id: "yoffset",
kind: "number",
min: 1,
max: 200,
step: 1,
default: 22,
label: "Popup offset, vertical (pixels, default is 22)"
});
settings.push({
id: "width",
kind: "number",
min: 100,
max: 10000,
step: 1,
default: 600,
label: "Lookup popup width (before scaling) (limited to half the browser window width)"
});
settings.push({
id: "sticky_maxheight",
kind: "number",
min: 0,
max: 10000,
default: 0,
label: "Maximum height of Sticky and Mining UI modes - 0 is full screen"
});
settings.push({
id: "fixedwidth",
kind: "checkbox",
default: false,
label: "Fixed width"
});
settings.push({
id: "novalign",
kind: "checkbox",
default: false,
label: "Disable use of `vertical-align: middle;` for reading/etc info"
});
settings.push({
id: "inserthr",
kind: "checkbox",
default: false,
label: "Insert horizontal bar between entries"
});
/*
// currently broken
settings.push({
id: "fixedwidthpositioning",
kind: "checkbox",
default: false,
label: "Position as though fixed width (currently nonfunctional; will fix later)"
});
*/
settings.push({
id: "corner",
kind: "combobox",
options: ["Top left", "Top right", "Bottom left", "Bottom right"],
default: 0,
label: "Which corner of the popup follows the mouse"
});
settings.push({
id: "x_dodge",
kind: "combobox",
options: ["Flip", "Push"],
default: 1,
label: "How to keep the popup on the screen horizontally"
});
settings.push({
id: "y_dodge",
kind: "combobox",
options: ["Flip", "Push"],
default: 0,
label: "How to keep the popup on the screen vertically (at least one of these two options should be \"Flip\")"
});
// theme
settings.push({
kind: "dummy",
label: "Theme"
});
settings.push({
id: "superborder",
kind: "checkbox",
default: false,
label: "Super border"
});
settings.push({
id: "disableborder",
kind: "checkbox",
default: false,
label: "Disable border"
});
settings.push({
id: "dropshadow",
kind: "checkbox",
default: false,
label: "Enable dropshadow"
});
settings.push({
id: "bgcolor",
kind: "color",
default: "#111111",
label: "Background color"
});
settings.push({
id: "fgcolor",
kind: "color",
default: "#CCCCCC",
label: "Foreground color"
});
settings.push({
id: "hlcolor",
kind: "color",
default: "#99DDFF",
label: "Main highlight color"
});
settings.push({
id: "hlcolor2",
kind: "color",
default: "#99FF99",
label: "Reading highlight color"
});
settings.push({
id: "titlecolor",
kind: "color",
default: "#D8A888",
label: "Dictionary title color (for when using json dictionaries)"
});
settings.push({
id: "highlight_dict_headers",
kind: "checkbox",
default: false,
label: "Highlight dictionary headers"
});
settings.push({
id: "dropshadowcolor",
kind: "color",
default: "#000000",
label: "Dropshadow color"
});
settings.push({
id: "dropshadowradius",
kind: "number",
min: 1,
max: 50,
default: 10,
label: "Dropshadow radius"
});
settings.push({
id: "font",
kind: "text",
default: "",
label: "Font override (without trailing comma)"
});
settings.push({
id: "definition_fontsize",
kind: "number",
min: 4,
max: 48,
default: 13,
label: "Definition font size"
});
settings.push({
id: "dict_item_fontsize",
kind: "number",
min: 4,
max: 48,
default: 18,
label: "Dictionary item font size"
});
settings.push({
id: "reading_fontsize",
kind: "number",
min: 4,
max: 48,
default: 15,
label: "Reading font size"
});
settings.push({
id: "hlfont",
kind: "text",
default: "",
label: "Font override (highlighted text only) (without trailing comma)"
});
settings.push({
id: "sticky",
kind: "checkbox",
default: false,
label: "Sticky mode"
});
settings.push({
id: "padding",
kind: "number",
min: 0,
max: 10,
default: 2,
label: "Padding"
});
settings.push({
id: "info_styling",
kind: "checkbox",
default: false,
label: "Yomichan-like definition info tag styling"
});
settings.push({
id: "info_fgcolor",
kind: "color",
default: "#CCCCCC",
label: "Yomichan-like info tag text color"
});
settings.push({
id: "info_bgcolor_pos",
kind: "color",
default: "#284880",
label: "Yomichan-like info tag background for part-of-speech tags"
});
settings.push({
id: "info_bgcolor_num",
kind: "color",
default: "#484848",
label: "Yomichan-like info tag background color for sense numbers"
});
settings.push({
id: "info_bgcolor_etc",
kind: "color",
default: "#305028",
label: "Yomichan-like info tag background color for etc tags"
});
// reader
settings.push({
kind: "dummy",
label: "Reader"
});
settings.push({
id: "reader_width",
kind: "number",
min: 100,
max: 10000,
step: 1,
default: 806,
label: "Reader window default width"
});
settings.push({
id: "reader_height",
kind: "number",
min: 50,
max: 10000,
step: 1,
default: 300,
label: "Reader window default height"
});
settings.push({
id: "reader_leeway",
kind: "number",
min: 0,
max: 10000,
step: 1,
default: 200,
label: "Reader autoscroll leeway (when \"insert at bottom\" is enabled) (0 disables)"
});
settings.push({
id: "reader_sticky",
kind: "checkbox",
default: false,
label: "Force 'sticky' mode in reader"
});
settings.push({
id: "reader_auto",
kind: "checkbox",
default: false,
label: "Automatically look up the beginning of new text in the reader"
});
settings.push({
id: "reader_reverse",
kind: "checkbox",
default: false,
label: "Reader insert at bottom"
});
settings.push({
id: "reader_convert_newlines",
kind: "checkbox",
default: false,
label: "Reader force newlines into linebreaks"
});
settings.push({
id: "reader_bg",
kind: "color",
default: "#111111",
label: "Reader background color"
});
settings.push({
id: "reader_fg",
kind: "color",
default: "#CCCCCC",
label: "Reader new text color"
});
settings.push({
id: "reader_fg_old",
kind: "color",
default: "#B0B0B0",
label: "Reader old text color"
});
settings.push({
id: "reader_font_size",
kind: "text",
default: "1.4em",
label: "Reader text size"
});
settings.push({
id: "reader_right_padding",
kind: "text",
default: "0px",
label: "Reader right padding (useful if you use 'sticky' mode)"
});
settings.push({
id: "reader_max_width",
kind: "text",
default: "1000px",
label: "Reader max width"
});
settings.push({
id: "reader_margin",
kind: "text",
default: "8px",
label: "Reader left/right margins"
});
settings.push({
id: "reader_font",
kind: "text",
default: "",
label: "Reader font override (without trailing comma)"
});
settings.push({
id: "reader_line_height",
kind: "text",
default: "normal",
label: "Reader line height size (default: 'normal' example: '140%')"
});
settings.push({
id: "reader_throttle",
kind: "number",
min: 5,
max: 1000,
step: 5,
default: 200,
label: "Reader clipboard access interval"
});
// hotkeys
settings.push({
kind: "dummy",
label: "Kanji mode"
});
settings.push({
id: "kanji_show_stroke_count",
kind: "checkbox",
default: true,
label: "Show stroke count"
});
settings.push({
id: "kanji_show_readings",
kind: "checkbox",
default: true,
label: "Show jouyou readings"
});
settings.push({
id: "kanji_show_composition",
kind: "checkbox",
default: true,
label: "Show composition"
});
settings.push({
id: "kanji_show_quality_warning",
kind: "checkbox",
default: true,
label: "Show data quality warning"
});
// hotkeys
settings.push({
kind: "dummy",
label: "Hotkeys (KeyboardEvent.key values)"
});
settings.push({
id: "hotkey_mine",
kind: "text",
default: "m",
label: "Mining UI hotkey"
});
settings.push({
id: "hotkey_nazeka_toggle",
kind: "text",
default: "j",
label: "Toggle nazeka on/off"
});
settings.push({
id: "hotkey_close",
kind: "text",
default: "n",
label: "Close popup (does not disable nazeka)"
});
settings.push({
id: "hotkey_sticky",
kind: "text",
default: "b",
label: "Toggle sticky mode (useful for very long definition lists)"
});
settings.push({
id: "hotkey_audio",
kind: "text",
default: "p",
label: "Play audio from jpod101 if available"
});
settings.push({
id: "hotkey_kanji_mode",
kind: "text",
default: "k",
label: "Toggle individual kanji information mode on/off"
});
settings.push({
id: "hotkey_nudge_left",
kind: "text",
default: "ArrowLeft",
label: "Nudge lookup text left"
});
settings.push({
id: "hotkey_nudge_right",
kind: "text",
default: "ArrowRight",
label: "Nudge lookup text right"
});
settings.push({
id: "volume",
kind: "number",
min: 0.0,
max: 1.0,
step: 0.05,
default: 0.2,
label: "Audio playback volume (press \"p\" while popup is open)"
});
settings.push({
id: "audio_force_https",
kind: "checkbox",
default: false,
label: "Grab audio files over HTTPS instead of HTTP"
});
// other (added imperatively)
settings.push({
kind: "dummy",
label: "Other"
});
}
defaults();
function restoreListeners()
{
for(let option of settings)
{
if(option.kind == "dummy") continue;
document.querySelector("#"+option.id).addEventListener("change", setOptions);
}
}
function removeListeners()
{
for(let option of settings)
{
if(option.kind == "dummy") continue;
document.querySelector("#"+option.id).removeEventListener("change", setOptions);
}
}
async function buildpage()
{
let optionsection = document.querySelector("#optionsection");
for(let option of settings)
{
if(option.kind == "dummy")
{
let header = document.createElement("h2");
header.textContent = option.label;
optionsection.appendChild(header);
continue;
}
let container = document.createElement("div");
let configger = undefined;
if(option.kind == "checkbox")
{
let input = document.createElement("input");
input.type = "checkbox";
input.id = option.id;
input.name = option.id;
input.checked = option.default;
input.style.zIndex = -100000;
configger = input;
}
if(option.kind == "number")
{
let input = document.createElement("input");
input.type = "number";
input.id = option.id;
input.name = option.id;
input.min = option.min;
input.max = option.max;
input.value = option.default;
input.step = option.step;
configger = input;
}
if(option.kind == "combobox")
{
let select = document.createElement("select");
select.id = option.id;
select.name = option.id;
let i = 0;
for(let setting of option.options)
{
let opt = document.createElement("option");
opt.value = i;
opt.text = setting;
select.add(opt);
i += 1;
}
select.value = option.default;
configger = select;
}
if(option.kind == "color")
{
let input = document.createElement("input");
input.type = "color";
input.id = option.id;
input.name = option.id;
input.value = option.default;
configger = input;
}
if(option.kind == "text")
{
let input = document.createElement("input");
input.type = "text";
input.id = option.id;
input.name = option.id;
input.value = option.default;
configger = input;
}
let label = document.createElement("label");
label.for = option.id;
let labelText = document.createTextNode(option.label);
if(option.kind == "checkbox")
{
label.appendChild(configger);
label.appendChild(labelText);
container.appendChild(label);
}
else
{
label.appendChild(labelText);
let cont1 = document.createElement("div");
let cont2 = document.createElement("div");
cont1.appendChild(configger);
cont2.appendChild(label);
container.appendChild(cont1);
container.appendChild(cont2);
}
container.style.marginBottom = "8px";
optionsection.appendChild(container);
}
await get_real_platform();
if(platform != "android")
{
// mining
let liveminingbutton = document.createElement("button");
liveminingbutton.type = "button";
liveminingbutton.innerText = "Configure live mining";
liveminingbutton.onclick = function(e){browser.windows.create({url:browser.extension.getURL('livemining.html'),type:'popup'}); e.preventDefault();};
optionsection.appendChild(liveminingbutton);
optionsection.appendChild(document.createElement("hr"));
// import
let jsonmanagebutton = document.createElement("button");
jsonmanagebutton.type = "button";
jsonmanagebutton.innerText = "Manage JSON Dictionaries";
jsonmanagebutton.onclick = function(e){browser.windows.create({url:browser.extension.getURL('json_config.html'),type:'popup'}); e.preventDefault();};
optionsection.appendChild(jsonmanagebutton);
optionsection.appendChild(document.createElement("hr"));
}
else
{
// import
let jsonmanagebutton = document.createElement("button");
jsonmanagebutton.type = "button";
jsonmanagebutton.innerText = "Manage JSON Dictionaries";
jsonmanagebutton.onclick = function(e){browser.tabs.create({url:browser.extension.getURL('json_config.html')}); e.preventDefault();};
optionsection.appendChild(jsonmanagebutton);
optionsection.appendChild(document.createElement("hr"));
}
// deconjugation rules
let decon_file = document.createElement("input");
decon_file.type = "file";
decon_file.id = "decon_file";
decon_file.addEventListener("change", () =>
{
let fname = document.querySelector("#decon_file").files[0];
let reader = new FileReader();
reader.onload = async(e) =>
{
try
{
let text = e.target.result;
if(text == "" || text == "\n" || text == "\r\n")
storageSet({"deconjugator_rules_json":""});
else
storageSet({"deconjugator_rules_json":JSON.stringify(JSON.parse())});
document.querySelector("#decon_label").textContent = "Imported. Might take a few seconds to apply.";
}
catch(except)
{
console.log(except.stack);
}
};
reader.readAsText(fname);
});
let decon_label = document.createElement("label");
decon_label.for = decon_file.id;
decon_label.id = "decon_label";
decon_label.textContent = "Import deconjugation ruleset. Overrides default deconjugation ruleset. Importing a blank file will restore the default ruleset.";
decon_label.style.display = "block";
optionsection.appendChild(decon_file);
optionsection.appendChild(decon_label);
optionsection.appendChild(document.createElement("hr"));
// backup
let backup_save = document.createElement("button");
backup_save.type = "button";
backup_save.innerText = "Save Backup";
backup_save.addEventListener("click", (async function ()
{
let blob = new Blob([JSON.stringify((await browser.storage.local.get()))], {type: 'text/plain'});
let url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "nazeka_data_backup.json";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}));
optionsection.appendChild(backup_save);
optionsection.appendChild(document.createElement("br"));
let backup_load = document.createElement("input");
backup_load.type = "file";
backup_load.id = "backup_file";
backup_load.addEventListener("change", () =>
{
let fname = document.querySelector("#backup_file").files[0];
let reader = new FileReader();
reader.onload = async(e) =>
{
try
{
storageSet(JSON.parse(e.target.result));
browser.runtime.sendMessage({type:"refreshjson"});
document.querySelector("#backup_load_label").textContent = "Loaded backup. Might take a few seconds to apply.";
}
catch(except)
{
console.log(except.stack);
}
};
reader.readAsText(fname);
});
// FIXME: add asking for the unlimited storage permission
let backup_load_label = document.createElement("label");
backup_load_label.for = backup_save.id;
backup_load_label.id = "backup_load_label";
backup_load_label.textContent = "Import Backup. WARNING: Overwrites ALMOST EVERYTHING, INCLUDING MINED CARDS.";
backup_load_label.style.display = "block";
optionsection.appendChild(backup_load);
optionsection.appendChild(backup_load_label);
optionsection.appendChild(document.createElement("hr"));
let abbrlink = document.getElementById("abbrlink");
abbrlink.onclick = function(e){browser.windows.create({url:browser.extension.getURL('jmdictabbreviations.html'),type:'popup'}); e.preventDefault();};
}
async function restoreOptions()
{
try
{
async function getvar(name, defval)
{
let temp = (await storageGet(name))[name]; // FIXME do this for all options instead of once per option
if(temp == undefined)
temp = defval;
return temp;
}
let alternatives_mode = await getvar("alternatives_mode", 0);
let strict_alternatives = await getvar("strict_alternatives", true);
removeListeners();
for(let option of settings)
{
if(option.kind == "dummy") continue;
let value = await getvar(option.id, option.default);
if(option.kind == "checkbox")
document.querySelector("#"+option.id).checked = value?true:false;
if(option.kind == "number" || option.kind == "text" || option.kind == "color" || option.kind == "combobox")
document.querySelector("#"+option.id).value = value?value:option.default;
}
} catch (error) {}
removeListeners();
restoreListeners();
}
function fixicon()
{
browser.runtime.sendMessage({type:"fixicon"});
}
function setOptions()
{
let setstuff = {};
for(let option of settings)
{
if(option.kind == "dummy") continue;
if(option.kind == "checkbox")
setstuff[option.id] = document.querySelector("#"+option.id).checked;
if(option.kind == "number")
{
let num = Number(document.querySelector("#"+option.id).value);
if(!num) // NaN is falsy
num = option.default;
if(option.step % 1 == 0)
num = Math.round(num);
setstuff[option.id] = num;
}
if(option.kind == "text")
setstuff[option.id] = document.querySelector("#"+option.id).value;
if(option.kind == "color")
setstuff[option.id] = document.querySelector("#"+option.id).value;
if(option.kind == "combobox")
setstuff[option.id] = document.querySelector("#"+option.id).value;
}
storageSet(setstuff).then(()=>{fixicon();},()=>{});
}
if (document.readyState == "complete")
{
buildpage();
restoreOptions();
}
else
{
document.addEventListener("DOMContentLoaded", buildpage);
document.addEventListener("DOMContentLoaded", restoreOptions);
}