diff --git a/content.js b/content.js index 9859255..f5f7838 100644 --- a/content.js +++ b/content.js @@ -228,28 +228,76 @@ function extractApplicationQuestions() { const questions = []; - const modal = document.querySelector('.artdeco-modal, .jobs-easy-apply-modal, #artdeco-modal-outlet'); - if (!modal) return questions; - - const labels = modal.querySelectorAll('label, legend'); const seen = new Set(); - labels.forEach(label => { - let text = label.textContent.replace(/\*/g, '').replace(/Submit/i, '').trim(); - if (text && text.length > 5 && text.length < 200 && !seen.has(text)) { - seen.add(text); + // Strategy 1: Look inside known modal containers + const containers = document.querySelectorAll( + '.artdeco-modal, .jobs-easy-apply-modal, #artdeco-modal-outlet, ' + + '.jobs-easy-apply-content, .jobs-easy-apply-form-section__grouping, ' + + '[data-test-modal], [role="dialog"]' + ); + + // Strategy 2: If no modal found, scan the full page + const searchRoots = containers.length > 0 ? containers : [document.body]; + + searchRoots.forEach(container => { + // Scan labels, legends, spans that look like question text + const candidates = container.querySelectorAll( + 'label, legend, .fb-dash-form-element__label, ' + + '.jobs-easy-apply-form-element__label, ' + + 'span.t-14, span.t-bold' + ); + + candidates.forEach(el => { + let text = el.textContent.replace(/\*/g, '').replace(/required/gi, '').trim(); + // Remove "Select an option" and similar noise + text = text.replace(/Select an option/gi, '').replace(/Show less|Show more/gi, '').trim(); + + if (!text || text.length < 8 || text.length > 300 || seen.has(text.toLowerCase())) return; + // Only accept text that looks like a question or form label + const isQuestion = ( + text.endsWith('?') || + /^(how many|what|do you|are you|have you|will you|can you|would you|is your|describe|tell us)/i.test(text) || + /salary|experience|education|degree|visa|relocat|notice period|start date|certif/i.test(text) + ); + + if (!isQuestion) return; + + seen.add(text.toLowerCase()); + + // Detect input type from nearest form element let inputType = 'text'; - const parent = label.closest('div') || label.parentElement; - if (parent.querySelector('select')) inputType = 'select'; - else if (parent.querySelector('input[type="radio"]')) inputType = 'radio'; - else if (parent.querySelector('textarea')) inputType = 'textarea'; - else if (parent.querySelector('input[type="checkbox"]')) inputType = 'checkbox'; + const parent = el.closest('.fb-dash-form-element, .jobs-easy-apply-form-section__grouping, div') || el.parentElement; + if (parent) { + if (parent.querySelector('select')) inputType = 'select'; + else if (parent.querySelector('input[type="radio"]')) inputType = 'radio'; + else if (parent.querySelector('textarea')) inputType = 'textarea'; + else if (parent.querySelector('input[type="checkbox"]')) inputType = 'checkbox'; + else if (parent.querySelector('input[type="number"]')) inputType = 'number'; + } questions.push({ question: text, type: inputType }); - } + }); }); + // Strategy 3: Last resort — scan ALL visible text for question patterns + if (questions.length === 0) { + const allSpans = document.querySelectorAll('span, label, legend, p'); + allSpans.forEach(el => { + const text = el.textContent.replace(/\*/g, '').trim(); + if (text && text.endsWith('?') && text.length > 10 && text.length < 200 && !seen.has(text.toLowerCase())) { + // Make sure this is a visible form question, not random page text + const rect = el.getBoundingClientRect(); + if (rect.width > 0 && rect.height > 0 && rect.top > 0 && rect.top < window.innerHeight) { + seen.add(text.toLowerCase()); + questions.push({ question: text, type: 'text' }); + } + } + }); + } + + console.log('[LJA] Scraped questions:', questions); return questions.slice(0, 15); } @@ -586,7 +634,15 @@ const isArabic = /[\u0600-\u06FF]/.test(text); const rtlAttr = isArabic ? 'dir="rtl" style="text-align: right; padding-right: 15px;"' : ''; + // For Q&A, show how many questions were detected + const qaHeader = (tab === 'qa' && jobData.questions) + ? `
+ 🔍 Detected ${jobData.questions.length} question(s) from Easy Apply form +
` + : ''; + pane.innerHTML = ` + ${qaHeader}
${renderMarkdown(text)}
@@ -595,7 +651,7 @@ copyBtn.style.display = 'block'; // Show auto-fill button for Q&A tab - if (tab === 'qa' && jobData.questions.length > 0) { + if (tab === 'qa') { const fillBtn = document.createElement('button'); fillBtn.className = 'lja-fill-btn'; fillBtn.textContent = '📝 Auto-fill Answers'; @@ -804,7 +860,12 @@ Brief honest assessment of this opportunity for my profile` } let filled = 0; - const labels = document.querySelectorAll('.jobs-easy-apply-content label, .jobs-easy-apply-content legend, .jobs-easy-apply-content .fb-dash-form-element__label'); + const labels = document.querySelectorAll( + '.jobs-easy-apply-content label, .jobs-easy-apply-content legend, ' + + '.artdeco-modal label, .artdeco-modal legend, ' + + '[role="dialog"] label, [role="dialog"] legend, ' + + '#artdeco-modal-outlet label, #artdeco-modal-outlet legend' + ); labels.forEach(label => { const qText = label.textContent.trim().toLowerCase();