Skip to content

Commit ce2ef70

Browse files
authored
Add some site search enhancement #15 (#20)
- restored original lunr search algorithm - added search help tooltip and page - search string is now preserved between page reloads - excluded not wanted pages from search results - tooltip is getting hidden automatically now on window focus lost as well Solves: #15 Signed-off-by: Hofi <hofione@gmail.com>
2 parents a953b79 + c3cf7d7 commit ce2ef70

File tree

16 files changed

+447
-202
lines changed

16 files changed

+447
-202
lines changed

_config.yml

+4-3
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,14 @@ defaults:
164164

165165
# Search settings
166166
search: true
167+
# Setting search_full_content to true could impact page load performance!
167168
search_full_content: true
168169

169170
search_provider: lunr
170171
lunr:
171-
search_within_pages: true
172-
# Setting search_full_content to true could impact page load performance!
173-
search_full_content: true
172+
# No we have all the valuable content in collections
173+
# Standalone pages like, sitemap.xml, 404, etc. should not be searched
174+
search_within_pages: false
174175

175176
# search_provider: algolia
176177
# algolia:

_data/external_links.yml

+10
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,13 @@ ietf-syslog-proto:
132132
id: ietf-syslog-proto
133133
url: https://tools.ietf.org/html/rfc5424
134134
title: [ "new syslog (IETF-syslog) protocol" ]
135+
136+
lunr-site:
137+
id: lunr-site
138+
url: https://lunrjs.com
139+
title: [ "Lunar site" ]
140+
141+
lunr-search-help:
142+
id: lunr-search-help
143+
url: https://lunrjs.com/guides/searching.html
144+
title: [ "Lunar search help" ]
+8-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1-
{% assign lang = site.locale | slice: 0,2 | default: "en" %}
1+
{% comment %}
2+
<!-- {% assign lang = site.locale | slice: 0,2 | default: "en" %}
3+
4+
NOTE: currently only EN is supported
5+
26
{% case lang %}
37
{% when "gr" %}
48
{% assign lang = "gr" %}
59
{% else %}
610
{% assign lang = "en" %}
7-
{% endcase %}
11+
{% endcase %} -->
12+
{% endcomment %}
13+
{% assign lang = "en" %}
814
<script src="{{ '/assets/js/lunr/lunr.min.js' | relative_url }}"></script>
915
<script src="{{ '/assets/js/lunr/lunr-store.js' | relative_url }}"></script>
1016
<script src="{{ '/assets/js/lunr/lunr-' | append: lang | append: '.js' | relative_url }}"></script>

_includes/search/search_form.html

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
{{ site.data.ui-text[site.locale].search_label_text | default: 'Enter your search term...' }}
88
</label>
99
<input type="search" id="search" class="search-input" tabindex="-1" placeholder="{{ site.data.ui-text[site.locale].search_placeholder_text | default: 'Enter your search term...' }}" />
10+
<a class="search-help content-tooltip full-content-tooltip nav-link" href="/lunr_search_help.html">[ Hover or click for search help ]</a>
1011
</form>
1112
<div id="results" class="results"></div>
1213
{%- when "google" -%}

_js/custom/custom-init.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
Custom js init stuff
33
========================================================================== */
44

5-
$(function () {
6-
7-
// Override the default lunr tokenizer options, as a quick fix added _ to the list to get ignored the differences like option-1 and option_1
8-
lunr.tokenizer.separator = /[\s\-_]+/
9-
10-
});
5+
// $(function () {
6+
//
7+
// // Override the default lunr tokenizer options, as a quick fix added _ to the list to get ignored the differences like option-1 and option_1
8+
// //lunr.tokenizer.separator = /[\s\-_]+/
9+
// lunr.tokenizer.separator = /[\s]+/
10+
//
11+
// });

_js/custom/navigation.js

+91-42
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,35 @@
44

