mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-03 07:55:36 +00:00
change selection (#2587)
This commit is contained in:
@@ -67,9 +67,8 @@ class ReviewCommentDialog extends React.Component {
|
|||||||
|
|
||||||
setQuoteText = (text) => {
|
setQuoteText = (text) => {
|
||||||
if (text.length > 0) {
|
if (text.length > 0) {
|
||||||
let comment = '> ' + text;
|
|
||||||
this.setState({
|
this.setState({
|
||||||
comment: comment
|
comment: text
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,10 +12,7 @@ import '../../css/review-comments.css';
|
|||||||
const commentPropTypes = {
|
const commentPropTypes = {
|
||||||
getCommentsNumber: PropTypes.func.isRequired,
|
getCommentsNumber: PropTypes.func.isRequired,
|
||||||
inResizing: PropTypes.bool.isRequired,
|
inResizing: PropTypes.bool.isRequired,
|
||||||
commentsNumber: PropTypes.number.isRequired,
|
commentsNumber: PropTypes.number,
|
||||||
selectedText: PropTypes.string,
|
|
||||||
newIndex: PropTypes.number,
|
|
||||||
oldIndex: PropTypes.number,
|
|
||||||
scrollToQuote: PropTypes.func.isRequired
|
scrollToQuote: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,24 +66,10 @@ class ReviewComments extends React.Component {
|
|||||||
submitComment = () => {
|
submitComment = () => {
|
||||||
let comment = this.state.comment.trim();
|
let comment = this.state.comment.trim();
|
||||||
if (comment.length > 0) {
|
if (comment.length > 0) {
|
||||||
if (this.props.selectedText.length > 0) {
|
seafileAPI.addReviewComment(reviewID, comment).then((response) => {
|
||||||
let detail = {
|
this.listComments(true);
|
||||||
selectedText: this.props.selectedText.slice(0, 10),
|
this.props.getCommentsNumber();
|
||||||
newIndex: this.props.newIndex,
|
});
|
||||||
oldIndex: this.props.oldIndex
|
|
||||||
};
|
|
||||||
let detailJSON = JSON.stringify(detail);
|
|
||||||
seafileAPI.addReviewComment(reviewID, comment, detailJSON).then((response) => {
|
|
||||||
this.listComments(true);
|
|
||||||
this.props.getCommentsNumber();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
seafileAPI.addReviewComment(reviewID, comment).then((response) => {
|
|
||||||
this.listComments(true);
|
|
||||||
this.props.getCommentsNumber();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setState({
|
this.setState({
|
||||||
comment: ''
|
comment: ''
|
||||||
});
|
});
|
||||||
@@ -148,15 +131,6 @@ class ReviewComments extends React.Component {
|
|||||||
commentFooterHeight: rate
|
commentFooterHeight: rate
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
setQuoteText = (text) => {
|
|
||||||
if (text.length > 0) {
|
|
||||||
let comment = '> ' + text;
|
|
||||||
this.setState({
|
|
||||||
comment: comment
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollToQuote = (newIndex, oldIndex, selectedText) => {
|
scrollToQuote = (newIndex, oldIndex, selectedText) => {
|
||||||
this.props.scrollToQuote(newIndex, oldIndex, selectedText);
|
this.props.scrollToQuote(newIndex, oldIndex, selectedText);
|
||||||
@@ -170,13 +144,9 @@ class ReviewComments extends React.Component {
|
|||||||
this.listComments();
|
this.listComments();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.setQuoteText(this.props.selectedText);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (this.props.selectedText !== nextProps.selectedText) {
|
if (this.props.commentsNumber !== nextProps.commentsNumber) {
|
||||||
this.setQuoteText(nextProps.selectedText);
|
this.listComments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,12 +26,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .cur-view-container .cur-view-content-commenton {
|
|
||||||
overflow: auto;
|
|
||||||
width: 70%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main .cur-view-container .seafile-comment {
|
.main .cur-view-container .seafile-comment {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -177,9 +171,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
.main .cur-view-container .cur-view-content-commenton {
|
|
||||||
width: 20% !important;
|
|
||||||
}
|
|
||||||
.main .cur-view-right-part {
|
.main .cur-view-right-part {
|
||||||
width: 80% !important;
|
width: 80% !important;
|
||||||
}
|
}
|
||||||
|
@@ -10,16 +10,20 @@ import { siteRoot, gettext, reviewID, draftOriginFilePath, draftFilePath, draftO
|
|||||||
import { seafileAPI } from './utils/seafile-api';
|
import { seafileAPI } from './utils/seafile-api';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer';
|
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 Loading from './components/loading';
|
||||||
import Toast from './components/toast';
|
import Toast from './components/toast';
|
||||||
import ReviewComments from './components/review-list-view/review-comments';
|
import ReviewComments from './components/review-list-view/review-comments';
|
||||||
import ReviewCommentDialog from './components/review-list-view/review-comment-dialog.js'
|
import ReviewCommentDialog from './components/review-list-view/review-comment-dialog.js';
|
||||||
import { Tooltip } from 'reactstrap';
|
import { Tooltip } from 'reactstrap';
|
||||||
import AddReviewerDialog from './components/dialog/add-reviewer-dialog.js';
|
import AddReviewerDialog from './components/dialog/add-reviewer-dialog.js';
|
||||||
import { findRange } from '@seafile/slate-react';
|
import { findRange } from '@seafile/slate-react';
|
||||||
import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
|
import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import HistoryList from './pages/review/history-list';
|
import HistoryList from './pages/review/history-list';
|
||||||
|
import Plain from 'slate-plain-serializer';
|
||||||
|
import { Document, Block, Value } from 'slate';
|
||||||
|
|
||||||
import 'seafile-ui';
|
import 'seafile-ui';
|
||||||
import './assets/css/fa-solid.css';
|
import './assets/css/fa-solid.css';
|
||||||
@@ -41,7 +45,6 @@ class DraftReview extends React.Component {
|
|||||||
reviewStatus: opStatus,
|
reviewStatus: opStatus,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
commentsNumber: null,
|
commentsNumber: null,
|
||||||
isShowComments: false,
|
|
||||||
inResizing: false,
|
inResizing: false,
|
||||||
commentWidth: 30,
|
commentWidth: 30,
|
||||||
isShowDiff: true,
|
isShowDiff: true,
|
||||||
@@ -250,8 +253,36 @@ class DraftReview extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addComment = (e) => {
|
getSelectedText = () => {
|
||||||
e.stopPropagation();
|
const value = this.refs.diffViewer.value;
|
||||||
|
const native = window.getSelection();
|
||||||
|
const { fragment } = value;
|
||||||
|
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 = [];
|
||||||
|
for (let i = 0; i < fragmentDOM.nodes.toArray().length; i++) {
|
||||||
|
let node = Block.create({
|
||||||
|
data: fragmentDOM.nodes.toArray()[i].data,
|
||||||
|
key: fragmentDOM.nodes.toArray()[i].key,
|
||||||
|
nodes: fragmentDOM.nodes.toArray()[i].nodes,
|
||||||
|
type: 'blockquote'
|
||||||
|
});
|
||||||
|
nodes[i] = node;
|
||||||
|
}
|
||||||
|
let newDocument = Document.create({
|
||||||
|
nodes: nodes
|
||||||
|
});
|
||||||
|
let newValue = Value.create({
|
||||||
|
document: newDocument
|
||||||
|
});
|
||||||
|
this.selectedText = serialize(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndexs = () => {
|
||||||
let range = this.setBtnPosition();
|
let range = this.setBtnPosition();
|
||||||
if (!range) {
|
if (!range) {
|
||||||
return;
|
return;
|
||||||
@@ -286,9 +317,14 @@ class DraftReview extends React.Component {
|
|||||||
}
|
}
|
||||||
let blockPath = document.createSelection(range).anchor.path.slice(0, 1);
|
let blockPath = document.createSelection(range).anchor.path.slice(0, 1);
|
||||||
let node = document.getNode(blockPath);
|
let node = document.getNode(blockPath);
|
||||||
this.selectedText = window.getSelection().toString().trim();
|
|
||||||
this.newIndex = node.data.get('new_index');
|
this.newIndex = node.data.get('new_index');
|
||||||
this.oldIndex = node.data.get('old_index');
|
this.oldIndex = node.data.get('old_index');
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment = (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.getSelectedText();
|
||||||
|
this.getIndexs();
|
||||||
this.setState({
|
this.setState({
|
||||||
isShowCommentDialog: true
|
isShowCommentDialog: true
|
||||||
});
|
});
|
||||||
@@ -503,7 +539,7 @@ class DraftReview extends React.Component {
|
|||||||
<div className="cur-view-container content-container"
|
<div className="cur-view-container content-container"
|
||||||
onMouseMove={onResizeMove} onMouseUp={this.onResizeMouseUp} ref="comment">
|
onMouseMove={onResizeMove} onMouseUp={this.onResizeMouseUp} ref="comment">
|
||||||
<div style={{width:(100-this.state.commentWidth)+'%'}}
|
<div style={{width:(100-this.state.commentWidth)+'%'}}
|
||||||
className={!this.state.isShowComments ? 'cur-view-content' : 'cur-view-content cur-view-content-commenton'} ref="viewContent">
|
className='cur-view-content' ref="viewContent">
|
||||||
{this.state.isLoading ?
|
{this.state.isLoading ?
|
||||||
<div className="markdown-viewer-render-content article">
|
<div className="markdown-viewer-render-content article">
|
||||||
<Loading />
|
<Loading />
|
||||||
@@ -537,79 +573,71 @@ class DraftReview extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{ !this.state.isShowComments &&
|
<div className="cur-view-right-part" style={{width:(this.state.commentWidth)+'%'}}>
|
||||||
<div className="cur-view-right-part" style={{width:(this.state.commentWidth)+'%'}}>
|
<div className="seafile-comment-resize" onMouseDown={this.onResizeMouseDown}></div>
|
||||||
<div className="seafile-comment-resize" onMouseDown={this.onResizeMouseDown}></div>
|
<div className="review-side-panel">
|
||||||
<div className="review-side-panel">
|
<Nav tabs className="review-side-panel-nav">
|
||||||
<Nav tabs className="review-side-panel-nav">
|
<NavItem className="nav-item">
|
||||||
|
<NavLink
|
||||||
|
className={classnames({ active: this.state.activeTab === 'reviewInfo' })}
|
||||||
|
onClick={() => { this.tabItemClick('reviewInfo');}}
|
||||||
|
>
|
||||||
|
<i className="fas fa-info-circle"></i>
|
||||||
|
</NavLink>
|
||||||
|
</NavItem>
|
||||||
|
<NavItem className="nav-item">
|
||||||
|
<NavLink
|
||||||
|
className={classnames({ active: this.state.activeTab === 'comments' })}
|
||||||
|
onClick={() => { this.tabItemClick('comments');}}
|
||||||
|
>
|
||||||
|
<i className="fa fa-comments"></i>
|
||||||
|
{ this.state.commentsNumber > 0 &&
|
||||||
|
<div className='comments-number'>{this.state.commentsNumber}</div>}
|
||||||
|
</NavLink>
|
||||||
|
</NavItem>
|
||||||
|
{ this.state.reviewStatus == 'finished' ? '':
|
||||||
<NavItem className="nav-item">
|
<NavItem className="nav-item">
|
||||||
<NavLink
|
<NavLink
|
||||||
className={classnames({ active: this.state.activeTab === 'reviewInfo' })}
|
className={classnames({ active: this.state.activeTab === 'history' })}
|
||||||
onClick={() => { this.tabItemClick('reviewInfo');}}
|
onClick={() => { this.tabItemClick('history');}}
|
||||||
>
|
>
|
||||||
<i className="fas fa-info-circle"></i>
|
<i className="fas fa-history"></i>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<NavItem className="nav-item">
|
}
|
||||||
<NavLink
|
</Nav>
|
||||||
className={classnames({ active: this.state.activeTab === 'comments' })}
|
<TabContent activeTab={this.state.activeTab}>
|
||||||
onClick={() => { this.tabItemClick('comments');}}
|
<TabPane tabId="reviewInfo">
|
||||||
>
|
<div className="review-side-panel-body">
|
||||||
<i className="fa fa-comments"></i>
|
<SidePanelReviewers
|
||||||
{ this.state.commentsNumber > 0 &&
|
reviewers={this.state.reviewers}
|
||||||
<div className='comments-number'>{this.state.commentsNumber}</div>}
|
toggleAddReviewerDialog={this.toggleAddReviewerDialog}/>
|
||||||
</NavLink>
|
<SidePanelAuthor/>
|
||||||
</NavItem>
|
{ this.state.isShowDiff &&
|
||||||
{ this.state.reviewStatus == 'finished' ? '':
|
<SidePanelChanges
|
||||||
<NavItem className="nav-item">
|
changedNumber={this.state.changedNodes.length}
|
||||||
<NavLink
|
scrollToChangedNode={this.scrollToChangedNode}/>
|
||||||
className={classnames({ active: this.state.activeTab === 'history' })}
|
|
||||||
onClick={() => { this.tabItemClick('history');}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-history"></i>
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
}
|
|
||||||
</Nav>
|
|
||||||
<TabContent activeTab={this.state.activeTab}>
|
|
||||||
<TabPane tabId="reviewInfo">
|
|
||||||
<div className="review-side-panel-body">
|
|
||||||
<SidePanelReviewers
|
|
||||||
reviewers={this.state.reviewers}
|
|
||||||
toggleAddReviewerDialog={this.toggleAddReviewerDialog}/>
|
|
||||||
<SidePanelAuthor/>
|
|
||||||
{ this.state.isShowDiff &&
|
|
||||||
<SidePanelChanges
|
|
||||||
changedNumber={this.state.changedNodes.length}
|
|
||||||
scrollToChangedNode={this.scrollToChangedNode}/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</TabPane>
|
|
||||||
<TabPane tabId="comments" className="comments">
|
|
||||||
{this.state.commentsNumber &&
|
|
||||||
<ReviewComments
|
|
||||||
scrollToQuote={this.scrollToQuote}
|
|
||||||
getCommentsNumber={this.getCommentsNumber}
|
|
||||||
commentsNumber={this.state.commentsNumber}
|
|
||||||
inResizing={this.state.inResizing}
|
|
||||||
selectedText={this.selectedText}
|
|
||||||
newIndex={this.newIndex}
|
|
||||||
oldIndex={this.oldIndex}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tabId="comments" className="comments">
|
||||||
|
<ReviewComments
|
||||||
|
scrollToQuote={this.scrollToQuote}
|
||||||
|
getCommentsNumber={this.getCommentsNumber}
|
||||||
|
commentsNumber={this.state.commentsNumber}
|
||||||
|
inResizing={this.state.inResizing}
|
||||||
|
/>
|
||||||
|
</TabPane>
|
||||||
|
{ this.state.reviewStatus == 'finished'? '':
|
||||||
|
<TabPane tabId="history" className="history">
|
||||||
|
<HistoryList setDiffViewerContent={this.setDiffViewerContent}
|
||||||
|
historyList={this.state.historyList}
|
||||||
|
totalReversionCount={this.state.totalReversionCount}/>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
}
|
||||||
{ this.state.reviewStatus == 'finished'? '':
|
</TabContent>
|
||||||
<TabPane tabId="history" className="history">
|
|
||||||
<HistoryList setDiffViewerContent={this.setDiffViewerContent}
|
|
||||||
historyList={this.state.historyList}
|
|
||||||
totalReversionCount={this.state.totalReversionCount}/>
|
|
||||||
</TabPane>
|
|
||||||
}
|
|
||||||
</TabContent>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ this.state.showReviewerDialog &&
|
{ this.state.showReviewerDialog &&
|
||||||
|
Reference in New Issue
Block a user