mirror of https://github.com/laurent22/joplin.git
All: Support natural sorting by title (#4272)
parent
9cb576889f
commit
7a6966405c
|
@ -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);
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue