1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-04 08:28:11 +00:00

add rich editor top bar

This commit is contained in:
cainiao222
2019-04-17 18:39:36 +08:00
parent 8dd1a0efa8
commit 582d68de4b
2 changed files with 376 additions and 38 deletions

View File

@@ -5,14 +5,25 @@ import i18n from './i18n';
import { seafileAPI } from './utils/seafile-api';
import io from 'socket.io-client';
import { gettext } from './utils/constants';
import ModalPortal from './components/modal-portal';
import { RichEditor } from './src/editor/editor';
import CDOCTypeChooser from './src/components/codc-type-chooser';
import { Value } from 'slate';
import CDOCTopbar from './components/toolbar/cdoc-editor-topbar';
import ShareDialog from './components/dialog/share-dialog';
import { Utils } from './utils/utils';
import { translate } from 'react-i18next';
import { RichEditor } from '@seafile/seafile-editor';
import { EditorUtilities } from '@seafile/seafile-editor/dist/editorUtilities';
import toaster from './components/toast';
import './css/markdown-viewer/markdown-editor.css';
import './assets/css/fa-solid.css';
import './assets/css/fa-regular.css';
import './assets/css/fontawesome.css';
import './index.css';
const JSZip = require('jszip');
const request = require('request');
const CryptoJS = require('crypto-js');
const lang = window.app.config.lang;
@@ -21,7 +32,7 @@ const { repoID, repoName, filePath, fileName, username, contactEmail } = window.
const { siteRoot, seafileCollabServer, serviceURL} = window.app.config;
const { name } = window.app.userInfo;
let dirPath = '/';
let dirPath = '/';
const editorUtilities = new EditorUtilities(seafileAPI, repoID, fileName, dirPath, name, filePath, serviceURL, username, contactEmail, repoName);
const userInfo = window.app.userInfo;
class CDOCEditor extends React.Component {
@@ -30,6 +41,7 @@ class CDOCEditor extends React.Component {
super(props);
this.collabServer = seafileCollabServer ? seafileCollabServer : null
this.state = {
value: Value.create({}),
collabUsers: userInfo ?
[{user: userInfo, is_editing: false}] : [],
fileInfo: {
@@ -39,6 +51,11 @@ class CDOCEditor extends React.Component {
lastModifier: '',
id: '',
},
isShowTypeChooser: false,
isSaving: false,
contentChanged: false,
showShareLinkDialog: false,
isShowHistory: false,
}
if (this.state.collabServer) {
@@ -52,41 +69,31 @@ class CDOCEditor extends React.Component {
}
}
componentDidMount() {
editorUtilities.getFileInfo(repoID, filePath).then((res) => {
let { mtime, size, starred, permission, last_modifier_name, id } = res.data;
let lastModifier = last_modifier_name;
this.setState((prevState, props) => ({
fileInfo: {
...prevState.fileInfo,
mtime,
size,
starred,
permission,
lastModifier,
id
}
}));
resetContentChange = () => {
this.setState({
contentChanged: false
})
}
componentDidMount() {
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
});
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.socket.emit('repo_update', {
request: 'watch_update',
repo_id: editorUtilities.repoID,
user: {
name: editorUtilities.name,
username: editorUtilities.username,
contact_email: editorUtilities.contact_email,
},
});
}
}
receiveUpdateData (data) {
@@ -141,20 +148,260 @@ class CDOCEditor extends React.Component {
}
}
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})
});
});
}
}
toggleHistory = () => {
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
}
backToParentDirectory = () => {
window.location.href = editorUtilities.getParentDectionaryUrl();
}
toggleShareLinkDialog = () => {
this.openDialogs('share_link');
}
toggleCancel = () => {
this.setState({
showShareLinkDialog: false,
});
}
openDialogs = (option) => {
switch(option)
{
case 'help':
window.richEditor.showHelpDialog();
break;
case 'share_link':
this.setState({
showMarkdownEditorDialog: true,
showShareLinkDialog: true,
});
break;
case 'insert_file':
this.setState({
showMarkdownEditorDialog: true,
showInsertFileDialog: true,
});
break;
default:
return;
}
}
initialContent(){
const that = this;
editorUtilities.getFileDownloadLink().then((res) => {
request({ method : 'GET', url : res.data, encoding: null}, function (error, response, body) {
if (error || response.statusCode !== 200) {
console.log(error);
return;
}
if (body.length === 0 ) {
that.setState({
isShowTypeChooser: true,
});
return;
}
JSZip.loadAsync(body).then((zip) => {
if (zip.file('content.json')) {
zip.file('content.json').async('string').then((res) => {
const value = { object: 'value', document: JSON.parse(res) };
that.setState({
value: Value.create(value),
});
}, (err) => {
console.log(err);
});
}
if (zip.file('info.json')) {
zip.file('info.json').async('string').then((res) => {
that.setState({
zipVersion: JSON.parse(res).version,
});
this.documentType = JSON.parse(res).type;
}, (err) => {
console.log(err);
});
}
// const assets = zip.folder('assets/'); // get images in the future
});
});
});
}
componentWillMount() {
this.initialContent();
editorUtilities.getFileInfo().then((response) => {
this.setState({
fileInfo:Object.assign({}, this.state.fileInfo, {
mtime: response.data.mtime,
size: response.data.size,
name: response.data.name,
starred: response.data.starred,
lastModifier: response.data.last_modifier_name,
permission: response.data.permission,
id: response.data.id,
})
});
});
}
onChange = (editor) => {
const ops = editor.operations
.filter(o => o.type !== 'set_selection' && o.type !== 'set_value');
if (ops.size !== 0) {
this.setState({
contentChanged: true,
value: editor.value
})
}
}
onSave = (editor) => {
const info = { 'version': 1, type: this.documentType };
let zip = new JSZip();
this.setState({
isSaving: true
});
zip.file('info.json', JSON.stringify(info));
zip.file('content.json', JSON.stringify(this.state.value.document));
zip.folder('assets');
zip.generateAsync({ type: 'blob' }).then((blob) => {
editorUtilities.saveContent(blob).then(() =>{
this.setState({
isSaving: false,
contentChanged: false
});
toaster.success(this.props.t('file_saved'), {
duration: 2,
});
editorUtilities.getFileInfo().then((res) => {
this.setFileInfoMtime(res.data);
});
}, (err) => {
this.setState({
isSaving: false
});
});
}, function (err) {
this.setState({
isSaving: false
});
console.log(err);
});
}
setFileInfoMtime = (fileInfo) => {
this.setState({
fileInfo: Object.assign({}, this.state.fileInfo, { mtime: fileInfo.mtime, id: fileInfo.id, lastModifier: fileInfo.last_modifier_name })
});
};
setDocument = (type, value) => {
this.setState({
value: value,
});
this.documentType = type;
// save the document type
{
const info = { 'version': 1, type: type};
let zip = new JSZip();
zip.file('info.json', JSON.stringify(info));
zip.file('content.json', JSON.stringify(value.document));
zip.folder('assets');
zip.generateAsync({ type: 'blob' }).then((blob) => {
editorUtilities.saveContent(blob).then(() =>{
editorUtilities.getFileInfo().then((res) => {
this.setFileInfoMtime(res.data);
});
}, (err) => {
});
}, function (err) {
console.log(err);
});
}
this.toggleTypeChooser();
}
toggleTypeChooser = () => {
this.setState({
isShowTypeChooser: !this.state.isShowTypeChooser
});
}
render() {
return(
<I18nextProvider i18n={ i18n } initialLanguage={ lang } >
<React.Fragment>
<CDOCTopbar
fileInfo={this.state.fileInfo}
collabUsers={this.state.collabUsers}
toggleStar={this.toggleStar}
editorUtilities={editorUtilities}
backToParentDirectory={this.backToParentDirectory}
toggleShareLinkDialog={this.toggleShareLinkDialog}
openDialogs={this.openDialogs}
showFileHistory={this.state.isShowHistory ? false : true }
toggleHistory={this.toggleHistory}
saving={this.state.isSaving}
onSave={this.onSave}
contentChanged={this.state.contentChanged}
/>
<RichEditor
collabUsers = {this.state.collabUsers}
onSave = {this.onSave}
resetContentChange = {this.resetContentChange}
value = {this.state.value}
onChange = {this.onChange}
editorUtilities = {editorUtilities}
/>
</I18nextProvider>
/>
{this.state.showShareLinkDialog &&
<ModalPortal>
<ShareDialog
itemType="file"
itemName={this.state.fileInfo.name}
itemPath={filePath}
repoID={repoID}
toggleDialog={this.toggleCancel}
isGroupOwnedRepo={false}
repoEncrypted={false}
/>
</ModalPortal>
}
{
this.state.isShowTypeChooser &&
<CDOCTypeChooser
showTypeChooser={this.state.isShowTypeChooser}
setDocument = {this.setDocument}
/>
}
</React.Fragment>
)
}
}
const TranslatedCDOCEditor = translate('translations')(CDOCEditor)
ReactDOM.render (
<CDOCEditor/>,
<I18nextProvider i18n={ i18n } initialLanguage={ lang } >
<TranslatedCDOCEditor/>
</I18nextProvider>
,
document.getElementById('wrapper')
);