@recogito/recogito-client-core
Advanced tools
Comparing version 0.2.5 to 0.2.6
{ | ||
"name": "@recogito/recogito-client-core", | ||
"version": "0.2.5", | ||
"version": "0.2.6", | ||
"description": "Core functions, classes and components for RecogitoJS", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -39,8 +39,12 @@ import React from 'preact/compat'; | ||
// The 'currentAnnotation' differs from props.annotation because | ||
// the user has been editing. Moving the selection bounds will | ||
// trigger this effect, but we don't want to update the currentAnnotation | ||
// the user has been editing. Moving the selection bounds will | ||
// trigger the re-render effect, but we don't want to update the currentAnnotation | ||
// on move. Therefore, don't update if a) props.annotation equals | ||
// the currentAnnotation, or props.annotation and currentAnnotations are | ||
// a selection, just created by the user. | ||
const preventUpdate = currentAnnotation?.isEqual(annotation); | ||
const preventUpdate = | ||
currentAnnotation && ( // Always update if there is no current annotation | ||
(currentAnnotation.isSelection && annotation.isSelection) || // Don't update selection | ||
(currentAnnotation.id === annotation.id) // Don't update if annotation ID is the same | ||
) | ||
@@ -80,5 +84,4 @@ if (!preventUpdate) | ||
// Metadata is only added when a user is set, otherwise | ||
// the Editor operates in 'anonymous mode'. Also, | ||
// no point in adding meta while we're in draft state | ||
if (!body.draft && user) { | ||
// the Editor operates in 'anonymous mode'. | ||
if (user) { | ||
meta.creator = {}; | ||
@@ -120,8 +123,7 @@ if (user.id) meta.creator.id = user.id; | ||
const onOk = _ => { | ||
// Removes the 'draft' flag from all bodies | ||
// Removes the state payload from all bodies | ||
const undraft = annotation => | ||
annotation.clone({ | ||
body : annotation.bodies.map(({ draft, ...rest }) => | ||
draft ? { ...rest, ...creationMeta(rest) } : rest ) | ||
}); | ||
annotation.clone({ | ||
body : annotation.bodies.map(({ draft, ...rest }) => rest) | ||
}); | ||
@@ -128,0 +130,0 @@ // Current annotation is either a selection (if it was created from |
@@ -6,7 +6,6 @@ import React from 'preact/compat'; | ||
import TextEntryField from './TextEntryField'; | ||
import PurposeDropdown from './PurposeDropdown'; | ||
import PurposeSelect from './PurposeSelect'; | ||
import { ChevronDownIcon } from '../../../Icons'; | ||
import i18n from '../../../i18n'; | ||
/** A single comment inside the CommentWidget **/ | ||
@@ -19,3 +18,2 @@ const Comment = props => { | ||
const onMakeEditable = _ => { | ||
props.body.draft = true; | ||
setIsEditable(true); | ||
@@ -30,10 +28,10 @@ setIsMenuVisible(false); | ||
const onUpdateComment = evt => { | ||
const onUpdateComment = evt => | ||
props.onUpdate(props.body, { ...props.body, value: evt.target.value }); | ||
} | ||
const onUpdateDropdown = evt => { | ||
const onChangePurpose = evt => | ||
props.onUpdate(props.body, { ...props.body, purpose: evt.value }); | ||
} | ||
const timestamp = props.body.modified || props.body.created; | ||
const creatorInfo = props.body.creator && | ||
@@ -45,3 +43,3 @@ <div className="r6o-lastmodified"> | ||
<TimeAgo | ||
datetime={props.env.toClientTime(props.body.created)} | ||
datetime={props.env.toClientTime(timestamp)} | ||
locale={i18n.locale()} /> | ||
@@ -65,9 +63,9 @@ </span> | ||
/> | ||
{ creatorInfo } | ||
{ !isEditable && creatorInfo } | ||
{ props.purpose && | ||
<PurposeDropdown | ||
{ props.purposeSelector && | ||
<PurposeSelect | ||
editable={isEditable} | ||
content={props.body.purpose} | ||
onChange={onUpdateDropdown} | ||
onChange={onChangePurpose} | ||
onSaveAndClose={props.onSaveAndClose} | ||
@@ -74,0 +72,0 @@ /> } |
@@ -5,5 +5,6 @@ import React from 'preact/compat'; | ||
import i18n from '../../../i18n'; | ||
import PurposeDropdown, {purposes} from './PurposeDropdown'; | ||
import PurposeSelect, { PURPOSES } from './PurposeSelect'; | ||
const purposeValues = purposes.map(p => p.value); | ||
const validPurposes = PURPOSES.map(p => p.value); | ||
/** | ||
@@ -13,23 +14,19 @@ * Comments are TextualBodies where the purpose field is either | ||
*/ | ||
const isComment = (body, purposenabled) => | ||
body.type === 'TextualBody' && ( | ||
!body.hasOwnProperty('purpose') || purposeCheck(body.purpose, purposenabled) | ||
const isComment = (body, matchAllPurposes) => { | ||
const hasMatchingPurpose = matchAllPurposes ? | ||
validPurposes.indexOf(body.purpose) > -1 : body.purpose == 'commenting' || body.purpose == 'replying'; | ||
return body.type === 'TextualBody' && ( | ||
!body.hasOwnProperty('purpose') || hasMatchingPurpose | ||
); | ||
} | ||
/** | ||
* The draft reply is a comment body with a 'draft' flag | ||
*/ | ||
const purposeCheck = (purpose, purposenabled) => { | ||
if (purposenabled){ | ||
return purposeValues.indexOf(purpose) > -1 | ||
} else { | ||
return purpose == 'commenting' || purpose == 'replying' | ||
} | ||
} | ||
const getDraftReply = (existingDraft, isReply) => { | ||
let draft = existingDraft ? existingDraft : { | ||
type: 'TextualBody', value: '', draft: true | ||
const purpose = isReply ? 'replying' : 'commenting'; | ||
return existingDraft ? existingDraft : { | ||
type: 'TextualBody', value: '', purpose, draft: true | ||
}; | ||
draft.purpose = draft.purpose ? draft.purpose : isReply ? 'replying' : 'commenting'; | ||
return draft; | ||
}; | ||
@@ -41,9 +38,12 @@ | ||
const CommentWidget = props => { | ||
// All comments (draft + non-draft) | ||
// All comments | ||
const all = props.annotation ? | ||
props.annotation.bodies.filter(body => isComment(body, props.purpose)) : []; | ||
// Last draft comment without a creator field goes into the reply field | ||
const draftReply = getDraftReply(all.slice().reverse().find(b => b.draft && !b.creator), all.length > 1); | ||
props.annotation.bodies.filter(body => isComment(body, props.purposeSelector)) : []; | ||
// Add a draft reply if there isn't one already | ||
const draftReply = getDraftReply(all.find(b => b.draft == true), all.length > 1); | ||
// All except draft reply | ||
const comments = all.filter(b => b != draftReply); | ||
const onEditReply = evt => { | ||
@@ -62,10 +62,4 @@ const prev = draftReply.value; | ||
const onUpdatePurpose = evt => { | ||
const updated = evt.value.trim(); | ||
if (draftReply.value == '' && updated.length > 0) { | ||
draftReply.purpose = updated; | ||
} else { | ||
props.onUpdateBody(draftReply, { ...draftReply, purpose: updated }); | ||
} | ||
} | ||
const onChangeReplyPurpose = purpose => | ||
props.onUpdateBody(draftReply, { ...draftReply, purpose: purpose.value }); | ||
@@ -103,3 +97,3 @@ // A comment should be read-only if: | ||
env={props.env} | ||
purpose={props.purpose} | ||
purposeSelector={props.purposeSelector} | ||
readOnly={isReadOnly(body)} | ||
@@ -121,7 +115,7 @@ body={body} | ||
/> | ||
{ props.purpose == true && draftReply.value.length > 0 && | ||
<PurposeDropdown | ||
{ props.purposeSelector && draftReply.value.length > 0 && | ||
<PurposeSelect | ||
editable={true} | ||
content={draftReply.purpose} | ||
onChange={onUpdatePurpose} | ||
onChange={onChangeReplyPurpose} | ||
onSaveAndClose={() => props.onSaveAndClose()} | ||
@@ -128,0 +122,0 @@ /> |
1216359
2793