mirror of
https://github.com/snachodog/just-the-docs.git
synced 2025-04-18 00:52:24 -06:00
Multi search match highlight
Added multiple previews, configurable by site.search.previews Improved search-data.json
This commit is contained in:
parent
74681aeb21
commit
f1c306c814
@ -30,6 +30,9 @@ search:
|
|||||||
# Split documents into sections that can be individually searched
|
# Split documents into sections that can be individually searched
|
||||||
# Supports 1 - 6, default: 2
|
# Supports 1 - 6, default: 2
|
||||||
heading_level: 2
|
heading_level: 2
|
||||||
|
# Maximum amount of previews to display
|
||||||
|
# Default: 3
|
||||||
|
previews: 3
|
||||||
# Maximum amount of words to display before a matched word in the preview
|
# Maximum amount of words to display before a matched word in the preview
|
||||||
# Default: 5
|
# Default: 5
|
||||||
preview_words_before: 5
|
preview_words_before: 5
|
||||||
|
@ -183,7 +183,7 @@
|
|||||||
@include fs-1;
|
@include fs-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-result-preview {
|
.search-result-previews {
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: $sp-2;
|
padding-top: $sp-2;
|
||||||
padding-bottom: $sp-2;
|
padding-bottom: $sp-2;
|
||||||
@ -203,6 +203,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-result-preview + .search-result-preview {
|
||||||
|
margin-top: $sp-1;
|
||||||
|
}
|
||||||
|
|
||||||
.search-result-highlight {
|
.search-result-highlight {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ function searchLoaded(index, docs) {
|
|||||||
resultTitle.appendChild(resultDoc);
|
resultTitle.appendChild(resultDoc);
|
||||||
|
|
||||||
var resultDocSpan = document.createElement('span');
|
var resultDocSpan = document.createElement('span');
|
||||||
resultDocSpan.innerText = doc.doc;
|
resultDocSpan.innerHTML = doc.doc;
|
||||||
resultDoc.appendChild(resultDocSpan);
|
resultDoc.appendChild(resultDocSpan);
|
||||||
var resultDocOrSection = resultDocSpan;
|
var resultDocOrSection = resultDocSpan;
|
||||||
|
|
||||||
@ -196,74 +196,119 @@ function searchLoaded(index, docs) {
|
|||||||
resultDoc.classList.add('search-result-doc-parent');
|
resultDoc.classList.add('search-result-doc-parent');
|
||||||
var resultSection = document.createElement('div');
|
var resultSection = document.createElement('div');
|
||||||
resultSection.classList.add('search-result-section');
|
resultSection.classList.add('search-result-section');
|
||||||
resultSection.innerText = doc.title;
|
resultSection.innerHTML = doc.title;
|
||||||
resultTitle.appendChild(resultSection);
|
resultTitle.appendChild(resultSection);
|
||||||
resultDocOrSection = resultSection;
|
resultDocOrSection = resultSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata = result.matchData.metadata;
|
var metadata = result.matchData.metadata;
|
||||||
var contentFound = false;
|
var titlePositions = [];
|
||||||
|
var contentPositions = [];
|
||||||
for (var j in metadata) {
|
for (var j in metadata) {
|
||||||
if (metadata[j].title) {
|
var meta = metadata[j];
|
||||||
var position = metadata[j].title.position[0];
|
if (meta.title) {
|
||||||
var start = position[0];
|
var positions = meta.title.position;
|
||||||
var end = position[0] + position[1];
|
for (var k in positions) {
|
||||||
resultDocOrSection.innerHTML = doc.title.substring(0, start) + '<span class="search-result-highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length);
|
titlePositions.push(positions[k]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (metadata[j].content && !contentFound) {
|
if (meta.content) {
|
||||||
contentFound = true;
|
var positions = meta.content.position;
|
||||||
|
for (var k in positions) {
|
||||||
|
var position = positions[k];
|
||||||
|
var previewStart = position[0];
|
||||||
|
var previewEnd = position[0] + position[1];
|
||||||
|
var ellipsesBefore = true;
|
||||||
|
var ellipsesAfter = true;
|
||||||
|
for (var k = 0; k < {{ site.search.preview_words_before | default: 5 }}; k++) {
|
||||||
|
var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
|
||||||
|
var nextDot = doc.content.lastIndexOf('. ', previewStart - 2);
|
||||||
|
if ((nextDot >= 0) && (nextDot > nextSpace)) {
|
||||||
|
previewStart = nextDot + 1;
|
||||||
|
ellipsesBefore = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nextSpace < 0) {
|
||||||
|
previewStart = 0;
|
||||||
|
ellipsesBefore = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previewStart = nextSpace + 1;
|
||||||
|
}
|
||||||
|
for (var k = 0; k < {{ site.search.preview_words_after | default: 10 }}; k++) {
|
||||||
|
var nextSpace = doc.content.indexOf(' ', previewEnd + 1);
|
||||||
|
var nextDot = doc.content.indexOf('. ', previewEnd + 1);
|
||||||
|
if ((nextDot >= 0) && (nextDot < nextSpace)) {
|
||||||
|
previewEnd = nextDot;
|
||||||
|
ellipsesAfter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nextSpace < 0) {
|
||||||
|
previewEnd = doc.content.length;
|
||||||
|
ellipsesAfter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previewEnd = nextSpace;
|
||||||
|
}
|
||||||
|
contentPositions.push({
|
||||||
|
highlight: position,
|
||||||
|
previewStart: previewStart, previewEnd: previewEnd,
|
||||||
|
ellipsesBefore: ellipsesBefore, ellipsesAfter: ellipsesAfter
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var position = metadata[j].content.position[0];
|
if (titlePositions.length > 0) {
|
||||||
var start = position[0];
|
titlePositions.sort(function(p1, p2){ return p1[0] - p2[0] });
|
||||||
var end = position[0] + position[1];
|
resultDocOrSection.innerHTML = '';
|
||||||
var previewStart = start;
|
addHighlightedText(resultDocOrSection, doc.title, 0, doc.title.length, titlePositions);
|
||||||
var previewEnd = end;
|
}
|
||||||
var ellipsesBefore = true;
|
|
||||||
var ellipsesAfter = true;
|
if (contentPositions.length > 0) {
|
||||||
for (var k = 0; k < {{ site.search.preview_words_before | default: 5 }}; k++) {
|
contentPositions.sort(function(p1, p2){ return p1.highlight[0] - p2.highlight[0] });
|
||||||
var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
|
var contentPosition = contentPositions[0];
|
||||||
var nextDot = doc.content.lastIndexOf('. ', previewStart - 2);
|
var previewPosition = {
|
||||||
if ((nextDot >= 0) && (nextDot > nextSpace)) {
|
highlight: [contentPosition.highlight],
|
||||||
previewStart = nextDot + 1;
|
previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd,
|
||||||
ellipsesBefore = false;
|
ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter
|
||||||
break;
|
};
|
||||||
|
var previewPositions = [previewPosition];
|
||||||
|
for (var j = 1; j < contentPositions.length; j++) {
|
||||||
|
contentPosition = contentPositions[j];
|
||||||
|
if (previewPosition.previewEnd < contentPosition.previewStart) {
|
||||||
|
previewPosition = {
|
||||||
|
highlight: [contentPosition.highlight],
|
||||||
|
previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd,
|
||||||
|
ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter
|
||||||
}
|
}
|
||||||
if (nextSpace < 0) {
|
previewPositions.push(previewPosition);
|
||||||
previewStart = 0;
|
} else {
|
||||||
ellipsesBefore = false;
|
previewPosition.highlight.push(contentPosition.highlight);
|
||||||
break;
|
previewPosition.previewEnd = contentPosition.previewEnd;
|
||||||
}
|
previewPosition.ellipsesAfter = contentPosition.ellipsesAfter;
|
||||||
previewStart = nextSpace + 1;
|
|
||||||
}
|
|
||||||
for (var k = 0; k < {{ site.search.preview_words_after | default: 10 }}; k++) {
|
|
||||||
var nextSpace = doc.content.indexOf(' ', previewEnd + 1);
|
|
||||||
var nextDot = doc.content.indexOf('. ', previewEnd + 1);
|
|
||||||
if ((nextDot >= 0) && (nextDot < nextSpace)) {
|
|
||||||
previewEnd = nextDot;
|
|
||||||
ellipsesAfter = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (nextSpace < 0) {
|
|
||||||
previewEnd = doc.content.length;
|
|
||||||
ellipsesAfter = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
previewEnd = nextSpace;
|
|
||||||
}
|
|
||||||
var preview = doc.content.substring(previewStart, start);
|
|
||||||
if (ellipsesBefore) {
|
|
||||||
preview = '... ' + preview;
|
|
||||||
}
|
|
||||||
preview += '<span class="search-result-highlight">' + doc.content.substring(start, end) + '</span>';
|
|
||||||
preview += doc.content.substring(end, previewEnd);
|
|
||||||
if (ellipsesAfter) {
|
|
||||||
preview += ' ...';
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultPreviews = document.createElement('div');
|
||||||
|
resultPreviews.classList.add('search-result-previews');
|
||||||
|
resultLink.appendChild(resultPreviews);
|
||||||
|
|
||||||
|
var content = doc.content;
|
||||||
|
for (var j = 0; j < Math.min(previewPositions.length, {{ site.search.previews | default: 3 }}); j++) {
|
||||||
|
var position = previewPositions[j];
|
||||||
|
|
||||||
var resultPreview = document.createElement('div');
|
var resultPreview = document.createElement('div');
|
||||||
resultPreview.classList.add('search-result-preview');
|
resultPreview.classList.add('search-result-preview');
|
||||||
resultPreview.innerHTML = preview;
|
resultPreviews.appendChild(resultPreview);
|
||||||
resultLink.appendChild(resultPreview);
|
|
||||||
|
if (position.ellipsesBefore) {
|
||||||
|
resultPreview.appendChild(document.createTextNode('... '));
|
||||||
|
}
|
||||||
|
addHighlightedText(resultPreview, content, position.previewStart, position.previewEnd, position.highlight);
|
||||||
|
if (position.ellipsesAfter) {
|
||||||
|
resultPreview.appendChild(document.createTextNode(' ...'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +320,24 @@ function searchLoaded(index, docs) {
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addHighlightedText(parent, text, start, end, positions) {
|
||||||
|
var index = start;
|
||||||
|
for (var i in positions) {
|
||||||
|
var position = positions[i];
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.innerHTML = text.substring(index, position[0]);
|
||||||
|
parent.appendChild(span);
|
||||||
|
index = position[0] + position[1];
|
||||||
|
var highlight = document.createElement('span');
|
||||||
|
highlight.classList.add('search-result-highlight');
|
||||||
|
highlight.innerHTML = text.substring(position[0], index);
|
||||||
|
parent.appendChild(highlight);
|
||||||
|
}
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.innerHTML = text.substring(index, end);
|
||||||
|
parent.appendChild(span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jtd.addEvent(searchInput, 'focus', function(){
|
jtd.addEvent(searchInput, 'focus', function(){
|
||||||
|
@ -34,9 +34,9 @@ permalink: /assets/js/search-data.json
|
|||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- unless i == 0 -%},{%- endunless -%}
|
{%- unless i == 0 -%},{%- endunless -%}
|
||||||
"{{ i }}": {
|
"{{ i }}": {
|
||||||
"doc": "{{ page.title | escape_once }}",
|
"doc": {{ page.title | jsonify }},
|
||||||
"title": "{{ title | escape_once }}",
|
"title": {{ title | jsonify }},
|
||||||
"content": "{{ content | replace: '</h', ' . </h' | replace: '<hr', ' . <hr' | replace: '</p', ' . </p' | replace: '<ul', ' . <ul' | replace: '</ul', ' . </ul' | replace: '<ol', ' . <ol' | replace: '</ol', ' . </ol' | replace: '</tr', ' . </tr' | replace: '<li', ' | <li' | replace: '</li', ' | </li' | replace: '</td', ' | </td' | replace: '<td', ' | <td' | replace: '</th', ' | </th' | replace: '<th', ' | <th' | strip_html | escape_once | remove: 'Table of contents' | replace: '\', '\' | replace: ' . . . ', ' . ' | replace: ' . . ', ' . ' | normalize_whitespace | replace: '| |', '|' }}",
|
"content": {{ content | replace: '</h', ' . </h' | replace: '<hr', ' . <hr' | replace: '</p', ' . </p' | replace: '<ul', ' . <ul' | replace: '</ul', ' . </ul' | replace: '<ol', ' . <ol' | replace: '</ol', ' . </ol' | replace: '</tr', ' . </tr' | replace: '<li', ' | <li' | replace: '</li', ' | </li' | replace: '</td', ' | </td' | replace: '<td', ' | <td' | replace: '</th', ' | </th' | replace: '<th', ' | <th' | strip_html | remove: 'Table of contents' | normalize_whitespace | replace: '. . .', '.' | replace: '. .', '.' | replace: '| |', '|' | append: ' ' | jsonify }},
|
||||||
"url": "{{ url | absolute_url }}",
|
"url": "{{ url | absolute_url }}",
|
||||||
"relUrl": "{{ url }}"
|
"relUrl": "{{ url }}"
|
||||||
}
|
}
|
||||||
@ -45,9 +45,9 @@ permalink: /assets/js/search-data.json
|
|||||||
{%- unless title_found -%}
|
{%- unless title_found -%}
|
||||||
{%- unless i == 0 -%},{%- endunless -%}
|
{%- unless i == 0 -%},{%- endunless -%}
|
||||||
"{{ i }}": {
|
"{{ i }}": {
|
||||||
"doc": "{{ page.title | escape_once }}",
|
"doc": {{ page.title | jsonify }},
|
||||||
"title": "{{ page.title | escape_once }}",
|
"title": {{ page.title | jsonify }},
|
||||||
"content": "{{ parts[0] | replace: '</h', ' . </h' | replace: '<hr', ' . <hr' | replace: '</p', ' . </p' | replace: '<ul', ' . <ul' | replace: '</ul', ' . </ul' | replace: '<ol', ' . <ol' | replace: '</ol', ' . </ol' | replace: '</tr', ' . </tr' | replace: '<li', ' | <li' | replace: '</li', ' | </li' | replace: '</td', ' | </td' | replace: '<td', ' | <td' | replace: '</th', ' | </th' | replace: '<th', ' | <th' | strip_html | escape_once | remove: 'Table of contents' | replace: '\', '\' | replace: ' . . . ', ' . ' | replace: ' . . ', ' . ' | normalize_whitespace | replace: '| |', '|' }}",
|
"content": {{ parts[0] | replace: '</h', ' . </h' | replace: '<hr', ' . <hr' | replace: '</p', ' . </p' | replace: '<ul', ' . <ul' | replace: '</ul', ' . </ul' | replace: '<ol', ' . <ol' | replace: '</ol', ' . </ol' | replace: '</tr', ' . </tr' | replace: '<li', ' | <li' | replace: '</li', ' | </li' | replace: '</td', ' | </td' | replace: '<td', ' | <td' | replace: '</th', ' | </th' | replace: '<th', ' | <th' | strip_html | remove: 'Table of contents' | normalize_whitespace | replace: '. . .', '.' | replace: '. .', '.' | replace: '| |', '|' | append: ' ' | jsonify }},
|
||||||
"url": "{{ page.url | absolute_url }}",
|
"url": "{{ page.url | absolute_url }}",
|
||||||
"relUrl": "{{ page.url }}"
|
"relUrl": "{{ page.url }}"
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@ search:
|
|||||||
# Split documents into sections that can be individually searched
|
# Split documents into sections that can be individually searched
|
||||||
# Supports 1 - 6, default: 2
|
# Supports 1 - 6, default: 2
|
||||||
heading_level: 2
|
heading_level: 2
|
||||||
|
# Maximum amount of previews to display
|
||||||
|
# Default: 3
|
||||||
|
previews: 3
|
||||||
# Maximum amount of words to display before a matched word in the preview
|
# Maximum amount of words to display before a matched word in the preview
|
||||||
# Default: 5
|
# Default: 5
|
||||||
preview_words_before: 5
|
preview_words_before: 5
|
||||||
|
Loading…
x
Reference in New Issue
Block a user