@luomus/laji-form 15.1.88 → 15.1.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/laji-form.js +1 -1
- package/dist/styles.css +3 -1
- package/lib/components/LajiForm.js +1 -0
- package/lib/components/fields/EnumRangeArrayField.js +1 -1
- package/lib/components/fields/ImageArrayField.js +1 -1
- package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooser.d.ts +1 -1
- package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooserField.d.ts +1 -1
- package/lib/components/fields/NamedPlaceChooserField/Popup.d.ts +1 -1
- package/lib/components/fields/ScientificNameTaxonAutosuggestField.d.ts +39 -0
- package/lib/components/fields/ScientificNameTaxonAutosuggestField.js +260 -0
- package/lib/components/widgets/AutosuggestWidget.d.ts +4 -1
- package/lib/components/widgets/AutosuggestWidget.js +48 -20
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -2389,8 +2389,10 @@ body .laji-form {
|
|
|
2389
2389
|
margin-bottom: 0px;
|
|
2390
2390
|
}
|
|
2391
2391
|
.laji-form .autosuggest-wrapper .rw-list-option img {
|
|
2392
|
-
border: 1px solid;
|
|
2393
2392
|
float: right;
|
|
2393
|
+
}
|
|
2394
|
+
.laji-form .autosuggest-wrapper .rw-list-option img.flag-img {
|
|
2395
|
+
border: 1px solid;
|
|
2394
2396
|
margin-top: 4px;
|
|
2395
2397
|
}
|
|
2396
2398
|
|
|
@@ -146,6 +146,7 @@ const fields = importLocalComponents("fields", [
|
|
|
146
146
|
"MultiActiveArrayField",
|
|
147
147
|
"PrefixArrayField",
|
|
148
148
|
"FillDateRangeField",
|
|
149
|
+
"ScientificNameTaxonAutosuggestField",
|
|
149
150
|
{ "InputTransformerField": "ConditionalOnChangeField" }, // Alias for backward compatibility.
|
|
150
151
|
{ "ConditionalField": "ConditionalUiSchemaField" }, // Alias for backward compatibility.
|
|
151
152
|
{ "UnitRapidField": "UnitShorthandField" }, // Alias for backward compatibility.
|
|
@@ -60,7 +60,7 @@ function EnumRangeArrayField(props) {
|
|
|
60
60
|
propsOnChange(value);
|
|
61
61
|
}, [propsOnChange]);
|
|
62
62
|
const getEnumOptionsAsync = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () {
|
|
63
|
-
const enums = yield props.formContext.apiClient.get(
|
|
63
|
+
const enums = (yield props.formContext.apiClient.get("/metadata/alts/{alt}", { path: { alt: range } })).results;
|
|
64
64
|
return enums.map(({ value }) => ({ value, label: value }));
|
|
65
65
|
}), [props.formContext.apiClient, range]);
|
|
66
66
|
const { Label } = props.formContext;
|
|
@@ -189,7 +189,7 @@ function MediaArrayField(ComposedComponent) {
|
|
|
189
189
|
const metadataForm = this.state.metadataForm || {};
|
|
190
190
|
if (typeof metadataModalOpen === "number" && !this.state.metadataForm) {
|
|
191
191
|
const { metadataFormId = this.METADATA_FORM_ID } = (0, utils_1.getUiOptions)(this.props.uiSchema);
|
|
192
|
-
this.apiClient.get("/forms/{id}", { path: { id: metadataFormId }, query: {
|
|
192
|
+
this.apiClient.get("/forms/{id}", { path: { id: metadataFormId }, query: { format: "schema" } })
|
|
193
193
|
.then(metadataForm => {
|
|
194
194
|
if (this.mounted) {
|
|
195
195
|
this.setState({ metadataForm });
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { ByLang, FormContext } from "../../LajiForm";
|
|
3
3
|
import memoize from "memoizee";
|
|
4
4
|
import type { components } from "generated/api.d";
|
|
5
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
5
|
+
type NamedPlace = components["schemas"]["store-namedPlace"];
|
|
6
6
|
type Props = {
|
|
7
7
|
places: NamedPlace[];
|
|
8
8
|
failed?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { FieldProps, JSONSchemaArray, JSONSchemaObject } from "../../../types";
|
|
3
3
|
import type { components } from "generated/api.d";
|
|
4
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
4
|
+
type NamedPlace = components["schemas"]["store-namedPlace"];
|
|
5
5
|
type Props = FieldProps<NamedPlace, JSONSchemaObject | JSONSchemaArray<JSONSchemaObject>>;
|
|
6
6
|
type State = {
|
|
7
7
|
show?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { FormContext } from "src/components/LajiForm";
|
|
3
3
|
import type { components } from "generated/api.d";
|
|
4
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
4
|
+
type NamedPlace = components["schemas"]["store-namedPlace"];
|
|
5
5
|
type Props = {
|
|
6
6
|
onPlaceSelected: (place: NamedPlace) => void;
|
|
7
7
|
onPlaceDeleted: (place: NamedPlace) => void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as PropTypes from "prop-types";
|
|
3
|
+
import { FieldProps, JSONSchemaObject, JSONSchemaEnumOneOf } from "../../types";
|
|
4
|
+
interface State extends Pick<FieldProps<JSONSchemaObject>, "schema" | "uiSchema"> {
|
|
5
|
+
suggestion?: any;
|
|
6
|
+
}
|
|
7
|
+
interface ValueContext {
|
|
8
|
+
taxonRank?: string;
|
|
9
|
+
author?: string;
|
|
10
|
+
}
|
|
11
|
+
export default class ScientificNameTaxonAutosuggestField extends React.Component<FieldProps<JSONSchemaObject>, State> {
|
|
12
|
+
static contextType: React.Context<import("../../ReactContext").ContextProps>;
|
|
13
|
+
static propTypes: {
|
|
14
|
+
uiSchema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
|
|
15
|
+
"ui:options": PropTypes.Validator<NonNullable<PropTypes.InferProps<{
|
|
16
|
+
taxonField: PropTypes.Validator<string>;
|
|
17
|
+
taxonRankField: PropTypes.Validator<string>;
|
|
18
|
+
authorField: PropTypes.Validator<string>;
|
|
19
|
+
allowNonsuggestedValue: PropTypes.Requireable<boolean>;
|
|
20
|
+
}>>>;
|
|
21
|
+
uiSchema: PropTypes.Requireable<object>;
|
|
22
|
+
}>>>;
|
|
23
|
+
schema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
|
|
24
|
+
type: PropTypes.Requireable<string>;
|
|
25
|
+
}>>>;
|
|
26
|
+
formData: PropTypes.Validator<object>;
|
|
27
|
+
};
|
|
28
|
+
getStateFromProps: (props: FieldProps<JSONSchemaObject>) => State;
|
|
29
|
+
getSuggestionValue: (suggestion: any) => string;
|
|
30
|
+
onSuggestionSelected: (suggestion: any, mounted: boolean) => void;
|
|
31
|
+
onUnsuggestionSelected: (value: any) => void;
|
|
32
|
+
isValueSuggested: (value?: string, valueContext?: ValueContext) => boolean | undefined;
|
|
33
|
+
getSuggestionFromValue: (value?: string, valueContext?: ValueContext) => Promise<any>;
|
|
34
|
+
suggestionMatchesData: (suggestion: any, value?: string, valueContext?: ValueContext) => boolean;
|
|
35
|
+
getTaxonRankOptions: () => JSONSchemaEnumOneOf[] | undefined;
|
|
36
|
+
renderSuggestion(suggestion: any, inputValue?: string): JSX.Element;
|
|
37
|
+
render(): JSX.Element;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
42
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
43
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
44
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
45
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
46
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
47
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
51
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
52
|
+
};
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
const React = __importStar(require("react"));
|
|
55
|
+
const PropTypes = __importStar(require("prop-types"));
|
|
56
|
+
const utils_1 = require("../../utils");
|
|
57
|
+
const ReactContext_1 = __importDefault(require("../../ReactContext"));
|
|
58
|
+
const AutosuggestWidget_1 = require("../widgets/AutosuggestWidget");
|
|
59
|
+
const BaseComponent_1 = __importDefault(require("../BaseComponent"));
|
|
60
|
+
const components_1 = require("../components");
|
|
61
|
+
function addBold(original, substring) {
|
|
62
|
+
const newOriginal = original.toLowerCase();
|
|
63
|
+
const newString = substring.toLowerCase();
|
|
64
|
+
const index = newOriginal.indexOf(newString);
|
|
65
|
+
return index > -1 ?
|
|
66
|
+
React.createElement(React.Fragment, null,
|
|
67
|
+
original.slice(0, index),
|
|
68
|
+
React.createElement("b", null, original.slice(index, index + substring.length)),
|
|
69
|
+
original.slice(index + substring.length))
|
|
70
|
+
: original;
|
|
71
|
+
}
|
|
72
|
+
let ScientificNameTaxonAutosuggestField = class ScientificNameTaxonAutosuggestField extends React.Component {
|
|
73
|
+
constructor() {
|
|
74
|
+
super(...arguments);
|
|
75
|
+
this.getStateFromProps = (props) => {
|
|
76
|
+
var _a;
|
|
77
|
+
let { schema, uiSchema, formData = {} } = props;
|
|
78
|
+
const uiOptions = (0, utils_1.getUiOptions)(uiSchema);
|
|
79
|
+
const { taxonField, taxonRankField, authorField } = uiOptions;
|
|
80
|
+
const scientificName = (0, utils_1.parseJSONPointer)(formData, taxonField, true);
|
|
81
|
+
const taxonRank = (0, utils_1.parseJSONPointer)(formData, taxonRankField, true);
|
|
82
|
+
const author = (0, utils_1.parseJSONPointer)(formData, authorField, true);
|
|
83
|
+
let taxonRankLabel = undefined;
|
|
84
|
+
if (taxonRank) {
|
|
85
|
+
taxonRankLabel = (_a = (this.getTaxonRankOptions() || []).find(option => option.const === taxonRank)) === null || _a === void 0 ? void 0 : _a.title;
|
|
86
|
+
}
|
|
87
|
+
let options = Object.assign(Object.assign({}, uiOptions), { autosuggestField: "taxon", onSuggestionSelected: this.onSuggestionSelected, onUnsuggestedSelected: this.onUnsuggestionSelected, isValueSuggested: this.isValueSuggested, getSuggestionFromValue: this.getSuggestionFromValue, getSuggestionValue: this.getSuggestionValue, renderSuggestion: this.renderSuggestion, valueContext: { taxonRank, author }, taxonRankLabel, Wrapper: TaxonWrapper });
|
|
88
|
+
if (!(0, utils_1.isEmptyString)(scientificName)) {
|
|
89
|
+
options.value = scientificName;
|
|
90
|
+
}
|
|
91
|
+
const innerUiSchema = (0, utils_1.getInnerUiSchema)(uiSchema);
|
|
92
|
+
const _uiSchemaJSONPointer = (0, utils_1.uiSchemaJSONPointer)(schema, taxonField);
|
|
93
|
+
if (!_uiSchemaJSONPointer) {
|
|
94
|
+
throw new Error("Invalid taxon field");
|
|
95
|
+
}
|
|
96
|
+
const taxonExistingUiSchema = (0, utils_1.parseJSONPointer)(innerUiSchema, _uiSchemaJSONPointer);
|
|
97
|
+
let widgetProps = taxonExistingUiSchema || {};
|
|
98
|
+
let _uiSchema = (0, utils_1.updateSafelyWithJSONPointer)(innerUiSchema, Object.assign(Object.assign({ "ui:widget": "AutosuggestWidget" }, widgetProps), { "ui:options": Object.assign(Object.assign({}, (0, utils_1.getUiOptions)((taxonExistingUiSchema || {})[taxonField])), options) }), _uiSchemaJSONPointer);
|
|
99
|
+
return { schema, uiSchema: _uiSchema };
|
|
100
|
+
};
|
|
101
|
+
this.getSuggestionValue = (suggestion) => {
|
|
102
|
+
return suggestion.scientificName;
|
|
103
|
+
};
|
|
104
|
+
this.onSuggestionSelected = (suggestion, mounted) => {
|
|
105
|
+
if (suggestion === null)
|
|
106
|
+
suggestion = undefined;
|
|
107
|
+
let { formData, uiSchema, formContext, registry, schema } = this.props;
|
|
108
|
+
const { taxonField, taxonRankField, authorField } = (0, utils_1.getUiOptions)(uiSchema);
|
|
109
|
+
if (typeof suggestion === "object") {
|
|
110
|
+
this.setState({ suggestion });
|
|
111
|
+
const scientificName = suggestion.scientificName;
|
|
112
|
+
formData = (0, utils_1.updateFormDataWithJSONPointer)({ formData, registry, schema }, scientificName, taxonField);
|
|
113
|
+
let taxonRank = suggestion.taxonRank;
|
|
114
|
+
const taxonRankOptions = this.getTaxonRankOptions();
|
|
115
|
+
if (taxonRankOptions && !taxonRankOptions.some(option => option.const === taxonRank)) {
|
|
116
|
+
taxonRank = undefined;
|
|
117
|
+
}
|
|
118
|
+
formData = (0, utils_1.updateFormDataWithJSONPointer)({ formData, registry, schema }, taxonRank, taxonRankField);
|
|
119
|
+
const author = suggestion.scientificNameAuthorship;
|
|
120
|
+
formData = (0, utils_1.updateFormDataWithJSONPointer)({ formData, registry, schema }, author, authorField);
|
|
121
|
+
}
|
|
122
|
+
if (mounted) {
|
|
123
|
+
this.props.onChange(formData);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
if (formContext.formDataTransformers) {
|
|
127
|
+
formData = formContext.formDataTransformers.reduce((unit, { "ui:field": uiField, props: fieldProps }) => {
|
|
128
|
+
let changed;
|
|
129
|
+
const getChanged = (_changed) => {
|
|
130
|
+
changed = _changed;
|
|
131
|
+
};
|
|
132
|
+
const field = new fieldProps.registry.fields[uiField](Object.assign(Object.assign({}, fieldProps), { formData: formData, onChange: getChanged }));
|
|
133
|
+
field.onChange(field.state && field.state.formData ? field.state.formData : formData);
|
|
134
|
+
return changed;
|
|
135
|
+
}, formData);
|
|
136
|
+
}
|
|
137
|
+
const lajiFormInstance = formContext.services.rootInstance;
|
|
138
|
+
const pointer = this.props.formContext.services.ids.getJSONPointerFromLajiFormIdAndFormDataAndIdSchemaId(this.props.idSchema.$id, (0, utils_1.getFieldUUID)(this.props));
|
|
139
|
+
const newFormData = Object.assign(Object.assign({}, (0, utils_1.parseJSONPointer)(lajiFormInstance.getFormData(), pointer)), formData);
|
|
140
|
+
lajiFormInstance.onChange((0, utils_1.updateSafelyWithJSONPointer)(lajiFormInstance.getFormData(), newFormData, pointer));
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
this.onUnsuggestionSelected = (value) => {
|
|
144
|
+
this.setState({ suggestion: undefined });
|
|
145
|
+
let { formData, uiSchema, registry, schema } = this.props;
|
|
146
|
+
const { taxonField } = (0, utils_1.getUiOptions)(uiSchema);
|
|
147
|
+
formData = (0, utils_1.updateFormDataWithJSONPointer)({ formData, registry, schema }, value, taxonField);
|
|
148
|
+
this.props.onChange(formData);
|
|
149
|
+
};
|
|
150
|
+
this.isValueSuggested = (value, valueContext) => {
|
|
151
|
+
const { suggestion } = this.state;
|
|
152
|
+
if (!suggestion) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
return this.suggestionMatchesData(suggestion, value, valueContext);
|
|
156
|
+
};
|
|
157
|
+
this.getSuggestionFromValue = (value, valueContext) => __awaiter(this, void 0, void 0, function* () {
|
|
158
|
+
if (this.isValueSuggested(value, valueContext)) {
|
|
159
|
+
return this.state.suggestion;
|
|
160
|
+
}
|
|
161
|
+
if (!value) {
|
|
162
|
+
throw new Error("Missing scientific name");
|
|
163
|
+
}
|
|
164
|
+
if (!(valueContext === null || valueContext === void 0 ? void 0 : valueContext.taxonRank)) {
|
|
165
|
+
throw new Error("Missing taxon rank");
|
|
166
|
+
}
|
|
167
|
+
const query = { query: value, limit: 100, nameTypes: "MX.scientificName", matchType: "exact" };
|
|
168
|
+
const result = yield this.props.formContext.apiClient.get("/autocomplete/taxa", { query });
|
|
169
|
+
for (const suggestion of result.results) {
|
|
170
|
+
if (this.suggestionMatchesData(suggestion, value, valueContext)) {
|
|
171
|
+
this.setState({ suggestion });
|
|
172
|
+
return suggestion;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
throw new Error("Unknown scientific name");
|
|
176
|
+
});
|
|
177
|
+
this.suggestionMatchesData = (suggestion, value, valueContext) => {
|
|
178
|
+
var _a, _b, _c;
|
|
179
|
+
const normalizedValue = value === null || value === void 0 ? void 0 : value.replace(/\s+/g, " ").trim().toLowerCase();
|
|
180
|
+
const normalizedAuthor = (_a = valueContext === null || valueContext === void 0 ? void 0 : valueContext.author) === null || _a === void 0 ? void 0 : _a.replace(/\s/g, "").trim().toLowerCase();
|
|
181
|
+
return normalizedValue === ((_b = suggestion.scientificName) === null || _b === void 0 ? void 0 : _b.toLowerCase()) &&
|
|
182
|
+
(valueContext === null || valueContext === void 0 ? void 0 : valueContext.taxonRank) === suggestion.taxonRank &&
|
|
183
|
+
normalizedAuthor === ((_c = suggestion.scientificNameAuthorship) === null || _c === void 0 ? void 0 : _c.replace(/\s/g, "").toLowerCase());
|
|
184
|
+
};
|
|
185
|
+
this.getTaxonRankOptions = () => {
|
|
186
|
+
let { uiSchema } = this.props;
|
|
187
|
+
const { taxonRankField } = (0, utils_1.getUiOptions)(uiSchema);
|
|
188
|
+
const taxonRankSchemaPointer = (0, utils_1.schemaJSONPointer)(this.props.schema, taxonRankField);
|
|
189
|
+
if (taxonRankSchemaPointer === undefined) {
|
|
190
|
+
throw new Error("Invalid taxon rank field");
|
|
191
|
+
}
|
|
192
|
+
return (0, utils_1.parseJSONPointer)(this.props.schema, taxonRankSchemaPointer).oneOf;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
renderSuggestion(suggestion, inputValue) {
|
|
196
|
+
let value = suggestion.scientificName;
|
|
197
|
+
if (suggestion.nameType === "MX.scientificName" && inputValue) {
|
|
198
|
+
value = addBold(value, inputValue);
|
|
199
|
+
}
|
|
200
|
+
return (React.createElement("span", { className: "simple-option" },
|
|
201
|
+
React.createElement(React.Fragment, null,
|
|
202
|
+
value,
|
|
203
|
+
(0, AutosuggestWidget_1.renderTaxonIcons)(suggestion))));
|
|
204
|
+
}
|
|
205
|
+
render() {
|
|
206
|
+
const { SchemaField } = this.props.registry.fields;
|
|
207
|
+
return React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: this.state.uiSchema }));
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
ScientificNameTaxonAutosuggestField.contextType = ReactContext_1.default;
|
|
211
|
+
ScientificNameTaxonAutosuggestField.propTypes = {
|
|
212
|
+
uiSchema: PropTypes.shape({
|
|
213
|
+
"ui:options": PropTypes.shape({
|
|
214
|
+
taxonField: PropTypes.string.isRequired,
|
|
215
|
+
taxonRankField: PropTypes.string.isRequired,
|
|
216
|
+
authorField: PropTypes.string.isRequired,
|
|
217
|
+
allowNonsuggestedValue: PropTypes.bool
|
|
218
|
+
}).isRequired,
|
|
219
|
+
uiSchema: PropTypes.object
|
|
220
|
+
}).isRequired,
|
|
221
|
+
schema: PropTypes.shape({
|
|
222
|
+
type: PropTypes.oneOf(["object"])
|
|
223
|
+
}).isRequired,
|
|
224
|
+
formData: PropTypes.object.isRequired
|
|
225
|
+
};
|
|
226
|
+
ScientificNameTaxonAutosuggestField = __decorate([
|
|
227
|
+
BaseComponent_1.default
|
|
228
|
+
], ScientificNameTaxonAutosuggestField);
|
|
229
|
+
exports.default = ScientificNameTaxonAutosuggestField;
|
|
230
|
+
class _TaxonWrapper extends React.Component {
|
|
231
|
+
render() {
|
|
232
|
+
const { id, formContext, suggestion, children, placement, inputValue, isSuggested, options } = this.props;
|
|
233
|
+
const { Popover, Tooltip } = this.context.theme;
|
|
234
|
+
const tooltipElem = (React.createElement(Tooltip, { id: `${id}-popover-tooltip` }, formContext.translations.OpenSpeciedCard));
|
|
235
|
+
const taxonLinkElem = (React.createElement(components_1.OverlayTrigger, { overlay: tooltipElem, style: { display: "inline" } },
|
|
236
|
+
React.createElement("a", { href: `http://tun.fi/${suggestion === null || suggestion === void 0 ? void 0 : suggestion.id}`, target: "_blank", rel: "noopener noreferrer" }, suggestion === null || suggestion === void 0 ? void 0 : suggestion.id)));
|
|
237
|
+
let popover;
|
|
238
|
+
if ((0, utils_1.isEmptyString)(inputValue)) {
|
|
239
|
+
popover = React.createElement(React.Fragment, null);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
popover = (React.createElement(Popover, { id: `${id}-popover` },
|
|
243
|
+
!isSuggested && this.props.formContext.translations.UnknownName,
|
|
244
|
+
isSuggested && (React.createElement("div", null, options === null || options === void 0 ? void 0 :
|
|
245
|
+
options.taxonRankLabel,
|
|
246
|
+
" ",
|
|
247
|
+
suggestion.cursiveName ? React.createElement("i", null, suggestion.scientificName) : suggestion.scientificName,
|
|
248
|
+
" ",
|
|
249
|
+
suggestion.scientificNameAuthorship,
|
|
250
|
+
" ",
|
|
251
|
+
(0, AutosuggestWidget_1.renderTaxonIcons)(suggestion),
|
|
252
|
+
" (",
|
|
253
|
+
taxonLinkElem,
|
|
254
|
+
")"))));
|
|
255
|
+
}
|
|
256
|
+
return (React.createElement(components_1.OverlayTrigger, { hoverable: true, placement: placement, overlay: popover, ref: this.props.overlayRef, formContext: this.props.formContext }, children));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
_TaxonWrapper.contextType = ReactContext_1.default;
|
|
260
|
+
const TaxonWrapper = React.forwardRef((props, ref) => React.createElement(_TaxonWrapper, Object.assign({}, props, { overlayRef: ref })));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export function renderTaxonIcons(suggestion: any, prepend: any): JSX.Element | null;
|
|
1
2
|
export default class _AutosuggestWidget extends React.Component<any, any, any> {
|
|
2
3
|
static propTypes: {
|
|
3
4
|
schema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
|
|
@@ -22,6 +23,7 @@ export class Autosuggest extends React.Component<any, any, any> {
|
|
|
22
23
|
informalTaxonGroups: PropTypes.Requireable<string>;
|
|
23
24
|
onInformalTaxonGroupSelected: PropTypes.Requireable<(...args: any[]) => any>;
|
|
24
25
|
cache: PropTypes.Requireable<boolean>;
|
|
26
|
+
valueContext: PropTypes.Requireable<object>;
|
|
25
27
|
};
|
|
26
28
|
static defaultProps: {
|
|
27
29
|
allowNonsuggestedValue: boolean;
|
|
@@ -43,12 +45,13 @@ export class Autosuggest extends React.Component<any, any, any> {
|
|
|
43
45
|
mounted: boolean | undefined;
|
|
44
46
|
componentWillUnmount(): void;
|
|
45
47
|
componentDidUpdate(prevProps: any): void;
|
|
48
|
+
triggerConvertTimeout: any;
|
|
46
49
|
keyFunctions: {
|
|
47
50
|
autosuggestToggle: () => boolean;
|
|
48
51
|
};
|
|
49
52
|
triggerConvert: (props: any) => void;
|
|
50
53
|
getSuggestionValue: (suggestion: any) => any;
|
|
51
|
-
renderSuggestion: (suggestion: any) => JSX.Element;
|
|
54
|
+
renderSuggestion: (suggestion: any, inputValue: any) => JSX.Element;
|
|
52
55
|
selectSuggestion: (suggestion: any) => void;
|
|
53
56
|
selectUnsuggested: (inputValue: any) => void;
|
|
54
57
|
onSuggestionSelected: (suggestion: any) => void;
|
|
@@ -63,6 +63,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
63
63
|
};
|
|
64
64
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
65
|
exports.Autosuggest = void 0;
|
|
66
|
+
exports.renderTaxonIcons = renderTaxonIcons;
|
|
66
67
|
const React = __importStar(require("react"));
|
|
67
68
|
const react_dom_1 = require("react-dom");
|
|
68
69
|
const PropTypes = __importStar(require("prop-types"));
|
|
@@ -71,11 +72,16 @@ const utils_1 = require("../../utils");
|
|
|
71
72
|
const components_1 = require("../components");
|
|
72
73
|
const ReactContext_1 = __importDefault(require("../../ReactContext"));
|
|
73
74
|
const InformalTaxonGroupChooserWidget_1 = require("./InformalTaxonGroupChooserWidget");
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const utils_2 = require("@rjsf/utils");
|
|
76
|
+
function renderTaxonIcons(suggestion, prepend) {
|
|
77
|
+
const { finnish, checklist } = suggestion || {};
|
|
78
|
+
const flagIcon = finnish ? React.createElement("img", { src: "https://cdn.laji.fi/images/icons/flag_fi_small.png", width: "16", className: "flag-img" }) : null;
|
|
79
|
+
const gbifIcon = checklist === "MR.2" ? React.createElement("img", { src: "https://cdn.laji.fi/images/icons/gbif.svg", width: "18" }) : null;
|
|
80
|
+
return flagIcon || gbifIcon
|
|
76
81
|
? React.createElement(React.Fragment, null,
|
|
77
82
|
prepend || null,
|
|
78
|
-
|
|
83
|
+
flagIcon,
|
|
84
|
+
gbifIcon)
|
|
79
85
|
: null;
|
|
80
86
|
}
|
|
81
87
|
class _AutosuggestWidget extends React.Component {
|
|
@@ -248,7 +254,7 @@ function TaxonAutosuggest(ComposedComponent) {
|
|
|
248
254
|
&& React.createElement("span", { dangerouslySetInnerHTML: { __html: suggestion.autocompleteDisplayName } })
|
|
249
255
|
|| React.createElement(React.Fragment, null,
|
|
250
256
|
suggestion.value,
|
|
251
|
-
|
|
257
|
+
renderTaxonIcons(suggestion));
|
|
252
258
|
return React.createElement("span", { className: "simple-option" }, renderedSuggestion);
|
|
253
259
|
}
|
|
254
260
|
render() {
|
|
@@ -303,7 +309,7 @@ let UnitAutosuggestWidget = class UnitAutosuggestWidget extends React.Component
|
|
|
303
309
|
maleElem,
|
|
304
310
|
femaleElem && " ",
|
|
305
311
|
femaleElem,
|
|
306
|
-
|
|
312
|
+
renderTaxonIcons(suggestion));
|
|
307
313
|
}
|
|
308
314
|
};
|
|
309
315
|
UnitAutosuggestWidget = __decorate([
|
|
@@ -456,7 +462,7 @@ class Autosuggest extends React.Component {
|
|
|
456
462
|
const { isValueSuggested, suggestionReceive, onSuggestionSelected } = props;
|
|
457
463
|
if (!onSuggestionSelected && suggestionReceive !== "key")
|
|
458
464
|
return undefined;
|
|
459
|
-
return isValueSuggested ? isValueSuggested(props.value) : undefined;
|
|
465
|
+
return isValueSuggested ? isValueSuggested(props.value, props.valueContext) : undefined;
|
|
460
466
|
};
|
|
461
467
|
this.wrapperRef = React.createRef();
|
|
462
468
|
this.keyFunctions = {
|
|
@@ -469,7 +475,7 @@ class Autosuggest extends React.Component {
|
|
|
469
475
|
}
|
|
470
476
|
};
|
|
471
477
|
this.triggerConvert = (props) => {
|
|
472
|
-
const { value, getSuggestionFromValue } = props;
|
|
478
|
+
const { value, getSuggestionFromValue, valueContext } = props;
|
|
473
479
|
if ((0, utils_1.isEmptyString)(value) || !getSuggestionFromValue) {
|
|
474
480
|
if (this.state.suggestion && Object.keys(this.state.suggestion).length > 0) {
|
|
475
481
|
this.setState({ suggestion: undefined, inputValue: value, suggestionForValue: value });
|
|
@@ -477,7 +483,7 @@ class Autosuggest extends React.Component {
|
|
|
477
483
|
return;
|
|
478
484
|
}
|
|
479
485
|
this.setState({ isLoading: true });
|
|
480
|
-
getSuggestionFromValue(value).then(suggestion => {
|
|
486
|
+
getSuggestionFromValue(value, valueContext).then(suggestion => {
|
|
481
487
|
if (!this.mounted)
|
|
482
488
|
return;
|
|
483
489
|
this.setState({ suggestion, inputValue: this.getSuggestionValue(suggestion), isLoading: false, suggestionForValue: value });
|
|
@@ -494,11 +500,11 @@ class Autosuggest extends React.Component {
|
|
|
494
500
|
? getSuggestionValue(suggestion, def)
|
|
495
501
|
: def;
|
|
496
502
|
};
|
|
497
|
-
this.renderSuggestion = (suggestion) => {
|
|
503
|
+
this.renderSuggestion = (suggestion, inputValue) => {
|
|
498
504
|
let { renderSuggestion } = this.props;
|
|
499
505
|
if (!renderSuggestion)
|
|
500
506
|
renderSuggestion = suggestion => suggestion.value;
|
|
501
|
-
return (React.createElement("span", null, renderSuggestion(suggestion)));
|
|
507
|
+
return (React.createElement("span", null, renderSuggestion(suggestion, inputValue)));
|
|
502
508
|
};
|
|
503
509
|
this.selectSuggestion = (suggestion) => {
|
|
504
510
|
const { onSuggestionSelected, onChange, suggestionReceive } = this.props;
|
|
@@ -764,7 +770,7 @@ class Autosuggest extends React.Component {
|
|
|
764
770
|
const input = (React.createElement(components_1.FetcherInput, Object.assign({ value: inputValue, glyph: glyph, loading: this.state.isLoading, validationState: validationState, extra: [addon, toggler] }, inputProps)));
|
|
765
771
|
let component = input;
|
|
766
772
|
if (displayValidationState && Wrapper) {
|
|
767
|
-
component = (React.createElement(Wrapper, { isSuggested: isSuggested, suggestion: suggestion, options: (0, utils_1.getUiOptions)(this.props), id: this.props.id, value: suggestion && suggestion.key, inputValue: value, ref: this.wrapperRef, formContext: this.props.formContext }, component));
|
|
773
|
+
component = (React.createElement(Wrapper, { isSuggested: isSuggested, suggestion: suggestion, options: (0, utils_1.getUiOptions)(this.props.uiSchema), id: this.props.id, value: suggestion && suggestion.key, inputValue: value, ref: this.wrapperRef, formContext: this.props.formContext }, component));
|
|
768
774
|
}
|
|
769
775
|
if (informalTaxonGroups) {
|
|
770
776
|
component = (React.createElement(React.Fragment, null,
|
|
@@ -793,13 +799,34 @@ class Autosuggest extends React.Component {
|
|
|
793
799
|
this.props.formContext.services.keyHandler.removeKeyHandler(this.props.id, this.keyFunctions);
|
|
794
800
|
}
|
|
795
801
|
componentDidUpdate(prevProps) {
|
|
796
|
-
if (
|
|
797
|
-
|
|
802
|
+
if (this.props.controlledValue) {
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
const valueChanged = this.state.suggestion && this.props && prevProps.value !== this.props.value && this.props.value !== this.state.suggestionForValue;
|
|
806
|
+
const valueContextChanged = !(0, utils_2.deepEquals)(prevProps.valueContext, this.props.valueContext);
|
|
807
|
+
if (valueChanged) {
|
|
808
|
+
this.props.getSuggestionFromValue(this.props.value, this.props.valueContext).then(suggestion => {
|
|
798
809
|
this.setState({ inputValue: this.getSuggestionValue(suggestion), suggestion });
|
|
799
810
|
}, () => {
|
|
800
|
-
|
|
811
|
+
const state = { suggestion: undefined };
|
|
812
|
+
if (!this.props.allowNonsuggestedValue) {
|
|
813
|
+
state.inputValue = "";
|
|
814
|
+
}
|
|
815
|
+
this.setState(state);
|
|
801
816
|
});
|
|
802
817
|
}
|
|
818
|
+
else if (valueContextChanged) {
|
|
819
|
+
this.setState({ isLoading: true });
|
|
820
|
+
if (this.triggerConvertTimeout) {
|
|
821
|
+
clearTimeout(this.triggerConvertTimeout);
|
|
822
|
+
}
|
|
823
|
+
// debounce trigger convert function so that it's not called too frequently
|
|
824
|
+
this.triggerConvertTimeout = this.props.formContext.setTimeout(() => {
|
|
825
|
+
if (!this.mounted)
|
|
826
|
+
return;
|
|
827
|
+
this.triggerConvert(this.props);
|
|
828
|
+
}, 100);
|
|
829
|
+
}
|
|
803
830
|
}
|
|
804
831
|
render() {
|
|
805
832
|
const { props } = this;
|
|
@@ -833,7 +860,8 @@ Autosuggest.propTypes = {
|
|
|
833
860
|
uiSchema: PropTypes.object,
|
|
834
861
|
informalTaxonGroups: PropTypes.string,
|
|
835
862
|
onInformalTaxonGroupSelected: PropTypes.func,
|
|
836
|
-
cache: PropTypes.bool
|
|
863
|
+
cache: PropTypes.bool,
|
|
864
|
+
valueContext: PropTypes.object
|
|
837
865
|
};
|
|
838
866
|
Autosuggest.defaultProps = {
|
|
839
867
|
allowNonsuggestedValue: true,
|
|
@@ -861,10 +889,10 @@ class _TaxonWrapper extends React.Component {
|
|
|
861
889
|
this.setState({ scientificName: "", cursiveName: false });
|
|
862
890
|
}
|
|
863
891
|
else {
|
|
864
|
-
this.props.formContext.apiClient.get(`/taxa/${value}`).then(({ scientificName, cursiveName, vernacularName, taxonRank, informalGroups, finnish }) => {
|
|
892
|
+
this.props.formContext.apiClient.get(`/taxa/${value}`).then(({ scientificName, cursiveName, vernacularName, taxonRank, informalGroups, finnish, checklist }) => {
|
|
865
893
|
if (!this.mounted)
|
|
866
894
|
return;
|
|
867
|
-
this.setState({ value, taxonRank, informalTaxonGroups: informalGroups, taxon: { scientificName, vernacularName, cursiveName, finnish } });
|
|
895
|
+
this.setState({ value, taxonRank, informalTaxonGroups: informalGroups, taxon: { scientificName, vernacularName, cursiveName, finnish, checklist } });
|
|
868
896
|
(0, InformalTaxonGroupChooserWidget_1.getInformalGroups)(this.props.formContext.apiClient).then(({ informalTaxonGroupsById }) => {
|
|
869
897
|
if (!this.mounted)
|
|
870
898
|
return;
|
|
@@ -889,7 +917,7 @@ class _TaxonWrapper extends React.Component {
|
|
|
889
917
|
}
|
|
890
918
|
}
|
|
891
919
|
this.setState(Object.assign(Object.assign({}, state), { higherThanOrder: !state.order && !state.family }));
|
|
892
|
-
const taxonRanks = yield this.props.formContext.apiClient.get("/metadata/
|
|
920
|
+
const taxonRanks = (yield this.props.formContext.apiClient.get("/metadata/properties/MX.taxonRank/alt")).results;
|
|
893
921
|
if (!this.mounted)
|
|
894
922
|
return;
|
|
895
923
|
this.setState({ taxonRanks: (0, utils_1.dictionarify)(taxonRanks, function getKey(rank) { return rank.id; }, function getValue(rank) { return rank.value; }) });
|
|
@@ -1049,14 +1077,14 @@ class TaxonImgChooser extends React.Component {
|
|
|
1049
1077
|
}
|
|
1050
1078
|
}
|
|
1051
1079
|
TaxonImgChooser.contextType = ReactContext_1.default;
|
|
1052
|
-
const TaxonName = ({ scientificName, vernacularName = "", cursiveName, finnish }) => {
|
|
1080
|
+
const TaxonName = ({ scientificName, vernacularName = "", cursiveName, finnish, checklist }) => {
|
|
1053
1081
|
const _scientificName = vernacularName && scientificName
|
|
1054
1082
|
? `(${scientificName})`
|
|
1055
1083
|
: (scientificName || "");
|
|
1056
1084
|
return (React.createElement(React.Fragment, null,
|
|
1057
1085
|
`${vernacularName}${vernacularName ? " " : ""}`,
|
|
1058
1086
|
cursiveName ? React.createElement("i", null, _scientificName) : _scientificName,
|
|
1059
|
-
|
|
1087
|
+
renderTaxonIcons({ finnish, checklist }, " ")));
|
|
1060
1088
|
};
|
|
1061
1089
|
class ReactAutosuggest extends React.Component {
|
|
1062
1090
|
constructor(props) {
|