1+ export { }
2+
3+ type CheckResult = { ok : boolean ; details : string }
4+ // 判定する関数
5+ function checkAnswer ( ) : CheckResult {
6+ const el = document . querySelector < HTMLElement > ( '[data-check]' )
7+ if ( ! el ) return { ok : false , details : 'data-check 要素が見つかりません' }
8+ const expected = el . getAttribute ( 'data-check' ) ?? ''
9+ const actual = ( el . textContent ?? '' ) . trim ( )
10+ return actual === expected
11+ ? { ok : true , details : `一致: "${ actual } "` }
12+ : { ok : false , details : `不一致: expected="${ expected } ", actual="${ actual } "` }
13+ }
14+
15+ // デバウンス
16+ const debounce = < T extends ( ...a : any [ ] ) => void > ( fn : T , delay : number ) => {
17+ let t : number | undefined // タイマーの識別子
18+ return ( ...args : Parameters < T > ) => {
19+ if ( t ) clearTimeout ( t )
20+ // @ts -ignore
21+ t = setTimeout ( ( ) => fn ( ...args ) , delay ) as unknown as number
22+ }
23+ }
24+
25+ const ports = new Set < chrome . runtime . Port > ( )
26+
27+ // サイドパネルからの Port 接続のみ対応
28+ chrome . runtime . onConnect . addListener ( ( port ) => {
29+ if ( port . name !== 'sidepanel' ) return
30+ ports . add ( port )
31+ // 接続直後に最新判定を送る
32+ port . postMessage ( { type : 'UPDATE' , result : checkAnswer ( ) } )
33+ port . onDisconnect . addListener ( ( ) => ports . delete ( port ) )
34+ } )
35+ // DevTools等でのDOM変更を監視し、判定結果をサイドパネルへ通知
36+ const notify = debounce ( ( ) => {
37+ const result = checkAnswer ( )
38+ for ( const p of ports ) {
39+ try { p . postMessage ( { type : 'UPDATE' , result } ) } catch { }
40+ }
41+ } , 200 ) // 200ms ディレイ
42+
43+ const mo = new MutationObserver ( ( ) => notify ( ) )
44+ mo . observe ( document . documentElement , {
45+ childList : true ,
46+ subtree : true ,
47+ characterData : true ,
48+ attributes : true ,
49+ } )
0 commit comments