mirror of
https://github.com/PeWu/topola-viewer.git
synced 2025-12-23 18:50:04 +00:00
Initialize search from JsonGedcomData instead of raw gedcom
This commit is contained in:
parent
36dabfc4a1
commit
c9d5dac0f2
@ -566,7 +566,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
||||
render={(props: RouteComponentProps) => (
|
||||
<TopBar
|
||||
{...props}
|
||||
gedcom={this.state.data && this.state.data.gedcom}
|
||||
data={this.state.data && this.state.data.chartData}
|
||||
allowAllRelativesChart={
|
||||
this.state.source !== DataSourceEnum.WIKITREE
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {Date as TopolaDate, DateRange, getDate} from 'topola';
|
||||
import {Date as TopolaDate, DateRange, getDate, DateOrRange} from 'topola';
|
||||
import {InjectedIntl} from 'react-intl';
|
||||
|
||||
const DATE_QUALIFIERS = new Map([
|
||||
@ -76,9 +76,11 @@ function formatDateRage(dateRange: DateRange, intl: InjectedIntl) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** Formats a date given in GEDCOM format. */
|
||||
export function translateDate(gedcomDate: string, intl: InjectedIntl) {
|
||||
const dateOrRange = getDate(gedcomDate);
|
||||
/** Formats a DateOrRange object. */
|
||||
export function formatDateOrRange(
|
||||
dateOrRange: DateOrRange | undefined,
|
||||
intl: InjectedIntl,
|
||||
): string {
|
||||
if (!dateOrRange) {
|
||||
return '';
|
||||
}
|
||||
@ -90,3 +92,8 @@ export function translateDate(gedcomDate: string, intl: InjectedIntl) {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/** Formats a date given in GEDCOM format. */
|
||||
export function translateDate(gedcomDate: string, intl: InjectedIntl): string {
|
||||
return formatDateOrRange(getDate(gedcomDate), intl);
|
||||
}
|
||||
|
||||
@ -32,6 +32,22 @@ export function pointerToId(pointer: string): string {
|
||||
return pointer.substring(1, pointer.length - 1);
|
||||
}
|
||||
|
||||
export function idToIndiMap(data: JsonGedcomData): Map<string, JsonIndi> {
|
||||
const map = new Map<string, JsonIndi>();
|
||||
data.indis.forEach((indi) => {
|
||||
map.set(indi.id, indi);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
export function idToFamMap(data: JsonGedcomData): Map<string, JsonFam> {
|
||||
const map = new Map<string, JsonFam>();
|
||||
data.fams.forEach((fam) => {
|
||||
map.set(fam.id, fam);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function prepareGedcom(entries: GedcomEntry[]): GedcomData {
|
||||
const head = entries.find((entry) => entry.tag === 'HEAD')!;
|
||||
const indis: {[key: string]: GedcomEntry} = {};
|
||||
@ -88,14 +104,11 @@ function compareDates(
|
||||
|
||||
/** Birth date comparator for individuals. */
|
||||
function birthDatesComparator(gedcom: JsonGedcomData) {
|
||||
const idToIndiMap = new Map<string, JsonIndi>();
|
||||
gedcom.indis.forEach((indi) => {
|
||||
idToIndiMap[indi.id] = indi;
|
||||
});
|
||||
const indiMap = idToIndiMap(gedcom);
|
||||
|
||||
return (indiId1: string, indiId2: string) => {
|
||||
const indi1: JsonIndi = idToIndiMap[indiId1];
|
||||
const indi2: JsonIndi = idToIndiMap[indiId2];
|
||||
const indi1: JsonIndi | undefined = indiMap.get(indiId1);
|
||||
const indi2: JsonIndi | undefined = indiMap.get(indiId2);
|
||||
return (
|
||||
compareDates(indi1 && indi1.birth, indi2 && indi2.birth) ||
|
||||
strcmp(indiId1, indiId2)
|
||||
@ -105,14 +118,11 @@ function birthDatesComparator(gedcom: JsonGedcomData) {
|
||||
|
||||
/** Marriage date comparator for families. */
|
||||
function marriageDatesComparator(gedcom: JsonGedcomData) {
|
||||
const idToFamMap = new Map<string, JsonFam>();
|
||||
gedcom.fams.forEach((fam) => {
|
||||
idToFamMap[fam.id] = fam;
|
||||
});
|
||||
const famMap = idToFamMap(gedcom);
|
||||
|
||||
return (famId1: string, famId2: string) => {
|
||||
const fam1: JsonFam = idToFamMap[famId1];
|
||||
const fam2: JsonFam = idToFamMap[famId2];
|
||||
const fam1: JsonFam | undefined = famMap.get(famId1);
|
||||
const fam2: JsonFam | undefined = famMap.get(famId2);
|
||||
return (
|
||||
compareDates(fam1 && fam1.marriage, fam2 && fam2.marriage) ||
|
||||
strcmp(famId1, famId2)
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import naturalSort from 'javascript-natural-sort';
|
||||
import lunr from 'lunr';
|
||||
import {GedcomData, pointerToId} from './gedcom_util';
|
||||
import {GedcomEntry} from 'parse-gedcom';
|
||||
import {idToIndiMap, idToFamMap} from './gedcom_util';
|
||||
import {JsonIndi, JsonFam, JsonGedcomData} from 'topola';
|
||||
|
||||
const MAX_RESULTS = 8;
|
||||
|
||||
export interface SearchResult {
|
||||
id: string;
|
||||
indi: GedcomEntry;
|
||||
indi: JsonIndi;
|
||||
}
|
||||
|
||||
export interface SearchIndex {
|
||||
@ -32,36 +32,28 @@ function compare(a: lunr.Index.Result, b: lunr.Index.Result) {
|
||||
}
|
||||
|
||||
/** Returns all last names of all husbands as a space-separated string. */
|
||||
function getHusbandLastName(indi: GedcomEntry, gedcom: GedcomData): string {
|
||||
return indi.tree
|
||||
.filter((entry) => entry.tag === 'FAMS')
|
||||
.map((entry) => gedcom.fams[pointerToId(entry.data)])
|
||||
.filter((entry) => !!entry)
|
||||
.map((entry) => {
|
||||
const husband = entry.tree.find((entry) => entry.tag === 'HUSB');
|
||||
const husbandId = husband && pointerToId(husband.data);
|
||||
return (
|
||||
husbandId &&
|
||||
husbandId !== pointerToId(indi.pointer) &&
|
||||
gedcom.indis[husbandId]
|
||||
);
|
||||
})
|
||||
.filter((entry) => !!entry)
|
||||
.flatMap((husband) =>
|
||||
(husband as GedcomEntry).tree
|
||||
.filter((entry) => entry.tag === 'NAME')
|
||||
.map((entry) => {
|
||||
const names = entry.data.split('/');
|
||||
return names.length >= 2 ? names[1] : '';
|
||||
}),
|
||||
)
|
||||
function getHusbandLastName(
|
||||
indi: JsonIndi,
|
||||
indiMap: Map<String, JsonIndi>,
|
||||
famMap: Map<string, JsonFam>,
|
||||
): string {
|
||||
return (indi.fams || [])
|
||||
.map((famId) => famMap.get(famId))
|
||||
.map((fam) => fam && fam.husb)
|
||||
.map((husbId) => husbId && indiMap.get(husbId))
|
||||
.map((husband) => husband && husband.lastName)
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
class LunrSearchIndex implements SearchIndex {
|
||||
private index: lunr.Index | undefined;
|
||||
private indiMap: Map<string, JsonIndi>;
|
||||
private famMap: Map<string, JsonFam>;
|
||||
|
||||
constructor(private gedcom: GedcomData) {}
|
||||
constructor(data: JsonGedcomData) {
|
||||
this.indiMap = idToIndiMap(data);
|
||||
this.famMap = idToFamMap(data);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
const self = this;
|
||||
@ -73,25 +65,25 @@ class LunrSearchIndex implements SearchIndex {
|
||||
this.field('spouseLastName', {boost: 2});
|
||||
this.field('normalizedSpouseLastName', {boost: 2});
|
||||
|
||||
for (let id in self.gedcom.indis) {
|
||||
const indi = self.gedcom.indis[id];
|
||||
const name = indi.tree
|
||||
.filter((entry) => entry.tag === 'NAME')
|
||||
.map((entry) => entry.data)
|
||||
.join(' ');
|
||||
const spouseLastName = getHusbandLastName(indi, self.gedcom);
|
||||
self.indiMap.forEach((indi) => {
|
||||
const name = [indi.firstName, indi.lastName].join(' ');
|
||||
const spouseLastName = getHusbandLastName(
|
||||
indi,
|
||||
self.indiMap,
|
||||
self.famMap,
|
||||
);
|
||||
this.add({
|
||||
id,
|
||||
id: indi.id,
|
||||
name,
|
||||
normalizedName: normalize(name),
|
||||
spouseLastName,
|
||||
normalizedSpouseLastName: normalize(spouseLastName),
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public search(input: string) {
|
||||
public search(input: string): SearchResult[] {
|
||||
const query = input
|
||||
.split(' ')
|
||||
.filter((s) => !!s)
|
||||
@ -101,13 +93,13 @@ class LunrSearchIndex implements SearchIndex {
|
||||
return results
|
||||
.sort(compare)
|
||||
.slice(0, MAX_RESULTS)
|
||||
.map((result) => ({id: result.ref, indi: this.gedcom.indis[result.ref]}));
|
||||
.map((result) => ({id: result.ref, indi: this.indiMap.get(result.ref)!}));
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds a search index from data. */
|
||||
export function buildSearchIndex(gedcom: GedcomData): SearchIndex {
|
||||
const index = new LunrSearchIndex(gedcom);
|
||||
export function buildSearchIndex(data: JsonGedcomData): SearchIndex {
|
||||
const index = new LunrSearchIndex(data);
|
||||
index.initialize();
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -1,17 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import {GedcomEntry} from 'parse-gedcom';
|
||||
import {InjectedIntl} from 'react-intl';
|
||||
import {SearchResult} from './search_index';
|
||||
import {translateDate} from './date_util';
|
||||
import {formatDateOrRange} from './date_util';
|
||||
import {JsonIndi} from 'topola';
|
||||
|
||||
function getNameLine(result: SearchResult) {
|
||||
const nameTag = result.indi.tree.find((entry) => entry.tag === 'NAME');
|
||||
const name =
|
||||
nameTag &&
|
||||
nameTag.data
|
||||
.split('/')
|
||||
.filter((s) => !!s)
|
||||
.join(' ');
|
||||
const name = [result.indi.firstName, result.indi.lastName].join(' ').trim();
|
||||
if (result.id.length > 8) {
|
||||
return name;
|
||||
}
|
||||
@ -22,16 +16,9 @@ function getNameLine(result: SearchResult) {
|
||||
);
|
||||
}
|
||||
|
||||
function getDate(indi: GedcomEntry, tag: string, intl: InjectedIntl) {
|
||||
const eventEntry = indi.tree.find((entry) => entry.tag === tag);
|
||||
const dateEntry =
|
||||
eventEntry && eventEntry.tree.find((entry) => entry.tag === 'DATE');
|
||||
return (dateEntry && translateDate(dateEntry.data, intl)) || '';
|
||||
}
|
||||
|
||||
function getDescriptionLine(indi: GedcomEntry, intl: InjectedIntl) {
|
||||
const birthDate = getDate(indi, 'BIRT', intl);
|
||||
const deathDate = getDate(indi, 'DEAT', intl);
|
||||
function getDescriptionLine(indi: JsonIndi, intl: InjectedIntl) {
|
||||
const birthDate = formatDateOrRange(indi.birth, intl);
|
||||
const deathDate = formatDateOrRange(indi.death, intl);
|
||||
if (!deathDate) {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
@ -7,8 +7,7 @@ import {analyticsEvent} from './analytics';
|
||||
import {buildSearchIndex, SearchIndex} from './search_index';
|
||||
import {displaySearchResult} from './search_util';
|
||||
import {FormattedMessage, intlShape} from 'react-intl';
|
||||
import {GedcomData} from './gedcom_util';
|
||||
import {IndiInfo} from 'topola';
|
||||
import {IndiInfo, JsonGedcomData} from 'topola';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {RouteComponentProps} from 'react-router-dom';
|
||||
import {
|
||||
@ -58,7 +57,7 @@ interface Props {
|
||||
/** True if the application is currently showing a chart. */
|
||||
showingChart: boolean;
|
||||
/** Data used for the search index. */
|
||||
gedcom?: GedcomData;
|
||||
data?: JsonGedcomData;
|
||||
standalone: boolean;
|
||||
/** Whether to show the "All relatives" chart type in the menu. */
|
||||
allowAllRelativesChart: boolean;
|
||||
@ -213,8 +212,8 @@ export class TopBar extends React.Component<
|
||||
}
|
||||
|
||||
private initializeSearchIndex() {
|
||||
if (this.props.gedcom) {
|
||||
this.searchIndex = buildSearchIndex(this.props.gedcom);
|
||||
if (this.props.data) {
|
||||
this.searchIndex = buildSearchIndex(this.props.data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +264,7 @@ export class TopBar extends React.Component<
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
this.checkWikiTreeLoginState();
|
||||
if (prevProps.gedcom !== this.props.gedcom) {
|
||||
if (prevProps.data !== this.props.data) {
|
||||
this.initializeSearchIndex();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user