feat: rework the scripts to make it closer to docsy
feat: implement custom partial in search--input.html chore: add some comments on how things can be refactored later feat: bring the search.html closer to docsy by only including the search-input partial and using the other things from baseof.html fix: first line comments need to be in the {{/* */}} block, see https://github.com/gohugoio/hugo/issues/7243 Apply suggestions from code review fix: apply review suggestions fix: search bar should be removed in page find results and should be present in the sidebar Co-authored-by: Tim Bannister <tim@scalefactory.com>
This commit is contained in:
parent
74343d4d3b
commit
8af973175c
|
@ -0,0 +1,139 @@
|
|||
document.querySelector('html').classList.add('search');
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let searchTerm = new URLSearchParams(window.location.search).get('q');
|
||||
let fetchingElem = document.getElementById('bing-results-container');
|
||||
|
||||
if (!searchTerm) {
|
||||
if (fetchingElem) fetchingElem.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
window.renderGoogleSearchResults = () => {
|
||||
const cx = '013288817511911618469:elfqqbqldzg';
|
||||
const gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cse.google.com/cse.js?cx=' + cx;
|
||||
const s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
}
|
||||
|
||||
window.renderPageFindSearchResults = () => {
|
||||
let urlParams = new URLSearchParams(window.location.search);
|
||||
let searchTerm = urlParams.get("q") || "";
|
||||
let sidebarSearch = document.querySelector('#search-results-search');
|
||||
if (sidebarSearch) {
|
||||
sidebarSearch.remove();
|
||||
}
|
||||
document.getElementById('search').style.display = 'block';
|
||||
let pagefind = new PagefindUI({ element: "#search", showImages: false });
|
||||
if (searchTerm) {
|
||||
pagefind.triggerSearch(searchTerm);
|
||||
}
|
||||
|
||||
document.querySelector("#search input").addEventListener("input", function() {
|
||||
const inputValue = this.value;
|
||||
const queryStringVar = "q";
|
||||
updateQueryString(queryStringVar, inputValue);
|
||||
});
|
||||
}
|
||||
|
||||
function updateQueryString(key, value) {
|
||||
const baseUrl = window.location.href.split("?")[0];
|
||||
const queryString = window.location.search.slice(1);
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
|
||||
if (urlParams.has(key)) {
|
||||
urlParams.set(key, value);
|
||||
} else {
|
||||
urlParams.append(key, value);
|
||||
}
|
||||
|
||||
const newUrl = baseUrl + "?" + urlParams.toString();
|
||||
// Update the browser history (optional)
|
||||
history.replaceState(null, '', newUrl);
|
||||
}
|
||||
|
||||
// China Verification.
|
||||
const path = "path=/;";
|
||||
let d = new Date()
|
||||
d.setTime(d.getTime() + (7 * 24 * 60 * 60 * 1000))
|
||||
let expires = "expires=" + d.toUTCString()
|
||||
|
||||
function getCookie(name) {
|
||||
const value = "; " + document.cookie;
|
||||
const parts = value.split("; " + name + "=");
|
||||
if (parts.length === 2) return parts.pop().split(";").shift();
|
||||
else return "";
|
||||
}
|
||||
|
||||
async function checkBlockedSite(url) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
controller.abort();
|
||||
}, 5000); // Timeout set to 5000ms (5 seconds)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { method: 'HEAD', mode: 'no-cors', signal: controller.signal });
|
||||
// If we reach this point, the site is accessible (since mode: 'no-cors' doesn't allow us to check response.ok)
|
||||
clearTimeout(timeout);
|
||||
return false;
|
||||
} catch (error) {
|
||||
// If an error occurs, it's likely the site is blocked
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSearch() {
|
||||
if (getCookie("can_google") === "") {
|
||||
const isGoogleBlocked = await checkBlockedSite("https://www.google.com/favicon.ico");
|
||||
if ( isGoogleBlocked ) {
|
||||
// Google is blocked.
|
||||
document.cookie = "can_google=false;" + path + expires
|
||||
window.renderPageFindSearchResults()
|
||||
} else {
|
||||
// Google is not blocked.
|
||||
document.cookie = "can_google=true;" + path + expires
|
||||
window.renderGoogleSearchResults()
|
||||
}
|
||||
} else if (getCookie("can_google") === "false") {
|
||||
window.renderPageFindSearchResults()
|
||||
} else {
|
||||
window.renderGoogleSearchResults()
|
||||
}
|
||||
}
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
const Search = {
|
||||
init: function () {
|
||||
$(document).ready(function () {
|
||||
// Fill the search input form with the current search keywords
|
||||
const searchKeywords = new URLSearchParams(location.search).get('q');
|
||||
if (searchKeywords !== null && searchKeywords !== '') {
|
||||
const searchInput = document.querySelector('.td-search-input');
|
||||
searchInput.focus();
|
||||
searchInput.value = searchKeywords;
|
||||
}
|
||||
|
||||
// Set a keydown event
|
||||
$(document).on("keypress", ".td-search-input", function (e) {
|
||||
if (e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
const query = $(this).val();
|
||||
document.location = $(this).data('search-page') + "?q=" + query;
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
Search.init();
|
||||
})(jQuery);
|
||||
|
||||
window.onload = loadSearch;
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
Copyright 2018 Google LLC
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
var Search = {
|
||||
init: function () {
|
||||
$(document).ready(function () {
|
||||
// Fill the search input form with the current search keywords
|
||||
const searchKeywords = new URLSearchParams(location.search).get('q');
|
||||
if (searchKeywords !== null && searchKeywords !== '') {
|
||||
const searchInput = document.querySelector('.td-search-input');
|
||||
searchInput.focus();
|
||||
searchInput.value = searchKeywords;
|
||||
}
|
||||
|
||||
// Set a keydown event
|
||||
$(document).on("keypress", ".td-search-input", function (e) {
|
||||
if (e.keyCode !== 13) {
|
||||
return;
|
||||
}
|
||||
|
||||
var query = $(this).val();
|
||||
var searchPage = $(this).data('search-page') + "?q=" + query;
|
||||
document.location = searchPage;
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
Search.init();
|
||||
})(jQuery);
|
|
@ -151,7 +151,7 @@ githubWebsiteRaw = "raw.githubusercontent.com/kubernetes/website"
|
|||
github_repo = "https://github.com/kubernetes/website"
|
||||
|
||||
# Searching
|
||||
k8s_search = true
|
||||
customSearch = true
|
||||
|
||||
# The following search parameters are specific to Docsy's implementation. Kubernetes implementes its own search-related partials and scripts.
|
||||
|
||||
|
|
|
@ -1,54 +1,42 @@
|
|||
<!doctype html>
|
||||
<html lang="{{ .Site.Language.Lang }}" class="{{.Params.class}} no-js">
|
||||
<head>
|
||||
{{ partial "head.html" . }}
|
||||
</head>
|
||||
<body class="td-search {{- if ne (lower .Params.cid) "" -}}{{- printf " cid-%s" (lower .Params.cid) -}}{{- end -}}">
|
||||
<header>
|
||||
{{ partial "navbar.html" . }}
|
||||
{{ block "announcement" . }}
|
||||
{{ partial "announcement.html" . }}
|
||||
{{ end }}
|
||||
{{ block "hero" . }}
|
||||
<section class="header-hero filler">
|
||||
</section>
|
||||
{{ block "hero-more" . }}{{ end }}
|
||||
{{ end }}
|
||||
</header>
|
||||
<div class="td-outer">
|
||||
<main role="main" class="td-main">
|
||||
<section class="row td-search-result">
|
||||
<div class="col-12 col-md-4 offset-md-2">
|
||||
<form class="td-sidebar__search d-flex align-items-center">
|
||||
{{ partial "search-input.html" . }}
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
{{ if .Site.Params.gcs_engine_id }}
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '{{ . }}';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:searchresults-only></gcse:searchresults-only>
|
||||
{{ else if .Site.Params.k8s_search }}
|
||||
<script src="{{ "js/search.js" | relURL }}"></script>
|
||||
<script src="/pagefind/pagefind-ui.js"></script>
|
||||
<gcse:searchresults-only linktarget="_parent">
|
||||
<div id="search" style="display:none"></div>
|
||||
</gcse:searchresults-only>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
{{ partial "footer.html" . }}
|
||||
{{ partialCached "scripts.html" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{/*
|
||||
Copied from Docsy with the addition of the search-input and the customSearch block.
|
||||
Revisit this if / when either of https://github.com/google/docsy/issues/2194 and https://github.com/google/docsy/pull/1512 are closed
|
||||
*/}}
|
||||
{{ define "main" }}
|
||||
|
||||
{{/*
|
||||
Do not use the `search-results-search` id elsewhere as it is used
|
||||
delete this element for pagefind/China users
|
||||
*/}}
|
||||
|
||||
{{/* From shortcodes/site-searchbar.html which is used in the home page */}}
|
||||
<div id="search-results-search" class="col-sm-6 col-md-6 col-lg-6 mx-auto py-3">
|
||||
{{partial "search-input" .}}
|
||||
</div>
|
||||
<section class="row td-search-result">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<h2 class="ml-4">{{ .Title }}</h2>
|
||||
{{ with .Site.Params.gcs_engine_id }}
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '{{ . }}';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:searchresults-only></gcse:searchresults-only>
|
||||
{{ end }}
|
||||
{{ if .Site.Params.customSearch }}
|
||||
<script src="/pagefind/pagefind-ui.js"></script>
|
||||
<gcse:searchresults-only linktarget="_parent">
|
||||
<div id="search" style="display:none"></div>
|
||||
</gcse:searchresults-only>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{ end }}
|
|
@ -33,6 +33,9 @@
|
|||
{{ $jsSearch := resources.Get "js/search.js" | resources.ExecuteAsTemplate "js/search.js" .Site.Home }}
|
||||
{{ if .Site.Params.offlineSearch }}
|
||||
{{ $jsSearch = resources.Get "js/offline-search.js" }}
|
||||
{{/* Revisit this if / when either of https://github.com/google/docsy/issues/2194 and https://github.com/google/docsy/pull/1512 are closed */}}
|
||||
{{ else if .Site.Params.customSearch }}
|
||||
{{ $jsSearch = resources.Get "js/custom-search.js" }}
|
||||
{{ end }}
|
||||
{{ $js := (slice $jsBs $jsBase $jsAnchor $jsSearch) | resources.Concat "js/main.js" -}}
|
||||
{{ if hugo.IsProduction -}}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{{/* Revisit this if / when either of https://github.com/google/docsy/issues/2194 and https://github.com/google/docsy/pull/1512 are closed */}}
|
||||
{{ $lang := .Site.Language.Lang }}
|
||||
{{ $searchFile := printf "content/%s/search.md" $lang }}
|
||||
|
||||
<div class="search-bar">
|
||||
<i class="search-icon fa-solid fa-search"></i>
|
||||
<input
|
||||
type="search"
|
||||
name="q"
|
||||
{{ if fileExists $searchFile }}
|
||||
data-search-page="{{ "search/" | relLangURL }}"
|
||||
{{ else }}
|
||||
data-search-page="{{ "search/" | relURL }}"
|
||||
{{ end }}
|
||||
class="search-input td-search-input"
|
||||
placeholder="{{ T "ui_search_placeholder" }}"
|
||||
aria-label="{{ T "ui_search_placeholder" }}"
|
||||
autocomplete="off"
|
||||
>
|
||||
</div>
|
|
@ -1,45 +1,43 @@
|
|||
{{ if or .Site.Params.gcs_engine_id .Site.Params.algolia_docsearch }}
|
||||
<div class="search-bar">
|
||||
<i class="search-icon fa-solid fa-search"></i>
|
||||
<input
|
||||
type="search"
|
||||
class="search-input td-search-input"
|
||||
placeholder="{{ T "ui_search_placeholder" }}"
|
||||
aria-label="{{ T "ui_search_placeholder" }}"
|
||||
autocomplete="off"
|
||||
>
|
||||
{{/*
|
||||
Copied from Docsy with the addition of the customSearch block.
|
||||
This can be deleted once https://github.com/google/docsy/issues/2194 and https://github.com/google/docsy/pull/1512 are closed
|
||||
and the site has been updated to incorporate the upstream change.
|
||||
*/}}
|
||||
{{ if .Site.Params.gcs_engine_id -}}
|
||||
<div class="td-search">
|
||||
<div class="td-search__icon"></div>
|
||||
<input type="search" class="td-search__input form-control td-search-input" placeholder="{{ T "ui_search" }}" aria-label="{{ T "ui_search" }}" autocomplete="off">
|
||||
</div>
|
||||
{{ else if .Site.Params.offlineSearch }}
|
||||
<div class="search-bar" id="search-nav-container">
|
||||
<i class="search-icon fa-solid fa-search"></i>
|
||||
<input
|
||||
type="search"
|
||||
class="search-input td-search-input"
|
||||
id="search-input"
|
||||
placeholder="{{ T "ui_search_placeholder" }}"
|
||||
aria-label="{{ T "ui_search_placeholder" }}"
|
||||
autocomplete="off"
|
||||
>
|
||||
</div>
|
||||
{{ else if .Site.Params.k8s_search }}
|
||||
{{ else if .Site.Params.algolia_docsearch -}}
|
||||
<div id="docsearch"></div>
|
||||
{{ else if .Site.Params.offlineSearch -}}
|
||||
{{ $offlineSearchIndex := resources.Get "json/offline-search-index.json" | resources.ExecuteAsTemplate "offline-search-index.json" . -}}
|
||||
{{ if hugo.IsProduction -}}
|
||||
{{/* Use `md5` as finger print hash function to shorten file name to avoid `file name too long` error. */ -}}
|
||||
{{ $offlineSearchIndex = $offlineSearchIndex | fingerprint "md5" -}}
|
||||
{{ end -}}
|
||||
{{ $offlineSearchLink := $offlineSearchIndex.RelPermalink -}}
|
||||
|
||||
{{ $lang := .Site.Language.Lang }}
|
||||
{{ $searchFile := printf "content/%s/search.md" $lang }}
|
||||
|
||||
<div class="search-bar">
|
||||
<i class="search-icon fa-solid fa-search"></i>
|
||||
<div class="td-search td-search--offline">
|
||||
<div class="td-search__icon"></div>
|
||||
<input
|
||||
type="search"
|
||||
name="q"
|
||||
{{ if fileExists $searchFile }}
|
||||
data-search-page="{{ "search/" | relLangURL }}"
|
||||
{{ else }}
|
||||
data-search-page="{{ "search/" | relURL }}"
|
||||
{{ end }}
|
||||
class="search-input td-search-input"
|
||||
placeholder="{{ T "ui_search_placeholder" }}"
|
||||
aria-label="{{ T "ui_search_placeholder" }}"
|
||||
class="td-search__input form-control"
|
||||
placeholder="{{ T "ui_search" }}"
|
||||
aria-label="{{ T "ui_search" }}"
|
||||
autocomplete="off"
|
||||
{{/*
|
||||
The data attribute name of the json file URL must end with `src` since
|
||||
Hugo's absurlreplacer requires `src`, `href`, `action` or `srcset` suffix for the attribute name.
|
||||
If the absurlreplacer is not applied, the URL will start with `/`.
|
||||
It causes the json file loading error when when relativeURLs is enabled.
|
||||
https://github.com/google/docsy/issues/181
|
||||
*/}}
|
||||
data-offline-search-index-json-src="{{ $offlineSearchLink }}"
|
||||
data-offline-search-base-href="/"
|
||||
data-offline-search-max-results="{{ .Site.Params.offlineSearchMaxResults | default 10 }}"
|
||||
>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ else if .Site.Params.customSearch -}}
|
||||
{{ partialCached "search-input-custom" . }}
|
||||
{{ end -}}
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
document.querySelector('html').classList.add('search');
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let searchTerm = new URLSearchParams(window.location.search).get('q');
|
||||
let fetchingElem = document.getElementById('bing-results-container');
|
||||
|
||||
if (!searchTerm) {
|
||||
if (fetchingElem) fetchingElem.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
window.renderGoogleSearchResults = () => {
|
||||
var cx = '013288817511911618469:elfqqbqldzg';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//cse.google.com/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
}
|
||||
|
||||
window.renderPageFindSearchResults = () => {
|
||||
let urlParams = new URLSearchParams(window.location.search);
|
||||
let searchTerm = urlParams.get("q") || "";
|
||||
let sidebarSearch = document.querySelector('.td-sidebar__search');
|
||||
if (sidebarSearch) {
|
||||
sidebarSearch.remove();
|
||||
}
|
||||
document.getElementById('search').style.display = 'block';
|
||||
pagefind = new PagefindUI({ element: "#search", showImages: false });
|
||||
if (searchTerm) {
|
||||
pagefind.triggerSearch(searchTerm);
|
||||
}
|
||||
|
||||
document.querySelector("#search input").addEventListener("input", function() {
|
||||
var inputValue = this.value;
|
||||
var queryStringVar = "q";
|
||||
updateQueryString(queryStringVar, inputValue);
|
||||
});
|
||||
}
|
||||
|
||||
function updateQueryString(key, value) {
|
||||
var baseUrl = window.location.href.split("?")[0];
|
||||
var queryString = window.location.search.slice(1);
|
||||
var urlParams = new URLSearchParams(queryString);
|
||||
|
||||
if (urlParams.has(key)) {
|
||||
urlParams.set(key, value);
|
||||
} else {
|
||||
urlParams.append(key, value);
|
||||
}
|
||||
|
||||
var newUrl = baseUrl + "?" + urlParams.toString();
|
||||
// Update the browser history (optional)
|
||||
history.replaceState(null, '', newUrl);
|
||||
}
|
||||
|
||||
// China Verification.
|
||||
var path = "path=/;"
|
||||
d = new Date()
|
||||
d.setTime(d.getTime() + (7 * 24 * 60 * 60 * 1000))
|
||||
expires = "expires=" + d.toUTCString()
|
||||
|
||||
function getCookie(name) {
|
||||
var value = "; " + document.cookie;
|
||||
var parts = value.split("; " + name + "=");
|
||||
if (parts.length == 2) return parts.pop().split(";").shift();
|
||||
else return "";
|
||||
}
|
||||
|
||||
async function checkBlockedSite(url) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
controller.abort();
|
||||
}, 5000); // Timeout set to 5000ms (5 seconds)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { method: 'HEAD', mode: 'no-cors', signal: controller.signal });
|
||||
// If we reach this point, the site is accessible (since mode: 'no-cors' doesn't allow us to check response.ok)
|
||||
clearTimeout(timeout);
|
||||
return false;
|
||||
} catch (error) {
|
||||
// If an error occurs, it's likely the site is blocked
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSearch() {
|
||||
if (getCookie("can_google") === "") {
|
||||
const isGoogleBlocked = await checkBlockedSite("https://www.google.com/favicon.ico");
|
||||
if ( isGoogleBlocked ) {
|
||||
// Google is blocked.
|
||||
document.cookie = "can_google=false;" + path + expires
|
||||
window.renderPageFindSearchResults()
|
||||
} else {
|
||||
// Google is not blocked.
|
||||
document.cookie = "can_google=true;" + path + expires
|
||||
window.renderGoogleSearchResults()
|
||||
}
|
||||
} else if (getCookie("can_google") == "false") {
|
||||
window.renderPageFindSearchResults()
|
||||
} else {
|
||||
window.renderGoogleSearchResults()
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = loadSearch;
|
||||
|
Loading…
Reference in New Issue