diff --git a/apps/comments-ui/src/components/Comment.js b/apps/comments-ui/src/components/Comment.js index f1e545a500..4e3a550513 100644 --- a/apps/comments-ui/src/components/Comment.js +++ b/apps/comments-ui/src/components/Comment.js @@ -27,6 +27,9 @@ const Comment = ({updateIsEditing = null, isEditing, ...props}) => { let comment = props.comment; useEffect(() => { + // This doesn't work, and should receive an update. + // When one Comment shows reply, while a different Form hides the reply form at the same time, the global + // 'isEditing' is unreliable. We should use a counter of total open forms instead of a boolean. updateIsEditing?.(isInReplyMode || isInEditMode); }, [updateIsEditing, isInReplyMode, isInEditMode]); const toggleEditMode = () => { @@ -99,7 +102,7 @@ const Comment = ({updateIsEditing = null, isEditing, ...props}) => {

{notPublishedMessage}

- +
:
@@ -122,8 +125,8 @@ const Comment = ({updateIsEditing = null, isEditing, ...props}) => { {!isNotPublished && (
{!isNotPublished && } - {!isNotPublished && (canReply && (isNotPublished || !props.parent) && )} - {!isNotPublished && } + {!isNotPublished && (canReply && (isNotPublished || !props.parent) && )} + {!isNotPublished && }
)} diff --git a/apps/comments-ui/src/components/CommentsBox.js b/apps/comments-ui/src/components/CommentsBox.js index becf4b4944..b49e9df97f 100644 --- a/apps/comments-ui/src/components/CommentsBox.js +++ b/apps/comments-ui/src/components/CommentsBox.js @@ -50,6 +50,7 @@ const CommentsBoxTitle = ({title, showCount, count}) => { }; const CommentsBoxContent = (props) => { + // @todo: This doesn't work and should get replaced with a counter of total open forms. If total open forms > 0, don't show the main form. const [isEditing, setIsEditing] = useState(false); const {pagination, member, comments, commentCount, commentsEnabled, title, showCount} = useContext(AppContext); diff --git a/apps/comments-ui/src/components/Form.js b/apps/comments-ui/src/components/Form.js index 2f36d0a273..064a4e4586 100644 --- a/apps/comments-ui/src/components/Form.js +++ b/apps/comments-ui/src/components/Form.js @@ -8,6 +8,9 @@ import {isMobile} from '../utils/helpers'; // import {formatRelativeTime} from '../utils/helpers'; import {ReactComponent as SpinnerIcon} from '../images/icons/spinner.svg'; import {ReactComponent as EditIcon} from '../images/icons/edit.svg'; +import {GlobalEventBus} from '../utils/event-bus'; + +let formId = 0; const Form = (props) => { const {member, postId, dispatchAction, avatarSaturation} = useContext(AppContext); @@ -55,7 +58,7 @@ const Form = (props) => { }); const getScrollToPosition = () => { - let yOffset = -100; + let yOffset = 0; const element = formEl.current; // Because we are working in an iframe, we need to resolve the position inside this iframe to the position in the top window @@ -83,7 +86,45 @@ const Form = (props) => { return y; }; + // Generate an unique ID so we can exclude events that we send ourselve + const [uniqueId] = useState(() => { + formId += 1; + return 'form-' + formId; + }); + + const onOtherFormFocus = useCallback(() => { + // A different form got focus. Should we close this form now? + if ((props.isReply && editor?.isEmpty) || (props.isEdit && editor?.getHTML() === props.comment.html)) { + if (props.close) { + props.close(); + } + } + }, [editor, props]); + + useEffect(() => { + // Send event before attaching the listeer + GlobalEventBus.addListener(uniqueId, 'form-focus', onOtherFormFocus); + + return () => { + GlobalEventBus.removeListener(uniqueId); + }; + }, [onOtherFormFocus, uniqueId]); + + useEffect(() => { + // When opening a reply or edit form, try to close other forms that are open and can get closed + if (props.isReply || props.isEdit) { + // Send a form-focus event, but exclude ourself (uniqueId) + GlobalEventBus.sendEvent('form-focus', {}, uniqueId); + } + }, [props.isReply, props.isEdit, uniqueId]); + const onFormFocus = useCallback(() => { + // When focusing the main form, try to close other forms that are open and can get closed + if (!props.isReply && !props.isEdit) { + // Send a form-focus event, but exclude ourself (uniqueId) + GlobalEventBus.sendEvent('form-focus', {}, uniqueId); + } + // Send an event around and try to close other forms that are open and can get closed if (!memberName && !props.isEdit) { setPreventClosing(true); editor.commands.blur(); @@ -103,7 +144,7 @@ const Form = (props) => { } else { setFormOpen(true); } - }, [editor, dispatchAction, memberName, props]); + }, [editor, dispatchAction, memberName, props, uniqueId]); // Set the cursor position at the end of the form, instead of the beginning (= when using autofocus) useEffect(() => { @@ -116,12 +157,26 @@ const Form = (props) => { // Scroll to view if it's a reply if (props.isReply) { timer = setTimeout(() => { - window.scrollTo({ - top: getScrollToPosition(), - left: 0, - behavior: 'smooth' - }); - }, 100); + // Is the form already in view? + const formHeight = 100; + const yMin = getScrollToPosition(); + const yMax = yMin + formHeight; + + const viewportHeight = window.innerHeight; + const viewPortYMin = window.scrollY; + const viewPortYMax = viewPortYMin + viewportHeight; + + if (yMin < viewPortYMin || yMax > viewPortYMax) { + // Center the form in the viewport + const yCenter = (yMin + yMax) / 2; + + window.scrollTo({ + top: yCenter - viewportHeight / 2, + left: 0, + behavior: 'smooth' + }); + } + }, 50); } // Focus editor + jump to end @@ -150,7 +205,7 @@ const Form = (props) => { clearTimeout(timer); } }; - }, [editor, props]); + }, [editor, props.isReply, props.isEdit]); const submitForm = useCallback(async () => { if (editor.isEmpty) { @@ -226,11 +281,6 @@ const Form = (props) => { editor.on('blur', () => { if (editor?.isEmpty) { setFormOpen(false); - if (props.isReply && props.close && !preventClosing) { - // TODO: we cannot toggle the form when this happens, because when the member doesn't have a name we'll always loose focus to input the name... - // Need to find a different way for this behaviour - props.close(); - } } }); diff --git a/apps/comments-ui/src/components/More.js b/apps/comments-ui/src/components/More.js index ad505ee02d..31d3cfcc00 100644 --- a/apps/comments-ui/src/components/More.js +++ b/apps/comments-ui/src/components/More.js @@ -30,7 +30,7 @@ const More = (props) => { return (
{show ? : null} - {isContextMenuOpen ? : null} + {isContextMenuOpen ? : null}
); }; diff --git a/apps/comments-ui/src/components/Reply.js b/apps/comments-ui/src/components/Reply.js index 4d688e30ff..e8bf7ae421 100644 --- a/apps/comments-ui/src/components/Reply.js +++ b/apps/comments-ui/src/components/Reply.js @@ -5,13 +5,8 @@ import {ReactComponent as ReplyIcon} from '../images/icons/reply.svg'; function Reply(props) { const {member} = useContext(AppContext); - const preventDefault = (event) => { - // We need to prevent blurring the input field when clicking the reply button (that could cause blur + focus again because mousedown is causing the input blur, then onclick focusses again) - event.preventDefault(); - }; - return member ? - () : null; } diff --git a/apps/comments-ui/src/components/modals/AuthorContextMenu.js b/apps/comments-ui/src/components/modals/AuthorContextMenu.js index 803e0eb9ca..c6be7222a6 100644 --- a/apps/comments-ui/src/components/modals/AuthorContextMenu.js +++ b/apps/comments-ui/src/components/modals/AuthorContextMenu.js @@ -11,7 +11,7 @@ const AuthorContextMenu = (props) => { return (
-