From b0430e4915785c266f6f8c3e7037926b8ee56552 Mon Sep 17 00:00:00 2001 From: Torey <torey.scheer@solo.io> Date: Mon, 10 Jun 2024 09:18:06 -0400 Subject: [PATCH 1/4] Fixed flexsearch freezing when using `tokenize:full` --- layouts/partials/docs/footer/flexsearch.html | 310 ++++++++++--------- 1 file changed, 169 insertions(+), 141 deletions(-) diff --git a/layouts/partials/docs/footer/flexsearch.html b/layouts/partials/docs/footer/flexsearch.html index 3d252ff1..3d477475 100644 --- a/layouts/partials/docs/footer/flexsearch.html +++ b/layouts/partials/docs/footer/flexsearch.html @@ -39,12 +39,11 @@ }; document.addEventListener('click', function(event) { + var isClickInsideElement = suggestions.contains(event.target); - var isClickInsideElement = suggestions.contains(event.target); - - if (!isClickInsideElement) { + if (!isClickInsideElement) { suggestions.classList.add('d-none'); - } + } }); @@ -82,29 +81,61 @@ - https://github.com/nextapps-de/flexsearch#index-documents-field-search - https://raw.githack.com/nextapps-de/flexsearch/master/demo/autocomplete.html */ - (function(){ - - var indexSectionMap = {}; - function getIndex(section) { - if (!indexSectionMap[section]) { - indexSectionMap[section] = new FlexSearch.Document({ - // charset: "latin:default", - tokenize: {{ .Site.Params.flexsearch.tokenize | default "forward" }}, - minlength: {{ .Site.Params.flexsearch.minQueryChar | default 0}}, - cache: {{ .Site.Params.flexsearch.cache | default 100 }}, - optimize: {{ .Site.Params.flexsearch.optimize | default true }}, - document: { - id: 'id', - store: [ - "href", "title", "description" - ], - index: ["title", "description", "content"] - } - }); + const siteFlexJson = JSON.parse({{ .Site.Params.flexsearch | jsonify }}); + const siteFlexConfig = { + enabled: siteFlexJson.enabled ?? true, + tokenize: siteFlexJson.tokenize ?? "full", + minLength: siteFlexJson.minquerychar ?? 0, + cache: siteFlexJson.cache ?? 100, + maxResult: siteFlexJson.maxresult ?? 5, + searchSectionsIndex: siteFlexJson.searchsectionsindex ?? [], + }; + + var indexSectionMap = {}; + function getIndex(section) { + if (!indexSectionMap[section]) { + indexSectionMap[section] = new FlexSearch.Document({ + // charset: "latin:default", + tokenize: siteFlexConfig.tokenize, + minlength: siteFlexConfig.minLength, + cache: siteFlexConfig.cache, + optimize: siteFlexConfig.optimize, + document: { + id: 'id', + store: ["href", "title", "description"], + index: ["title", "description", "content"] } - return indexSectionMap[section]; + }); } + return indexSectionMap[section]; + } + + ///////////////////////// + // Index ID Gen + ///////////////////////// + const versionSubversionMap = {}; + {{ if .Site.Params.versions }} + {{ range .Site.Params.versions }} + {{ $version := .linkVersion }} + versionSubversionMap[{{$version}}] = []; + {{ if .subversions }} + {{ range .subversions }} + versionSubversionMap[{{$version}}].push({{.id}}); + {{ end }} + {{ end }} + {{ end }} + {{ end }} + + function getIndexIdOfCurrentPage() { + // There doesn't seem to be a perfect way to detect "Section" via JS, but + // this should work by finding any cases where something in url exists in search index key + const curSection = window.location.pathname.replace(/^\//, '').split('/') + .find(part=>!!versionSubversionMap[part]) || "{{ .Site.Params.version }}" || 'main'; + const curSubversion = window.location.pathname.replace(/^\//, '').split('/') + .find(part=>!!versionSubversionMap[curSection].includes(part)) || ""; + return curSection+'-'+curSubversion; + } // Not yet supported: https://github.com/nextapps-de/flexsearch#complex-documents @@ -112,142 +143,139 @@ // var docs = [ // {{ range $index, $page := (where .Site.Pages "Section" "docs") -}} - // { - // id: {{ $index }}, - // href: {{ .Permalink }}, - // title: {{ .Title }}, - // description: {{ .Params.description }}, - // content: {{ .Content }} - // }, + // { id: {{ $index }}, href: {{ .Permalink }}, title: {{ .Title }}, description: {{ .Params.description }}, content: {{ .Content }} }, // {{ end -}} // ]; - - // https://discourse.gohugo.io/t/range-length-or-last-element/3803/2 - - // {{ $list := slice }} - // {{- if and (isset .Site.Params.flexsearch "searchsectionsindex") (not (eq (len .Site.Params.flexsearch.searchSectionsIndex) 0)) }} - // {{- if eq .Site.Params.docs.searchSectionsIndex "ALL" }} - // {{- $list = .Site.Pages }} - // {{- else }} - // {{- $list = (where .Site.Pages "Type" "in" .Site.Params.flexsearch.searchSectionsIndex) }} - // {{- if (in .Site.Params.flexsearch.searchSectionsIndex "HomePage") }} - // {{ $list = $list | append .Site.Home }} - // {{- end }} - // {{- end }} - // {{- else }} - // {{ $version := .Site.Params.version }} - // {{- $list = (where .Site.Pages "Section" $version) }} - // {{- end }} - - {{ $list := .Site.Pages }} - - {{ range $index, $element := $list -}} - {{ $subversion := or .Params.Params.subversion "" }} - {{ range .Ancestors -}} - {{ if .Params.Params.subversion }} - {{ $subversion = .Params.Params.subversion }} - {{ end }} - {{ end -}} - getIndex("{{ .Section }}-{{ $subversion }}").add( - { - id: {{ $index }}, - href: "{{ .RelPermalink }}", - title: {{ .Title }}, - {{ with .Description -}} - description: {{ . }}, - {{ else -}} - description: {{ .Summary | htmlUnescape | plainify }}, - {{ end -}} - {{ $keywords := "" -}} - {{ with .Keywords -}} - {{ $keywords = delimit . ", " }} - {{ end -}} - content: "{{ $keywords }}" - // content: {{ .Content | htmlUnescape | plainify }} - } - ); - {{ end -}} - - const versionSubversionMap = {}; - {{ if .Site.Params.versions }} - {{ range .Site.Params.versions }} - {{ $version := .linkVersion }} - versionSubversionMap[{{$version}}] = []; - {{ if .subversions }} - {{ range .subversions }} - versionSubversionMap[{{$version}}].push({{.id}}); + function populateIndex() { + // https://discourse.gohugo.io/t/range-length-or-last-element/3803/2 + + // {{ $list := slice }} + // {{- if and (isset .Site.Params.flexsearch "searchsectionsindex") (not (eq (len .Site.Params.flexsearch.searchSectionsIndex) 0)) }} + // {{- if eq .Site.Params.docs.searchSectionsIndex "ALL" }} + // {{- $list = .Site.Pages }} + // {{- else }} + // {{- $list = (where .Site.Pages "Type" "in" .Site.Params.flexsearch.searchSectionsIndex) }} + // {{- if (in .Site.Params.flexsearch.searchSectionsIndex "HomePage") }} + // {{ $list = $list | append .Site.Home }} + // {{- end }} + // {{- end }} + // {{- else }} + // {{ $version := .Site.Params.version }} + // {{- $list = (where .Site.Pages "Section" $version) }} + // {{- end }} + + const indexDocItemList = []; + + {{ $list := .Site.Pages }} + {{ range $index, $element := $list -}} + {{ $subversion := or .Params.Params.subversion "" }} + {{ range .Ancestors -}} + {{ if .Params.Params.subversion }} + {{ $subversion = .Params.Params.subversion }} {{ end }} - {{ end }} - {{ end }} - {{ end }} + {{ end -}} + + {{ $description := "" }} + {{ with .Description -}} + {{ $description = . }} + {{ else -}} + {{ $description = .Summary | htmlUnescape | plainify }} + {{ end -}} + + {{ $keywords := "" -}} + {{ with .Keywords -}} + {{ $keywords = delimit . ", " }} + {{ end -}} + + indexDocItemList.push([ + "{{ .Section }}-{{ $subversion }}", + { + id: {{ $index }}, + href: "{{ .RelPermalink }}", + title: {{ .Title }}, + description: {{ $description }}, + // content: "{{ $keywords }}" + content: {{ .Content | htmlUnescape | plainify }} + } + ]); + {{ end -}} + + const currentPageIndexId = getIndexIdOfCurrentPage(); + for(const [indexId, doc] of indexDocItemList) { + if(indexId != currentPageIndexId) continue; + // Words that are to long cause flexsearch to freeze, so remove them from text we give to index + doc.content = doc.content.replaceAll(/\w{40,}/g, '-'); + getIndex(indexId).add(doc); + } + } + populateIndex(); - search.addEventListener('input', show_results, true); + search.addEventListener('input', find_results, true); - function show_results(){ - const maxResult = {{ .Site.Params.flexsearch.maxResult | default 5}}; - const minlength = {{ .Site.Params.flexsearch.minQueryChar | default 0}}; - var searchQuery = this.value; - // There doesn't seem to be a perfect way to detect "Section" via JS, but - // this should work by finding any cases where something in url exists in search index key - const curSection = window.location.pathname.replace(/^\//, '').split('/') - .find(part=>!!versionSubversionMap[part]) || "{{ .Site.Params.version }}" || 'main'; - const curSubversion = window.location.pathname.replace(/^\//, '').split('/') - .find(part=>!!versionSubversionMap[curSection].includes(part)) || ""; - var index = getIndex(curSection+'-'+curSubversion); - var results = index.search(searchQuery, {limit: maxResult, enrich: true}); + function find_results(){ + var searchQuery = this.value; + + suggestions.innerHTML = ""; + suggestions.classList.remove('d-none'); - // flatten results since index.search() returns results for each indexed field - const flatResults = new Map(); // keyed by href to dedupe results - for (const result of results.flatMap(r => r.result)) { + // inform user of search query minimum character requirement + const minlength = siteFlexConfig.minLength; + if (searchQuery.length < minlength) { + const minCharMessage = document.createElement('div') + minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters` + minCharMessage.classList.add("suggestion__no-results"); + suggestions.appendChild(minCharMessage); + return; + } + + var index = getIndex(getIndexIdOfCurrentPage()); + var results = index.search(searchQuery, { limit: siteFlexConfig.maxResult, enrich: true }); + show_results(results, searchQuery); + } + function show_results(results, searchQuery){ + // flatten results since index.search() returns results for each indexed field + const flatResults = new Map(); // keyed by href to dedupe results + for (const result of results.flatMap(r => r.result)) { if (flatResults.has(result.doc.href)) continue; flatResults.set(result.doc.href, result.doc); - } + } - suggestions.innerHTML = ""; - suggestions.classList.remove('d-none'); + suggestions.innerHTML = ""; + suggestions.classList.remove('d-none'); - // inform user of search query minimum character requirement - if (searchQuery.length < minlength) { - const minCharMessage = document.createElement('div') - minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters` - minCharMessage.classList.add("suggestion__no-results"); - suggestions.appendChild(minCharMessage); + // inform user that no results were found + if (flatResults.size === 0 && searchQuery) { + const noResultsMessage = document.createElement('div') + noResultsMessage.innerHTML = {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"` + noResultsMessage.classList.add("suggestion__no-results"); + suggestions.appendChild(noResultsMessage); return; - } else { - // inform user that no results were found - if (flatResults.size === 0 && searchQuery) { - const noResultsMessage = document.createElement('div') - noResultsMessage.innerHTML = {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"` - noResultsMessage.classList.add("suggestion__no-results"); - suggestions.appendChild(noResultsMessage); - return; - } } - // construct a list of suggestions - for(const [href, doc] of flatResults) { - const entry = document.createElement('div'); - suggestions.appendChild(entry); + // construct a list of suggestions + for(const [href, doc] of flatResults) { + const entry = document.createElement('div'); + suggestions.appendChild(entry); - const a = document.createElement('a'); - a.href = href; - entry.appendChild(a); + const a = document.createElement('a'); + a.href = href; + entry.appendChild(a); - const title = document.createElement('span'); - title.textContent = doc.title; - title.classList.add("suggestion__title"); - a.appendChild(title); + const title = document.createElement('span'); + title.textContent = doc.title; + title.classList.add("suggestion__title"); + a.appendChild(title); - const description = document.createElement('span'); - description.textContent = doc.description; - description.classList.add("suggestion__description"); - a.appendChild(description); + const description = document.createElement('span'); + description.textContent = doc.description; + description.classList.add("suggestion__description"); + a.appendChild(description); - suggestions.appendChild(entry); + suggestions.appendChild(entry); - if(suggestions.childElementCount == maxResult) break; - } + if(suggestions.childElementCount == siteFlexConfig.maxResult) break; + } } }()); </script> From 3495d128f2c38f94abb0514aaeb1b31e9b074da6 Mon Sep 17 00:00:00 2001 From: Torey <torey.scheer@solo.io> Date: Mon, 10 Jun 2024 15:31:34 -0400 Subject: [PATCH 2/4] flexsearch entry description now contains search term, bolded --- .../plugins/flexsearch/_flexsearch.scss | 1 + layouts/partials/docs/footer/flexsearch.html | 253 +++++++++++------- 2 files changed, 162 insertions(+), 92 deletions(-) diff --git a/assets/docs/scss/custom/plugins/flexsearch/_flexsearch.scss b/assets/docs/scss/custom/plugins/flexsearch/_flexsearch.scss index 678961c5..b275f606 100644 --- a/assets/docs/scss/custom/plugins/flexsearch/_flexsearch.scss +++ b/assets/docs/scss/custom/plugins/flexsearch/_flexsearch.scss @@ -231,6 +231,7 @@ .suggestion__description, .suggestion__no-results { + display: block; color: var(--flexsearch-suggestion-desc-color); } diff --git a/layouts/partials/docs/footer/flexsearch.html b/layouts/partials/docs/footer/flexsearch.html index 3d477475..7c28f965 100644 --- a/layouts/partials/docs/footer/flexsearch.html +++ b/layouts/partials/docs/footer/flexsearch.html @@ -92,6 +92,9 @@ searchSectionsIndex: siteFlexJson.searchsectionsindex ?? [], }; + ///////////////////////// + // Create Index + ///////////////////////// var indexSectionMap = {}; function getIndex(section) { if (!indexSectionMap[section]) { @@ -103,8 +106,8 @@ optimize: siteFlexConfig.optimize, document: { id: 'id', - store: ["href", "title", "description"], - index: ["title", "description", "content"] + store: ["href", "title", "description", "content"], + index: ["title", "description", "keywords", "content"] } }); } @@ -137,17 +140,10 @@ return curSection+'-'+curSubversion; } + ///////////////////////// + // Populate Index + ///////////////////////// - // Not yet supported: https://github.com/nextapps-de/flexsearch#complex-documents - - - // var docs = [ - // {{ range $index, $page := (where .Site.Pages "Section" "docs") -}} - // { id: {{ $index }}, href: {{ .Permalink }}, title: {{ .Title }}, description: {{ .Params.description }}, content: {{ .Content }} }, - // {{ end -}} - // ]; - - function populateIndex() { // https://discourse.gohugo.io/t/range-length-or-last-element/3803/2 // {{ $list := slice }} @@ -165,98 +161,106 @@ // {{- $list = (where .Site.Pages "Section" $version) }} // {{- end }} - const indexDocItemList = []; - - {{ $list := .Site.Pages }} - {{ range $index, $element := $list -}} - {{ $subversion := or .Params.Params.subversion "" }} - {{ range .Ancestors -}} - {{ if .Params.Params.subversion }} - {{ $subversion = .Params.Params.subversion }} - {{ end }} - {{ end -}} - - {{ $description := "" }} - {{ with .Description -}} - {{ $description = . }} - {{ else -}} - {{ $description = .Summary | htmlUnescape | plainify }} - {{ end -}} - - {{ $keywords := "" -}} - {{ with .Keywords -}} - {{ $keywords = delimit . ", " }} - {{ end -}} - - indexDocItemList.push([ - "{{ .Section }}-{{ $subversion }}", - { - id: {{ $index }}, - href: "{{ .RelPermalink }}", - title: {{ .Title }}, - description: {{ $description }}, - // content: "{{ $keywords }}" - content: {{ .Content | htmlUnescape | plainify }} - } - ]); - {{ end -}} - - const currentPageIndexId = getIndexIdOfCurrentPage(); - for(const [indexId, doc] of indexDocItemList) { - if(indexId != currentPageIndexId) continue; - // Words that are to long cause flexsearch to freeze, so remove them from text we give to index - doc.content = doc.content.replaceAll(/\w{40,}/g, '-'); - getIndex(indexId).add(doc); - } - } - populateIndex(); - - search.addEventListener('input', find_results, true); + const indexDocItemList = []; - function find_results(){ - var searchQuery = this.value; + {{ $list := .Site.Pages }} + {{ range $index, $element := $list -}} + {{ $subversion := or .Params.Params.subversion "" }} + {{ range .Ancestors -}} + {{ if .Params.Params.subversion }} + {{ $subversion = .Params.Params.subversion }} + {{ end }} + {{ end -}} + + {{ $description := "" }} + {{ with .Description -}} + {{ $description = . }} + {{ else -}} + {{ $description = .Summary | htmlUnescape | plainify }} + {{ end -}} + + {{ $keywords := "" -}} + {{ with .Keywords -}} + {{ $keywords = delimit . ", " }} + {{ end -}} + + indexDocItemList.push([ + "{{ .Section }}-{{ $subversion }}", + { + id: {{ $index }}, + href: "{{ .RelPermalink }}", + title: {{ .Title }}, + description: {{ $description }}, + keywords: "{{ $keywords }}", + content: {{ .Content | htmlUnescape | plainify }} + } + ]); + {{ end -}} + + const currentPageIndexId = getIndexIdOfCurrentPage(); + for(const [indexId, doc] of indexDocItemList) { + if(indexId != currentPageIndexId) continue; + // Words that are to long cause flexsearch to freeze, so remove them from text we give to index + doc.content = doc.content.replaceAll(/\w{40,}/g, '-'); + getIndex(indexId).add(doc); + } - suggestions.innerHTML = ""; - suggestions.classList.remove('d-none'); + ///////////////////////// + // Search Logic + ///////////////////////// + search.addEventListener('input', find_results, true); + + function find_results(){ + var searchQuery = this.value; + + suggestions.innerHTML = ""; + suggestions.classList.remove('d-none'); + + // inform user of search query minimum character requirement + const minlength = siteFlexConfig.minLength; + if (searchQuery.length < minlength) { + const minCharMessage = document.createElement('div') + minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters` + minCharMessage.classList.add("suggestion__no-results"); + suggestions.appendChild(minCharMessage); + return; + } - // inform user of search query minimum character requirement - const minlength = siteFlexConfig.minLength; - if (searchQuery.length < minlength) { - const minCharMessage = document.createElement('div') - minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters` - minCharMessage.classList.add("suggestion__no-results"); - suggestions.appendChild(minCharMessage); - return; + var index = getIndex(getIndexIdOfCurrentPage()); + var results = index.search(searchQuery, { limit: siteFlexConfig.maxResult, enrich: true }); + show_results(results, searchQuery); } - var index = getIndex(getIndexIdOfCurrentPage()); - var results = index.search(searchQuery, { limit: siteFlexConfig.maxResult, enrich: true }); - show_results(results, searchQuery); - } - function show_results(results, searchQuery){ - // flatten results since index.search() returns results for each indexed field - const flatResults = new Map(); // keyed by href to dedupe results - for (const result of results.flatMap(r => r.result)) { - if (flatResults.has(result.doc.href)) continue; - flatResults.set(result.doc.href, result.doc); - } + function show_results(results, searchQuery){ + // flatten results since index.search() returns results for each indexed field + const flatResults = new Map(); // keyed by href to dedupe results + for (const result of results.flatMap(r => r.result)) { + if (flatResults.has(result.doc.href)) continue; + flatResults.set(result.doc.href, result.doc); + } - suggestions.innerHTML = ""; - suggestions.classList.remove('d-none'); + suggestions.innerHTML = ""; + suggestions.classList.remove('d-none'); // inform user that no results were found if (flatResults.size === 0 && searchQuery) { const noResultsMessage = document.createElement('div') - noResultsMessage.innerHTML = {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"` + noResultsMessage.innerHTML = getNoResultsMessage(searchQuery); noResultsMessage.classList.add("suggestion__no-results"); suggestions.appendChild(noResultsMessage); return; } - // construct a list of suggestions - for(const [href, doc] of flatResults) { + // construct a list of suggestions + for(const [href, doc] of flatResults) { + suggestions.appendChild( createSuggestion(doc, href, searchQuery) ); + if(suggestions.childElementCount == siteFlexConfig.maxResult) break; + } + } + + function createSuggestion(doc, href, searchQuery) { + const queryWords = searchQuery.trim().split(' '); const entry = document.createElement('div'); - suggestions.appendChild(entry); const a = document.createElement('a'); a.href = href; @@ -268,14 +272,79 @@ a.appendChild(title); const description = document.createElement('span'); - description.textContent = doc.description; + description.innerHTML = getSuggestionDescription(doc, queryWords); description.classList.add("suggestion__description"); a.appendChild(description); - suggestions.appendChild(entry); + return entry; + } - if(suggestions.childElementCount == siteFlexConfig.maxResult) break; + function getSuggestionDescription(doc, queryWords) { + // For the description, we should do the following: + // - If the `doc` description contains all search terms, show that (and highlight them all in that message) + // - otherwise try to find them in body, and highlight setence fragment of first instance when found + // - else if none found in body (perhaps word only in title/keywords, or regex didn't find it), fallback to description (and highlight any that are found) + let desc = doc.description; + if(stringContainsAllFuzzyWords(doc.description, queryWords)) { + desc = highlightFuzzyWordsInString(doc.description, queryWords); + } else { + // Find indiviudal segments that contain the search terms + const matchedSegments = queryWords.map(queryWord=>{ + const match = doc.content.match(new RegExp(`(\\W?)(\\w*${queryWord}\\w*)(\\W?)`, 'i')); + if(match) { + try { + let string = ''; + const { [0]:fullmatch, index } = match; + if(index > 0) { + // we want words before the matched word - ignore the earliest one though, since it will likely not be a full word. + string += doc.content.substring(index-30, index).trim().split(' ').slice(1).join(' '); + } + string += fullmatch; + + const indexAfter = index + fullmatch.length; + // we want words after the matched word - ignore the last one though, since it will likely not be a full word. + string += doc.content.substring(indexAfter, indexAfter+30).trim().split(' ').slice(0, -1).join(' '); + + return string.trim(); + } + catch(e){} + } + return null; + }).filter(s=>!!s); + + // See if one of the returned segments contains all search terms, and if so return only that one with all words highlighted in it + const singleSegmentIfOneExists = matchedSegments.find(segment=>stringContainsAllFuzzyWords(segment, queryWords)); + if(!matchedSegments.length) { + desc = highlightFuzzyWordsInString(doc.description, queryWords); + } + else if(singleSegmentIfOneExists) { + desc = highlightFuzzyWordsInString(singleSegmentIfOneExists, queryWords); + } + else { + desc = matchedSegments.map(str=>highlightFuzzyWordsInString(str, queryWords)).join('<hr />'); + } + } + return desc; + } + + function stringContainsAllFuzzyWords(string, words) { + string = string.toLowerCase(); + return words.every(w=>string.includes(w.toLowerCase())) + } + + function highlightFuzzyWordsInString(string, words) { + words.forEach(queryWord=>{ + const match = string.match(new RegExp(`(\\W?)(\\w*${queryWord}\\w*)(\\W?)`, 'i')); + if(match) { + const { [0]:fullmatch, [1]:pre, [2]:word, [3]:suff, index } = match; + string = string.substring(0, index) + `${pre}<b>${word}</b>${suff}` + string.substring(index+fullmatch.length); + } + }); + return string; + } + + function getNoResultsMessage(searchQuery) { + return {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"`; } - } }()); </script> From b2542ed119ed1f1dce070f012ee2a7e2dedd9fc0 Mon Sep 17 00:00:00 2001 From: Torey <torey.scheer@solo.io> Date: Mon, 10 Jun 2024 15:50:18 -0400 Subject: [PATCH 3/4] fixing bug where search text remains even after suggestions cleared --- layouts/partials/docs/footer/flexsearch.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/layouts/partials/docs/footer/flexsearch.html b/layouts/partials/docs/footer/flexsearch.html index 7c28f965..479f1db5 100644 --- a/layouts/partials/docs/footer/flexsearch.html +++ b/layouts/partials/docs/footer/flexsearch.html @@ -14,7 +14,7 @@ flexsearchContainer.addEventListener('shown.bs.collapse', function () { search.focus(); }); - // hide search collapse containder by clicking outside (except top header) + // hide search collapse container by clicking outside (except top header) var topHeader = document.getElementById("top-header"); document.addEventListener('click', function(elem) { if (!flexsearchContainer.contains(elem.target) && !topHeader.contains(elem.target)) @@ -38,13 +38,13 @@ } }; + // Clears suggestion when clicking out document.addEventListener('click', function(event) { - var isClickInsideElement = suggestions.contains(event.target); - + var isClickInsideElement = suggestions.contains(event.target) || flexsearchContainer.contains(event.target); if (!isClickInsideElement) { suggestions.classList.add('d-none'); + search.value = ''; } - }); /* From 0ce90e5b0c6df004888e606383b9e723a3f9ae98 Mon Sep 17 00:00:00 2001 From: Torey <torey.scheer@solo.io> Date: Mon, 10 Jun 2024 16:26:05 -0400 Subject: [PATCH 4/4] ellipsis --- layouts/partials/docs/footer/flexsearch.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/docs/footer/flexsearch.html b/layouts/partials/docs/footer/flexsearch.html index 479f1db5..abde5995 100644 --- a/layouts/partials/docs/footer/flexsearch.html +++ b/layouts/partials/docs/footer/flexsearch.html @@ -305,7 +305,7 @@ // we want words after the matched word - ignore the last one though, since it will likely not be a full word. string += doc.content.substring(indexAfter, indexAfter+30).trim().split(' ').slice(0, -1).join(' '); - return string.trim(); + return '…' + string.trim() + '…'; } catch(e){} }