MacOS专区新增浏览器管理添加浏览器自动化,实现自动点击元素,输入文本,注入css等功能

This commit is contained in:
fofolee 2025-01-12 00:57:29 +08:00
parent b7af2bd1ff
commit c3a07ed0b5
9 changed files with 1036 additions and 185 deletions

View File

@ -297,10 +297,15 @@ window.runPythonCommand = (py) => {
};
// 在终端中执行
if (process.platform !== "linux")
if (process.platform !== "linux") {
quickcommand.runInTerminal = function (cmdline, dir) {
let command = getCommandToLaunchTerminal(cmdline, dir);
child_process.exec(command);
};
}
quickcommand.showSystemMessageBox = function (title, content) {
window.utools.showNotification(title + "\n" + content);
};
module.exports = quickcommand;

View File

@ -0,0 +1,347 @@
module.exports = {
// 获取当前地址
getUrl: async function (browser = "Microsoft Edge") {
const result = await quickcommand.runAppleScript(`
tell application "${browser}"
set currentTab to active tab of front window
return URL of currentTab
end tell
`);
return result;
},
// 设置当前地址
setUrl: async function (browser = "Microsoft Edge", url) {
return await quickcommand.runAppleScript(`
tell application "${browser}"
set URL of active tab of front window to "${url}"
end tell
`);
},
// 获取标签列表
getTabs: async function (browser = "Microsoft Edge") {
const result = await quickcommand.runAppleScript(`
tell application "${browser}"
set tabList to every tab of front window
set json to "["
repeat with i from 1 to count of tabList
set currentTab to item i of tabList
set json to json & "{"
set json to json & "\\"title\\":\\"" & title of currentTab & "\\","
set json to json & "\\"url\\":\\"" & URL of currentTab & "\\","
set json to json & "\\"index\\":" & i & ","
set json to json & "\\"loading\\":" & loading of currentTab
set json to json & "}"
if i < count of tabList then
set json to json & ","
end if
end repeat
set json to json & "]"
return json
end tell
`);
return JSON.parse(result);
},
// 切换标签
activateTab: async function (browser = "Microsoft Edge", index) {
return await quickcommand.runAppleScript(`
tell application "${browser}"
activate
tell front window
set active tab index to ${index}
end tell
end tell
`);
},
// 执行脚本
executeScript: async function (
browser = "Microsoft Edge",
script,
newScope = true
) {
try {
// 默认在两边加上括号让脚本每次在新的作用域执行,防止变量污染
if (newScope) script = "{" + script + "}";
// 使用JSON.stringify处理转义
const escapedScript = JSON.stringify(script);
console.log(escapedScript);
return await quickcommand.runAppleScript(`
tell application "${browser}"
tell front window
tell active tab
execute javascript ${escapedScript}
end tell
end tell
end tell
`);
} catch (error) {
quickcommand.showSystemMessageBox("执行失败", error.toString());
}
},
// 点击元素
clickElement: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
if (element) {
element.click();
'success';
} else {
'element not found';
}
`;
return await this.executeScript(browser, script);
},
// 输入文本
inputText: async function (browser = "Microsoft Edge", selector, text) {
const script = `
const element = document.querySelector('${selector}');
if (element) {
element.value = '${text}';
element.dispatchEvent(new Event('input'));
element.dispatchEvent(new Event('change'));
'success';
} else {
'element not found';
}
`;
return await this.executeScript(browser, script);
},
// 获取文本
getText: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
element ? element.textContent : '';
`;
return await this.executeScript(browser, script);
},
// 获取HTML
getHtml: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
element ? element.innerHTML : '';
`;
return await this.executeScript(browser, script);
},
// 隐藏元素
hideElement: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
if (element) {
element.style.display = 'none';
'success';
} else {
'element not found';
}
`;
return await this.executeScript(browser, script);
},
// 显示元素
showElement: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
if (element) {
element.style.display = '';
'success';
} else {
'element not found';
}
`;
return await this.executeScript(browser, script);
},
// 注入CSS
injectCSS: async function (browser = "Microsoft Edge", css) {
const script = `
const style = document.createElement('style');
style.textContent = \`${css}\`;
document.head.appendChild(style);
'success';
`;
return await this.executeScript(browser, script);
},
// 设置Cookie
setCookie: async function (
browser = "Microsoft Edge",
cookies,
options = {}
) {
// 在外部构建所有cookie的设置语句
console.log(cookies, options);
const cookieStatements = cookies
.map((cookie) => {
let cookieString = `${cookie.name}=${cookie.value}`;
if (options.expires) cookieString += `;expires=${options.expires}`;
if (options.path) cookieString += `;path=${options.path}`;
if (options.domain) cookieString += `;domain=${options.domain}`;
if (options.secure) cookieString += ";secure";
if (options.sameSite) cookieString += `;samesite=${options.sameSite}`;
return `document.cookie = ${JSON.stringify(cookieString)};`;
})
.join("\n");
const script = `
${cookieStatements}
'success';
`;
return await this.executeScript(browser, script);
},
// 获取Cookie
getCookie: async function (browser = "Microsoft Edge", name) {
const script = `
const value = document.cookie
.split('; ')
.find(row => row.startsWith('${name}='))
?.split('=')[1];
value || '';
`;
return await this.executeScript(browser, script);
},
// 删除Cookie
deleteCookie: async function (
browser = "Microsoft Edge",
name,
path = "/",
domain = ""
) {
const script = `
document.cookie = '${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
(${domain ? `'; domain=${domain}'` : "''"}) +
(${path ? `'; path=${path}'` : "''"});
'success';
`;
return await this.executeScript(browser, script);
},
// 滚动到指定位置
scrollTo: async function (browser = "Microsoft Edge", x, y) {
const script = `
window.scrollTo(${x}, ${y});
'success';
`;
return await this.executeScript(browser, script);
},
// 滚动到元素位置
scrollToElement: async function (browser = "Microsoft Edge", selector) {
const script = `
const element = document.querySelector('${selector}');
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
'success';
} else {
'element not found';
}
`;
return await this.executeScript(browser, script);
},
// 获取滚动位置
getScrollPosition: async function (browser = "Microsoft Edge") {
const script = `
JSON.stringify({
x: window.pageXOffset || document.documentElement.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop
});
`;
return await this.executeScript(browser, script);
},
// 获取页面尺寸
getPageSize: async function (browser = "Microsoft Edge") {
const script = `
JSON.stringify({
width: Math.max(
document.documentElement.scrollWidth,
document.documentElement.clientWidth
),
height: Math.max(
document.documentElement.scrollHeight,
document.documentElement.clientHeight
)
});
`;
return await this.executeScript(browser, script);
},
// 等待元素出现
waitForElement: async function (
browser = "Microsoft Edge",
selector,
timeout = 5000
) {
const script = `
new Promise((resolve, reject) => {
const element = document.querySelector('${selector}');
if (element) {
resolve('found');
return;
}
const observer = new MutationObserver((mutations, obs) => {
const element = document.querySelector('${selector}');
if (element) {
obs.disconnect();
resolve('found');
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(() => {
observer.disconnect();
reject('timeout');
}, ${timeout});
});
`;
return await this.executeScript(browser, script);
},
// 监听元素变化
observeElement: async function (
browser = "Microsoft Edge",
selector,
callback
) {
const script = `
const element = document.querySelector('${selector}');
if (!element) return 'element not found';
const observer = new MutationObserver((mutations) => {
const data = mutations.map(mutation => ({
type: mutation.type,
target: mutation.target.outerHTML,
addedNodes: Array.from(mutation.addedNodes).map(node => node.outerHTML),
removedNodes: Array.from(mutation.removedNodes).map(node => node.outerHTML)
}));
window.webkit.messageHandlers.callback.postMessage(JSON.stringify(data));
});
observer.observe(element, {
attributes: true,
childList: true,
subtree: true,
characterData: true
});
'success';
`;
return await this.executeScript(browser, script);
},
};

