mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 02:42:47 +00:00
@@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext } from '../../utils/constants';
|
import { gettext } from '../../utils/constants';
|
||||||
import { IconButton, ButtonGroup, CollabUsersButton } from '@seafile/seafile-editor/dist/components/topbarcomponent/editorToolBar';
|
import { IconButton, ButtonGroup, CollabUsersButton } from '@seafile/seafile-editor/dist/components/topbarcomponent/editorToolBar';
|
||||||
|
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Tooltip } from 'reactstrap';
|
||||||
import FileInfo from '@seafile/seafile-editor/dist/components/topbarcomponent/file-info';
|
import FileInfo from '@seafile/seafile-editor/dist/components/topbarcomponent/file-info';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
@@ -11,8 +12,6 @@ const propTypes = {
|
|||||||
editorUtilities: PropTypes.object.isRequired,
|
editorUtilities: PropTypes.object.isRequired,
|
||||||
collabUsers: PropTypes.array.isRequired,
|
collabUsers: PropTypes.array.isRequired,
|
||||||
fileInfo: PropTypes.object.isRequired,
|
fileInfo: PropTypes.object.isRequired,
|
||||||
fileTagList: PropTypes.array.isRequired,
|
|
||||||
relatedFiles: PropTypes.array.isRequired,
|
|
||||||
toggleShareLinkDialog: PropTypes.func.isRequired,
|
toggleShareLinkDialog: PropTypes.func.isRequired,
|
||||||
onEdit: PropTypes.func.isRequired,
|
onEdit: PropTypes.func.isRequired,
|
||||||
toggleNewDraft: PropTypes.func.isRequired,
|
toggleNewDraft: PropTypes.func.isRequired,
|
||||||
@@ -23,114 +22,137 @@ const propTypes = {
|
|||||||
toggleHistory: PropTypes.func.isRequired,
|
toggleHistory: PropTypes.func.isRequired,
|
||||||
commentsNumber: PropTypes.number.isRequired,
|
commentsNumber: PropTypes.number.isRequired,
|
||||||
toggleCommentList: PropTypes.func.isRequired,
|
toggleCommentList: PropTypes.func.isRequired,
|
||||||
|
editorMode: PropTypes.string.isRequired,
|
||||||
|
readOnly: PropTypes.bool.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MoreMenuPropTypes = {
|
||||||
|
readOnly: PropTypes.bool.isRequired,
|
||||||
|
openDialogs: PropTypes.func.isRequired,
|
||||||
|
onEdit: PropTypes.func.isRequired,
|
||||||
|
editorMode: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
class MoreMenu extends React.PureComponent {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
tooltipOpen: false,
|
||||||
|
dropdownOpen:false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltipToggle = () => {
|
||||||
|
this.setState({ tooltipOpen: !this.state.tooltipOpen });
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdownToggle = () => {
|
||||||
|
this.setState({ dropdownOpen:!this.state.dropdownOpen });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const editorMode = this.props.editorMode;
|
||||||
|
return (
|
||||||
|
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.dropdownToggle} direction="down" className="mx-lg-1">
|
||||||
|
<DropdownToggle id="moreButton">
|
||||||
|
<i className="fa fa-ellipsis-v"/>
|
||||||
|
<Tooltip toggle={this.tooltipToggle} delay={{show: 0, hide: 0}} target="moreButton" placement='bottom' isOpen={this.state.tooltipOpen}>{gettext('More')}
|
||||||
|
</Tooltip>
|
||||||
|
</DropdownToggle>
|
||||||
|
<DropdownMenu className="drop-list" right={true}>
|
||||||
|
{(!this.props.readOnly && editorMode === 'rich') &&
|
||||||
|
<DropdownItem onMouseDown={this.props.onEdit.bind(this, 'plain')}>{gettext('Switch to plain text editor')}</DropdownItem>}
|
||||||
|
{(!this.props.readOnly && editorMode === 'plain') &&
|
||||||
|
<DropdownItem onMouseDown={this.props.onEdit.bind(this, 'rich')}>{gettext('Switch to rich text editor')}</DropdownItem>}
|
||||||
|
{(this.props.openDialogs && editorMode === 'rich') &&
|
||||||
|
<DropdownItem onMouseDown={this.props.openDialogs.bind(this, 'help')}>{gettext('Help')}</DropdownItem>
|
||||||
|
}
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MoreMenu.propTypes = MoreMenuPropTypes;
|
||||||
|
|
||||||
|
|
||||||
class MarkdownViewerToolbar extends React.Component {
|
class MarkdownViewerToolbar extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFirstToolbar() {
|
|
||||||
return (
|
|
||||||
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
|
||||||
<FileInfo toggleStar={this.props.toggleStar} editorUtilities={this.props.editorUtilities}
|
|
||||||
fileInfo={this.props.fileInfo}/>
|
|
||||||
{(this.props.hasDraft && !this.props.isDraft) &&
|
|
||||||
<div className='seafile-btn-view-review'>
|
|
||||||
<div className='tag tag-green'>{gettext('This file is in draft stage.')}
|
|
||||||
<a className="ml-2" onMouseDown={this.props.editorUtilities.goDraftPage}>{gettext('View Draft')}</a></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div className="topbar-btn-container">
|
|
||||||
{ (!this.props.hasDraft && !this.props.isDraft && this.props.isDocs) &&
|
|
||||||
<button onMouseDown={this.props.toggleNewDraft} className="btn btn-success btn-new-draft">
|
|
||||||
{gettext('New Draft')}</button>
|
|
||||||
}
|
|
||||||
{this.props.collabUsers.length > 0 && <CollabUsersButton className={'collab-users-dropdown'}
|
|
||||||
users={this.props.collabUsers} id={'usersButton'} />}
|
|
||||||
<ButtonGroup>
|
|
||||||
<IconButton id={'shareBtn'} text={gettext('Share')} icon={'fa fa-share-alt'}
|
|
||||||
onMouseDown={this.props.toggleShareLinkDialog}/>
|
|
||||||
{
|
|
||||||
this.props.commentsNumber > 0 ?
|
|
||||||
<button className="btn btn-icon btn-secondary btn-active" id="commentsNumber" type="button"
|
|
||||||
data-active="false" onMouseDown={this.props.toggleCommentList}>
|
|
||||||
<i className="fa fa-comments"></i>{' '}<span>{this.props.commentsNumber}</span>
|
|
||||||
</button>
|
|
||||||
:
|
|
||||||
<IconButton id={'commentsNumber'} text={gettext('Comments')} icon={'fa fa-comments'} onMouseDown={this.props.toggleCommentList}/>
|
|
||||||
}
|
|
||||||
<IconButton text={gettext('Back to parent directory')} id={'parentDirectory'}
|
|
||||||
icon={'fa fa-folder-open'} onMouseDown={this.props.backToParentDirectory}/>
|
|
||||||
{
|
|
||||||
(!this.props.hasDraft && this.props.fileInfo.permission === 'rw')? <IconButton text={gettext('Edit')}
|
|
||||||
id={'editButton'} icon={'fa fa-edit'} onMouseDown={this.props.onEdit}/>: null
|
|
||||||
}
|
|
||||||
{
|
|
||||||
this.props.showFileHistory && <IconButton id={'historyButton'}
|
|
||||||
text={gettext('File History')} onMouseDown={this.props.toggleHistory} icon={'fa fa-history'}/>
|
|
||||||
}
|
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSecondToolbar() {
|
|
||||||
const { relatedFiles, fileTagList } = this.props;
|
|
||||||
const openDialogs = this.props.openDialogs;
|
|
||||||
let relatedFileString = '';
|
|
||||||
if (relatedFiles) {
|
|
||||||
const length = relatedFiles.length;
|
|
||||||
if (length === 1) relatedFileString = gettext('related file');
|
|
||||||
else if (length > 1) relatedFileString = gettext('related files');
|
|
||||||
}
|
|
||||||
return(
|
|
||||||
<div className="sf-md-viewer-topbar-second d-flex justify-content-center">
|
|
||||||
{(fileTagList) && (fileTagList.length > 0 ?
|
|
||||||
<ul className="sf-files-tags">
|
|
||||||
{
|
|
||||||
fileTagList.map((item, index=0) => {
|
|
||||||
return (
|
|
||||||
<li key={index} className='sf-files-tag'>
|
|
||||||
<span className="file-tag-icon" style={{backgroundColor: item.tag_color}}></span>
|
|
||||||
<span className="file-tag-name" title={item.tag_name}>{item.tag_name}</span>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<li className='sf-files-tag'><span className="file-tag-name"
|
|
||||||
onClick={openDialogs.bind(this, 'tags')}>{gettext('Edit')}</span></li>
|
|
||||||
</ul>
|
|
||||||
:
|
|
||||||
<span className="no-file-tag edit-related-file"
|
|
||||||
onClick={openDialogs.bind(this, 'tags')}>{gettext('No tags')}</span>
|
|
||||||
)}
|
|
||||||
{relatedFiles &&
|
|
||||||
<div className="sf-related-files-bar">
|
|
||||||
{relatedFiles.length === 0 ?
|
|
||||||
<span className="edit-related-file no-related-file"
|
|
||||||
onClick={openDialogs.bind(this, 'related_files')}>{gettext('No related files')}</span>:
|
|
||||||
<React.Fragment>
|
|
||||||
<a href="#sf-releted-files">{relatedFiles.length}{' '}{relatedFileString}</a>
|
|
||||||
<span className="edit-related-file" onClick={openDialogs.bind(this, 'related_files')}>
|
|
||||||
{gettext('Edit')}</span>
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
|
||||||
<div className="sf-md-viewer-topbar">
|
if (this.props.editorMode === 'rich') {
|
||||||
{this.renderFirstToolbar()}
|
return (
|
||||||
{this.renderSecondToolbar()}
|
<div className="sf-md-viewer-topbar">
|
||||||
</div>
|
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
||||||
);
|
<FileInfo toggleStar={this.props.toggleStar} editorUtilities={this.props.editorUtilities}
|
||||||
|
fileInfo={this.props.fileInfo}/>
|
||||||
|
{(this.props.hasDraft && !this.props.isDraft) &&
|
||||||
|
<div className='seafile-btn-view-review'>
|
||||||
|
<div className='tag tag-green'>{gettext('This file is in draft stage.')}
|
||||||
|
<a className="ml-2" onMouseDown={this.props.editorUtilities.goDraftPage}>{gettext('View Draft')}</a></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div className="topbar-btn-container">
|
||||||
|
{ (!this.props.hasDraft && !this.props.isDraft && this.props.isDocs) &&
|
||||||
|
<button onMouseDown={this.props.toggleNewDraft} className="btn btn-success btn-new-draft">
|
||||||
|
{gettext('New Draft')}</button>
|
||||||
|
}
|
||||||
|
{this.props.collabUsers.length > 0 && <CollabUsersButton className={'collab-users-dropdown'}
|
||||||
|
users={this.props.collabUsers} id={'usersButton'} />}
|
||||||
|
<ButtonGroup>
|
||||||
|
<IconButton id={'shareBtn'} text={gettext('Share')} icon={'fa fa-share-alt'}
|
||||||
|
onMouseDown={this.props.toggleShareLinkDialog}/>
|
||||||
|
{
|
||||||
|
this.props.commentsNumber > 0 ?
|
||||||
|
<button className="btn btn-icon btn-secondary btn-active" id="commentsNumber" type="button"
|
||||||
|
data-active="false" onMouseDown={this.props.toggleCommentList}>
|
||||||
|
<i className="fa fa-comments"></i>{' '}<span>{this.props.commentsNumber}</span>
|
||||||
|
</button>
|
||||||
|
:
|
||||||
|
<IconButton id={'commentsNumber'} text={gettext('Comments')} icon={'fa fa-comments'} onMouseDown={this.props.toggleCommentList}/>
|
||||||
|
}
|
||||||
|
<IconButton text={gettext('Back to parent directory')} id={'parentDirectory'}
|
||||||
|
icon={'fa fa-folder-open'} onMouseDown={this.props.backToParentDirectory}/>
|
||||||
|
{
|
||||||
|
this.props.showFileHistory && <IconButton id={'historyButton'}
|
||||||
|
text={gettext('File History')} onMouseDown={this.props.toggleHistory} icon={'fa fa-history'}/>
|
||||||
|
}
|
||||||
|
</ButtonGroup>
|
||||||
|
<MoreMenu
|
||||||
|
readOnly={this.props.readOnly}
|
||||||
|
openDialogs={this.props.openDialogs}
|
||||||
|
editorMode={this.props.editorMode}
|
||||||
|
onEdit={this.props.onEdit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (this.props.editorMode === 'plain') {
|
||||||
|
return (
|
||||||
|
<div className="sf-md-viewer-topbar">
|
||||||
|
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
||||||
|
<FileInfo toggleStar={this.props.toggleStar} editorUtilities={this.props.editorUtilities}
|
||||||
|
fileInfo={this.props.fileInfo}/>
|
||||||
|
<div className="topbar-btn-container">
|
||||||
|
{this.props.collabUsers.length > 0 && <CollabUsersButton className={'collab-users-dropdown'}
|
||||||
|
users={this.props.collabUsers} id={'usersButton'} />}
|
||||||
|
<MoreMenu
|
||||||
|
readOnly={this.props.readOnly}
|
||||||
|
openDialogs={this.props.openDialogs}
|
||||||
|
editorMode={this.props.editorMode}
|
||||||
|
onEdit={this.props.onEdit}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -116,6 +116,7 @@
|
|||||||
width: 23em;
|
width: 23em;
|
||||||
min-height: 90px;
|
min-height: 90px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
.seafile-comment-footer .submit-comment {
|
.seafile-comment-footer .submit-comment {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
@@ -142,3 +142,17 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.seafile-md-comment {
|
||||||
|
background-color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
right: 1px;
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
.seafile-md-comment .seafile-comment {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.seafile-md-comment .seafile-comment .seafile-comment-toggle-resolved {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
@@ -1,28 +1,18 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { SeafileEditor } from '@seafile/seafile-editor';
|
import { SeafileEditor } from '@seafile/seafile-editor/dist/editor/editor.js';
|
||||||
import 'whatwg-fetch';
|
import 'whatwg-fetch';
|
||||||
import { Value, Document, Block } from 'slate';
|
|
||||||
import { seafileAPI } from './utils/seafile-api';
|
import { seafileAPI } from './utils/seafile-api';
|
||||||
import { Utils } from './utils/utils';
|
import { Utils } from './utils/utils';
|
||||||
import { gettext, isDocs } from './utils/constants';
|
import { gettext, isDocs } from './utils/constants';
|
||||||
import io from 'socket.io-client';
|
import io from 'socket.io-client';
|
||||||
import toaster from './components/toast';
|
import toaster from './components/toast';
|
||||||
import ModalPortal from './components/modal-portal';
|
import ModalPortal from './components/modal-portal';
|
||||||
import EditFileTagDialog from './components/dialog/edit-filetag-dialog';
|
|
||||||
import RelatedFileDialogs from './components/dialog/related-file-dialogs';
|
|
||||||
import ShareDialog from './components/dialog/share-dialog';
|
import ShareDialog from './components/dialog/share-dialog';
|
||||||
import CommentDialog from './components/markdown-view/comment-dialog';
|
|
||||||
import InsertFileDialog from './components/dialog/insert-file-dialog';
|
import InsertFileDialog from './components/dialog/insert-file-dialog';
|
||||||
import MarkdownViewerSlate from '@seafile/seafile-editor/dist/viewer/markdown-viewer-slate';
|
|
||||||
import { serialize, deserialize } from '@seafile/seafile-editor/dist/utils/slate2markdown';
|
import { serialize, deserialize } from '@seafile/seafile-editor/dist/utils/slate2markdown';
|
||||||
import LocalDraftDialog from './components/dialog/local-draft-dialog';
|
import LocalDraftDialog from './components/dialog/local-draft-dialog';
|
||||||
import DiffViewer from '@seafile/seafile-editor/dist/viewer/diff-viewer';
|
|
||||||
import MarkdownViewerToolbar from './components/toolbar/markdown-viewer-toolbar';
|
import MarkdownViewerToolbar from './components/toolbar/markdown-viewer-toolbar';
|
||||||
import HistoryList from './components/markdown-view/history-list';
|
|
||||||
import CommentPanel from './components/file-view/comment-panel';
|
import CommentPanel from './components/file-view/comment-panel';
|
||||||
import OutlineView from './components/markdown-view/outline';
|
|
||||||
import Loading from './components/loading';
|
|
||||||
import { findRange } from '@seafile/slate-react';
|
|
||||||
|
|
||||||
import './css/markdown-viewer/markdown-editor.css';
|
import './css/markdown-viewer/markdown-editor.css';
|
||||||
|
|
||||||
@@ -274,7 +264,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
this.draftPlainValue = '';
|
this.draftPlainValue = '';
|
||||||
this.state = {
|
this.state = {
|
||||||
markdownContent: '',
|
markdownContent: '',
|
||||||
oldMarkdownContent: '',
|
|
||||||
loading: true,
|
loading: true,
|
||||||
mode: 'editor',
|
mode: 'editor',
|
||||||
fileInfo: {
|
fileInfo: {
|
||||||
@@ -288,27 +277,20 @@ class MarkdownEditor extends React.Component {
|
|||||||
lastModifier: '',
|
lastModifier: '',
|
||||||
id: '',
|
id: '',
|
||||||
},
|
},
|
||||||
editorMode: 'viewer',
|
editorMode: 'rich',
|
||||||
collabServer: seafileCollabServer ? seafileCollabServer : null,
|
collabServer: seafileCollabServer ? seafileCollabServer : null,
|
||||||
relatedFiles: [],
|
|
||||||
fileTagList: [],
|
|
||||||
localDraftDialog: false,
|
localDraftDialog: false,
|
||||||
showRelatedFileDialog: false,
|
|
||||||
showEditFileTagDialog: false,
|
|
||||||
showMarkdownEditorDialog: false,
|
showMarkdownEditorDialog: false,
|
||||||
showShareLinkDialog: false,
|
showShareLinkDialog: false,
|
||||||
showCommentDialog: false,
|
|
||||||
showInsertFileDialog: false,
|
showInsertFileDialog: false,
|
||||||
showDraftSaved: false,
|
showDraftSaved: false,
|
||||||
collabUsers: userInfo ?
|
collabUsers: userInfo ?
|
||||||
[{user: userInfo, is_editing: false}] : [],
|
[{user: userInfo, is_editing: false}] : [],
|
||||||
commentsNumber: null,
|
commentsNumber: null,
|
||||||
loadingDiff: false,
|
|
||||||
value: null,
|
value: null,
|
||||||
isShowComments: false,
|
isShowComments: false,
|
||||||
isShowHistory: false,
|
isShowHistory: false,
|
||||||
isShowOutline: true,
|
readOnly: true,
|
||||||
viewMode:'list_related_file',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.state.collabServer) {
|
if (this.state.collabServer) {
|
||||||
@@ -389,11 +371,8 @@ class MarkdownEditor extends React.Component {
|
|||||||
|
|
||||||
toggleCancel = () => {
|
toggleCancel = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showRelatedFileDialog: false,
|
|
||||||
showEditFileTagDialog: false,
|
|
||||||
showMarkdownEditorDialog: false,
|
showMarkdownEditorDialog: false,
|
||||||
showShareLinkDialog: false,
|
showShareLinkDialog: false,
|
||||||
showCommentDialog: false,
|
|
||||||
showInsertFileDialog: false,
|
showInsertFileDialog: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -469,27 +448,8 @@ class MarkdownEditor extends React.Component {
|
|||||||
openDialogs = (option) => {
|
openDialogs = (option) => {
|
||||||
switch(option)
|
switch(option)
|
||||||
{
|
{
|
||||||
case 'related_files':
|
case 'help':
|
||||||
if (this.state.relatedFiles.length > 0) {
|
window.richMarkdownEditor.showHelpDialog();
|
||||||
this.setState({
|
|
||||||
showRelatedFileDialog: true,
|
|
||||||
showMarkdownEditorDialog: true,
|
|
||||||
viewMode: 'list_related_file',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.setState({
|
|
||||||
showRelatedFileDialog: true,
|
|
||||||
showMarkdownEditorDialog: true,
|
|
||||||
viewMode: 'add_related_file',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'tags':
|
|
||||||
this.setState({
|
|
||||||
showEditFileTagDialog: true,
|
|
||||||
showMarkdownEditorDialog: true,
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case 'share_link':
|
case 'share_link':
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -497,12 +457,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
showShareLinkDialog: true,
|
showShareLinkDialog: true,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'comment':
|
|
||||||
this.setState({
|
|
||||||
showMarkdownEditorDialog: true,
|
|
||||||
showCommentDialog: true,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'insert_file':
|
case 'insert_file':
|
||||||
this.setState({
|
this.setState({
|
||||||
showMarkdownEditorDialog: true,
|
showMarkdownEditorDialog: true,
|
||||||
@@ -525,7 +479,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
contact_email: editorUtilities.contact_email,
|
contact_email: editorUtilities.contact_email,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
document.removeEventListener('selectionchange', this.setBtnPosition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -562,7 +515,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
// case1: If file is draft file
|
// case1: If file is draft file
|
||||||
// case2: If mode == 'edit' and the file has no draft
|
// case2: If mode == 'edit' and the file has no draft
|
||||||
// case3: The length of markDownContent is 1 when clear all content in editor and the file has no draft
|
// case3: The length of markDownContent is 1 when clear all content in editor and the file has no draft
|
||||||
editorMode: (hasPermission && (isDraft || (isEditMode && !hasDraft) || (isBlankFile && !hasDraft))) ? 'rich' : 'viewer',
|
readOnly: !(hasPermission && (isDraft || (isEditMode && !hasDraft) || (isBlankFile && !hasDraft))),
|
||||||
value: value,
|
value: value,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -587,11 +540,8 @@ class MarkdownEditor extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.checkDraft();
|
this.checkDraft();
|
||||||
this.listRelatedFiles();
|
|
||||||
this.listFileTags();
|
|
||||||
this.getCommentsNumber();
|
this.getCommentsNumber();
|
||||||
|
|
||||||
document.addEventListener('selectionchange', this.setBtnPosition);
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let url = new URL(window.location.href);
|
let url = new URL(window.location.href);
|
||||||
if (url.hash) {
|
if (url.hash) {
|
||||||
@@ -600,34 +550,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
listRelatedFiles = () => {
|
|
||||||
seafileAPI.listRelatedFiles(repoID, filePath).then(res => {
|
|
||||||
this.setState({
|
|
||||||
relatedFiles: res.data.related_files
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listFileTags = () => {
|
|
||||||
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
|
||||||
let fileTagList = res.data.file_tags;
|
|
||||||
for (let i = 0, length = fileTagList.length; i < length; i++) {
|
|
||||||
fileTagList[i].id = fileTagList[i].file_tag_id;
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
fileTagList: fileTagList
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onRelatedFileChange = () => {
|
|
||||||
this.listRelatedFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
onFileTagChanged = () => {
|
|
||||||
this.listFileTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
setFileInfoMtime = (fileInfo) => {
|
setFileInfoMtime = (fileInfo) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
fileInfo: Object.assign({}, this.state.fileInfo, { mtime: fileInfo.mtime, id: fileInfo.id, lastModifier: fileInfo.last_modifier_name })
|
fileInfo: Object.assign({}, this.state.fileInfo, { mtime: fileInfo.mtime, id: fileInfo.id, lastModifier: fileInfo.last_modifier_name })
|
||||||
@@ -685,9 +607,12 @@ class MarkdownEditor extends React.Component {
|
|||||||
window.location.href = editorUtilities.getParentDectionaryUrl();
|
window.location.href = editorUtilities.getParentDectionaryUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
onEdit = (event) => {
|
onEdit = (mode) => {
|
||||||
event.preventDefault();
|
if (mode === 'rich') {
|
||||||
this.setEditorMode('rich');
|
window.seafileEditor.switchToRichTextEditor();
|
||||||
|
} else if (mode === 'plain') {
|
||||||
|
window.seafileEditor.switchToPlainTextEditor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleShareLinkDialog = () => {
|
toggleShareLinkDialog = () => {
|
||||||
@@ -708,242 +633,23 @@ class MarkdownEditor extends React.Component {
|
|||||||
this.toggleCancel();
|
this.toggleCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
showDiffViewer = () => {
|
|
||||||
this.setState({
|
|
||||||
loadingDiff: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDiffViewerContent = (markdownContent, oldMarkdownContent) => {
|
|
||||||
this.setState({
|
|
||||||
markdownContent: markdownContent,
|
|
||||||
oldMarkdownContent: oldMarkdownContent
|
|
||||||
});
|
|
||||||
this.showDiffViewer();
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadDiffContent = () =>{
|
|
||||||
this.setState({
|
|
||||||
loadingDiff: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setBtnPosition = (e) => {
|
|
||||||
if (!this.state.isShowComments) return;
|
|
||||||
const nativeSelection = window.getSelection();
|
|
||||||
if (!nativeSelection.rangeCount) {
|
|
||||||
this.range = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nativeSelection.isCollapsed === false) {
|
|
||||||
const nativeRange = nativeSelection.getRangeAt(0);
|
|
||||||
const focusNode = nativeSelection.focusNode;
|
|
||||||
if ((focusNode.tagName === 'I') ||
|
|
||||||
(focusNode.nodeType !== 3 && focusNode.getAttribute('class') === 'language-type')) {
|
|
||||||
// fix select last paragraph
|
|
||||||
let fragment = nativeRange.cloneContents();
|
|
||||||
let startNode = fragment.firstChild.firstChild;
|
|
||||||
if (!startNode) return;
|
|
||||||
let newNativeRange = document.createRange();
|
|
||||||
newNativeRange.setStartBefore(startNode);
|
|
||||||
newNativeRange.setEndAfter(startNode);
|
|
||||||
|
|
||||||
let editor = {value: this.state.value};
|
|
||||||
this.range = findRange(nativeRange, editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
let editor = {value: this.state.value};
|
|
||||||
this.range = findRange(nativeRange, editor);
|
|
||||||
}
|
|
||||||
if (!this.range) return;
|
|
||||||
let rect = nativeRange.getBoundingClientRect();
|
|
||||||
// fix Safari bug
|
|
||||||
if (navigator.userAgent.indexOf('Chrome') < 0 && navigator.userAgent.indexOf('Safari') > 0) {
|
|
||||||
if (nativeRange.collapsed && rect.top == 0 && rect.height == 0) {
|
|
||||||
if (nativeRange.startOffset == 0) {
|
|
||||||
nativeRange.setEnd(nativeRange.endContainer, 1);
|
|
||||||
} else {
|
|
||||||
nativeRange.setStart(nativeRange.startContainer, nativeRange.startOffset - 1);
|
|
||||||
}
|
|
||||||
rect = nativeRange.getBoundingClientRect();
|
|
||||||
if (rect.top == 0 && rect.height == 0) {
|
|
||||||
if (nativeRange.getClientRects().length) {
|
|
||||||
rect = nativeRange.getClientRects()[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let style = this.refs.commentbtn.style;
|
|
||||||
style.top = `${rect.top - 63 + this.refs.markdownContainer.scrollTop}px`;
|
|
||||||
style.right = '0px';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let style = this.refs.commentbtn.style;
|
|
||||||
style.top = '-1000px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addComment = (e) => {
|
addComment = (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.getQuote();
|
|
||||||
this.openDialogs('comment');
|
this.openDialogs('comment');
|
||||||
}
|
}
|
||||||
|
|
||||||
getQuote = () => {
|
|
||||||
let range = this.range;
|
|
||||||
if (!range) return;
|
|
||||||
const { document } = this.state.value;
|
|
||||||
let { anchor, focus } = range;
|
|
||||||
const anchorText = document.getNode(anchor.key);
|
|
||||||
const focusText = document.getNode(focus.key);
|
|
||||||
const anchorInline = document.getClosestInline(anchor.key);
|
|
||||||
const focusInline = document.getClosestInline(focus.key);
|
|
||||||
// COMPAT: If the selection is at the end of a non-void inline node, and
|
|
||||||
// there is a node after it, put it in the node after instead. This
|
|
||||||
// standardizes the behavior, since it's indistinguishable to the user.
|
|
||||||
if (anchorInline && anchor.offset == anchorText.text.length) {
|
|
||||||
const block = document.getClosestBlock(anchor.key);
|
|
||||||
const nextText = block.getNextText(anchor.key);
|
|
||||||
if (nextText) {
|
|
||||||
range = range.moveAnchorTo(nextText.key, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (focusInline && focus.offset == focusText.text.length) {
|
|
||||||
const block = document.getClosestBlock(focus.key);
|
|
||||||
const nextText = block.getNextText(focus.key);
|
|
||||||
if (nextText) {
|
|
||||||
range = range.moveFocusTo(nextText.key, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let fragment = document.getFragmentAtRange(range);
|
|
||||||
let nodes = this.removeNullNode(fragment.nodes);
|
|
||||||
let newFragment = Document.create({
|
|
||||||
nodes: nodes
|
|
||||||
});
|
|
||||||
let newValue = Value.create({
|
|
||||||
document: newFragment
|
|
||||||
});
|
|
||||||
this.quote = serialize(newValue.toJSON());
|
|
||||||
let selection = document.createSelection(range);
|
|
||||||
selection = selection.setIsFocused(true);
|
|
||||||
this.setState({
|
|
||||||
commentPosition: selection.anchor.path
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeNullNode = (oldNodes) => {
|
|
||||||
let newNodes = [];
|
|
||||||
oldNodes.map((node) => {
|
|
||||||
const text = node.text.trim();
|
|
||||||
const childNodes = node.nodes;
|
|
||||||
if (!text) return;
|
|
||||||
if ((childNodes && childNodes.size === 1) || (!childNodes)) {
|
|
||||||
newNodes.push(node);
|
|
||||||
}
|
|
||||||
else if (childNodes.size > 1) {
|
|
||||||
let nodes = this.removeNullNode(childNodes);
|
|
||||||
let newNode = Block.create({
|
|
||||||
nodes: nodes,
|
|
||||||
data: node.data,
|
|
||||||
key: node.key,
|
|
||||||
type: node.type
|
|
||||||
});
|
|
||||||
newNodes.push(newNode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollToNode = (node) => {
|
scrollToNode = (node) => {
|
||||||
let url = new URL(window.location.href);
|
let url = new URL(window.location.href);
|
||||||
url.set('hash', 'user-content-' + node.text);
|
url.set('hash', 'user-content-' + node.text);
|
||||||
window.location.href = url.toString();
|
window.location.href = url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
findScrollContainer = (el, window) => {
|
|
||||||
let parent = el.parentNode;
|
|
||||||
const OVERFLOWS = ['auto', 'overlay', 'scroll'];
|
|
||||||
let scroller;
|
|
||||||
while (!scroller) {
|
|
||||||
if (!parent.parentNode) break;
|
|
||||||
const style = window.getComputedStyle(parent);
|
|
||||||
const { overflowY } = style;
|
|
||||||
if (OVERFLOWS.includes(overflowY)) {
|
|
||||||
scroller = parent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parent = parent.parentNode;
|
|
||||||
}
|
|
||||||
if (!scroller) {
|
|
||||||
return window.document.body;
|
|
||||||
}
|
|
||||||
return scroller;
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollToQuote = (path) => {
|
|
||||||
if (!path) return;
|
|
||||||
const win = window;
|
|
||||||
if (path.length > 2) {
|
|
||||||
// deal with code block or chart
|
|
||||||
path[0] = path[0] > 1 ? path[0] - 1 : path[0] + 1;
|
|
||||||
path = path.slice(0, 1);
|
|
||||||
}
|
|
||||||
let node = this.state.value.document.getNode(path);
|
|
||||||
if (!node) {
|
|
||||||
path = path.slice(0, 1);
|
|
||||||
node = this.state.value.document.getNode(path);
|
|
||||||
}
|
|
||||||
if (node) {
|
|
||||||
let element = win.document.querySelector(`[data-key="${node.key}"]`);
|
|
||||||
while (element.tagName === 'CODE') {
|
|
||||||
element = element.parentNode;
|
|
||||||
}
|
|
||||||
const scroller = this.findScrollContainer(element, win);
|
|
||||||
const isWindow = scroller == win.document.body || scroller == win.document.documentElement;
|
|
||||||
if (isWindow) {
|
|
||||||
win.scrollTo(0, element.offsetTop);
|
|
||||||
} else {
|
|
||||||
scroller.scrollTop = element.offsetTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleHistory = () => {
|
toggleHistory = () => {
|
||||||
if (!isDocs) {
|
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
|
||||||
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.isShowHistory) {
|
|
||||||
this.setState({
|
|
||||||
isShowHistory: false,
|
|
||||||
isShowOutline: true,
|
|
||||||
isShowComments: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
isShowHistory: true,
|
|
||||||
isShowOutline: false,
|
|
||||||
isShowComments: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleCommentList = () => {
|
toggleCommentList = () => {
|
||||||
if (this.state.isShowComments) {
|
this.setState({ isShowComments: !this.state.isShowComments });
|
||||||
this.setState({
|
|
||||||
isShowHistory: false,
|
|
||||||
isShowOutline: true,
|
|
||||||
isShowComments: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
isShowHistory: false,
|
|
||||||
isShowOutline: false,
|
|
||||||
isShowComments: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getInsertLink = (repoID, filePath) => {
|
getInsertLink = (repoID, filePath) => {
|
||||||
@@ -965,8 +671,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
let component;
|
let component;
|
||||||
let sidePanel = this.state.isShowHistory ? true : false;
|
let sidePanel = this.state.isShowHistory ? true : false;
|
||||||
let markdownViewer = sidePanel ? 'seafile-md-viewer-slate side-panel-on' :
|
|
||||||
(this.state.isShowComments ? 'seafile-md-viewer-slate comment-on' : 'seafile-md-viewer-slate');
|
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
return (
|
return (
|
||||||
<div className="empty-loading-page">
|
<div className="empty-loading-page">
|
||||||
@@ -974,109 +678,61 @@ class MarkdownEditor extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.state.mode === 'editor') {
|
} else if (this.state.mode === 'editor') {
|
||||||
if (this.state.editorMode === 'viewer') {
|
component = (
|
||||||
component = (
|
<Fragment>
|
||||||
<div className="seafile-md-viewer d-flex flex-column">
|
<MarkdownViewerToolbar
|
||||||
<MarkdownViewerToolbar
|
isDocs={isDocs}
|
||||||
isDocs={isDocs}
|
hasDraft={hasDraft}
|
||||||
hasDraft={hasDraft}
|
isDraft={isDraft}
|
||||||
isDraft={isDraft}
|
editorUtilities={editorUtilities}
|
||||||
editorUtilities={editorUtilities}
|
collabUsers={this.state.collabUsers}
|
||||||
collabUsers={this.state.collabUsers}
|
fileInfo={this.state.fileInfo}
|
||||||
fileInfo={this.state.fileInfo}
|
toggleStar={this.toggleStar}
|
||||||
toggleStar={this.toggleStar}
|
backToParentDirectory={this.backToParentDirectory}
|
||||||
backToParentDirectory={this.backToParentDirectory}
|
openDialogs={this.openDialogs}
|
||||||
openDialogs={this.openDialogs}
|
toggleShareLinkDialog={this.toggleShareLinkDialog}
|
||||||
fileTagList={this.state.fileTagList}
|
onEdit={this.onEdit}
|
||||||
relatedFiles={this.state.relatedFiles}
|
toggleNewDraft={editorUtilities.createDraftFile}
|
||||||
toggleShareLinkDialog={this.toggleShareLinkDialog}
|
commentsNumber={this.state.commentsNumber}
|
||||||
onEdit={this.onEdit}
|
toggleCommentList={this.toggleCommentList}
|
||||||
toggleNewDraft={editorUtilities.createDraftFile}
|
showFileHistory={this.state.isShowHistory ? false : true }
|
||||||
commentsNumber={this.state.commentsNumber}
|
toggleHistory={this.toggleHistory}
|
||||||
toggleCommentList={this.toggleCommentList}
|
readOnly={this.state.readOnly}
|
||||||
showFileHistory={this.state.isShowHistory ? false : true }
|
mode={this.state.mode}
|
||||||
toggleHistory={this.toggleHistory}
|
editorMode={this.state.editorMode}
|
||||||
/>
|
/>
|
||||||
<div className="seafile-md-viewer d-flex">
|
<SeafileEditor
|
||||||
<div className={sidePanel ? 'seafile-md-viewer-container side-panel-on' : 'seafile-md-viewer-container'} ref="markdownContainer">
|
fileInfo={this.state.fileInfo}
|
||||||
{
|
markdownContent={this.state.markdownContent}
|
||||||
this.state.isShowHistory ?
|
editorUtilities={editorUtilities}
|
||||||
<div className="diff-container">
|
collabUsers={this.state.collabUsers}
|
||||||
<div className="diff-wrapper article">
|
setFileInfoMtime={this.setFileInfoMtime}
|
||||||
{ this.state.loadingDiff ?
|
toggleStar={this.toggleStar}
|
||||||
<Loading/> :
|
showFileHistory={true}
|
||||||
<DiffViewer
|
setEditorMode={this.setEditorMode}
|
||||||
newMarkdownContent={this.state.markdownContent}
|
setContent={this.setContent}
|
||||||
oldMarkdownContent={this.state.oldMarkdownContent}
|
draftID={draftID}
|
||||||
/>
|
isDraft={isDraft}
|
||||||
}
|
mode={this.state.mode}
|
||||||
</div>
|
emitSwitchEditor={this.emitSwitchEditor}
|
||||||
</div>
|
hasDraft={hasDraft}
|
||||||
:
|
editorMode={this.state.editorMode}
|
||||||
<div className={markdownViewer}>
|
siteRoot={siteRoot}
|
||||||
<MarkdownViewerSlate
|
autoSaveDraft={this.autoSaveDraft}
|
||||||
relatedFiles={this.state.relatedFiles}
|
setDraftValue={this.setDraftValue}
|
||||||
siteRoot={siteRoot}
|
clearTimer={this.clearTimer}
|
||||||
value={this.state.value}
|
openDialogs={this.openDialogs}
|
||||||
/>
|
deleteDraft={this.deleteDraft}
|
||||||
{this.state.isShowComments &&
|
showDraftSaved={this.state.showDraftSaved}
|
||||||
<i className="fa fa-plus-square seafile-viewer-comment-btn" ref="commentbtn" onMouseDown={this.addComment}></i>}
|
readOnly={this.state.readOnly}
|
||||||
</div>
|
/>
|
||||||
}
|
{this.state.isShowComments &&
|
||||||
{
|
<div className="seafile-md-comment">
|
||||||
this.state.isShowOutline &&
|
<CommentPanel toggleCommentPanel={this.toggleCommentList} commentsNumber={this.state.commentsNumber}/>
|
||||||
<OutlineView
|
|
||||||
isViewer={true}
|
|
||||||
document={this.state.value.document}
|
|
||||||
scrollToNode={this.scrollToNode}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.isShowComments &&
|
|
||||||
<CommentPanel toggleCommentPanel={this.toggleCommentList} commentsNumber={this.state.commentsNumber}/>}
|
|
||||||
</div>
|
|
||||||
<div className="seafile-md-viewer-side-panel">
|
|
||||||
{
|
|
||||||
this.state.isShowHistory &&
|
|
||||||
<HistoryList
|
|
||||||
editorUtilities={editorUtilities}
|
|
||||||
showDiffViewer={this.showDiffViewer}
|
|
||||||
setDiffViewerContent={this.setDiffViewerContent}
|
|
||||||
reloadDiffContent={this.reloadDiffContent}
|
|
||||||
toggleHistoryPanel={this.toggleHistory}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
);
|
</Fragment>
|
||||||
} else {
|
);
|
||||||
component = <SeafileEditor
|
|
||||||
fileInfo={this.state.fileInfo}
|
|
||||||
markdownContent={this.state.markdownContent}
|
|
||||||
editorUtilities={editorUtilities}
|
|
||||||
collabUsers={this.state.collabUsers}
|
|
||||||
setFileInfoMtime={this.setFileInfoMtime}
|
|
||||||
toggleStar={this.toggleStar}
|
|
||||||
showFileHistory={true}
|
|
||||||
setEditorMode={this.setEditorMode}
|
|
||||||
setContent={this.setContent}
|
|
||||||
draftID={draftID}
|
|
||||||
isDraft={isDraft}
|
|
||||||
mode={this.state.mode}
|
|
||||||
emitSwitchEditor={this.emitSwitchEditor}
|
|
||||||
hasDraft={hasDraft}
|
|
||||||
editorMode={this.state.editorMode}
|
|
||||||
relatedFiles={this.state.relatedFiles}
|
|
||||||
siteRoot={siteRoot}
|
|
||||||
autoSaveDraft={this.autoSaveDraft}
|
|
||||||
setDraftValue={this.setDraftValue}
|
|
||||||
clearTimer={this.clearTimer}
|
|
||||||
openDialogs={this.openDialogs}
|
|
||||||
fileTagList={this.state.fileTagList}
|
|
||||||
deleteDraft={this.deleteDraft}
|
|
||||||
showDraftSaved={this.state.showDraftSaved}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
@@ -1093,30 +749,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
{component}
|
{component}
|
||||||
{this.state.showMarkdownEditorDialog && (
|
{this.state.showMarkdownEditorDialog && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{this.state.showEditFileTagDialog &&
|
|
||||||
<ModalPortal>
|
|
||||||
<EditFileTagDialog
|
|
||||||
repoID={repoID}
|
|
||||||
filePath={filePath}
|
|
||||||
fileTagList={this.state.fileTagList}
|
|
||||||
toggleCancel={this.toggleCancel}
|
|
||||||
onFileTagChanged={this.onFileTagChanged}
|
|
||||||
/>
|
|
||||||
</ModalPortal>
|
|
||||||
}
|
|
||||||
{this.state.showRelatedFileDialog &&
|
|
||||||
<ModalPortal>
|
|
||||||
<RelatedFileDialogs
|
|
||||||
repoID={repoID}
|
|
||||||
filePath={filePath}
|
|
||||||
relatedFiles={this.state.relatedFiles}
|
|
||||||
toggleCancel={this.toggleCancel}
|
|
||||||
onRelatedFileChange={this.onRelatedFileChange}
|
|
||||||
dirent={this.state.fileInfo}
|
|
||||||
viewMode={this.state.viewMode}
|
|
||||||
/>
|
|
||||||
</ModalPortal>
|
|
||||||
}
|
|
||||||
{this.state.showInsertFileDialog &&
|
{this.state.showInsertFileDialog &&
|
||||||
<ModalPortal>
|
<ModalPortal>
|
||||||
<InsertFileDialog
|
<InsertFileDialog
|
||||||
@@ -1140,17 +772,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</ModalPortal>
|
</ModalPortal>
|
||||||
}
|
}
|
||||||
{this.state.showCommentDialog &&
|
|
||||||
<ModalPortal>
|
|
||||||
<CommentDialog
|
|
||||||
toggleCommentDialog={this.toggleCancel}
|
|
||||||
editorUtilities={editorUtilities}
|
|
||||||
onCommentAdded={this.onCommentAdded}
|
|
||||||
commentPosition={this.state.commentPosition}
|
|
||||||
quote={this.quote}
|
|
||||||
/>
|
|
||||||
</ModalPortal>
|
|
||||||
}
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
Reference in New Issue
Block a user