4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | /* This CSS file contains some styles I use for my option pages */
20 |
21 | /* Dark them support */
22 |
23 | :root {
24 | --page-bg-color: #fff;
25 | --page-fg-color: #15141a;
26 | }
27 |
28 | @media (prefers-color-scheme: dark) {
29 | :root {
30 | --page-bg-color: #23222b;
31 | --page-fg-color: #fbfbfe;
32 | }
33 | }
34 |
35 | body {
36 | background-color: var(--page-bg-color);
37 | color: var(--page-fg-color);
38 | min-height: 250px; /* This fills the space in the add-ons manager */
39 | }
40 |
41 | /* Style for a checkbox with label, grouped by a */
42 |
43 | div.checkbox {
44 | display: flex;
45 | margin: 4px 0px;
46 | }
47 |
48 | div.checkbox input {
49 | margin: 2px 6px 2px 0px;
50 | }
51 |
52 | div.checkbox label {
53 | margin: 1px 0px;
54 | }
55 |
--------------------------------------------------------------------------------
/utils/storage.js:
--------------------------------------------------------------------------------
1 | /*
2 | WebExtension utils for use in my Firefox Add-ons
3 | Copyright (C) 2021 Manuel Reimer
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | 'use strict';
20 |
21 | // Central place for storage handling and preference defaults
22 | const Storage = {
23 | _defaults: false,
24 |
25 | get: async function() {
26 | if (!this._defaults) {
27 | const url = browser.runtime.getURL('/default-preferences.json');
28 | const txt = await (await fetch(url)).text();
29 | // VERY basic comment support! Only "//" and only at the start of lines!
30 | let json = txt.replace(/^\s*\/\/.*$/mg, "");
31 | // Allow localized strings
32 | json = json.replace(/__MSG_([A-Za-z0-9_]+?)__/g, (match, msgName) => {
33 | return browser.i18n.getMessage(msgName);
34 | });
35 | const defaults = JSON.parse(json);
36 | await this._apply_managed_defaults(defaults);
37 | this._defaults = defaults;
38 | }
39 |
40 | const prefs = await browser.storage.local.get();
41 | for (let name in this._defaults) {
42 | if (prefs[name] === undefined)
43 | prefs[name] = this._defaults[name];
44 | }
45 | return prefs;
46 | },
47 |
48 | _gettype: function(object) {
49 | return Object.prototype.toString.call(object);
50 | },
51 |
52 | set: function(aObject) {
53 | return browser.storage.local.set(aObject);
54 | },
55 |
56 | remove: function(keys) {
57 | return browser.storage.local.remove(keys);
58 | },
59 |
60 |
61 | // IMPORTANT!!!
62 | // If you found this, then you hopefully know what you are doing!
63 | // Mozilla decided against verification of managed preferences:
64 | // https://bugzil.la/1230802#c30
65 | // The following code does *very basic* verification on *very low* level,
66 | // but you can still create unsupported cases very easily, which could make my
67 | // Add-ons break. I have no regard for managed preferences! The way how I
68 | // handle my preferences could change with any Add-on release, and it is
69 | // *your job* to keep track of this if you decide to use managed preferences!
70 | _apply_managed_defaults: async function(defaults) {
71 | let mgdefaults = {};
72 | // Do not allow storage.managed to make Add-ons unusable.
73 | // Catch all errors that may occur. Then log and ignore them.
74 | try {
75 | mgdefaults = await browser.storage.managed.get();
76 | }
77 | catch(e) {
78 | // HACK: https://bugzil.la/1784446
79 | // Only log message if it's not caused by above bug.
80 | if (e.message != "Managed storage manifest not found")
81 | console.log(e);
82 | return;
83 | }
84 |
85 | // Run over all managed preference values that target an existing default
86 | for (const [name, mgvalue] of Object.entries(mgdefaults)) {
87 | if (!Object.hasOwn(defaults, name))
88 | continue;
89 | const ourvalue = defaults[name];
90 |
91 | // Do not allow managed preferences to change a type of a preference
92 | const mgtype = Object.prototype.toString.call(mgvalue);
93 | const ourtype = Object.prototype.toString.call(ourvalue);
94 | if (mgtype !== ourtype) {
95 | console.log(`Managed default applying failed for "${name}" which is of type ${mgtype} but should be of type ${ourtype}`);
96 | continue;
97 | }
98 |
99 | // Do not allow managed preferences to empty arrays
100 | if (Array.isArray(mgvalue) && mgvalue.length == 0) {
101 | console.log(`Managed default applying failed for "${name}" because managed preferences are not allowed to empty arrays`);
102 | continue;
103 | }
104 |
105 | // Force managed array values to be of same type as our defaults
106 | if (Array.isArray(ourvalue) && ourvalue.length > 0) {
107 | const itemtype = Object.prototype.toString.call(ourvalue[0]);
108 | const mgtypes = mgvalue.map(x => Object.prototype.toString.call(x));
109 | const invalid = mgtypes.filter(x => x !== itemtype);
110 | if (invalid.length) {
111 | console.log(`Managed default applying failed for "${name}" because one of its items is of type ${invalid[0]} but should be of type ${itemtype}`);
112 | continue;
113 | }
114 | }
115 |
116 | // If we reach here, then we apply the managed default value
117 | defaults[name] = mgvalue;
118 | }
119 | }
120 | };
121 |
--------------------------------------------------------------------------------