1// search.js - Enhanced comprehensive search functionality for support pages 2 3// This object contains searchable content from all support pages 4// Format: { 'page-url.html': { title: 'Page Title', description: 'Page description', content: 'Searchable content...' } } 5const searchIndex = { 6 'index.html': { 7 title: 'Support Center', 8 description: 'Find answers, guides, and resources to help you get the most out of Tailorly', 9 content: 'Find answers, guides, and resources to help you get the most out of Tailorly. Browse our most frequently accessed guides and tutorials. Getting Started Guide, How to Save Your Resume, Extracting Job Descriptions, Troubleshooting, ATS Optimization Tips, Contact Support.' 10 }, 11 'how-to-use.html': { 12 title: 'How to Use Tailorly', 13 description: 'A comprehensive guide to getting started and maximizing your results', 14 content: 'A comprehensive guide to getting started and maximizing your results. Tailorly is designed to be intuitive and easy to use, helping you optimize your resume for any job application in just seconds. This guide will walk you through the entire process from installation to applying with your tailored resume. Install the Browser Extension, Create Your Account, Upload Your Base Resume, Tailor Your Resume for a Job, Review and Download Your Tailored Resume, ATS Compatibility Score, Keyword Optimization, Cover Letter Generation, Pro Feature, Troubleshooting Common Issues.' 15 }, 16 'save-resume.html': { 17 title: 'How to Save Your Resume', 18 description: 'Learn how to save, manage, and organize multiple versions of your tailored resumes', 19 content: 'Learn how to save, manage, and organize multiple versions of your tailored resumes. This guide covers saving your resume to your account, downloading different file formats, organizing your saved resumes, and accessing your resume history. Tailorly makes it easy to keep track of all your tailored resumes for different job applications. Save to Your Tailorly Account, Download Your Resume in Different Formats, Managing Your Saved Resumes, Accessing Your Resume Library, Organizing Your Resumes, Resume Version History, Sharing Your Resume, Creating Shareable Links, Backup and Recovery.' 20 }, 21 'extract-job-description.html': { 22 title: 'Extracting Job Descriptions', 23 description: '3 ways to automatically extract job descriptions for our extension from any job site', 24 content: '3 ways to automatically extract job descriptions for our extension from any job site. Learn how to use the automatic extraction feature, manual copy-paste method, and URL sharing. This guide helps you efficiently capture job descriptions from LinkedIn, Indeed, Glassdoor, and company career pages to optimize your resume with Tailorly. Job Site Compatibility, Automatic Extraction, Manual Copy-Paste, URL Sharing Method, Troubleshooting Extraction Issues, Job Description Not Detected, Extracted Description Is Incomplete, Extraction Works But Analysis Fails, Extracting from Unusual Sources, PDF Job Descriptions, Email Job Descriptions, Protected Job Boards.' 25 }, 26 'troubleshooting.html': { 27 title: 'Troubleshooting', 28 description: 'Solutions to common issues and problems you might encounter while using Tailorly', 29 content: 'Solutions to common issues and problems you might encounter while using Tailorly. This guide covers installation problems, resume parsing errors, job description detection issues, account access problems, and subscription management. Find quick fixes and step-by-step solutions to get back on track with your job applications. Installation Issues, Can\'t Install the Browser Extension, Extension Installed But Not Working, Resume Parsing Issues, Resume Not Parsing Correctly, Job Description Issues, Job Description Not Detected, Account and Subscription Issues, Can\'t Log In to My Account, Subscription Issues, Performance Issues, Resume Optimization Is Slow.' 30 }, 31 'cancellationandrefunds.html': { 32 title: 'Cancellation and Refunds', 33 description: 'Understand Tailorlyâs cancellation and refunds policy, outage credits, and how to request help.', 34 content: 'We do not offer cancellations or refunds mid-billing period. Try the free plan first. In certain verified cases such as service outages or confirmed extension malfunctions that prevent core use, we may provide remedies like subscription extensions or additional credits. This policy covers exceptions, what is not covered, and how to request help. Eligible situations: Verified service outage, Extension not functioning as intended after troubleshooting. Remedies: add credits, extend subscription. No refunds for change of mind or partial periods. Contact support with browser, OS, reproduction steps, screenshots, timestamps.' 35 }, 36 'products.html': { 37 title: 'Products (Shipping and Access)', 38 description: 'Tailorly is a digital, subscription-based Chrome extension. No physical shipping. Access continues while subscribed.', 39 content: 'Tailorly is an online product and Chrome extension. No physical items are shipped. Access begins after account creation and continues while your subscription is active. Free plan available to try before upgrading. For refunds, credits, or outage remedies, see
39Cancellation and Refunds. Getting started: install extension, create account, use free plan or upgrade.' 40 }, 41 'ats-optimization.html': { 42 title: 'ATS Optimization Tips', 43 description: 'Learn how to maximize your resume\'s compatibility with Applicant Tracking Systems', 44 content: 'Learn how to maximize your resume\'s compatibility with Applicant Tracking Systems. This guide explains how ATS systems work, key formatting guidelines, optimal keyword usage, section organization, and how to test your resume against common ATS platforms. Follow these tips to ensure your resume passes through ATS filters and reaches human recruiters. Understanding ATS Systems, ATS Compatibility Score, Key Formatting Guidelines for ATS, Keyword Optimization Strategies, Identify Relevant Keywords, Use Keywords Naturally, Include Both Acronyms and Full Terms, Create a Skills Section, Resume Section Organization, Contact Information, Professional Summary/Objective, Work Experience, Education, Skills, Additional Sections, Testing Your Resume Against ATS, Common ATS Myths Debunked, Final Tips for ATS Success.' 45 }, 46 'shippingpolicy.html': { 47 title: 'Shipping and Product Policies', 48 description: 'Tailorly is a digital, subscription-based Chrome extension. No physical shipping. Access continues while subscribed.', 49 content: 'Tailorly is an online product and Chrome extension. No physical items are shipped. Access begins after account creation and continues while your subscription is active. Free plan available to try before upgrading. For refunds, credits, or outage remedies, see Cancellation and Refunds. Getting started: install extension, create account, use free plan or upgrade.' 50 } 51}; 52 53// Function to normalize text for searching (remove extra spaces, lowercase) 54function normalizeText(text) { 55 return text.toLowerCase().replace(/\s+/g, ' ').trim(); 56} 57 58// Function to perform search across all pages 59function performSearch(query) { 60 const normalizedQuery = normalizeText(query); 61 62 // If search is empty, return empty results 63 if (normalizedQuery === '') { 64 return []; 65 } 66 67 const results = []; 68 69 // Search through the index 70 for (const [url, pageData] of Object.entries(searchIndex)) { 71 const normalizedTitle = normalizeText(pageData.title); 72 const normalizedDescription = normalizeText(pageData.description); 73 const normalizedContent = normalizeText(pageData.content); 74 75 // Check if query appears in title, description or content 76 if (normalizedTitle.includes(normalizedQuery) || 77 normalizedDescription.includes(normalizedQuery) || 78 normalizedContent.includes(normalizedQuery)) { 79 80 // Calculate relevance score (higher for title matches, then description, then content) 81 let score = 0; 82 let matchType = ''; 83 let snippet = ''; 84 85 // Title matches get highest score 86 if (normalizedTitle.includes(normalizedQuery)) { 87 score += 100; 88 matchType = 'title'; 89 // Bonus points for exact title match 90 if (normalizedTitle === normalizedQuery) { 91 score += 50; 92 } 93 snippet = pageData.description; // Use description as snippet for title matches 94 } 95 96 // Description matches get medium score 97 if (normalizedDescription.includes(normalizedQuery)) { 98 score += 75; 99 if (!matchType) { 100 matchType = 'description'; 101 snippet = pageData.description; 102 } 103 } 104 105 // Content matches get lowest score 106 if (normalizedContent.includes(normalizedQuery)) { 107 score += 50; 108 109 if (!matchType) { 110 matchType = 'content'; 111 112 // Find the position of the match to extract a snippet 113 const matchPosition = normalizedContent.indexOf(normalizedQuery); 114 115 // Create a snippet around the match 116 const snippetStart = Math.max(0, matchPosition - 50); 117 const snippetEnd = Math.min(normalizedContent.length, matchPosition + normalizedQuery.length + 50); 118 snippet = normalizedContent.substring(snippetStart, snippetEnd); 119 120 // Add ellipsis if needed 121 if (snippetStart > 0) { 122 snippet = '...' + snippet; 123 } 124 if (snippetEnd < normalizedContent.length) { 125 snippet += '...'; 126 } 127 } 128 } 129 130 // Add result with snippet and score 131 results.push({ 132 url, 133 title: pageData.title, 134 snippet: snippet || normalizedContent.substring(0, 100) + '...', 135 score, 136 matchType 137 }); 138 } 139 } 140 141 // Sort results by relevance score (highest first) 142 results.sort((a, b) => b.score - a.score); 143 144 return results; 145} 146 147// Function to display search results 148function displaySearchResults(results, container) { 149 container.innerHTML = ''; 150 151 if (results.length === 0) { 152 container.innerHTML = ` 153 <div class="search-no-results"> 154 <p>No results found. Please try a different search term.</p> 155 </div> 156 `; 157 return; 158 } 159
160 results.forEach(result => { 161 const resultElement = document.createElement('div'); 162 resultElement.className = 'search-result'; 163 164 // Create badge for match type 165 let badgeHtml = ''; 166 if (result.matchType === 'title') { 167 badgeHtml = '<span class="match-badge title-match">Title Match</span>'; 168 } else if (result.matchType === 'description') { 169 badgeHtml = '<span class="match-badge desc-match">Description Match</span>'; 170 } else { 171 badgeHtml = '<span class="match-badge content-match">Content Match</span>'; 172 } 173 174 resultElement.innerHTML = ` 175 <h3> 176 <a href="${result.url}">${result.title}</a> 177 ${badgeHtml} 178 </h3> 179 <p>${result.snippet}</p> 180 <a href="${result.url}" class="result-link">Read more</a> 181 `; 182 183 container.appendChild(resultElement); 184 }); 185} 186 187// Initialize search when DOM is loaded 188document.addEventListener('DOMContentLoaded', function() { 189 const searchInput = document.getElementById('search-input'); 190 const searchResults = document.getElementById('search-results'); 191 const searchForm = document.getElementById('search-form'); 192 193 if (searchForm) { 194 searchForm.addEventListener('submit', function(e) { 195 e.preventDefault(); 196 const query = searchInput.value; 197 const results = performSearch(query); 198 displaySearchResults(results, searchResults); 199 }); 200 } 201 202 // Add live search functionality 203 if (searchInput) { 204 searchInput.addEventListener('input', function() { 205 const query = this.value; 206 if (query.length >= 2) { // Only search for queries with 2+ characters 207 const results = performSearch(query); 208 displaySearchResults(results, searchResults); 209 } else if (query.length === 0) { 210 searchResults.innerHTML = ''; // Clear results when search is empty 211 } 212 }); 213 } 214 215 // Check for URL parameters to handle searches from other pages 216 const urlParams = new URLSearchParams(window.location.search); 217 const queryParam = urlParams.get('q'); 218 if (queryParam && searchInput && searchResults) { 219 searchInput.value = queryParam; 220 const results = performSearch(queryParam); 221 displaySearchResults(results, searchResults); 222 } 223});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.