Merge pull request #11524 from thaJeztah/rewrite_search

Rewrite/update styling of local search
This commit is contained in:
Usha Mandya 2020-10-15 17:31:11 +01:00 committed by GitHub
commit ab0d6134c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 190 additions and 278 deletions

View File

@ -34,7 +34,7 @@
</div>
</div>
<div class="row justify-content-center">
<form action="/search/" method="GET" class="col-xs-12 col-sm-offset-2 col-sm-8 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6">
<form action="/search/" method="get" class="col-xs-12 col-sm-offset-2 col-sm-8 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6">
<label class="sr-only" for="st-search-input">Search</label>
<input
id="st-search-input"
@ -47,9 +47,7 @@
dir="auto"
autofocus
/>
<div id="autocompleteContainer">
<div id="autocompleteResults"></div>
</div>
<div id="autocompleteResults"></div>
</form>
</div>
</section>

View File

@ -4,12 +4,10 @@
</a>
</div>
<div class="search-form" id="search-div">
<form class="search-form form-inline" id="searchForm" action="/search/">
<form class="search-form form-inline" id="searchForm" action="/search/" method="get">
<label for="st-search-input" class="sr-only">Search</label>
<input class="search-field form-control ds-input" id="st-search-input" value="" name="q" placeholder="Search the docs" type="search" autocomplete="off" spellcheck="false" dir="auto" style="position: relative; vertical-align: top;">
<div id="autocompleteContainer">
<div id="autocompleteResults"></div>
</div>
<input class="search-field form-control ds-input" id="st-search-input" name="q" placeholder="Search the docs" type="search" autocomplete="off" spellcheck="false" dir="auto" style="position: relative; vertical-align: top;">
<div id="autocompleteResults"></div>
<!-- <button type="submit" class="search-submit btn btn-default">Search</button> -->
</form>
</div>

View File

