1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-09 10:50:24 +00:00

change menu implatement method

This commit is contained in:
shanshuirenjia
2018-12-11 13:22:52 +08:00
parent 48e855452f
commit ef3d5e5c6f
9 changed files with 85 additions and 166 deletions

View File

@@ -15,10 +15,10 @@ const devServerOptions = Object.assign({}, config.devServer, {
console.log('Dev server options:', devServerOptions); console.log('Dev server options:', devServerOptions);
const server = new WebpackDevServer(compiler, devServerOptions); const server = new WebpackDevServer(compiler, devServerOptions);
server.listen(3001, '0.0.0.0', function (err, result) { server.listen(3000, '0.0.0.0', function (err, result) {
if (err) { if (err) {
console.log(err) console.log(err)
} }
console.log('Listening at 0.0.0.0:3001') console.log('Listening at 0.0.0.0:3000')
}) })

View File

@@ -15,7 +15,7 @@ const BundleTracker = require('webpack-bundle-tracker');
// Webpack uses `publicPath` to determine where the app is being served from. // Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier. // In development, we always serve from the root. This makes config easier.
const publicPath = 'http://127.0.0.1:3001/assets/bundles/'; const publicPath = 'http://127.0.0.1:3000/assets/bundles/';
// `publicUrl` is just like `publicPath`, but we will provide it to our app // `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. // Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.

View File

@@ -180,7 +180,7 @@
"dependencies": { "dependencies": {
"reactstrap": { "reactstrap": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "http://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz", "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-5.0.0.tgz",
"integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==", "integrity": "sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==",
"requires": { "requires": {
"classnames": "^2.2.3", "classnames": "^2.2.3",
@@ -640,7 +640,7 @@
}, },
"axios": { "axios": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": { "requires": {
"follow-redirects": "^1.3.0", "follow-redirects": "^1.3.0",
@@ -10793,9 +10793,9 @@
} }
}, },
"seafile-js": { "seafile-js": {
"version": "0.2.42", "version": "0.2.43",
"resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.42.tgz", "resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.43.tgz",
"integrity": "sha512-qbia7tcIRRtI16ks42ocJHd2i1z7QkfsvqGawATKtrnvij2kXNRnTnZqwbHpSjv1H1yctots+NN9F1JRziHDkQ==", "integrity": "sha512-9Y3pssifTbHMEbsa7aQEHMuiauOZzSj2/L1Z8IhMLBDtO58Zp5wgn4FmDCeNR1tRPGIsJbFYaMOMBjwYGy3p9w==",
"requires": { "requires": {
"axios": "^0.18.0", "axios": "^0.18.0",
"form-data": "^2.3.2", "form-data": "^2.3.2",

View File

@@ -29,7 +29,7 @@
"react-moment": "^0.7.9", "react-moment": "^0.7.9",
"react-select": "^2.1.1", "react-select": "^2.1.1",
"reactstrap": "^6.4.0", "reactstrap": "^6.4.0",
"seafile-js": "^0.2.42", "seafile-js": "^0.2.43",
"seafile-ui": "^0.1.10", "seafile-ui": "^0.1.10",
"sw-precache-webpack-plugin": "0.11.4", "sw-precache-webpack-plugin": "0.11.4",
"unified": "^7.0.0", "unified": "^7.0.0",

View File

@@ -1,12 +1,11 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import moment from 'moment'; import moment from 'moment';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { gettext, siteRoot } from '../../utils/constants'; import { gettext, siteRoot } from '../../utils/constants';
import Toast from '../toast';
import ModalPortal from '../modal-portal'; import ModalPortal from '../modal-portal';
import WikiDeleteDialog from '../dialog/wiki-delete-dialog'; import WikiDeleteDialog from '../dialog/wiki-delete-dialog';
import MenuControl from '../menu-control';
import Toast from '../toast';
import WikiMenu from './wiki-menu';
import WikiRename from './wiki-rename'; import WikiRename from './wiki-rename';
const propTypes = { const propTypes = {
@@ -23,58 +22,42 @@ class WikiListItem extends Component {
super(props); super(props);
this.state = { this.state = {
isShowWikiMenu: false, isShowWikiMenu: false,
position: {top:'', left: ''},
isShowDeleteDialog: false, isShowDeleteDialog: false,
isShowMenuControl: false, isShowMenuControl: false,
isRenameing: false, isRenameing: false,
highlight: '', highlight: false,
}; };
} }
componentDidMount() { clickMenuToggle = (e) => {
document.addEventListener('click', this.onHideWikiMenu); e.preventDefault();
} this.onMenuToggle(e);
componentWillUnmount() {
document.removeEventListener('click', this.onHideWikiMenu);
} }
onMenuToggle = (e) => { onMenuToggle = (e) => {
e.stopPropagation(); let targetType = e.target.dataset.toggle;
e.nativeEvent.stopImmediatePropagation(); if (targetType === 'dropdown') {
if (this.props.isItemFreezed) {
if (this.state.isShowWikiMenu) { this.setState({
this.onHideWikiMenu(); highlight: false,
} else { isShowMenuControl: false,
this.onShowWikiMenu(e); isShowWikiMenu: !this.state.isShowWikiMenu
});
this.props.onUnfreezedItem();
} else {
this.setState({
isShowWikiMenu: !this.state.isShowWikiMenu
});
this.props.onFreezedItem();
}
} }
} }
onShowWikiMenu = (e) => {
let left = e.clientX - 8*16;
let top = e.clientY + 12;
let position = {top: top, left: left};
this.setState({
isShowWikiMenu: true,
position: position,
});
this.props.onFreezedItem();
}
onHideWikiMenu = () => {
this.setState({
isShowWikiMenu: false,
isShowMenuControl: false,
highlight: '',
});
this.props.onUnfreezedItem();
}
onMouseEnter = () => { onMouseEnter = () => {
if (!this.props.isItemFreezed) { if (!this.props.isItemFreezed) {
this.setState({ this.setState({
isShowMenuControl: true, isShowMenuControl: true,
highlight: 'tr-highlight', highlight: true,
}); });
} }
} }
@@ -83,13 +66,12 @@ class WikiListItem extends Component {
if (!this.props.isItemFreezed) { if (!this.props.isItemFreezed) {
this.setState({ this.setState({
isShowMenuControl: false, isShowMenuControl: false,
highlight: '', highlight: false,
}); });
} }
} }
onRenameToggle = (e) => { onRenameToggle = (e) => {
e.nativeEvent.stopImmediatePropagation();
this.props.onFreezedItem(); this.props.onFreezedItem();
this.setState({ this.setState({
isShowWikiMenu: false, isShowWikiMenu: false,
@@ -123,12 +105,21 @@ class WikiListItem extends Component {
this.setState({isRenameing: false}); this.setState({isRenameing: false});
this.props.onUnfreezedItem(); this.props.onUnfreezedItem();
} }
onDeleteToggle = () => { onDeleteToggle = () => {
this.setState({ this.setState({
isShowDeleteDialog: !this.state.isShowDeleteDialog, isShowDeleteDialog: !this.state.isShowDeleteDialog,
isShowWikiMenu: false,
isShowMenuControl: false,
}); });
} }
onDeleteCancel = () => {
this.setState({
isShowDeleteDialog: !this.state.isShowDeleteDialog,
});
this.props.onUnfreezedItem();
}
renameWiki = (newName) => { renameWiki = (newName) => {
let wiki = this.props.wiki; let wiki = this.props.wiki;
@@ -149,7 +140,7 @@ class WikiListItem extends Component {
return ( return (
<Fragment> <Fragment>
<tr className={this.state.highlight} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}> <tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
<td className="name"> <td className="name">
{this.state.isRenameing ? {this.state.isRenameing ?
<WikiRename wiki={wiki} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel}/> : <WikiRename wiki={wiki} onRenameConfirm={this.onRenameConfirm} onRenameCancel={this.onRenameCancel}/> :
@@ -159,23 +150,28 @@ class WikiListItem extends Component {
<td><a href={userProfileURL} target='_blank'>{gettext(wiki.owner_nickname)}</a></td> <td><a href={userProfileURL} target='_blank'>{gettext(wiki.owner_nickname)}</a></td>
<td>{moment(wiki.updated_at).fromNow()}</td> <td>{moment(wiki.updated_at).fromNow()}</td>
<td className="menu-toggle"> <td className="menu-toggle">
<MenuControl {this.state.isShowMenuControl && (
isShow={this.state.isShowMenuControl} <Dropdown isOpen={this.state.isShowWikiMenu} toggle={this.onMenuToggle}>
onClick={this.onMenuToggle} <DropdownToggle
/> tag="a"
{this.state.isShowWikiMenu && className="fas fa-ellipsis-v"
<WikiMenu title={gettext('More Operations')}
position={this.state.position} data-toggle="dropdown"
onRenameToggle={this.onRenameToggle} aria-expanded={this.state.isShowWikiMenu}
onDeleteToggle={this.onDeleteToggle} onClick={this.clickMenuToggle}
/> />
} <DropdownMenu>
<DropdownItem onClick={this.onRenameToggle}>{gettext('Rename')}</DropdownItem>
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Delete')}</DropdownItem>
</DropdownMenu>
</Dropdown>
)}
</td> </td>
</tr> </tr>
{this.state.isShowDeleteDialog && {this.state.isShowDeleteDialog &&
<ModalPortal> <ModalPortal>
<WikiDeleteDialog <WikiDeleteDialog
toggleCancel={this.onDeleteToggle} toggleCancel={this.onDeleteCancel}
handleSubmit={this.deleteWiki} handleSubmit={this.deleteWiki}
/> />
</ModalPortal> </ModalPortal>

View File

@@ -46,7 +46,7 @@ class WikiListView extends Component {
</thead> </thead>
<tbody> <tbody>
{wikis.map((wiki, index) => { {wikis.map((wiki, index) => {
return( return (
<WikiListItem <WikiListItem
key={index} key={index}
wiki={wiki} wiki={wiki}
@@ -55,7 +55,8 @@ class WikiListView extends Component {
isItemFreezed={this.state.isItemFreezed} isItemFreezed={this.state.isItemFreezed}
onFreezedItem={this.onFreezedItem} onFreezedItem={this.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem} onUnfreezedItem={this.onUnfreezedItem}
/>); />
);
})} })}
</tbody> </tbody>
</table> </table>

View File

@@ -1,28 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants';
const propTypes = {
position: PropTypes.object.isRequired,
onRenameToggle: PropTypes.func.isRequired,
onDeleteToggle: PropTypes.func.isRequired,
};
class WikiMenu extends React.Component {
render() {
let position = this.props.position;
let style = {position: 'fixed', top: position.top, left: position.left, display: 'block'};
return (
<ul className="dropdown-menu" style={style}>
<li className="dropdown-item" onClick={this.props.onRenameToggle}>{gettext('Rename')}</li>
<li className="dropdown-item" onClick={this.props.onDeleteToggle}>{gettext('Delete')}</li>
</ul>
);
}
}
WikiMenu.propTypes = propTypes;
export default WikiMenu;

View File

@@ -1,31 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants';
const propTypes = {
isShowWikiAdd: PropTypes.bool.isRequired,
position: PropTypes.object.isRequired,
onSelectToggle: PropTypes.func.isRequired,
onCreateToggle: PropTypes.func.isRequired,
};
class WikiAdd extends React.Component {
render() {
let style = {};
let {isShowWikiAdd, position} = this.props;
if (isShowWikiAdd) {
style = {position: 'fixed', top: position.top, left: position.left, display: 'block'};
}
return (
<ul className="dropdown-menu" style={style}>
<li className="dropdown-item" onClick={this.props.onCreateToggle}>{gettext('New Wiki')}</li>
<li className="dropdown-item" onClick={this.props.onSelectToggle}>{gettext('Choose a library as Wiki')}</li>
</ul>
);
}
}
WikiAdd.propTypes = propTypes;
export default WikiAdd;

View File

@@ -1,8 +1,8 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import { gettext, loginUrl } from '../../utils/constants'; import { gettext, loginUrl } from '../../utils/constants';
import WikiAdd from './wiki-add';
import toaster from '../../components/toast'; import toaster from '../../components/toast';
import ModalPortal from '../../components/modal-portal'; import ModalPortal from '../../components/modal-portal';
import NewWikiDialog from '../../components/dialog/new-wiki-dialog'; import NewWikiDialog from '../../components/dialog/new-wiki-dialog';
@@ -25,14 +25,9 @@ class Wikis extends Component {
} }
componentDidMount() { componentDidMount() {
document.addEventListener('click', this.onHideWikiAdd);
this.getWikis(); this.getWikis();
} }
componentWillUnmount() {
document.removeEventListener('click', this.onHideWikiAdd);
}
getWikis = () => { getWikis = () => {
seafileAPI.listWikis().then(res => { seafileAPI.listWikis().then(res => {
this.setState({ this.setState({
@@ -62,31 +57,13 @@ class Wikis extends Component {
}); });
} }
onAddMenuToggle = (e) => { clickMenuToggle = (e) => {
e.stopPropagation(); e.preventDefault();
e.nativeEvent.stopImmediatePropagation(); this.onMenuToggle();
if (this.state.isShowWikiAdd) {
this.onHideWikiAdd();
} else {
this.onShowWikiAdd(e);
}
} }
onShowWikiAdd = (e) => { onMenuToggle = () => {
let left = e.clientX - 10*20; this.setState({isShowWikiAdd: !this.state.isShowWikiAdd})
let top = e.clientY + 12;
let position = {top: top, left: left};
this.setState({
isShowWikiAdd: true,
position: position,
});
}
onHideWikiAdd = () => {
this.setState({
isShowWikiAdd: false,
});
} }
onSelectToggle = () => { onSelectToggle = () => {
@@ -156,19 +133,23 @@ class Wikis extends Component {
<h3 className="sf-heading">{gettext('Wikis')}</h3> <h3 className="sf-heading">{gettext('Wikis')}</h3>
</div> </div>
<div className="path-toolbar"> <div className="path-toolbar">
<button className="btn btn-secondary operation-item" style={{marginTop: '-0.25rem'}} onClick={this.onAddMenuToggle}> <Dropdown tag="div" className="btn btn-secondary operation-item" style={{marginTop: '-0.25rem'}} isOpen={this.state.isShowWikiAdd} toggle={this.onMenuToggle}>
<i className="fa fa-plus-square op-icon"></i> <DropdownToggle
{gettext('Add Wiki')} tag="i"
</button> className="fa fa-plus-square op-icon"
title={gettext('More Operations')}
data-toggle="dropdown"
aria-expanded={this.state.isShowWikiAdd}
onClick={this.clickMenuToggle}
>
{gettext(' Add Wiki')}
</DropdownToggle>
<DropdownMenu>
<DropdownItem onClick={this.onCreateToggle}>{gettext('New Wiki')}</DropdownItem>
<DropdownItem onClick={this.onSelectToggle}>{gettext('Choose a library as Wiki')}</DropdownItem>
</DropdownMenu>
</Dropdown>
</div> </div>
{this.state.isShowWikiAdd &&
<WikiAdd
isShowWikiAdd={this.state.isShowWikiAdd}
position={this.state.position}
onSelectToggle={this.onSelectToggle}
onCreateToggle={this.onCreateToggle}
/>
}
</div> </div>
<div className="cur-view-content"> <div className="cur-view-content">
{(this.state.loading || this.state.wikis.length !== 0) && {(this.state.loading || this.state.wikis.length !== 0) &&