From 0e70226aaa12da6e24f766134eea9e1266c97be7 Mon Sep 17 00:00:00 2001 From: Rainer Simon Date: Sat, 4 Apr 2020 20:47:04 +0200 Subject: [PATCH] Rolled the reply field into CommentWidget, where it belongs --- src/editor/Editor.jsx | 35 +++++------ src/editor/index.js | 2 - src/editor/widgets/comment/Comment.jsx | 2 +- src/editor/widgets/comment/CommentWidget.jsx | 60 +++++++++++++++---- src/editor/widgets/comment/TextEntryField.jsx | 2 +- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/editor/Editor.jsx b/src/editor/Editor.jsx index 1edb955..0754ebb 100644 --- a/src/editor/Editor.jsx +++ b/src/editor/Editor.jsx @@ -1,7 +1,6 @@ import React, { useState, useRef, useEffect } from 'react'; import setPosition from './setPosition'; import TagWidget from './widgets/tag/TagWidget'; -import TypeSelectorWidget from './widgets/type/TypeSelectorWidget'; import CommentWidget from './widgets/comment/CommentWidget'; /** @@ -15,7 +14,6 @@ const Editor = props => { // The current state of the edited annotation vs. original const [ currentAnnotation, setCurrentAnnotation ] = useState(); - const [ currentReply, setCurrentReply ] = useState(''); // Reference to the DOM element, so we can set position const element = useRef(); @@ -23,7 +21,6 @@ const Editor = props => { // Re-render: set derived annotation state & position the editor useEffect(() => { setCurrentAnnotation(props.annotation); - setCurrentReply(''); if (element.current) setPosition(props.containerEl, element.current, props.bounds); @@ -48,25 +45,24 @@ const Editor = props => { ); const onOk = _ => { - // If there is a non-empty reply, append it as a comment body - const updated = currentReply.trim() ? - currentAnnotation.clone({ - body: [ ...currentAnnotation.bodies, { type: 'TextualBody', value: currentReply.trim() } ] - }) : currentAnnotation; + // Removes the 'draft' flag from all bodies + const undraft = annotation => 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 // opened for editing) - if (updated.bodies.length === 0) { - if (updated.isSelection) + if (currentAnnotation.bodies.length === 0) { + if (currentAnnotation.isSelection) props.onCancel(); else props.onAnnotationDeleted(props.annotation); } else { - if (updated.isSelection) - props.onAnnotationCreated(updated.toAnnotation()); + if (currentAnnotation.isSelection) + props.onAnnotationCreated(undraft(currentAnnotation).toAnnotation()); else - props.onAnnotationUpdated(updated, props.annotation); + props.onAnnotationUpdated(undraft(currentAnnotation), props.annotation); } }; @@ -76,16 +72,15 @@ const Editor = props => {
setCurrentReply(evt.target.value.trim())} - onOk={onOk} /> + onAppendBody={onAppendBody} + onUpdateBody={onUpdateBody} + onRemoveBody={onRemoveBody} + onSaveAndClose={onOk} /> + onAppendBody={onAppendBody} + onRemoveBody={onRemoveBody} /> { props.readOnly ? (
diff --git a/src/editor/index.js b/src/editor/index.js index 2620410..4bf9280 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -2,10 +2,8 @@ import Editor from './Editor'; import CommentWidget from './widgets/comment/CommentWidget'; import TagWidget from './widgets/tag/TagWidget'; -import TypeSelectorWidget from './widgets/type/TypeSelectorWidget'; Editor.CommentWidget = CommentWidget; Editor.TagWidget = TagWidget; -Editor.TypeSelectorWidget = TypeSelectorWidget; export { Editor }; diff --git a/src/editor/widgets/comment/Comment.jsx b/src/editor/widgets/comment/Comment.jsx index a6bf190..5fbb8f4 100644 --- a/src/editor/widgets/comment/Comment.jsx +++ b/src/editor/widgets/comment/Comment.jsx @@ -32,7 +32,7 @@ const Comment = props => { editable={isEditable} content={props.body.value} onChange={onUpdateComment} - onOk={props.onOk} + onSaveAndClose={props.onSaveAndClose} />
+ body.type === 'TextualBody' && ( + !body.hasOwnProperty('purpose') || body.purpose === 'commenting' || body.purpose === 'replying' + ); + +/** + * The draft reply is a comment body with a 'draft' flag + */ +const getDraftReply = (existingDraft, isReply) => { + return existingDraft ? existingDraft : { + type: 'TextualBody', value: '', purpose: isReply ? 'replying' : 'commenting', draft: true + }; +}; + /** * Renders a list of comment bodies, followed by a 'reply' field. */ const CommentWidget = props => { - const commentBodies = props.annotation ? - props.annotation.bodies.filter(b => // No purpose or 'commenting', 'replying' - !b.hasOwnProperty('purpose') || b.purpose === 'commenting' || b.purpose === 'replying' - ) : []; + // All comments (draft + non-draft) + const all = props.annotation ? + props.annotation.bodies.filter(isComment) : []; + + // Non-draft comments + const comments = all.filter(b => !b.draft); + + // Draft reply + const draftReply = getDraftReply(all.find(b => b.draft), comments.length > 0); + + const onEditReply = evt => { + const prev = draftReply.value.trim(); + const updated = evt.target.value.trim(); + + if (prev.length === 0 && updated.length > 0) { + props.onAppendBody({ ...draftReply, value: updated }); + } else if (prev.length > 0 && updated.length === 0) { + props.onRemoveBody(draftReply); + } else { + props.onUpdateBody(draftReply, { ...draftReply, value: updated }); + } + } return ( <> - { commentBodies.map((body, idx) => + { comments.map((body, idx) => + onUpdate={props.onUpdateBody} + onDelete={props.onRemoveBody} + onSaveAndClose={props.onSaveAndClose} /> )} { !props.readOnly && props.annotation &&
0 ? 'Add a reply...' : 'Add a comment...'} - onChange={props.onUpdateReply} - onOk={() => props.onOk()} + placeholder={comments.length > 0 ? 'Add a reply...' : 'Add a comment...'} + onChange={onEditReply} + onSaveAndClose={() => props.onSaveAndClose()} />
} diff --git a/src/editor/widgets/comment/TextEntryField.jsx b/src/editor/widgets/comment/TextEntryField.jsx index 87e684c..553f15d 100644 --- a/src/editor/widgets/comment/TextEntryField.jsx +++ b/src/editor/widgets/comment/TextEntryField.jsx @@ -13,7 +13,7 @@ export default class TextEntryField extends Component { // CTRL+Enter functions as Ok onKeyDown = evt => { if (evt.which === 13 && evt.ctrlKey) - this.props.onOk(); + this.props.onSaveAndClose(); } // Focus on render