feat: search ignore diacritical marks (#1434)

* feat: search ignore diacritical marks

* Check if normalize is supported

* Update docs

* Fix escape

* remove escapeHtml

Co-authored-by: John Hildenbiddle <jhildenbiddle@users.noreply.github.com>
This commit is contained in:
沈唁 2021-02-05 13:40:26 +08:00 committed by GitHub
parent c7f4c7cf9b
commit 8968a744ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 5 deletions

View File

@ -62,6 +62,12 @@ By default, the hyperlink on the current page is recognized and the content is s
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
```
This plugin ignores diacritical marks when performing a full text search (e.g., "cafe" will also match "café"). Legacy browsers like IE11 require the following [String.normalize()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize) polyfill to ignore diacritical marks:
```html
<script src="//polyfill.io/v3/polyfill.min.js?features=String.prototype.normalize"></script>
```
## Google Analytics
Install the plugin and configure the track id.

View File

@ -131,6 +131,13 @@ export function genIndex(path, content = '', router, depth) {
return index;
}
export function ignoreDiacriticalMarks(keyword) {
if (keyword && keyword.normalize) {
return keyword.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
return keyword;
}
/**
* @param {String} query Search query
* @returns {Array} Array of results
@ -152,6 +159,8 @@ export function search(query) {
const post = data[i];
let matchesScore = 0;
let resultStr = '';
let handlePostTitle = '';
let handlePostContent = '';
const postTitle = post.title && post.title.trim();
const postContent = post.body && post.body.trim();
const postUrl = post.slug || '';
@ -160,14 +169,23 @@ export function search(query) {
keywords.forEach(keyword => {
// From https://github.com/sindresorhus/escape-string-regexp
const regEx = new RegExp(
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
ignoreDiacriticalMarks(keyword).replace(
/[|\\{}()[\]^$+*?.]/g,
'\\$&'
),
'gi'
);
let indexTitle = -1;
let indexContent = -1;
handlePostTitle = postTitle
? ignoreDiacriticalMarks(postTitle)
: postTitle;
handlePostContent = postContent
? ignoreDiacriticalMarks(postContent)
: postContent;
indexTitle = postTitle ? postTitle.search(regEx) : -1;
indexContent = postContent ? postContent.search(regEx) : -1;
indexTitle = postTitle ? handlePostTitle.search(regEx) : -1;
indexContent = postContent ? handlePostContent.search(regEx) : -1;
if (indexTitle >= 0 || indexContent >= 0) {
matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0;
@ -187,7 +205,7 @@ export function search(query) {
const matchContent =
'...' +
escapeHtml(postContent)
handlePostContent
.substring(start, end)
.replace(
regEx,
@ -201,7 +219,7 @@ export function search(query) {
if (matchesScore > 0) {
const matchingPost = {
title: escapeHtml(postTitle),
title: handlePostTitle,
content: postContent ? resultStr : '',
url: postUrl,
score: matchesScore,

View File

@ -105,4 +105,23 @@ describe('Search Plugin Tests', function() {
await page.fill('input[type=search]', 'test');
await expect(page).toEqualText('.results-panel h2', 'Test Page');
});
test('search ignore diacritical marks', async () => {
const docsifyInitConfig = {
markdown: {
homepage: `
# Qué es
docsify genera su sitio web de documentación sobre la marcha. A diferencia de GitBook, no genera archivos estáticos html. En cambio, carga y analiza de forma inteligente sus archivos de Markdown y los muestra como sitio web. Todo lo que necesita hacer es crear un index.html para comenzar y desplegarlo en GitHub Pages.
`,
},
scriptURLs: ['/lib/plugins/search.min.js'],
};
await docsifyInit(docsifyInitConfig);
await page.fill('input[type=search]', 'documentacion');
await expect(page).toEqualText('.results-panel h2', 'Que es');
await page.click('.clear-button');
await page.fill('input[type=search]', 'estáticos');
await expect(page).toEqualText('.results-panel h2', 'Que es');
});
});