mirror of
https://github.com/PeWu/topola-viewer.git
synced 2025-12-23 18:50:04 +00:00
Added "Select WikiTree ID" to the menu
This commit is contained in:
parent
b1d2ac5734
commit
c3b988e4b7
16
src/app.tsx
16
src/app.tsx
@ -133,8 +133,18 @@ class GedcomUrlDataSource implements DataSource {
|
||||
/** Loading data from the WikiTree API. */
|
||||
class WikiTreeDataSource implements DataSource {
|
||||
isNewData(args: Arguments, state: State): boolean {
|
||||
// WikiTree is always a single data source.
|
||||
return false;
|
||||
if (state.selection && state.selection.id === args.indi) {
|
||||
// Selection unchanged -> don't reload.
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
state.data &&
|
||||
state.data.chartData.indis.some((indi) => indi.id === args.indi)
|
||||
) {
|
||||
// New selection exists in current view -> animate instead of reloading.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async loadData(args: Arguments): Promise<TopolaData> {
|
||||
@ -379,7 +389,7 @@ export class App extends React.Component<RouteComponentProps, {}> {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
data: undefined,
|
||||
selection: undefined,
|
||||
selection: {id: args.indi},
|
||||
hash: args.hash,
|
||||
error: undefined,
|
||||
loading: true,
|
||||
|
||||
@ -126,3 +126,8 @@ div.ui.card.intro {
|
||||
.content .ui.image.blockImage {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.link-span {
|
||||
color: #4183c4;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
192
src/top_bar.tsx
192
src/top_bar.tsx
@ -25,6 +25,9 @@ import {
|
||||
Responsive,
|
||||
} from 'semantic-ui-react';
|
||||
|
||||
const WIKITREE_LOGO_URL =
|
||||
'https://www.wikitree.com/photo.php/a/a5/WikiTree_Images.png';
|
||||
|
||||
enum WikiTreeLoginState {
|
||||
UNKNOWN,
|
||||
NOT_LOGGED_IN,
|
||||
@ -39,7 +42,9 @@ enum ScreenSize {
|
||||
/** Menus and dialogs state. */
|
||||
interface State {
|
||||
loadUrlDialogOpen: boolean;
|
||||
wikiTreeIdDialogOpen: boolean;
|
||||
url?: string;
|
||||
wikiTreeId?: string;
|
||||
wikiTreeLoginState: WikiTreeLoginState;
|
||||
wikiTreeLoginUsername?: string;
|
||||
searchResults: SearchResultProps[];
|
||||
@ -87,6 +92,7 @@ export class TopBar extends React.Component<
|
||||
> {
|
||||
state: State = {
|
||||
loadUrlDialogOpen: false,
|
||||
wikiTreeIdDialogOpen: false,
|
||||
searchResults: [],
|
||||
wikiTreeLoginState: WikiTreeLoginState.UNKNOWN,
|
||||
};
|
||||
@ -96,6 +102,7 @@ export class TopBar extends React.Component<
|
||||
};
|
||||
|
||||
urlInputRef: React.RefObject<Input> = React.createRef();
|
||||
wikiTreeIdInputRef: React.RefObject<Input> = React.createRef();
|
||||
wikiTreeLoginFormRef: React.RefObject<HTMLFormElement> = React.createRef();
|
||||
wikiTreeReturnUrlRef: React.RefObject<HTMLInputElement> = React.createRef();
|
||||
searchRef?: {setValue(value: string): void};
|
||||
@ -163,12 +170,24 @@ export class TopBar extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
/** Cancels the "Load from URL" dialog. */
|
||||
private handleClose() {
|
||||
this.setState(Object.assign({}, this.state, {loadUrlDialogOpen: false}));
|
||||
private openWikiTreeIdDialog() {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {wikiTreeIdDialogOpen: true}),
|
||||
() => this.wikiTreeIdInputRef.current!.focus(),
|
||||
);
|
||||
}
|
||||
|
||||
/** Upload button clicked in the "Load from URL" dialog. */
|
||||
/** Cancels any of the open dialogs. */
|
||||
private handleClose() {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
loadUrlDialogOpen: false,
|
||||
wikiTreeIdDialogOpen: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** Load button clicked in the "Load from URL" dialog. */
|
||||
private handleLoad() {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
@ -184,11 +203,43 @@ export class TopBar extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the URL input is typed into. */
|
||||
private handleUrlChange(event: React.SyntheticEvent) {
|
||||
/** Select button clicked in the "Select WikiTree ID" dialog. */
|
||||
private handleSelectWikiTreeId() {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
url: (event.target as HTMLInputElement).value,
|
||||
wikiTreeIdDialogOpen: false,
|
||||
}),
|
||||
);
|
||||
if (this.state.wikiTreeId) {
|
||||
analyticsEvent('wikitree_id_selected');
|
||||
const search = queryString.parse(this.props.location.search);
|
||||
const standalone =
|
||||
search.standalone !== undefined ? search.standalone : true;
|
||||
this.props.history.push({
|
||||
pathname: '/view',
|
||||
search: queryString.stringify({
|
||||
indi: this.state.wikiTreeId,
|
||||
source: 'wikitree',
|
||||
standalone,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the URL input is typed into. */
|
||||
private handleUrlChange(value: string) {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
url: value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** Called when the URL input is typed into. */
|
||||
private handleWikiTreeIdChange(value: string) {
|
||||
this.setState(
|
||||
Object.assign({}, this.state, {
|
||||
wikiTreeId: value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -289,7 +340,7 @@ export class TopBar extends React.Component<
|
||||
<Input
|
||||
placeholder="https://"
|
||||
fluid
|
||||
onChange={(e) => this.handleUrlChange(e)}
|
||||
onChange={(e, data) => this.handleUrlChange(data.value)}
|
||||
ref={this.urlInputRef}
|
||||
/>
|
||||
<p>
|
||||
@ -324,6 +375,95 @@ export class TopBar extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
private enterWikiTreeId(event: React.MouseEvent, id: string) {
|
||||
event.preventDefault(); // Do not follow link in href.
|
||||
((this.wikiTreeIdInputRef.current as unknown) as {
|
||||
inputRef: HTMLInputElement;
|
||||
}).inputRef.value = id;
|
||||
this.handleWikiTreeIdChange(id);
|
||||
}
|
||||
|
||||
private wikiTreeIdModal() {
|
||||
return (
|
||||
<Modal
|
||||
open={this.state.wikiTreeIdDialogOpen}
|
||||
onClose={() => this.handleClose()}
|
||||
centered={false}
|
||||
>
|
||||
<Header>
|
||||
<img
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '32px', height: '32px'}}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id="select_wikitree_id.title"
|
||||
defaultMessage="Select WikiTree ID"
|
||||
children={(txt) => txt}
|
||||
/>
|
||||
</Header>
|
||||
<Modal.Content>
|
||||
<Form onSubmit={() => this.handleLoad()}>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="select_wikitree_id.comment"
|
||||
defaultMessage={
|
||||
'Enter a {wikiTreeLink} profile ID. Examples: {example1}, {example2}.'
|
||||
}
|
||||
values={{
|
||||
wikiTreeLink: (
|
||||
<a
|
||||
href="https://wikitree.com/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
WikiTree
|
||||
</a>
|
||||
),
|
||||
example1: (
|
||||
<span
|
||||
onClick={(e) => this.enterWikiTreeId(e, 'Wojtyla-13')}
|
||||
className="link-span"
|
||||
>
|
||||
Wojtyla-13
|
||||
</span>
|
||||
),
|
||||
example2: (
|
||||
<span
|
||||
onClick={(e) => this.enterWikiTreeId(e, 'Skłodowska-2')}
|
||||
className="link-span"
|
||||
>
|
||||
Skłodowska-2
|
||||
</span>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<Input
|
||||
fluid
|
||||
onChange={(e, data) => this.handleWikiTreeIdChange(data.value)}
|
||||
ref={this.wikiTreeIdInputRef}
|
||||
/>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button secondary onClick={() => this.handleClose()}>
|
||||
<FormattedMessage
|
||||
id="select_wikitree_id.cancel"
|
||||
defaultMessage="Cancel"
|
||||
/>
|
||||
</Button>
|
||||
<Button primary onClick={() => this.handleSelectWikiTreeId()}>
|
||||
<FormattedMessage
|
||||
id="select_wikitree_id.load"
|
||||
defaultMessage="Load"
|
||||
/>
|
||||
</Button>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
private search() {
|
||||
return (
|
||||
<Search
|
||||
@ -521,9 +661,23 @@ export class TopBar extends React.Component<
|
||||
/>
|
||||
</>
|
||||
);
|
||||
const loadWikiTreeItem = (
|
||||
<>
|
||||
<img
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '24px', height: '24px'}}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id="menu.select_wikitree_id"
|
||||
defaultMessage="Select WikiTree ID"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
const commonElements = (
|
||||
<>
|
||||
{this.loadFromUrlModal()}
|
||||
{this.wikiTreeIdModal()}
|
||||
<input
|
||||
className="hidden"
|
||||
type="file"
|
||||
@ -555,6 +709,9 @@ export class TopBar extends React.Component<
|
||||
<Dropdown.Item onClick={() => this.openLoadUrlDialog()}>
|
||||
{loadUrlItem}
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item onClick={() => this.openWikiTreeIdDialog()}>
|
||||
{loadWikiTreeItem}
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
) : (
|
||||
@ -565,6 +722,9 @@ export class TopBar extends React.Component<
|
||||
<Menu.Item onClick={() => this.openLoadUrlDialog()}>
|
||||
{loadUrlItem}
|
||||
</Menu.Item>
|
||||
<Menu.Item onClick={() => this.openWikiTreeIdDialog()}>
|
||||
{loadWikiTreeItem}
|
||||
</Menu.Item>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
@ -583,6 +743,9 @@ export class TopBar extends React.Component<
|
||||
<Dropdown.Item onClick={() => this.openLoadUrlDialog()}>
|
||||
{loadUrlItem}
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item onClick={() => this.openWikiTreeIdDialog()}>
|
||||
{loadWikiTreeItem}
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
{commonElements}
|
||||
</>
|
||||
@ -594,9 +757,6 @@ export class TopBar extends React.Component<
|
||||
if (!this.props.showWikiTreeLogin) {
|
||||
return null;
|
||||
}
|
||||
const wikiTreeLogoUrl =
|
||||
'https://www.wikitree.com/photo.php/a/a5/WikiTree_Images.png';
|
||||
|
||||
switch (this.state.wikiTreeLoginState) {
|
||||
case WikiTreeLoginState.NOT_LOGGED_IN:
|
||||
const loginForm = (
|
||||
@ -619,7 +779,7 @@ export class TopBar extends React.Component<
|
||||
return (
|
||||
<Menu.Item onClick={() => this.wikiTreeLogin()}>
|
||||
<img
|
||||
src={wikiTreeLogoUrl}
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '24px', height: '24px'}}
|
||||
/>
|
||||
@ -636,7 +796,7 @@ export class TopBar extends React.Component<
|
||||
<>
|
||||
<Dropdown.Item onClick={() => this.wikiTreeLogin()}>
|
||||
<img
|
||||
src={wikiTreeLogoUrl}
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '24px', height: '24px'}}
|
||||
/>
|
||||
@ -670,7 +830,7 @@ export class TopBar extends React.Component<
|
||||
return (
|
||||
<Menu.Item title={tooltip}>
|
||||
<img
|
||||
src={wikiTreeLogoUrl}
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '24px', height: '24px'}}
|
||||
/>
|
||||
@ -686,7 +846,7 @@ export class TopBar extends React.Component<
|
||||
<>
|
||||
<Menu.Item title={tooltip}>
|
||||
<img
|
||||
src={wikiTreeLogoUrl}
|
||||
src={WIKITREE_LOGO_URL}
|
||||
alt="WikiTree logo"
|
||||
style={{width: '24px', height: '24px'}}
|
||||
/>
|
||||
@ -725,6 +885,7 @@ export class TopBar extends React.Component<
|
||||
<Dropdown.Item
|
||||
href="https://github.com/PeWu/topola-viewer"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="menu.github"
|
||||
@ -753,6 +914,7 @@ export class TopBar extends React.Component<
|
||||
<Menu.Item
|
||||
href="https://github.com/PeWu/topola-viewer"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="menu.github"
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"menu.open": "Otwórz",
|
||||
"menu.open_file": "Otwórz plik",
|
||||
"menu.load_from_url": "Otwórz URL",
|
||||
"menu.select_wikitree_id": "WikiTree ID",
|
||||
"menu.print": "Drukuj",
|
||||
"menu.download": "Pobierz",
|
||||
"menu.pdf_file": "Plik PDF",
|
||||
@ -32,6 +33,10 @@
|
||||
"load_from_url.comment": "Dane z podanego adresu URL zostaną załadowane poprzez usługę {link} w celu uniknięcia problemów z CORS.",
|
||||
"load_from_url.cancel": "Anuluj",
|
||||
"load_from_url.load": "Otwórz",
|
||||
"select_wikitree_id.title": "Podaj WikiTree ID",
|
||||
"select_wikitree_id.comment": "Wpisz identyfikator profilu {wikiTreeLink}. Przykłady: {example1}, {example2}",
|
||||
"select_wikitree_id.cancel": "Anuluj",
|
||||
"select_wikitree_id.load": "Otwórz",
|
||||
"gedcom.BAPM": "Chrzest",
|
||||
"gedcom.BIRT": "Narodziny",
|
||||
"gedcom.BURI": "Pogrzeb",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user