Introduces 'draft mode' tags, so user doesn't need to hit Enter to store

This commit is contained in:
Rainer Simon 2020-09-15 15:09:32 +02:00
parent 48d65ce520
commit 4373abf54b
2 changed files with 37 additions and 9 deletions

View File

@ -9,7 +9,6 @@ const Autocomplete = props => {
const onInputValueChange = ({ inputValue }) => {
if (inputValue.length > 0) {
// Set suggestions to prefix matches...
const prefixMatches = props.vocabulary.filter(item => {
return item.toLowerCase().startsWith(inputValue.toLowerCase());
});
@ -61,6 +60,7 @@ const Autocomplete = props => {
<div {...getComboboxProps()}>
<input
{...getInputProps({ onKeyDown })}
onChange={evt => props.onChange && props.onChange(evt)}
placeholder={props.placeholder}
defaultValue={props.initialValue}
/>

View File

@ -5,14 +5,25 @@ import { CloseIcon } from '../../../Icons';
import i18n from '../../../i18n';
import Autocomplete from '../Autocomplete';
const getDraftTag = existingDraft =>
existingDraft ? existingDraft : {
type: 'TextualBody', value: '', purpose: 'tagging', draft: true
};
/** The basic freetext tag control from original Recogito **/
const TagWidget = props => {
const [ showDelete, setShowDelete ] = useState(false);
// All tags (draft + non-draft)
const all = props.annotation ?
props.annotation.bodies.filter(b => b.type === 'TextualBody' && b.purpose === 'tagging') : [];
// Every body with a 'tagging' purpose is considered a tag
const tagBodies = props.annotation ?
props.annotation.bodies.filter(b => b.purpose === 'tagging') : [];
// Last draft tag goes into the input field
const draftTag = getDraftTag(all.slice().reverse().find(b => b.draft));
// All except draft tag
const tags = all.filter(b => b != draftTag);
const [ showDelete, setShowDelete ] = useState(false);
const toggle = tag => _ => {
if (showDelete === tag) // Removes delete button
@ -26,16 +37,31 @@ const TagWidget = props => {
props.onRemoveBody(tag);
}
const onDraftChange = evt => {
const prev = draftTag.value.trim();
const updated = evt.target.value.trim();
if (prev.length === 0 && updated.length > 0) {
props.onAppendBody({ ...draftTag, value: updated });
} else if (prev.length > 0 && updated.length === 0) {
props.onRemoveBody(draftTag);
} else {
props.onUpdateBody(draftTag, { ...draftTag, value: updated });
}
}
const onSubmit = tag => {
props.onAppendBody({ type: 'TextualBody', purpose: 'tagging', value: tag.trim() });
// Just 'undraft' the current draft tag
const { draft, ...undrafted } = draftTag;
props.onUpdateBody(draftTag, undrafted);
}
return (
<div className="r6o-widget tag">
<div>
{ tagBodies.length > 0 &&
{ tags.length > 0 &&
<ul className="r6o-taglist">
{ tagBodies.map(tag =>
{ tags.map(tag =>
<li key={tag.value} onClick={toggle(tag.value)}>
<span className="label">{tag.value}</span>
@ -57,6 +83,8 @@ const TagWidget = props => {
{!props.readOnly &&
<Autocomplete
placeholder={i18n.t('Add tag...')}
initialValue={draftTag.value}
onChange={onDraftChange}
onSubmit={onSubmit}
vocabulary={props.vocabulary || []} />
}