@ -99,8 +99,8 @@ body.landing {
}
#autocompleteResults {
left: 10px;
right: 10px;
left: 14px;
right: 14px;
width: unset;
@include before-lg-width {

View File

@ -89,16 +89,21 @@ body.night {
.toc-nav i.fa {
color: $body-text-night;
}
div#autocompleteResults {
#autocompleteResults {
background: $bg-search-results-night;
border: 1px solid $black;
color: $white;
//color: $white;
}
.autocompleteList li {
color: #b4c3d2;
}
div#autocompleteResults span {
color: #b7a4de;
.autocompleteResult {
&.selected {
background-color: #1f262e;
}
li {
color: #b4c3d2;
}
span {
color: #b7a4de;
}
}
/* for google results styles - forgive us css gods */

View File

@ -135,73 +135,59 @@ input[type=text] {
* autocompleteResults *********************************************************
*/
div#autocompleteResults {
#autocompleteResults {
display: none; /* toggled through javascript */
background: #E6F5FD;
border: 1px solid #eee;
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.28);
padding: 20px 0 15px 0;
margin: 10px 0 0 0;
position: absolute;
width: 600px;
z-index: 9999;
}
ul.autocompleteList {
list-style: none;
max-width: 100%;
@include before-lg-width {
padding: 0;
}
}
.autocompleteList li {
padding: 5px 0 7px 0;
max-width: 100%;
}
div#autocompleteResults span {
background: transparent!important;
color: #518cad;
}
.autocompleteTitle {
font-weight: bold;
font-size: large;
}
.autocompleteSelected {
background-color: #f5f5f5;
}
.autocompleteList {
list-style-type: none;
width: 400px;
/* commented out 0 padding to allow inherit padding, search results on autocompleteList were getting smashed up against left margin due to this */
/* padding: 0; */
margin-bottom: 0;
}
.autoCompleteResult {
.autocompleteResult {
border-bottom: 1px solid rgba(203, 205, 209, 0.4);
cursor: pointer;
padding: 15px;
&:hover {
cursor: pointer;
&.selected {
background-color: #f5f5f5;
}
}
#autocompleteShowAll {
padding: 20px 15px;
}
ul {
list-style: none;
margin: 0 5px 0 5px;
padding-inline-start: 0;
.autocompleteList li {
width: 380px;
border: 0;
padding-right: 20px;
margin: 0;
@include before-lg-width {
padding: 0;
}
}
li {
border: 0;
margin: 0;
max-width: 100%;
padding: 5px 0 7px 0;
line-height: normal;
}
.title {
font-weight: bold;
}
.keywords {
font-size: 12px;
.glyphicon {
padding-right: 10px
}
}
span {
background: transparent;
color: #518cad;
}
}
@media print {

View File

@ -1,199 +1,115 @@
var metadata, glossary;
var autoCompleteShowing = false;
var displayingAutcompleteResults = new Array();
var autoCompleteShowingID = 0;
var lastSearch = "";
var autoCompleteResultLimit = 3;
var results = new Array();
var scoreForTitleMatch = 10;
var scoreForURLMatch = 5;
var scoreForKeywordMatch = 3;
var scoreForDescriptionMatch = 1
function addResult(topic, matchesTitle, matchesDescription, matchesURL, matchesKeywords)
{
var matchScore = (matchesTitle * scoreForTitleMatch) + (matchesDescription * scoreForDescriptionMatch) + (matchesURL * scoreForURLMatch) + (matchesKeywords * scoreForKeywordMatch);
if (matchScore > 0)
{
var resultIndex = results.length;
results[resultIndex] = new Array();
results[resultIndex].topic = topic;
results[resultIndex].score = matchScore;
}
}
function loadPage(url)
{
window.location.replace(url);
window.location.href = url;
}
$(document).on("keypress", function(event) {
if (event.keyCode == 13) {
if(autoCompleteShowing) event.preventDefault();
const maxResults = 3, titleWeight = 10, urlWeight = 5, keywordWeight = 3, descriptionWeight = 1
let searchVal = "", pages = []
function handleKeyNav(/* KeyboardEvent */ e) {
let row = _(".autocompleteResult.selected")
switch (e.key) {
case "ArrowUp":
if (row && row.previousElementSibling) {
row.classList.remove("selected")
row = row.previousElementSibling
row.classList.add("selected")
}
break;
case "ArrowDown":
if (!row) {
// pick the first one
row = _(".autocompleteResult")
} else if (row.nextElementSibling) {
row.classList.remove("selected")
row = row.nextElementSibling
}
if (row) {
row.classList.add("selected")
}
break;
case "Enter":
e.preventDefault();
if (!row || row.id === "autocompleteShowAll") {
// "see all" is selected or no autocomplete result selected
window.location.href = "/search/?q=" + e.target.value;
} else {
// an autocomplete result is selected
row.click()
}
break;
}
});
}
function highlightMe(inputTxt,keyword)
{
inputTxt = String(inputTxt);
simpletext = new RegExp("(" + keyword + ")","gi");
return inputTxt.replace(simpletext, "<span>$1</span>")
function matches(input, search) {
return String(input).toUpperCase().split(search.toUpperCase()).length - 1;
}
function matches(inputTxt,searchTxt)
{
var subs = inputTxt.split(searchTxt);
return subs.length - 1;
}
function bindSearch()
{
$("#st-search-input").on('keyup change', function(e) {
e = e || window.event;
if (autoCompleteShowing)
{
if (e.keyCode == '38') {
// up arrow
if (autoCompleteShowingID > -1)
{
// go up a result
$("#autoCompleteResult" + autoCompleteShowingID).removeClass("autocompleteSelected");
autoCompleteShowingID = autoCompleteShowingID - 1;
$("#autoCompleteResult" + autoCompleteShowingID).addClass("autocompleteSelected");
$("#autocompleteShowAll").removeClass("autocompleteSelected");
} else {
// de-selection auto-complete; reverting to raw search
$("#autoCompleteResult0").removeClass("autocompleteSelected");
autoCompleteShowingID = -1;
}
} else if (e.keyCode == '40') {
// down arrow
if (autoCompleteShowingID < (displayingAutcompleteResults.length - 1))
{
// go down to the next result
$("#autoCompleteResult" + autoCompleteShowingID).removeClass("autocompleteSelected");
autoCompleteShowingID = autoCompleteShowingID + 1;
$("#autoCompleteResult" + autoCompleteShowingID).addClass("autocompleteSelected");
} else {
// select "See all results..." and go no further
$("#autoCompleteResult" + autoCompleteShowingID).removeClass("autocompleteSelected");
$("#autocompleteShowAll").addClass("autocompleteSelected");
autoCompleteShowingID = autoCompleteResultLimit;
}
} else if (e.keyCode == '13') {
// return key
e.preventDefault();
if (autoCompleteShowingID==autoCompleteResultLimit || autoCompleteShowingID == -1 || autoCompleteShowing == false)
{
// "see all" is selected or they don't have an autocomplete result selected
loadPage("/search/?q=" + $("#st-search-input").val());
} else {
// an autocomplete result is selected
loadPage(pages[displayingAutcompleteResults[autoCompleteShowingID]].url);
}
}
//console.log('autoCompleteShowingID:',autoCompleteShowingID,'displayingAutcompleteResults[id]:',displayingAutcompleteResults[autoCompleteShowingID],'pages[id].url:',pages[displayingAutcompleteResults[autoCompleteShowingID]].url);
function handleSearch(/* KeyboardEvent */ e) {
if (e.target.value === searchVal) {
// no new search
return
}
var searchVal = $("#st-search-input").val();
if (lastSearch != searchVal)
{
displayingAutcompleteResults = [];
results = [];
var uppercaseSearchVal = searchVal.toUpperCase();
//console.log("input changed: ",$("#st-search-input").val());
if (searchVal.length > 2) {
for (i=0;i<pages.length;i++)
{
// search url, description, title, and keywords for search input
var thisPage = pages[i];
var matchesTitle=0, matchesDescription=0, matchesURL=0, matchesKeywords=0;
var matchesTitle = matches(String(thisPage.title).toUpperCase(),uppercaseSearchVal);
//if (titleMatches > 0) console.log(uppercaseSearchVal,'matches',thisPage.title,titleMatches,'times');
if (thisPage.description != null) {
matchesDescription = matches(String(thisPage.description).toUpperCase(),uppercaseSearchVal);
}
if (thisPage.url != null) {
matchesURL = matches(String(thisPage.url).toUpperCase(),uppercaseSearchVal);
}
if (thisPage.keywords != null) {
matchesKeywords = matches(String(thisPage.keywords).toUpperCase(),uppercaseSearchVal);
}
addResult(i, matchesTitle, matchesDescription, matchesURL, matchesKeywords);
searchVal = e.target.value
let results = [];
if (searchVal.length > 2) {
for (let i = 0; i < pages.length; i++) {
// search url, description, title, and keywords for search input
const p = pages[i];
if (!p.title) {
continue
}
let score = (matches(p.title, searchVal) * titleWeight)
if (p.description != null) {
score += (matches(p.description, searchVal) * descriptionWeight)
}
if (p.url != null) {
score += (matches(p.url, searchVal) * urlWeight)
}
if (p.keywords != null) {
score += (matches(p.keywords, searchVal) * keywordWeight)
}
if (score > 0) {
results.push({ "topic": i, "score": score });
}
}
results.sort(function(a,b) {
return b.score - a.score;
});
}
if (results.length > 0)
{
autoCompleteShowingID = -1;
var resultsShown = 0;
var resultsOutput = new Array();
resultsOutput.push("<div id='autoContainer'>")
//console.log(results);
for (i=0; i < autoCompleteResultLimit && i < results.length; i++)
{
//console.log(i, "of", autoCompleteResultLimit, "is underway");
displayingAutcompleteResults.push(results[i].topic); //log results to global array
resultsOutput.push("<div class='autoCompleteResult' id='autoCompleteResult" + i + "' onclick='loadPage(\"" + pages[results[i].topic].url + "\")'>");
resultsOutput.push("<ul class='autocompleteList'>");
resultsOutput.push("<li id='autoTitle" + i + "' class='autocompleteTitle'>")
resultsOutput.push("<a href=" + pages[results[i].topic].url + ">" + highlightMe(pages[results[i].topic].title,searchVal) + "</a>");
resultsOutput.push("</li>");
resultsOutput.push("<li id='autoUrl" + i + "' class='autocompleteUrl'>")
resultsOutput.push(highlightMe(pages[results[i].topic].url,searchVal));
resultsOutput.push("</li>");
/*
resultsOutput.push("<li id='autoBreadcrumb" + i + "' class='autocompleteBreadcrumb'>")
resultsOutput.push("Breadcrumb: " + breadcrumbString(pages[results[i]].url));
resultsOutput.push("</li>");
*/
if (pages[results[i].topic].keywords)
{
resultsOutput.push("<li id='autoKeywords" + i + "' class='autocompleteKeywords'>")
resultsOutput.push("<b>Keywords</b>: <i>" + highlightMe(pages[results[i].topic].keywords,searchVal) + "</i>");
resultsOutput.push("</li>");
}
if (pages[results[i].topic].description)
{
resultsOutput.push("<li id='autoDescription" + i + "' class='autocompleteDescription'>")
resultsOutput.push("<b>Description</b>: " + highlightMe(pages[results[i].topic].description,searchVal));
resultsOutput.push("</li>");
}
resultsOutput.push("</ul>");
resultsOutput.push("</div>")
resultsShown++;
}
var resultsShownText = (resultsShown > 1) ? resultsShown + " of " + results.length + " docs" : "doc";
resultsOutput.push("<div id='autocompleteShowAll'><ul class='autocompleteList'><li class='autocompleteTitle' id='autoSeeAll'><a href='/search/?q=" + searchVal + "'><b>Showing top " + resultsShownText + ". See all results...</b></a></li></ul></div>")
resultsOutput.push("</div>");
$("#autocompleteResults").css("display","block");
$("#autocompleteResults").html(resultsOutput.join(""));
autoCompleteShowing = true;
} else {
$("#autocompleteResults").css("display","none");
$("#autocompleteResults").html("");
autoCompleteShowing = false;
}
lastSearch = searchVal;
} // if searchVal != lastSearch
});
}
function queryString()
{
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
let rows = []
if (results.length > 0) {
results.sort((a, b) => b.score - a.score);
const match = new RegExp(`(${searchVal})`, "gi");
const highlight = function (/* String */ content) {
return content.replace(match, "<span>$1</span>")
}
for (let i = 0; i < maxResults && i < results.length; i++) {
const p = pages[results[i].topic];
rows.push(`<div class='autocompleteResult' onclick='window.location.href = "${p.url}"'><ul>`);
rows.push(`<li><a class='title' href='${p.url}'>${ highlight(p.title) }</a></li>`);
if (p.description && p.description !== p.title) {
// Omit description if it's the same as the title
rows.push(`<li>${ highlight(p.description) }</li>`);
}
if (p.keywords) {
rows.push(`<li class='keywords'><span class='glyphicon glyphicon-tags'></span><i>${ highlight(p.keywords) }</i></li>`);
}
rows.push("</ul></div>")
}
let shown = Math.min(results.length, maxResults)
rows.push(`<div class='autocompleteResult' id='autocompleteShowAll'><ul><li>Showing ${shown} of ${results.length} ${ (shown > 1) ? "results" : "result" }. <a href='/search/?q=${searchVal}'>See all results...</a></li></ul></div>`)
}
let pages = []
const out = _("#autocompleteResults")
if (out) {
out.innerHTML = rows.join("");
let shown = Math.min(results.length, maxResults)
out.style.display = shown === 0 ? "none" : "block"
}
}
ready(() => {
getJSON( "/js/metadata.json", data => pages = data);
bindSearch()
getJSON( "/js/metadata.json", function(data) {
pages = data
const input = _("#st-search-input")
if (/* HTMLInputElement */ input) {
input.form.addEventListener('submit', (e) => e.preventDefault());
input.addEventListener('keyup', handleKeyNav, {capture: true })
input.addEventListener('keyup', debounce(handleSearch, 100), {capture: true })
}
});
})

View File

@ -10,6 +10,14 @@ function getJSON(url, fn) {
xhr.send();
}
// throttle / debounce events. taken from https://programmingwithmosh.com/javascript/javascript-throttle-and-debounce-patterns/
function debounce(fn, msec) {
let id;
return function(...args) {
clearTimeout(id); id = setTimeout(() => fn.apply(this, args), msec);
}
}
const darkMode = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
const selectedTheme = window.localStorage ? localStorage.getItem("theme") : null;

View File

@ -10,29 +10,29 @@ skip_read_time: true
<style type='text/css'>
#my-cse1 { all: initial !important; all: default !important; }
#my-cse1 table, #my-cse1 table tr, #my-cse1 table tr th, #my-cse1 table tr td, .gs-bidi-start-align { border: 0px !important; padding: 0px !important; line-height: initial !important; margin: 0px !important; }
.gs-snippet { margin-top: 0px !important; margin-bottom: 0px !important; padding: 0px !important; color: #999}
#my-cse1 table, #my-cse1 table tr, #my-cse1 table tr th, #my-cse1 table tr td, .gs-bidi-start-align { border: 0 !important; padding: 0 !important; line-height: initial !important; margin: 0 !important; }
.gs-snippet { margin-top: 0 !important; margin-bottom: 0 !important; padding: 0 !important; color: #999}
.gs-webResult .gs-result .gs-no-results-result { padding: 10px !important; }
.gs-per-result-labels { display: none !important; }
.gsc-url-top, .gsc-thumbnail-inside, .gs-spelling { padding: 0px !important; }
.gcsc-branding { padding-right: 0px !important; }
.gsc-url-top, .gsc-thumbnail-inside, .gs-spelling { padding: 0 !important; }
.gcsc-branding { padding-right: 0 !important; }
.gsc-tabHeader.gsc-tabhActive, .gsc-tabsArea { border-color: #CCC !important; }
.gcs-input, #gsc-i-id1 { padding: 5px 5px 5px 5px !important; }
#gscb_a, .gscb_a { padding: 3px 0px 0px 0px !important;}
.gsc-control-cse, .gsc-control-cse-en { padding: 0px !important; }
.gsc-result-info { padding-bottom: 0px !important; }
#gscb_a, .gscb_a { padding: 3px 0 0 0 !important;}
.gsc-control-cse, .gsc-control-cse-en { padding: 0 !important; }
.gsc-result-info { padding-bottom: 0 !important; }
.gsc-adBlock { display: none; }
</style>
<div id="my-cse1">
<script>
(function() {
var cx = '005610573923180467403:iwlnuvjqpv4';
var gcse = document.createElement('script');
const cx = '005610573923180467403:iwlnuvjqpv4';
let 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];
let s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
@ -41,16 +41,17 @@ skip_read_time: true
</div>
<script defer>
setTimeout(function(){
$(document).ready(function() {
let searchTerm = decodeURI(queryString().q);
if(searchTerm != 'undefined' && searchTerm != "") {
$("#st-search-input").val(searchTerm);
$("#st-search-input").focus();
// Update heading with term user searched for
let currHeading = $("h1").text();
$("h1").text(currHeading + " results for: " + searchTerm);
(function() {
let query = new URLSearchParams(window.location.search);
if (query.has("q")) {
let h = document.querySelector("h1");
if (h) {
h.textContent += " results for: " + query.get("q");
}
let s = document.querySelector("#st-search-input");
if (s && s instanceof HTMLInputElement) {
s.value = query.get("q");
}
}
});
}, 1);
})();
</script>