@vacantthinker/firefox-addon-framework-easy 2026.605.843 → 2026.605.1024
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 +12 -16
- package/package.json +22 -2
- package/src/BaseORM.js +1 -1
- package/src/browserDownload.js +4 -4
- package/src/browserNotification.js +2 -2
- package/src/browserRuntime.js +1 -1
- package/src/browserRuntimeOnMessageCommon.js +4 -29
- package/src/browserTab.js +28 -28
- package/src/generate.js +13 -13
- package/src/opTab.js +1 -1
- package/src/serviceFetch.js +2 -2
- package/src/serviceOpContent.js +18 -33
- package/src/serviceOpJavascript.js +27 -27
- package/src/serviceUpdateTabStyle.js +6 -6
- package/src/serviceUserSettings.js +9 -9
package/README.md
CHANGED
|
@@ -26,15 +26,15 @@ export class BaseORM { }
|
|
|
26
26
|
### 📄 File: `src/browserDownload.js`
|
|
27
27
|
```javascript
|
|
28
28
|
export async function browserDownloadByDownlink(
|
|
29
|
-
|
|
29
|
+
{ }
|
|
30
30
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
### 📄 File: `src/browserNotification.js`
|
|
34
34
|
```javascript
|
|
35
35
|
export async function browserNotificationCreate(
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
content,
|
|
37
|
+
title = browserRuntimeManifestName(),
|
|
38
38
|
) { }
|
|
39
39
|
|
|
40
40
|
```
|
|
@@ -44,7 +44,7 @@ export async function browserNotificationCreate(
|
|
|
44
44
|
export function browserRuntimeReload() { }
|
|
45
45
|
|
|
46
46
|
export async function browserRuntimeSetUninstallURL(
|
|
47
|
-
|
|
47
|
+
url = '',
|
|
48
48
|
) { }
|
|
49
49
|
|
|
50
50
|
export function browserRuntimeOnUpdateAvailable(doWhat = null) { }
|
|
@@ -62,13 +62,9 @@ export function browserRuntimeManifestName() { }
|
|
|
62
62
|
### 📄 File: `src/browserRuntimeOnMessageCommon.js`
|
|
63
63
|
```javascript
|
|
64
64
|
export function browserRuntimeOnMessageCommon(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
) { }
|
|
69
|
-
|
|
70
|
-
export function browserRuntimeOnMessageMerge(
|
|
71
|
-
message, sender
|
|
65
|
+
act,
|
|
66
|
+
message,
|
|
67
|
+
sendResponse
|
|
72
68
|
) { }
|
|
73
69
|
|
|
74
70
|
```
|
|
@@ -96,8 +92,8 @@ export class DomainORM extends BaseORM { }
|
|
|
96
92
|
### 📄 File: `src/generate.js`
|
|
97
93
|
```javascript
|
|
98
94
|
export function generateHtmlByUserSettings(
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
userSettings,
|
|
96
|
+
radioItemClickCallback,
|
|
101
97
|
) { }
|
|
102
98
|
|
|
103
99
|
export function generateMkvScriptForSystemWindows({ }
|
|
@@ -171,8 +167,8 @@ export async function serviceDownloadByDownlink(message) { }
|
|
|
171
167
|
### 📄 File: `src/serviceFetch.js`
|
|
172
168
|
```javascript
|
|
173
169
|
export async function servicePostJson(
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
serverUrl,
|
|
171
|
+
message,
|
|
176
172
|
) { }
|
|
177
173
|
|
|
178
174
|
export async function serviceSendDataToLocalAria2(message) { }
|
|
@@ -202,7 +198,7 @@ export function serviceRemoveIllegalWord(value) { }
|
|
|
202
198
|
### 📄 File: `src/serviceOpJavascript.js`
|
|
203
199
|
```javascript
|
|
204
200
|
export async function serviceTakeScreenshot(
|
|
205
|
-
|
|
201
|
+
{ }
|
|
206
202
|
|
|
207
203
|
export async function serviceElementPicker(message) { }
|
|
208
204
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vacantthinker/firefox-addon-framework-easy",
|
|
3
|
-
"version": "2026.0605.
|
|
3
|
+
"version": "2026.0605.1024",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public",
|
|
8
8
|
"provenance": true
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
10
|
+
"scripts": {
|
|
11
|
+
"install_package": "npm install"
|
|
12
|
+
},
|
|
11
13
|
"author": "VacantThinker",
|
|
12
14
|
"license": "AGPL-3.0-only",
|
|
13
15
|
"repository": {
|
|
@@ -20,5 +22,23 @@
|
|
|
20
22
|
},
|
|
21
23
|
"dependencies": {
|
|
22
24
|
"@types/firefox-webext-browser": "^143.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"prettier": "3.8.3",
|
|
28
|
+
"prettier-plugin-jsdoc": "1.8.1"
|
|
29
|
+
},
|
|
30
|
+
"prettier": {
|
|
31
|
+
"semi": true,
|
|
32
|
+
"singleQuote": true,
|
|
33
|
+
"tabWidth": 2,
|
|
34
|
+
"useTabs": false,
|
|
35
|
+
"printWidth": 80,
|
|
36
|
+
"plugins": [
|
|
37
|
+
"prettier-plugin-jsdoc"
|
|
38
|
+
],
|
|
39
|
+
"jsdocVerticalizeParams": true,
|
|
40
|
+
"jsdocLineWrappingStyle": "balance",
|
|
41
|
+
"jsdocPreferToKeepShortOnOneLine": false,
|
|
42
|
+
"jsdocKeepUnpublished": false
|
|
23
43
|
}
|
|
24
44
|
}
|
package/src/BaseORM.js
CHANGED
|
@@ -19,7 +19,7 @@ export class BaseORM {
|
|
|
19
19
|
constructor(prefix, id, defaultValue = {}) {
|
|
20
20
|
if (new.target === BaseORM) {
|
|
21
21
|
throw new TypeError(
|
|
22
|
-
|
|
22
|
+
'Cannot construct BaseORM instances directly (Abstract Class).');
|
|
23
23
|
}
|
|
24
24
|
if (!prefix || !id) {
|
|
25
25
|
throw new Error('Both prefix and id must be specified.');
|
package/src/browserDownload.js
CHANGED
|
@@ -7,8 +7,8 @@ import {browserRuntimeManifestName} from './browserRuntime.js';
|
|
|
7
7
|
* @returns {Promise<string>}
|
|
8
8
|
*/
|
|
9
9
|
export async function browserNotificationCreate(
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
content,
|
|
11
|
+
title = browserRuntimeManifestName(),
|
|
12
12
|
) {
|
|
13
13
|
|
|
14
14
|
const tag = 'browserNotificationCreate';
|
package/src/browserRuntime.js
CHANGED
|
@@ -7,7 +7,7 @@ import {browserNotificationCreate} from './browserNotification.js';
|
|
|
7
7
|
* offer common act <=> function, eg: actRemoveTab, actLog
|
|
8
8
|
*
|
|
9
9
|
* @param act{
|
|
10
|
-
* 'actLog'
|
|
10
|
+
* |'actLog'
|
|
11
11
|
* |'actRequestTabIdTabUrl'
|
|
12
12
|
* |'actNotification'
|
|
13
13
|
* |'actRemoveTab'
|
|
@@ -18,9 +18,9 @@ import {browserNotificationCreate} from './browserNotification.js';
|
|
|
18
18
|
* @param sendResponse
|
|
19
19
|
*/
|
|
20
20
|
export function browserRuntimeOnMessageCommon(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
act,
|
|
22
|
+
message,
|
|
23
|
+
sendResponse
|
|
24
24
|
) {
|
|
25
25
|
switch (act) {
|
|
26
26
|
case 'actLog':
|
|
@@ -44,28 +44,3 @@ export function browserRuntimeOnMessageCommon(
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
* @param message
|
|
51
|
-
* @param sender
|
|
52
|
-
* @returns {
|
|
53
|
-
* 'actLog'
|
|
54
|
-
* |'actRequestTabIdTabUrl'
|
|
55
|
-
* |'actNotification'
|
|
56
|
-
* |'actRemoveTab'
|
|
57
|
-
* |'actDownloadFile'
|
|
58
|
-
* |'actSendMessageToTab'
|
|
59
|
-
* }
|
|
60
|
-
*/
|
|
61
|
-
export function browserRuntimeOnMessageMerge(
|
|
62
|
-
message, sender
|
|
63
|
-
) {
|
|
64
|
-
let keyAct = 'act';
|
|
65
|
-
let act = message[keyAct];
|
|
66
|
-
delete message[keyAct];
|
|
67
|
-
message['tabId'] = sender.tab?.id;
|
|
68
|
-
message['tabUrl'] = sender.tab?.url;
|
|
69
|
-
|
|
70
|
-
return act;
|
|
71
|
-
}
|
package/src/browserTab.js
CHANGED
|
@@ -10,13 +10,13 @@ export async function browserTabSendMessage(tabId, message) {
|
|
|
10
10
|
export function browserTabWaitReloadThenSendMessageToContentJs(message) {
|
|
11
11
|
let tabId = message.tabId;
|
|
12
12
|
browser.tabs.onUpdated.addListener(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
13
|
+
async function lis(tabId, changeInfo) {
|
|
14
|
+
if (changeInfo.status === 'complete') {
|
|
15
|
+
browser.tabs.onUpdated.removeListener(lis);
|
|
16
|
+
await browserTabSendMessage(tabId, message);
|
|
18
17
|
}
|
|
19
|
-
|
|
18
|
+
}
|
|
19
|
+
, {tabId, properties: ['status']});
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -41,14 +41,14 @@ export async function browserTabCreateToDownload(message) {
|
|
|
41
41
|
|
|
42
42
|
let {tabId} = await tabOpCreateNear(properties);
|
|
43
43
|
browser.tabs.onUpdated.addListener(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
44
|
+
async function lis(tabId, changeInfo) {
|
|
45
|
+
if (changeInfo.status === 'complete') {
|
|
46
|
+
browser.tabs.onUpdated.removeListener(lis);
|
|
47
|
+
// todo code here
|
|
48
|
+
await tabOpRemove(tabId);
|
|
50
49
|
}
|
|
51
|
-
|
|
50
|
+
}
|
|
51
|
+
, {tabId, properties: ['status']});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -73,15 +73,15 @@ export async function browserTabCreateNearSendMessageToContentJs(message) {
|
|
|
73
73
|
|
|
74
74
|
let {tabId} = await tabOpCreateNear(properties);
|
|
75
75
|
browser.tabs.onUpdated.addListener(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
76
|
+
async function lis(tabId, changeInfo) {
|
|
77
|
+
if (changeInfo.status === 'complete') {
|
|
78
|
+
browser.tabs.onUpdated.removeListener(lis);
|
|
79
|
+
// todo code here
|
|
80
|
+
await browserTabSendMessage(
|
|
81
|
+
tabId, Object.assign({}, message, {tabId}));
|
|
83
82
|
}
|
|
84
|
-
|
|
83
|
+
}
|
|
84
|
+
, {tabId, properties: ['status']});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
@@ -91,13 +91,13 @@ export async function browserTabCreateNearSendMessageToContentJs(message) {
|
|
|
91
91
|
*/
|
|
92
92
|
export function browserTabWaitReloadThenRemoveIt({tabId}) {
|
|
93
93
|
browser.tabs.onUpdated.addListener(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
94
|
+
async function lis(tabId, changeInfo) {
|
|
95
|
+
if (changeInfo.status === 'complete') {
|
|
96
|
+
browser.tabs.onUpdated.removeListener(lis);
|
|
97
|
+
// todo code here
|
|
98
|
+
await tabOpRemove(tabId);
|
|
100
99
|
}
|
|
101
|
-
|
|
100
|
+
}
|
|
101
|
+
, {tabId, properties: ['status']});
|
|
102
102
|
|
|
103
103
|
}
|
package/src/generate.js
CHANGED
|
@@ -8,8 +8,8 @@ import {stoOpGet, stoOpSet} from './opStorage.js';
|
|
|
8
8
|
* @returns {HTMLFieldSetElement[]}
|
|
9
9
|
*/
|
|
10
10
|
export function generateHtmlByUserSettings(
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
userSettings,
|
|
12
|
+
radioItemClickCallback,
|
|
13
13
|
) {
|
|
14
14
|
// Keeps track of all generated fieldsets by their storageKey
|
|
15
15
|
const elementsMap = {};
|
|
@@ -56,7 +56,7 @@ export function generateHtmlByUserSettings(
|
|
|
56
56
|
|
|
57
57
|
eleInput.addEventListener('change', async () => {
|
|
58
58
|
const optionsCurrent = await stoOpGet(storageKey) ||
|
|
59
|
-
|
|
59
|
+
storageValue.selected || [];
|
|
60
60
|
const set = new Set(Array.from(optionsCurrent));
|
|
61
61
|
|
|
62
62
|
if (eleInput.checked) {
|
|
@@ -76,8 +76,8 @@ export function generateHtmlByUserSettings(
|
|
|
76
76
|
else if (type === 'radio') {
|
|
77
77
|
stoOpGet(storageKey).then((v) => {
|
|
78
78
|
const currentSelected = (v !== undefined && v !== null) ?
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
v :
|
|
80
|
+
storageValue.selected;
|
|
81
81
|
if (option === currentSelected) {
|
|
82
82
|
eleInput.checked = true;
|
|
83
83
|
}
|
|
@@ -86,7 +86,7 @@ export function generateHtmlByUserSettings(
|
|
|
86
86
|
triggerVisibility(storageKey, currentSelected);
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
eleLabel.onclick = function() {
|
|
89
|
+
eleLabel.onclick = function () {
|
|
90
90
|
stoOpSet(storageKey, option).then(() => {
|
|
91
91
|
if (typeof radioItemClickCallback === 'function') {
|
|
92
92
|
radioItemClickCallback(storageKey, option);
|
|
@@ -111,8 +111,8 @@ export function generateHtmlByUserSettings(
|
|
|
111
111
|
stoOpGet(storageKey).then((v) => {
|
|
112
112
|
// Fallback to default schema configuration if no value is stored yet
|
|
113
113
|
let currentStatus = (v !== undefined && v !== null) ?
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
(v === true || v === 'true') :
|
|
115
|
+
storageValue.selected;
|
|
116
116
|
eleButton.textContent = String(currentStatus);
|
|
117
117
|
|
|
118
118
|
// Initial visibility evaluation
|
|
@@ -139,8 +139,8 @@ export function generateHtmlByUserSettings(
|
|
|
139
139
|
|
|
140
140
|
stoOpGet(storageKey).then((v) => {
|
|
141
141
|
const currentVal = (v !== undefined && v !== null) ?
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
v :
|
|
143
|
+
storageValue.selected;
|
|
144
144
|
eleInput.value = currentVal;
|
|
145
145
|
|
|
146
146
|
// Initial visibility evaluation
|
|
@@ -162,7 +162,7 @@ export function generateHtmlByUserSettings(
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// --- CONDITION 4: SPAN / READ-ONLY TEXT ---
|
|
165
|
-
else if (type === 'span'
|
|
165
|
+
else if (type === 'span') {
|
|
166
166
|
const eleSpan = document.createElement('span');
|
|
167
167
|
// Optional: Add a class for styling read-only text differently
|
|
168
168
|
// eleSpan.className = 'read-only-text';
|
|
@@ -170,8 +170,8 @@ export function generateHtmlByUserSettings(
|
|
|
170
170
|
stoOpGet(storageKey).then((v) => {
|
|
171
171
|
// Fallback to default schema configuration if no value is stored yet
|
|
172
172
|
const currentVal = (v !== undefined && v !== null) ?
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
v :
|
|
174
|
+
storageValue.selected;
|
|
175
175
|
|
|
176
176
|
// Render as plain text
|
|
177
177
|
eleSpan.textContent = String(currentVal);
|
package/src/opTab.js
CHANGED
package/src/serviceFetch.js
CHANGED
package/src/serviceOpContent.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import {browserRuntimePlatformInfo} from './browserRuntime.js';
|
|
2
|
-
import {
|
|
3
|
-
generateMkvScriptForSystemFedora,
|
|
4
|
-
generateMkvScriptForSystemWindows,
|
|
5
|
-
} from './generate.js';
|
|
2
|
+
import {generateMkvScriptForSystemFedora, generateMkvScriptForSystemWindows,} from './generate.js';
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
5
|
*
|
|
@@ -22,23 +19,23 @@ export async function serviceCopyContentToClipboard(data) {
|
|
|
22
19
|
export function serviceSaveContentToLocal(content, filename, ext = 'txt') {
|
|
23
20
|
const eleBtn = document.createElement('button');
|
|
24
21
|
eleBtn.addEventListener(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
'click',
|
|
23
|
+
function () {
|
|
24
|
+
const eleA = document.createElement('a');
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
const extObj = {
|
|
27
|
+
txt: 'text/plain',
|
|
28
|
+
json: 'application/json',
|
|
29
|
+
};
|
|
30
|
+
const type = extObj[ext];
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
const file = new Blob([content], {type});
|
|
33
|
+
eleA.href = URL.createObjectURL(file);
|
|
34
|
+
eleA.download = [filename, ext].join('.');
|
|
35
|
+
eleA.click();
|
|
36
|
+
URL.revokeObjectURL(eleA.href);
|
|
37
|
+
},
|
|
38
|
+
false,
|
|
42
39
|
);
|
|
43
40
|
eleBtn.click();
|
|
44
41
|
// eleBtn.previousElementSibling
|
|
@@ -65,31 +62,19 @@ export async function serviceGenerateMkvToolNixScript({vid, title}) {
|
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param {string} value - 原始视频标题
|
|
71
|
-
* @returns {string} - 干净、安全的纯文本/字母数字文件名
|
|
65
|
+
* @param {string} value -
|
|
66
|
+
* @returns {string} -
|
|
72
67
|
*/
|
|
73
68
|
export function serviceRemoveIllegalWord(value) {
|
|
74
69
|
if (!value) return '';
|
|
75
70
|
|
|
76
|
-
// 1. 获取第一行并去除两端空格
|
|
77
71
|
let name = value.trim().split(/\r?\n/).shift();
|
|
78
72
|
|
|
79
|
-
// 2. 使用 Unicode 属性移除所有危险字符:
|
|
80
|
-
// \p{P} = 所有标点符号
|
|
81
|
-
// \p{S} = 所有符号(Emoji、数学符号、货币符号)
|
|
82
|
-
// \p{C} = 所有控制/格式化/代理字符(完美修复不可见的 U+202A/U+202C 导致崩溃的 Bug!)
|
|
83
73
|
name = name.replace(/[\p{P}\p{S}\p{C}]/gu, ' ');
|
|
84
74
|
|
|
85
|
-
// 3. Firefox WebExtension 严格拦截的特殊字符。
|
|
86
|
-
// (大部分已经被 \p{P} 和 \p{S} 处理,但显式移除可以确保彻底杜绝边缘报错)
|
|
87
75
|
name = name.replace(/[~"#%&*:<>?/\\{|}]/g, ' ');
|
|
88
76
|
|
|
89
|
-
// 4. 将连续的空格(包括全角/Unicode空格)合并为一个标准空格
|
|
90
77
|
name = name.replace(/[\s\u3000]+/g, ' ').trim();
|
|
91
78
|
|
|
92
|
-
// 5. Firefox 下载 API 会因为文件名以点(.)或连字符(-)开头/结尾而报错
|
|
93
|
-
// 再次修剪以确保绝对安全
|
|
94
79
|
return name.replace(/^[-.]+|[-.]+$/g, '');
|
|
95
80
|
}
|
|
@@ -20,24 +20,24 @@ import {browserNotificationCreate} from './browserNotification.js';
|
|
|
20
20
|
* @returns {Promise<void>}
|
|
21
21
|
*/
|
|
22
22
|
export async function serviceTakeScreenshot(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
{
|
|
24
|
+
tabId,
|
|
25
|
+
filename,
|
|
26
|
+
rect,
|
|
27
|
+
}) {
|
|
28
28
|
|
|
29
29
|
const tag = 'actTakeScreenshot()';
|
|
30
30
|
let dataURI = await browser.tabs.captureTab(tabId, {
|
|
31
31
|
rect: rect,
|
|
32
32
|
});
|
|
33
33
|
let assign = Object.assign(
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
{},
|
|
35
|
+
{dataURI, filename},
|
|
36
36
|
);
|
|
37
37
|
await browser.scripting.executeScript({
|
|
38
38
|
target: {tabId},
|
|
39
39
|
args: [assign],
|
|
40
|
-
func: function(message) {
|
|
40
|
+
func: function (message) {
|
|
41
41
|
if (message) {
|
|
42
42
|
let {dataURI, filename} = message;
|
|
43
43
|
|
|
@@ -70,7 +70,7 @@ export async function serviceElementPicker(message) {
|
|
|
70
70
|
await browser.scripting.executeScript({
|
|
71
71
|
target: {tabId},
|
|
72
72
|
args: [message],
|
|
73
|
-
func: async function(message) {
|
|
73
|
+
func: async function (message) {
|
|
74
74
|
if (!message) return;
|
|
75
75
|
console.log('picker.js initialized', message);
|
|
76
76
|
|
|
@@ -137,9 +137,9 @@ export async function serviceElementPicker(message) {
|
|
|
137
137
|
overlay.style.setProperty('top', `${clientRect.top}px`, 'important');
|
|
138
138
|
overlay.style.setProperty('left', `${clientRect.left}px`, 'important');
|
|
139
139
|
overlay.style.setProperty('width', `${clientRect.width}px`,
|
|
140
|
-
|
|
140
|
+
'important');
|
|
141
141
|
overlay.style.setProperty('height', `${clientRect.height}px`,
|
|
142
|
-
|
|
142
|
+
'important');
|
|
143
143
|
|
|
144
144
|
// Change mouse cursor to indicate picking mode
|
|
145
145
|
document.body.style.setProperty('cursor', 'crosshair', 'important');
|
|
@@ -165,13 +165,13 @@ export async function serviceElementPicker(message) {
|
|
|
165
165
|
|
|
166
166
|
// Assuming 'target' is your clicked element (e.g., from e.target)
|
|
167
167
|
let messageTakeScreenshot = Object.assign(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
{}, // Start with a fresh, empty object
|
|
169
|
+
message, // Put the original message first so it doesn't overwrite your new data
|
|
170
|
+
{rect},
|
|
171
|
+
{
|
|
172
|
+
// The guaranteed unique CSS path (e.g., "div#wrap > ul > li:nth-of-type(2)")
|
|
173
|
+
uniqueSelector: getUniqueSelector(target),
|
|
174
|
+
},
|
|
175
175
|
);
|
|
176
176
|
|
|
177
177
|
await browser.runtime.sendMessage(messageTakeScreenshot);
|
|
@@ -225,9 +225,9 @@ export async function serviceGetFullPageRectData(message) {
|
|
|
225
225
|
x, y, width, height,
|
|
226
226
|
};
|
|
227
227
|
browser.runtime.sendMessage(Object.assign(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
{},
|
|
229
|
+
message,
|
|
230
|
+
{rect},
|
|
231
231
|
));
|
|
232
232
|
// todo end if (message)
|
|
233
233
|
},
|
|
@@ -275,7 +275,7 @@ export async function serviceFindAllMagnetLink(message) {
|
|
|
275
275
|
// --- Type 2: Find inside raw text (for <div>, <span>, <td>, etc.) ---
|
|
276
276
|
// We target elements that don't have children to avoid grabbing huge parent container blocks
|
|
277
277
|
const allElements = document.querySelectorAll(
|
|
278
|
-
|
|
278
|
+
'div, span, td, p, a, button');
|
|
279
279
|
allElements.forEach(el => {
|
|
280
280
|
if (el.children.length === 0) { // Deepest element
|
|
281
281
|
const text = el.textContent.trim();
|
|
@@ -293,11 +293,11 @@ export async function serviceFindAllMagnetLink(message) {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
await browser.runtime.sendMessage(Object.assign(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
296
|
+
{},
|
|
297
|
+
message,
|
|
298
|
+
{
|
|
299
|
+
data: findAllMagnetLinks(),
|
|
300
|
+
},
|
|
301
301
|
));
|
|
302
302
|
|
|
303
303
|
// todo end if(message)
|
|
@@ -31,9 +31,9 @@ export async function serviceUpdataALLTextNodeColor(message) {
|
|
|
31
31
|
*/
|
|
32
32
|
function nativeTreeWalkerFindALLElementHasNodeText() {
|
|
33
33
|
const walker = document.createTreeWalker(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
document.body,
|
|
35
|
+
NodeFilter.SHOW_TEXT,
|
|
36
|
+
null,
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
let node;
|
|
@@ -96,9 +96,9 @@ export async function serviceUpdataALLNodeBackgroundColor(message) {
|
|
|
96
96
|
*/
|
|
97
97
|
function nativeTreeWalker() {
|
|
98
98
|
const walker = document.createTreeWalker(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
document.body,
|
|
100
|
+
NodeFilter.SHOW_ELEMENT,
|
|
101
|
+
null,
|
|
102
102
|
);
|
|
103
103
|
|
|
104
104
|
let node;
|
|
@@ -7,15 +7,15 @@ import {stoOpGet, stoOpSet} from './opStorage.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export async function serviceInitUserSettings(userSettings) {
|
|
9
9
|
const initPromises = Object.entries(userSettings)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
.map(async ([key, setting]) => {
|
|
11
|
+
const oldValue = await stoOpGet(key);
|
|
12
|
+
|
|
13
|
+
// FIX: Check strictly for null or undefined.
|
|
14
|
+
// This allows `false` and `0` to be recognized as valid saved values.
|
|
15
|
+
if (oldValue === null || oldValue === undefined) {
|
|
16
|
+
await stoOpSet(key, setting.selected);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
19
|
|
|
20
20
|
await Promise.all(initPromises);
|
|
21
21
|
}
|