Ignore diacritics when searching presets (close #8242)

This commit is contained in:
Quincy Morgan
2020-12-09 17:12:43 -05:00
parent e3394a4821
commit b3ad282f40
3 changed files with 50 additions and 24 deletions

View File

@@ -8,6 +8,7 @@ import { presetCollection } from './collection';
//
export function presetCategory(categoryID, category, all) {
let _this = Object.assign({}, category); // shallow copy
let _searchName; // cache
_this.id = categoryID;
@@ -38,6 +39,16 @@ export function presetCategory(categoryID, category, all) {
_this.terms = () => [];
_this.searchName = () => {
if (!_searchName) {
_searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
// split combined diacritical characters into their parts
if (_searchName.normalize) _searchName = _searchName.normalize('NFD');
// remove diacritics
_searchName = _searchName.replace(/[\u0300-\u036f]/g, '');
}
return _searchName;
};
return _this;
}

View File

@@ -49,6 +49,10 @@ export function presetCollection(collection) {
if (!value) return _this;
value = value.toLowerCase().trim();
// split combined diacritical characters into their parts
if (value.normalize) value = value.normalize('NFD');
// remove diacritics
value = value.replace(/[\u0300-\u036f]/g, '');
// match at name beginning or just after a space (e.g. "office" -> match "Law Office")
function leading(a) {
@@ -63,8 +67,8 @@ export function presetCollection(collection) {
}
function sortNames(a, b) {
let aCompare = (a.suggestion ? a.originalName : a.name()).toLowerCase();
let bCompare = (b.suggestion ? b.originalName : b.name()).toLowerCase();
let aCompare = a.searchName();
let bCompare = b.searchName();
// priority if search string matches preset name exactly - #4325
if (value === aCompare) return -1;
@@ -96,52 +100,52 @@ export function presetCollection(collection) {
const suggestions = pool.filter(a => a.suggestion === true);
// matches value to preset.name
const leading_name = searchable
.filter(a => leading(a.name().toLowerCase()))
const leadingName = searchable
.filter(a => leading(a.searchName()))
.sort(sortNames);
// matches value to preset suggestion name (original name is unhyphenated)
const leading_suggestions = suggestions
.filter(a => leadingStrict(a.originalName.toLowerCase()))
// matches value to preset suggestion name
const leadingSuggestions = suggestions
.filter(a => leadingStrict(a.searchName()))
.sort(sortNames);
// matches value to preset.terms values
const leading_terms = searchable
const leadingTerms = searchable
.filter(a => (a.terms() || []).some(leading));
// matches value to preset.tags values
const leading_tag_values = searchable
const leadingTagValues = searchable
.filter(a => Object.values(a.tags || {}).filter(val => val !== '*').some(leading));
// finds close matches to value in preset.name
const similar_name = searchable
.map(a => ({ preset: a, dist: utilEditDistance(value, a.name()) }))
.filter(a => a.dist + Math.min(value.length - a.preset.name().length, 0) < 3)
const similarName = searchable
.map(a => ({ preset: a, dist: utilEditDistance(value, a.searchName()) }))
.filter(a => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3)
.sort((a, b) => a.dist - b.dist)
.map(a => a.preset);
// finds close matches to value to preset suggestion name (original name is unhyphenated)
const similar_suggestions = suggestions
.map(a => ({ preset: a, dist: utilEditDistance(value, a.originalName.toLowerCase()) }))
.filter(a => a.dist + Math.min(value.length - a.preset.originalName.length, 0) < 1)
// finds close matches to value to preset suggestion name
const similarSuggestions = suggestions
.map(a => ({ preset: a, dist: utilEditDistance(value, a.searchName()) }))
.filter(a => a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1)
.sort((a, b) => a.dist - b.dist)
.map(a => a.preset);
// finds close matches to value in preset.terms
const similar_terms = searchable
const similarTerms = searchable
.filter(a => {
return (a.terms() || []).some(b => {
return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
});
});
let results = leading_name.concat(
leading_suggestions,
leading_terms,
leading_tag_values,
similar_name,
similar_suggestions,
similar_terms
let results = leadingName.concat(
leadingSuggestions,
leadingTerms,
leadingTagValues,
similarName,
similarSuggestions,
similarTerms
).slice(0, MAXRESULTS - 1);
if (geometry) {

View File

@@ -15,6 +15,7 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
let _addable = addable || false;
let _resolvedFields; // cache
let _resolvedMoreFields; // cache
let _searchName; // cache
_this.id = presetID;
@@ -120,6 +121,16 @@ export function presetPreset(presetID, preset, addable, allFields, allPresets) {
_this.terms = () => _this.t('terms', { 'default': _this.originalTerms })
.toLowerCase().trim().split(/\s*,+\s*/);
_this.searchName = () => {
if (!_searchName) {
_searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
// split combined diacritical characters into their parts
if (_searchName.normalize) _searchName = _searchName.normalize('NFD');
// remove diacritics
_searchName = _searchName.replace(/[\u0300-\u036f]/g, '');
}
return _searchName;
};
_this.isFallback = () => {
const tagCount = Object.keys(_this.tags).length;