Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore diacritics by default when searching #1243

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions src/angular-app/bellows/core/offline/editor-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class EntryListModifiers {
sortOptions: SortOption[] = [];
sortReverse = false;
wholeWord = false;
matchDiacritic = false;
filterBy: {
text: string;
option: FilterOption;
Expand Down Expand Up @@ -450,18 +451,36 @@ export class EditorDataService {
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matche
}

private removeDiacritics(input: string) {
// refs:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
// https://unicode.org/reports/tr44/#Diacritic
// https://stackoverflow.com/a/37511463/10818013

return input.normalize('NFD').replace(/\p{Diacritic}/gu, '')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💥 This is it! Well done, and elegant too. I didn't know about Regex Unicode Property Escapes so my own solution probably would have been multiple lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great, I'm glad you're pleased with it, thanks for reviewing. Just to confirm, you're good with the browser support and you think \p{Diacritic} is good, no need to further investigate InCombiningDiacriticalMarks?

}

private entryMeetsFilterCriteria(config: any, entry: LexEntry): boolean {
if (this.entryListModifiers.filterText() !== '') {
const query = this.escapeRegex(this.entryListModifiers.filterText());
const queryRegex = new RegExp(this.entryListModifiers.wholeWord ? `\\b${query}\\b` : query, 'i');
const rawQuery = this.entryListModifiers.filterText()
const normalizedQuery = this.entryListModifiers.matchDiacritic ? rawQuery : this.removeDiacritics(rawQuery);
const regexSafeQuery = this.escapeRegex(normalizedQuery);
const queryRegex = new RegExp(this.entryListModifiers.wholeWord ? `\\b${regexSafeQuery}\\b` : regexSafeQuery, 'i');
let found = false;

this.walkEntry(config.entry, entry, (val, isSemanticDomain) => {
if (queryRegex.test(val) || (isSemanticDomain && this.semanticDomainsMatch(val, query))) {
found = true
if (isSemanticDomain && this.semanticDomainsMatch(val, rawQuery)) {
found = true;
} else {
const normalizedValue = this.entryListModifiers.matchDiacritic ? val : this.removeDiacritics(val)

if (queryRegex.test(normalizedValue)) {
found = true;
}
}
});

if (!found) return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,21 @@
<div class="form-group sortfilter-form">
<label class="font-weight-bold" for="sortEntriesBy">Advanced</label>

<section class="d-flex justify-content-around">
<label>
<section class="d-flex flex-wrap">
<label class="mr-3">
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.sortReverse" class="align-middle">
<span class="align-middle pl-1">Reverse</span>
</label>
<label>

<label class="mr-3">
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.wholeWord" class="align-middle">
<span class="align-middle pl-1">Whole word</span>
</label>

<label class="mr-3">
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.matchDiacritic" class="align-middle">
<span class="align-middle pl-1">Match diacritics</span>
</label>
</section>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,21 @@
<div class="sortfilter-form h-100">
<label class="font-weight-bold">Advanced</label>

<section class="d-flex justify-content-around">
<label>
<section class="d-flex flex-wrap">
<label class="mr-3">
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.sortReverse" class="align-middle">
<span class="align-middle pl-1">Reverse</span>
</label>

<label>
<label class="mr-3">
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.wholeWord" class="align-middle">
<span class="align-middle pl-1">Whole word</span>
</label>

<label>
<input type="checkbox" data-ng-change="$ctrl.filterAndSortEntries()" data-ng-model="$ctrl.entryListModifiers.matchDiacritic" class="align-middle">
<span class="align-middle pl-1">Match diacritics</span>
</label>
</section>
</div>
</div>
Expand Down
10 changes: 8 additions & 2 deletions src/angular-app/languageforge/lexicon/editor/editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ export class LexiconEditorController implements angular.IController {
filterText: this.$state.params.filterText,
sortReverse: this.$state.params.sortReverse,
wholeWord: this.$state.params.wholeWord,
matchDiacritic: this.$state.params.matchDiacritic,
filterType: this.$state.params.filterType,
filterBy: this.$state.params.filterBy
}, { notify: true });
Expand Down Expand Up @@ -270,6 +271,7 @@ export class LexiconEditorController implements angular.IController {
}
this.entryListModifiers.sortReverse = this.$state.params.sortReverse === 'true';
this.entryListModifiers.wholeWord = this.$state.params.wholeWord === 'true';
this.entryListModifiers.matchDiacritic = this.$state.params.matchDiacritic === 'true';

if (this.$state.params.filterType) {
this.entryListModifiers.filterType = this.$state.params.filterType;
Expand Down Expand Up @@ -299,6 +301,7 @@ export class LexiconEditorController implements angular.IController {
filterText: this.entryListModifiers.filterText(),
sortReverse: this.entryListModifiers.sortReverse,
wholeWord: this.entryListModifiers.wholeWord,
matchDiacritic: this.entryListModifiers.matchDiacritic,
filterType: this.entryListModifiers.filterType,
filterBy: this.entryListModifiers.filterByLabel()
}, { notify: false });
Expand All @@ -307,7 +310,7 @@ export class LexiconEditorController implements angular.IController {

filterOptionsActive() {
const mod = this.entryListModifiers;
return (mod.filterBy && mod.filterBy.option) || mod.sortBy.value !== 'default' || mod.sortReverse || mod.wholeWord
return (mod.filterBy && mod.filterBy.option) || mod.sortBy.value !== 'default' || mod.sortReverse || mod.wholeWord || mod.matchDiacritic
}

shouldShowFilterReset() {
Expand All @@ -318,6 +321,7 @@ export class LexiconEditorController implements angular.IController {
resetEntryListFilter(): void {
this.entryListModifiers.filterBy = null;
this.entryListModifiers.wholeWord = false;
this.entryListModifiers.matchDiacritic = false;

this.filterAndSortEntries();
}
Expand Down Expand Up @@ -921,6 +925,7 @@ export class LexiconEditorController implements angular.IController {
filterText: this.entryListModifiers.filterText(),
sortReverse: this.entryListModifiers.sortReverse,
wholeWord: this.entryListModifiers.wholeWord,
matchDiacritic: this.entryListModifiers.matchDiacritic,
filterType: this.entryListModifiers.filterType,
filterBy: this.entryListModifiers.filterByLabel()
}, { notify: false });
Expand All @@ -931,6 +936,7 @@ export class LexiconEditorController implements angular.IController {
filterText: this.$state.params.filterText,
sortReverse: this.$state.params.sortReverse,
wholeWord: this.$state.params.wholeWord,
matchDiacritic: this.$state.params.matchDiacritic,
filterType: this.$state.params.filterType,
filterBy: this.$state.params.filterBy
});
Expand Down Expand Up @@ -1245,7 +1251,7 @@ export class LexiconEditorController implements angular.IController {
private static scrollDivToId(containerId: string, divId: string, posOffset: number = 0): void {
const $containerDiv: any = $(containerId)
const $div: any = $(divId)[0];

if ($div && $containerDiv.scrollTop) {
let offsetTop: number = $div.offsetTop - posOffset;

Expand Down
4 changes: 2 additions & 2 deletions src/angular-app/languageforge/lexicon/editor/editor.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ export const LexiconEditorModule = angular
lec-rights="$ctrl.rights"></lexicon-editor>`
})
.state('editor.list', {
url: '/list?sortBy&filterText&sortReverse&wholeWord&filterType&filterBy',
url: '/list?sortBy&filterText&sortReverse&wholeWord&matchDiacritic&filterType&filterBy',
templateUrl: '/angular-app/languageforge/lexicon/editor/editor-list.view.html',
controller: 'EditorListCtrl'
})
.state('editor.entry', {
url: '/entry/{entryId:[0-9a-z_]{6,24}}?sortBy&filterText&sortReverse&wholeWord&filterType&filterBy',
url: '/entry/{entryId:[0-9a-z_]{6,24}}?sortBy&filterText&sortReverse&wholeWord&matchDiacritic&filterType&filterBy',
templateUrl: '/angular-app/languageforge/lexicon/editor/editor-entry.view.html',
controller: 'EditorEntryCtrl'
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const LexiconAppModule = angular
// this is needed to allow style="font-family" on ng-bind-html elements
$sanitizeProvider.addValidAttrs(['style']);

$urlRouterProvider.otherwise('/editor/list?sortBy=Default&sortReverse=false&wholeWord=false&filterType=isNotEmpty&filterBy=null');
$urlRouterProvider.otherwise('/editor/list?sortBy=Default&sortReverse=false&wholeWord=false&matchDiacritic=false&filterType=isNotEmpty&filterBy=null');

// State machine from ui.router
$stateProvider
Expand Down