-
Notifications
You must be signed in to change notification settings - Fork 2
/
search.html
155 lines (130 loc) · 5.07 KB
/
search.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
---
title: Search
layout: default
---
<script src="https://cdn.rawgit.com/nextapps-de/bulksearch/master/bulksearch.min.js"></script>
<script src="/data/documents.js"></script>
<script defer type="text/javascript">
//
// HTML templates to populate page with search results
//
const SEARCH_RESULT_TEMPLATE = '\
<article class="mt-10 mb-16">\
<header><a href="$DOC_URL">$DOC_TITLE</a></header>\
<body class="font-normal block">$DOC_PREVIEW</body>\
<div class="mt-1">$TAGS</div>\
</article>'
const TAG_TEMPLATE = '\
<span class="mr-3 inline-flex items-center px-3 py-1 rounded-md border-gray-300 text-gray-400 border font-medium uppercase text-xs tracking-wider">\
$TAG\
</span>'
//
// Index all posts that are autogenerated as JSON objects in /data/documents.js
//
const index = new BulkSearch();
documents.forEach((doc, i) => index.add(i, doc.body))
window.onload = function() {
let pos = window.location.hash.indexOf('q=')
let query = window.location.hash.substring(pos + 2)
query = decodeURI(query)
document.getElementById('search_input').value = query
if (query.length) {
search(query)
}
}
//
// Search function to query index for matching documents.
//
function search(query) {
window.location.hash = '#q=' + encodeURI(query)
const element = document.getElementById('search_results')
const results = index.search(query, { suggest: true })
// populates the "XX matching results" text below search box
showResultCount(results.length)
// show search result links and previews
element.innerHTML = results
.slice(0, 20)
.map(i => documents[i])
.map(doc => {
doc.preview = createPreview(query, doc.body)
const tags = (doc.tags)
? doc.tags
.split(',')
.map(tag => TAG_TEMPLATE.replace('$TAG', tag))
.join('')
: ''
return SEARCH_RESULT_TEMPLATE
.replace('$DOC_URL' , doc.url)
.replace('$DOC_TITLE' , doc.title)
.replace('$DOC_PREVIEW' , doc.preview)
.replace('$TAGS' , tags)
})
.join('')
}
//
// populates the "XX matching results" text below search box
//
function showResultCount(count) {
const element = document.getElementById('search_count')
element.innerHTML = count + ' matching results'
}
//
// Generates a short preview of the matching document.
//
function createPreview(query, text) {
const idx = new BulkSearch();
const chunks = splitByWordCount(text, 16, 64)
chunks.forEach((chunk, i) => idx.add(i, chunk))
const result = idx.search(query)
.slice(0, 1)
.map(i => {
const prefix = []
const suffix = []
// copy before the matching text to better show context.
for (let k = i - 1; k >= 0 && prefix.reduce((p, c) => p + c.replace(/\s+/g, '').length, 0) < 64; k--) {
prefix.push(chunks[k])
}
// copy after the matching text to better show context.
for (let k = i + 1; k < chunks.length && suffix.reduce((p, c) => p + c.replace(/\s+/g, '').length, 0) < 64; k++) {
suffix.push(chunks[k])
}
// return the before, match, and after texts
return [
prefix.join('|'),
chunks[i],
suffix.join('|')
].join(' ')
})
.pop()
return result || chunks.slice(0, 2).join(' ')
}
// https://stackoverflow.com/questions/40817167/splitting-a-string-into-an-array-of-n-words
function splitByWordCount(str, count, min) {
var arr = str.split(' ')
var r = [];
while (arr.length) {
r.push(arr.splice(0, count).join(' '))
}
return r;
}
</script>
<form x-data="{ $query : '' }" @submit.prevent="search($query)" >
<!--<label for="email" class="block text-sm font-medium text-gray-700">Search candidates</label>-->
<div class="mt-1 flex shadow-md">
<div class="relative flex items-stretch flex-grow focus-within:z-10">
<!-- <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z" />
</svg>
</div> -->
<input type="text" id="search_input" x-model="$query" autofocus class="focus:outline-none focus:border-gray-300 focus:ring-0 block w-full p-3 sm:text-base border-gray-300" placeholder="What are you looking for?">
</div>
<button type="submit" class="-ml-px relative inline-flex items-center space-x-2 px-4 py-2 border border-gray-300 text-sm font-medium text-gray-700 bg-gray-50 hover:bg-gray-100 ">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</button>
</div>
</form>
<div class="font-medium uppercase text-sm tracking-wider mt-3 text-mol-aqua" id="search_count"></div>
<div id="search_results" class="font-normal"></div>