Add Ignore Diacritics search option

This commit is contained in:
Robbie Antenesse 2019-05-08 14:09:00 -06:00
parent a6727bd0e4
commit 29488f2ed5
4 changed files with 90 additions and 14 deletions

View File

@ -35,6 +35,9 @@
<label>Case-Sensitive
<input type="checkbox" id="searchCaseSensitive">
</label>
<label>Ignore Diacritics/Accents
<input type="checkbox" id="searchIgnoreDiacritics">
</label>
<label>Exact Words
<input type="checkbox" id="searchExactWords">
</label>

View File

@ -32,3 +32,21 @@ export function removeTags(html) {
export function slugify(string) {
return removeDiacritics(string).replace(/[!a-zA-Z0-9-_]/g, '-');
}
export function getIndicesOf(searchStr, findIn, caseSensitive) {
// https://stackoverflow.com/a/3410557
const searchStrLen = searchStr.length;
if (searchStrLen == 0) {
return [];
}
let startIndex = 0, index, indices = [];
if (!caseSensitive) {
findIn = findIn.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ((index = findIn.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}

View File

@ -1,4 +1,5 @@
import { cloneObject } from "../helpers";
import { cloneObject, getIndicesOf } from "../helpers";
import removeDiacritics from "./StackOverflow/removeDiacritics";
export function getSearchTerm() {
return document.getElementById('searchBox').value;
@ -7,6 +8,7 @@ export function getSearchTerm() {
export function getSearchFilters() {
const filters = {
caseSensitive: document.getElementById('searchCaseSensitive').checked,
ignoreDiacritics: document.getElementById('searchIgnoreDiacritics').checked,
exact: document.getElementById('searchExactWords').checked,
name: document.getElementById('searchIncludeName').checked,
definition: document.getElementById('searchIncludeDefinition').checked,
@ -39,17 +41,19 @@ export function getMatchingSearchWords() {
}
return true;
}).filter(word => {
searchTerm = filters.ignoreDiacritics ? removeDiacritics(searchTerm) : searchTerm;
searchTerm = filters.caseSensitive ? searchTerm : searchTerm.toLowerCase();
const name = filters.caseSensitive ? word.name : word.name.toLowerCase();
const simpleDefinition = filters.caseSensitive ? word.simpleDefinition : word.simpleDefinition.toLowerCase();
const longDefinition = filters.caseSensitive ? word.longDefinition : word.longDefinition.toLowerCase();
let name = filters.ignoreDiacritics ? removeDiacritics(word.name) : word.name;
name = filters.caseSensitive ? name : name.toLowerCase();
let simpleDefinition = filters.ignoreDiacritics ? removeDiacritics(word.simpleDefinition) : word.simpleDefinition;
simpleDefinition = filters.caseSensitive ? simpleDefinition : simpleDefinition.toLowerCase();
let longDefinition = filters.ignoreDiacritics ? removeDiacritics(word.longDefinition) : word.longDefinition;
longDefinition = filters.caseSensitive ? longDefinition : longDefinition.toLowerCase();
const isInName = filters.name
&& (filters.exact
const isInName = filters.name && (filters.exact
? searchTerm == name
: new RegExp(searchTerm, 'g').test(name));
const isInDefinition = filters.definition
&& (filters.exact
const isInDefinition = filters.definition && (filters.exact
? searchTerm == simpleDefinition
: new RegExp(searchTerm, 'g').test(simpleDefinition));
const isInDetails = filters.details && new RegExp(searchTerm, 'g').test(longDefinition);
@ -62,14 +66,52 @@ export function getMatchingSearchWords() {
}
export function highlightSearchTerm(word) {
const searchTerm = getSearchTerm();
let searchTerm = getSearchTerm();
if (searchTerm) {
const filters = getSearchFilters();
const regexMethod = 'g' + (filters.caseSensitive ? '' : 'i');
const markedUpWord = cloneObject(word);
markedUpWord.name = markedUpWord.name.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
markedUpWord.simpleDefinition = markedUpWord.simpleDefinition.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
markedUpWord.longDefinition = markedUpWord.longDefinition.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
if (filters.ignoreDiacritics) {
const searchTermLength = searchTerm.length;
searchTerm = removeDiacritics(searchTerm);
if (filters.name) {
const nameMatches = getIndicesOf(searchTerm, removeDiacritics(markedUpWord.name), filters.caseSensitive);
nameMatches.forEach((wordIndex, i) => {
wordIndex += '<mark></mark>'.length * i;
markedUpWord.name = markedUpWord.name.substring(0, wordIndex)
+ '<mark>' + markedUpWord.name.substr(wordIndex, searchTermLength) + '</mark>'
+ markedUpWord.name.substr(wordIndex + searchTermLength);
});
}
if (filters.definition) {
const simpleDefinitionMatches = getIndicesOf(searchTerm, removeDiacritics(markedUpWord.simpleDefinition), filters.caseSensitive);
simpleDefinitionMatches.forEach((wordIndex, i) => {
wordIndex += '<mark></mark>'.length * i;
markedUpWord.simpleDefinition = markedUpWord.simpleDefinition.substring(0, wordIndex)
+ '<mark>' + markedUpWord.simpleDefinition.substr(wordIndex, searchTermLength) + '</mark>'
+ markedUpWord.simpleDefinition.substr(wordIndex + searchTermLength);
});
}
if (filters.details) {
const longDefinitionMatches = getIndicesOf(searchTerm, removeDiacritics(markedUpWord.longDefinition), filters.caseSensitive);
longDefinitionMatches.forEach((wordIndex, i) => {
wordIndex += '<mark></mark>'.length * i;
markedUpWord.longDefinition = markedUpWord.longDefinition.substring(0, wordIndex)
+ '<mark>' + markedUpWord.longDefinition.substr(wordIndex, searchTermLength) + '</mark>'
+ markedUpWord.longDefinition.substr(wordIndex + searchTermLength);
});
}
} else {
const regexMethod = 'g' + (filters.caseSensitive ? '' : 'i');
if (filters.name) {
markedUpWord.name = markedUpWord.name.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
}
if (filters.definition) {
markedUpWord.simpleDefinition = markedUpWord.simpleDefinition.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
}
if (filters.details) {
markedUpWord.longDefinition = markedUpWord.longDefinition.replace(new RegExp(`(${searchTerm})`, regexMethod), `<mark>$1</mark>`);
}
}
return markedUpWord;
}
return word;

View File

@ -84,6 +84,7 @@ function setupSearchBar() {
const searchBox = document.getElementById('searchBox'),
clearSearchButton = document.getElementById('clearSearchButton'),
openSearchModal = document.getElementById('openSearchModal'),
searchIgnoreDiacritics = document.getElementById('searchIgnoreDiacritics'),
searchExactWords = document.getElementById('searchExactWords'),
searchIncludeDetails = document.getElementById('searchIncludeDetails');
searchBox.addEventListener('change', () => {
@ -102,7 +103,7 @@ function setupSearchBar() {
searchBox.focus();
});
searchExactWords.addEventListener('change', () => {
const toggleDetailsCheck = function() {
if (searchExactWords.checked) {
searchIncludeDetails.checked = false;
searchIncludeDetails.disabled = true;
@ -110,7 +111,19 @@ function setupSearchBar() {
searchIncludeDetails.disabled = false;
searchIncludeDetails.checked = true;
}
}
searchIgnoreDiacritics.addEventListener('change', () => {
if (searchIgnoreDiacritics.checked) {
searchExactWords.checked = false;
searchExactWords.disabled = true;
} else {
searchExactWords.disabled = false;
}
toggleDetailsCheck();
});
searchExactWords.addEventListener('change', () => toggleDetailsCheck());
}
export function setupSearchFilters() {