55
$(function () {
66
// FIXME: How to get the real base URL (without using Liquid and Front Matter) ?!?!
7-
const docRootName = 'doc';
7+
const docRoot = '';
88
const notFoundPageName = '404.html';
99
const contentID = 'article';
1010

11+
function trimCharFromString(str, char) {
12+
// Create a regular expression to match the given character at the beginning or end of the string
13+
const regex = new RegExp(`^${char}|${char}$`, 'g');
14+
15+
// Use replace() to trim the character from the string
16+
return str.replace(regex, '');
17+
}
18+
19+
function hideTocIfNotNeeded(docObject, forceHide) {
20+
var shouldHide = forceHide;
21+
var tocElement = docObject.querySelector('.toc');
22+
23+
if (tocElement) {
24+
var tocMenuElement = tocElement.querySelector('.toc__menu');
25+
if (null == tocMenuElement || false == tocMenuElement.hasChildNodes)
26+
shouldHide = true;
27+
}
28+
if (shouldHide) {
29+
// TOC is autogenerated via 'include toc.html' so its size is not known prior the call of toc.html
30+
// Signal emptiness, css will hide if needed based on it and config settings
31+
// NOTE: Not hiding directly here to behave the same way like the left sidebar does
32+
tocElement.classList.add('empty');
33+
}
34+
}
35+
1136
function adjustSidebars() {
1237
// Identify the URL of the loaded page
1338
var loadedPageUrl = window.location.pathname;
@@ -56,15 +81,7 @@ $(function () {
5681
matchingNavItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
5782
}
5883

59-
// TOC is autogenerated via 'include toc.html' so its size is not known prior the call of toc.html
60-
// Signal emptiness, css will hide if needed based on it and config settings
61-
// NOTE: Not hiding directly here to behave the same way like the left sidebar does
62-
var tocElement = document.querySelector('.toc');
63-
if (tocElement) {
64-
var tocMenuElement = tocElement.querySelector('.toc__menu');
65-
if (null == tocMenuElement || false == tocMenuElement.hasChildNodes)
66-
tocElement.classList.add('empty');
67-
}
84+
hideTocIfNotNeeded(document, false);
6885
}
6986
}
7087

@@ -158,7 +175,7 @@ $(function () {
158175
error => {
159176
if (error == "Error: 404") {
160177
var baseURL = window.location.origin;
161-
var notFoundURL = baseURL + '/' + docRoot + '/' + notFoundPageName;
178+
var notFoundURL = baseURL + '/' + (docRoot != '' ? docRoot + '/' : '') + notFoundPageName;
162179

163180
updateContentFromUrl(notFoundURL);
164181
}
@@ -174,15 +191,20 @@ $(function () {
174191
// Functions to handle link clicks
175192
// -------------
176193
function getCollectionFromDocPath(url) {
177-
var parts = url.href.split('/');
178-
var docIndex = parts.indexOf(docRootName);
194+
var collection = '';
195+
var parts = trimCharFromString(url.pathname, '/').split('/');
179196

180-
// If 'doc' is not found or it's the last segment, return an empty string
181-
if (docIndex === -1 || docIndex === parts.length - 1) {
182-
return '';
197+
if (docRoot == '') {
198+
collection = parts[0];
183199
}
200+
else {
201+
var docIndex = parts.indexOf(docRoot);
184202

185-
return parts[docIndex + 1];
203+
// If 'docRoot' is found or it is not the last segment, return the next part after it as the collection name
204+
if (docIndex !== -1 && docIndex !== parts.length - 1)
205+
collection = parts[docIndex + 1];
206+
}
207+
return collection;
186208
}
187209

188210
function sameCollection(url1, url2) {
@@ -194,6 +216,9 @@ $(function () {
194216

195217
function handleNavLinkClick(event) {
196218
if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey) {
219+
if (tooltipTarget)
220+
hideTooltip(true);
221+
197222
var updated = false;
198223
// Get the relative URL value and update the browser URL
199224
// Use originalTarget or explicitTarget to get the correct one even for clicks from the tooltips
@@ -205,7 +230,7 @@ $(function () {
205230
// Try to load into the inner content frame only if the collection has not changed
206231
// Otherwise let the original click flow take effect, as the nav bar must be reloaded too
207232
// for a different collection
208-
if (url.origin == window.location.origin && sameCollection(url, window.location)) {
233+
if (url.origin === window.location.origin && anchorElement.target !== '_blank' && sameCollection(url, window.location)) {
209234
// Prevent default navigation behavior, we will use our content load method
210235
event.preventDefault();
211236

@@ -224,7 +249,7 @@ $(function () {
224249
event.target.blur();
225250
}
226251
if (false == updated)
227-
console.debug("Different collection item requested, loading full page...")
252+
console.debug("Different collection item or new tab/page requested, loading full page...")
228253
}
229254
}
230255

@@ -287,10 +312,13 @@ $(function () {
287312
});
288313
}
289314

290-
function alterPageTitle(content) {
315+
function alterPageForTooltip(content, fullPageContent) {
291316
let tempContainer = document.createElement('div');
292317
tempContainer.innerHTML = content;
293318

319+
if (fullPageContent)
320+
hideTocIfNotNeeded(tempContainer, true);
321+
294322
// Remove/Override some default title style formatting to look better in the tooltip
295323
const pageTitle = tempContainer.querySelector('#page-title');
296324
if (pageTitle)
@@ -300,7 +328,11 @@ $(function () {
300328
if (pageSubtitle)
301329
pageSubtitle.style.borderBottom = '0px';
302330

303-
return tempContainer.innerHTML;
331+
var newContent = tempContainer.innerHTML
332+
// remove unnecessary, reqursive inner content tooltips
333+
newContent = newContent.replace(/\bcontent-tooltip\b/g, '');
334+
335+
return newContent;
304336
}
305337

306338
function loadContentPartFrom(url, onSuccess, onError) {
@@ -319,17 +351,14 @@ $(function () {
319351
var startHeading = newContent.querySelector('#' + startHeadingId);
320352
if (startHeading) {
321353
var content = startHeading.outerHTML; // Include the starting <h> element itself
322-
323354
var nextSibling = startHeading.nextElementSibling;
355+
324356
// Collect all siblings until the next heading or the end of the document
325357
// FIXME: This magic 6 must be maintained together now with generate_links.rb (and other places ?!)
326358
while (nextSibling && nextSibling.tagName !== 'H1' && nextSibling.tagName !== 'H2' && nextSibling.tagName !== 'H3' && nextSibling.tagName !== 'H4' && nextSibling.tagName !== 'H5' && nextSibling.tagName !== 'H6') {
327359
content += nextSibling.outerHTML;
328360
nextSibling = nextSibling.nextElementSibling;
329361
}
330-
if (false == hasAnchor)
331-
content = alterPageTitle(content);
332-
333362
onSuccess(content);
334363
}
335364
else
@@ -373,9 +402,14 @@ $(function () {
373402
tooltip.style.setProperty(posName, newPosition);
374403
}
375404

376-
function showTooltip(event, tooltipText) {
405+
function showTooltip(event, tooltipText, fullPageContent) {
377406
tooltip.innerHTML = tooltipText.innerHTML;
378407

408+
if (fullPageContent)
409+
tooltip.classList.add("full-content-tooltip");
410+
else
411+
tooltip.classList.remove("full-content-tooltip");
412+
379413
var tooltipPos = getTooltipPos(event, tooltipTarget)
380414
var tooltipArrowLeftShift = 2 * toolTipArrowSize;
381415

@@ -436,31 +470,41 @@ $(function () {
436470
element.appendChild(tooltipText);
437471

438472
element.addEventListener('mouseover', function (event) {
473+
var fullPageContent = element.classList.contains('full-content-tooltip');
474+
439475
tooltipTarget = element;
440476

441477
// Load only once per page load
442478
if (tooltipText.innerHTML === '') {
443479
var url = element.href;
444-
loadContentPartFrom(
445-
url,
446-
newContent => {
447-
// remove unnecessary inner content tooltips
448-
newContent = newContent.replace(/\bcontent-tooltip\b/g, '');
449-
// cache for reuse
450-
tooltipText.innerHTML = newContent;
451-
showTooltip(event, tooltipText);
452-
},
453-
error => {
454-
console.error('Error loading the tooltip content!' + error);
455-
}
456-
);
480+
481+
function onSuccess(newContent) {
482+
if (typeof (newContent) === 'object' && 'innerHTML' in newContent)
483+
newContent = newContent.innerHTML;
484+
newContent = alterPageForTooltip(newContent, fullPageContent);
485+
486+
// cache for reuse
487+
tooltipText.innerHTML = newContent;
488+
showTooltip(event, tooltipText, fullPageContent);
489+
}
490+
491+
function onError(error) {
492+
console.error('Error loading the tooltip content!' + error);
493+
}
494+
495+
if (fullPageContent) {
496+
loadContentFromUrl(url, newContent => onSuccess(newContent), error => onError(error));
497+
}
498+
else {
499+
loadContentPartFrom(url, newContent => onSuccess(newContent), error => onError(error));
500+
}
457501
}
458502
else
459-
showTooltip(event, tooltipText);
503+
showTooltip(event, tooltipText, fullPageContent);
460504
});
461505
});
462506

463-
document.addEventListener('mousemove', (event) => {
507+
document.addEventListener('mousemove', function (event) {
464508
if (shouldHideTooltip(event.target)) {
465509
if (tooltipTarget)
466510
hideTooltip(true);
@@ -471,7 +515,7 @@ $(function () {
471515
}
472516
});
473517

474-
document.addEventListener('scroll', (event) => {
518+
document.addEventListener('scroll', function (event) {
475519
if (elementUnderCursor == null || shouldHideTooltip(elementUnderCursor)) {
476520
if (tooltipTarget)
477521
hideTooltip(true);
@@ -481,6 +525,11 @@ $(function () {
481525
document.addEventListener("mouseover", function (event) {
482526
elementUnderCursor = event.target;
483527
});
528+
529+
window.addEventListener('blur', function () {
530+
if (tooltipTarget)
531+
hideTooltip(true);
532+
});
484533
}
485534

486535
// -------------

0 commit comments

Comments
 (0)