Skip to content

Commit 8968a74

Browse files
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 <[email protected]>
1 parent c7f4c7c commit 8968a74

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

docs/plugins.md

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ By default, the hyperlink on the current page is recognized and the content is s
6262
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
6363
```
6464

65+
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:
66+
67+
```html
68+
<script src="//polyfill.io/v3/polyfill.min.js?features=String.prototype.normalize"></script>
69+
```
70+
6571
## Google Analytics
6672

6773
Install the plugin and configure the track id.

src/plugins/search/search.js

+23-5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ export function genIndex(path, content = '', router, depth) {
131131
return index;
132132
}
133133

134+
export function ignoreDiacriticalMarks(keyword) {
135+
if (keyword && keyword.normalize) {
136+
return keyword.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
137+
}
138+
return keyword;
139+
}
140+
134141
/**
135142
* @param {String} query Search query
136143
* @returns {Array} Array of results
@@ -152,6 +159,8 @@ export function search(query) {
152159
const post = data[i];
153160
let matchesScore = 0;
154161
let resultStr = '';
162+
let handlePostTitle = '';
163+
let handlePostContent = '';
155164
const postTitle = post.title && post.title.trim();
156165
const postContent = post.body && post.body.trim();
157166
const postUrl = post.slug || '';
@@ -160,14 +169,23 @@ export function search(query) {
160169
keywords.forEach(keyword => {
161170
// From https://github.com/sindresorhus/escape-string-regexp
162171
const regEx = new RegExp(
163-
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
172+
ignoreDiacriticalMarks(keyword).replace(
173+
/[|\\{}()[\]^$+*?.]/g,
174+
'\\$&'
175+
),
164176
'gi'
165177
);
166178
let indexTitle = -1;
167179
let indexContent = -1;
180+
handlePostTitle = postTitle
181+
? ignoreDiacriticalMarks(postTitle)
182+
: postTitle;
183+
handlePostContent = postContent
184+
? ignoreDiacriticalMarks(postContent)
185+
: postContent;
168186

169-
indexTitle = postTitle ? postTitle.search(regEx) : -1;
170-
indexContent = postContent ? postContent.search(regEx) : -1;
187+
indexTitle = postTitle ? handlePostTitle.search(regEx) : -1;
188+
indexContent = postContent ? handlePostContent.search(regEx) : -1;
171189

172190
if (indexTitle >= 0 || indexContent >= 0) {
173191
matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0;
@@ -187,7 +205,7 @@ export function search(query) {
187205

188206
const matchContent =
189207
'...' +
190-
escapeHtml(postContent)
208+
handlePostContent
191209
.substring(start, end)
192210
.replace(
193211
regEx,
@@ -201,7 +219,7 @@ export function search(query) {
201219

202220
if (matchesScore > 0) {
203221
const matchingPost = {
204-
title: escapeHtml(postTitle),
222+
title: handlePostTitle,
205223
content: postContent ? resultStr : '',
206224
url: postUrl,
207225
score: matchesScore,

test/e2e/search.test.js

+19
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,23 @@ describe('Search Plugin Tests', function() {
105105
await page.fill('input[type=search]', 'test');
106106
await expect(page).toEqualText('.results-panel h2', 'Test Page');
107107
});
108+
109+
test('search ignore diacritical marks', async () => {
110+
const docsifyInitConfig = {
111+
markdown: {
112+
homepage: `
113+
# Qué es
114+
115+
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.
116+
`,
117+
},
118+
scriptURLs: ['/lib/plugins/search.min.js'],
119+
};
120+
await docsifyInit(docsifyInitConfig);
121+
await page.fill('input[type=search]', 'documentacion');
122+
await expect(page).toEqualText('.results-panel h2', 'Que es');
123+
await page.click('.clear-button');
124+
await page.fill('input[type=search]', 'estáticos');
125+
await expect(page).toEqualText('.results-panel h2', 'Que es');
126+
});
108127
});

0 commit comments

Comments
 (0)