diff --git a/plugin/lib/quickcomposer/browser/browser.js b/plugin/lib/quickcomposer/browser/browser.js index 73308e1..22ff72e 100644 --- a/plugin/lib/quickcomposer/browser/browser.js +++ b/plugin/lib/quickcomposer/browser/browser.js @@ -225,7 +225,7 @@ const executeScript = async (script, args = {}) => { const argValues = Object.values(args).map((v) => JSON.stringify(v)); const wrappedScript = ` - (function(${argNames.join(", ")}) { + (async function(${argNames.join(", ")}) { ${script} })(${argValues.join(", ")}) `; diff --git a/plugin/lib/quickcomposer/browser/tabs.js b/plugin/lib/quickcomposer/browser/tabs.js new file mode 100644 index 0000000..de341cf --- /dev/null +++ b/plugin/lib/quickcomposer/browser/tabs.js @@ -0,0 +1,76 @@ +const CDP = require("chrome-remote-interface"); +const { executeScript } = require("./browser"); + +let client = null; +let Page = null; +let Runtime = null; +let Target = null; + +const initCDP = async (port) => { + if (!client) { + try { + client = await CDP({ port }); + ({ Page, Runtime, Target } = client); + await Promise.all([Page.enable(), Runtime.enable()]); + } catch (err) { + console.log(err); + throw new Error(`请先通过浏览器控制中的"启动浏览器"打开浏览器`); + } + } + return { Page, Runtime, Target }; +}; + +// 获取所有标签页 +const getTabs = async () => { + const targets = await CDP.List(); + return targets + .filter((target) => target.type === "page") + .map((target) => ({ + url: target.url, + title: target.title, + id: target.id, + })); +}; + +const searchTarget = async (searchProperty, searchValue) => { + const targets = await CDP.List(); + const target = targets.find((target) => + target[searchProperty].includes(searchValue) + ); + if (!target) { + throw new Error(`未找到目标: ${searchProperty} = ${searchValue}`); + } + return target; +}; + +// 激活指定标签页 +const activateTab = async (searchProperty, searchValue) => { + const target = await searchTarget(searchProperty, searchValue); + await CDP.Activate({ id: target.id }); +}; + +// 创建新标签页 +const createNewTab = async (url = "about:blank") => { + const { Target } = await initCDP(); + const { targetId } = await Target.createTarget({ url }); + const { targetInfo } = await Target.getTargetInfo({ targetId }); + return { + url: targetInfo.url, + title: targetInfo.title, + id: targetId, + }; +}; + +// 关闭标签页 +const closeTab = async (searchProperty, searchValue) => { + const target = await searchTarget(searchProperty, searchValue); + await CDP.Close({ id: target.id }); +}; + + +module.exports = { + getTabs, + activateTab, + createNewTab, + closeTab, +}; diff --git a/src/js/composer/commands/browserCommands.js b/src/js/composer/commands/browserCommands.js index 5cafb76..0a7c6b6 100644 --- a/src/js/composer/commands/browserCommands.js +++ b/src/js/composer/commands/browserCommands.js @@ -137,6 +137,45 @@ export const browserCommands = { }, ], }, + { + value: "quickcomposer.browser.createNewTab", + label: "创建新标签页", + icon: "tab", + config: [ + { + label: "网址", + component: "VariableInput", + icon: "link", + width: 12, + placeholder: "留空则打开about:blank", + }, + ], + }, + { + value: "quickcomposer.browser.closeTab", + label: "关闭标签页", + icon: "tab", + config: [ + { + component: "QSelect", + icon: "tab", + width: 3, + options: [ + { label: "通过URL", value: "url" }, + { label: "通过标题", value: "title" }, + { label: "通过ID", value: "id" }, + ], + defaultValue: "url", + }, + { + label: "搜索条件", + component: "VariableInput", + icon: "tab", + width: 9, + placeholder: "支持模糊匹配", + }, + ], + }, ], }, {