View File

@ -1,9 +1,11 @@
const app = require("./app");
const system = require("./system");
const finder = require("./finder");
const browser = require("./browser");
module.exports = {
app,
system,
finder,
browser,
};

View File

@ -152,7 +152,7 @@ export default defineComponent({
if (config.component === "VariableInput") {
variableFormatPaths.push(prefix);
} else if (config.component === "ArrayEditor") {
variableFormatPaths.push(`${prefix}[*]`);
variableFormatPaths.push(`${prefix}[*].**`, `${prefix}[*]`);
} else if (config.component === "DictEditor") {
variableFormatPaths.push(`${prefix}.**`);
}
@ -167,7 +167,6 @@ export default defineComponent({
addVariableFormatPath(`arg${index}`, item);
}
});
try {
argvs = parseFunction(code, { variableFormatPaths }).argvs;
} catch (e) {

View File

@ -58,7 +58,6 @@ export default defineComponent({
width: 100%;
flex-wrap: wrap;
gap: 6px;
padding: 10px;
border-radius: 6px;
}

View File

@ -112,15 +112,6 @@ export default {
}
},
},
//
language: {
immediate: true,
handler(newValue) {
if (this.editor) {
monaco.editor.setModelLanguage(this.editor.getModel(), newValue);
}
},
},
"$q.dark.isActive": {
immediate: true,
handler(newValue) {
@ -132,6 +123,7 @@ export default {
this.initEditor();
// MonacoResizeObserver loop limit exceeded
window.addEventListener("resize", this.resizeEditor);
monaco.editor.setTheme(this.$q.dark.isActive ? "vs-dark" : "vs");
},
beforeUnmount() {
this.destroyEditor();

View File

@ -27,43 +27,44 @@
</q-input>
</template>
<template v-else>
<q-select
<q-input
v-if="options?.optionKeys"
:model-value="item.key"
:options="normalizedOptionKeys"
label="名称"
dense
filled
use-input
input-debounce="0"
:hide-selected="!!inputValue"
@filter="filterFn"
@update:model-value="
(val) => handleSelect(val, getEditableIndex(index))
"
@input-value="(val) => handleInput(val, getEditableIndex(index))"
@blur="handleBlur"
@update:model-value="(val) => handleInput(val, index)"
>
<template v-slot:prepend>
<q-icon name="code" />
</template>
<template v-slot:option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section>
{{ getKeyLabel(scope.opt) }}
</q-item-section>
</q-item>
<template v-slot:append>
<q-btn dense flat icon="arrow_drop_down">
<q-menu>
<q-list dense>
<q-item
v-for="opt in normalizedOptionKeys"
:key="opt.value"
clickable
v-close-popup
@click="handleSelect(opt, index)"
>
<q-item-section>
{{ getKeyLabel(opt) }}
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</template>
</q-select>
</q-input>
<q-input
v-else
:model-value="item.key"
label="名称"
dense
filled
@update:model-value="
(val) => updateItemKey(val, getEditableIndex(index))
"
@update:model-value="(val) => handleInput(val, index)"
>
<template v-slot:prepend>
<q-icon name="code" />
@ -77,9 +78,7 @@
label="值"
icon="code"
class="col-grow"
@update:model-value="
(val) => updateItemValue(val, index, item.type === 'fixed')
"
@update:model-value="(val) => updateItemValue(val, index)"
/>
</div>
<div
@ -87,7 +86,7 @@
class="col-auto"
>
<div class="btn-container">
<template v-if="editableItems.length === 1">
<template v-if="localItems.length === 1">
<q-btn
flat
dense
@ -97,16 +96,14 @@
@click="addItem"
/>
</template>
<template
v-else-if="getEditableIndex(index) === editableItems.length - 1"
>
<template v-else-if="index === allItems.length - 1">
<q-btn
flat
dense
size="sm"
icon="remove"
class="top-btn"
@click="removeItem(getEditableIndex(index))"
@click="removeItem(index)"
/>
<q-btn
flat
@ -124,7 +121,7 @@
size="sm"
icon="remove"
class="center-btn"
@click="removeItem(getEditableIndex(index))"
@click="removeItem(index)"
/>
</template>
</div>
@ -140,30 +137,6 @@ import { newVarInputVal } from "js/composer/varInputValManager";
import VariableInput from "components/composer/common/VariableInput.vue";
import BorderLabel from "components/composer/common/BorderLabel.vue";
/**
* 字典编辑器组件
* @description 支持键值对编辑键支持变量选择和字符串输入值为VariableInput特有对象
*
* @property {Object} modelValue - 绑定的字典对象
* @property {Object} options - 配置选项
* @property {String[]|Object[]} [options.optionKeys] - 可选键名
* @property {String[]|Object[]} [options.fixedKeys] - 固定键名
* @property {Boolean} [options.disableAdd] - 禁止添加新的键值对
*
* @example
* //
* {
* key: newVarInputVal("str"),
* }
*
* //
* options.optionKeys = ['User-Agent', 'Content-Type', 'Accept']
* {
* "User-Agent": newVarInputVal("str", "Mozilla/5.0"),
* "Content-Type": newVarInputVal("str", "text/html"),
* "Accept": newVarInputVal("str", "text/html")
* }
*/
export default defineComponent({
name: "DictEditor",
components: {
@ -173,7 +146,6 @@ export default defineComponent({
props: {
modelValue: {
type: Object,
required: true,
default: () => ({}),
},
options: {
@ -198,35 +170,23 @@ export default defineComponent({
},
},
emits: ["update:modelValue"],
created() {
if (!this.modelValue || Object.keys(this.modelValue).length === 0) {
this.$emit("update:modelValue", { "": newVarInputVal("str") });
}
},
data() {
return {
inputValue: "",
};
},
computed: {
editableItems: {
get() {
return this.localItems;
},
set(newItems) {
this.localItems = newItems;
this.updateModelValue();
},
},
normalizedOptionKeys() {
return this.filterOptions;
},
//
normalizedFixedKeys() {
return this.normalizeKeys(this.options?.fixedKeys || []);
},
// modelValue
modelEntries() {
return Object.entries(this.modelValue || {});
},
//
fixedItems() {
return this.normalizedFixedKeys.map((key) => ({
const fixedKeys = this.normalizeKeys(this.options?.fixedKeys || []);
return fixedKeys.map((key) => ({
type: "fixed",
key: key.value,
value:
@ -234,137 +194,85 @@ export default defineComponent({
newVarInputVal("str"),
}));
},
//
localItems() {
//
const editableEntries = this.modelEntries.filter(
([key]) => !this.normalizedFixedKeys.some((k) => k.value === key)
);
return editableEntries.length || this.options?.disableAdd
? editableEntries.map(([key, value]) => ({
type: "editable",
key,
value,
}))
: [{ type: "editable", key: "", value: newVarInputVal("str") }];
return this.modelEntries
.filter(
([key]) =>
!this.normalizeKeys(this.options?.fixedKeys || []).some(
(k) => k.value === key
)
)
.map(([key, value]) => ({
type: "editable",
key,
value,
}));
},
//
allItems() {
return [...this.fixedItems, ...this.localItems];
},
//
filterOptions() {
normalizedOptionKeys() {
return this.normalizeKeys(this.options?.optionKeys || []);
},
},
methods: {
normalizeKeys(keys) {
return keys.map((key) => {
if (typeof key === "string") {
return { value: key, label: key };
}
return key;
});
return keys.map((key) =>
typeof key === "string" ? { value: key, label: key } : key
);
},
getKeyLabel(key) {
if (typeof key === "object") return key.label;
const allKeys = [...this.normalizedFixedKeys, ...this.filterOptions];
const allKeys = [
...this.normalizeKeys(this.options?.fixedKeys || []),
...this.normalizedOptionKeys,
];
return allKeys.find((k) => k.value === key)?.label || key;
},
getEditableIndex(index) {
return index - this.fixedItems.length;
},
updateModelValue() {
const dict = {};
//
this.fixedItems.forEach((item) => {
if (item.key) {
dict[item.key] = item.value;
}
});
//
this.localItems.forEach((item) => {
if (item.key) {
dict[item.key] = item.value;
}
});
updateItemValue(val, index) {
const item = this.allItems[index];
const dict = { ...this.modelValue };
dict[item.key] = val;
this.$emit("update:modelValue", dict);
},
updateItemValue(val, index, isFixed = false) {
const dict = { ...this.modelValue };
const item = this.allItems[index];
if (item.key) {
dict[item.key] = val;
this.$emit("update:modelValue", dict);
}
},
addItem() {
if (this.options?.disableAdd) return;
const dict = { ...this.modelValue };
dict[""] = newVarInputVal("str");
this.$emit("update:modelValue", dict);
},
removeItem(index) {
if (this.options?.disableAdd) return;
const dict = { ...this.modelValue };
const item = this.localItems[index];
if (item.key) {
delete dict[item.key];
this.$emit("update:modelValue", dict);
}
},
updateItemKey(val, index) {
const dict = { ...this.modelValue };
const oldItem = this.localItems[index];
if (oldItem.key) {
delete dict[oldItem.key];
delete dict[item.key];
//
if (Object.keys(dict).length === 0) {
dict[""] = newVarInputVal("str");
}
dict[val] = oldItem.value;
this.$emit("update:modelValue", dict);
},
handleInput(val, index) {
this.inputValue = val;
if (val) {
this.updateItemKey(val, index);
}
const item = this.allItems[index];
const dict = { ...this.modelValue };
delete dict[item.key];
dict[val] = item.value;
this.$emit("update:modelValue", dict);
},
handleSelect(val, index) {
this.inputValue = "";
this.updateItemKey(val.value || val, index);
const value = val?.value || val;
const item = this.allItems[index];
const dict = { ...this.modelValue };
delete dict[item.key];
dict[value] = item.value;
this.$emit("update:modelValue", dict);
},
handleBlur() {
this.inputValue = "";
},
filterFn(val, update) {
if (!this.options?.optionKeys) return;
update(() => {
if (val === "") {
this.filterOptions = this.normalizeKeys(this.options.optionKeys);
} else {
const needle = val.toLowerCase();
this.filterOptions = this.normalizeKeys(
this.options.optionKeys
).filter(
(v) =>
v.label.toLowerCase().indexOf(needle) > -1 ||
v.value.toLowerCase().indexOf(needle) > -1
);
}
});
},
},
});
</script>

View File

@ -1,3 +1,5 @@
import { newVarInputVal } from "js/composer/varInputValManager";
export const macosCommands = {
label: "MacOS专区",
icon: "laptop_mac",
@ -343,5 +345,594 @@ export const macosCommands = {
},
],
},
{
value: "quickcomposer.macos.browser.getUrl",
label: "浏览器管理",
desc: "浏览器管理功能",
icon: "web",
isAsync: true,
subCommands: [
{
value: "quickcomposer.macos.browser.getUrl",
label: "获取当前地址",
desc: "获取当前标签页的URL地址",
icon: "link",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
],
},
{
value: "quickcomposer.macos.browser.setUrl",
label: "设置当前地址",
desc: "设置当前标签页的URL地址",
icon: "link",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "url",
label: "网址",
component: "VariableInput",
icon: "link",
width: 12,
placeholder: "输入网址",
},
],
},
{
value: "quickcomposer.macos.browser.getTabs",
label: "获取标签列表",
desc: "获取所有打开的标签页信息",
icon: "tab",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
],
},
{
value: "quickcomposer.macos.browser.activateTab",
label: "切换标签",
desc: "切换到指定的标签页",
icon: "tab_unselected",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "index",
label: "标签索引",
component: "NumberInput",
icon: "tab",
min: 1,
defaultValue: 1,
width: 12,
},
],
},
{
value: "quickcomposer.macos.browser.executeScript",
label: "执行脚本",
desc: "在当前标签页执行JavaScript脚本",
icon: "code",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "script",
label: "脚本内容",
component: "CodeEditor",
icon: "code",
width: 12,
placeholder: "输入JavaScript代码",
},
],
},
{
value: "quickcomposer.macos.browser.clickElement",
label: "点击元素",
desc: "点击指定的页面元素",
icon: "mouse",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
],
},
{
value: "quickcomposer.macos.browser.inputText",
label: "输入文本",
desc: "在指定输入框中输入文本",
icon: "edit",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
{
key: "text",
label: "文本内容",
component: "VariableInput",
icon: "edit",
width: 12,
placeholder: "输入要填写的文本",
},
],
},
{
value: "quickcomposer.macos.browser.getText",
label: "获取文本",
desc: "获取指定元素的文本内容",
icon: "text_fields",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
],
},
{
value: "quickcomposer.macos.browser.hideElement",
label: "隐藏元素",
desc: "隐藏指定的页面元素",
icon: "visibility_off",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
],
},
{
value: "quickcomposer.macos.browser.showElement",
label: "显示元素",
desc: "显示指定的页面元素",
icon: "visibility",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
],
},
{
value: "quickcomposer.macos.browser.injectCSS",
label: "注入CSS",
desc: "向页面注入CSS样式",
icon: "style",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "css",
label: "CSS内容",
component: "CodeEditor",
icon: "style",
width: 12,
placeholder: "输入CSS代码",
},
],
},
{
value: "quickcomposer.macos.browser.setCookie",
label: "设置Cookie",
desc: "设置浏览器Cookie",
icon: "cookie",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
label: "Cookie",
component: "ArrayEditor",
icon: "cookie",
width: 12,
columns: {
name: {
label: "名称",
defaultValue: newVarInputVal("str"),
},
value: {
label: "值",
defaultValue: newVarInputVal("str"),
},
},
},
{
label: "选项",
component: "DictEditor",
icon: "settings",
width: 12,
options: {
optionKeys: ["expires", "path", "domain", "secure", "sameSite"],
},
},
],
},
{
value: "quickcomposer.macos.browser.getCookie",
label: "获取Cookie",
desc: "获取指定的Cookie值",
icon: "cookie",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "name",
label: "名称",
component: "VariableInput",
icon: "label",
width: 12,
placeholder: "输入Cookie名称",
},
],
},
{
value: "quickcomposer.macos.browser.scrollTo",
label: "滚动到位置",
desc: "滚动到指定坐标位置",
icon: "open_in_full",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "x",
label: "X坐标",
component: "NumberInput",
icon: "arrow_right",
width: 12,
defaultValue: 0,
},
{
key: "y",
label: "Y坐标",
component: "NumberInput",
icon: "arrow_drop_down",
width: 12,
defaultValue: 0,
},
],
},
{
value: "quickcomposer.macos.browser.scrollToElement",
label: "滚动到元素",
desc: "滚动到指定元素位置",
icon: "open_in_full",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
],
},
{
value: "quickcomposer.macos.browser.waitForElement",
label: "等待元素",
desc: "等待指定元素出现",
icon: "hourglass_empty",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
{
key: "timeout",
label: "超时时间",
component: "NumberInput",
icon: "timer",
width: 12,
defaultValue: 5000,
min: 1000,
step: 1000,
},
],
},
{
value: "quickcomposer.macos.browser.observeElement",
label: "监听元素",
desc: "监听指定元素的变化",
icon: "visibility",
config: [
{
key: "browser",
component: "ButtonGroup",
defaultValue: "Microsoft Edge",
options: [
{
label: "Edge 浏览器",
value: "Microsoft Edge",
},
{
label: "Chrome 浏览器",
value: "Google Chrome",
},
],
width: 12,
},
{
key: "selector",
label: "选择器",
component: "VariableInput",
icon: "code",
width: 12,
placeholder: "输入CSS选择器",
},
{
key: "callback",
label: "回调函数",
component: "CodeEditor",
icon: "code",
width: 12,
placeholder: "输入回调函数代码",
},
],
},
],
},
],
};

View File

@ -5,6 +5,14 @@ import {
newVarInputVal,
} from "./varInputValManager";
const processString = (value) => {
try {
return JSON.stringify(value);
} catch (error) {
return `"${value}"`;
}
};
/**
* 处理单个值返回格式化后的字符串
*/
@ -12,13 +20,13 @@ const processValue = (value, parentPath = "") => {
if (!value) return value;
if (typeof value === "object") {
if (isVarInputVal(value)) {
return stringifyVarInputVal(value);
}
return processObject(value, parentPath);
}
if (typeof value === "string") {
return processString(value);
}
return typeof value === "string" ? `"${value}"` : value;
return value;
};
/**
@ -131,7 +139,7 @@ const stringifyObject = (jsonObj) => {
export const stringifyArgv = (argv) => {
// 普通字符串加上引号
if (typeof argv === "string") {
return `"${argv}"`;
return processString(argv);
}
// null类型是Object需要单独处理返回原值
if (argv === null) {