@vacantthinker/firefox-addon-framework-easy 2026.526.1222 → 2026.526.1620

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,7 +56,7 @@ export function browserRuntimeManifestName() { }
56
56
  ```javascript
57
57
  export function generateHtmlByUserSettings(
58
58
  userSettings,
59
- radioItemClickFn,
59
+ radioItemClickCallback,
60
60
  ) { }
61
61
 
62
62
  ```
@@ -131,6 +131,8 @@ export async function servicePostJson(
131
131
  handleError,
132
132
  ) { }
133
133
 
134
+ export async function serviceSendDataToLocalAria2(message) { }
135
+
134
136
  ```
135
137
 
136
138
  ### 📄 File: `src/serviceGet.js`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vacantthinker/firefox-addon-framework-easy",
3
- "version": "2026.0526.1222",
3
+ "version": "2026.0526.1620",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "publishConfig": {
package/src/generate.js CHANGED
@@ -1,142 +1,128 @@
1
- import {stoOpGet, stoOpSet} from './opStorage.js';
1
+ import { stoOpGet, stoOpSet } from './opStorage.js';
2
2
 
3
3
  /**
4
- * this function can use when you use serviceUserSettings.js
4
+ * Generates HTML elements based on a user settings schema object.
5
5
  *
6
- *
7
- * searchEngine: {
8
- * optionType: 'checkbox',
9
- * options: ['Searcher1', 'Searcher2'],
10
- * selected: ['Searcher1', 'Searcher2'],
11
- * },
12
- * videoQuality: {
13
- * options: ['360', '480', '720', '1080', '1440', '2160'],
14
- * selected: '720',
15
- * },
16
- * @param userSettings{{}}
17
- * @param radioItemClickFn{function}
6
+ * @param {Object} userSettings
7
+ * @param {Function} radioItemClickCallback
18
8
  * @returns {HTMLFieldSetElement[]}
19
9
  */
20
10
  export function generateHtmlByUserSettings(
21
11
  userSettings,
22
- radioItemClickFn,
12
+ radioItemClickCallback,
23
13
  ) {
24
-
25
- // todo generate html by data
26
- return Object.keys(userSettings).map(
27
- /**
28
- *
29
- * @param k{string}
30
- * @returns {HTMLFieldSetElement}
31
- */
32
- (k) => {
33
- /**
34
- * @type{{optionType:'checkbox'|'radio',options:[string], selected: string, }}
35
- */
36
- let v = userSettings[k];
37
-
38
- let optionType = v.optionType;
39
- if (optionType === undefined) {
40
- optionType = 'radio';
14
+ return Object.keys(userSettings).map((storageKey) => {
15
+ const storageValue = userSettings[storageKey];
16
+ const type = storageValue.type || 'text'; // Default to text if type is not specified
17
+
18
+ // Common container wrapper for every configuration item
19
+ const eleWrap = document.createElement('fieldset');
20
+ const eleTitle = document.createElement('legend');
21
+ eleTitle.textContent = storageKey;
22
+ eleWrap.append(eleTitle);
23
+
24
+ // --- CONDITION 1: CHECKBOX & RADIO ---
25
+ if (type === 'checkbox' || type === 'radio') {
26
+ const options = storageValue.options || [];
27
+
28
+ options.map((option) => {
29
+ const eleLabel = document.createElement('label');
30
+ eleLabel.textContent = option;
31
+
32
+ const eleInput = document.createElement('input');
33
+ eleInput.name = storageKey;
34
+ eleInput.type = type;
35
+ eleInput.value = option;
36
+
37
+ if (type === 'checkbox') {
38
+ stoOpGet(storageKey).then((v) => {
39
+ const initialArray = Array.from(v || storageValue.selected || []);
40
+ const set = new Set(initialArray);
41
+ eleInput.checked = set.has(option);
42
+ });
43
+
44
+ eleInput.addEventListener('change', async () => {
45
+ const optionsCurrent = await stoOpGet(storageKey) || storageValue.selected || [];
46
+ const set = new Set(Array.from(optionsCurrent));
47
+
48
+ if (eleInput.checked) {
49
+ set.add(option);
50
+ } else {
51
+ set.delete(option);
52
+ }
53
+
54
+ const valueNew = Array.from(set);
55
+ console.info(`k=${storageKey} option=${option} eleInput.checked=${eleInput.checked} valueNew=${valueNew}`);
56
+ await stoOpSet(storageKey, valueNew);
57
+ });
41
58
  }
42
-
43
- /**
44
- *
45
- * @type {string[]}
46
- */
47
- let options = v.options;
48
- // /**
49
- // *
50
- // * @type {string}
51
- // */
52
- // let selected = v.selected;
53
-
54
- let eleWrap = document.createElement('fieldset');
55
-
56
- let eleTitle = document.createElement('legend');
57
- eleTitle.textContent = k;
58
- eleWrap.append(eleTitle);
59
-
60
- // console.info(`optionType=${optionType} options=${options}`)
61
- options.map(
62
- /**
63
- *
64
- * @param option{string}
65
- */
66
- option => {
67
-
68
- let eleLabel = document.createElement('label');
69
- eleLabel.textContent = option;
70
-
71
- let eleInput = document.createElement('input');
72
- eleInput.name = k;
73
- eleInput.type = optionType;
74
- eleInput.value = option;
75
-
76
- if (optionType === 'checkbox') {
77
- stoOpGet(k).then(
78
- /**
79
- *
80
- * @param v{string}
81
- */
82
- v => {
83
- let strings = Array.from(v);
84
- console.info(`strings=${strings} option=${option}`);
85
- const set = new Set(strings);
86
- eleInput.checked = set.has(option);
87
-
88
- });
89
- }
90
- else if (optionType === 'radio') {
91
- stoOpGet(k).then(
92
- /**
93
- *
94
- * @param v{string}
95
- */
96
- v => {
97
- if (option === v) {
98
- eleInput.checked = true;
99
- }
100
- });
59
+ else if (type === 'radio') {
60
+ stoOpGet(storageKey).then((v) => {
61
+ const currentSelected = (v !== undefined && v !== null) ? v : storageValue.selected;
62
+ if (option === currentSelected) {
63
+ eleInput.checked = true;
64
+ }
65
+ });
66
+
67
+ eleLabel.onclick = function () {
68
+ stoOpSet(storageKey, option).then(() => {
69
+ console.info(`k=${storageKey} option=${option}`);
70
+ if (typeof radioItemClickCallback === 'function') {
71
+ radioItemClickCallback(storageKey, option);
101
72
  }
73
+ });
74
+ };
75
+ }
102
76
 
103
- eleLabel.append(eleInput);
77
+ eleLabel.append(eleInput);
78
+ return eleLabel;
79
+ }).forEach((ele) => eleWrap.append(ele));
80
+ }
81
+
82
+ // --- CONDITION 2: TOGGLE BUTTON ---
83
+ else if (type === 'button') {
84
+ const eleButton = document.createElement('button');
85
+ eleButton.type = 'button'; // Prevent accidental form submissions
86
+
87
+ stoOpGet(storageKey).then((v) => {
88
+ // Fallback to default schema configuration if no value is stored yet
89
+ let currentStatus = (v !== undefined && v !== null) ? (v === true || v === 'true') : storageValue.selected;
90
+ eleButton.textContent = String(currentStatus);
91
+
92
+ eleButton.addEventListener('click', async () => {
93
+ currentStatus = !currentStatus; // Toggle state
94
+ eleButton.textContent = String(currentStatus);
95
+ console.info(`k=${storageKey} toggled to=${currentStatus}`);
96
+ await stoOpSet(storageKey, currentStatus);
97
+ });
98
+ });
104
99
 
105
- if (optionType === 'checkbox') {
106
- eleInput.addEventListener('change', async () => {
107
- let textCurrent = eleLabel.textContent;
100
+ eleWrap.append(eleButton);
101
+ }
108
102
 
109
- let optionsCurrent = await stoOpGet(k);
110
- console.info('optionsCurrent=', optionsCurrent);
103
+ // --- CONDITION 3: NUMBER & TEXT INPUTS ---
104
+ else if (type === 'number' || type === 'text') {
105
+ const eleInput = document.createElement('input');
106
+ eleInput.type = type;
107
+ eleInput.name = storageKey;
111
108
 
112
- let optionsArr = Array.from(optionsCurrent);
113
- let set = new Set(optionsArr);
114
- if (eleInput.checked) {
115
- set.add(textCurrent);
116
- }
117
- else {
118
- set.delete(textCurrent);
119
- }
109
+ stoOpGet(storageKey).then((v) => {
110
+ const currentVal = (v !== undefined && v !== null) ? v : storageValue.selected;
111
+ eleInput.value = currentVal;
112
+ });
120
113
 
121
- let valueNew = Array.from(set);
122
- console.info(
123
- `k=${k} text=${textCurrent} eleInput.checked=${eleInput.checked} valueNew=${valueNew}`);
124
- await stoOpSet(k, valueNew);
114
+ // Updates storage on every keystroke/change execution
115
+ eleInput.addEventListener('input', async () => {
116
+ const rawValue = eleInput.value;
117
+ const finalizedValue = type === 'number' ? Number(rawValue) : rawValue;
125
118
 
126
- });
127
- }
128
- else if (optionType === 'radio') {
129
- eleLabel.onclick = function() {
130
- stoOpSet(k, option).then(() => {
131
- console.info(`k=${k} option=${option}`);
132
- radioItemClickFn(k, option);
133
- });
134
- };
135
- }
136
- return eleLabel;
119
+ console.info(`k=${storageKey} value changed to=${finalizedValue}`);
120
+ await stoOpSet(storageKey, finalizedValue);
121
+ });
137
122
 
138
- }).forEach(ele => eleWrap.append(ele));
123
+ eleWrap.append(eleInput);
124
+ }
139
125
 
140
- return eleWrap;
141
- });
142
- }
126
+ return eleWrap;
127
+ });
128
+ }
@@ -40,7 +40,7 @@ export async function servicePostJson(
40
40
  * }}
41
41
  * @returns {Promise<Response>}
42
42
  */
43
- async function serviceSendDataToLocalAria2(message) {
43
+ export async function serviceSendDataToLocalAria2(message) {
44
44
  let {downlink, filename, rpcsecret, rpcport} = message;
45
45
 
46
46
  const secret = rpcsecret;
@@ -2,18 +2,6 @@ import {stoOpGet, stoOpSet} from './opStorage.js';
2
2
 
3
3
  /**
4
4
  * this function connect with generateHtmlByUserSettings()
5
- * example
6
- * searchEngine: {
7
- * optionType: 'checkbox',
8
- * options: ['Searcher1', 'Searcher2'],
9
- * selected: ['Searcher1', 'Searcher2'],
10
- * },
11
- * videoQuality: {
12
- * optionType: 'radio',
13
- * options: ['360', '480', '720', '1080', '1440', '2160'],
14
- * selected: '720',
15
- * },
16
- *
17
5
  *
18
6
  * @param userSettings{{}}
19
7
  * @returns {Promise<void>}
@@ -38,7 +26,7 @@ export async function serviceInitUserSettings(userSettings) {
38
26
  /**
39
27
  * // todo
40
28
  * @param userSettings{{}}
41
- * @returns {Promise<{}>}
29
+ * @returns {Promise<{Object}>}
42
30
  */
43
31
  export async function serviceGetUserSettings(userSettings) {
44
32
  const red = {};