diff --git a/frontend/config/webpack.config.dev.js b/frontend/config/webpack.config.dev.js index 8620f22373..ae37eed6b2 100644 --- a/frontend/config/webpack.config.dev.js +++ b/frontend/config/webpack.config.dev.js @@ -139,6 +139,11 @@ module.exports = { require.resolve('react-dev-utils/webpackHotDevClient'), paths.appSrc + "/view-file-document.js", ], + viewFileSpreadsheet: [ + require.resolve('./polyfills'), + require.resolve('react-dev-utils/webpackHotDevClient'), + paths.appSrc + "/view-file-spreadsheet.js", + ], viewFileSVG: [ require.resolve('./polyfills'), require.resolve('react-dev-utils/webpackHotDevClient'), diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js index 4a050f4d1f..9c58796981 100644 --- a/frontend/config/webpack.config.prod.js +++ b/frontend/config/webpack.config.prod.js @@ -76,6 +76,7 @@ module.exports = { viewFileVideo: [require.resolve('./polyfills'), paths.appSrc + "/view-file-video.js"], viewFilePDF: [require.resolve('./polyfills'), paths.appSrc + "/view-file-pdf.js"], viewFileDocument: [require.resolve('./polyfills'), paths.appSrc + "/view-file-document.js"], + viewFileSpreadsheet: [require.resolve('./polyfills'), paths.appSrc + "/view-file-spreadsheet.js"], viewFileSVG: [require.resolve('./polyfills'), paths.appSrc + "/view-file-svg.js"], viewFileAudio: [require.resolve('./polyfills'), paths.appSrc + "/view-file-audio.js"], orgAdmin: [require.resolve('./polyfills'), paths.appSrc + "/pages/org-admin"], diff --git a/frontend/src/css/spreadsheet-file-view.css b/frontend/src/css/spreadsheet-file-view.css new file mode 100644 index 0000000000..966eee97ad --- /dev/null +++ b/frontend/src/css/spreadsheet-file-view.css @@ -0,0 +1,13 @@ +.spreadsheet-file-view { + overflow: auto; +} +#spreadsheet-container { + display: block; + width: calc(100% - 40px); + max-width: 950px; + min-height: 100%; + margin: 0 auto; + background: #fff; + border: 1px solid #ccc; + box-shadow: 0 0 6px #ccc; +} diff --git a/frontend/src/view-file-document.js b/frontend/src/view-file-document.js index c2f77b667c..d2aa188092 100644 --- a/frontend/src/view-file-document.js +++ b/frontend/src/view-file-document.js @@ -16,7 +16,7 @@ import './css/pdf-file-view.css'; const { isStarred, isLocked, lockedByMe, repoID, filePath, err, enableWatermark, userNickName, // the following are only for this type of file view - commitID + commitID, fileType } = window.app.pageOptions; class ViewFileDocument extends React.Component { @@ -114,7 +114,7 @@ class FileContent extends React.Component { } let queryStatus = () => { - seafileAPI.queryDocumentConvertStatus(repoID, commitID, filePath).then((res) => { + seafileAPI.queryOfficeFileConvertStatus(repoID, commitID, filePath, fileType.toLowerCase()).then((res) => { const convertStatus = res.data['status']; switch (convertStatus) { case 'PROCESSING': diff --git a/frontend/src/view-file-spreadsheet.js b/frontend/src/view-file-spreadsheet.js new file mode 100644 index 0000000000..39e738e9bf --- /dev/null +++ b/frontend/src/view-file-spreadsheet.js @@ -0,0 +1,194 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import watermark from 'watermark-dom'; +import { seafileAPI } from './utils/seafile-api'; +import { siteRoot, siteName, gettext } from './utils/constants'; +import FileInfo from './components/file-view/file-info'; +import FileToolbar from './components/file-view/file-toolbar'; +import FileViewTip from './components/file-view/file-view-tip'; +import CommentPanel from './components/file-view/comment-panel'; +import Loading from './components/loading'; + +import './css/file-view.css'; +import './css/spreadsheet-file-view.css'; + +const { isStarred, isLocked, lockedByMe, + repoID, filePath, err, enableWatermark, userNickName, + // the following are only for this type of file view + commitID, fileType, fileName +} = window.app.pageOptions; + +class ViewFileSpreadsheet extends React.Component { + + constructor(props) { + super(props); + this.state = { + isStarred: isStarred, + isLocked: isLocked, + lockedByMe: lockedByMe, + isCommentPanelOpen: false + }; + } + + toggleCommentPanel = () => { + this.setState({ + isCommentPanelOpen: !this.state.isCommentPanelOpen + }); + } + + toggleStar = () => { + if (this.state.isStarred) { + seafileAPI.unStarItem(repoID, filePath).then((res) => { + this.setState({ + isStarred: false + }); + }); + } else { + seafileAPI.starItem(repoID, filePath).then((res) => { + this.setState({ + isStarred: true + }); + }); + } + } + + toggleLockFile = () => { + if (this.state.isLocked) { + seafileAPI.unlockfile(repoID, filePath).then((res) => { + this.setState({ + isLocked: false, + lockedByMe: false + }); + }); + } else { + seafileAPI.lockfile(repoID, filePath).then((res) => { + this.setState({ + isLocked: true, + lockedByMe: true + }); + }); + } + } + + render() { + return ( +
+
+ + +
+
+ + {this.state.isCommentPanelOpen && + + } +
+
+ ); + } +} + +class FileContent extends React.Component { + + constructor(props) { + super(props); + this.state = { + isLoading: !err, + errorMsg: '' + }; + } + + componentDidMount() { + if (err) { + return; + } + + let queryStatus = () => { + seafileAPI.queryOfficeFileConvertStatus(repoID, commitID, filePath, fileType.toLowerCase()).then((res) => { + const convertStatus = res.data['status']; + switch (convertStatus) { + case 'QUEUED': + case 'PROCESSING': + this.setState({ + isLoading: true + }); + setTimeout(queryStatus, 2000); + break; + case 'ERROR': + this.setState({ + isLoading: false, + errorMsg: gettext('Document convertion failed.') + }); + break; + case 'DONE': + this.setState({ + isLoading: false, + errorMsg: '' + }); + } + }).catch((error) => { + if (error.response) { + this.setState({ + isLoading: false, + errorMsg: gettext('Document convertion failed.') + }); + } else { + this.setState({ + isLoading: false, + errorMsg: gettext('Please check the network.') + }); + } + }); + }; + + queryStatus(); + } + + setIframeHeight = (e) => { + const iframe = e.currentTarget; + iframe.height = iframe.contentDocument.body.scrollHeight; + } + + render() { + const { isLoading, errorMsg } = this.state; + + if (err) { + return ; + } + + if (isLoading) { + return ; + } + + if (errorMsg) { + return ; + } + + return ( +
+ +
+ ); + } +} + +if (enableWatermark) { + watermark.init({ + watermark_txt: `${siteName} ${userNickName}`, + watermark_alpha: 0.075 + }); +} + +ReactDOM.render ( + , + document.getElementById('wrapper') +); diff --git a/seahub/templates/spreadsheet_file_view_react.html b/seahub/templates/spreadsheet_file_view_react.html new file mode 100644 index 0000000000..2294da62c1 --- /dev/null +++ b/seahub/templates/spreadsheet_file_view_react.html @@ -0,0 +1,18 @@ +{% extends 'file_view_react.html' %} +{% load render_bundle from webpack_loader %} +{% load seahub_tags %} + +{% block extra_style %} +{% render_bundle 'viewFileSpreadsheet' 'css' %} +{% endblock %} + +{% block extra_data %} + commitID: '{{ current_commit.id }}' || '{{ repo.head_cmmt_id }}' +{% endblock %} + +{% block render_bundle %} +{% render_bundle 'viewFileSpreadsheet' 'js' %} + +{% endblock %} diff --git a/seahub/views/file.py b/seahub/views/file.py index a9896223ca..2672ee704b 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -768,9 +768,11 @@ def view_lib_file(request, repo_id, path): elif filetype in (DOCUMENT, SPREADSHEET): + template = '%s_file_view_react.html' % filetype.lower() + if repo.encrypted: return_dict['err'] = _(u'The library is encrypted, can not open file online.') - return render(request, 'view_file_base.html', return_dict) + return render(request, template, return_dict) if ENABLE_OFFICE_WEB_APP: action_name = None @@ -835,13 +837,13 @@ def view_lib_file(request, repo_id, path): if not HAS_OFFICE_CONVERTER: return_dict['err'] = "File preview unsupported" - return render(request, 'view_file_base.html', return_dict) + return render(request, template, return_dict) if file_size > OFFICE_PREVIEW_MAX_SIZE: error_msg = _(u'File size surpasses %s, can not be opened online.') % \ filesizeformat(OFFICE_PREVIEW_MAX_SIZE) return_dict['err'] = error_msg - return render(request, 'view_file_base.html', return_dict) + return render(request, template, return_dict) error_msg = prepare_converted_html(inner_path, file_id, fileext, return_dict) if error_msg: @@ -849,9 +851,6 @@ def view_lib_file(request, repo_id, path): return render(request, template, return_dict) send_file_access_msg(request, repo, path, 'web') - # render file preview page - if filetype == DOCUMENT: - template = '%s_file_view_react.html' % filetype.lower() return render(request, template, return_dict) else: return_dict['err'] = "File preview unsupported"