@gxp-dev/tools 2.0.6 โ 2.0.8
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/bin/lib/commands/build.js +18 -12
- package/browser-extensions/README.md +1 -0
- package/browser-extensions/chrome/background.js +857 -0
- package/browser-extensions/chrome/content.js +51 -0
- package/browser-extensions/chrome/devtools.html +9 -0
- package/browser-extensions/chrome/devtools.js +23 -0
- package/browser-extensions/chrome/icons/gx_off_128.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_16.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_32.png +0 -0
- package/browser-extensions/chrome/icons/gx_off_64.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_128.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_16.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_32.png +0 -0
- package/browser-extensions/chrome/icons/gx_on_64.png +0 -0
- package/browser-extensions/chrome/inspector.js +1087 -0
- package/browser-extensions/chrome/manifest.json +70 -0
- package/browser-extensions/chrome/panel.html +638 -0
- package/browser-extensions/chrome/panel.js +862 -0
- package/browser-extensions/chrome/popup.html +399 -0
- package/browser-extensions/chrome/popup.js +515 -0
- package/browser-extensions/chrome/rules.json +1 -0
- package/browser-extensions/chrome/test-chrome.html +145 -0
- package/browser-extensions/chrome/test-mixed-content.html +190 -0
- package/browser-extensions/chrome/test-uri-pattern.html +199 -0
- package/browser-extensions/firefox/README.md +134 -0
- package/browser-extensions/firefox/background.js +804 -0
- package/browser-extensions/firefox/content.js +120 -0
- package/browser-extensions/firefox/debug-errors.html +229 -0
- package/browser-extensions/firefox/debug-https.html +113 -0
- package/browser-extensions/firefox/devtools.html +9 -0
- package/browser-extensions/firefox/devtools.js +24 -0
- package/browser-extensions/firefox/icons/gx_off_128.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_16.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_32.png +0 -0
- package/browser-extensions/firefox/icons/gx_off_64.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_128.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_16.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_32.png +0 -0
- package/browser-extensions/firefox/icons/gx_on_64.png +0 -0
- package/browser-extensions/firefox/inspector.js +1087 -0
- package/browser-extensions/firefox/manifest.json +67 -0
- package/browser-extensions/firefox/panel.html +638 -0
- package/browser-extensions/firefox/panel.js +862 -0
- package/browser-extensions/firefox/popup.html +525 -0
- package/browser-extensions/firefox/popup.js +536 -0
- package/browser-extensions/firefox/test-gramercy.html +126 -0
- package/browser-extensions/firefox/test-imports.html +58 -0
- package/browser-extensions/firefox/test-masking.html +147 -0
- package/browser-extensions/firefox/test-uri-pattern.html +199 -0
- package/package.json +7 -2
- package/runtime/PortalContainer.vue +326 -0
- package/runtime/dev-tools/DevToolsModal.vue +217 -0
- package/runtime/dev-tools/LayoutSwitcher.vue +221 -0
- package/runtime/dev-tools/MockDataEditor.vue +621 -0
- package/runtime/dev-tools/SocketSimulator.vue +562 -0
- package/runtime/dev-tools/StoreInspector.vue +644 -0
- package/runtime/dev-tools/index.js +6 -0
- package/runtime/gxpStringsPlugin.js +428 -0
- package/runtime/index.html +22 -0
- package/runtime/main.js +32 -0
- package/runtime/mock-api/auth-middleware.js +97 -0
- package/runtime/mock-api/image-generator.js +221 -0
- package/runtime/mock-api/index.js +197 -0
- package/runtime/mock-api/response-generator.js +394 -0
- package/runtime/mock-api/route-generator.js +323 -0
- package/runtime/mock-api/socket-triggers.js +371 -0
- package/runtime/mock-api/spec-loader.js +300 -0
- package/runtime/server.js +180 -0
- package/runtime/stores/gxpPortalConfigStore.js +554 -0
- package/runtime/stores/index.js +6 -0
- package/runtime/vite-inspector-plugin.js +749 -0
- package/runtime/vite-source-tracker-plugin.js +232 -0
- package/runtime/vite.config.js +402 -0
- package/scripts/launch-chrome.js +90 -0
- package/scripts/pack-chrome.js +91 -0
- package/socket-events/AiSessionMessageCreated.json +18 -0
- package/socket-events/SocialStreamPostCreated.json +24 -0
- package/socket-events/SocialStreamPostVariantCompleted.json +23 -0
- package/template/README.md +332 -0
- package/template/app-manifest.json +32 -0
- package/template/dev-assets/images/avatar-placeholder.png +0 -0
- package/template/dev-assets/images/background-placeholder.jpg +0 -0
- package/template/dev-assets/images/banner-placeholder.jpg +0 -0
- package/template/dev-assets/images/icon-placeholder.png +0 -0
- package/template/dev-assets/images/logo-placeholder.png +0 -0
- package/template/dev-assets/images/product-placeholder.jpg +0 -0
- package/template/dev-assets/images/thumbnail-placeholder.jpg +0 -0
- package/template/env.example +51 -0
- package/template/gitignore +53 -0
- package/template/index.html +22 -0
- package/template/main.js +28 -0
- package/template/src/DemoPage.vue +459 -0
- package/template/src/Plugin.vue +38 -0
- package/template/src/stores/index.js +9 -0
- package/template/src/stores/test-data.json +173 -0
- package/template/theme-layouts/AdditionalStyling.css +0 -0
- package/template/theme-layouts/PrivateLayout.vue +39 -0
- package/template/theme-layouts/PublicLayout.vue +39 -0
- package/template/theme-layouts/SystemLayout.vue +39 -0
- package/template/vite.config.js +333 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
document.addEventListener("DOMContentLoaded", async function () {
|
|
2
|
+
// Get all DOM elements
|
|
3
|
+
const toggleButton = document.getElementById("toggleButton");
|
|
4
|
+
const toggleText = document.getElementById("toggleText");
|
|
5
|
+
const saveButton = document.getElementById("saveButton");
|
|
6
|
+
const statusDiv = document.getElementById("status");
|
|
7
|
+
const maskingModeCheckbox = document.getElementById("maskingMode");
|
|
8
|
+
const clearCacheOnEnableCheckbox =
|
|
9
|
+
document.getElementById("clearCacheOnEnable");
|
|
10
|
+
const disableCacheForRedirectsCheckbox = document.getElementById(
|
|
11
|
+
"disableCacheForRedirects"
|
|
12
|
+
);
|
|
13
|
+
const clearCacheButton = document.getElementById("clearCacheButton");
|
|
14
|
+
|
|
15
|
+
// Inspector elements
|
|
16
|
+
const inspectorToggle = document.getElementById("inspectorToggle");
|
|
17
|
+
const inspectorText = document.getElementById("inspectorText");
|
|
18
|
+
|
|
19
|
+
// Inspector state
|
|
20
|
+
let inspectorEnabled = false;
|
|
21
|
+
|
|
22
|
+
// JS Rule elements
|
|
23
|
+
const jsRuleEnabled = document.getElementById("jsRuleEnabled");
|
|
24
|
+
const jsRuleContent = document.getElementById("jsRuleContent");
|
|
25
|
+
const jsRedirectUrl = document.getElementById("jsRedirectUrl");
|
|
26
|
+
const jsCustomPattern = document.getElementById("jsCustomPattern");
|
|
27
|
+
const jsPatternDisplay = document.getElementById("jsPatternDisplay");
|
|
28
|
+
const jsCustomPatternInput = document.getElementById("jsCustomPatternInput");
|
|
29
|
+
|
|
30
|
+
// CSS Rule elements
|
|
31
|
+
const cssRuleEnabled = document.getElementById("cssRuleEnabled");
|
|
32
|
+
const cssRuleContent = document.getElementById("cssRuleContent");
|
|
33
|
+
const cssRedirectUrl = document.getElementById("cssRedirectUrl");
|
|
34
|
+
const cssReturnBlank = document.getElementById("cssReturnBlank");
|
|
35
|
+
const cssRedirectSection = document.getElementById("cssRedirectSection");
|
|
36
|
+
const cssCustomPattern = document.getElementById("cssCustomPattern");
|
|
37
|
+
const cssPatternDisplay = document.getElementById("cssPatternDisplay");
|
|
38
|
+
const cssCustomPatternInput = document.getElementById(
|
|
39
|
+
"cssCustomPatternInput"
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Default configuration
|
|
43
|
+
const defaultConfig = {
|
|
44
|
+
enabled: false,
|
|
45
|
+
// Legacy fields for backward compatibility
|
|
46
|
+
redirectUrl: "https://localhost:3060/src/Plugin.vue",
|
|
47
|
+
urlPattern: "uploads\\/plugin-version\\/\\d+\\/file_name\\/.*\\.js(\\?.*)?",
|
|
48
|
+
useCustomPattern: false,
|
|
49
|
+
// New rules-based configuration
|
|
50
|
+
rules: {
|
|
51
|
+
js: {
|
|
52
|
+
enabled: true,
|
|
53
|
+
pattern:
|
|
54
|
+
"uploads\\/plugin-version\\/\\d+\\/file_name\\/.*\\.js(\\?.*)?",
|
|
55
|
+
redirectUrl: "https://localhost:3060/src/Plugin.vue",
|
|
56
|
+
useCustomPattern: false,
|
|
57
|
+
},
|
|
58
|
+
css: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
pattern:
|
|
61
|
+
"uploads\\/plugin-version\\/\\d+\\/style_file_name\\/.*\\.css(\\?.*)?",
|
|
62
|
+
redirectUrl: "",
|
|
63
|
+
returnBlank: true,
|
|
64
|
+
useCustomPattern: false,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
maskingMode: false,
|
|
68
|
+
clearCacheOnEnable: true,
|
|
69
|
+
disableCacheForRedirects: true,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Load current configuration
|
|
73
|
+
let config = {};
|
|
74
|
+
try {
|
|
75
|
+
const result = await chrome.storage.sync.get(defaultConfig);
|
|
76
|
+
config = result;
|
|
77
|
+
|
|
78
|
+
// Migrate legacy config if needed
|
|
79
|
+
config = migrateConfig(config);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error("Error loading config:", error);
|
|
82
|
+
config = defaultConfig;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Initialize UI with loaded config
|
|
86
|
+
updateUI();
|
|
87
|
+
updatePatternDisplays();
|
|
88
|
+
|
|
89
|
+
function migrateConfig(config) {
|
|
90
|
+
// If rules don't exist, create them from legacy config
|
|
91
|
+
if (!config.rules) {
|
|
92
|
+
config.rules = {
|
|
93
|
+
js: {
|
|
94
|
+
enabled: true,
|
|
95
|
+
pattern: config.urlPattern || defaultConfig.rules.js.pattern,
|
|
96
|
+
redirectUrl: config.redirectUrl || defaultConfig.rules.js.redirectUrl,
|
|
97
|
+
useCustomPattern: config.useCustomPattern || false,
|
|
98
|
+
},
|
|
99
|
+
css: {
|
|
100
|
+
enabled: true,
|
|
101
|
+
pattern: defaultConfig.rules.css.pattern,
|
|
102
|
+
redirectUrl: "",
|
|
103
|
+
returnBlank: true,
|
|
104
|
+
useCustomPattern: false,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return config;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function updateUI() {
|
|
112
|
+
// Update toggle button
|
|
113
|
+
if (config.enabled) {
|
|
114
|
+
toggleButton.classList.add("enabled");
|
|
115
|
+
toggleText.textContent = "ON";
|
|
116
|
+
} else {
|
|
117
|
+
toggleButton.classList.remove("enabled");
|
|
118
|
+
toggleText.textContent = "OFF";
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Update global settings
|
|
122
|
+
maskingModeCheckbox.checked = config.maskingMode || false;
|
|
123
|
+
clearCacheOnEnableCheckbox.checked = config.clearCacheOnEnable !== false;
|
|
124
|
+
disableCacheForRedirectsCheckbox.checked =
|
|
125
|
+
config.disableCacheForRedirects !== false;
|
|
126
|
+
|
|
127
|
+
// Update JS rule
|
|
128
|
+
if (config.rules && config.rules.js) {
|
|
129
|
+
jsRuleEnabled.checked = config.rules.js.enabled;
|
|
130
|
+
jsRedirectUrl.value = config.rules.js.redirectUrl || "";
|
|
131
|
+
jsCustomPattern.checked = config.rules.js.useCustomPattern || false;
|
|
132
|
+
jsCustomPatternInput.value = config.rules.js.pattern || "";
|
|
133
|
+
|
|
134
|
+
// Toggle JS rule content visibility
|
|
135
|
+
if (config.rules.js.enabled) {
|
|
136
|
+
jsRuleContent.classList.remove("rule-disabled");
|
|
137
|
+
} else {
|
|
138
|
+
jsRuleContent.classList.add("rule-disabled");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Toggle custom pattern input visibility
|
|
142
|
+
if (config.rules.js.useCustomPattern) {
|
|
143
|
+
jsCustomPatternInput.classList.add("visible");
|
|
144
|
+
jsPatternDisplay.style.display = "none";
|
|
145
|
+
} else {
|
|
146
|
+
jsCustomPatternInput.classList.remove("visible");
|
|
147
|
+
jsPatternDisplay.style.display = "block";
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Update CSS rule
|
|
152
|
+
if (config.rules && config.rules.css) {
|
|
153
|
+
cssRuleEnabled.checked = config.rules.css.enabled;
|
|
154
|
+
cssRedirectUrl.value = config.rules.css.redirectUrl || "";
|
|
155
|
+
cssReturnBlank.checked = config.rules.css.returnBlank || false;
|
|
156
|
+
cssCustomPattern.checked = config.rules.css.useCustomPattern || false;
|
|
157
|
+
cssCustomPatternInput.value = config.rules.css.pattern || "";
|
|
158
|
+
|
|
159
|
+
// Toggle CSS rule content visibility
|
|
160
|
+
if (config.rules.css.enabled) {
|
|
161
|
+
cssRuleContent.classList.remove("rule-disabled");
|
|
162
|
+
} else {
|
|
163
|
+
cssRuleContent.classList.add("rule-disabled");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Toggle redirect section based on blank return setting
|
|
167
|
+
if (config.rules.css.returnBlank) {
|
|
168
|
+
cssRedirectSection.style.display = "none";
|
|
169
|
+
} else {
|
|
170
|
+
cssRedirectSection.style.display = "block";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Toggle custom pattern input visibility
|
|
174
|
+
if (config.rules.css.useCustomPattern) {
|
|
175
|
+
cssCustomPatternInput.classList.add("visible");
|
|
176
|
+
cssPatternDisplay.style.display = "none";
|
|
177
|
+
} else {
|
|
178
|
+
cssCustomPatternInput.classList.remove("visible");
|
|
179
|
+
cssPatternDisplay.style.display = "block";
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function updatePatternDisplays() {
|
|
185
|
+
// Update JS pattern display
|
|
186
|
+
if (config.rules && config.rules.js) {
|
|
187
|
+
const jsPattern = config.rules.js.useCustomPattern
|
|
188
|
+
? config.rules.js.pattern
|
|
189
|
+
: defaultConfig.rules.js.pattern;
|
|
190
|
+
jsPatternDisplay.textContent = jsPattern;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Update CSS pattern display
|
|
194
|
+
if (config.rules && config.rules.css) {
|
|
195
|
+
const cssPattern = config.rules.css.useCustomPattern
|
|
196
|
+
? config.rules.css.pattern
|
|
197
|
+
: defaultConfig.rules.css.pattern;
|
|
198
|
+
cssPatternDisplay.textContent = cssPattern;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function showStatus(message, isSuccess = true) {
|
|
203
|
+
statusDiv.textContent = message;
|
|
204
|
+
statusDiv.className = `status ${isSuccess ? "success" : "error"}`;
|
|
205
|
+
statusDiv.style.display = "block";
|
|
206
|
+
|
|
207
|
+
setTimeout(() => {
|
|
208
|
+
statusDiv.style.display = "none";
|
|
209
|
+
}, 3000);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function validateRedirectUrl(url) {
|
|
213
|
+
if (!url || url.trim() === "") {
|
|
214
|
+
return null; // Empty URL is valid for optional fields
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
new URL(url);
|
|
219
|
+
return null; // Valid
|
|
220
|
+
} catch {
|
|
221
|
+
// Check if it's a relative-style URL like localhost:3060/path
|
|
222
|
+
if (url.includes("://")) {
|
|
223
|
+
return "Invalid URL format";
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Try to parse as localhost-style URL
|
|
227
|
+
try {
|
|
228
|
+
new URL("https://" + url);
|
|
229
|
+
return null; // Valid
|
|
230
|
+
} catch {
|
|
231
|
+
return "Invalid URL format";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function validatePattern(pattern) {
|
|
237
|
+
if (!pattern || pattern.trim() === "") {
|
|
238
|
+
return "URL pattern is required";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
new RegExp(pattern);
|
|
243
|
+
return null; // Valid
|
|
244
|
+
} catch {
|
|
245
|
+
return "Invalid regular expression pattern";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function normalizeUrl(url) {
|
|
250
|
+
if (!url || url.trim() === "") return "";
|
|
251
|
+
if (!url.includes("://")) {
|
|
252
|
+
return "https://" + url;
|
|
253
|
+
}
|
|
254
|
+
return url;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Event listeners
|
|
258
|
+
toggleButton.addEventListener("click", async function () {
|
|
259
|
+
config.enabled = !config.enabled;
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
await chrome.storage.sync.set({ enabled: config.enabled });
|
|
263
|
+
updateUI();
|
|
264
|
+
|
|
265
|
+
// Send message to background script
|
|
266
|
+
chrome.runtime.sendMessage({
|
|
267
|
+
action: "toggleProxy",
|
|
268
|
+
enabled: config.enabled,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
showStatus(config.enabled ? "Proxy enabled" : "Proxy disabled");
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error("Error toggling proxy:", error);
|
|
274
|
+
showStatus("Error toggling proxy", false);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Global settings event listeners
|
|
279
|
+
maskingModeCheckbox.addEventListener("change", function () {
|
|
280
|
+
config.maskingMode = this.checked;
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
clearCacheOnEnableCheckbox.addEventListener("change", function () {
|
|
284
|
+
config.clearCacheOnEnable = this.checked;
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
disableCacheForRedirectsCheckbox.addEventListener("change", function () {
|
|
288
|
+
config.disableCacheForRedirects = this.checked;
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// JS rule event listeners
|
|
292
|
+
jsRuleEnabled.addEventListener("change", function () {
|
|
293
|
+
if (!config.rules) config.rules = {};
|
|
294
|
+
if (!config.rules.js) config.rules.js = { ...defaultConfig.rules.js };
|
|
295
|
+
config.rules.js.enabled = this.checked;
|
|
296
|
+
updateUI();
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
jsCustomPattern.addEventListener("change", function () {
|
|
300
|
+
if (!config.rules) config.rules = {};
|
|
301
|
+
if (!config.rules.js) config.rules.js = { ...defaultConfig.rules.js };
|
|
302
|
+
config.rules.js.useCustomPattern = this.checked;
|
|
303
|
+
updateUI();
|
|
304
|
+
updatePatternDisplays();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// CSS rule event listeners
|
|
308
|
+
cssRuleEnabled.addEventListener("change", function () {
|
|
309
|
+
if (!config.rules) config.rules = {};
|
|
310
|
+
if (!config.rules.css) config.rules.css = { ...defaultConfig.rules.css };
|
|
311
|
+
config.rules.css.enabled = this.checked;
|
|
312
|
+
updateUI();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
cssReturnBlank.addEventListener("change", function () {
|
|
316
|
+
if (!config.rules) config.rules = {};
|
|
317
|
+
if (!config.rules.css) config.rules.css = { ...defaultConfig.rules.css };
|
|
318
|
+
config.rules.css.returnBlank = this.checked;
|
|
319
|
+
updateUI();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
cssCustomPattern.addEventListener("change", function () {
|
|
323
|
+
if (!config.rules) config.rules = {};
|
|
324
|
+
if (!config.rules.css) config.rules.css = { ...defaultConfig.rules.css };
|
|
325
|
+
config.rules.css.useCustomPattern = this.checked;
|
|
326
|
+
updateUI();
|
|
327
|
+
updatePatternDisplays();
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
clearCacheButton.addEventListener("click", async function () {
|
|
331
|
+
try {
|
|
332
|
+
this.textContent = "Clearing...";
|
|
333
|
+
this.disabled = true;
|
|
334
|
+
|
|
335
|
+
const response = await chrome.runtime.sendMessage({
|
|
336
|
+
action: "clearCache",
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (response.success) {
|
|
340
|
+
showStatus("Cache cleared successfully");
|
|
341
|
+
} else {
|
|
342
|
+
showStatus(
|
|
343
|
+
"Error clearing cache: " + (response.error || "Unknown error"),
|
|
344
|
+
false
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
} catch (error) {
|
|
348
|
+
console.error("Error clearing cache:", error);
|
|
349
|
+
showStatus("Error clearing cache", false);
|
|
350
|
+
} finally {
|
|
351
|
+
this.textContent = "Clear Cache Now";
|
|
352
|
+
this.disabled = false;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
saveButton.addEventListener("click", async function () {
|
|
357
|
+
// Ensure rules structure exists
|
|
358
|
+
if (!config.rules) config.rules = {};
|
|
359
|
+
if (!config.rules.js) config.rules.js = { ...defaultConfig.rules.js };
|
|
360
|
+
if (!config.rules.css) config.rules.css = { ...defaultConfig.rules.css };
|
|
361
|
+
|
|
362
|
+
// Validate JS rule if enabled
|
|
363
|
+
if (config.rules.js.enabled) {
|
|
364
|
+
const jsRedirectUrlValue = jsRedirectUrl.value.trim();
|
|
365
|
+
const jsPatternValue = config.rules.js.useCustomPattern
|
|
366
|
+
? jsCustomPatternInput.value.trim()
|
|
367
|
+
: defaultConfig.rules.js.pattern;
|
|
368
|
+
|
|
369
|
+
if (!jsRedirectUrlValue) {
|
|
370
|
+
showStatus(
|
|
371
|
+
"JavaScript redirect URL is required when JS rule is enabled",
|
|
372
|
+
false
|
|
373
|
+
);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const jsUrlError = validateRedirectUrl(jsRedirectUrlValue);
|
|
378
|
+
if (jsUrlError) {
|
|
379
|
+
showStatus("JavaScript rule: " + jsUrlError, false);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const jsPatternError = validatePattern(jsPatternValue);
|
|
384
|
+
if (jsPatternError) {
|
|
385
|
+
showStatus("JavaScript rule: " + jsPatternError, false);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Update JS rule config
|
|
390
|
+
config.rules.js.redirectUrl = normalizeUrl(jsRedirectUrlValue);
|
|
391
|
+
config.rules.js.pattern = jsPatternValue;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Validate CSS rule if enabled
|
|
395
|
+
if (config.rules.css.enabled) {
|
|
396
|
+
const cssRedirectUrlValue = cssRedirectUrl.value.trim();
|
|
397
|
+
const cssPatternValue = config.rules.css.useCustomPattern
|
|
398
|
+
? cssCustomPatternInput.value.trim()
|
|
399
|
+
: defaultConfig.rules.css.pattern;
|
|
400
|
+
|
|
401
|
+
// Only validate redirect URL if not returning blank
|
|
402
|
+
if (!config.rules.css.returnBlank && !cssRedirectUrlValue) {
|
|
403
|
+
showStatus(
|
|
404
|
+
"CSS redirect URL is required when CSS rule is enabled and not returning blank",
|
|
405
|
+
false
|
|
406
|
+
);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (!config.rules.css.returnBlank) {
|
|
411
|
+
const cssUrlError = validateRedirectUrl(cssRedirectUrlValue);
|
|
412
|
+
if (cssUrlError) {
|
|
413
|
+
showStatus("CSS rule: " + cssUrlError, false);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const cssPatternError = validatePattern(cssPatternValue);
|
|
419
|
+
if (cssPatternError) {
|
|
420
|
+
showStatus("CSS rule: " + cssPatternError, false);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Update CSS rule config
|
|
425
|
+
config.rules.css.redirectUrl = normalizeUrl(cssRedirectUrlValue);
|
|
426
|
+
config.rules.css.pattern = cssPatternValue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
try {
|
|
430
|
+
await chrome.storage.sync.set(config);
|
|
431
|
+
|
|
432
|
+
// Send updated config to background script
|
|
433
|
+
chrome.runtime.sendMessage({
|
|
434
|
+
action: "updateConfig",
|
|
435
|
+
config: config,
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
updateUI();
|
|
439
|
+
updatePatternDisplays();
|
|
440
|
+
showStatus("Configuration saved successfully");
|
|
441
|
+
} catch (error) {
|
|
442
|
+
console.error("Error saving config:", error);
|
|
443
|
+
showStatus("Error saving configuration", false);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Send initial config to background script
|
|
448
|
+
chrome.runtime.sendMessage({
|
|
449
|
+
action: "updateConfig",
|
|
450
|
+
config: config,
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// ============================================================
|
|
454
|
+
// Component Inspector
|
|
455
|
+
// ============================================================
|
|
456
|
+
|
|
457
|
+
function updateInspectorUI() {
|
|
458
|
+
if (inspectorEnabled) {
|
|
459
|
+
inspectorToggle.classList.add("enabled");
|
|
460
|
+
inspectorText.textContent = "ON";
|
|
461
|
+
} else {
|
|
462
|
+
inspectorToggle.classList.remove("enabled");
|
|
463
|
+
inspectorText.textContent = "OFF";
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Get initial inspector state from content script
|
|
468
|
+
async function getInspectorState() {
|
|
469
|
+
try {
|
|
470
|
+
const [tab] = await chrome.tabs.query({
|
|
471
|
+
active: true,
|
|
472
|
+
currentWindow: true,
|
|
473
|
+
});
|
|
474
|
+
if (tab?.id) {
|
|
475
|
+
const response = await chrome.tabs.sendMessage(tab.id, {
|
|
476
|
+
action: "getInspectorState",
|
|
477
|
+
});
|
|
478
|
+
if (response) {
|
|
479
|
+
inspectorEnabled = response.enabled;
|
|
480
|
+
updateInspectorUI();
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
} catch (error) {
|
|
484
|
+
// Content script might not be loaded yet
|
|
485
|
+
console.log("Could not get inspector state:", error);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Toggle inspector
|
|
490
|
+
inspectorToggle.addEventListener("click", async function () {
|
|
491
|
+
try {
|
|
492
|
+
const [tab] = await chrome.tabs.query({
|
|
493
|
+
active: true,
|
|
494
|
+
currentWindow: true,
|
|
495
|
+
});
|
|
496
|
+
if (tab?.id) {
|
|
497
|
+
const response = await chrome.tabs.sendMessage(tab.id, {
|
|
498
|
+
action: "toggleInspector",
|
|
499
|
+
});
|
|
500
|
+
if (response) {
|
|
501
|
+
inspectorEnabled = response.enabled;
|
|
502
|
+
updateInspectorUI();
|
|
503
|
+
showStatus(
|
|
504
|
+
inspectorEnabled ? "Inspector enabled" : "Inspector disabled"
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
} catch (error) {
|
|
509
|
+
showStatus("Could not toggle inspector. Make sure you're on a web page.", false);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Initialize inspector state
|
|
514
|
+
getInspectorState();
|
|
515
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Test Chrome Extension</title>
|
|
5
|
+
<style>
|
|
6
|
+
body { font-family: Arial, sans-serif; padding: 20px; max-width: 800px; }
|
|
7
|
+
.test-section { margin: 20px 0; padding: 20px; border: 2px solid #ddd; border-radius: 8px; }
|
|
8
|
+
.success { border-color: #28a745; background: #f8fff8; }
|
|
9
|
+
.warning { border-color: #ffc107; background: #fffbf0; }
|
|
10
|
+
.info { border-color: #17a2b8; background: #f0f9ff; }
|
|
11
|
+
.code { background: #e9ecef; padding: 8px; font-family: monospace; margin: 8px 0; word-break: break-all; }
|
|
12
|
+
.results { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 4px; max-height: 300px; overflow-y: auto; }
|
|
13
|
+
button { padding: 10px 15px; margin: 5px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 4px; }
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<h1>๐ง Chrome Extension Test</h1>
|
|
18
|
+
|
|
19
|
+
<div class="test-section info">
|
|
20
|
+
<h2>๐ Chrome Extension Differences</h2>
|
|
21
|
+
<ul>
|
|
22
|
+
<li><strong>Manifest V3:</strong> Uses service workers instead of background scripts</li>
|
|
23
|
+
<li><strong>declarativeNetRequest:</strong> Replaces webRequest API for better performance</li>
|
|
24
|
+
<li><strong>chrome API:</strong> Uses <code>chrome.*</code> instead of <code>browser.*</code></li>
|
|
25
|
+
<li><strong>Limited Regex:</strong> Chrome's declarativeNetRequest has more limited pattern matching</li>
|
|
26
|
+
</ul>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="test-section warning">
|
|
30
|
+
<h2>โ ๏ธ Installation Steps for Chrome</h2>
|
|
31
|
+
<ol>
|
|
32
|
+
<li>Open Chrome and go to <code>chrome://extensions/</code></li>
|
|
33
|
+
<li>Enable "Developer mode" (toggle in top right)</li>
|
|
34
|
+
<li>Click "Load unpacked"</li>
|
|
35
|
+
<li>Select the <code>chrome</code> folder</li>
|
|
36
|
+
<li>The extension should appear in your toolbar</li>
|
|
37
|
+
</ol>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div class="test-section success">
|
|
41
|
+
<h2>๐งช Chrome Extension Tests</h2>
|
|
42
|
+
<button onclick="checkChromeExtension()">Check Chrome Extension</button>
|
|
43
|
+
<button onclick="testChromeRequest()">Test Chrome Request</button>
|
|
44
|
+
<button onclick="testDeclarativeRules()">Test Declarative Rules</button>
|
|
45
|
+
<div id="chromeResults" class="results"></div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="test-section">
|
|
49
|
+
<h2>๐ Chrome vs Firefox Comparison</h2>
|
|
50
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
51
|
+
<tr style="background: #f8f9fa;">
|
|
52
|
+
<th style="border: 1px solid #ddd; padding: 8px;">Feature</th>
|
|
53
|
+
<th style="border: 1px solid #ddd; padding: 8px;">Firefox</th>
|
|
54
|
+
<th style="border: 1px solid #ddd; padding: 8px;">Chrome</th>
|
|
55
|
+
</tr>
|
|
56
|
+
<tr>
|
|
57
|
+
<td style="border: 1px solid #ddd; padding: 8px;">API</td>
|
|
58
|
+
<td style="border: 1px solid #ddd; padding: 8px;">browser.*</td>
|
|
59
|
+
<td style="border: 1px solid #ddd; padding: 8px;">chrome.*</td>
|
|
60
|
+
</tr>
|
|
61
|
+
<tr>
|
|
62
|
+
<td style="border: 1px solid #ddd; padding: 8px;">Manifest</td>
|
|
63
|
+
<td style="border: 1px solid #ddd; padding: 8px;">v2</td>
|
|
64
|
+
<td style="border: 1px solid #ddd; padding: 8px;">v3</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td style="border: 1px solid #ddd; padding: 8px;">Background</td>
|
|
68
|
+
<td style="border: 1px solid #ddd; padding: 8px;">Persistent scripts</td>
|
|
69
|
+
<td style="border: 1px solid #ddd; padding: 8px;">Service worker</td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr>
|
|
72
|
+
<td style="border: 1px solid #ddd; padding: 8px;">Network API</td>
|
|
73
|
+
<td style="border: 1px solid #ddd; padding: 8px;">webRequest (full regex)</td>
|
|
74
|
+
<td style="border: 1px solid #ddd; padding: 8px;">declarativeNetRequest (limited patterns)</td>
|
|
75
|
+
</tr>
|
|
76
|
+
</table>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<script>
|
|
80
|
+
function log(message, type = 'info') {
|
|
81
|
+
const results = document.getElementById('chromeResults');
|
|
82
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
83
|
+
const icon = type === 'error' ? 'โ' : type === 'success' ? 'โ
' : type === 'warning' ? 'โ ๏ธ' : 'โน๏ธ';
|
|
84
|
+
results.innerHTML += `<div>${timestamp} ${icon} ${message}</div>`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function checkChromeExtension() {
|
|
88
|
+
log('Checking Chrome extension status...');
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
if (typeof chrome === 'undefined' || !chrome.runtime) {
|
|
92
|
+
log('Chrome extension API not available', 'error');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const response = await chrome.runtime.sendMessage({ action: 'getState' });
|
|
97
|
+
log(`โ
Chrome extension responding: Enabled=${response.enabled}, Rules=${response.rules.length}`, 'success');
|
|
98
|
+
|
|
99
|
+
response.rules.forEach((rule, index) => {
|
|
100
|
+
log(`Rule ${index + 1}: ${rule.pattern} โ ${rule.redirect} (Mask: ${rule.maskUrl || false})`, 'info');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
} catch (error) {
|
|
104
|
+
log(`Chrome extension communication failed: ${error.message}`, 'error');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function testChromeRequest() {
|
|
109
|
+
log('Testing request with Chrome extension...');
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch('https://httpbin.org/get?test=chrome');
|
|
113
|
+
const data = await response.json();
|
|
114
|
+
log(`Request successful: ${response.status}`, 'success');
|
|
115
|
+
log(`Response URL: ${data.url}`, 'info');
|
|
116
|
+
log('Check Chrome DevTools Network tab to see if request was intercepted', 'info');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
log(`Request failed: ${error.message}`, 'error');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function testDeclarativeRules() {
|
|
123
|
+
log('Testing Chrome declarativeNetRequest rules...');
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
if (chrome.declarativeNetRequest) {
|
|
127
|
+
const rules = await chrome.declarativeNetRequest.getDynamicRules();
|
|
128
|
+
log(`Found ${rules.length} declarative rules`, 'success');
|
|
129
|
+
|
|
130
|
+
rules.forEach((rule, index) => {
|
|
131
|
+
log(`Rule ${rule.id}: ${rule.condition.regexFilter || rule.condition.urlFilter} โ ${rule.action.type}`, 'info');
|
|
132
|
+
});
|
|
133
|
+
} else {
|
|
134
|
+
log('declarativeNetRequest API not available', 'warning');
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
log(`Error checking declarative rules: ${error.message}`, 'error');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Auto-run extension check on page load
|
|
142
|
+
window.addEventListener('load', checkChromeExtension);
|
|
143
|
+
</script>
|
|
144
|
+
</body>
|
|
145
|
+
</html>
|