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'); + }); });