diff --git a/docs/plugins.md b/docs/plugins.md
index c56514d1a..cd7016d6b 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -62,6 +62,12 @@ By default, the hyperlink on the current page is recognized and the content is s
```
+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
+
+```
+
## Google Analytics
Install the plugin and configure the track id.
diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js
index e16c3a313..dd809d791 100644
--- a/src/plugins/search/search.js
+++ b/src/plugins/search/search.js
@@ -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,
diff --git a/test/e2e/search.test.js b/test/e2e/search.test.js
index dcdc6c872..8afce5500 100644
--- a/test/e2e/search.test.js
+++ b/test/e2e/search.test.js
@@ -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');
+ });
});