diff --git a/src/editor/Editor.jsx b/src/editor/Editor.jsx
index ebc7fe9..b6383bc 100644
--- a/src/editor/Editor.jsx
+++ b/src/editor/Editor.jsx
@@ -41,8 +41,8 @@ const Editor = props => {
// 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 = setCurrentAnnotation.isSelection ?
- annotation.isSelection : currentAnnotation.annotationId === annotation.annotationId;
+ const preventUpdate = currentAnnotation?.isSelection ?
+ annotation?.isSelection : currentAnnotation?.id === annotation.id;
if (!preventUpdate)
setCurrentAnnotation(annotation);
@@ -77,9 +77,8 @@ const Editor = props => {
const { user } = props.env;
// 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 = {};
if (user.id) meta.creator.id = user.id;
if (user.displayName) meta.creator.name = user.displayName;
@@ -116,12 +115,11 @@ const Editor = props => {
props.onCancel(currentAnnotation);
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)
+ });
// Current annotation is either a selection (if it was created from
// scratch just now) or an annotation (if it existed already and was
diff --git a/src/editor/widgets/comment/Comment.jsx b/src/editor/widgets/comment/Comment.jsx
index 8560faa..7667307 100644
--- a/src/editor/widgets/comment/Comment.jsx
+++ b/src/editor/widgets/comment/Comment.jsx
@@ -3,11 +3,10 @@ import { useState } from 'preact/hooks';
import TimeAgo from 'timeago-react';
import DropdownMenu from './DropdownMenu';
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 **/
const Comment = props => {
@@ -15,7 +14,6 @@ const Comment = props => {
const [ isMenuVisible, setIsMenuVisible ] = useState(false);
const onMakeEditable = _ => {
- props.body.draft = true;
setIsEditable(true);
setIsMenuVisible(false);
}
@@ -25,13 +23,13 @@ const Comment = props => {
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 &&
@@ -39,7 +37,7 @@ const Comment = props => {
{ props.body.created &&
}
@@ -58,13 +56,13 @@ const Comment = props => {
onChange={onUpdateComment}
onSaveAndClose={props.onSaveAndClose}
/>
- { creatorInfo }
+ { !isEditable && creatorInfo }
- { props.purpose &&
-
}
diff --git a/src/editor/widgets/comment/CommentWidget.jsx b/src/editor/widgets/comment/CommentWidget.jsx
index 100221c..1fe0fdc 100644
--- a/src/editor/widgets/comment/CommentWidget.jsx
+++ b/src/editor/widgets/comment/CommentWidget.jsx
@@ -2,47 +2,47 @@ import React from 'preact/compat';
import Comment from './Comment';
import TextEntryField from './TextEntryField';
import i18n from '../../../i18n';
-import PurposeDropdown, {purposes} from './PurposeDropdown';
+import PurposeSelect, { PURPOSES } from './PurposeSelect';
+
+const validPurposes = PURPOSES.map(p => p.value);
-const purposeValues = purposes.map(p => p.value);
/**
* Comments are TextualBodies where the purpose field is either
* blank or 'commenting' or 'replying'
*/
-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;
};
/**
* Renders a list of comment bodies, followed by a 'reply' field.
*/
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 => {
const prev = draftReply.value;
const updated = evt.target.value;
@@ -56,14 +56,8 @@ const CommentWidget = props => {
}
}
- 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 });
// A comment should be read-only if:
// - the global read-only flag is set
@@ -96,7 +90,7 @@ const CommentWidget = props => {
{
onChange={onEditReply}
onSaveAndClose={() => props.onSaveAndClose()}
/>
- { props.purpose == true && draftReply.value.length > 0 &&
- 0 &&
+ props.onSaveAndClose()}
/>
}
diff --git a/src/editor/widgets/comment/PurposeDropdown.jsx b/src/editor/widgets/comment/PurposeSelect.jsx
similarity index 83%
rename from src/editor/widgets/comment/PurposeDropdown.jsx
rename to src/editor/widgets/comment/PurposeSelect.jsx
index 3937b74..64f44ce 100644
--- a/src/editor/widgets/comment/PurposeDropdown.jsx
+++ b/src/editor/widgets/comment/PurposeSelect.jsx
@@ -1,7 +1,7 @@
import React from 'preact/compat';
import Select from 'react-select';
-export const purposes = [
+export const PURPOSES = [
{'value': 'assessing', 'label': 'Assessing'},
{'value': 'bookmarking', 'label': 'Bookmarking'},
{'value': 'classifying', 'label': 'Classifying'},
@@ -16,17 +16,17 @@ export const purposes = [
{'value': 'replying', 'label': 'Replying'}
]
-const PurposeDropdown = props => {
+const PurposeSelect = props => {
const selectedOption = props.content ?
- purposes.find(p => p.value === props.content) : null;
+ PURPOSES.find(p => p.value === props.content) : null;
return (
@@ -34,4 +34,4 @@ const PurposeDropdown = props => {
}
-export default PurposeDropdown;
\ No newline at end of file
+export default PurposeSelect;
\ No newline at end of file