mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-05 09:25:03 +00:00
Enhancement: diacritic-insensitive UI filters
This commit is contained in:
+2
-3
@@ -23,6 +23,7 @@ import {
|
||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { pngxPopperOptions } from 'src/app/utils/popper-options'
|
||||
import { matchesSearchText } from 'src/app/utils/text-search'
|
||||
import { LoadingComponentWithPermissions } from '../../loading-component/loading.component'
|
||||
import { CustomFieldEditDialogComponent } from '../edit-dialog/custom-field-edit-dialog/custom-field-edit-dialog.component'
|
||||
|
||||
@@ -69,9 +70,7 @@ export class CustomFieldsDropdownComponent extends LoadingComponentWithPermissio
|
||||
|
||||
public get filteredFields(): CustomField[] {
|
||||
return this.unusedFields.filter(
|
||||
(f) =>
|
||||
!this.filterText ||
|
||||
f.name.toLowerCase().includes(this.filterText.toLowerCase())
|
||||
(f) => !this.filterText || matchesSearchText(f.name, this.filterText)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { MatchingModel } from '../data/matching-model'
|
||||
import { matchesSearchText } from '../utils/text-search'
|
||||
|
||||
@Pipe({
|
||||
name: 'filter',
|
||||
@@ -21,9 +22,7 @@ export class FilterPipe implements PipeTransform {
|
||||
typeof item[key] === 'string' || typeof item[key] === 'number'
|
||||
)
|
||||
return keys.some((key) => {
|
||||
return String(item[key])
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase())
|
||||
return matchesSearchText(item[key], searchText)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { matchesSearchText } from './text-search'
|
||||
|
||||
describe('text search utilities', () => {
|
||||
it('matches text accent-insensitively', () => {
|
||||
expect(matchesSearchText('R\u00e9sum\u00e9', 'resume')).toBeTruthy()
|
||||
expect(matchesSearchText('S\u00f8ren', 'soren')).toBeTruthy()
|
||||
expect(matchesSearchText('\u0152uvre', 'oeuvre')).toBeTruthy()
|
||||
expect(matchesSearchText('Invoice', 'receipt')).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,42 @@
|
||||
const EXTRA_DIACRITIC_REPLACEMENTS: Record<string, string> = {
|
||||
'\u00c6': 'AE',
|
||||
'\u00e6': 'ae',
|
||||
'\u00d0': 'D',
|
||||
'\u00f0': 'd',
|
||||
'\u00d8': 'O',
|
||||
'\u00f8': 'o',
|
||||
'\u00de': 'Th',
|
||||
'\u00fe': 'th',
|
||||
'\u0110': 'D',
|
||||
'\u0111': 'd',
|
||||
'\u0131': 'i',
|
||||
'\u0141': 'L',
|
||||
'\u0142': 'l',
|
||||
'\u0152': 'OE',
|
||||
'\u0153': 'oe',
|
||||
'\u00df': 'ss',
|
||||
}
|
||||
|
||||
// ng-select has a similar private helper stripSpecialChars, but we can't use it
|
||||
const EXTRA_DIACRITICS_PATTERN = new RegExp(
|
||||
`[${Object.keys(EXTRA_DIACRITIC_REPLACEMENTS).join('')}]`,
|
||||
'g'
|
||||
)
|
||||
|
||||
function normalizeSearchText(value: unknown): string {
|
||||
return String(value ?? '')
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(
|
||||
EXTRA_DIACRITICS_PATTERN,
|
||||
(char) => EXTRA_DIACRITIC_REPLACEMENTS[char] ?? char
|
||||
)
|
||||
.toLocaleLowerCase()
|
||||
}
|
||||
|
||||
export function matchesSearchText(
|
||||
value: unknown,
|
||||
searchText: unknown
|
||||
): boolean {
|
||||
return normalizeSearchText(value).includes(normalizeSearchText(searchText))
|
||||
}
|
||||
Reference in New Issue
Block a user