mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-07 01:41:39 +00:00
replace tree with index content (#2819)
This commit is contained in:
33
frontend/src/components/index-viewer.js
Normal file
33
frontend/src/components/index-viewer.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import MarkdownViewer from '@seafile/seafile-editor/dist/viewer/markdown-viewer';
|
||||||
|
|
||||||
|
const viewerPropTypes = {
|
||||||
|
onLinkClick: PropTypes.func,
|
||||||
|
onContentRendered: PropTypes.func.isRequired,
|
||||||
|
indexContent: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
class IndexContentViewer extends React.Component {
|
||||||
|
|
||||||
|
onLinkClick = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
this.props.onLinkClick(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="markdown-content">
|
||||||
|
<MarkdownViewer
|
||||||
|
markdownContent={this.props.indexContent}
|
||||||
|
onContentRendered={this.props.onContentRendered}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexContentViewer.propTypes = viewerPropTypes;
|
||||||
|
|
||||||
|
export default IndexContentViewer;
|
@@ -34,6 +34,9 @@
|
|||||||
.wiki-pages-container .tree-view {
|
.wiki-pages-container .tree-view {
|
||||||
padding-left:0;
|
padding-left:0;
|
||||||
}
|
}
|
||||||
|
.wiki-pages-container .article {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.wiki-md-viewer-rendered-content {
|
.wiki-md-viewer-rendered-content {
|
||||||
padding: 30px 0 0;
|
padding: 30px 0 0;
|
||||||
@@ -177,6 +180,17 @@ img[src=""] {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wiki-side-nav .markdown-content a {
|
||||||
|
color: #212529;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index-edit {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.25rem;
|
||||||
|
top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.wiki-main-panel .markdown-content .ml-2 {
|
.wiki-main-panel .markdown-content .ml-2 {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext, siteRoot, logoPath, mediaUrl, siteTitle, logoWidth, logoHeight } from '../../utils/constants';
|
import { gettext, siteRoot, logoPath, mediaUrl, siteTitle, logoWidth, logoHeight, repoID } from '../../utils/constants';
|
||||||
import TreeView from '../../components/tree-view/tree-view';
|
import TreeView from '../../components/tree-view/tree-view';
|
||||||
import NodeMenu from '../../components/tree-view/node-menu';
|
import NodeMenu from '../../components/tree-view/node-menu';
|
||||||
import MenuControl from '../../components/menu-control';
|
import MenuControl from '../../components/menu-control';
|
||||||
@@ -8,6 +8,7 @@ import Delete from '../../components/dialog/delete-dialog';
|
|||||||
import Rename from '../../components/dialog/rename-dialog';
|
import Rename from '../../components/dialog/rename-dialog';
|
||||||
import CreateFolder from '../../components/dialog/create-folder-dialog';
|
import CreateFolder from '../../components/dialog/create-folder-dialog';
|
||||||
import CreateFile from '../../components/dialog/create-file-dialog';
|
import CreateFile from '../../components/dialog/create-file-dialog';
|
||||||
|
import IndexContentViewer from '../../components/index-viewer';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
changedNode: PropTypes.object,
|
changedNode: PropTypes.object,
|
||||||
@@ -21,6 +22,11 @@ const propTypes = {
|
|||||||
onDeleteNode: PropTypes.func.isRequired,
|
onDeleteNode: PropTypes.func.isRequired,
|
||||||
onAddFileNode: PropTypes.func.isRequired,
|
onAddFileNode: PropTypes.func.isRequired,
|
||||||
onAddFolderNode: PropTypes.func.isRequired,
|
onAddFolderNode: PropTypes.func.isRequired,
|
||||||
|
onLinkClick: PropTypes.func,
|
||||||
|
hasIndex: PropTypes.bool.isRequired,
|
||||||
|
indexContent: PropTypes.string,
|
||||||
|
indexPath: PropTypes.string,
|
||||||
|
indexPermission: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class SidePanel extends Component {
|
class SidePanel extends Component {
|
||||||
@@ -173,6 +179,15 @@ class SidePanel extends Component {
|
|||||||
this.setState({showRename: !this.state.showRename});
|
this.setState({showRename: !this.state.showRename});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEditClick = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
window.location.href= siteRoot + 'lib/' + repoID + '/file' + this.props.indexPath + '?mode=edit';
|
||||||
|
}
|
||||||
|
|
||||||
|
onContentRendered = () => {
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className={`side-panel wiki-side-panel ${this.props.closeSideBar ? '': 'left-zero'}`}>
|
<div className={`side-panel wiki-side-panel ${this.props.closeSideBar ? '': 'left-zero'}`}>
|
||||||
@@ -183,6 +198,23 @@ class SidePanel extends Component {
|
|||||||
<a title="Close" aria-label="Close" onClick={this.closeSide} className="sf2-icon-x1 sf-popover-close side-panel-close action-icon d-md-none "></a>
|
<a title="Close" aria-label="Close" onClick={this.closeSide} className="sf2-icon-x1 sf-popover-close side-panel-close action-icon d-md-none "></a>
|
||||||
</div>
|
</div>
|
||||||
<div id="side-nav" className="wiki-side-nav" role="navigation">
|
<div id="side-nav" className="wiki-side-nav" role="navigation">
|
||||||
|
{this.props.hasIndex ?
|
||||||
|
<Fragment>
|
||||||
|
<h3 className="wiki-pages-heading">
|
||||||
|
{gettext('Contents')}
|
||||||
|
{this.props.indexPermission === 'rw' &&
|
||||||
|
<button className="btn btn-secondary operation-item index-edit" title="Edit Index" onClick={this.onEditClick}>{gettext('Edit')}</button>
|
||||||
|
}
|
||||||
|
</h3>
|
||||||
|
<div className="wiki-pages-container">
|
||||||
|
<IndexContentViewer
|
||||||
|
onLinkClick={this.props.onLinkClick}
|
||||||
|
onContentRendered={this.onContentRendered}
|
||||||
|
indexContent={this.props.indexContent}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Fragment> :
|
||||||
|
<Fragment>
|
||||||
<h3
|
<h3
|
||||||
className="wiki-pages-heading"
|
className="wiki-pages-heading"
|
||||||
onMouseEnter={this.onMouseEnter}
|
onMouseEnter={this.onMouseEnter}
|
||||||
@@ -248,6 +280,8 @@ class SidePanel extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@@ -30,7 +30,11 @@ class Wiki extends Component {
|
|||||||
permission: '',
|
permission: '',
|
||||||
isFileLoading: false,
|
isFileLoading: false,
|
||||||
changedNode: null,
|
changedNode: null,
|
||||||
isViewFileState: true
|
isViewFileState: true,
|
||||||
|
hasIndex: false,
|
||||||
|
indexContent: '',
|
||||||
|
indexPath: '',
|
||||||
|
indexPermission: '',
|
||||||
};
|
};
|
||||||
window.onpopstate = this.onpopstate;
|
window.onpopstate = this.onpopstate;
|
||||||
}
|
}
|
||||||
@@ -39,6 +43,23 @@ class Wiki extends Component {
|
|||||||
this.initWikiData(initialPath);
|
this.initWikiData(initialPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIndexContent = (files) => {
|
||||||
|
files.some(file => {
|
||||||
|
if (file.type === 'file' && file.name === 'index.md') {
|
||||||
|
let filePath = Utils.joinPath(file.parent_path, file.name);
|
||||||
|
editorUtilities.getWikiFileContent(slug, filePath).then((res) => {
|
||||||
|
this.setState({
|
||||||
|
hasIndex: true,
|
||||||
|
indexContent: res.data.content,
|
||||||
|
indexPath: filePath,
|
||||||
|
indexPermission: res.data.permission,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
initWikiData(filePath){
|
initWikiData(filePath){
|
||||||
this.setState({isFileLoading: true});
|
this.setState({isFileLoading: true});
|
||||||
editorUtilities.getFiles().then((files) => {
|
editorUtilities.getFiles().then((files) => {
|
||||||
@@ -68,6 +89,7 @@ class Wiki extends Component {
|
|||||||
let fileUrl = siteRoot + 'wikis/' + slug + filePath + hash;
|
let fileUrl = siteRoot + 'wikis/' + slug + filePath + hash;
|
||||||
window.history.pushState({urlPath: fileUrl, filePath: filePath}, filePath, fileUrl);
|
window.history.pushState({urlPath: fileUrl, filePath: filePath}, filePath, fileUrl);
|
||||||
}
|
}
|
||||||
|
this.getIndexContent(files);
|
||||||
}, () => {
|
}, () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoadFailed: true
|
isLoadFailed: true
|
||||||
@@ -81,6 +103,7 @@ class Wiki extends Component {
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
content: res.data.content,
|
content: res.data.content,
|
||||||
|
isViewFileState: true,
|
||||||
latestContributor: res.data.latest_contributor,
|
latestContributor: res.data.latest_contributor,
|
||||||
lastModified: moment.unix(res.data.last_modified).fromNow(),
|
lastModified: moment.unix(res.data.last_modified).fromNow(),
|
||||||
permission: res.data.permission,
|
permission: res.data.permission,
|
||||||
@@ -95,7 +118,7 @@ class Wiki extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLinkClick = (event) => {
|
onLinkClick = (event) => {
|
||||||
const url = event.target.href;
|
const url = event.path[2].href;
|
||||||
if (this.isInternalMarkdownLink(url)) {
|
if (this.isInternalMarkdownLink(url)) {
|
||||||
let path = this.getPathFromInternalMarkdownLink(url);
|
let path = this.getPathFromInternalMarkdownLink(url);
|
||||||
this.initMainPanelData(path);
|
this.initMainPanelData(path);
|
||||||
@@ -450,7 +473,7 @@ class Wiki extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isInternalDirLink(url) {
|
isInternalDirLink(url) {
|
||||||
var re = new RegExp(siteRoot + '#[a-z\-]*?/lib/' + repoID + '/.*');
|
var re = new RegExp(siteRoot + 'library/' + repoID + '/.*');
|
||||||
return re.test(url);
|
return re.test(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,11 +485,12 @@ class Wiki extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPathFromInternalDirLink(url) {
|
getPathFromInternalDirLink(url) {
|
||||||
var re = new RegExp(siteRoot + '#[a-z\-]*?/lib/' + repoID + '(/.*)');
|
var re = new RegExp(siteRoot + 'library/' + repoID + '(/.*)');
|
||||||
var array = re.exec(url);
|
var array = re.exec(url);
|
||||||
var path = decodeURIComponent(array[1]);
|
var path = decodeURIComponent(array[1]);
|
||||||
|
|
||||||
var dirPath = path.substring(1);
|
var index = path.substring(1).indexOf('/');
|
||||||
|
var dirPath = path.substring(index + 1);
|
||||||
re = new RegExp('(^/.*)');
|
re = new RegExp('(^/.*)');
|
||||||
if (re.test(dirPath)) {
|
if (re.test(dirPath)) {
|
||||||
path = dirPath;
|
path = dirPath;
|
||||||
@@ -492,6 +516,11 @@ class Wiki extends Component {
|
|||||||
onRenameNode={this.onRenameNode}
|
onRenameNode={this.onRenameNode}
|
||||||
onDeleteNode={this.onDeleteNode}
|
onDeleteNode={this.onDeleteNode}
|
||||||
onDirCollapse={this.onDirCollapse}
|
onDirCollapse={this.onDirCollapse}
|
||||||
|
onLinkClick={this.onLinkClick}
|
||||||
|
hasIndex={this.state.hasIndex}
|
||||||
|
indexContent={this.state.indexContent}
|
||||||
|
indexPath={this.state.indexPath}
|
||||||
|
indexPermission={this.state.indexPermission}
|
||||||
/>
|
/>
|
||||||
<MainPanel
|
<MainPanel
|
||||||
content={this.state.content}
|
content={this.state.content}
|
||||||
|
Reference in New Issue
Block a user