|
38 | 38 | debounceTimer: null, |
39 | 39 | entryKeys: new Set(), |
40 | 40 | elements: null, |
41 | | - deepIndexingEnabled: false |
| 41 | + deepIndexingEnabled: false, |
| 42 | + indexLoaded: false, |
| 43 | + indexFile: 'search-index.json' |
42 | 44 | }; |
43 | 45 | var domParserInstance = null; |
44 | 46 | var cachedNavFromStorage = null; |
|
703 | 705 | }); |
704 | 706 |
|
705 | 707 | updateSearchFeedback(); |
706 | | - scheduleIndexing(); |
| 708 | + loadSearchIndexFromFile(); |
| 709 | + } |
| 710 | + |
| 711 | + function loadSearchIndexFromFile() { |
| 712 | + if (!searchState.deepIndexingEnabled) { |
| 713 | + searchState.indexLoaded = true; |
| 714 | + scheduleIndexing(); |
| 715 | + return; |
| 716 | + } |
| 717 | + |
| 718 | + fetch(searchState.indexFile) |
| 719 | + .then(function(response) { |
| 720 | + if (!response.ok) { |
| 721 | + throw new Error('Index file not found'); |
| 722 | + } |
| 723 | + return response.json(); |
| 724 | + }) |
| 725 | + .then(function(indexData) { |
| 726 | + if (indexData && indexData.entries && Array.isArray(indexData.entries)) { |
| 727 | + console.log('Search index loaded from file:', indexData.entries.length, 'entries'); |
| 728 | + searchState.extraEntries = indexData.entries; |
| 729 | + searchState.entryKeys.clear(); |
| 730 | + searchState.baseEntries.forEach(function(entry) { |
| 731 | + searchState.entryKeys.add(entryKey(entry)); |
| 732 | + }); |
| 733 | + indexData.entries.forEach(function(entry) { |
| 734 | + searchState.entryKeys.add(entryKey(entry)); |
| 735 | + }); |
| 736 | + searchState.indexLoaded = true; |
| 737 | + searchState.indexing = false; |
| 738 | + updateSearchFeedback(searchState.activeQuery, null); |
| 739 | + if (searchState.activeQuery && searchState.activeQuery.length >= 2) { |
| 740 | + performSearch(searchState.activeQuery); |
| 741 | + } |
| 742 | + } |
| 743 | + }) |
| 744 | + .catch(function(error) { |
| 745 | + console.log('Search index file not found, will build dynamically'); |
| 746 | + searchState.indexLoaded = false; |
| 747 | + scheduleIndexing(); |
| 748 | + }); |
707 | 749 | } |
708 | 750 |
|
709 | 751 | function prepareBaseSearchEntries() { |
|
774 | 816 | return a.entry.title.localeCompare(b.entry.title); |
775 | 817 | }); |
776 | 818 |
|
777 | | - var topResults = matches.slice(0, 50).map(function(item) { |
| 819 | + var topResults = matches.slice(0, 100).map(function(item) { |
778 | 820 | return item.entry; |
779 | 821 | }); |
780 | 822 |
|
781 | 823 | renderSearchResults(topResults, query); |
782 | 824 | } |
783 | 825 |
|
784 | 826 | function evaluateMatch(entry, normalizedQuery) { |
785 | | - if (entry.titleLower === normalizedQuery) { |
| 827 | + var titleLower = entry.titleLower; |
| 828 | + var searchBlob = entry.searchBlob || ''; |
| 829 | + |
| 830 | + // Exact match - highest priority |
| 831 | + if (titleLower === normalizedQuery) { |
786 | 832 | return 0; |
787 | 833 | } |
788 | | - if (entry.titleLower.indexOf(normalizedQuery) === 0) { |
| 834 | + |
| 835 | + // Starts with query - very high priority |
| 836 | + if (titleLower.indexOf(normalizedQuery) === 0) { |
789 | 837 | return 1; |
790 | 838 | } |
791 | | - if (entry.titleLower.indexOf(normalizedQuery) !== -1) { |
| 839 | + |
| 840 | + // Query appears in title - high priority |
| 841 | + var titleIndex = titleLower.indexOf(normalizedQuery); |
| 842 | + if (titleIndex !== -1) { |
792 | 843 | return 2; |
793 | 844 | } |
794 | | - if (entry.searchBlob && entry.searchBlob.indexOf(normalizedQuery) !== -1) { |
795 | | - return 3; |
| 845 | + |
| 846 | + // Check for word boundary matches in title (e.g., "CONTENT" matches "CONTENT_AWARE_FITTING") |
| 847 | + var titleParts = titleLower.split(/[._\s-]+/); |
| 848 | + for (var i = 0; i < titleParts.length; i++) { |
| 849 | + if (titleParts[i] === normalizedQuery) { |
| 850 | + return 2.5; // Between substring match and blob match |
| 851 | + } |
| 852 | + if (titleParts[i].indexOf(normalizedQuery) === 0) { |
| 853 | + return 3; |
| 854 | + } |
| 855 | + } |
| 856 | + |
| 857 | + // Match in search blob (context, description, keywords) - lower priority |
| 858 | + if (searchBlob && searchBlob.indexOf(normalizedQuery) !== -1) { |
| 859 | + return 4; |
| 860 | + } |
| 861 | + |
| 862 | + // Try fuzzy matching for partial words in search blob |
| 863 | + var queryWords = normalizedQuery.split(/\s+/); |
| 864 | + if (queryWords.length > 1 && searchBlob) { |
| 865 | + var allWordsMatch = queryWords.every(function(word) { |
| 866 | + return searchBlob.indexOf(word) !== -1; |
| 867 | + }); |
| 868 | + if (allWordsMatch) { |
| 869 | + return 5; |
| 870 | + } |
796 | 871 | } |
| 872 | + |
797 | 873 | return Infinity; |
798 | 874 | } |
799 | 875 |
|
|
919 | 995 | searchState.indexing = false; |
920 | 996 | return; |
921 | 997 | } |
| 998 | + if (searchState.indexLoaded) { |
| 999 | + searchState.indexing = false; |
| 1000 | + return; |
| 1001 | + } |
922 | 1002 | if (searchState.indexing || !searchState.queue.length) { |
923 | 1003 | searchState.indexing = searchState.queue.length > 0; |
924 | 1004 | return; |
|
1040 | 1120 | }); |
1041 | 1121 | } |
1042 | 1122 |
|
1043 | | - if (headingText.indexOf('property') !== -1) { |
| 1123 | + if (headingText.indexOf('property') !== -1 || headingText.indexOf('properties') !== -1) { |
1044 | 1124 | var propertyNames = collectPropertyNames(section); |
1045 | 1125 | var anchorId = section.getAttribute('id'); |
1046 | 1126 | var anchorHref = anchorId ? baseHref + '#' + anchorId : baseHref; |
|
1061 | 1141 | }); |
1062 | 1142 | } |
1063 | 1143 | } |
| 1144 | + |
| 1145 | + // Index values/constants/enums (like CONTENT_AWARE_FITTING) |
| 1146 | + if (headingText.indexOf('value') !== -1 || headingText.indexOf('constant') !== -1) { |
| 1147 | + var valueRows = section.querySelectorAll('table tbody tr'); |
| 1148 | + valueRows.forEach(function(row) { |
| 1149 | + var cells = row.querySelectorAll('td'); |
| 1150 | + if (!cells.length) { |
| 1151 | + return; |
| 1152 | + } |
| 1153 | + var nameCell = cells[0]; |
| 1154 | + var descCell = cells.length > 1 ? cells[1] : null; |
| 1155 | + |
| 1156 | + // Extract the value name (e.g., "Fitting.CONTENT_AWARE_FITTING") |
| 1157 | + var clipButton = nameCell.querySelector('.clip_button'); |
| 1158 | + var text = clipButton ? clipButton.textContent.trim() : nameCell.textContent.trim(); |
| 1159 | + |
| 1160 | + if (!text) { |
| 1161 | + return; |
| 1162 | + } |
| 1163 | + |
| 1164 | + // Get description for better search context |
| 1165 | + var description = descCell ? descCell.textContent.trim() : ''; |
| 1166 | + var keywords = description ? description.toLowerCase() : ''; |
| 1167 | + |
| 1168 | + // Use section anchor or base href |
| 1169 | + var anchorId = section.getAttribute('id'); |
| 1170 | + var resolved = anchorId ? baseHref + '#' + anchorId : baseHref; |
| 1171 | + |
| 1172 | + pushEntry(buildSearchEntry('value', text, resolved, { |
| 1173 | + context: pageTitle, |
| 1174 | + keywords: keywords |
| 1175 | + })); |
| 1176 | + }); |
| 1177 | + } |
| 1178 | + }); |
| 1179 | + |
| 1180 | + // Also index all tables that might contain constants/values outside of sections |
| 1181 | + var allTables = doc.querySelectorAll('table'); |
| 1182 | + allTables.forEach(function(table) { |
| 1183 | + // Check if table has class indicators or if it's in body |
| 1184 | + var inSection = table.closest('div.section'); |
| 1185 | + if (inSection) { |
| 1186 | + return; // Already processed in sections |
| 1187 | + } |
| 1188 | + |
| 1189 | + var rows = table.querySelectorAll('tbody tr'); |
| 1190 | + rows.forEach(function(row) { |
| 1191 | + var cells = row.querySelectorAll('td'); |
| 1192 | + if (cells.length < 1) { |
| 1193 | + return; |
| 1194 | + } |
| 1195 | + var nameCell = cells[0]; |
| 1196 | + var descCell = cells.length > 1 ? cells[1] : null; |
| 1197 | + |
| 1198 | + // Look for clip_button or structured content |
| 1199 | + var clipButton = nameCell.querySelector('.clip_button'); |
| 1200 | + if (!clipButton) { |
| 1201 | + return; |
| 1202 | + } |
| 1203 | + |
| 1204 | + var text = clipButton.textContent.trim(); |
| 1205 | + if (!text) { |
| 1206 | + return; |
| 1207 | + } |
| 1208 | + |
| 1209 | + // Get description for context |
| 1210 | + var description = descCell ? descCell.textContent.trim() : ''; |
| 1211 | + var keywords = description ? description.toLowerCase() : ''; |
| 1212 | + |
| 1213 | + pushEntry(buildSearchEntry('constant', text, baseHref, { |
| 1214 | + context: pageTitle, |
| 1215 | + keywords: keywords |
| 1216 | + })); |
| 1217 | + }); |
1064 | 1218 | }); |
1065 | 1219 |
|
1066 | 1220 | return entries; |
|
0 commit comments