All: Support natural sorting by title (#4272)

pull/4306/head
Jerry Zhao 2021-01-07 08:29:53 -08:00 committed by GitHub
parent 9cb576889f
commit 7a6966405c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 4 deletions

View File

@ -271,4 +271,48 @@ describe('models_Note', function() {
expect(result).toBe(`[](:/${note1.id})`);
}));
it('should perform natural sorting', (async () => {
const folder1 = await Folder.save({});
const sortedNotes = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
});
expect(sortedNotes.length).toBe(0);
const note0 = await Note.save({ title: 'A3', parent_id: folder1.id, is_todo: false });
const note1 = await Note.save({ title: 'A20', parent_id: folder1.id, is_todo: false });
const note2 = await Note.save({ title: 'A100', parent_id: folder1.id, is_todo: false });
const note3 = await Note.save({ title: 'égalité', parent_id: folder1.id, is_todo: false });
const note4 = await Note.save({ title: 'z', parent_id: folder1.id, is_todo: false });
const sortedNotes2 = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
});
expect(sortedNotes2.length).toBe(5);
expect(sortedNotes2[0].id).toBe(note0.id);
expect(sortedNotes2[1].id).toBe(note1.id);
expect(sortedNotes2[2].id).toBe(note2.id);
expect(sortedNotes2[3].id).toBe(note3.id);
expect(sortedNotes2[4].id).toBe(note4.id);
const todo3 = Note.changeNoteType(note3, 'todo');
const todo4 = Note.changeNoteType(note4, 'todo');
await Note.save(todo3);
await Note.save(todo4);
const sortedNotes3 = await Note.previews(folder1.id, {
fields: ['id', 'title'],
order: [{ by: 'title', dir: 'ASC' }],
uncompletedTodosOnTop: true,
});
expect(sortedNotes3.length).toBe(5);
expect(sortedNotes3[0].id).toBe(note3.id);
expect(sortedNotes3[1].id).toBe(note4.id);
expect(sortedNotes3[2].id).toBe(note0.id);
expect(sortedNotes3[3].id).toBe(note1.id);
expect(sortedNotes3[4].id).toBe(note2.id);
}));
});

View File

@ -109,7 +109,10 @@ def enableProguardInReleaseBuilds = false
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
// We need the intl variant to support natural sorting of notes.
// https://github.com/laurent22/joplin/pull/4272
def jscFlavor = 'org.webkit:android-jsc-intl:+'
/**
* Whether to enable the Hermes VM.

View File

@ -260,6 +260,8 @@ class Note extends BaseItem {
return noteFieldComp(a.id, b.id);
};
const collator = this.getNaturalSortingCollator();
return notes.sort((a, b) => {
if (noteOnTop(a) && !noteOnTop(b)) return -1;
if (!noteOnTop(a) && noteOnTop(b)) return +1;
@ -272,8 +274,13 @@ class Note extends BaseItem {
let bProp = b[order.by];
if (typeof aProp === 'string') aProp = aProp.toLowerCase();
if (typeof bProp === 'string') bProp = bProp.toLowerCase();
if (aProp < bProp) r = +1;
if (aProp > bProp) r = -1;
if (order.by === 'title') {
r = -1 * collator.compare(aProp, bProp);
} else {
if (aProp < bProp) r = +1;
if (aProp > bProp) r = -1;
}
if (order.dir == 'ASC') r = -r;
if (r !== 0) return r;
}
@ -377,6 +384,7 @@ class Note extends BaseItem {
tempOptions.conditions = cond;
const uncompletedTodos = await this.search(tempOptions);
this.handleTitleNaturalSorting(uncompletedTodos, tempOptions);
cond = options.conditions.slice();
if (hasNotes && hasTodos) {
@ -389,6 +397,7 @@ class Note extends BaseItem {
tempOptions.conditions = cond;
if ('limit' in tempOptions) tempOptions.limit -= uncompletedTodos.length;
const theRest = await this.search(tempOptions);
this.handleTitleNaturalSorting(theRest, tempOptions);
return uncompletedTodos.concat(theRest);
}
@ -401,7 +410,10 @@ class Note extends BaseItem {
options.conditions.push('is_todo = 1');
}
return this.search(options);
const results = await this.search(options);
this.handleTitleNaturalSorting(results, options);
return results;
}
static preview(noteId, options = null) {
@ -862,6 +874,17 @@ class Note extends BaseItem {
}
}
static handleTitleNaturalSorting(items, options) {
if (options.order.length > 0 && options.order[0].by === 'title') {
const collator = this.getNaturalSortingCollator();
items.sort((a, b) => ((options.order[0].dir === 'ASC') ? 1 : -1) * collator.compare(a.title, b.title));
}
}
static getNaturalSortingCollator() {
return new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
}
}
Note.updateGeolocationEnabled_ = true;