diff --git a/database.go b/database.go index 64e41f2..e93a2a8 100644 --- a/database.go +++ b/database.go @@ -13,12 +13,12 @@ import ( ) type Database struct { - Keys []string + Titles map[string]string Entries map[string]string matcher *search.Matcher } -func (db *Database) search(query string) []string { // returns keys (entry names) +func (db *Database) searchForIds(query string) []string { // returns keys (entry names) results := []string{} // compile patterns queryPatterns := []*search.Pattern{} @@ -26,16 +26,18 @@ func (db *Database) search(query string) []string { // returns keys (entry names queryPatterns = append(queryPatterns, db.matcher.CompileString(q)) } // search - for _, k := range db.Keys { + for k, v := range db.Entries { // title (k) - if strings.Contains(k, query) || strings.Contains(query, k) { + titleLower := strings.ToLower(db.Titles[k]) + queryLower := strings.ToLower(query) + if strings.Contains(titleLower, queryLower) { results = append(results, k) continue } // content body patternsFound := 0 for _, p := range queryPatterns { - if s, _ := p.IndexString(db.Entries[k]); s != -1 { + if s, _ := p.IndexString(v); s != -1 { patternsFound++ // this pattern was found } } @@ -44,6 +46,7 @@ func (db *Database) search(query string) []string { // returns keys (entry names results = append(results, k) } } + slices.Sort(results) return results } @@ -58,8 +61,10 @@ func BuildDB(directory string) Database { entriesDirFs := os.DirFS(directory) files, err := fs.Glob(entriesDirFs, "*.txt") if err != nil { logger.Panicln(err) } - titles := []string{} + titles := map[string]string{} for _, f := range files { + k := f[:len(f)-4] // remove ".txt" + k = strings.ReplaceAll(k, "|", "_") // we don't want | because it is used in the search protocol fileData, err := os.ReadFile(directory + "/" + f) if err != nil { logger.Panicln(err) } content := string(fileData) @@ -80,14 +85,13 @@ func BuildDB(directory string) Database { if len(body) < 1 { body = " " } - titles = append(titles, title) - entries[title] = body + titles[k] = title + entries[k] = body } else { - title := f[:len(f)-4] // remove ".txt" - titles = append(titles, title) - entries[title] = content + titles[k] = k + entries[k] = content } } matcher := search.New(ContentLanguage, search.IgnoreCase, search.IgnoreDiacritics) - return Database{Keys: titles, Entries: entries, matcher: matcher} + return Database{Titles: titles, Entries: entries, matcher: matcher} } diff --git a/main.go b/main.go index 0c87e4d..c2d4639 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ var db Database type TemplateData struct { Title string SiteDescription string - TOC []string + TOC map[string]string EntryTitle string Entry string Footer []template.HTML @@ -33,10 +33,10 @@ func loadTemplate() { func handleApplication(w http.ResponseWriter, req *http.Request) { var entry string var err error - entryName := path.Base(req.URL.Path) - if entryName != "/" { + entryId := path.Base(req.URL.Path) + if entryId != "/" { // load entry - entry = db.Entries[entryName] + entry = db.Entries[entryId] if entry == "" { // redirect if entry doesn't exist (or is empty) http.Redirect(w, req, "/", http.StatusTemporaryRedirect) } @@ -44,10 +44,10 @@ func handleApplication(w http.ResponseWriter, req *http.Request) { err = appTemplate.ExecuteTemplate( w, "app", TemplateData{ - TOC: db.Keys, + TOC: db.Titles, Entry: entry, Title: MainTitle, - EntryTitle: entryName, + EntryTitle: db.Titles[entryId], Footer: FooterContent, SiteDescription: SiteDescription, }) @@ -60,7 +60,10 @@ func handleSearchAPI(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusBadRequest) return } - results := db.search(searchQuery) + results := db.searchForIds(searchQuery) + for i, r := range results { + results[i] = r + "|" + db.Titles[r] + } w.Write([]byte(strings.Join(results, "\n"))) } diff --git a/public/index.html b/public/index.html index 0b3b3b4..62d0e0f 100644 --- a/public/index.html +++ b/public/index.html @@ -25,8 +25,8 @@
- {{- range .TOC -}} -
{{ . }}
+ {{- range $k, $title := .TOC -}} +
{{ $title }}
{{- end -}}
diff --git a/public/static/search.js b/public/static/search.js index ca77feb..3f726f8 100644 --- a/public/static/search.js +++ b/public/static/search.js @@ -7,30 +7,31 @@ /** * @param {string} results */ - function updateSearchResults(results) { + function showSearchResults(results) { + searchResults.innerHTML = ""; if (results.length > 0) { - searchResults.innerHTML = ""; - for (let i = 0; i < results.length; i++) { + results.forEach(r => { let resultElem = document.createElement("div"); let resultAnchor = document.createElement("a"); - resultAnchor.href = results[i]; // we should be at /, so this is right - resultAnchor.innerText = results[i]; + resultAnchor.href = r[0]; // we should be at /, so this is right + resultAnchor.innerText = r[1]; resultElem.appendChild(resultAnchor); searchResults.appendChild(resultElem); - } - toc.classList.add("hidden"); - searchResults.classList.remove("hidden"); - } else { - toc.classList.remove("hidden"); - searchResults.classList.add("hidden"); + }); } + toc.classList.add("hidden"); + searchResults.classList.remove("hidden"); + } + function hideSearchResults() { + toc.classList.remove("hidden"); + searchResults.classList.add("hidden"); } async function handleSearchInput() { // get search query const query = searchBox.value; if (query == "") { - updateSearchResults([]); + hideSearchResults(); return } // make request @@ -38,8 +39,14 @@ if (!response.ok) { throw new Error(`Search API returned status code ${response.status}`); } - let result = await response.text(); - updateSearchResults(result.split('\n')); + let results_raw = await response.text(); + let results = []; + if (results_raw.length > 0) { + results_raw.split('\n').forEach(r => { + results.push(r.split("|", 2)); + }); + } + showSearchResults(results); } searchBox.addEventListener("input", handleSearchInput);