1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-07 01:41:39 +00:00

Viewer add (#3084)

This commit is contained in:
cainiao222
2019-03-11 21:08:25 +08:00
committed by Daniel Pan
parent e31a67dea6
commit 599ea3bf5d
4 changed files with 512 additions and 14 deletions

View File

@@ -8,7 +8,14 @@ import EditFileTagDialog from './components/dialog/edit-filetag-dialog';
import ListRelatedFileDialog from './components/dialog/list-related-file-dialog';
import AddRelatedFileDialog from './components/dialog/add-related-file-dialog';
import ShareDialog from './components/dialog/share-dialog';
import MarkdownViewerSlate from '@seafile/seafile-editor/dist/viewer/markdown-viewer-slate';
import io from "socket.io-client";
import toaster from "./components/toast";
import { serialize } from "@seafile/seafile-editor/dist/utils/slate2markdown";
import LocalDraftDialog from "@seafile/seafile-editor/dist/components/local-draft-dialog";
import MarkdownViewerToolbar from './components/toolbar/markdown-viewer-toolbar';
const CryptoJS = require('crypto-js');
const { repoID, repoName, filePath, fileName, mode, draftID, draftFilePath, draftOriginFilePath, isDraft, hasDraft, shareLinkExpireDaysMin, shareLinkExpireDaysMax } = window.app.pageOptions;
const { siteRoot, serviceUrl, seafileCollabServer } = window.app.config;
const userInfo = window.app.userInfo;
@@ -256,6 +263,11 @@ const editorUtilities = new EditorUtilities();
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.timer = null;
this.localDraft = '';
this.autoSave = false;
this.draftRichValue = '';
this.draftPlainValue = '';
this.state = {
markdownContent: '',
loading: true,
@@ -271,15 +283,98 @@ class MarkdownEditor extends React.Component {
lastModifier: '',
id: '',
},
editorMode: 'viewer',
collabServer: seafileCollabServer ? seafileCollabServer : null,
relatedFiles: [],
fileTagList: [],
localDraftDialog: false,
showRelatedFileDialog: false,
showEditFileTagDialog: false,
showAddRelatedFileDialog: false,
showMarkdownEditorDialog: false,
showShareLinkDialog: false,
showDraftSaved: false,
collabUsers: userInfo ?
[{user: userInfo, is_editing: false}] : [],
isShowHistory: false,
isShowComments: false,
commentsNumber: null,
};
if (this.state.collabServer) {
const socket = io(this.state.collabServer);
this.socket = socket;
socket.on('presence', (data) => this.receivePresenceData(data));
socket.on('repo_update', (data) => this.receiveUpdateData(data));
socket.on('connect', () => {
this.socket_id = socket.id;
});
}
}
emitSwitchEditor = (is_editing=false) => {
if (userInfo && this.state.collabServer) {
const { repoID, path } = this.state.fileInfo;
this.socket.emit('presence', {
request: 'editing',
doc_id: CryptoJS.MD5(repoID+path).toString(),
user: userInfo,
is_editing,
});
}
}
receiveUpdateData (data) {
let currentTime = new Date();
if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) {
return;
}
editorUtilities.fileMetaData().then((res) => {
if (res.data.id !== this.state.fileInfo.id) {
toaster.notify(
<span>
{this.props.t('this_file_has_been_updated')}
<a href='' >{' '}{this.props.t('refresh')}</a>
</span>,
{id: 'repo_updated', duration: 3600});
}
});
}
receivePresenceData(data) {
switch(data.response) {
case 'user_join':
toaster.notify(`user ${data.user.name} joined`, {
duration: 3
});
return;
case 'user_left':
toaster.notify(`user ${data.user.name} left`, {
duration: 3
});
return;
case 'update_users':
for (var prop in data.users) {
if (data.users.hasOwnProperty(prop)) {
if (prop === this.socket_id) {
data.users[prop]['myself'] = true;
break;
}
}
}
this.setState({collabUsers: Object.values(data.users)});
return;
case 'user_editing':
toaster.danger(`user ${data.user.name} is editing this file!`, {
duration: 3
});
return;
default:
console.log('unknown response type: ' + data.response);
return;
}
}
toggleCancel = () => {
@@ -292,6 +387,65 @@ class MarkdownEditor extends React.Component {
});
}
setEditorMode = (type) => {
this.setState({
editorMode: type
})
}
setDraftValue = (type, value) => {
if (type === 'rich') {
this.draftRichValue = value
} else {
this.draftPlainValue = value;
}
}
setContent = (str) => {
this.setState({
markdownContent: str
});
}
checkDraft = () => {
let draftKey = editorUtilities.getDraftKey();
let draft = localStorage.getItem(draftKey);
let that = this;
if (draft) {
that.setState({
localDraftDialog: true,
});
that.localDraft = draft;
localStorage.removeItem(draftKey);
}
}
useDraft = () => {
this.setState({
localDraftDialog: false,
loading: false,
markdownContent: this.localDraft,
editorMode: 'rich',
});
this.emitSwitchEditor(true);
}
deleteDraft = () => {
if (this.state.localDraftDialog) {
this.setState({
localDraftDialog: false,
loading: false,
});
} else {
let draftKey = editorUtilities.getDraftKey();
localStorage.removeItem(draftKey);
}
}
clearTimer = () => {
clearTimeout(this.timer);
this.timer = null;
}
closeAddRelatedFileDialog = () => {
this.setState({
showAddRelatedFileDialog: false,
@@ -340,6 +494,18 @@ class MarkdownEditor extends React.Component {
}
}
componentWillUnmount() {
this.socket.emit('repo_update', {
request: 'unwatch_update',
repo_id: this.props.editorUtilities.repoID,
user: {
name: this.props.editorUtilities.name,
username: this.props.editorUtilities.username,
contact_email: this.props.editorUtilities.contact_email,
},
});
}
componentDidMount() {
seafileAPI.getFileInfo(repoID, filePath).then((res) => {
@@ -361,15 +527,46 @@ class MarkdownEditor extends React.Component {
seafileAPI.getFileDownloadLink(repoID, filePath).then((res) => {
const downLoadUrl = res.data;
seafileAPI.getFileContent(downLoadUrl).then((res) => {
const contentLength = res.data.length;
let isBlankFile = (contentLength === 0 || contentLength === 1);
let hasPermission = (this.state.fileInfo.permission === 'rw');
let isEditMode = this.state.mode;
this.setState({
markdownContent: res.data,
loading: false
loading: false,
// Goto rich edit page
// First, the user has the relevant permissions, otherwise he can only enter the viewer interface or cannot access
// case1: If file is draft file
// 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
editorMode: (hasPermission && (isDraft || (isEditMode && !hasDraft) || (isBlankFile && !hasDraft))) ? 'rich' : 'viewer',
});
});
});
});
if (userInfo && this.socket) {
const { repoID, path } = this.state.fileInfo;
this.socket.emit('presence', {
request: 'join_room',
doc_id: CryptoJS.MD5(repoID+path).toString(),
user: userInfo
});
this.socket.emit('repo_update', {
request: 'watch_update',
repo_id: editorUtilities.repoID,
user: {
name: editorUtilities.name,
username: editorUtilities.username,
contact_email: editorUtilities.contact_email,
},
});
}
this.checkDraft();
this.listRelatedFiles();
this.listFileTags();
this.getCommentsNumber();
}
listRelatedFiles = () => {
@@ -400,7 +597,99 @@ class MarkdownEditor extends React.Component {
this.listFileTags();
}
setFileInfoMtime = (fileInfo) => {
this.setState({
fileInfo: Object.assign({}, this.state.fileInfo, { mtime: fileInfo.mtime, id: fileInfo.id, lastModifier: fileInfo.last_modifier_name })
});
};
toggleStar = () => {
let starrd = this.state.fileInfo.starred;
if (starrd) {
editorUtilities.unStarItem().then((response) => {
this.setState({
fileInfo: Object.assign({}, this.state.fileInfo, {starred: !starrd})
});
});
} else if (!starrd) {
editorUtilities.starItem().then((response) => {
this.setState({
fileInfo: Object.assign({}, this.state.fileInfo, {starred: !starrd})
});
});
}
}
autoSaveDraft = () => {
let that = this;
if (that.timer) {
return;
} else {
that.timer = setTimeout(() => {
let str = '';
if (this.state.editorMode == 'rich') {
let value = this.draftRichValue;
str = serialize(value.toJSON());
}
else if (this.state.editorMode == 'plain') {
str = this.draftPlainValue;
}
let draftKey = editorUtilities.getDraftKey();
localStorage.setItem(draftKey, str);
that.setState({
showDraftSaved: true
});
setTimeout(() => {
that.setState({
showDraftSaved: false
});
}, 3000);
that.timer = null;
}, 60000);
}
}
backToParentDirectory = () => {
window.location.href = editorUtilities.getParentDectionaryUrl();
}
onEdit = (event) => {
event.preventDefault();
this.setEditorMode('rich');
}
toggleShareLinkDialog = () => {
this.openDialogs('share_link');
}
toggleHistory = () => {
this.setState({ isShowHistory: !this.state.isShowHistory });
}
toggleCommentList = () => {
if (this.state.isShowHistory) {
this.setState({ isShowHistory: false, isShowComments: true });
}
else {
this.setState({ isShowComments: !this.state.isShowComments });
}
}
getCommentsNumber = () => {
editorUtilities.getCommentsNumber().then((res) => {
let commentsNumber = res.data[Object.getOwnPropertyNames(res.data)[0]];
this.setState({
commentsNumber: commentsNumber
});
});
}
onCommentAdded = () => {
this.getCommentsNumber();
}
render() {
let component;
if (this.state.loading) {
return (
<div className="empty-loading-page">
@@ -408,26 +697,96 @@ class MarkdownEditor extends React.Component {
</div>
);
} else if (this.state.mode === 'editor') {
return (
<React.Fragment>
<SeafileEditor
if (this.state.editorMode === 'viewer') {
component = (
<div className="seafile-md-viewer d-flex flex-column">
<MarkdownViewerToolbar
hasDraft={hasDraft}
isDraft={isDraft}
editorUtilities={editorUtilities}
collabUsers={this.state.collabUsers}
fileInfo={this.state.fileInfo}
toggleStar={this.toggleStar}
backToParentDirectory={this.backToParentDirectory}
openDialogs={this.openDialogs}
fileTagList={this.state.fileTagList}
relatedFiles={this.state.relatedFiles}
commentsNumber={this.state.commentsNumber}
toggleCommentList={this.toggleCommentList}
toggleShareLinkDialog={this.toggleShareLinkDialog}
onEdit={this.onEdit}
showFileHistory={true}
toggleHistory={this.toggleHistory}
toggleNewDraft={editorUtilities.createDraftFile}
/>
<MarkdownViewerSlate
fileInfo={this.state.fileInfo}
markdownContent={this.state.markdownContent}
editorUtilities={editorUtilities}
collabUsers={this.state.collabUsers}
showFileHistory={true}
setFileInfoMtime={this.setFileInfoMtime}
toggleStar={this.toggleStar}
setEditorMode={this.setEditorMode}
draftID={draftID}
isDraft={isDraft}
emitSwitchEditor={this.emitSwitchEditor}
hasDraft={hasDraft}
shareLinkExpireDaysMin={shareLinkExpireDaysMin}
shareLinkExpireDaysMax={shareLinkExpireDaysMax}
relatedFiles={this.state.relatedFiles}
siteRoot={siteRoot}
openDialogs={this.openDialogs}
fileTagList={this.state.fileTagList}
showDraftSaved={this.state.showDraftSaved}
isShowHistory={this.state.isShowHistory}
isShowComments={this.state.isShowComments}
onCommentAdded={this.onCommentAdded}
commentsNumber={this.state.commentsNumber}
getCommentsNumber={this.getCommentsNumber}
toggleHistory={this.toggleHistory}
toggleCommentList={this.toggleCommentList}
/>
</div>
)
} else {
component = <SeafileEditor
fileInfo={this.state.fileInfo}
markdownContent={this.state.markdownContent}
editorUtilities={editorUtilities}
userInfo={this.state.collabServer ? userInfo : null}
collabServer={this.state.collabServer}
collabUsers={this.state.collabUsers}
setFileInfoMtime={this.setFileInfoMtime}
toggleStar={this.toggleStar}
showFileHistory={true}
mode={mode}
setEditorMode={this.setEditorMode}
setContent={this.setContent}
draftID={draftID}
isDraft={isDraft}
mode={this.state.mode}
emitSwitchEditor={this.emitSwitchEditor}
hasDraft={hasDraft}
shareLinkExpireDaysMin={shareLinkExpireDaysMin}
shareLinkExpireDaysMax={shareLinkExpireDaysMax}
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 (
<React.Fragment>
{this.state.localDraftDialog?
<LocalDraftDialog
localDraftDialog={this.state.localDraftDialog}
deleteDraft={this.deleteDraft}
useDraft={this.useDraft}/>:
null}
{component}
{this.state.showMarkdownEditorDialog && (
<React.Fragment>
{this.state.showRelatedFileDialog &&
@@ -485,4 +844,4 @@ class MarkdownEditor extends React.Component {
}
}
export default MarkdownEditor;
export default MarkdownEditor;