You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-13 22:12:50 +02:00
All: Support natural sorting by title (#4272)
This commit is contained in:
@@ -271,4 +271,48 @@ describe('models_Note', function() {
|
|||||||
expect(result).toBe(`[](:/${note1.id})`);
|
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
|
* give correct results when using with locales other than en-US. Note that
|
||||||
* this variant is about 6MiB larger per architecture than default.
|
* 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.
|
* Whether to enable the Hermes VM.
|
||||||
|
@@ -260,6 +260,8 @@ class Note extends BaseItem {
|
|||||||
return noteFieldComp(a.id, b.id);
|
return noteFieldComp(a.id, b.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const collator = this.getNaturalSortingCollator();
|
||||||
|
|
||||||
return notes.sort((a, b) => {
|
return notes.sort((a, b) => {
|
||||||
if (noteOnTop(a) && !noteOnTop(b)) return -1;
|
if (noteOnTop(a) && !noteOnTop(b)) return -1;
|
||||||
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];
|
let bProp = b[order.by];
|
||||||
if (typeof aProp === 'string') aProp = aProp.toLowerCase();
|
if (typeof aProp === 'string') aProp = aProp.toLowerCase();
|
||||||
if (typeof bProp === 'string') bProp = bProp.toLowerCase();
|
if (typeof bProp === 'string') bProp = bProp.toLowerCase();
|
||||||
|
|
||||||
|
if (order.by === 'title') {
|
||||||
|
r = -1 * collator.compare(aProp, bProp);
|
||||||
|
} else {
|
||||||
if (aProp < bProp) r = +1;
|
if (aProp < bProp) r = +1;
|
||||||
if (aProp > bProp) r = -1;
|
if (aProp > bProp) r = -1;
|
||||||
|
}
|
||||||
if (order.dir == 'ASC') r = -r;
|
if (order.dir == 'ASC') r = -r;
|
||||||
if (r !== 0) return r;
|
if (r !== 0) return r;
|
||||||
}
|
}
|
||||||
@@ -377,6 +384,7 @@ class Note extends BaseItem {
|
|||||||
tempOptions.conditions = cond;
|
tempOptions.conditions = cond;
|
||||||
|
|
||||||
const uncompletedTodos = await this.search(tempOptions);
|
const uncompletedTodos = await this.search(tempOptions);
|
||||||
|
this.handleTitleNaturalSorting(uncompletedTodos, tempOptions);
|
||||||
|
|
||||||
cond = options.conditions.slice();
|
cond = options.conditions.slice();
|
||||||
if (hasNotes && hasTodos) {
|
if (hasNotes && hasTodos) {
|
||||||
@@ -389,6 +397,7 @@ class Note extends BaseItem {
|
|||||||
tempOptions.conditions = cond;
|
tempOptions.conditions = cond;
|
||||||
if ('limit' in tempOptions) tempOptions.limit -= uncompletedTodos.length;
|
if ('limit' in tempOptions) tempOptions.limit -= uncompletedTodos.length;
|
||||||
const theRest = await this.search(tempOptions);
|
const theRest = await this.search(tempOptions);
|
||||||
|
this.handleTitleNaturalSorting(theRest, tempOptions);
|
||||||
|
|
||||||
return uncompletedTodos.concat(theRest);
|
return uncompletedTodos.concat(theRest);
|
||||||
}
|
}
|
||||||
@@ -401,7 +410,10 @@ class Note extends BaseItem {
|
|||||||
options.conditions.push('is_todo = 1');
|
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) {
|
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;
|
Note.updateGeolocationEnabled_ = true;
|
||||||
|
Reference in New Issue
Block a user