astro-accelerator 5.9.9 → 5.9.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/public/css/main.css +10 -4
- package/public/js/search.js +0 -3
- package/src/pages/404.md +2 -2
- package/public/js/search2.js +0 -676
package/package.json
CHANGED
package/public/css/main.css
CHANGED
|
@@ -637,7 +637,7 @@ nav.site-nav h2 {
|
|
|
637
637
|
z-index: 1;
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
-
.site-search-results {
|
|
640
|
+
header .site-search-results {
|
|
641
641
|
background-color: var(--white);
|
|
642
642
|
position: absolute;
|
|
643
643
|
top: var(--search-height);
|
|
@@ -667,7 +667,7 @@ nav.site-nav h2 {
|
|
|
667
667
|
margin-inline-start: 0;
|
|
668
668
|
}
|
|
669
669
|
|
|
670
|
-
.site-search-results ul:not(.post-list):not(.result-headings) {
|
|
670
|
+
header .site-search-results ul:not(.post-list):not(.result-headings) {
|
|
671
671
|
margin: 0;
|
|
672
672
|
max-height: var(--search-dropdown-height);
|
|
673
673
|
overflow-y: scroll;
|
|
@@ -760,7 +760,6 @@ nav.site-nav h2 {
|
|
|
760
760
|
|
|
761
761
|
.result-wrapper {
|
|
762
762
|
display: flex;
|
|
763
|
-
padding: 1.5rem 3.6rem 1.75rem;
|
|
764
763
|
text-decoration: none;
|
|
765
764
|
flex-direction: column;
|
|
766
765
|
gap: 0.56rem;
|
|
@@ -770,6 +769,10 @@ nav.site-nav h2 {
|
|
|
770
769
|
}
|
|
771
770
|
}
|
|
772
771
|
|
|
772
|
+
header .result-wrapper {
|
|
773
|
+
padding: 1.5rem 3.6rem 1.75rem;
|
|
774
|
+
}
|
|
775
|
+
|
|
773
776
|
.result-wrapper:hover {
|
|
774
777
|
background-color: initial;
|
|
775
778
|
}
|
|
@@ -882,10 +885,13 @@ nav.site-nav h2 {
|
|
|
882
885
|
|
|
883
886
|
.result-headings li {
|
|
884
887
|
text-align: left;
|
|
885
|
-
padding: 0.1rem 3.6rem;
|
|
886
888
|
font-size: 1rem;
|
|
887
889
|
}
|
|
888
890
|
|
|
891
|
+
header .result-headings li {
|
|
892
|
+
padding: 0.1rem 3.6rem;
|
|
893
|
+
}
|
|
894
|
+
|
|
889
895
|
.show-more {
|
|
890
896
|
padding: 0.5em 1em;
|
|
891
897
|
background-color: var(--fore-link);
|
package/public/js/search.js
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import { qs } from './modules/query.js';
|
|
11
11
|
import { raiseEvent } from './modules/events.js';
|
|
12
|
-
import { removeScroll, resetScroll } from './modules/scrollbar.js';
|
|
13
12
|
import { contains, sanitise, explode, highlight } from './modules/string.js';
|
|
14
13
|
import { stemmer } from './modules/stemmer.js';
|
|
15
14
|
|
|
@@ -158,7 +157,6 @@ function initializeSearch() {
|
|
|
158
157
|
return;
|
|
159
158
|
}
|
|
160
159
|
siteSearchWrapper.classList.add('is-active');
|
|
161
|
-
removeScroll();
|
|
162
160
|
openDropdown();
|
|
163
161
|
}
|
|
164
162
|
|
|
@@ -167,7 +165,6 @@ function initializeSearch() {
|
|
|
167
165
|
return;
|
|
168
166
|
}
|
|
169
167
|
siteSearchWrapper.classList.remove('is-active');
|
|
170
|
-
resetScroll();
|
|
171
168
|
}
|
|
172
169
|
|
|
173
170
|
function openDropdown() {
|
package/src/pages/404.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
warning: This file is overwritten by Astro Accelerator
|
|
3
|
-
layout: src/layouts/
|
|
3
|
+
layout: src/layouts/Default.astro
|
|
4
4
|
title: Not Found
|
|
5
5
|
listable: false
|
|
6
6
|
navMenu: false
|
|
@@ -13,7 +13,7 @@ bannerImage:
|
|
|
13
13
|
alt: Dummy image
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
We couldn't find that
|
|
16
|
+
We couldn't find that... hit the search bar as you might have a super old link
|
|
17
17
|
|
|
18
18
|
<script>
|
|
19
19
|
{
|
package/public/js/search2.js
DELETED
|
@@ -1,676 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This javascript file comes from Astro Accelerator
|
|
3
|
-
* Edits will be overwritten if you change the file locally
|
|
4
|
-
* THIS IS THE PREVIOUS SEARCH VERSION
|
|
5
|
-
*
|
|
6
|
-
* @format
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// @ts-check
|
|
10
|
-
|
|
11
|
-
import { qs } from './modules/query.js';
|
|
12
|
-
import { raiseEvent } from './modules/events.js';
|
|
13
|
-
import { removeScroll, resetScroll } from './modules/scrollbar.js';
|
|
14
|
-
import { contains, sanitise, explode, highlight } from './modules/string.js';
|
|
15
|
-
import { stemmer } from './modules/stemmer.js';
|
|
16
|
-
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
const f = window.site_features ?? {};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
* @param {string[]} settings
|
|
23
|
-
* @param {string} option
|
|
24
|
-
* @returns
|
|
25
|
-
*/
|
|
26
|
-
function enabled(settings, option) {
|
|
27
|
-
return settings && settings.includes(option);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
@typedef {
|
|
32
|
-
{
|
|
33
|
-
text: string;
|
|
34
|
-
safeText: string;
|
|
35
|
-
slug: string;
|
|
36
|
-
}
|
|
37
|
-
} Heading
|
|
38
|
-
|
|
39
|
-
@typedef {
|
|
40
|
-
{
|
|
41
|
-
foundWords: number;
|
|
42
|
-
score: number;
|
|
43
|
-
depth: number;
|
|
44
|
-
title: string;
|
|
45
|
-
keywords: string;
|
|
46
|
-
safeTitle: string;
|
|
47
|
-
description: string;
|
|
48
|
-
safeDescription: string;
|
|
49
|
-
headings: Heading[];
|
|
50
|
-
tags: string[];
|
|
51
|
-
url: string;
|
|
52
|
-
date: string;
|
|
53
|
-
matchedHeadings: Heading[];
|
|
54
|
-
}
|
|
55
|
-
} SearchEntry
|
|
56
|
-
|
|
57
|
-
@typedef {
|
|
58
|
-
{
|
|
59
|
-
[ix: string]: string
|
|
60
|
-
}
|
|
61
|
-
} Synonyms
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
function initializeSearch() {
|
|
65
|
-
const siteSearchInput = qs('[data-site-search-query]');
|
|
66
|
-
const siteSearchWrapper = qs('[data-site-search-wrapper]');
|
|
67
|
-
const siteSearchElement = qs('[data-site-search]');
|
|
68
|
-
const siteSearchResults = qs('[data-site-search-results');
|
|
69
|
-
const removeSearchButton = qs('[data-site-search-remove]');
|
|
70
|
-
|
|
71
|
-
/** @type {SearchEntry[]} */
|
|
72
|
-
var haystack = [];
|
|
73
|
-
var currentQuery = '';
|
|
74
|
-
var dataUrl = siteSearchElement.dataset.sourcedata;
|
|
75
|
-
|
|
76
|
-
var scoring = {
|
|
77
|
-
depth: 5,
|
|
78
|
-
phraseTitle: 60,
|
|
79
|
-
phraseHeading: 20,
|
|
80
|
-
phraseDescription: 20,
|
|
81
|
-
termTitle: 40,
|
|
82
|
-
termHeading: 15,
|
|
83
|
-
termDescription: 15,
|
|
84
|
-
termTags: 15,
|
|
85
|
-
termKeywords: 15,
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
var ready = false;
|
|
89
|
-
var scrolled = false;
|
|
90
|
-
|
|
91
|
-
siteSearchInput.addEventListener('focus', () => activateInput());
|
|
92
|
-
|
|
93
|
-
function deactivate(e) {
|
|
94
|
-
if (
|
|
95
|
-
!siteSearchElement.contains(e.target) &&
|
|
96
|
-
!siteSearchResults.contains(e.target)
|
|
97
|
-
) {
|
|
98
|
-
closeDropdown();
|
|
99
|
-
|
|
100
|
-
const duration = getComputedStyle(
|
|
101
|
-
siteSearchWrapper
|
|
102
|
-
).getPropertyValue('--search-dropdown-duration');
|
|
103
|
-
|
|
104
|
-
// Convert duration to milliseconds for setTimeout
|
|
105
|
-
const durationMs =
|
|
106
|
-
parseFloat(duration) * (duration.endsWith('ms') ? 1 : 1000);
|
|
107
|
-
|
|
108
|
-
setTimeout(() => {
|
|
109
|
-
deactivateInput();
|
|
110
|
-
}, durationMs);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Close the dropdown upon activity outside the search
|
|
115
|
-
document.addEventListener('click', deactivate);
|
|
116
|
-
document.addEventListener('keydown', deactivate);
|
|
117
|
-
|
|
118
|
-
function removeSearch() {
|
|
119
|
-
clearInput();
|
|
120
|
-
deactivateInput();
|
|
121
|
-
debounceSearch();
|
|
122
|
-
siteSearchInput.focus();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Clear the search input
|
|
126
|
-
removeSearchButton.addEventListener('click', () => {
|
|
127
|
-
removeSearch();
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Dropdown accessibility controls
|
|
131
|
-
document.addEventListener('keydown', handleDropdownKeyboardNavigation);
|
|
132
|
-
|
|
133
|
-
function activateInput() {
|
|
134
|
-
if (
|
|
135
|
-
siteSearchWrapper.classList.contains('is-active') ||
|
|
136
|
-
siteSearchInput.value.trim().length === 0
|
|
137
|
-
) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
siteSearchWrapper.classList.add('is-active');
|
|
141
|
-
removeScroll();
|
|
142
|
-
openDropdown();
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function deactivateInput() {
|
|
146
|
-
if (!siteSearchWrapper.classList.contains('is-active')) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
siteSearchWrapper.classList.remove('is-active');
|
|
150
|
-
resetScroll();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function openDropdown() {
|
|
154
|
-
siteSearchElement.classList.add('is-active');
|
|
155
|
-
|
|
156
|
-
requestAnimationFrame(() => {
|
|
157
|
-
const dropdownHeightPercentage = parseFloat(
|
|
158
|
-
getComputedStyle(siteSearchWrapper).getPropertyValue(
|
|
159
|
-
'--search-dropdown-height'
|
|
160
|
-
)
|
|
161
|
-
);
|
|
162
|
-
// Convert vh to pixels
|
|
163
|
-
const dropdownHeight =
|
|
164
|
-
window.innerHeight * (dropdownHeightPercentage / 100) + 32;
|
|
165
|
-
const siteSearchElementRect =
|
|
166
|
-
siteSearchElement.getBoundingClientRect();
|
|
167
|
-
const offsetFromBottomToElement =
|
|
168
|
-
window.innerHeight - siteSearchElementRect.bottom;
|
|
169
|
-
|
|
170
|
-
if (offsetFromBottomToElement < dropdownHeight) {
|
|
171
|
-
document.body.style.overflow = '';
|
|
172
|
-
|
|
173
|
-
// Scroll to the siteSearchElement
|
|
174
|
-
siteSearchElement.scrollIntoView({
|
|
175
|
-
behavior: 'smooth',
|
|
176
|
-
block: 'start',
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Delay the overflow to allow for smooth scrolling
|
|
180
|
-
setTimeout(() => {
|
|
181
|
-
document.body.style.overflow = 'hidden';
|
|
182
|
-
}, 300);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function closeDropdown() {
|
|
188
|
-
siteSearchElement.classList.remove('is-active');
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function clearInput() {
|
|
192
|
-
closeDropdown();
|
|
193
|
-
siteSearchInput.value = '';
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function handleDropdownKeyboardNavigation(e) {
|
|
197
|
-
// Proceed only if search dropdown is active
|
|
198
|
-
if (!siteSearchWrapper.classList.contains('is-active')) return;
|
|
199
|
-
|
|
200
|
-
if (e.key === 'Escape') {
|
|
201
|
-
removeSearch();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (e.key === 'Tab') {
|
|
206
|
-
const firstElement = siteSearchInput;
|
|
207
|
-
const lastElement =
|
|
208
|
-
siteSearchResults.querySelector('button') ||
|
|
209
|
-
siteSearchResults.querySelector(
|
|
210
|
-
'.site-search-results-item:last-child .result-wrapper'
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
if (e.shiftKey && document.activeElement === firstElement) {
|
|
214
|
-
// Shift + Tab: Move focus to the last element if the first element is currently focused
|
|
215
|
-
e.preventDefault();
|
|
216
|
-
if (lastElement) lastElement.focus();
|
|
217
|
-
} else if (!e.shiftKey && document.activeElement === lastElement) {
|
|
218
|
-
// Tab: Move focus to the first element if the last element is currently focused
|
|
219
|
-
e.preventDefault();
|
|
220
|
-
firstElement.focus();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** @type{Synonyms | null} */
|
|
226
|
-
var _synonyms = null;
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Gets the list of synonyms if they exist
|
|
230
|
-
* @returns { Promise<Synonyms> }
|
|
231
|
-
*/
|
|
232
|
-
async function getSynonyms() {
|
|
233
|
-
if (_synonyms != null) {
|
|
234
|
-
return _synonyms;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
const synonymsModule = await import('./synonyms.js');
|
|
239
|
-
_synonyms = synonymsModule.synonyms;
|
|
240
|
-
} catch {
|
|
241
|
-
_synonyms = {};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return _synonyms ?? {};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Replaces synonyms
|
|
249
|
-
* @param {string[]} queryTerms
|
|
250
|
-
*/
|
|
251
|
-
async function replaceSynonyms(queryTerms) {
|
|
252
|
-
const synonyms = await getSynonyms();
|
|
253
|
-
|
|
254
|
-
for (let i = 0; i < queryTerms.length; i++) {
|
|
255
|
-
const term = queryTerms[i];
|
|
256
|
-
if (synonyms[term] != null) {
|
|
257
|
-
queryTerms.push(synonyms[term]);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return queryTerms;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Search term `s` and number of results `r`
|
|
266
|
-
* @param {string} s
|
|
267
|
-
* @param {number|null} [r=12]
|
|
268
|
-
* @returns
|
|
269
|
-
*/
|
|
270
|
-
async function search(s, r) {
|
|
271
|
-
const numberOfResults = r ?? 12;
|
|
272
|
-
|
|
273
|
-
// Add 'is-active' class when search is performed
|
|
274
|
-
if (s && s.trim().length > 0) {
|
|
275
|
-
activateInput();
|
|
276
|
-
openDropdown();
|
|
277
|
-
} else if (siteSearchElement.classList.contains('is-active')) {
|
|
278
|
-
// Remove 'is-active' class when search is cleared
|
|
279
|
-
closeDropdown();
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** @type {SearchEntry[]} */
|
|
283
|
-
const needles = [];
|
|
284
|
-
|
|
285
|
-
// Clean the input
|
|
286
|
-
const cleanQuery = sanitise(s);
|
|
287
|
-
|
|
288
|
-
if (currentQuery === cleanQuery) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
currentQuery = cleanQuery;
|
|
293
|
-
/** @type {string[]} */
|
|
294
|
-
const stemmedTerms = [];
|
|
295
|
-
const queryTerms = await replaceSynonyms(explode(currentQuery));
|
|
296
|
-
|
|
297
|
-
for (const term of queryTerms) {
|
|
298
|
-
const stemmed = stemmer(term);
|
|
299
|
-
if (stemmed !== term) {
|
|
300
|
-
stemmedTerms.push(stemmed);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const allTerms = queryTerms.concat(stemmedTerms);
|
|
305
|
-
|
|
306
|
-
cleanQuery.length > 0 &&
|
|
307
|
-
haystack.forEach((item) => {
|
|
308
|
-
item.foundWords = 0;
|
|
309
|
-
item.score = 0;
|
|
310
|
-
item.matchedHeadings = [];
|
|
311
|
-
|
|
312
|
-
// The user searches for "Kitchen Sink"
|
|
313
|
-
|
|
314
|
-
// Part 1 - Phrase Matches, i.e. "Kitchen Sink"
|
|
315
|
-
|
|
316
|
-
// Title
|
|
317
|
-
if (item.safeTitle === currentQuery) {
|
|
318
|
-
item.foundWords += 2;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (contains(item.safeTitle, currentQuery)) {
|
|
322
|
-
item.score = item.score + scoring.phraseTitle;
|
|
323
|
-
item.foundWords += 2;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Headings
|
|
327
|
-
item.headings.forEach((c) => {
|
|
328
|
-
if (contains(c.safeText, currentQuery)) {
|
|
329
|
-
item.score = item.score + scoring.phraseHeading;
|
|
330
|
-
item.matchedHeadings.push(c);
|
|
331
|
-
item.foundWords++;
|
|
332
|
-
}
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// Description
|
|
336
|
-
if (contains(item.description, currentQuery)) {
|
|
337
|
-
item.score = item.score + scoring.phraseDescription;
|
|
338
|
-
item.foundWords++;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Part 2 - Term Matches, i.e. "Kitchen" or "Sink"
|
|
342
|
-
|
|
343
|
-
let foundWords = 0;
|
|
344
|
-
|
|
345
|
-
allTerms.forEach((term) => {
|
|
346
|
-
let isTermFound = false;
|
|
347
|
-
|
|
348
|
-
// Title
|
|
349
|
-
if (contains(item.safeTitle, term)) {
|
|
350
|
-
item.score = item.score + scoring.termTitle;
|
|
351
|
-
isTermFound = true;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Headings
|
|
355
|
-
item.headings.forEach((c) => {
|
|
356
|
-
if (contains(c.safeText, term)) {
|
|
357
|
-
item.score = item.score + scoring.termHeading;
|
|
358
|
-
isTermFound = true;
|
|
359
|
-
|
|
360
|
-
if (
|
|
361
|
-
item.matchedHeadings.filter(
|
|
362
|
-
(h) => h.slug == c.slug
|
|
363
|
-
).length == 0
|
|
364
|
-
) {
|
|
365
|
-
item.matchedHeadings.push(c);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
// Description
|
|
371
|
-
if (contains(item.description, term)) {
|
|
372
|
-
isTermFound = true;
|
|
373
|
-
item.score = item.score + scoring.termDescription;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Tags
|
|
377
|
-
item.tags.forEach((t) => {
|
|
378
|
-
if (contains(t, term)) {
|
|
379
|
-
isTermFound = true;
|
|
380
|
-
item.score = item.score + scoring.termTags;
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// Keywords
|
|
385
|
-
if (contains(item.keywords, term)) {
|
|
386
|
-
isTermFound = true;
|
|
387
|
-
item.score = item.score + scoring.termKeywords;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (isTermFound) {
|
|
391
|
-
foundWords++;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
item.foundWords += foundWords;
|
|
396
|
-
|
|
397
|
-
if (item.score > 0) {
|
|
398
|
-
needles.push(item);
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
needles.forEach((n) => {
|
|
403
|
-
// Bonus points for shallow results, i.e. /features over /features/something/something
|
|
404
|
-
|
|
405
|
-
if (n.depth < 5) {
|
|
406
|
-
n.score += scoring.depth;
|
|
407
|
-
n.foundWords++;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (n.depth < 4) {
|
|
411
|
-
n.score += scoring.depth;
|
|
412
|
-
n.foundWords++;
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
needles.sort(function (a, b) {
|
|
417
|
-
if (b.foundWords === a.foundWords) {
|
|
418
|
-
return b.score - a.score;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
return b.foundWords - a.foundWords;
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
const total = needles.reduce(function (accumulator, needle) {
|
|
425
|
-
return accumulator + needle.score;
|
|
426
|
-
}, 0);
|
|
427
|
-
|
|
428
|
-
const results = siteSearchResults;
|
|
429
|
-
|
|
430
|
-
const ul = document.createElement('ul');
|
|
431
|
-
ul.className = 'site-search-results__list';
|
|
432
|
-
|
|
433
|
-
const limit = Math.min(needles.length, numberOfResults);
|
|
434
|
-
|
|
435
|
-
// @ts-ignore
|
|
436
|
-
const siteUrl = new URL(site_url);
|
|
437
|
-
|
|
438
|
-
for (let i = 0; i < limit; i++) {
|
|
439
|
-
const needle = needles[i];
|
|
440
|
-
|
|
441
|
-
const address = new URL(needle.url);
|
|
442
|
-
const isSameHost = siteUrl.host == address.host;
|
|
443
|
-
const url = isSameHost ? address.pathname : needle.url;
|
|
444
|
-
|
|
445
|
-
const listElementWrapper = document.createElement('a');
|
|
446
|
-
listElementWrapper.href = url;
|
|
447
|
-
listElementWrapper.className = 'result-wrapper';
|
|
448
|
-
|
|
449
|
-
const listElementTitle = document.createElement('span');
|
|
450
|
-
// Only highlight user query terms, not stemmed terms
|
|
451
|
-
listElementTitle.innerHTML = highlight(needle.title, queryTerms);
|
|
452
|
-
listElementTitle.className = 'result-title';
|
|
453
|
-
|
|
454
|
-
const path = document.createElement('div');
|
|
455
|
-
path.className = 'result-path';
|
|
456
|
-
|
|
457
|
-
// Split the path into segments, filter out empty segments (in case of leading slash)
|
|
458
|
-
const segments = address.pathname.split('/').filter(Boolean);
|
|
459
|
-
|
|
460
|
-
segments.forEach((segment, index) => {
|
|
461
|
-
const words = segment.replace(/-/g, ' ').split(' ');
|
|
462
|
-
const processedSegment = words
|
|
463
|
-
.map((word, index) =>
|
|
464
|
-
index === 0
|
|
465
|
-
? word.charAt(0).toUpperCase() +
|
|
466
|
-
word.slice(1).toLowerCase()
|
|
467
|
-
: word.toLowerCase()
|
|
468
|
-
)
|
|
469
|
-
.join(' ');
|
|
470
|
-
|
|
471
|
-
const segmentSpan = document.createElement('span');
|
|
472
|
-
segmentSpan.className = 'result-path-segment';
|
|
473
|
-
segmentSpan.textContent = processedSegment;
|
|
474
|
-
path.appendChild(segmentSpan);
|
|
475
|
-
|
|
476
|
-
if (index < segments.length - 1) {
|
|
477
|
-
const svgIcon = document.createElement('span');
|
|
478
|
-
svgIcon.className = 'result-path-icon';
|
|
479
|
-
svgIcon.innerHTML = `
|
|
480
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="10" viewBox="0 0 6 10">
|
|
481
|
-
<path d="M1 9L5 5L1 1" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
482
|
-
</svg>
|
|
483
|
-
`;
|
|
484
|
-
path.appendChild(svgIcon);
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
const listElementDescription = document.createElement('p');
|
|
489
|
-
listElementDescription.className = 'result-description';
|
|
490
|
-
// Only highlight user query terms, not stemmed terms
|
|
491
|
-
listElementDescription.innerHTML = highlight(
|
|
492
|
-
needle.description,
|
|
493
|
-
queryTerms
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
const li = document.createElement('li');
|
|
497
|
-
li.classList.add('site-search-results-item');
|
|
498
|
-
li.dataset.words = needle.foundWords.toString();
|
|
499
|
-
li.dataset.score = (
|
|
500
|
-
Math.round((needle.score / total) * 1000) / 1000
|
|
501
|
-
).toString();
|
|
502
|
-
listElementWrapper.appendChild(path);
|
|
503
|
-
listElementWrapper.appendChild(listElementTitle);
|
|
504
|
-
listElementWrapper.appendChild(listElementDescription);
|
|
505
|
-
li.appendChild(listElementWrapper);
|
|
506
|
-
|
|
507
|
-
if (
|
|
508
|
-
enabled(f.search, 'headings') &&
|
|
509
|
-
needle.matchedHeadings.length > 0
|
|
510
|
-
) {
|
|
511
|
-
const headings = document.createElement('ul');
|
|
512
|
-
headings.className = 'result-headings';
|
|
513
|
-
|
|
514
|
-
headings.tabIndex = 0;
|
|
515
|
-
|
|
516
|
-
needle.matchedHeadings.forEach((h) => {
|
|
517
|
-
const item = document.createElement('li');
|
|
518
|
-
const link = document.createElement('a');
|
|
519
|
-
link.href = url + '#' + h.slug;
|
|
520
|
-
// Only highlight user query terms, not stemmed terms
|
|
521
|
-
link.innerHTML = highlight(h.text, queryTerms);
|
|
522
|
-
item.appendChild(link);
|
|
523
|
-
headings.append(item);
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
li.appendChild(headings);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
ul.appendChild(li);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
let h4;
|
|
533
|
-
if (needles.length === 0) {
|
|
534
|
-
h4 = document.createElement('h4');
|
|
535
|
-
h4.classList.add('search-results-heading');
|
|
536
|
-
h4.innerHTML = results.dataset.emptytitle || 'No Results';
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
const more = document.createElement('button');
|
|
540
|
-
more.className = 'show-more';
|
|
541
|
-
more.type = 'button';
|
|
542
|
-
more.innerHTML = 'See more';
|
|
543
|
-
more.addEventListener('click', async function (e) {
|
|
544
|
-
e.stopPropagation(); // Prevent the click from closing the dropdown
|
|
545
|
-
currentQuery = '';
|
|
546
|
-
const oldTotal = numberOfResults;
|
|
547
|
-
const newTotal = numberOfResults + 12;
|
|
548
|
-
await search(s, newTotal);
|
|
549
|
-
window.setTimeout(function () {
|
|
550
|
-
const previousPosition = qs(
|
|
551
|
-
`.site-search-results__list li:nth-child(${oldTotal}) > a`
|
|
552
|
-
);
|
|
553
|
-
console.log(previousPosition.outerHTML);
|
|
554
|
-
previousPosition.focus();
|
|
555
|
-
}, 10);
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
if (needles.length > numberOfResults) {
|
|
559
|
-
const moreLi = document.createElement('li');
|
|
560
|
-
moreLi.appendChild(more);
|
|
561
|
-
ul.appendChild(moreLi);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
results.innerHTML = '';
|
|
565
|
-
results.appendChild(ul);
|
|
566
|
-
h4 && results.appendChild(h4);
|
|
567
|
-
|
|
568
|
-
const address = window.location.href.split('?')[0];
|
|
569
|
-
window.history.pushState(
|
|
570
|
-
{},
|
|
571
|
-
'',
|
|
572
|
-
address + '?q=' + encodeURIComponent(cleanQuery)
|
|
573
|
-
);
|
|
574
|
-
raiseEvent('searched', { search: s });
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
/** @type {Number} */
|
|
578
|
-
var debounceTimer;
|
|
579
|
-
|
|
580
|
-
function debounceSearch() {
|
|
581
|
-
var input = siteSearchInput;
|
|
582
|
-
|
|
583
|
-
if (input == null) {
|
|
584
|
-
throw new Error('Cannot find data-site-search-query');
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Words chained with . are combined, i.e. System.Text is "systemtext"
|
|
588
|
-
var s = input.value.replace(/\./g, '').trim();
|
|
589
|
-
|
|
590
|
-
if (!s) {
|
|
591
|
-
const address = window.location.href.split('?')[0];
|
|
592
|
-
window.history.pushState({}, '', address);
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
window.clearTimeout(debounceTimer);
|
|
596
|
-
debounceTimer = window.setTimeout(function () {
|
|
597
|
-
if (ready && s) {
|
|
598
|
-
search(s);
|
|
599
|
-
}
|
|
600
|
-
}, 400);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
fetch(dataUrl)
|
|
604
|
-
.then(function (response) {
|
|
605
|
-
return response.json();
|
|
606
|
-
})
|
|
607
|
-
.then(function (data) {
|
|
608
|
-
haystack = data;
|
|
609
|
-
ready = true;
|
|
610
|
-
|
|
611
|
-
for (let i = 0; i < haystack.length; i++) {
|
|
612
|
-
const item = haystack[i];
|
|
613
|
-
item.safeTitle = sanitise(item.title);
|
|
614
|
-
item.tags = item.tags.map((t) => sanitise(t));
|
|
615
|
-
item.safeDescription = sanitise(item.description);
|
|
616
|
-
item.depth = item.url.match(/\//g)?.length ?? 0;
|
|
617
|
-
|
|
618
|
-
item.headings.forEach((h) => (h.safeText = sanitise(h.text)));
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
/** @type {HTMLFormElement} */
|
|
622
|
-
const siteSearch = siteSearchElement;
|
|
623
|
-
|
|
624
|
-
/** @type {HTMLInputElement} */
|
|
625
|
-
const siteSearchQuery = siteSearchInput;
|
|
626
|
-
|
|
627
|
-
if (siteSearch == null || siteSearchQuery == null) {
|
|
628
|
-
throw new Error(
|
|
629
|
-
'Cannot find #site-search or data-site-search-query'
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
siteSearch.addEventListener('submit', function (e) {
|
|
634
|
-
e.preventDefault();
|
|
635
|
-
debounceSearch();
|
|
636
|
-
return false;
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
siteSearchQuery.addEventListener('keyup', function (e) {
|
|
640
|
-
e.preventDefault();
|
|
641
|
-
if (!scrolled) {
|
|
642
|
-
scrolled = true;
|
|
643
|
-
this.scrollIntoView(true);
|
|
644
|
-
}
|
|
645
|
-
debounceSearch();
|
|
646
|
-
return false;
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
const params = new URLSearchParams(window.location.search);
|
|
650
|
-
if (params.has('q')) {
|
|
651
|
-
siteSearchQuery.value = params.get('q') ?? '';
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
for (let key of Object.keys(scoring)) {
|
|
655
|
-
if (params.has(`s_${key}`)) {
|
|
656
|
-
scoring[key] = parseInt(
|
|
657
|
-
params.get(`s_${key}`) ?? scoring[key].toString(),
|
|
658
|
-
10
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
debounceSearch();
|
|
664
|
-
})
|
|
665
|
-
.catch((error) => {
|
|
666
|
-
console.log(error);
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
if (document.readyState === 'loading') {
|
|
671
|
-
// Loading hasn't finished yet
|
|
672
|
-
document.addEventListener('DOMContentLoaded', initializeSearch);
|
|
673
|
-
} else {
|
|
674
|
-
// `DOMContentLoaded` has already fired
|
|
675
|
-
initializeSearch();
|
|
676
|
-
}
|