[gi-docgen: 8/10] feat(search): implement live results
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gi-docgen: 8/10] feat(search): implement live results
- Date: Fri, 9 Apr 2021 18:19:38 +0000 (UTC)
commit a8649efa2801e1157e8b8865353f5ec8e1eb7321
Author: Rom Grk <romgrk cc gmail com>
Date: Thu Apr 1 10:25:00 2021 -0400
feat(search): implement live results
gidocgen/templates/basic/base.html | 4 +-
gidocgen/templates/basic/search.js | 177 +++++++++++++++++++++----------------
gidocgen/templates/basic/style.css | 2 +-
3 files changed, 102 insertions(+), 81 deletions(-)
---
diff --git a/gidocgen/templates/basic/base.html b/gidocgen/templates/basic/base.html
index 677040d..d3446f7 100644
--- a/gidocgen/templates/basic/base.html
+++ b/gidocgen/templates/basic/base.html
@@ -61,8 +61,8 @@ SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later
{% endif %}
{% if CONFIG.search_index %}
<div class="search section">
- <form id="search-form" method="GET">
- <input class="search-input" type="text" name="q" placeholder="Search docs"/>
+ <form id="search-form" autocomplete="off">
+ <input id="search-input" type="text" name="do-not-autocomplete" placeholder="Search docs"
autocomplete="off"/>
</form>
</div>
{% endif %}
diff --git a/gidocgen/templates/basic/search.js b/gidocgen/templates/basic/search.js
index c26efa5..905b019 100644
--- a/gidocgen/templates/basic/search.js
+++ b/gidocgen/templates/basic/search.js
@@ -29,8 +29,15 @@ const QUERY_PATTERN = new RegExp("^(" + QUERY_TYPES.join('|') + ")\\s*:\\s*", 'i
const fzy = window.fzy;
const searchParams = getSearchParams();
+const refs = {
+ input: null,
+ form: null,
+ search: null,
+ main: null,
+};
let searchIndex = undefined;
+let searchResults = [];
// Exports
window.onInitSearch = onInitSearch;
@@ -42,107 +49,114 @@ function onInitSearch() {
}
function onDidLoadSearchIndex(data) {
- const searchInput = getSearchInput();
- const searchIndex = new SearchIndex(data)
+ searchIndex = new SearchIndex(data)
- if (searchInput.value === "") {
- searchInput.value === searchParams.q || "";
- }
+ refs.input = document.querySelector("#search-input")
+ refs.form = document.querySelector("#search-form")
+ refs.search = document.querySelector("#search")
+ refs.main = document.querySelector("#main")
- function runQuery(query) {
- const q = matchQuery(query);
- const docs = searchIndex.searchDocs(q.term, q.type);
-
- const results = docs.map(function(doc) {
- return {
- name: doc.name,
- type: doc.type,
- text: getTextForDocument(doc, searchIndex.meta),
- href: getLinkForDocument(doc),
- summary: doc.summary,
- };
- });
+ attachInputHandlers()
- return results;
+ if (searchParams.q) {
+ search(searchParams.q);
}
+}
- function search() {
- const query = searchParams.q;
- if (searchInput.value === "" && query) {
- searchInput.value = query;
- }
- window.title = "Results for: " + query.user;
- showResults(query, runQuery(query));
- }
+function onDidSearch() {
+ const query = refs.input.value
+ if (query)
+ search(refs.input.value)
+ else
+ hideSearchResults()
+}
- window.onpageshow = function() {
- var query = getQuery(searchParams.q);
- if (searchInput.value === "" && query) {
- searchInput.value = query.user;
- }
- search();
- };
+function onDidSubmit(ev) {
+ ev.preventDefault();
+ if (searchResults.length > 0) {
+ window.location.href = searchResults[0].href
+ }
+}
- if (searchParams.q) {
- search();
+function attachInputHandlers() {
+ if (refs.input.value === "") {
+ refs.input.value === searchParams.q || "";
}
-};
+ refs.input.addEventListener('keydown', debounce(200, onDidSearch))
+ refs.form.addEventListener('submit', onDidSubmit)
+}
-/* Rendering */
+/* Searching */
-function showSearchResults(search) {
- if (search === null || typeof search === 'undefined') {
- search = getSearchElement();
- }
+function searchQuery(query) {
+ const q = matchQuery(query);
+ const docs = searchIndex.searchDocs(q.term, q.type);
- addClass(main, "hidden");
- removeClass(search, "hidden");
+ const results = docs.map(function(doc) {
+ return {
+ name: doc.name,
+ type: doc.type,
+ text: getTextForDocument(doc, searchIndex.meta),
+ href: getLinkForDocument(doc),
+ summary: doc.summary,
+ };
+ });
+ return results;
}
-function hideSearchResults(search) {
- if (search === null || typeof search === 'undefined') {
- search = getSearchElement();
- }
+function search(query) {
+ searchResults = searchQuery(query)
+ showResults(query, searchResults);
+}
+
+/* Rendering */
- addClass(search, "hidden");
- removeClass(search, "hidden");
+function showSearchResults() {
+ addClass(refs.main, "hidden");
+ removeClass(refs.search, "hidden");
}
-function addResults(results) {
- var output = "";
+function hideSearchResults() {
+ addClass(refs.search, "hidden");
+ removeClass(refs.main, "hidden");
+}
- if (results.length > 0) {
- output += "<table class=\"results\">" +
- "<tr><th>Name</th><th>Description</th></tr>";
+function renderResults(results) {
+ if (results.length === 0)
+ return "No results found.";
- results.forEach(function(item) {
- output += "<tr>" +
- "<td class=\"result " + item.type + "\">" +
- "<a href=\"" + item.href + "\"><code>" + item.text + "</code></a>" +
- "</td>" +
- "<td>" + item.summary + "</td>" +
- "</tr>";
- });
+ let output = "";
- output += "</table>";
- } else {
- output = "No results found.";
- }
+ output += "<table class=\"results\">" +
+ "<tr><th>Name</th><th>Description</th></tr>";
+
+ results.forEach(function(item) {
+ output += "<tr>" +
+ "<td class=\"result " + item.type + "\">" +
+ "<a href=\"" + item.href + "\"><code>" + item.text + "</code></a>" +
+ "</td>" +
+ "<td>" + item.summary + "</td>" +
+ "</tr>";
+ });
+
+ output += "</table>";
return output;
}
function showResults(query, results) {
- const search = getSearchElement();
+ window.title = "Results for: " + query;
+ window.scroll({ top: 0 })
+
const output =
"<h1>Results for "" + query + "" (" + results.length + ")</h1>" +
"<div id=\"search-results\">" +
- addResults(results) +
+ renderResults(results) +
"</div>";
- search.innerHTML = output;
+ refs.search.innerHTML = output;
showSearchResults(search);
}
@@ -250,14 +264,6 @@ function fetchJSON(url, callback) {
request.send(null);
}
-function getSearchElement() {
- return document.getElementById("search");
-}
-
-function getSearchInput() {
- return document.getElementsByClassName("search-input")[0];
-}
-
function getSearchParams() {
const params = {};
window.location.search.substring(1).split('&')
@@ -285,4 +291,19 @@ function matchQuery(input) {
return { type: type, term: term }
}
+function debounce(delay, fn) {
+ let timeout
+ let savedArgs
+ return function() {
+ const self = this
+ savedArgs = Array.prototype.slice.call(arguments)
+ if (timeout)
+ clearTimeout(timeout)
+ timeout = setTimeout(function() {
+ fn.apply(self, savedArgs)
+ timeout = undefined
+ }, delay)
+ }
+}
+
})()
diff --git a/gidocgen/templates/basic/style.css b/gidocgen/templates/basic/style.css
index e79cbe5..84915a9 100644
--- a/gidocgen/templates/basic/style.css
+++ b/gidocgen/templates/basic/style.css
@@ -448,7 +448,7 @@ footer {
border-radius: 50px;
padding: 6px 12px;
display: inline-block;
- font-size: 80%;
+ font-size: 14px;
box-shadow: inset 0 1px 3px #ddd;
transition: border .3s linear;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]