PageSourceSearch

https://www.footballcritic.com/js/header_typesense.js?v=1790942148

js footballcritic.com collected 2026-10-02 11:56:16 UTC 9,130 bytes, 247 lines download raw bytes

1const currentHost = window.location.hostname.toLowerCase();
2const currentPort = window.location.port;
3const isNlHost = currentHost === 'footballcritic.nl' || currentHost === 'www.footballcritic.nl' || currentPort === '8001';
4
5function normalizeFcUrl(url) {
6	if (!url) return url;
7
8	url = url.replace('https://www.footballcritic.com/nl', 'https://www.footballcritic.nl');
9	url = url.replace('https://footballcritic.com/nl', 'https://www.footballcritic.nl');
10
11	if (currentHost === 'localhost' || currentHost === '127.0.0.1') {
12		const targetPort = isNlHost ? '8001' : '8000';
13		url = url.replace(/https?:\/\/(www\.)?footballcritic\.(com|nl)/g, window.location.protocol + '//' + currentHost + ':' + targetPort);
14		return url;
15	}
16
17	if (isNlHost) {
18		url = url.replace('https://www.footballcritic.com', 'https://www.footballcritic.nl');
19		url = url.replace('https://footballcritic.com', 'https://www.footballcritic.nl');
20	} else {
21		url = url.replace('https://www.footballcritic.nl', 'https://www.footballcritic.com');
22		url = url.replace('https://footballcritic.nl', 'https://www.footballcritic.com');
23	}
24
25	return url;
26}
27
28// SEARCH - VISUAL INTERACTIONS
29$('#aa-search-input').focusin(function() {
30	$('#mobsearchVisual').show();
31	$(this).addClass('bigger');
32});
33
34$('#mobsearchVisual .closeSub').click(function() {
35	$('#mobsearchVisual').hide();
36});
37
38$('#aa-search-input').on('input', function() {
39	var strL = $(this).val();
40	if (strL.length > 0) {
41		$('#mobsearchVisual').hide();
42	}
43});
44
45$(document).mouseup(function(e) {
46	var containerVisSearch = $("#mobsearchVisual, #aa-search-input, .add-nav");
47	if (!containerVisSearch.is(e.target) && containerVisSearch.has(e.target).length === 0) {
48		$("#mobsearchVisual").hide();
49		$('#aa-search-input').removeClass('bigger');
50		$(".add-nav").removeClass('active');
51		$(".hasSubmenu").removeClass('on');
52	}
53});
54
55$('#aa-search-input, #bb-search-input').keyup(function(e) {
56	if (e.keyCode == 13) {
57		window.location = "/search?q=" + encodeURIComponent($(this).val());
58	}
59});
60
61$('#homeSearch').click(function() {
62	window.location = "/search?q=" + encodeURIComponent($("#bb-search-input").val());
63});
64
65function foreSearch() {
66	if ($('#homeSearch').length) {
67		$('#homeSearch').click();
68	} else {
69		window.location = "/search?q=" + encodeURIComponent($("#aa-search-input").val());
70	}
71}
72
73// TYPESENSE SEARCH CLIENT & SOURCE ADAPTER
74const TYPESENSE_HOST = 't63phscirf75198op-1.a1.typesense.net';
75const TYPESENSE_SEARCH_KEY = 'ft6uQPuwlxXfg9y4oWMeHG4fr2cID8dm';
76
77function typesenseSource(collection, queryBy, perPage) {
78	return function(query, callback) {
79		if (!query || query.trim().length === 0) {
80			callback([]);
81			return;
82		}
83
84		const url = 'https://' + TYPESENSE_HOST + '/collections/' + collection + '/documents/search?' +
85			'q=' + encodeURIComponent(query) +
86			'&query_by=' + encodeURIComponent(queryBy) +
87			'&per_page=' + perPage +
88			'&x-typesense-api-key=' + TYPESENSE_SEARCH_KEY;
89
90		fetch(url)
91			.then(function(res) { return res.json(); })
92			.then(function(data) {
93				const hits = (data.hits || []).map(function(h) {
94					const doc = h.document || {};
95					doc._highlightResult = {
96						name: {
97							value: (h.highlight && h.highlight.name && h.highlight.name.snippet)
98								? h.highlight.name.snippet
99								: (doc.name || '')
100						}
101					};
102					if (doc.team_name) {
103						doc._highlightResult.team_name = {
104							value: (h.highlight && h.highlight.team_name && h.highlight.team_name.snippet)
105								? h.highlight.team_name.snippet
106								: doc.team_name
107						};
108					}
109					return doc;
110				});
111
112				callback(hits, { hits: hits, nbHits: data.found || 0 });
113			})
114			.catch(function(err) {
115				console.error('Typesense search error:', err);
116				callback([]);
117			});
118	};
119}
120
121// AUTOCOMPLETE INITIALIZATION
122$('#aa-search-input, #bb-search-input').autocomplete({ hint: false }, [
123	// 1. TEAMS DATASET
124	{
125		source: typesenseSource('fc_teams', 'name,full_name', 6),
126		displayKey: 'title, description, link',
127		templates: {
128			header: function(data, response) {
129				var totalTmp = response ? response.nbHits : 0;
130				if (totalTmp > 99) totalTmp = "99+";
131				var label = isNlHost ? 'Clubs (' + totalTmp + ')' : 'Teams (' + totalTmp + ')';
132				var btnText = isNlHost ? 'Bekijk alles' : 'View all';
133				return '<div class="aa-search-head"><span>' + label + '</span> <a onclick="foreSearch()" class="btn small rightside">' + btnText + '</a></div>';
134			},
135			suggestion: function(data) {
136				var plPic = (data.logo && data.logo !== "") ? data.logo : ("https://www.sportsbase.io/images/clubs/" + data.team_id + ".png");
137				if (data.ranking == "0") {
138					data.ranking = "";
139					data.ranking_class = "";
140				}
141
142				if (isNlHost) {
143					data.team_url = normalizeFcUrl(data.team_url);
144				}
145
146				var highlightVal = (data._highlightResult && data._highlightResult.name) ? data._highlightResult.name.value : data.name;
147				var subVal = data.area_name ? data.area_name : '';
148				var rankingBadge = '';
149				if (data.ranking > 0) {
150					rankingBadge = '<span class="aa-badge ' + (data.ranking_class || '') + '"' + (data.ranking_color ? ' style="background-color:' + data.ranking_color + ' !important;"' : '') + '>' + data.ranking + '</span>';
151				}
152
153				return '<div class="aa-item-row">' +
154					'<div class="aa-photo team"><img src="' + plPic + '" onerror="this.onerror=null;this.src=\'https://www.footballcritic.com/images/no_team.png\';" /></div>' +
155					'<div class="aa-info">' +
156						'<span class="aa-name">' + highlightVal + '</span>' +
157						(subVal ? '<span class="aa-sub">' + subVal + '</span>' : '') +
158					'</div>' +
159					rankingBadge +
160					'</div>';
161			}
162		}
163	},
164
165	// 2. COMPETITIONS DATASET
166	{
167		source: typesenseSource('fc_competitions', 'name', 6),
168		displayKey: 'title, description, link',
169		templates: {
170			header: function(data, response) {
171				var totalTmp = response ? response.nbHits : 0;
172				if (totalTmp > 99) totalTmp = "99+";
173				var label = isNlHost ? 'Competities (' + totalTmp + ')' : 'Competitions (' + totalTmp + ')';
174				var btnText = isNlHost ? 'Bekijk alles' : 'View all';
175				return '<div class="aa-search-head"><span>' + label + '</span> <a onclick="foreSearch()" class="btn small rightside">' + btnText + '</a></div>';
176			},
177			suggestion: function(data) {
178				var cCode = (data.code || '').toLowerCase();
179				if (isNlHost) {
180					data.seo_url = normalizeFcUrl(data.seo_url);
181				}
182
183				var highlightVal = (data._highlightResult && data._highlightResult.name) ? data._highlightResult.name.value : data.name;
184				var subVal = data.area_name ? data.area_name : '';
185
186				return '<div class="aa-item-row">' +
187					'<div class="aa-photo comp"><i class="flag flag-' + cCode + '"></i></div>' +
188					'<div class="aa-info">' +
189						'<span class="aa-name">' + highlightVal + '</span>' +
190						(subVal ? '<span class="aa-sub">' + subVal + '</span>' : '') +
191					'</div>' +
192					'</div>';
193			}
194		}
195	},
196
197	// 3. PLAYERS DATASET
198	{
199		source: typesenseSource('fc_players', 'name,team_name', 8),
200		displayKey: 'title, description, link',
201		templates: {
202			header: function(data, response) {
203				var totalTmp = response ? response.nbHits : 0;
204				if (totalTmp > 99) totalTmp = "99+";
205				var label = isNlHost ? 'Spelers (' + totalTmp + ')' : 'Players (' + totalTmp + ')';
206				var btnText = isNlHost ? 'Bekijk alles' : 'View all';
207				return '<div class="aa-search-head"><span>' + label + '</span> <a onclick="foreSearch()" class="btn small rightside">' + btnText + '</a></div>';
208			},
209			suggestion: function(data) {
210				var plPic = (data.picture && data.picture !== "") ? data.picture : "https://www.footballcritic.com/images/no_player4.png";
211
212				if (isNlHost) {
213					data.people_url = normalizeFcUrl(data.people_url);
214				}
215
216				var playerName = (data._highlightResult && data._highlightResult.name) ? data._highlightResult.name.value : data.name;
217				var teamVal = (data._highlightResult && data._highlightResult.team_name) ? data._highlightResult.team_name.value : (data.team_name || '');
218
219				var rankingBadge = '';
220				if (data.ranking && data.ranking > 0) {
221					rankingBadge = '<span class="aa-badge ' + (data.ranking_class || '') + '"' + (data.ranking_color ? ' style="background-color:' + data.ranking_color + ' !important;"' : '') + '>' + data.ranking + '</span>';
222				} else {
223					rankingBadge = '<span class="aa-badge na">-</span>';
224				}
225
226				return '<div class="aa-item-row">' +
227					'<div class="aa-photo player"><img src="' + plPic + '" onerror="this.onerror=null;this.src=\'https://www.footballcritic.com/images/no_player4.png\';" /></div>' +
228					'<div class="aa-info">' +
229						'<span class="aa-name">' + playerName + '</span>' +
230						(teamVal ? '<span class="aa-sub">(' + teamVal + ')</span>' : '') +
231					'</div>' +
232					rankingBadge +
233					'</div>';
234			}
235		}
236	}
237]).on("autocomplete:selected", function(event, suggestion, dataset) {
238	if ((dataset == 1) || (dataset == 5) || (dataset == 9)) {
239		location.href = suggestion.team_url;
240	}
241	if ((dataset == 2) || (dataset == 6) || (dataset == 10)) {
242		location.href = suggestion.seo_url;
243	}
244	if ((dataset == 3) || (dataset == 7) || (dataset == 11)) {
245		location.href = suggestion.people_url;
246	}
247});

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.