PageSourceSearch

https://www.belfor.com/us/wp-content/plugins/ds-locations/js/locations.js?ver=0.1.0

js belfor.com collected 2026-10-03 22:02:40 UTC 13,661 bytes, 500 lines download raw bytes

1// import {
2//     getMarkers, getInfoWindow,
3// } from './helpers';
4
5// import {
6//     setDBAutocomplete
7// } from "./autocomplete-db";
8
9const selectors = {
10	locationsSection: '.js-locations-section',
11	locationsMap: '#locations-map',
12	searchInput: '#locations-search',
13	selectState: '#locations-state-select',
14	searchBtn: '.js-search-loc-btn',
15	locationsBlock: '.locations-block',
16	locationsList: '#locations-list',
17	lettersList: '#letters-list',
18	locationsSearchInfo: '.dsl-search-result-info',
19	currentLocationBtn: '.dsl-get-current-location',
20	loaderDiv: '.dsl-js-loader',
21	resetBtn: '.dsl-reset-filters',
22	radiusDiv: '#radius_range',
23	tabs: '.tab',
24};
25
26const state = {
27	map: null,
28	markers: [],
29	// allData: {},
30	address: null,
31	currentInfo: null,
32	radiusRange: 250,
33	circle: null,
34	resetBtn: null,
35	clusterer: null,
36	defaultCountryCode: ds_locations && ds_locations['default_country_code'] ? ds_locations['default_country_code'] : "USA",
37	searchRadius: ds_locations && ds_locations['search_radius'] ? ds_locations['search_radius'] : '100',
38};
39
40/**
41 * Switch to show or hide listing with locations in sidebar container.
42 * Depend on filter and search results.
43 */
44const switchLocationsBlock = (setShow = true) => {
45	const {locationsBlock} = state;
46	if (locationsBlock) {
47		const isShow = locationsBlock.classList.contains('is-visible');
48
49		if (setShow) {
50			!isShow && locationsBlock.classList.add('is-visible');
51		} else {
52			isShow && locationsBlock.classList.remove('is-visible');
53		}
54	}
55};
56
57/**
58 * Add info about locations init and search result.
59 * */
60const setLocationsSearchInfo = ({type = 'default', count}) => {
61	const {locationsSearchInfo, locationsSection} = state;
62	const checkCountryCodes = () => ['USA', 'CAN'].includes(state.defaultCountryCode);
63
64	if (locationsSearchInfo) {
65		const searchInfoMessages = {
66			default: (count) => checkCountryCodes ? '' : `${count} ` + ds_locations.translate.location,
67			error: () => '<span class="error">' + ds_locations.translate.error_locations + '</span>',
68			empty: () => '<span class="error">' + ds_locations.translate.no_locations + '</span>',
69			result: (count) => checkCountryCodes ? '' : `<span>${count}</span> ${(count > 1) ? ds_locations.translate.locations_f : ds_locations.translate.location_f}`,
70		};
71
72		// remove all previous "Search Result" status classes
73		locationsSection.classList.remove('search-error', 'search-empty', 'search-found');
74		locationsSearchInfo.classList.remove('no-results');
75		switchLocationsBlock(false);
76
77		if (type === 'error') {
78			locationsSearchInfo.classList.add('no-results');
79			locationsSection.classList.add('search-error');
80		}
81
82		if (type === 'empty') {
83			locationsSearchInfo.classList.add('no-results');
84			locationsSection.classList.add('search-empty');
85		}
86
87		if (type === 'result' && count) {
88			// show locations list
89			switchLocationsBlock();
90			locationsSection.classList.add('search-found');
91		}
92
93		locationsSearchInfo.innerHTML = searchInfoMessages[type](count);
94	}
95};
96
97const removeCurrentInfo = () => {
98	if (state.currentInfo) {
99		const {item, marker, info} = state.currentInfo;
100		item && item.classList.remove('active');
101
102		info.close();
103		state.currentInfo = null;
104	}
105};
106const setCurrentInfo = async (currentInfo, reset) => {
107	const {item, marker, info, id} = currentInfo;
108
109	// remove old info
110	if (reset) {
111		removeCurrentInfo();
112	}
113
114	// set current Info
115	state.currentInfo = currentInfo;
116
117	if (item) {
118		item.classList.add('active');
119	}
120
121	state.map.panTo(marker.getPosition());
122
123	if (info.getContent()) {
124		info.open(state.map, marker);
125	} else {
126		info.setContent('<div class="info-window-content"><p class="loading">Loading...</p></div>');
127		info.open(state.map, marker);
128
129		try {
130			const response = await getInfoWindow({pid: id});
131			if (response.html) {
132				info.setContent(response.html);
133			} else {
134				info.close();
135			}
136		} catch (e) {
137			console.log(e);
138			info.close();
139		}
140	}
141};
142
143const setLocationsList = ({data}) => {
144
145	const {locationsList} = state;
146
147	if (locationsList) {
148		locationsList.innerHTML = data.html;
149		const locationsListItems = locationsList.children;
150		[...locationsListItems].forEach((locationsListItem) => {
151			const id = locationsListItem.getAttribute('data-id');
152			// eslint-disable-next-line no-shadow
153			const marker = state.markers.find((marker) => marker.pid === +id);
154			locationsListItem.addEventListener('click', () => {
155				removeCurrentInfo();
156				state.map.panTo(marker.getPosition());
157				state.map.setZoom(8);
158			});
159		});
160	}
161};
162
163const setMarkers = ({data}) => {
164	// remove prevent info window popup on map
165	removeCurrentInfo();
166
167	// Reset old markers from map
168	state.markers.forEach((marker) => marker.setMap(null));
169	state.markers = [];
170
171	const clusterOptions = {styles: [{fillColor: '#DE1B22'}]};
172
173	state.clusterer = new markerClusterer.MarkerClusterer({map: state.map, markers: state.markers}, clusterOptions);
174
175	// show info message about search result
176	setLocationsSearchInfo({
177		type: 'result',
178		count: data.markers.length,
179	});
180
181	for (const key in data.markers) {
182		const markerData = data.markers[key];
183		const infowindow = new google.maps.InfoWindow();
184		infowindow.addListener('closeclick', () => {
185			removeCurrentInfo();
186		});
187
188		const icon = ds_locations.icon;
189		// Create and add new marker from response on map
190		// deprecated https://developers.google.com/maps/documentation/javascript/advanced-markers/migration
191		let marker = new google.maps.Marker({
192			map: state.map,
193			position: new google.maps.LatLng(markerData.lat, markerData.lng),
194			icon,
195			title: 'Marker',
196			pid: markerData.pid,
197		});
198
199		// let marker = new google.maps.marker.AdvancedMarkerElement({
200		//     map: state.map,
201		//     position: new google.maps.LatLng(markerData.lat, markerData.lng),
202		//     icon,
203		//     pid: markerData.pid,
204		// });
205
206		state.markers.push(marker);
207		state.clusterer.addMarker(marker);
208
209		marker.addListener('click', () => {
210			const locationsListItem = state.locationsList && state.locationsList.querySelector(`[data-id='${markerData.pid}']`);
211			const newCurrentInfo = {
212				id: markerData.pid,
213				item: locationsListItem,
214				marker,
215				info: infowindow,
216			};
217
218			// TODO WTF
219			if (state.currentInfo) {
220				// eslint-disable-next-line no-empty
221				if (state.currentInfo.id === markerData.pid) {
222
223				} else {
224					setCurrentInfo(newCurrentInfo, true);
225				}
226			} else {
227				setCurrentInfo(newCurrentInfo);
228			}
229		});
230	}
231};
232
233const fitBoundsToMarkers = (radiusVal) => {
234	if (state.circle) {
235		state.circle.setMap(null);
236	}
237	const circle = new google.maps.Circle({
238		map: state.map,
239		fillColor: 'transparent',
240		strokeColor: 'transparent',
241	});
242	state.circle = circle;
243	circle.setCenter(new google.maps.LatLng(state.map.getCenter()));
244
245	circle.setRadius((radiusVal * 850));
246	state.map.fitBounds(circle.getBounds());
247};
248
249const fitBoundsMarkers = () => {
250	const bounds = new google.maps.LatLngBounds();
251	state.markers.forEach((marker) => bounds.extend(marker.getPosition()));
252	state.map.fitBounds(bounds);
253	const listener = google.maps.event.addListener(state.map, 'idle', () => {
254		if (state.map.getZoom() > 16) state.map.setZoom(16);
255		google.maps.event.removeListener(listener);
256	});
257};
258
259const removeMarkers = () => {
260	state.clusterer.setMap(null);
261	state.markers.forEach((marker) => {
262		state.clusterer.removeMarker(marker);
263		marker.setMap(null);
264	});
265	state.markers = [];
266	state.locationsList.innerHTML = '';
267	state.map.setCenter(new google.maps.LatLng(20, 0));
268	state.map.setZoom(3);
269};
270
271const initMap = async () => {
272	const {locationsMap} = state;
273
274	if (locationsMap) {
275		try {
276			state.map = new google.maps.Map(locationsMap, {
277				center: {lat: parseInt(ds_locations.center.lat), lng: parseInt(ds_locations.center.lng)},
278				zoom: parseInt(ds_locations.zoom),
279				zoomControl: ds_locations.zoom_control,
280				disableDefaultUI: true,
281				zoomControlOptions: {
282					position: google.maps.ControlPosition.RIGHT_CENTER,
283				},
284				gestureHandling: 'cooperative',
285				mapId: 'DSL-WP',
286				//styles: JSON.parse(ds_locations.map_styles),
287			});
288			state.geocoder = new google.maps.Geocoder();
289
290			let data = {type: 'all'};
291
292			const response = await getMarkers(data);
293
294			if (response.success) {
295				// state.allData = response.data;
296				setMarkers({data: response.data});
297				setLocationsList({data: response.data});
298			} else {
299				setLocationsSearchInfo({type: 'empty'});
300				removeMarkers();
301			}
302		} catch (e) {
303			if (e.typeError === 'markers') {
304				setLocationsSearchInfo({type: 'empty'});
305				removeMarkers();
306			} else {
307				console.log(e);
308			}
309		}
310	}
311};
312
313const runSearch = async (coordinates, radius, region) => {
314	const {
315		searchInput
316	} = state;
317
318	const address = coordinates || searchInput.value;
319	const searchBy=searchInput.getAttribute('data-search') || 'address_title';
320
321	state.resetBtn.style.display = 'block';
322	try {
323		let data = {search: address, search_by:searchBy}, extendedAddress = `${address} , ${state.defaultCountryCode}`, response = {};
324
325		if (region) {
326			data = {type: 'by_state', state: region};
327			response = await getMarkers(data);
328		} else {
329
330			if (validationZipCode(address, state.defaultCountryCode)) {
331				response = await getMarkersByZip({address: extendedAddress, state});
332			}
333			if (!response.success) {
334				response = await getMarkers(data);
335			}
336		}
337
338
339		state.address = address;
340
341		if (response.success) {
342			removeMarkers();
343			setMarkers({data: response.data});
344			fitBoundsMarkers();
345			setLocationsList({data: response.data});
346		} else {
347			setLocationsSearchInfo({type: 'empty'});
348			removeMarkers();
349		}
350	} catch (e) {
351		if (e.typeError === 'markers') {
352			setLocationsSearchInfo({type: 'empty'});
353			removeMarkers();
354		}
355	}
356};
357
358const initSearch = () => {
359	const {
360		searchInput, currentLocationBtn, searchBtn, radiusDiv, selectState
361	} = state;
362
363	if (searchInput) {
364		const handlerSearchPlace = () => {
365			if (searchInput.value.trim().length !== 0) {
366				if (searchInput.value !== state.address) {
367					runSearch();
368				}
369			} else {
370				setLocationsSearchInfo({type: 'error'});
371			}
372		};
373		if (searchBtn) {
374			searchBtn.addEventListener('click', () => {
375				if (selectState) {
376					selectState.value = '';
377				}
378				handlerSearchPlace();
379			});
380		}
381
382		searchInput.addEventListener('keydown', (ev) => {
383			if (ev.keyCode === 13) {
384				if (selectState) {
385					selectState.value = '';
386				}
387				handlerSearchPlace();
388			}
389		});
390	}
391
392	if (selectState) {
393		selectState.addEventListener("change", function () {
394			searchInput.value = '';
395			runSearch(false, false, selectState.value);
396		});
397	}
398
399	if (currentLocationBtn) {
400		currentLocationBtn.addEventListener('click', () => {
401			if (navigator.geolocation) {
402				navigator.geolocation.getCurrentPosition((position) => {
403					const lat = position.coords.latitude;
404					const long = position.coords.longitude;
405					state.map.setCenter(new google.maps.LatLng(lat, long), 4);
406				}, (err) => {
407					console.log(err);
408				});
409			}
410		});
411	}
412
413	if (radiusDiv) {
414		radiusDiv.addEventListener('mouseup', () => {
415			if (state.radiusRange !== radiusDiv.value) {
416				if (navigator.geolocation) {
417					navigator.geolocation.getCurrentPosition((position) => {
418						state.map.setCenter(new google.maps.LatLng(position.coords.latitude, position.coords.longitude));
419						state.map.setZoom(9);
420
421						fitBoundsToMarkers(+radiusDiv.value);
422						runSearch(`${lat}, ${long}`, radiusDiv.value);
423					});
424				}
425			}
426			state.radiusRange = radiusDiv.value;
427		});
428	}
429
430	state.resetBtn.addEventListener('click', () => {
431		let data = {type: 'all'};
432
433		getMarkers(data).then((response) => {
434			if (response.success) {
435				searchInput.value = '';
436				selectState.value = '';
437
438				setMarkers({data: response.data});
439				setLocationsList({data: response.data});
440
441				state.map.setCenter(new google.maps.LatLng(parseInt(ds_locations.center.lat), parseInt(ds_locations.center.lng)));
442				state.map.setZoom(parseInt(ds_locations.zoom));
443				state.resetBtn.style.display = 'none';
444			}
445		});
446	});
447};
448
449// const initSingleMap = async () => {
450//     const {singleMap} = state;
451//     if (singleMap) {
452//         try {
453//             state.map = new google.maps.Map(singleMap, {
454//                 center: {lat: 40.2213207, lng: -94.6041298},
455//                 zoom: 5,
456//                 disableDefaultUI: true,
457//                 zoomControl: false,
458//                 gestureHandling: 'cooperative',
459//                 zoomControlOptions: {
460//                     //position: google.maps.ControlPosition.RIGHT_CENTER,
461//                 },
462//             });
463//
464//             const response = await getMarkers(data);
465//             if (response.success) {
466//                 setMarkers({data: response.data});
467//                 // eslint-disable-next-line max-len
468//                 //state.map.setCenter(new google.maps.LatLng(response.data.markers[0].lat, response.data.markers[0].lng));
469//                 fitBoundsMarkers();
470//                 setLocationsList({data});
471//             } else {
472//                 removeMarkers();
473//             }
474//         } catch (e) {
475//             if (e.typeError === 'markers') {
476//                 removeMarkers();
477//             } else {
478//                 console.log(e);
479//             }
480//         }
481//     }
482// };
483
484const mapSearchWithAutocomplete = () => {
485	const {locationsSection, ...restSelectors} = selectors;
486	state.locationsSection = document.querySelector(locationsSection);
487	if (state.locationsSection) {
488		Object.keys(restSelectors).forEach((key) => {
489			state[key] = document.querySelector(restSelectors[key]);
490		});
491
492		initMap();
493		//initSingleMap();
494		initSearch();
495
496		setDBAutocomplete(state.searchInput);
497	}
498};
499
500mapSearchWithAutocomplete();

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.