diff --git a/frontend/src/components/review-list-view/review-comment-dialog.js b/frontend/src/components/review-list-view/review-comment-dialog.js index f673a7aca7..4cca4745e3 100644 --- a/frontend/src/components/review-list-view/review-comment-dialog.js +++ b/frontend/src/components/review-list-view/review-comment-dialog.js @@ -3,13 +3,14 @@ import PropTypes from 'prop-types'; import { Button } from 'reactstrap'; import { seafileAPI } from '../../utils/seafile-api'; import { reviewID, gettext } from '../../utils/constants'; +import { processor } from '../../utils/seafile-markdown2html'; import '../../css/review-comment-dialog.css'; const commentDialogPropTypes = { onCommentAdded: PropTypes.func.isRequired, toggleCommentDialog: PropTypes.func.isRequired, - selectedText: PropTypes.string, + quote: PropTypes.string, newIndex: PropTypes.number, oldIndex: PropTypes.number, }; @@ -21,6 +22,7 @@ class ReviewCommentDialog extends React.Component { this.state = { comment: '', userName: '', + quote: '', }; } @@ -42,9 +44,9 @@ class ReviewCommentDialog extends React.Component { submitComment = () => { let comment = this.state.comment.trim(); if (comment.length > 0) { - if (this.props.selectedText.length > 0) { + if (this.props.quote.length > 0) { let detail = { - selectedText: this.props.selectedText.slice(0, 10), + quote: this.props.quote, newIndex: this.props.newIndex, oldIndex: this.props.oldIndex }; @@ -64,12 +66,15 @@ class ReviewCommentDialog extends React.Component { } } - setQuoteText = (text) => { - if (text.length > 0) { - this.setState({ - comment: text - }); - } + setQuoteText = (mdQuote) => { + processor.process(mdQuote).then( + (result) => { + let quote = String(result); + this.setState({ + quote: quote + }); + } + ); } componentWillMount() { @@ -77,12 +82,12 @@ class ReviewCommentDialog extends React.Component { } componentDidMount() { - this.setQuoteText(this.props.selectedText); + this.setQuoteText(this.props.quote); } componentWillReceiveProps(nextProps) { - if (this.props.selectedText !== nextProps.selectedText) { - this.setQuoteText(nextProps.selectedText); + if (this.props.quote !== nextProps.quote) { + this.setQuoteText(nextProps.quote); } } @@ -90,6 +95,9 @@ class ReviewCommentDialog extends React.Component { return (
{this.state.userName}
+
+
+
diff --git a/frontend/src/components/review-list-view/review-comments.js b/frontend/src/components/review-list-view/review-comments.js index 8cd5eb92c7..ea2e4ed25c 100644 --- a/frontend/src/components/review-list-view/review-comments.js +++ b/frontend/src/components/review-list-view/review-comments.js @@ -132,8 +132,8 @@ class ReviewComments extends React.Component { }); }; - scrollToQuote = (newIndex, oldIndex, selectedText) => { - this.props.scrollToQuote(newIndex, oldIndex, selectedText); + scrollToQuote = (newIndex, oldIndex, quote) => { + this.props.scrollToQuote(newIndex, oldIndex, quote); this.setState({ comment: '' }); @@ -227,7 +227,8 @@ class CommentItem extends React.Component { super(props); this.state = { dropdownOpen: false, - html: '', + comment: '', + quote: '', }; } @@ -237,66 +238,74 @@ class CommentItem extends React.Component { }); } - convertComment = (mdFile) => { - processor.process(mdFile).then( + convertComment = (item) => { + processor.process(item.comment).then( (result) => { - let html = String(result); + let comment = String(result); this.setState({ - html: html + comment: comment + }); + } + ); + processor.process(item.quote).then( + (result) => { + let quote = String(result); + this.setState({ + quote: quote }); } ); } scrollToQuote = () => { - this.props.scrollToQuote(this.props.item.newIndex, this.props.item.oldIndex, - this.props.item.selectedText); + const item = this.props.item; + this.props.scrollToQuote(item.newIndex, item.oldIndex, item.quote); } componentWillMount() { - this.convertComment(this.props.item.comment); + this.convertComment(this.props.item); } componentWillReceiveProps(nextProps) { - this.convertComment(nextProps.item.comment); + this.convertComment(nextProps.item); } render() { - if (this.props.item.resolved && !this.props.showResolvedComment) { + const item = this.props.item; + if (item.resolved && !this.props.showResolvedComment) { return null; } return ( -
  • +
  • - +
    -
    {this.props.item.name}
    -
    {this.props.item.time}
    +
    {item.name}
    +
    {item.time}
    - { !this.props.item.resolved && + { !item.resolved && - { (this.props.item.userEmail === this.props.accountInfo.email) && + { (item.userEmail === this.props.accountInfo.email) && {gettext('Delete')}} + className="delete-comment" id={item.id}>{gettext('Delete')}} {gettext('Mark as resolved')} + className="seafile-comment-resolved" id={item.id}>{gettext('Mark as resolved')} }
    - { (this.props.item.newIndex >= -1 && this.props.item.oldIndex >= -1)? -
    - : -
    + { (item.newIndex >= -1 && item.oldIndex >= -1) && +
    +
    +
    } +
  • ); } diff --git a/frontend/src/css/review-comment-dialog.css b/frontend/src/css/review-comment-dialog.css index 4140bed239..3b291fd0a1 100644 --- a/frontend/src/css/review-comment-dialog.css +++ b/frontend/src/css/review-comment-dialog.css @@ -3,7 +3,7 @@ position: absolute; top: 30%; right: 0; - padding: 10px; + padding: 15px; background-color: #fafafa; border: 1px solid rgba(0,0,0,.2); border-radius: .3rem; @@ -24,9 +24,14 @@ } .review-comment-dialog textarea { width: 100%; - min-height: 200px; + min-height: 100px; max-height: 300px; } .review-comment-dialog .button-group .btn { margin-right: 10px; +} +.review-comment-dialog .review-comment-dialog-quote { + margin-top: 10px; + max-height: 4rem; + overflow: hidden; } \ No newline at end of file diff --git a/frontend/src/css/review-comments.css b/frontend/src/css/review-comments.css index 01ff6080a4..ca3a34025e 100644 --- a/frontend/src/css/review-comments.css +++ b/frontend/src/css/review-comments.css @@ -96,10 +96,11 @@ .seafile-comment-item .seafile-comment-content td { border: 1px solid #333; } -.seafile-comment-item .seafile-comment-content blockquote { +.seafile-comment-item blockquote { word-wrap: break-word; overflow: hidden; margin-right: 10px; + cursor: pointer; } .seafile-comment-row-resize { height: 5px; diff --git a/frontend/src/draft-review.js b/frontend/src/draft-review.js index a70d427c80..6f5a6611a1 100644 --- a/frontend/src/draft-review.js +++ b/frontend/src/draft-review.js @@ -10,7 +10,6 @@ import { siteRoot, gettext, reviewID, draftOriginFilePath, draftFilePath, draftO import { seafileAPI } from './utils/seafile-api'; import axios from 'axios'; import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer'; -import { htmlSerializer } from '@seafile/seafile-editor/dist/utils/serialize-html'; import { serialize } from '@seafile/seafile-editor/dist/utils/slate2markdown/serialize'; import Loading from './components/loading'; import toaster from './components/toast'; @@ -22,7 +21,7 @@ import { findRange } from '@seafile/slate-react'; import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap'; import classnames from 'classnames'; import HistoryList from './pages/review/history-list'; -import { Document, Block, Value } from 'slate'; +import { Value } from 'slate'; import './assets/css/fa-solid.css'; import './assets/css/fa-regular.css'; @@ -55,7 +54,7 @@ class DraftReview extends React.Component { changedNodes: [], isShowCommentDialog: false, }; - this.selectedText = ''; + this.quote = ''; this.newIndex = null; this.oldIndex = null; this.changeIndex = -1; @@ -246,34 +245,8 @@ class DraftReview extends React.Component { } } - getSelectedText = () => { - const native = window.getSelection(); - const nativeRange = native.getRangeAt(0); - let contents = nativeRange.cloneContents(); - const div = window.document.createElement('div'); - div.appendChild(contents); - div.setAttribute('contenteditable', true); - let fragmentDOM = htmlSerializer.deserialize(div.innerHTML).document; - let nodes = []; - fragmentDOM.nodes.map(node => { - let newNode = Block.create({ - data: node.data, - key: node.key, - nodes: node.nodes, - type: 'blockquote' - }); - nodes.push(newNode); - }); - let newDocument = Document.create({ - nodes: nodes - }); - let newValue = Value.create({ - document: newDocument - }); - this.selectedText = serialize(newValue); - } - - getIndexs = () => { + getQuote = () => { + this.quote = ''; let range = this.setBtnPosition(); if (!range) { return; @@ -306,6 +279,11 @@ class DraftReview extends React.Component { range = range.moveFocusTo(nextText.key, 0); } } + let fragment = document.getFragmentAtRange(range); + let newValue = Value.create({ + document: fragment + }); + this.quote = serialize(newValue.toJSON()); let blockPath = document.createSelection(range).anchor.path.slice(0, 1); let node = document.getNode(blockPath); this.newIndex = node.data.get('new_index'); @@ -314,8 +292,10 @@ class DraftReview extends React.Component { addComment = (e) => { e.stopPropagation(); - this.getSelectedText(); - this.getIndexs(); + this.getQuote(); + if (!this.quote) { + return; + } this.setState({ isShowCommentDialog: true }); @@ -341,7 +321,7 @@ class DraftReview extends React.Component { return scroller; } - scrollToQuote = (newIndex, oldIndex, selectedText) => { + scrollToQuote = (newIndex, oldIndex, quote) => { const nodes = this.refs.diffViewer.value.document.nodes; let key; nodes.map((node) => { @@ -351,7 +331,7 @@ class DraftReview extends React.Component { }); if (typeof(key) !== 'string') { nodes.map((node) => { - if (node.text.indexOf(selectedText) > 0) { + if (node.text.indexOf(quote) > 0) { key = node.key; } }); @@ -633,7 +613,7 @@ class DraftReview extends React.Component {