mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-03-17 21:13:44 +00:00
Sort spouses by marriage date (#10)
This commit is contained in:
70
src/gedcom_util.spec.ts
Normal file
70
src/gedcom_util.spec.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import {normalizeGedcom} from './gedcom_util';
|
||||||
|
|
||||||
|
describe('normalizeGedcom()', () => {
|
||||||
|
it('sorts children', () => {
|
||||||
|
const data = {
|
||||||
|
indis: [
|
||||||
|
{
|
||||||
|
id: 'I3',
|
||||||
|
birth: {date: {year: 1901}},
|
||||||
|
famc: 'F1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'I2',
|
||||||
|
birth: {date: {year: 1902, month: 7}},
|
||||||
|
famc: 'F1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'I1',
|
||||||
|
birth: {date: {year: 1902, month: 8}},
|
||||||
|
famc: 'F1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
fams: [
|
||||||
|
{
|
||||||
|
id: 'F1',
|
||||||
|
children: ['I1', 'I2', 'I3'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const normalized = normalizeGedcom(data);
|
||||||
|
expect(normalized.fams[0].children).toEqual(['I3', 'I2', 'I1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sorts spouses', () => {
|
||||||
|
const data = {
|
||||||
|
indis: [
|
||||||
|
{id: 'I1', fams: ['F1']},
|
||||||
|
{id: 'I2', fams: ['F2']},
|
||||||
|
{id: 'I3', fams: ['F3']},
|
||||||
|
{id: 'I4', fams: ['F1', 'F2', 'F3']},
|
||||||
|
],
|
||||||
|
fams: [
|
||||||
|
{
|
||||||
|
id: 'F3',
|
||||||
|
marriage: {date: {year: 1901}},
|
||||||
|
husband: 'I4',
|
||||||
|
wife: 'I3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'F2',
|
||||||
|
marriage: {date: {year: 1902, month: 7}},
|
||||||
|
husband: 'I4',
|
||||||
|
wife: 'I2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'F1',
|
||||||
|
marriage: {date: {year: 1902, month: 8}},
|
||||||
|
husband: 'I4',
|
||||||
|
wife: 'I1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const normalized = normalizeGedcom(data);
|
||||||
|
expect(normalized.indis.find((i) => i.id === 'I4')!.fams).toEqual([
|
||||||
|
'F3',
|
||||||
|
'F2',
|
||||||
|
'F1',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
JsonIndi,
|
JsonIndi,
|
||||||
gedcomEntriesToJson,
|
gedcomEntriesToJson,
|
||||||
JsonImage,
|
JsonImage,
|
||||||
|
JsonEvent,
|
||||||
} from 'topola';
|
} from 'topola';
|
||||||
import {GedcomEntry, parse as parseGedcom} from 'parse-gedcom';
|
import {GedcomEntry, parse as parseGedcom} from 'parse-gedcom';
|
||||||
|
|
||||||
@@ -58,6 +59,33 @@ function strcmp(a: string, b: string) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compares dates of the given events. */
|
||||||
|
function compareDates(
|
||||||
|
event1: JsonEvent | undefined,
|
||||||
|
event2: JsonEvent | undefined,
|
||||||
|
): number {
|
||||||
|
const date1 =
|
||||||
|
event1 && (event1.date || (event1.dateRange && event1.dateRange.from));
|
||||||
|
const date2 =
|
||||||
|
event2 && (event2.date || (event2.dateRange && event2.dateRange.from));
|
||||||
|
if (!date1 || !date1.year || !date2 || !date2.year) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (date1.year !== date2.year) {
|
||||||
|
return date1.year - date2.year;
|
||||||
|
}
|
||||||
|
if (!date1.month || !date2.month) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (date1.month !== date2.month) {
|
||||||
|
return date1.month - date2.month;
|
||||||
|
}
|
||||||
|
if (date1.day && date2.day && date1.day !== date2.day) {
|
||||||
|
return date1.month - date2.month;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Birth date comparator for individuals. */
|
/** Birth date comparator for individuals. */
|
||||||
function birthDatesComparator(gedcom: JsonGedcomData) {
|
function birthDatesComparator(gedcom: JsonGedcomData) {
|
||||||
const idToIndiMap = new Map<string, JsonIndi>();
|
const idToIndiMap = new Map<string, JsonIndi>();
|
||||||
@@ -66,31 +94,29 @@ function birthDatesComparator(gedcom: JsonGedcomData) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (indiId1: string, indiId2: string) => {
|
return (indiId1: string, indiId2: string) => {
|
||||||
const idComparison = strcmp(indiId1, indiId2);
|
|
||||||
const indi1: JsonIndi = idToIndiMap[indiId1];
|
const indi1: JsonIndi = idToIndiMap[indiId1];
|
||||||
const indi2: JsonIndi = idToIndiMap[indiId2];
|
const indi2: JsonIndi = idToIndiMap[indiId2];
|
||||||
const birth1 = indi1 && indi1.birth;
|
return (
|
||||||
const birth2 = indi2 && indi2.birth;
|
compareDates(indi1 && indi1.birth, indi2 && indi2.birth) ||
|
||||||
const date1 =
|
strcmp(indiId1, indiId2)
|
||||||
birth1 && (birth1.date || (birth1.dateRange && birth1.dateRange.from));
|
);
|
||||||
const date2 =
|
};
|
||||||
birth2 && (birth2.date || (birth2.dateRange && birth2.dateRange.from));
|
}
|
||||||
if (!date1 || !date1.year || !date2 || !date2.year) {
|
|
||||||
return idComparison;
|
/** Marriage date comparator for families. */
|
||||||
}
|
function marriageDatesComparator(gedcom: JsonGedcomData) {
|
||||||
if (date1.year !== date2.year) {
|
const idToFamMap = new Map<string, JsonFam>();
|
||||||
return date1.year - date2.year;
|
gedcom.fams.forEach((fam) => {
|
||||||
}
|
idToFamMap[fam.id] = fam;
|
||||||
if (!date1.month || !date2.month) {
|
});
|
||||||
return idComparison;
|
|
||||||
}
|
return (famId1: string, famId2: string) => {
|
||||||
if (date1.month !== date2.month) {
|
const fam1: JsonFam = idToFamMap[famId1];
|
||||||
return date1.month - date2.month;
|
const fam2: JsonFam = idToFamMap[famId2];
|
||||||
}
|
return (
|
||||||
if (date1.day && date2.day && date1.day !== date2.day) {
|
compareDates(fam1 && fam1.marriage, fam2 && fam2.marriage) ||
|
||||||
return date1.month - date2.month;
|
strcmp(famId1, famId2)
|
||||||
}
|
);
|
||||||
return idComparison;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +145,34 @@ function sortChildren(gedcom: JsonGedcomData): JsonGedcomData {
|
|||||||
return Object.assign({}, gedcom, {fams: newFams});
|
return Object.assign({}, gedcom, {fams: newFams});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts spouses by marriage date.
|
||||||
|
* Does not modify the input objects.
|
||||||
|
*/
|
||||||
|
function sortIndiSpouses(
|
||||||
|
indi: JsonIndi,
|
||||||
|
comparator: (id1: string, id2: string) => number,
|
||||||
|
): JsonFam {
|
||||||
|
if (!indi.fams) {
|
||||||
|
return indi;
|
||||||
|
}
|
||||||
|
const newFams = indi.fams.sort(comparator);
|
||||||
|
return Object.assign({}, indi, {fams: newFams});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortSpouses(gedcom: JsonGedcomData): JsonGedcomData {
|
||||||
|
const comparator = marriageDatesComparator(gedcom);
|
||||||
|
const newIndis = gedcom.indis.map((indi) =>
|
||||||
|
sortIndiSpouses(indi, comparator),
|
||||||
|
);
|
||||||
|
return Object.assign({}, gedcom, {indis: newIndis});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sorts children and spouses. */
|
||||||
|
export function normalizeGedcom(gedcom: JsonGedcomData): JsonGedcomData {
|
||||||
|
return sortSpouses(sortChildren(gedcom));
|
||||||
|
}
|
||||||
|
|
||||||
const IMAGE_EXTENSIONS = ['.jpg', '.png', '.gif'];
|
const IMAGE_EXTENSIONS = ['.jpg', '.png', '.gif'];
|
||||||
|
|
||||||
/** Returns true if the given file name has a known image extension. */
|
/** Returns true if the given file name has a known image extension. */
|
||||||
@@ -185,7 +239,7 @@ export function convertGedcom(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chartData: filterImages(sortChildren(json), images),
|
chartData: filterImages(normalizeGedcom(json), images),
|
||||||
gedcom: prepareGedcom(entries),
|
gedcom: prepareGedcom(entries),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import {Date, JsonFam, JsonIndi} from 'topola';
|
import {Date, JsonFam, JsonIndi} from 'topola';
|
||||||
import {GedcomData, TopolaData} from './gedcom_util';
|
import {GedcomData, TopolaData, normalizeGedcom} from './gedcom_util';
|
||||||
import {GedcomEntry} from 'parse-gedcom';
|
import {GedcomEntry} from 'parse-gedcom';
|
||||||
|
|
||||||
/** WikiTree API getAncestors request. */
|
/** WikiTree API getAncestors request. */
|
||||||
@@ -286,8 +286,9 @@ export async function loadWikiTree(
|
|||||||
return fam;
|
return fam;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const chartData = normalizeGedcom({indis, fams});
|
||||||
const gedcom = buildGedcom(indis);
|
const gedcom = buildGedcom(indis);
|
||||||
return {chartData: {indis, fams}, gedcom};
|
return {chartData, gedcom};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a family identifier given 2 spouse identifiers. */
|
/** Creates a family identifier given 2 spouse identifiers. */
|
||||||
|
|||||||
Reference in New Issue
Block a user