@@ -276,8 +276,31 @@ function sendMessageToTab(tabId, message) {
276276 try {
277277 chrome . tabs . sendMessage ( tabId , message , ( response ) => {
278278 if ( chrome . runtime . lastError ) {
279- console . error ( `Error sending message to tab ${ tabId } :` , chrome . runtime . lastError . message || 'Unknown error' ) ;
280- reject ( new Error ( chrome . runtime . lastError . message || 'Error communicating with tab' ) ) ;
279+ const msg = chrome . runtime . lastError . message || 'Unknown error' ;
280+ // Attempt one-time dynamic injection if content script missing
281+ if ( msg . includes ( 'Could not establish connection. Receiving end does not exist' ) ) {
282+ console . warn ( 'Content script not found in tab ' + tabId + ', attempting dynamic injection...' ) ;
283+ // Try injecting JS and CSS then resend once
284+ Promise . all ( [
285+ chrome . scripting . insertCSS ( { target : { tabId } , files : [ 'content.css' ] } ) . catch ( ( ) => { } ) ,
286+ chrome . scripting . executeScript ( { target : { tabId } , files : [ 'content.js' ] } )
287+ ] ) . then ( ( ) => {
288+ chrome . tabs . sendMessage ( tabId , message , ( secondResp ) => {
289+ if ( chrome . runtime . lastError ) {
290+ console . error ( 'Retry after injection failed:' , chrome . runtime . lastError . message ) ;
291+ reject ( new Error ( chrome . runtime . lastError . message ) ) ;
292+ } else {
293+ resolve ( secondResp ) ;
294+ }
295+ } ) ;
296+ } ) . catch ( injectErr => {
297+ console . error ( 'Dynamic injection failed:' , injectErr ) ;
298+ reject ( new Error ( msg ) ) ;
299+ } ) ;
300+ } else {
301+ console . error ( `Error sending message to tab ${ tabId } :` , msg ) ;
302+ reject ( new Error ( msg ) ) ;
303+ }
281304 } else {
282305 resolve ( response ) ;
283306 }
@@ -289,6 +312,26 @@ function sendMessageToTab(tabId, message) {
289312 } ) ;
290313}
291314
315+ // Ensure content script is present in tab before messaging heavy workflow
316+ async function ensureContentScript ( tabId ) {
317+ try {
318+ await sendMessageToTab ( tabId , { action : 'ping' } ) ; // cheap test
319+ return true ; // already there
320+ } catch ( e ) {
321+ // Attempt injection
322+ try {
323+ await chrome . scripting . insertCSS ( { target : { tabId } , files : [ 'content.css' ] } ) . catch ( ( ) => { } ) ;
324+ await chrome . scripting . executeScript ( { target : { tabId } , files : [ 'content.js' ] } ) ;
325+ // Small delay to allow script init
326+ await new Promise ( r => setTimeout ( r , 50 ) ) ;
327+ return true ;
328+ } catch ( injErr ) {
329+ console . error ( 'ensureContentScript failed injection:' , injErr ) ;
330+ return false ;
331+ }
332+ }
333+ }
334+
292335// Create a term frequency map for the text
293336function createTextVector ( text ) {
294337 // Normalize text: lowercase, remove punctuation, split into words
@@ -534,9 +577,22 @@ async function processLicenseCheck(selectedText) {
534577 activeScans . add ( originTabId ) ;
535578
536579 try {
537- // Show UI and clear previous results
538- await sendMessageToTab ( originTabId , { action : 'showUI' } ) ;
539- await sendMessageToTab ( originTabId , { action : 'clearResults' } ) ;
580+ // Make sure content script is available
581+ const ready = await ensureContentScript ( originTabId ) ;
582+ if ( ! ready ) {
583+ console . error ( 'Content script not available after injection attempts.' ) ;
584+ return ;
585+ }
586+ // Show UI and clear previous results with retry
587+ for ( const m of [ 'showUI' , 'clearResults' ] ) {
588+ try {
589+ await sendMessageToTab ( originTabId , { action : m } ) ;
590+ } catch ( msgErr ) {
591+ console . warn ( 'Retrying message' , m , 'after brief delay due to' , msgErr . message ) ;
592+ await new Promise ( r => setTimeout ( r , 100 ) ) ;
593+ await sendMessageToTab ( originTabId , { action : m } ) ;
594+ }
595+ }
540596
541597 // Progress callback for reporting scan progress
542598 const sendProgress = async ( progress ) => {
@@ -1013,20 +1069,56 @@ function sendProgressUpdate(progress, message, complete = false) {
10131069// Update the action click handler to ensure connection before execution
10141070chrome . action . onClicked . addListener ( async ( tab ) => {
10151071 try {
1016- // Make sure we're on a supported page
10171072 const url = tab . url || '' ;
1018- if ( url . startsWith ( 'chrome://' ) || url . startsWith ( 'chrome-extension://' ) ||
1073+ if ( url . startsWith ( 'chrome://' ) || url . startsWith ( 'chrome-extension://' ) ||
10191074 url . startsWith ( 'about:' ) || url . startsWith ( 'edge://' ) ) {
10201075 console . warn ( 'Cannot run on this page type:' , url ) ;
10211076 return ;
10221077 }
1023-
1078+
1079+ // Collect selection info from all accessible frames (longest selection wins)
10241080 chrome . scripting . executeScript ( {
1025- target : { tabId : tab . id } ,
1026- function : checkedLicenses
1081+ target : { tabId : tab . id , allFrames : true } ,
1082+ func : ( ) => {
1083+ try {
1084+ const sel = window . getSelection ( ) ;
1085+ if ( sel && sel . toString ( ) . trim ( ) ) {
1086+ return {
1087+ text : sel . toString ( ) ,
1088+ inIframe : window . top !== window ,
1089+ frameUrl : location . href
1090+ } ;
1091+ }
1092+ } catch ( e ) {
1093+ // ignore frame errors
1094+ }
1095+ return null ;
1096+ }
1097+ } ) . then ( results => {
1098+ if ( ! results || ! Array . isArray ( results ) ) {
1099+ showNotification ( tab . id , 'No selection found.' , 'warning' ) ;
1100+ return ;
1101+ }
1102+ // Pick longest non-null selection
1103+ const candidates = results . map ( r => r . result ) . filter ( r => r && r . text && r . text . trim ( ) ) ;
1104+ if ( candidates . length === 0 ) {
1105+ showNotification ( tab . id , 'Please select text before running license check.' , 'warning' ) ;
1106+ return ;
1107+ }
1108+ const best = candidates . reduce ( ( a , b ) => ( b . text . length > a . text . length ? b : a ) ) ;
1109+
1110+ // Send single message to existing handler (adds iframe metadata for future use)
1111+ // Directly initiate processing instead of round-trip messaging
1112+ originTabId = tab . id ;
1113+ // Ensure content script/UI is present before processing (attempt a lightweight showUI message)
1114+ sendMessageToTab ( tab . id , { action : 'showUI' } )
1115+ . catch ( ( ) => Promise . resolve ( ) ) // ignore; injection fallback happens in sendMessageToTab
1116+ . finally ( ( ) => {
1117+ processLicenseCheck ( best . text ) ;
1118+ } ) ;
10271119 } ) . catch ( err => {
1028- console . error ( 'Script execution error:' , err ) ;
1029- showNotification ( tab . id , " Error executing script: " + ( err . message || " Unknown error" ) , " error" ) ;
1120+ console . error ( 'Selection collection error:' , err ) ;
1121+ showNotification ( tab . id , ' Error gathering selection: ' + ( err . message || ' Unknown error' ) , ' error' ) ;
10301122 } ) ;
10311123 } catch ( err ) {
10321124 console . error ( 'Error handling action click:' , err ) ;
0 commit comments