PageSourceSearch

https://findmylandlord.netlify.app/assets/js/matchAddresses.js

js findmylandlord.netlify.app collected 2026-10-03 10:44:24 UTC 6,145 bytes, 214 lines download raw bytes

1var searchResultsLimit = 50;
2
3// i18next ui translations
4appTitle.innerHTML = i18next.t('TITLE')
5datedWarning.innerHTML = i18next.t('DATED_WARNING')
6getHelpLinks.innerHTML = i18next.t('GET_HELP')
7legalNoticeLink.innerHTML = `<b>${i18next.t('LEGAL_NOTICE_TITLE')}</b>`
8affiliatedLabel.innerHTML = i18next.t('AFFILIATED_LABEL')
9ownedLabel.innerHTML = i18next.t('OWNED_LABEL')
10viewOnMap.innerHTML = i18next.t('VIEW_ON_MAP')
11taxpayerLabel.innerHTML = i18next.t('TAXPAYER_LABEL')
12unitsLabel.innerHTML = i18next.t('UNITS_LABEL')
13dataInfoLink.innerHTML = i18next.t('DATA_INFO_TITLE')
14additionalDetailsLink.innerHTML = i18next.t('ADDITIONAL_DETAILS_LABEL')
15switchLangLink.innerHTML = i18next.t('SWITCH_LANG_NAME')
16switchLangLink.href = location.origin + '?lng=' + i18next.t('SWITCH_LANG_CODE')
17
18searchInputContainer.querySelector('input').placeholder = i18next.t('SEARCH_LABEL')
19searchButton.innerHTML = i18next.t('SEARCH_BUTTON')
20
21const netlifyFunctionsBaseUrl = '.netlify/functions'
22
23const netlifyFunction = async (methodName, options = {}) => {
24  const response = await fetch(`/${netlifyFunctionsBaseUrl}/${methodName}`, options)
25  return await response.json()
26}
27
28const matchAddresses = async function (query) {
29	// Load search keys
30	var value = query.trim().toLowerCase();
31
32	firebase.analytics().logEvent("search-initiated", { 
33		property_address: searchInput.value
34	});
35
36	spinner.style.display = "block";
37	
38	// const { results } = await netlifyFunction('search', {
39	// 	body: JSON.stringify({query: value}),
40	// 	method: 'POST'
41	// })
42
43	const results = await flex.search(value, searchResultsLimit + 1)
44	spinner.style.display = "none";		
45	// Show "x"
46	renderClearButton(value);
47	// Reset rendered objects
48	resetSearchResults();
49	// Reset UI
50	resetMap();
51
52	if (value != "") {
53		// Render list
54		renderResults(results)
55	};
56};
57
58function renderClearButton(value) {
59	if (checkIE() == false) {
60		// Show if input has content
61		clearButton.style.display = (value.length) ? "block" : "none";
62
63		// Add listener
64		clearButton.onclick = function() {
65			// Hide button
66			this.style.display = "none";
67
68			// Reset UI
69			searchInput.value = "";
70			resetSearchResults();
71			resetMap();
72		};
73		// Accessibility
74		clearButton.addEventListener("keypress",
75			function(e) {
76				// Enter key
77				if (e.keyCode == 13) {
78					e.target.click();
79				};
80			}
81		);
82	};
83};
84
85function renderResults(features) {
86	if (features.length) {		
87		// Results were found
88		// Show container
89		searchResultsContainer.style.display = "block";
90		// Show counter
91		searchResultsCounter.style.display = "block";
92		// Show list
93		searchResultsList.style.display = "block";
94
95		if (features.length > searchResultsLimit) {
96			// More results than limit
97			searchResultsCounter.innerHTML = `<h4>${searchResultsLimit} ${i18next.t("SEARCH_RESULTS")}`;
98
99			var refineMessage = document.createElement("li");
100			refineMessage.id = "limit-message";
101			refineMessage.innerText = i18next.t("SEARCH_HINT", { searchResultsLimit })
102			searchResultsList.appendChild(refineMessage);
103		} else if (features.length > 1 && features.length <= searchResultsLimit) {
104			// Less results than limit
105			searchResultsCounter.innerHTML = `<h4>${features.length} ${i18next.t("SEARCH_RESULTS")}`;
106		} else if (features.length == 1) {
107			// 1 result
108			searchResultsCounter.innerHTML = `<h4>${features.length} ${i18next.t("SEARCH_RESULT")}`;
109		};
110
111		// Add ListItems
112		for (var i = 0; i < searchResultsLimit && i < features.length; i++) {
113			// Address at current index
114			createListItem(features[i]);
115		};
116	} else if (features.length == 0 && searchInput.value != "") {
117		// No results found
118		var title = i18next.t("NO_SEARCH_RESULTS");
119		var message = i18next.t("NO_SEARCH_RESULTS_MESSAGE");
120		showSearchMessage(title, message);
121	};
122};
123
124function showSearchMessage(title, message) {
125	// Show container
126	searchResultsContainer.style.display = "block";
127	// Show counter
128	searchResultsCounter.style.display = "block";
129
130	// Create elements
131	var headline = document.createElement("h4");
132	var description = document.createElement("p");
133
134	// Set values
135	headline.innerHTML = title;
136	description.id = "no-results-container";
137	description.innerHTML = message;
138
139	// Add content to containers
140	searchResultsCounter.appendChild(headline);
141	searchResultsContainer.appendChild(description);
142};
143
144function createListItem(feature) {
145	var item = document.createElement("li");
146	var address = feature[propertyAddressColumn];
147
148	item.className = "search-result";
149	item.tabIndex = 0;
150	item.innerHTML = address;
151
152	// Highlight part of string that matches input 
153	highlightText(searchInput, item);
154
155	if (document.getElementById("limit-message")) {
156		// Insert list items before limit message
157		searchResultsList.insertBefore(item, document.getElementById("limit-message"))
158	} else {
159		// Limit doesn't exist
160		searchResultsList.appendChild(item);
161	};
162
163	// Add click event
164	item.onclick = function(){
165		async function render() {
166			try {
167				// Show spinner
168				spinner.style.display = "block";
169
170				var selected = await searchProperty(feature[propertyIndexColumn]);
171				// Reset UI
172				resetMap();
173				// Update it
174				renderSelectedUI(selected);
175				// Log event
176				firebase.analytics().logEvent("search-result-clicked", { 
177					property_address: selected.properties[propertyAddressColumn],
178					taxpayer: selected.properties[taxpayerColumn],
179					affiliated_with: selected.properties[affiliatedWithColumn],
180				});
181
182				// Hide spinner
183				spinner.style.display = "none";
184			} catch {
185				// Show error message
186				resetSearchResults();
187				var title = i18next.t('ERROR_DB');
188				var message = i18next.t('ERROR_MESSAGE', { supportEmail });
189				showSearchMessage(title, message);
190
191				// Hide spinner
192				spinner.style.display = "none";
193			};	
194		};
195		render();
196	};
197	// Accessibility
198	item.addEventListener("keypress",
199		function(e) {
200			// Enter key
201			if (e.keyCode == 13) {
202				e.target.click();
203			};
204		}
205	);
206};
207
208function highlightText(input, destination) {
209	var regex = new RegExp(input.value, "gi")
210	var response = destination.innerHTML.replace(regex, function(str) {
211		return "<b>" + str + "</b>"
212	});
213	destination.innerHTML = response;
214};

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.