From cdd1d6ac9f718f2044625c40f83891cdf72231d5 Mon Sep 17 00:00:00 2001 From: Will Date: Sat, 14 Jun 2025 19:46:38 -0400 Subject: [PATCH] Liyourong added pop-up window feature to Tina-Pop-Up --- .DS_Store | Bin 0 -> 6148 bytes chrome-extension/js/background.js | 87 +++++++++++++++++++++++++++++- chrome-extension/js/panel.js | 38 +++++++++++++ chrome-extension/js/popup.js | 62 +++++++++++++++++++++ chrome-extension/manifest.json | 7 +++ chrome-extension/popup.html | 71 ++++++++++++++++++++++++ 6 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 .DS_Store create mode 100644 chrome-extension/js/popup.js create mode 100644 chrome-extension/popup.html diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 { popupPort = null; }); + + chrome.tabs.query({ active: true, lastFocusedWindow: true }, tabs => { + const tid = tabs[0]?.id; + console.log(`🔍 [BG→popup] popup connected, querying history for tabId =`, tid, + 'history length =', (eventHistoryMap[tid] || []).length); + if (tid != null) { + (eventHistoryMap[tid] || []).forEach((ev, i) => { + console.log(` → event[${i}] =`, ev); + popupPort.postMessage({ type: 'event', event: ev }); + }); + popupPort.postMessage({ + type: 'recording-state', + tabId: tid, + recording: !!recordingStateMap[tid] + }); + } + }); + + port.onMessage.addListener(msg => { + const { type, tabId, desc } = msg; + + // —— 1) 拉回历史 + if (type === 'get-history' && typeof tabId === 'number') { + const history = eventHistoryMap[tabId] || []; + history.forEach(ev => popupPort.postMessage({ type: 'event', event: ev })); + return; + } + + // —— 2) 拉回当前录制状态 + if (type === 'get-recording-state' && typeof tabId === 'number') { + const isRec = !!recordingStateMap[tabId]; + popupPort.postMessage({ type: 'recording-state', tabId, recording: isRec }); + return; + } + + // —— 3) popup 发来的开始/停止录制命令 + if (type === 'start-record' && typeof tabId === 'number') { + const p = devToolsPorts[tabId]; + if (p) p.postMessage({ type: 'popup-start', desc }); + return; + } + if (type === 'stop-record' && typeof tabId === 'number') { + const p = devToolsPorts[tabId]; + if (p) p.postMessage({ type: 'popup-stop' }); + return; + } + }); + } }); var devToolsPorts = {}; @@ -149,7 +205,20 @@ console.log('[OTA DOM Background]: Script injected successfully', injectionResults); } }); - } else { + } + else if (message.type === 'panel-record-started') { + recordingStateMap[tabId] = true; + if (popupPort) { + popupPort.postMessage({ type: 'recording-state', tabId, recording: true }); + } + } + else if (message.type === 'panel-record-stopped') { + recordingStateMap[tabId] = false; + if (popupPort) { + popupPort.postMessage({ type: 'recording-state', tabId, recording: false }); + } + } + else { //pass message from DevTools panel to a content script if (contentScriptPorts[tabId]) { contentScriptPorts[tabId].postMessage(message); @@ -175,9 +244,22 @@ console.log('[OTA DOM Background]: content script status: ', message.type, ', tab ID: ', tabId); //pass message from content script to the appropriate DevTools panel + if (message.type === 'event') { //如果有信息就缓存起来,到时候给popup发 + if (!eventHistoryMap[tabId]) eventHistoryMap[tabId] = []; + eventHistoryMap[tabId].push(message.event); + console.log( + `🔍 [BG] eventHistoryMap[${tabId}].length =`, + eventHistoryMap[tabId].length + ); + }else{ + console.log('[BG] NOT caching type=', message.type); + } if (devToolsPorts[tabId]) { devToolsPorts[tabId].postMessage(message); } + if (popupPort) { + popupPort.postMessage(message); + } }; port.onMessage.addListener(messageListener); @@ -191,6 +273,9 @@ type: 'disconnected' }); } + if (popupPort) { + popupPort.postMessage({ type: 'disconnected' }); + } }); } diff --git a/chrome-extension/js/panel.js b/chrome-extension/js/panel.js index 482e68e..cc3e8da 100644 --- a/chrome-extension/js/panel.js +++ b/chrome-extension/js/panel.js @@ -155,6 +155,8 @@ taskVisibilityBtn.innerText = 'Hide Task'; taskSection.style.display = 'block'; // Task visible by default + sendToBG({ type: 'panel-record-started' }); + /* Optional intro fade-out (unchanged) */ if (intro.style.display !== 'none') { intro.animate([{ opacity: 1 }, { opacity: 0 }], 300) @@ -185,6 +187,8 @@ eventTable.clear(); + sendToBG({ type: 'panel-record-stopped' }); + /* Optional intro fade-out (unchanged) */ intro.style.display = 'block'; // make it visible immediately intro.style.opacity = 0; // start transparent @@ -384,6 +388,40 @@ eventTable.clear(); break; + + case 'popup-start': { + // 来自 popup 的开始录制 + const desc = message.desc; + // 复用 recordBtnHandler 里的 Start 流程(不重复 UI 逻辑) + ContentScriptProxy.startRecording(desc); + // 更新面板 UI + showLabel(desc); + recordBtn.innerText = 'Finish Record'; + pauseResumeBtn.disabled = false; + recording = true; + // 请求并显示 taskId + setTimeout(() => getCurrentTaskId(), 1000); + // 通知 background “面板已开始” + sendToBG({ type: 'panel-record-started' }); + break; + } + + case 'popup-stop': { + // 来自 popup 的停止录制 + ContentScriptProxy.finishRecording(); + // 恢复面板 UI + showInput(true); + recordBtn.innerText = 'Start Record'; + pauseResumeBtn.disabled = true; + taskVisibilityBtn.hidden = true; + eventTable.clear(); + recording = false; + // 通知 background “面板已停止” + sendToBG({ type: 'panel-record-stopped' }); + break; + } + + /* you may add more cases as needed */ default: diff --git a/chrome-extension/js/popup.js b/chrome-extension/js/popup.js new file mode 100644 index 0000000..c3dd748 --- /dev/null +++ b/chrome-extension/js/popup.js @@ -0,0 +1,62 @@ +(function(){ + "use strict"; + + // —— UI 绑定 —— + const clearBtn = document.querySelector('.clear'); + const recordBtn = document.querySelector('.record-btn'); + const descInput = document.querySelector('.task-desc-input'); + const table = document.querySelector('.events'); + const eventTable = new EventTable(table); + + let currentTabId, recording = false; + + // —— 建立和 background 的长连接 —— + const port = chrome.runtime.connect({ name: 'popup' }); + port.onMessage.addListener(msg => { + console.log('📝 popup received message:', msg); + const { tabId, event, recording: isRec } = msg; + //if (tabId !== currentTabId) return; + + // —— 只要有 event 对象,就渲染它 —— + if (event) { + eventTable.addEvent(event); + const rowCount = document.querySelector('.events tbody').children.length; + console.log(`📝 popup: tbody now has ${rowCount} rows`); + return; + } + + // —— 同步录制状态 —— + if (msg.type === 'recording-state') { + recording = isRec; + recordBtn.innerText = recording ? 'Stop Record' : 'Start Record'; + descInput.disabled = recording; + } + }); + + // —— 一打开就抓 tabId —— + chrome.tabs.query({ active: true, currentWindow: true }, tabs => { + currentTabId = tabs[0].id; + }); + + // —— 清空表格 —— + clearBtn.addEventListener('click', () => { + eventTable.clear(); + }); + + // —— 开始/停止录制 —— + recordBtn.addEventListener('click', () => { + const desc = descInput.value.trim(); + console.log('📝 popup click recordBtn, recording=', recording, 'desc=', desc); + + if (!recording) { + if (!desc) { + console.warn('⚠️ popup: empty description, abort start-record'); + descInput.classList.add('invalid'); + return; + } + port.postMessage({ type: 'start-record', tabId: currentTabId, desc }); + } else { + port.postMessage({ type: 'stop-record', tabId: currentTabId }); + } + }); +})(); diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json index 11962f9..50f0f40 100644 --- a/chrome-extension/manifest.json +++ b/chrome-extension/manifest.json @@ -22,6 +22,13 @@ "devtools_page": "devtools.html", "content_security_policy": { "extension_pages": "script-src 'self'; object-src 'self'" + }, + "action": { + "default_icon": { + "128": "ico/ota-logo-128.png", + "48": "ico/ota-logo-48.png" + }, + "default_popup": "popup.html" } } \ No newline at end of file diff --git a/chrome-extension/popup.html b/chrome-extension/popup.html new file mode 100644 index 0000000..f5b1af9 --- /dev/null +++ b/chrome-extension/popup.html @@ -0,0 +1,71 @@ + + + + + + OTA Events + + + + + + + + +
+ + + + + + + + + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ Event (0) +
+ + Target + Details
+ +
+ + + + +