From f92df6095f48b814db06a637036be8a1cb72fcf6 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 17:02:27 +0900 Subject: [PATCH 01/11] =?UTF-8?q?registerMenuCommand=20=20&=20unregisterMe?= =?UTF-8?q?nuCommand=20=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 89 +++++++++++++------------ 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index b5152110e..9004bd4ed 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -25,6 +25,11 @@ type TxUpdateScriptMenuCallback = ( result: ScriptMenu[] ) => Promise | ScriptMenu[] | undefined; +const enum ScriptMenuRegisterType { + REGISTER = 1, + UNREGISTER = 2, +} + // 以 tabId 为 key 的「执行次数」快取(字串形式存放),供 badge 显示使用。 const runCountMap = new Map(); @@ -173,25 +178,19 @@ export class PopupService { } // 防止并发导致频繁更新菜单,将注册菜单的请求集中在一个队列中处理 - registerMenuCommandMessages = new Map(); - - async registerMenuCommand(message: TScriptMenuRegister) { - const { tabId, uuid } = message; - const mrKey = `${tabId}.${uuid}`; - if (!this.registerMenuCommandMessages.has(mrKey)) { - this.registerMenuCommandMessages.set(mrKey, []); - } - this.registerMenuCommandMessages.get(mrKey)!.push(message); + updateMenuCommends = new Map(); + updateMenuCommend(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { let retUpdated = false; - // 给脚本添加菜单 - await this.txUpdateScriptMenu(tabId, async (data) => { - while (true) { - const message = this.registerMenuCommandMessages.get(mrKey)?.shift(); - if (!message) { - this.registerMenuCommandMessages.delete(mrKey); - return data; - } + while (true) { + const message_ = this.updateMenuCommends.get(mrKey)?.shift(); + if (!message_) { + this.updateMenuCommends.delete(mrKey); + break; + } + if (message_.registerType === ScriptMenuRegisterType.REGISTER) { + const message = message_ as TScriptMenuRegister; + // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 const { key, name, uuid } = message; // 唯一键, 项目显示名字, 脚本uuid const script = data.find((item) => item.uuid === uuid); @@ -227,40 +226,38 @@ export class PopupService { menu.groupKey = groupKey; } } + } else if (message_.registerType === ScriptMenuRegisterType.UNREGISTER) { + const { key, uuid } = message_; + const script = data.find((item) => item.uuid === uuid); + if (script) { + // 删除菜单 + const index = script.menus.findIndex((item) => item.key === key); + if (index >= 0) { + retUpdated = true; + script.menus.splice(index, 1); + } + } } - }); - if (retUpdated) { - this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); - // 更新数据后再更新菜单 - await this.updateScriptMenu(tabId); } + return retUpdated; } - unregisterMenuCommandMessages = new Map(); - - async unregisterMenuCommand({ key, uuid, tabId }: TScriptMenuUnregister) { + async updateRegisterMenuCommand( + message: TScriptMenuRegister | TScriptMenuUnregister, + registerType: ScriptMenuRegisterType + ) { + const { tabId, uuid } = message; const mrKey = `${tabId}.${uuid}`; - if (!this.unregisterMenuCommandMessages.has(mrKey)) { - this.unregisterMenuCommandMessages.set(mrKey, []); + let list = this.updateMenuCommends.get(mrKey); + if (!list) { + this.updateMenuCommends.set(mrKey, (list = [])); } - this.unregisterMenuCommandMessages.get(mrKey)!.push({ key, uuid, tabId }); + list.push({ ...message, registerType }); let retUpdated = false; await this.txUpdateScriptMenu(tabId, async (data) => { - while (true) { - const message = this.unregisterMenuCommandMessages.get(mrKey)?.shift(); - if (!message) { - this.unregisterMenuCommandMessages.delete(mrKey); - return data; - } - const script = data.find((item) => item.uuid === uuid); - if (script) { - retUpdated = true; - // 删除菜单 - script.menus = script.menus.filter((item) => item.key !== key); - } - return data; - } + retUpdated = this.updateMenuCommend(tabId, uuid, data, mrKey); + return data; }); if (retUpdated) { @@ -270,6 +267,14 @@ export class PopupService { } } + async registerMenuCommand(message: TScriptMenuRegister) { + this.updateRegisterMenuCommand(message, ScriptMenuRegisterType.REGISTER); + } + + async unregisterMenuCommand({ key, uuid, tabId }: TScriptMenuUnregister) { + this.updateRegisterMenuCommand({ key, uuid, tabId }, ScriptMenuRegisterType.UNREGISTER); + } + async updateScriptMenu(tabId: number) { if (tabId !== lastActiveTabId) return; // 其他页面的指令,不理 From e18d16e7d496394e5d8cc6fedadc6d7e517f8506 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 17:50:07 +0900 Subject: [PATCH 02/11] =?UTF-8?q?//=20=E5=A2=9E=E5=8A=A0=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=20await=20Promise.reslove()=20=E8=BD=AC=E7=A7=BB=E5=BE=AE?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E9=98=9F=E5=88=97=20=E5=86=8D=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E9=95=BF=E5=BA=A6=E6=98=AF=E5=90=A6=E4=B8=BA0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 9004bd4ed..ba2318e86 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -178,14 +178,15 @@ export class PopupService { } // 防止并发导致频繁更新菜单,将注册菜单的请求集中在一个队列中处理 - updateMenuCommends = new Map(); + updateMenuCommands = new Map(); + isUpdateMenuDirty = false; - updateMenuCommend(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { + updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { let retUpdated = false; while (true) { - const message_ = this.updateMenuCommends.get(mrKey)?.shift(); + const message_ = this.updateMenuCommands.get(mrKey)?.shift(); if (!message_) { - this.updateMenuCommends.delete(mrKey); + this.updateMenuCommands.delete(mrKey); break; } if (message_.registerType === ScriptMenuRegisterType.REGISTER) { @@ -248,17 +249,20 @@ export class PopupService { ) { const { tabId, uuid } = message; const mrKey = `${tabId}.${uuid}`; - let list = this.updateMenuCommends.get(mrKey); + let list = this.updateMenuCommands.get(mrKey); if (!list) { - this.updateMenuCommends.set(mrKey, (list = [])); + this.updateMenuCommands.set(mrKey, (list = [])); } list.push({ ...message, registerType }); + await Promise.resolve(); // 增加一个 await Promise.reslove() 转移微任务队列 再判断长度是否为0 let retUpdated = false; - await this.txUpdateScriptMenu(tabId, async (data) => { - retUpdated = this.updateMenuCommend(tabId, uuid, data, mrKey); - return data; - }); + if (list.length) { + await this.txUpdateScriptMenu(tabId, async (data) => { + retUpdated = this.updateMenuCommand(tabId, uuid, data, mrKey); + return data; + }); + } if (retUpdated) { this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); From f6c11962a407619bb6b566b29ecd4c6224936096 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:17:11 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 31 +++++++++++-------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index ba2318e86..da959bc85 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -183,19 +183,19 @@ export class PopupService { updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { let retUpdated = false; - while (true) { - const message_ = this.updateMenuCommands.get(mrKey)?.shift(); - if (!message_) { - this.updateMenuCommands.delete(mrKey); - break; - } - if (message_.registerType === ScriptMenuRegisterType.REGISTER) { - const message = message_ as TScriptMenuRegister; + const script = data.find((item) => item.uuid === uuid); + if (script) { + while (true) { + const message_ = this.updateMenuCommands.get(mrKey)?.shift(); + if (!message_) { + this.updateMenuCommands.delete(mrKey); + break; + } + if (message_.registerType === ScriptMenuRegisterType.REGISTER) { + const message = message_ as TScriptMenuRegister; - // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 - const { key, name, uuid } = message; // 唯一键, 项目显示名字, 脚本uuid - const script = data.find((item) => item.uuid === uuid); - if (script) { + // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 + const { key, name } = message; // 唯一键, 项目显示名字, 脚本uuid retUpdated = true; // 以 options+name 生成稳定 groupKey:相同语义项目在 UI 只呈现一次,但可同时触发多个来源(frame)。 // groupKey 用来表示「相同性质的项目」,允许重叠。 @@ -226,11 +226,8 @@ export class PopupService { menu.options = message.options; menu.groupKey = groupKey; } - } - } else if (message_.registerType === ScriptMenuRegisterType.UNREGISTER) { - const { key, uuid } = message_; - const script = data.find((item) => item.uuid === uuid); - if (script) { + } else if (message_.registerType === ScriptMenuRegisterType.UNREGISTER) { + const { key } = message_; // 删除菜单 const index = script.menus.findIndex((item) => item.key === key); if (index >= 0) { From fd19059d49be8333ca479729988119acb8635d88 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:18:39 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index da959bc85..88c2982b9 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -185,6 +185,7 @@ export class PopupService { let retUpdated = false; const script = data.find((item) => item.uuid === uuid); if (script) { + const menus = script.menus; while (true) { const message_ = this.updateMenuCommands.get(mrKey)?.shift(); if (!message_) { @@ -208,7 +209,7 @@ export class PopupService { : `${name}\n${message.options?.accessKey || ""}`, groupKeyNS ); - const menu = script.menus.find((item) => item.key === key); + const menu = menus.find((item) => item.key === key); if (!menu) { // 不存在新增 script.menus.push({ @@ -229,10 +230,10 @@ export class PopupService { } else if (message_.registerType === ScriptMenuRegisterType.UNREGISTER) { const { key } = message_; // 删除菜单 - const index = script.menus.findIndex((item) => item.key === key); + const index = menus.findIndex((item) => item.key === key); if (index >= 0) { retUpdated = true; - script.menus.splice(index, 1); + menus.splice(index, 1); } } } From 661f6e67822572d82cd85fa6173ad13bc2d0d603 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:23:17 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 88c2982b9..4d3cb0318 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -183,15 +183,12 @@ export class PopupService { updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { let retUpdated = false; + const list = this.updateMenuCommands.get(mrKey); + if (!list) return false; const script = data.find((item) => item.uuid === uuid); if (script) { const menus = script.menus; - while (true) { - const message_ = this.updateMenuCommands.get(mrKey)?.shift(); - if (!message_) { - this.updateMenuCommands.delete(mrKey); - break; - } + for (const message_ of list) { if (message_.registerType === ScriptMenuRegisterType.REGISTER) { const message = message_ as TScriptMenuRegister; @@ -238,6 +235,8 @@ export class PopupService { } } } + list.length = 0; + this.updateMenuCommands.delete(mrKey); return retUpdated; } From 4eac28f0809de8c46216c7cfe75afec640cc8c8c Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:24:57 +0900 Subject: [PATCH 06/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 4d3cb0318..ba4de99dd 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -255,7 +255,7 @@ export class PopupService { let retUpdated = false; if (list.length) { - await this.txUpdateScriptMenu(tabId, async (data) => { + await this.txUpdateScriptMenu(tabId, (data) => { retUpdated = this.updateMenuCommand(tabId, uuid, data, mrKey); return data; }); From 04076eedb41bb42ed2209f66080f8aa32e475c06 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:34:16 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 38 +++++++++++++------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index ba4de99dd..2a67ec2cb 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -181,7 +181,7 @@ export class PopupService { updateMenuCommands = new Map(); isUpdateMenuDirty = false; - updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string) { + updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string): boolean { let retUpdated = false; const list = this.updateMenuCommands.get(mrKey); if (!list) return false; @@ -240,10 +240,10 @@ export class PopupService { return retUpdated; } - async updateRegisterMenuCommand( + updateRegisterMenuCommand( message: TScriptMenuRegister | TScriptMenuUnregister, registerType: ScriptMenuRegisterType - ) { + ): Promise { const { tabId, uuid } = message; const mrKey = `${tabId}.${uuid}`; let list = this.updateMenuCommands.get(mrKey); @@ -251,28 +251,30 @@ export class PopupService { this.updateMenuCommands.set(mrKey, (list = [])); } list.push({ ...message, registerType }); - await Promise.resolve(); // 增加一个 await Promise.reslove() 转移微任务队列 再判断长度是否为0 - let retUpdated = false; - if (list.length) { - await this.txUpdateScriptMenu(tabId, (data) => { - retUpdated = this.updateMenuCommand(tabId, uuid, data, mrKey); - return data; + return Promise.resolve() // 增加一个 await Promise.reslove() 转移微任务队列 再判断长度是否为0 + .then(() => { + if (list.length) { + return this.txUpdateScriptMenu(tabId, (data) => { + retUpdated = this.updateMenuCommand(tabId, uuid, data, mrKey); + return data; + }); + } + }) + .then(() => { + if (retUpdated) { + this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); + // 更新数据后再更新菜单 + this.updateScriptMenu(tabId); + } }); - } - - if (retUpdated) { - this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); - // 更新数据后再更新菜单 - await this.updateScriptMenu(tabId); - } } - async registerMenuCommand(message: TScriptMenuRegister) { + registerMenuCommand(message: TScriptMenuRegister) { this.updateRegisterMenuCommand(message, ScriptMenuRegisterType.REGISTER); } - async unregisterMenuCommand({ key, uuid, tabId }: TScriptMenuUnregister) { + unregisterMenuCommand({ key, uuid, tabId }: TScriptMenuUnregister) { this.updateRegisterMenuCommand({ key, uuid, tabId }, ScriptMenuRegisterType.UNREGISTER); } From 35046eb491c4e21613e6f132479641f3ce3873c5 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 18:35:42 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 2a67ec2cb..41eaf886f 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -188,9 +188,9 @@ export class PopupService { const script = data.find((item) => item.uuid === uuid); if (script) { const menus = script.menus; - for (const message_ of list) { - if (message_.registerType === ScriptMenuRegisterType.REGISTER) { - const message = message_ as TScriptMenuRegister; + for (const listEntry of list) { + if (listEntry.registerType === ScriptMenuRegisterType.REGISTER) { + const message = listEntry as TScriptMenuRegister; // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 const { key, name } = message; // 唯一键, 项目显示名字, 脚本uuid @@ -209,7 +209,7 @@ export class PopupService { const menu = menus.find((item) => item.key === key); if (!menu) { // 不存在新增 - script.menus.push({ + menus.push({ groupKey, key: key, // unique primary key name: name, @@ -224,8 +224,8 @@ export class PopupService { menu.options = message.options; menu.groupKey = groupKey; } - } else if (message_.registerType === ScriptMenuRegisterType.UNREGISTER) { - const { key } = message_; + } else if (listEntry.registerType === ScriptMenuRegisterType.UNREGISTER) { + const { key } = listEntry; // 删除菜单 const index = menus.findIndex((item) => item.key === key); if (index >= 0) { From cdec99371cfa570183b823cfa5b76d0bb5d84f96 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 19:14:08 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=E5=87=8F=E5=B0=91=E9=98=9F=E5=88=97?= =?UTF-8?q?=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 129 ++++++++++++------------ 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 41eaf886f..3df079304 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -178,92 +178,97 @@ export class PopupService { } // 防止并发导致频繁更新菜单,将注册菜单的请求集中在一个队列中处理 - updateMenuCommands = new Map(); + updateMenuCommands = new Map(); isUpdateMenuDirty = false; - updateMenuCommand(tabId: number, uuid: string, data: ScriptMenu[], mrKey: string): boolean { - let retUpdated = false; - const list = this.updateMenuCommands.get(mrKey); - if (!list) return false; - const script = data.find((item) => item.uuid === uuid); - if (script) { - const menus = script.menus; - for (const listEntry of list) { - if (listEntry.registerType === ScriptMenuRegisterType.REGISTER) { - const message = listEntry as TScriptMenuRegister; - - // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 - const { key, name } = message; // 唯一键, 项目显示名字, 脚本uuid - retUpdated = true; - // 以 options+name 生成稳定 groupKey:相同语义项目在 UI 只呈现一次,但可同时触发多个来源(frame)。 - // groupKey 用来表示「相同性质的项目」,允许重叠。 - // 例如 subframe 和 mainframe 创建了相同的 menu item,显示时只会出现一个。 - // 但点击后,两边都会执行。 - // 目的是整理显示,实际上内部还是存有多笔 entry(分别记录不同的 frameId 和 id)。 - const groupKey = uuidv5( - message.options?.inputType - ? JSON.stringify({ ...message.options, autoClose: undefined, id: undefined, name: name }) - : `${name}\n${message.options?.accessKey || ""}`, - groupKeyNS - ); - const menu = menus.find((item) => item.key === key); - if (!menu) { - // 不存在新增 - menus.push({ - groupKey, - key: key, // unique primary key - name: name, - options: message.options, - tabId: tabId, // fix - frameId: message.frameId, // fix with unique key - documentId: message.documentId, // fix with unique key - }); - } else { - // 存在修改信息 - menu.name = message.name; - menu.options = message.options; - menu.groupKey = groupKey; - } - } else if (listEntry.registerType === ScriptMenuRegisterType.UNREGISTER) { - const { key } = listEntry; - // 删除菜单 - const index = menus.findIndex((item) => item.key === key); - if (index >= 0) { - retUpdated = true; - menus.splice(index, 1); - } + updateMenuCommand(tabId: number, data: ScriptMenu[]): string[] { + const retUpdated = new Set(); + const list = this.updateMenuCommands.get(tabId); + if (!list) return []; + const uuids = new Set(list.map((entry) => entry.uuid)); + const scripts = new Map(data.filter((item) => uuids.has(item.uuid)).map((item) => [item.uuid, item])); + for (const listEntry of list) { + if (listEntry.registerType === ScriptMenuRegisterType.REGISTER) { + const message = listEntry as TScriptMenuRegister; + + // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 + const { key, name } = message; // 唯一键, 项目显示名字, 脚本uuid + const script = scripts.get(message.uuid); + if (!script) continue; + const menus = script.menus; + retUpdated.add(script.uuid); + // 以 options+name 生成稳定 groupKey:相同语义项目在 UI 只呈现一次,但可同时触发多个来源(frame)。 + // groupKey 用来表示「相同性质的项目」,允许重叠。 + // 例如 subframe 和 mainframe 创建了相同的 menu item,显示时只会出现一个。 + // 但点击后,两边都会执行。 + // 目的是整理显示,实际上内部还是存有多笔 entry(分别记录不同的 frameId 和 id)。 + const groupKey = uuidv5( + message.options?.inputType + ? JSON.stringify({ ...message.options, autoClose: undefined, id: undefined, name: name }) + : `${name}\n${message.options?.accessKey || ""}`, + groupKeyNS + ); + const menu = menus.find((item) => item.key === key); + if (!menu) { + // 不存在新增 + menus.push({ + groupKey, + key: key, // unique primary key + name: name, + options: message.options, + tabId: tabId, // fix + frameId: message.frameId, // fix with unique key + documentId: message.documentId, // fix with unique key + }); + } else { + // 存在修改信息 + menu.name = message.name; + menu.options = message.options; + menu.groupKey = groupKey; + } + } else if (listEntry.registerType === ScriptMenuRegisterType.UNREGISTER) { + const { uuid, key } = listEntry; + const script = scripts.get(uuid); + if (!script) continue; + const menus = script.menus; + // 删除菜单 + const index = menus.findIndex((item) => item.key === key); + if (index >= 0) { + retUpdated.add(uuid); + menus.splice(index, 1); } } } list.length = 0; - this.updateMenuCommands.delete(mrKey); - return retUpdated; + this.updateMenuCommands.delete(tabId); + return [...retUpdated]; } updateRegisterMenuCommand( message: TScriptMenuRegister | TScriptMenuUnregister, registerType: ScriptMenuRegisterType ): Promise { - const { tabId, uuid } = message; - const mrKey = `${tabId}.${uuid}`; - let list = this.updateMenuCommands.get(mrKey); + const { tabId } = message; + let list = this.updateMenuCommands.get(tabId); if (!list) { - this.updateMenuCommands.set(mrKey, (list = [])); + this.updateMenuCommands.set(tabId, (list = [])); } list.push({ ...message, registerType }); - let retUpdated = false; + let retUpdated: string[] | undefined; return Promise.resolve() // 增加一个 await Promise.reslove() 转移微任务队列 再判断长度是否为0 .then(() => { if (list.length) { return this.txUpdateScriptMenu(tabId, (data) => { - retUpdated = this.updateMenuCommand(tabId, uuid, data, mrKey); + retUpdated = this.updateMenuCommand(tabId, data); return data; }); } }) .then(() => { - if (retUpdated) { - this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); + if (retUpdated?.length) { + for (const uuid of retUpdated) { + this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); + } // 更新数据后再更新菜单 this.updateScriptMenu(tabId); } From da055232506d4235d3be2ea45f424761a9f66ccb Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Fri, 10 Oct 2025 19:16:21 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=E5=87=8F=E5=B0=91=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E4=BC=A0=E6=92=AD=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 4 +- src/app/service/service_worker/types.ts | 2 +- src/pages/popup/App.tsx | 70 +++++++++++++------------ 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index 3df079304..c7aa390ae 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -266,9 +266,7 @@ export class PopupService { }) .then(() => { if (retUpdated?.length) { - for (const uuid of retUpdated) { - this.mq.publish("popupMenuRecordUpdated", { tabId, uuid }); - } + this.mq.publish("popupMenuRecordUpdated", { tabId, uuids: retUpdated }); // 更新数据后再更新菜单 this.updateScriptMenu(tabId); } diff --git a/src/app/service/service_worker/types.ts b/src/app/service/service_worker/types.ts index c1cf18c81..cd8ece403 100644 --- a/src/app/service/service_worker/types.ts +++ b/src/app/service/service_worker/types.ts @@ -253,4 +253,4 @@ export type TBatchUpdateListAction = }[]; }; -export type TPopupScript = { tabId: number; uuid: string }; +export type TPopupScript = { tabId: number; uuids: string[] }; diff --git a/src/pages/popup/App.tsx b/src/pages/popup/App.tsx index 46a8ff421..fe07ce9a3 100644 --- a/src/pages/popup/App.tsx +++ b/src/pages/popup/App.tsx @@ -102,44 +102,46 @@ function App() { ); }), - subscribeMessage("popupMenuRecordUpdated", ({ tabId, uuid }: TPopupScript) => { - // 仅处理当前页签(tab)的菜单更新,其他页签的变更忽略 - if (pageTabIdRef.current !== tabId) return; - let url: string = ""; - // 透过 setState 回呼取得最新的 currentUrl(避免闭包读到旧值) - setCurrentUrl((v) => { - url = v || ""; - return v; - }); - if (!url) return; - popupClient.getPopupData({ url, tabId }).then((resp) => { - if (!isMounted) return; + subscribeMessage("popupMenuRecordUpdated", ({ tabId, uuids }: TPopupScript) => { + for (const uuid of uuids) { + // 仅处理当前页签(tab)的菜单更新,其他页签的变更忽略 + if (pageTabIdRef.current !== tabId) return; + let url: string = ""; + // 透过 setState 回呼取得最新的 currentUrl(避免闭包读到旧值) + setCurrentUrl((v) => { + url = v || ""; + return v; + }); + if (!url) return; + popupClient.getPopupData({ url, tabId }).then((resp) => { + if (!isMounted) return; - // 响应健全性检查:必须包含 scriptList,否则忽略此次更新 - if (!resp || !resp.scriptList) { - console.warn("Invalid popup data response:", resp); - return; - } + // 响应健全性检查:必须包含 scriptList,否则忽略此次更新 + if (!resp || !resp.scriptList) { + console.warn("Invalid popup data response:", resp); + return; + } - // 仅抽取该 uuid 最新的 menus;仅更新 menus 栏位以维持其他属性的引用稳定 - const newMenus = resp.scriptList.find((item) => item.uuid === uuid)?.menus; - if (!newMenus) return; - setScriptList((prev) => { - // 只针对 uuid 进行更新。其他项目保持参考一致 - const list = prev.map((item) => { - return item.uuid !== uuid - ? item - : { - ...item, - menus: [...newMenus], - menuUpdated: Date.now(), - }; + // 仅抽取该 uuid 最新的 menus;仅更新 menus 栏位以维持其他属性的引用稳定 + const newMenus = resp.scriptList.find((item) => item.uuid === uuid)?.menus; + if (!newMenus) return; + setScriptList((prev) => { + // 只针对 uuid 进行更新。其他项目保持参考一致 + const list = prev.map((item) => { + return item.uuid !== uuid + ? item + : { + ...item, + menus: [...newMenus], + menuUpdated: Date.now(), + }; + }); + // 若 menus 数量变动,可能影响排序结果,因此需重新 sort + list.sort(scriptListSorter); + return list; }); - // 若 menus 数量变动,可能影响排序结果,因此需重新 sort - list.sort(scriptListSorter); - return list; }); - }); + } }), ]; From 4e26b385b64bf42ac0ec3c254d3b153308c7321b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Fri, 10 Oct 2025 21:11:08 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/popup.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/app/service/service_worker/popup.ts b/src/app/service/service_worker/popup.ts index c7aa390ae..da96b49bc 100644 --- a/src/app/service/service_worker/popup.ts +++ b/src/app/service/service_worker/popup.ts @@ -181,6 +181,7 @@ export class PopupService { updateMenuCommands = new Map(); isUpdateMenuDirty = false; + // 此函数必须是同步执行的,避免updateMenuCommands并发问题 updateMenuCommand(tabId: number, data: ScriptMenu[]): string[] { const retUpdated = new Set(); const list = this.updateMenuCommands.get(tabId); @@ -188,13 +189,13 @@ export class PopupService { const uuids = new Set(list.map((entry) => entry.uuid)); const scripts = new Map(data.filter((item) => uuids.has(item.uuid)).map((item) => [item.uuid, item])); for (const listEntry of list) { - if (listEntry.registerType === ScriptMenuRegisterType.REGISTER) { - const message = listEntry as TScriptMenuRegister; + const message = listEntry as TScriptMenuRegister; + // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 + const { uuid, key, name } = message; + const script = scripts.get(uuid); + if (!script) continue; - // message.key是唯一的。 即使在同一tab里的mainframe subframe也是不一样 - const { key, name } = message; // 唯一键, 项目显示名字, 脚本uuid - const script = scripts.get(message.uuid); - if (!script) continue; + if (listEntry.registerType === ScriptMenuRegisterType.REGISTER) { const menus = script.menus; retUpdated.add(script.uuid); // 以 options+name 生成稳定 groupKey:相同语义项目在 UI 只呈现一次,但可同时触发多个来源(frame)。 @@ -227,9 +228,6 @@ export class PopupService { menu.groupKey = groupKey; } } else if (listEntry.registerType === ScriptMenuRegisterType.UNREGISTER) { - const { uuid, key } = listEntry; - const script = scripts.get(uuid); - if (!script) continue; const menus = script.menus; // 删除菜单 const index = menus.findIndex((item) => item.key === key);