1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-16 23:29:49 +00:00

12.0 refactor wiki codes (#6284)

* 01 change name

* 02 change name

* 03 change name

* 04 change name

* change className
This commit is contained in:
Michael An
2024-07-02 23:09:05 +08:00
committed by GitHub
parent 0dfc67a47f
commit 8874f44a1d
28 changed files with 814 additions and 904 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import { gettext } from '../../../../utils/constants'; import { gettext } from '../../../utils/constants';
export default class DeleteDialog extends React.Component { export default class DeleteDialog extends React.Component {

View File

@@ -0,0 +1,78 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { PopoverBody } from 'reactstrap';
import SeahubPopover from '../../../components/common/seahub-popover';
import { gettext } from '../../../utils/constants';
import '../css/name-edit-popover.css';
class NameEditPopover extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
const txtLength = this.props.oldName.length;
this.inputRef.current.setSelectionRange(0, txtLength);
}
onChangeName = (e) => {
this.props.onChangeName(e.target.value);
};
onEnter = (e) => {
e.preventDefault();
this.props.toggleEditor();
};
handleKeyDown = (e) => {
if (e.keyCode === 13) {
e.preventDefault();
this.props.toggleEditor();
}
};
render() {
return (
<SeahubPopover
placement='bottom-end'
target={this.props.targetId}
hideSeahubPopover={this.props.toggleEditor}
hideSeahubPopoverWithEsc={this.props.toggleEditor}
onEnter={this.onEnter}
hideArrow={true}
popoverClassName="name-edit-popover"
boundariesElement={document.body}
>
<div className="name-edit-popover-header">
<span className='header-text'>{gettext('Modify Name')}</span>
</div>
<PopoverBody className="name-edit-content">
<div className="item-name-editor">
<input
type="text"
className="form-control item-name-editor-input"
value={this.props.oldName}
onChange={this.onChangeName}
autoFocus={true}
ref={this.inputRef}
onKeyDown={this.handleKeyDown}
/>
</div>
</PopoverBody>
</SeahubPopover>
);
}
}
NameEditPopover.propTypes = {
oldName: PropTypes.string,
onChangeName: PropTypes.func,
toggleEditor: PropTypes.func,
targetId: PropTypes.string,
};
export default NameEditPopover;

View File

@@ -2,7 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Icon from '../../../components/icon'; import Icon from '../../../components/icon';
import classNames from 'classnames'; import classNames from 'classnames';
import './nav-item-icon.css';
import '../css/nav-item-icon.css';
function NavItemIcon({ symbol, className, disable, onClick }) { function NavItemIcon({ symbol, className, disable, onClick }) {
return ( return (

View File

@@ -0,0 +1,31 @@
.name-edit-popover .popover {
max-width: 460px;
width: 460px;
left: 140px !important;
}
.name-edit-popover .name-edit-content {
padding: 8px 12px;
}
.name-edit-popover .item-name-editor {
margin-bottom: 7px;
}
.name-edit-popover .item-name-editor-input {
height: 36px;
}
.name-edit-popover-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 12px;
border-bottom: 1px solid rgba(0, 40, 100, 0.12);
height: 40px;
font-size: 14px;
}
.name-edit-popover-header .header-text {
color: #212529;
}

View File

@@ -1,76 +0,0 @@
.view-edit-popover .popover {
max-width: 460px;
width: 460px;
left: 140px !important;
}
.view-edit-popover .view-edit-content {
padding: 8px 12px;
}
.view-edit-popover .view-name-editor {
margin-bottom: 7px;
}
.view-edit-popover .view-name-editor-input {
height: 36px;
}
.view-edit-popover .view-icon-editor {
display: flex;
flex-wrap: wrap;
margin-left: 1px;
}
.view-edit-popover .view-icon-item-editor {
overflow: hidden;
height: 36px;
width: 36px;
border-radius: 6px;
}
.view-edit-popover .view-icon-item-editor .svg-item {
width: 1em;
height: 1em;
font-size: 16px;
color: #999;
}
.view-edit-popover .view-icon-item-editor .view-icon-color-white {
color: #ffffff !important;
}
.view-edit-popover .view-icon-item-editor:hover {
background-color: #f5f5f5;
}
.view-edit-popover .view-icon-item-editor .view-icon-item-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
cursor: pointer;
}
.view-edit-popover-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 12px;
border-bottom: 1px solid rgba(0, 40, 100, 0.12);
height: 40px;
font-size: 14px;
}
.view-edit-popover-header .header-text {
color: #212529;
}
.view-edit-popover-header .remove-icon-button {
color: #ff8000;
}
.view-edit-popover-header .remove-icon-button:hover {
cursor: pointer;
}

View File

@@ -1,401 +0,0 @@
.view-structure {
height: 100%;
display: flex;
flex-direction: column;
}
.views-structure-header {
height: 30px;
min-height: 30px;
padding: 0.25rem 10px;
display: flex;
}
.view-structure-body {
padding-bottom: 0.5rem;
overflow: auto;
user-select: none;
}
.view-structure .view-folder {
position: relative;
}
.view-structure .view-folder.can-drop::after,
.view-structure .view-folder.can-drop-top::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 40px;
background-color: #666;
}
.view-structure .view-folder .view-folder-children {
transition: height 0.25s ease-in-out 0s;
}
.view-structure .view-drop-target {
position: absolute;
left: 0;
width: 100%;
z-index: 1;
border-bottom: 1px solid #666;
}
.view-structure .view-folder.can-drop::after {
top: unset;
bottom: 0;
}
.view-structure .view-folder.can-drop-top::after {
top: 0;
}
.view-structure .view-folder-wrapper,
.view-structure .view-item {
position: relative;
display: flex;
width: 100%;
height: 40px;
padding: 0 8px 0 0;
font-size: 14px;
font-weight: 500;
align-items: center;
justify-content: center;
border-radius: 3px;
background-color: #F7F7F5;
}
.view-structure .view-item.selected-view {
background-color: #EDEDEA;
}
.view-structure .view-folder-wrapper:hover,
.view-structure .view-item:hover {
background-color: #EFEFED;
}
.view-structure .view-item.selected-view:hover {
background-color: #E6E6E4;
}
.view-structure .folder-main,
.view-structure .view-item-main {
flex: 1;
display: flex;
align-items: center;
height: 100%;
overflow: hidden;
}
.view-structure .more-views .folder-main {
padding-left: 20px;
}
.view-structure .icon-expand-folder {
display: inline-block;
font-size: 12px;
transform: scale(0.8);
color: #b5b5b5;
cursor: pointer;
}
.view-structure .folder-content,
.view-structure .view-content {
height: 100%;
padding-right: 8px;
line-height: 1;
display: flex;
align-items: center;
flex: 1;
overflow: hidden;
}
.view-structure .in-folder .view-content {
padding-left: calc(12 * 0.8px + 0.5rem);
}
.view-structure .folder-content:hover,
.view-structure .view-content:hover {
cursor: pointer;
}
.view-structure .folder-content .dtable-font,
.view-structure .view-content .dtable-font {
margin-right: 6px;
font-size: 14px;
}
.view-structure .folder-content .folder-name,
.view-structure .view-content .view-title {
height: 40px;
line-height: 40px;
flex: 1;
}
.view-structure .more-view-folder-operation,
.view-structure .more-view-operation {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.view-structure .wiki-add-page-btn:hover,
.view-structure .more-view-folder-operation:hover,
.view-structure .more-view-operation:hover {
border-radius: 3px;
background-color: #DFDFDD;
}
.view-structure .view-folder-wrapper .more-view-folder-operation .seafile-multicolor-icon-more-level,
.view-structure .view-item .sf3-font.sf3-font-enlarge,
.view-structure .view-item .more-view-operation .seafile-multicolor-icon-more-level {
cursor: pointer;
opacity: 0;
}
.view-structure .view-item:hover .sf3-font.sf3-font-enlarge,
.view-structure .view-folder-wrapper:hover .more-view-folder-operation .seafile-multicolor-icon-more-level,
.view-structure .view-item:hover .more-view-operation .seafile-multicolor-icon-more-level {
opacity: 1;
}
.view-structure .more-view-folder-operation:hover,
.view-structure .more-view-operation:hover {
cursor: pointer;
}
.view-structure .more-view-folder-operation .dtable-font,
.view-structure .more-view-operation .dtable-font {
font-size: 14px;
margin-right: 10px;
}
.view-structure .folder-list .view-folder.fold-freezed .btn-folder-operation,
.view-structure .view-item.view-freezed .sf3-font.sf3-font-enlarge,
.view-structure .view-item.view-freezed .seafile-multicolor-icon-more-level {
opacity: 1;
}
.view-structure-footer {
user-select: none;
}
.view-structure-footer:hover {
background-color: #EFEFED;
}
.view-structure-footer.return-to-app {
position: absolute;
width: 100%;
bottom: 0;
}
.add-view-wrapper {
position: relative;
}
.view-structure-footer .dropdown {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.view-structure-footer .dropdown button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
background-color: transparent !important;
}
.view-structure-footer .dropdown button::after {
display: none !important;
}
.view-structure-footer .dropdown button:focus {
box-shadow: none !important;
}
.view-structure-footer .add-view-btn {
padding: 0 12px;
height: 40px;
border-top: none;
background-color: transparent;
}
.view-structure-footer .add-view-btn .dtable-icon-add-table {
margin-left: 1px;
margin-right: 0.5rem;
transform: unset;
}
.view-sidebar .view-structure-footer .add-view-btn {
border-top: none;
}
/* view operation dropdown */
.view-structure .view-operation-dropdown-toggle {
display: inline-block;
width: 0;
height: 0;
opacity: 0;
}
.view-structure .view-operation-dropdown .view-operation-dropdown-menu {
margin-left: -15px;
margin-top: 4px;
}
.view-operation-dropdown-menu .divider {
margin: 0.2rem 0;
}
/* folders dropdown */
.view-structure .more-view-operation .btn-move-to-folder {
display: flex;
align-items: center;
}
.view-structure .more-view-operation .move-to-folders-toggle {
opacity: 0;
width: 0;
min-width: 0;
margin-left: -12px;
padding: 0;
}
.view-structure .more-view-operation .folders-dropdown-menu {
margin-top: -16px;
margin-left: 10px;
}
.view-structure .folders-dropdown-menu .dropdown-item {
display: flex;
align-items: center;
}
.view-structure .more-view-operation .btn-move-to-folder:focus .dtable-icon-insert-right {
color: #fff;
}
.view-structure .folders-dropdown {
width: 100%;
}
.view-structure .folders-dropdown-toggle {
display: flex;
align-items: center;
}
.view-structure .folders-dropdown .item-text {
flex: 1;
}
.view-structure .folders-dropdown .dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
.view-structure .folders-dropdown .dropdown-menu .folder-name {
display: inline-block;
width: 100%;
}
.view-structure .folders-dropdown .icon-dropdown-toggle {
display: inline-flex;
align-items: center;
width: 12px;
height: 12px;
margin-right: 12px;
}
.view-structure .folders-dropdown .icon-dropdown-toggle .item-icon {
transform: scale(0.8);
}
.view-structure .view-item.view-can-drop::after,
.view-structure .view-item.view-can-drop-top::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 39px;
background-color: #666 !important;
}
.view-structure .view-item.view-can-drop-top::after {
top: 0;
}
.dtable-dropdown-menu .dropdown-item .sf3-font {
font-size: 14px;
margin-right: 10px;
color: #8c8c8c;
}
.dtable-dropdown-menu .dropdown-item:hover .sf3-font {
color: #fff;
}
.dtable-dropdown-menu.large .dropdown-item {
min-height: 32px;
padding: 3px 12px;
display: flex;
align-items: center;
}
/* dark mode */
.view-structure-dark.view-structure,
.view-structure-dark.view-structure .icon-expand-folder {
color: #fff;
}
/* light mode */
.view-structure-light.view-structure,
.view-structure-light.view-structure .icon-expand-folder:hover {
color: #212529;
}
.view-structure-light.view-structure .view-item .sf3-font.sf3-font-enlarge,
.view-structure-light.view-structure .view-item .seafile-multicolor-icon-more-level,
.view-structure-light.view-structure .view-folder .seafile-multicolor-icon-more-level,
.view-structure-light.view-structure .icon-expand-folder {
color: #666;
}
.view-structure .view-folder-wrapper.can-drop-top::before {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 0;
background-color: #666;
}
.view-structure .view-folder-wrapper.can-drop::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
background-color: #666;
top: unset;
bottom: 0;
}
.svg-item {
width: 1em;
height: 1em;
font-size: 16px;
}

View File

@@ -0,0 +1,392 @@
.wiki-nav {
height: 100%;
display: flex;
flex-direction: column;
}
.wiki-nav-header {
height: 30px;
min-height: 30px;
padding: 0.25rem 10px;
display: flex;
}
.wiki-nav-body {
padding-bottom: 0.5rem;
overflow: auto;
user-select: none;
}
.wiki-nav .page-folder {
position: relative;
}
.wiki-nav .page-folder.can-drop::after,
.wiki-nav .page-folder.can-drop-top::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 40px;
background-color: #666;
}
.wiki-nav .page-folder .page-folder-children {
transition: height 0.25s ease-in-out 0s;
}
.wiki-nav .page-drop-target {
position: absolute;
left: 0;
width: 100%;
z-index: 1;
border-bottom: 1px solid #666;
}
.wiki-nav .page-folder.can-drop::after {
top: unset;
bottom: 0;
}
.wiki-nav .page-folder.can-drop-top::after {
top: 0;
}
.wiki-nav .page-folder-wrapper,
.wiki-nav .wiki-page-item {
position: relative;
display: flex;
width: 100%;
height: 40px;
padding: 0 8px 0 0;
font-size: 14px;
font-weight: 500;
align-items: center;
justify-content: center;
border-radius: 3px;
background-color: #F7F7F5;
}
.wiki-nav .wiki-page-item.selected-page {
background-color: #EDEDEA;
}
.wiki-nav .page-folder-wrapper:hover,
.wiki-nav .wiki-page-item:hover {
background-color: #EFEFED;
}
.wiki-nav .wiki-page-item.selected-page:hover {
background-color: #E6E6E4;
}
.wiki-nav .folder-main,
.wiki-nav .wiki-page-item-main {
flex: 1;
display: flex;
align-items: center;
height: 100%;
overflow: hidden;
}
.wiki-nav .icon-expand-folder {
display: inline-block;
font-size: 12px;
transform: scale(0.8);
color: #b5b5b5;
cursor: pointer;
}
.wiki-nav .folder-content,
.wiki-nav .wiki-page-content {
height: 100%;
padding-right: 8px;
line-height: 1;
display: flex;
align-items: center;
flex: 1;
overflow: hidden;
}
.wiki-nav .in-folder .wiki-page-content {
padding-left: calc(12 * 0.8px + 0.5rem);
}
.wiki-nav .folder-content:hover,
.wiki-nav .wiki-page-content:hover {
cursor: pointer;
}
.wiki-nav .folder-content .dtable-font,
.wiki-nav .wiki-page-content .dtable-font {
margin-right: 6px;
font-size: 14px;
}
.wiki-nav .folder-content .folder-name,
.wiki-nav .wiki-page-content .wiki-page-title {
height: 40px;
line-height: 40px;
flex: 1;
}
.wiki-nav .folder-operation-dropdownmenu,
.wiki-nav .more-wiki-page-operation {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.wiki-nav .wiki-add-page-btn:hover,
.wiki-nav .folder-operation:hover,
.wiki-nav .more-wiki-page-operation:hover {
border-radius: 3px;
background-color: #DFDFDD;
}
.wiki-nav .wiki-page-item .sf3-font.sf3-font-enlarge,
.wiki-nav .page-folder-wrapper .folder-operation-dropdownmenu .seafile-multicolor-icon-more-level,
.wiki-nav .wiki-page-item .more-wiki-page-operation .seafile-multicolor-icon-more-level {
cursor: pointer;
opacity: 0;
}
.wiki-nav .wiki-page-item:hover .sf3-font.sf3-font-enlarge,
.wiki-nav .page-folder-wrapper:hover .folder-operation-dropdownmenu .seafile-multicolor-icon-more-level,
.wiki-nav .wiki-page-item:hover .more-wiki-page-operation .seafile-multicolor-icon-more-level {
opacity: 1;
}
.wiki-nav .folder-operation-dropdownmenu:hover,
.wiki-nav .more-wiki-page-operation:hover {
cursor: pointer;
}
.wiki-nav .folder-operation-dropdownmenu .dtable-font,
.wiki-nav .more-wiki-page-operation .dtable-font {
font-size: 14px;
margin-right: 10px;
}
.wiki-nav .folder-list .page-folder.fold-freezed .btn-folder-operation,
.wiki-nav .wiki-page-item.wiki-page-freezed .sf3-font.sf3-font-enlarge,
.wiki-nav .wiki-page-item.wiki-page-freezed .seafile-multicolor-icon-more-level {
opacity: 1;
}
.wiki-nav-footer {
user-select: none;
}
.wiki-nav-footer:hover {
background-color: #EFEFED;
}
.wiki-nav-footer.return-to-app {
position: absolute;
width: 100%;
bottom: 0;
}
.add-wiki-page-wrapper {
position: relative;
}
.wiki-nav-footer .dropdown {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.wiki-nav-footer .dropdown button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
background-color: transparent !important;
}
.wiki-nav-footer .dropdown button::after {
display: none !important;
}
.wiki-nav-footer .dropdown button:focus {
box-shadow: none !important;
}
.wiki-nav-footer .add-wiki-page-btn {
padding: 0 12px;
height: 40px;
border-top: none;
background-color: transparent;
}
.wiki-nav-footer .add-wiki-page-btn .dtable-icon-add-table {
margin-left: 1px;
margin-right: 0.5rem;
transform: unset;
}
.wiki-sidebar .wiki-nav-footer .add-wiki-page-btn {
border-top: none;
}
.wiki-nav .page-operation-dropdown-toggle {
display: inline-block;
width: 0;
height: 0;
opacity: 0;
}
.wiki-nav .page-operation-dropdown .page-operation-dropdown-menu {
margin-left: -15px;
margin-top: 4px;
}
.page-operation-dropdown-menu .divider {
margin: 0.2rem 0;
}
/* folders dropdown */
.wiki-nav .more-wiki-page-operation .btn-move-to-folder {
display: flex;
align-items: center;
}
.wiki-nav .more-wiki-page-operation .move-to-folders-toggle {
opacity: 0;
width: 0;
min-width: 0;
margin-left: -12px;
padding: 0;
}
.wiki-nav .more-wiki-page-operation .folders-dropdown-menu {
margin-top: -16px;
margin-left: 10px;
}
.wiki-nav .folders-dropdown-menu .dropdown-item {
display: flex;
align-items: center;
}
.wiki-nav .more-wiki-page-operation .btn-move-to-folder:focus .dtable-icon-insert-right {
color: #fff;
}
.wiki-nav .folders-dropdown {
width: 100%;
}
.wiki-nav .folders-dropdown-toggle {
display: flex;
align-items: center;
}
.wiki-nav .folders-dropdown .item-text {
flex: 1;
}
.wiki-nav .folders-dropdown .dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
.wiki-nav .folders-dropdown .dropdown-menu .folder-name {
display: inline-block;
width: 100%;
}
.wiki-nav .folders-dropdown .icon-dropdown-toggle {
display: inline-flex;
align-items: center;
width: 12px;
height: 12px;
margin-right: 12px;
}
.wiki-nav .folders-dropdown .icon-dropdown-toggle .item-icon {
transform: scale(0.8);
}
.wiki-nav .wiki-page-item.page-can-drop::after,
.wiki-nav .wiki-page-item.page-can-drop-top::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 39px;
background-color: #666 !important;
}
.wiki-nav .wiki-page-item.page-can-drop-top::after {
top: 0;
}
.dtable-dropdown-menu .dropdown-item .sf3-font {
font-size: 14px;
margin-right: 10px;
color: #8c8c8c;
}
.dtable-dropdown-menu .dropdown-item:hover .sf3-font {
color: #fff;
}
.dtable-dropdown-menu.large .dropdown-item {
min-height: 32px;
padding: 3px 12px;
display: flex;
align-items: center;
}
.wiki-nav,
.wiki-nav .wiki-page-item .sf3-font.sf3-font-enlarge:hover,
.wiki-nav .wiki-page-item .seafile-multicolor-icon-more-level:hover,
.wiki-nav .page-folder .seafile-multicolor-icon-more-level:hover,
.wiki-nav .icon-expand-folder:hover {
color: #212529;
}
.wiki-nav .wiki-page-item .sf3-font.sf3-font-enlarge,
.wiki-nav .wiki-page-item .seafile-multicolor-icon-more-level,
.wiki-nav .page-folder .seafile-multicolor-icon-more-level,
.wiki-nav .icon-expand-folder {
color: #666;
}
.wiki-nav .page-folder-wrapper.can-drop-top::before {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
top: 0;
background-color: #666;
}
.wiki-nav .page-folder-wrapper.can-drop::after {
content: '';
width: 100%;
height: 1px;
position: absolute;
left: 0;
background-color: #666;
top: unset;
bottom: 0;
}
.svg-item {
width: 1em;
height: 1em;
font-size: 16px;
}

View File

@@ -10,7 +10,7 @@ import WikiConfig from './models/wiki-config';
import toaster from '../../components/toast'; import toaster from '../../components/toast';
import SidePanel from './side-panel'; import SidePanel from './side-panel';
import MainPanel from './main-panel'; import MainPanel from './main-panel';
import PageUtils from './view-structure/page-utils'; import PageUtils from './wiki-nav/page-utils';
import LocalStorage from '../../utils/local-storage-utils'; import LocalStorage from '../../utils/local-storage-utils';
import '../../css/layout.css'; import '../../css/layout.css';

View File

@@ -5,11 +5,11 @@ import { UncontrolledTooltip } from 'reactstrap';
import { gettext, isWiki2, wikiId } from '../../utils/constants'; import { gettext, isWiki2, wikiId } from '../../utils/constants';
import toaster from '../../components/toast'; import toaster from '../../components/toast';
import Loading from '../../components/loading'; import Loading from '../../components/loading';
import ViewStructure from './view-structure'; import WikiNav from './wiki-nav/index';
import PageUtils from './view-structure/page-utils'; import PageUtils from './wiki-nav/page-utils';
import NewFolderDialog from './view-structure/new-folder-dialog'; import NewFolderDialog from './wiki-nav/new-folder-dialog';
import AddNewPageDialog from './view-structure/add-new-page-dialog'; import AddNewPageDialog from './wiki-nav/add-new-page-dialog';
import ViewStructureFooter from './view-structure/view-structure-footer'; import WikiNavFooter from './wiki-nav/wiki-nav-footer';
import { generateUniqueId, isObjectNotEmpty } from './utils'; import { generateUniqueId, isObjectNotEmpty } from './utils';
import Folder from './models/folder'; import Folder from './models/folder';
import Page from './models/page'; import Page from './models/page';
@@ -103,10 +103,10 @@ class SidePanel extends Component {
this.props.saveWikiConfig(config, onSuccess, errorCallback); this.props.saveWikiConfig(config, onSuccess, errorCallback);
}; };
movePage = ({ moved_view_id, target_view_id, source_view_folder_id, target_view_folder_id, move_position }) => { movePage = ({ moved_page_id, target_page_id, source_page_folder_id, target_page_folder_id, move_position }) => {
let config = deepCopy(this.props.config); let config = deepCopy(this.props.config);
let { navigation } = config; let { navigation } = config;
PageUtils.movePage(navigation, moved_view_id, target_view_id, source_view_folder_id, target_view_folder_id, move_position); PageUtils.movePage(navigation, moved_page_id, target_page_id, source_page_folder_id, target_page_folder_id, move_position);
config.navigation = navigation; config.navigation = navigation;
this.props.saveWikiConfig(config); this.props.saveWikiConfig(config);
}; };
@@ -279,15 +279,15 @@ class SidePanel extends Component {
const { pages, navigation } = config; const { pages, navigation } = config;
return ( return (
<div className="wiki2-pages-container"> <div className="wiki2-pages-container">
<ViewStructure <WikiNav
isEditMode={isWiki2} isEditMode={isWiki2}
navigation={navigation} navigation={navigation}
views={pages} pages={pages}
onToggleAddView={this.openAddPageDialog} onToggleAddPage={this.openAddPageDialog}
onDeleteView={this.confirmDeletePage} onDeletePage={this.confirmDeletePage}
onUpdatePage={onUpdatePage} onUpdatePage={onUpdatePage}
onSelectView={this.props.setCurrentPage} setCurrentPage={this.props.setCurrentPage}
onMoveView={this.movePage} onMovePage={this.movePage}
movePageOut={this.movePageOut} movePageOut={this.movePageOut}
onToggleAddFolder={this.onToggleAddFolder} onToggleAddFolder={this.onToggleAddFolder}
onModifyFolder={this.onModifyFolder} onModifyFolder={this.onModifyFolder}
@@ -321,8 +321,8 @@ class SidePanel extends Component {
return ( return (
<div className="wiki2-pages-container"> <div className="wiki2-pages-container">
{isWiki2 && {isWiki2 &&
<ViewStructureFooter <WikiNavFooter
onToggleAddView={this.openAddPageDialog} onToggleAddPage={this.openAddPageDialog}
onToggleAddFolder={this.onToggleAddFolder} onToggleAddFolder={this.onToggleAddFolder}
/> />
} }

View File

@@ -1,6 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import NavItemIcon from '../view-structure/nav-item-icon'; import NavItemIcon from '../common/nav-item-icon';
import './index.css'; import './index.css';
// Find the path array from the root to the leaf based on the currentPageId (leaf) // Find the path array from the root to the leaf based on the currentPageId (leaf)

View File

@@ -1,3 +0,0 @@
import ViewStructure from './view-structure';
export default ViewStructure;

View File

@@ -1,86 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { PopoverBody } from 'reactstrap';
import SeahubPopover from '../../../../components/common/seahub-popover';
import { gettext } from '../../../../utils/constants';
import '../../css/view-edit-popover.css';
class ViewEditPopover extends Component {
constructor(props) {
super(props);
this.viewInputRef = React.createRef();
}
componentDidMount() {
const txtLength = this.props.viewName.length;
this.viewInputRef.current.setSelectionRange(0, txtLength);
}
onChangeName = (e) => {
let name = e.target.value;
this.props.onChangeName(name);
};
onEnter = (e) => {
e.preventDefault();
this.props.toggleViewEditor();
};
handleKeyDown = (e) => {
if (e.keyCode === 13) {
e.preventDefault();
this.props.toggleViewEditor();
}
};
renderViewName = () => {
const { viewName } = this.props;
return (
<div className="view-name-editor">
<input
type="text"
className="form-control view-name-editor-input"
value={viewName}
onChange={this.onChangeName}
autoFocus={true}
ref={this.viewInputRef}
onKeyDown={this.handleKeyDown}
/>
</div>
);
};
render() {
return (
<SeahubPopover
placement='bottom-end'
target={this.props.viewEditorId}
hideSeahubPopover={this.props.toggleViewEditor}
hideSeahubPopoverWithEsc={this.props.toggleViewEditor}
onEnter={this.onEnter}
hideArrow={true}
popoverClassName="view-edit-popover"
boundariesElement={document.body}
>
<div className="view-edit-popover-header">
<span className='header-text'>{gettext('Modify Name')}</span>
</div>
<PopoverBody className="view-edit-content">
{this.renderViewName()}
</PopoverBody>
</SeahubPopover>
);
}
}
ViewEditPopover.propTypes = {
viewName: PropTypes.string,
onChangeName: PropTypes.func,
toggleViewEditor: PropTypes.func,
viewEditorId: PropTypes.string,
};
export default ViewEditPopover;

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Dropdown, DropdownMenu, DropdownItem, DropdownToggle } from 'reactstrap'; import { Dropdown, DropdownMenu, DropdownItem, DropdownToggle } from 'reactstrap';
import { gettext } from '../../../utils/constants'; import { gettext } from '../../../utils/constants';
class AddViewDropdownMenu extends Component { class AddPageDropdownMenu extends Component {
toggle = event => { toggle = event => {
this.onStopPropagation(event); this.onStopPropagation(event);
@@ -12,7 +12,7 @@ class AddViewDropdownMenu extends Component {
addPage = event => { addPage = event => {
this.onStopPropagation(event); this.onStopPropagation(event);
this.props.onToggleAddView(null); this.props.onToggleAddPage(null);
}; };
onToggleAddFolder = event => { onToggleAddFolder = event => {
@@ -43,10 +43,10 @@ class AddViewDropdownMenu extends Component {
} }
} }
AddViewDropdownMenu.propTypes = { AddPageDropdownMenu.propTypes = {
toggleDropdown: PropTypes.func, toggleDropdown: PropTypes.func,
onToggleAddView: PropTypes.func, onToggleAddPage: PropTypes.func,
onToggleAddFolder: PropTypes.func, onToggleAddFolder: PropTypes.func,
}; };
export default AddViewDropdownMenu; export default AddPageDropdownMenu;

View File

@@ -40,24 +40,24 @@ const dropTarget = {
if (className.includes('can-drop-top')) { if (className.includes('can-drop-top')) {
move_position = 'move_above'; move_position = 'move_above';
} }
let moveInto = className.includes('dragged-view-over'); let moveInto = className.includes('dragged-page-over');
// 1. drag source is page // 1. drag source is page
if (sourceRow.mode === DRAGGED_PAGE_MODE) { if (sourceRow.mode === DRAGGED_PAGE_MODE) {
const sourceFolderId = sourceRow.folderId; const sourceFolderId = sourceRow.folderId;
const draggedViewId = sourceRow.data.id; const draggedPageId = sourceRow.data.id;
// 1.1 move page into folder // 1.1 move page into folder
if (moveInto) { if (moveInto) {
props.onMoveView({ props.onMovePage({
moved_view_id: draggedViewId, moved_page_id: draggedPageId,
target_view_id: null, target_page_id: null,
source_view_folder_id: sourceFolderId, source_page_folder_id: sourceFolderId,
target_view_folder_id: targetFolderId, target_page_folder_id: targetFolderId,
move_position, move_position,
}); });
return; return;
} else { // 1.2 Drag the page above or below the folder } else { // 1.2 Drag the page above or below the folder
props.movePageOut(draggedViewId, sourceFolderId, targetFolderId, move_position); props.movePageOut(draggedPageId, sourceFolderId, targetFolderId, move_position);
return; return;
} }
} }
@@ -98,6 +98,6 @@ const dropCollect = (connect, monitor) => ({
monitor, monitor,
}); });
export default DropTarget('ViewStructure', dropTarget, dropCollect)( export default DropTarget('WikiNav', dropTarget, dropCollect)(
DragSource('ViewStructure', dragSource, dragCollect)(FolderItem) DragSource('WikiNav', dragSource, dragCollect)(FolderItem)
); );

View File

@@ -2,10 +2,10 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import FolderOperationDropdownMenu from './folder-operation-dropdownmenu'; import FolderOperationDropdownMenu from './folder-operation-dropdownmenu';
import DraggedViewItem from '../views/dragged-view-item'; import DraggedPageItem from '../pages/dragged-page-item';
import DraggedFolderItem from './dragged-folder-item'; import DraggedFolderItem from './dragged-folder-item';
import ViewEditPopover from '../../view-structure/views/view-edit-popover'; import NameEditPopover from '../../common/name-edit-popover';
import NavItemIcon from '../nav-item-icon'; import NavItemIcon from '../../common/nav-item-icon';
class FolderItem extends Component { class FolderItem extends Component {
@@ -53,40 +53,35 @@ class FolderItem extends Component {
changeItemFreeze = (isFreeze) => { changeItemFreeze = (isFreeze) => {
this.isFreeze = true; this.isFreeze = true;
// if (isFreeze) {
// this.foldRef.classList.add('fold-freezed');
// } else {
// this.foldRef.classList.remove('fold-freezed');
// }
}; };
renderFolder = (folder, index, pagesLength, isOnlyOneView, id_view_map) => { renderFolder = (folder, index, pagesLength, isOnlyOnePage, id_page_map) => {
const { isEditMode, views, pathStr } = this.props; const { isEditMode, pages, pathStr } = this.props;
const { id: folderId } = folder; const { id: folderId } = folder;
return ( return (
<DraggedFolderItem <DraggedFolderItem
key={`view-folder-${folderId}`} key={`page-folder-${folderId}`}
isEditMode={isEditMode} isEditMode={isEditMode}
folder={folder} folder={folder}
folderIndex={index} folderIndex={index}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
id_view_map={id_view_map} id_page_map={id_page_map}
renderFolderMenuItems={this.props.renderFolderMenuItems} renderFolderMenuItems={this.props.renderFolderMenuItems}
toggleExpand={this.props.toggleExpand} toggleExpand={this.props.toggleExpand}
onToggleAddView={this.props.onToggleAddView} onToggleAddPage={this.props.onToggleAddPage}
onModifyFolder={this.props.onModifyFolder} onModifyFolder={this.props.onModifyFolder}
onDeleteFolder={this.props.onDeleteFolder} onDeleteFolder={this.props.onDeleteFolder}
onMoveFolder={this.props.onMoveFolder} onMoveFolder={this.props.onMoveFolder}
onSelectView={this.props.onSelectView} setCurrentPage={this.props.setCurrentPage}
onUpdatePage={this.props.onUpdatePage} onUpdatePage={this.props.onUpdatePage}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onDeleteView={this.props.onDeleteView} onDeletePage={this.props.onDeletePage}
onMoveViewToFolder={this.props.onMoveViewToFolder} onMovePageToFolder={this.props.onMovePageToFolder}
onMoveView={this.props.onMoveView} onMovePage={this.props.onMovePage}
moveFolderToFolder={this.props.moveFolderToFolder} moveFolderToFolder={this.props.moveFolderToFolder}
views={views} pages={pages}
pathStr={pathStr + '-' + folderId} pathStr={pathStr + '-' + folderId}
setClassName={this.props.setClassName} setClassName={this.props.setClassName}
getClassName={this.props.getClassName} getClassName={this.props.getClassName}
@@ -99,33 +94,33 @@ class FolderItem extends Component {
); );
}; };
renderView = (view, index, pagesLength, isOnlyOneView) => { renderPage = (page, index, pagesLength, isOnlyOnePage) => {
const { isEditMode, views, folder, pathStr } = this.props; const { isEditMode, pages, folder, pathStr } = this.props;
const id = view.id; const id = page.id;
if (!views.find(item => item.id === id)) return; if (!pages.find(item => item.id === id)) return;
return ( return (
<DraggedViewItem <DraggedPageItem
key={id} key={id}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
infolder={false} infolder={false}
view={Object.assign({}, views.find(item => item.id === id), view)} page={Object.assign({}, pages.find(item => item.id === id), page)}
viewIndex={index} pageIndex={index}
folderId={folder.id} folderId={folder.id}
isEditMode={isEditMode} isEditMode={isEditMode}
renderFolderMenuItems={this.props.renderFolderMenuItems} renderFolderMenuItems={this.props.renderFolderMenuItems}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onSelectView={this.props.onSelectView} setCurrentPage={this.props.setCurrentPage}
onUpdatePage={this.props.onUpdatePage} onUpdatePage={this.props.onUpdatePage}
onDeleteView={this.props.onDeleteView} onDeletePage={this.props.onDeletePage}
onMoveViewToFolder={(targetFolderId) => { onMovePageToFolder={(targetFolderId) => {
this.props.onMoveViewToFolder(folder.id, view.id, targetFolderId); this.props.onMovePageToFolder(folder.id, page.id, targetFolderId);
}} }}
onMoveView={this.props.onMoveView} onMovePage={this.props.onMovePage}
onMoveFolder={this.props.onMoveFolder} onMoveFolder={this.props.onMoveFolder}
views={views} pages={pages}
pathStr={pathStr + '-' + view.id} pathStr={pathStr + '-' + page.id}
currentPageId={this.props.currentPageId} currentPageId={this.props.currentPageId}
addPageInside={this.props.addPageInside} addPageInside={this.props.addPageInside}
getFoldState={this.props.getFoldState} getFoldState={this.props.getFoldState}
@@ -136,14 +131,14 @@ class FolderItem extends Component {
getFolderClassName = (layerDragProps, state) => { getFolderClassName = (layerDragProps, state) => {
if (!state || ! layerDragProps || !layerDragProps.clientOffset) { if (!state || ! layerDragProps || !layerDragProps.clientOffset) {
return 'view-folder-wrapper'; return 'page-folder-wrapper';
} }
let y = layerDragProps.clientOffset.y; let y = layerDragProps.clientOffset.y;
let top = this.foldWrapprRef.getBoundingClientRect().y; let top = this.foldWrapprRef.getBoundingClientRect().y;
let className = ''; let className = '';
// middle // middle
if (top + 10 < y && y < top + 30) { if (top + 10 < y && y < top + 30) {
className += ' dragged-view-over '; className += ' dragged-page-over ';
} }
// top // top
if (top + 10 > y) { if (top + 10 > y) {
@@ -154,7 +149,7 @@ class FolderItem extends Component {
className += ' can-drop '; className += ' can-drop ';
} }
this.props.setClassName(className); this.props.setClassName(className);
return className + 'view-folder-wrapper'; return className + 'page-folder-wrapper';
}; };
getFolderChildrenHeight = () => { getFolderChildrenHeight = () => {
@@ -174,16 +169,16 @@ class FolderItem extends Component {
render() { render() {
const { const {
connectDropTarget, connectDragPreview, connectDragSource, isOver, canDrop, connectDropTarget, connectDragPreview, connectDragSource, isOver, canDrop,
isEditMode, folder, pagesLength, id_view_map, isOnlyOneView, layerDragProps, isEditMode, folder, pagesLength, id_page_map, isOnlyOnePage, layerDragProps,
} = this.props; } = this.props;
const { isEditing } = this.state; const { isEditing } = this.state;
const { id: folderId, name, children } = folder; const { id: folderId, name, children } = folder;
const folded = this.props.getFoldState(folderId); const folded = this.props.getFoldState(folderId);
let viewEditorId = `folder-item-${folderId}`; let navItemId = `folder-item-${folderId}`;
let fn = isEditMode ? connectDragSource : (argu) => {argu;}; let fn = isEditMode ? connectDragSource : (argu) => {argu;};
return ( return (
<div <div
className={classnames('view-folder', { 'readonly': !isEditMode })} className={classnames('page-folder', { 'readonly': !isEditMode })}
ref={ref => this.foldRef = ref} ref={ref => this.foldRef = ref}
onClick={this.toggleExpand} onClick={this.toggleExpand}
> >
@@ -199,7 +194,7 @@ class FolderItem extends Component {
<div <div
className='folder-content' className='folder-content'
style={{ marginLeft: `${(this.props.pathStr.split('-').length - 1) * 16}px` }} style={{ marginLeft: `${(this.props.pathStr.split('-').length - 1) * 16}px` }}
id={viewEditorId} id={navItemId}
> >
{this.state.isMouseEnter ? {this.state.isMouseEnter ?
<div className='nav-item-icon'> <div className='nav-item-icon'>
@@ -210,13 +205,11 @@ class FolderItem extends Component {
} }
<span className='folder-name text-truncate' title={name}>{name}</span> <span className='folder-name text-truncate' title={name}>{name}</span>
{isEditing && {isEditing &&
<ViewEditPopover <NameEditPopover
viewName={this.state.name} oldName={this.state.name}
viewEditorId={viewEditorId} targetId={navItemId}
viewIcon={this.state.icon}
onChangeName={this.onChangeName} onChangeName={this.onChangeName}
onChangeIcon={this.onChangeIcon} toggleEditor={this.closeFolderEditor}
toggleViewEditor={this.closeFolderEditor}
/> />
} }
</div> </div>
@@ -226,7 +219,7 @@ class FolderItem extends Component {
changeItemFreeze={this.changeItemFreeze} changeItemFreeze={this.changeItemFreeze}
openFolderEditor={this.openFolderEditor} openFolderEditor={this.openFolderEditor}
onDeleteFolder={this.props.onDeleteFolder} onDeleteFolder={this.props.onDeleteFolder}
onToggleAddView={this.props.onToggleAddView} onToggleAddPage={this.props.onToggleAddPage}
folderId={folderId} folderId={folderId}
/> />
} }
@@ -235,13 +228,13 @@ class FolderItem extends Component {
)) ))
} }
<div <div
className="view-folder-children" className="page-folder-children"
style={{ height: this.getFolderChildrenHeight() }} style={{ height: this.getFolderChildrenHeight() }}
onClick={this.onClickFolderChildren} onClick={this.onClickFolderChildren}
> >
{!folded && children && {!folded && children &&
children.map((item, index) => { children.map((item, index) => {
return item.type === 'folder' ? this.renderFolder(item, index, pagesLength, isOnlyOneView, id_view_map) : this.renderView(item, index, pagesLength, isOnlyOneView); return item.type === 'folder' ? this.renderFolder(item, index, pagesLength, isOnlyOnePage, id_page_map) : this.renderPage(item, index, pagesLength, isOnlyOnePage);
}) })
} }
</div> </div>
@@ -255,7 +248,7 @@ FolderItem.propTypes = {
folder: PropTypes.object, folder: PropTypes.object,
folderIndex: PropTypes.number, folderIndex: PropTypes.number,
pagesLength: PropTypes.number, pagesLength: PropTypes.number,
id_view_map: PropTypes.object, id_page_map: PropTypes.object,
isOver: PropTypes.bool, isOver: PropTypes.bool,
canDrop: PropTypes.bool, canDrop: PropTypes.bool,
isDragging: PropTypes.bool, isDragging: PropTypes.bool,
@@ -266,16 +259,16 @@ FolderItem.propTypes = {
duplicatePage: PropTypes.func, duplicatePage: PropTypes.func,
onSetFolderId: PropTypes.func, onSetFolderId: PropTypes.func,
toggleExpand: PropTypes.func, toggleExpand: PropTypes.func,
onToggleAddView: PropTypes.func, onToggleAddPage: PropTypes.func,
onModifyFolder: PropTypes.func, onModifyFolder: PropTypes.func,
onDeleteFolder: PropTypes.func, onDeleteFolder: PropTypes.func,
onSelectView: PropTypes.func, setCurrentPage: PropTypes.func,
onUpdatePage: PropTypes.func, onUpdatePage: PropTypes.func,
onDeleteView: PropTypes.func, onDeletePage: PropTypes.func,
onMoveViewToFolder: PropTypes.func, onMovePageToFolder: PropTypes.func,
onMoveView: PropTypes.func, onMovePage: PropTypes.func,
isOnlyOneView: PropTypes.bool, isOnlyOnePage: PropTypes.bool,
views: PropTypes.array, pages: PropTypes.array,
onMoveFolder: PropTypes.func, onMoveFolder: PropTypes.func,
moveFolderToFolder: PropTypes.func, moveFolderToFolder: PropTypes.func,
pathStr: PropTypes.string, pathStr: PropTypes.string,

View File

@@ -10,8 +10,7 @@ export default class FolderOperationDropdownMenu extends Component {
changeItemFreeze: PropTypes.func, changeItemFreeze: PropTypes.func,
openFolderEditor: PropTypes.func, openFolderEditor: PropTypes.func,
onDeleteFolder: PropTypes.func, onDeleteFolder: PropTypes.func,
onToggleAddView: PropTypes.func, onToggleAddPage: PropTypes.func,
onToggleAddArchiveView: PropTypes.func,
folderId: PropTypes.string, folderId: PropTypes.string,
}; };
@@ -45,7 +44,7 @@ export default class FolderOperationDropdownMenu extends Component {
<Dropdown <Dropdown
isOpen={this.state.isMenuShow} isOpen={this.state.isMenuShow}
toggle={this.onDropdownToggle} toggle={this.onDropdownToggle}
className="more-view-folder-operation" className="folder-operation-dropdownmenu"
> >
<DropdownToggle tag="span" data-toggle="dropdown" aria-expanded={this.state.isMenuShow}> <DropdownToggle tag="span" data-toggle="dropdown" aria-expanded={this.state.isMenuShow}>
<Icon symbol={'more-level'}/> <Icon symbol={'more-level'}/>
@@ -56,7 +55,7 @@ export default class FolderOperationDropdownMenu extends Component {
modifiers={{ preventOverflow: { boundariesElement: document.body } }} modifiers={{ preventOverflow: { boundariesElement: document.body } }}
positionFixed={true} positionFixed={true}
> >
<DropdownItem onClick={this.props.onToggleAddView.bind(this, this.props.folderId)}> <DropdownItem onClick={this.props.onToggleAddPage.bind(this, this.props.folderId)}>
<i className="sf3-font sf3-font-file" /> <i className="sf3-font sf3-font-file" />
<span className="item-text">{gettext('Add page')}</span> <span className="item-text">{gettext('Add page')}</span>
</DropdownItem> </DropdownItem>

View File

@@ -0,0 +1,3 @@
import WikiNav from './wiki-nav';
export default WikiNav;

View File

@@ -1,12 +1,12 @@
import { DragSource, DropTarget } from 'react-dnd'; import { DragSource, DropTarget } from 'react-dnd';
import { DRAGGED_FOLDER_MODE, DRAGGED_PAGE_MODE } from '../constant'; import { DRAGGED_FOLDER_MODE, DRAGGED_PAGE_MODE } from '../constant';
import ViewItem from './view-item'; import PageItem from './page-item';
const dragSource = { const dragSource = {
beginDrag: props => { beginDrag: props => {
return { return {
idx: props.viewIndex, idx: props.pageIndex,
data: { ...props.view, index: props.viewIndex }, data: { ...props.page, index: props.pageIndex },
folderId: props.folderId, folderId: props.folderId,
mode: DRAGGED_PAGE_MODE, mode: DRAGGED_PAGE_MODE,
}; };
@@ -20,7 +20,7 @@ const dragSource = {
} }
}, },
isDragging(props) { isDragging(props) {
const { draggedPage, viewIndex: targetIndex } = props; const { draggedPage, pageIndex: targetIndex } = props;
const { idx } = draggedPage; const { idx } = draggedPage;
return idx > targetIndex; return idx > targetIndex;
} }
@@ -31,12 +31,12 @@ const dropTarget = {
const sourceRow = monitor.getItem(); const sourceRow = monitor.getItem();
// 1 drag page // 1 drag page
if (sourceRow.mode === DRAGGED_PAGE_MODE) { if (sourceRow.mode === DRAGGED_PAGE_MODE) {
const { infolder, viewIndex: targetIndex, view: targetView, folderId: targetFolderId } = props; const { infolder, pageIndex: targetIndex, page: targetPage, folderId: targetFolderId } = props;
const sourceFolderId = sourceRow.folderId; const sourceFolderId = sourceRow.folderId;
const draggedViewId = sourceRow.data.id; const draggedPageId = sourceRow.data.id;
const targetViewId = targetView.id; const targetPageId = targetPage.id;
if (draggedViewId !== targetViewId) { if (draggedPageId !== targetPageId) {
const sourceIndex = sourceRow.idx; const sourceIndex = sourceRow.idx;
let move_position; let move_position;
if (infolder) { if (infolder) {
@@ -45,11 +45,11 @@ const dropTarget = {
move_position = sourceIndex > targetIndex ? 'move_above' : 'move_below'; move_position = sourceIndex > targetIndex ? 'move_above' : 'move_below';
} }
props.onMoveView({ props.onMovePage({
moved_view_id: draggedViewId, moved_page_id: draggedPageId,
target_view_id: targetViewId, target_page_id: targetPageId,
source_view_folder_id: sourceFolderId, source_page_folder_id: sourceFolderId,
target_view_folder_id: targetFolderId, target_page_folder_id: targetFolderId,
move_position, move_position,
}); });
} }
@@ -57,15 +57,15 @@ const dropTarget = {
} }
// 1 drag folder // 1 drag folder
if (sourceRow.mode === DRAGGED_FOLDER_MODE) { if (sourceRow.mode === DRAGGED_FOLDER_MODE) {
const { viewIndex: targetIndex, view: targetView } = props; const { pageIndex: targetIndex, page: targetPage } = props;
const draggedFolderId = sourceRow.data.id; const draggedFolderId = sourceRow.data.id;
const targetViewId = targetView.id; const targetPageId = targetPage.id;
const sourceIndex = sourceRow.idx; const sourceIndex = sourceRow.idx;
// Drag the parent folder to the child page, return // Drag the parent folder to the child page, return
if (props.pathStr.split('-').includes(draggedFolderId)) return; if (props.pathStr.split('-').includes(draggedFolderId)) return;
props.onMoveFolder( props.onMoveFolder(
draggedFolderId, draggedFolderId,
targetViewId, targetPageId,
sourceIndex > targetIndex ? 'move_above' : 'move_below', sourceIndex > targetIndex ? 'move_above' : 'move_below',
); );
return; return;
@@ -86,6 +86,6 @@ const dropCollect = (connect, monitor) => ({
draggedPage: monitor.getItem() draggedPage: monitor.getItem()
}); });
export default DropTarget('ViewStructure', dropTarget, dropCollect)( export default DropTarget('WikiNav', dropTarget, dropCollect)(
DragSource('ViewStructure', dragSource, dragCollect)(ViewItem) DragSource('WikiNav', dragSource, dragCollect)(PageItem)
); );

View File

@@ -8,21 +8,20 @@ import { getWikPageLink } from '../../utils';
export default class PageDropdownMenu extends Component { export default class PageDropdownMenu extends Component {
static propTypes = { static propTypes = {
view: PropTypes.object.isRequired, page: PropTypes.object.isRequired,
views: PropTypes.array, pages: PropTypes.array,
pagesLength: PropTypes.number, pagesLength: PropTypes.number,
folderId: PropTypes.string, folderId: PropTypes.string,
canDelete: PropTypes.bool, canDelete: PropTypes.bool,
canDuplicate: PropTypes.bool, canDuplicate: PropTypes.bool,
renderFolderMenuItems: PropTypes.func, renderFolderMenuItems: PropTypes.func,
toggle: PropTypes.func, toggle: PropTypes.func,
toggleViewEditor: PropTypes.func, toggleNameEditor: PropTypes.func,
duplicatePage: PropTypes.func, duplicatePage: PropTypes.func,
onSetFolderId: PropTypes.func, onSetFolderId: PropTypes.func,
onDeleteView: PropTypes.func, onDeletePage: PropTypes.func,
onModifyViewType: PropTypes.func, onMovePageToFolder: PropTypes.func,
onMoveViewToFolder: PropTypes.func, isOnlyOnePage: PropTypes.bool,
isOnlyOneView: PropTypes.bool,
}; };
constructor(props) { constructor(props) {
@@ -34,9 +33,9 @@ export default class PageDropdownMenu extends Component {
} }
calculateNameMap = () => { calculateNameMap = () => {
const { views } = this.props; const { pages } = this.props;
return views.reduce((map, view) => { return pages.reduce((map, page) => {
map[view.name] = true; map[page.name] = true;
return map; return map;
}, {}); }, {});
}; };
@@ -49,28 +48,23 @@ export default class PageDropdownMenu extends Component {
this.props.toggle(); this.props.toggle();
}; };
onRenameView = (event) => { onRename = (event) => {
event.nativeEvent.stopImmediatePropagation(); event.nativeEvent.stopImmediatePropagation();
this.props.toggleViewEditor(); this.props.toggleNameEditor();
}; };
onDeleteView = (event) => { onDeletePage = (event) => {
event.nativeEvent.stopImmediatePropagation(); event.nativeEvent.stopImmediatePropagation();
this.props.onDeleteView(); this.props.onDeletePage();
}; };
onModifyViewType = (event) => { onMovePageToFolder = (targetFolderId) => {
event.nativeEvent.stopImmediatePropagation(); this.props.onMovePageToFolder(targetFolderId);
this.props.onModifyViewType();
};
onMoveViewToFolder = (targetFolderId) => {
this.props.onMoveViewToFolder(targetFolderId);
}; };
onRemoveFromFolder = (evt) => { onRemoveFromFolder = (evt) => {
evt.nativeEvent.stopImmediatePropagation(); evt.nativeEvent.stopImmediatePropagation();
this.props.onMoveViewToFolder(null); this.props.onMovePageToFolder(null);
}; };
onToggleFoldersMenu = () => { onToggleFoldersMenu = () => {
@@ -78,8 +72,8 @@ export default class PageDropdownMenu extends Component {
}; };
duplicatePage = () => { duplicatePage = () => {
const { view, folderId } = this.props; const { page, folderId } = this.props;
const { id: from_page_id, name } = view; const { id: from_page_id, name } = page;
let duplicateCount = 1; let duplicateCount = 1;
let newName = name + '(copy)'; let newName = name + '(copy)';
while (this.pageNameMap[newName]) { while (this.pageNameMap[newName]) {
@@ -104,8 +98,8 @@ export default class PageDropdownMenu extends Component {
}; };
handleCopyLink = () => { handleCopyLink = () => {
const { view } = this.props; const { page } = this.props;
const wikiLink = getWikPageLink(view.id); const wikiLink = getWikPageLink(page.id);
const successText = gettext('Copied link to clipboard'); const successText = gettext('Copied link to clipboard');
const failedText = gettext('Copy failed'); const failedText = gettext('Copy failed');
@@ -117,26 +111,26 @@ export default class PageDropdownMenu extends Component {
}; };
handleOpenInNewTab = () => { handleOpenInNewTab = () => {
const { view } = this.props; const { page } = this.props;
const wikiLink = getWikPageLink(view.id); const wikiLink = getWikPageLink(page.id);
window.open(wikiLink); window.open(wikiLink);
}; };
render() { render() {
const { const {
folderId, canDelete, canDuplicate, renderFolderMenuItems, pagesLength, isOnlyOneView, folderId, canDelete, canDuplicate, renderFolderMenuItems, pagesLength, isOnlyOnePage,
} = this.props; } = this.props;
const folderMenuItems = renderFolderMenuItems && renderFolderMenuItems({ currentFolderId: folderId, onMoveViewToFolder: this.onMoveViewToFolder }); const folderMenuItems = renderFolderMenuItems && renderFolderMenuItems({ currentFolderId: folderId, onMovePageToFolder: this.onMovePageToFolder });
return ( return (
<Dropdown <Dropdown
isOpen={true} isOpen={true}
toggle={this.onDropdownToggle} toggle={this.onDropdownToggle}
className="view-operation-dropdown" className="page-operation-dropdown"
> >
<DropdownToggle className="view-operation-dropdown-toggle" tag="span" data-toggle="dropdown"></DropdownToggle> <DropdownToggle className="page-operation-dropdown-toggle" tag="span" data-toggle="dropdown"></DropdownToggle>
<DropdownMenu <DropdownMenu
className="view-operation-dropdown-menu dtable-dropdown-menu large" className="page-operation-dropdown-menu dtable-dropdown-menu large"
flip={false} flip={false}
modifiers={{ preventOverflow: { boundariesElement: document.body } }} modifiers={{ preventOverflow: { boundariesElement: document.body } }}
positionFixed={true} positionFixed={true}
@@ -145,7 +139,7 @@ export default class PageDropdownMenu extends Component {
<i className="sf3-font sf3-font-link" /> <i className="sf3-font sf3-font-link" />
<span className="item-text">{gettext('Copy link')}</span> <span className="item-text">{gettext('Copy link')}</span>
</DropdownItem> </DropdownItem>
<DropdownItem onClick={this.onRenameView}> <DropdownItem onClick={this.onRename}>
<i className="sf3-font sf3-font-rename" /> <i className="sf3-font sf3-font-rename" />
<span className="item-text">{gettext('Modify name')}</span> <span className="item-text">{gettext('Modify name')}</span>
</DropdownItem> </DropdownItem>
@@ -155,8 +149,8 @@ export default class PageDropdownMenu extends Component {
<span className="item-text">{gettext('Duplicate page')}</span> <span className="item-text">{gettext('Duplicate page')}</span>
</DropdownItem> </DropdownItem>
} }
{(isOnlyOneView || pagesLength === 1 || !canDelete) ? '' : ( {(isOnlyOnePage || pagesLength === 1 || !canDelete) ? '' : (
<DropdownItem onClick={this.onDeleteView}> <DropdownItem onClick={this.onDeletePage}>
<i className="sf3-font sf3-font-delete1" /> <i className="sf3-font sf3-font-delete1" />
<span className="item-text">{gettext('Delete page')}</span> <span className="item-text">{gettext('Delete page')}</span>
</DropdownItem> </DropdownItem>

View File

@@ -1,30 +1,30 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import ViewEditPopover from './view-edit-popover'; import NameEditPopover from '../../common/name-edit-popover';
import NavItemIcon from '../../common/nav-item-icon';
import PageDropdownMenu from './page-dropdownmenu'; import PageDropdownMenu from './page-dropdownmenu';
import DeleteDialog from './delete-dialog'; import DeleteDialog from '../../common/delete-dialog';
import { gettext } from '../../../../utils/constants'; import { gettext } from '../../../../utils/constants';
import AddNewPageDialog from '../add-new-page-dialog'; import AddNewPageDialog from '../add-new-page-dialog';
import Icon from '../../../../components/icon'; import Icon from '../../../../components/icon';
import NavItemIcon from '../nav-item-icon'; import DraggedPageItem from './dragged-page-item';
import DraggedViewItem from '../views/dragged-view-item';
class ViewItem extends Component { class PageItem extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isShowViewEditor: false, isShowNameEditor: false,
isShowViewOperationDropdown: false, isShowOperationDropdown: false,
isShowDeleteDialog: false, isShowDeleteDialog: false,
isShowInsertPage: false, isShowInsertPage: false,
viewName: props.view.name || '', pageName: props.page.name || '',
viewIcon: props.view.icon, pageIcon: props.page.icon,
isSelected: props.currentPageId === props.view.id, isSelected: props.currentPageId === props.page.id,
isMouseEnter: false, isMouseEnter: false,
}; };
this.viewItemRef = React.createRef(); this.pageItemRef = React.createRef();
} }
onMouseEnter = () => { onMouseEnter = () => {
@@ -43,18 +43,18 @@ class ViewItem extends Component {
onCurrentPageChanged = (currentPageId) => { onCurrentPageChanged = (currentPageId) => {
const { isSelected } = this.state; const { isSelected } = this.state;
if (currentPageId === this.props.view.id && isSelected === false) { if (currentPageId === this.props.page.id && isSelected === false) {
this.setState({ isSelected: true }); this.setState({ isSelected: true });
} else if (currentPageId !== this.props.view.id && isSelected === true) { } else if (currentPageId !== this.props.page.id && isSelected === true) {
this.setState({ isSelected: false }); this.setState({ isSelected: false });
} }
}; };
toggleViewEditor = (e) => { toggleNameEditor = (e) => {
if (e) e.stopPropagation(); if (e) e.stopPropagation();
this.setState({ isShowViewEditor: !this.state.isShowViewEditor }, () => { this.setState({ isShowNameEditor: !this.state.isShowNameEditor }, () => {
if (!this.state.isShowViewEditor) { if (!this.state.isShowNameEditor) {
this.saveViewProperties(); this.savePageProperties();
} }
}); });
}; };
@@ -63,28 +63,28 @@ class ViewItem extends Component {
this.setState({ isShowInsertPage: !this.state.isShowInsertPage }); this.setState({ isShowInsertPage: !this.state.isShowInsertPage });
}; };
saveViewProperties = () => { savePageProperties = () => {
const { name, icon, id } = this.props.view; const { name, icon, id } = this.props.page;
const { viewIcon } = this.state; const { pageIcon } = this.state;
let viewName = this.state.viewName.trim(); let pageName = this.state.pageName.trim();
if (viewIcon !== icon || viewName !== name) { if (pageIcon !== icon || pageName !== name) {
let newView = {}; let newView = {};
if (viewName !== name) { if (pageName !== name) {
newView.name = viewName; newView.name = pageName;
} }
if (viewIcon !== icon) { if (pageIcon !== icon) {
newView.icon = viewIcon; newView.icon = pageIcon;
} }
this.props.onUpdatePage(id, newView); this.props.onUpdatePage(id, newView);
} }
}; };
onChangeName = (newViewName) => { onChangeName = (newName) => {
this.setState({ viewName: newViewName }); this.setState({ pageName: newName });
}; };
onChangeIcon = (newViewIcon) => { onChangeIcon = (newIcon) => {
this.setState({ viewIcon: newViewIcon }); this.setState({ pageIcon: newIcon });
}; };
openDeleteDialog = () => { openDeleteDialog = () => {
@@ -95,28 +95,17 @@ class ViewItem extends Component {
this.setState({ isShowDeleteDialog: false }); this.setState({ isShowDeleteDialog: false });
}; };
onViewOperationDropdownToggle = () => { toggleDropdown = () => {
const isShowViewOperationDropdown = !this.state.isShowViewOperationDropdown; const isShowOperationDropdown = !this.state.isShowOperationDropdown;
this.setState({ isShowViewOperationDropdown }); this.setState({ isShowOperationDropdown });
this.changeItemFreeze(isShowViewOperationDropdown); this.changeItemFreeze(isShowOperationDropdown);
}; };
changeItemFreeze = (isFreeze) => { changeItemFreeze = (isFreeze) => {
if (isFreeze) { if (isFreeze) {
this.viewItemRef.classList.add('view-freezed'); this.pageItemRef.classList.add('wiki-page-freezed');
} else { } else {
this.viewItemRef.classList.remove('view-freezed'); this.pageItemRef.classList.remove('wiki-page-freezed');
}
};
renderIcon = (icon) => {
if (!icon) {
return null;
}
if (icon.includes('dtable-icon')) {
return <span className={`mr-2 dtable-font ${icon}`}></span>;
} else {
return <Icon className="mr-2" symbol={icon}/>;
} }
}; };
@@ -125,7 +114,7 @@ class ViewItem extends Component {
}; };
getFolderChildrenHeight = () => { getFolderChildrenHeight = () => {
const folded = this.props.getFoldState(this.props.view.id); const folded = this.props.getFoldState(this.props.page.id);
if (folded) return 0; if (folded) return 0;
return 'auto'; return 'auto';
}; };
@@ -135,33 +124,33 @@ class ViewItem extends Component {
e.nativeEvent.stopImmediatePropagation(); e.nativeEvent.stopImmediatePropagation();
}; };
renderView = (view, index, pagesLength, isOnlyOneView) => { renderPage = (page, index, pagesLength, isOnlyOnePage) => {
const { isEditMode, views, folderId, pathStr } = this.props; const { isEditMode, pages, folderId, pathStr } = this.props;
const id = view.id; const id = page.id;
if (!views.find(item => item.id === id)) return; if (!pages.find(item => item.id === id)) return;
return ( return (
<DraggedViewItem <DraggedPageItem
key={id} key={id}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
infolder={false} infolder={false}
view={Object.assign({}, views.find(item => item.id === id), view)} page={Object.assign({}, pages.find(item => item.id === id), page)}
viewIndex={index} pageIndex={index}
folderId={folderId} folderId={folderId}
isEditMode={isEditMode} isEditMode={isEditMode}
renderFolderMenuItems={this.props.renderFolderMenuItems} renderFolderMenuItems={this.props.renderFolderMenuItems}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onSelectView={this.props.onSelectView} setCurrentPage={this.props.setCurrentPage}
onUpdatePage={this.props.onUpdatePage} onUpdatePage={this.props.onUpdatePage}
onDeleteView={this.props.onDeleteView} onDeletePage={this.props.onDeletePage}
onMoveViewToFolder={(targetFolderId) => { onMovePageToFolder={(targetFolderId) => {
this.props.onMoveViewToFolder(folderId, view.id, targetFolderId); this.props.onMovePageToFolder(folderId, page.id, targetFolderId);
}} }}
onMoveView={this.props.onMoveView} onMovePage={this.props.onMovePage}
onMoveFolder={this.props.onMoveFolder} onMoveFolder={this.props.onMoveFolder}
views={views} pages={pages}
pathStr={pathStr + '-' + view.id} pathStr={pathStr + '-' + page.id}
currentPageId={this.props.currentPageId} currentPageId={this.props.currentPageId}
addPageInside={this.props.addPageInside} addPageInside={this.props.addPageInside}
getFoldState={this.props.getFoldState} getFoldState={this.props.getFoldState}
@@ -172,58 +161,57 @@ class ViewItem extends Component {
toggleExpand = (e) => { toggleExpand = (e) => {
e.nativeEvent.stopImmediatePropagation(); e.nativeEvent.stopImmediatePropagation();
this.props.toggleExpand(this.props.view.id); this.props.toggleExpand(this.props.page.id);
this.forceUpdate(); this.forceUpdate();
}; };
onAddNewPage = (newPage) => { onAddNewPage = (newPage) => {
const { view } = this.props; this.props.addPageInside(Object.assign({ parentPageId: this.props.page.id }, newPage));
this.props.addPageInside(Object.assign({ parentPageId: view.id }, newPage));
}; };
render() { render() {
const { const {
connectDragSource, connectDragPreview, connectDropTarget, isOver, canDrop, isDragging, connectDragSource, connectDragPreview, connectDropTarget, isOver, canDrop, isDragging,
infolder, view, pagesLength, isEditMode, folderId, isOnlyOneView, pathStr, infolder, page, pagesLength, isEditMode, folderId, isOnlyOnePage, pathStr,
} = this.props; } = this.props;
const { isShowViewEditor, viewName, viewIcon, isSelected } = this.state; const { isShowNameEditor, pageName, isSelected } = this.state;
const isOverView = isOver && canDrop; const isOverPage = isOver && canDrop;
if (isSelected) this.setDocUuid(view.docUuid); if (isSelected) this.setDocUuid(page.docUuid);
let viewCanDropTop; let pageCanDropTop;
let viewCanDrop; let pageCanDrop;
if (infolder) { if (infolder) {
viewCanDropTop = false; pageCanDropTop = false;
viewCanDrop = isOverView; pageCanDrop = isOverPage;
} else { } else {
viewCanDropTop = isOverView && isDragging; pageCanDropTop = isOverPage && isDragging;
viewCanDrop = isOverView && !isDragging; pageCanDrop = isOverPage && !isDragging;
} }
let viewEditorId = `view-editor-${view.id}`; let navItemId = `page-editor-${page.id}`;
let fn = isEditMode ? connectDragSource : (argu) => {argu;}; let fn = isEditMode ? connectDragSource : (argu) => {argu;};
let childNumber = Array.isArray(view.children) ? view.children.length : 0; let childNumber = Array.isArray(page.children) ? page.children.length : 0;
const folded = this.props.getFoldState(view.id); const folded = this.props.getFoldState(page.id);
return ( return (
<div> <div>
{ {
fn(connectDropTarget( fn(connectDropTarget(
connectDragPreview( connectDragPreview(
<div <div
className={classnames('view-item', 'view', className={classnames('wiki-page-item',
{ 'selected-view': isSelected }, { 'selected-page': isSelected },
{ 'view-can-drop-top': viewCanDropTop }, { 'page-can-drop-top': pageCanDropTop },
{ 'view-can-drop': viewCanDrop }, { 'page-can-drop': pageCanDrop },
{ 'readonly': !isEditMode }, { 'readonly': !isEditMode },
)} )}
ref={ref => this.viewItemRef = ref} ref={ref => this.pageItemRef = ref}
onMouseEnter={this.onMouseEnter} onMouseEnter={this.onMouseEnter}
onMouseMove={this.onMouseMove} onMouseMove={this.onMouseMove}
onMouseLeave={this.onMouseLeave} onMouseLeave={this.onMouseLeave}
id={viewEditorId} id={navItemId}
> >
<div className="view-item-main" onClick={isShowViewEditor ? () => {} : (e) => this.props.onSelectView(view.id)}> <div className="wiki-page-item-main" onClick={isShowNameEditor ? () => {} : (e) => this.props.setCurrentPage(page.id)}>
<div className='view-content' style={pathStr ? { marginLeft: `${(pathStr.split('-').length - 1) * 24}px` } : {}}> <div className='wiki-page-content' style={pathStr ? { marginLeft: `${(pathStr.split('-').length - 1) * 24}px` } : {}}>
{childNumber === 0 && {childNumber === 0 &&
<NavItemIcon symbol={'file'} disable={true} /> <NavItemIcon symbol={'file'} disable={true} />
} }
@@ -235,16 +223,13 @@ class ViewItem extends Component {
<i className={`sf3-font-down sf3-font ${folded ? 'rotate-270' : ''}`}></i> <i className={`sf3-font-down sf3-font ${folded ? 'rotate-270' : ''}`}></i>
</div> </div>
} }
{/* {this.renderIcon(view.icon)} */} <span className="wiki-page-title text-truncate" title={page.name}>{page.name}</span>
<span className="view-title text-truncate" title={view.name}>{view.name}</span> {isShowNameEditor && (
{isShowViewEditor && ( <NameEditPopover
<ViewEditPopover oldName={pageName}
viewName={viewName} targetId={navItemId}
viewIcon={viewIcon}
viewEditorId={viewEditorId}
onChangeName={this.onChangeName} onChangeName={this.onChangeName}
onChangeIcon={this.onChangeIcon} toggleEditor={this.toggleNameEditor}
toggleViewEditor={this.toggleViewEditor}
/> />
)} )}
</div> </div>
@@ -252,24 +237,24 @@ class ViewItem extends Component {
<div className="d-flex"> <div className="d-flex">
{isEditMode && {isEditMode &&
<> <>
<div className="more-view-operation" onClick={this.onViewOperationDropdownToggle}> <div className="more-wiki-page-operation" onClick={this.toggleDropdown}>
<Icon symbol={'more-level'}/> <Icon symbol={'more-level'}/>
{this.state.isShowViewOperationDropdown && {this.state.isShowOperationDropdown &&
<PageDropdownMenu <PageDropdownMenu
view={view} page={page}
views={this.props.views} pages={this.props.pages}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
folderId={folderId} folderId={folderId}
canDelete={true} canDelete={true}
canDuplicate={true} canDuplicate={true}
toggle={this.onViewOperationDropdownToggle} toggle={this.toggleDropdown}
renderFolderMenuItems={this.props.renderFolderMenuItems} renderFolderMenuItems={this.props.renderFolderMenuItems}
toggleViewEditor={this.toggleViewEditor} toggleNameEditor={this.toggleNameEditor}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onDeleteView={this.openDeleteDialog} onDeletePage={this.openDeleteDialog}
onMoveViewToFolder={this.props.onMoveViewToFolder} onMovePageToFolder={this.props.onMovePageToFolder}
/> />
} }
</div> </div>
@@ -282,7 +267,7 @@ class ViewItem extends Component {
{this.state.isShowDeleteDialog && {this.state.isShowDeleteDialog &&
<DeleteDialog <DeleteDialog
closeDeleteDialog={this.closeDeleteDialog} closeDeleteDialog={this.closeDeleteDialog}
handleSubmit={this.props.onDeleteView.bind(this, view.id)} handleSubmit={this.props.onDeletePage.bind(this, page.id)}
/> />
} }
{this.state.isShowInsertPage && {this.state.isShowInsertPage &&
@@ -297,13 +282,13 @@ class ViewItem extends Component {
)) ))
} }
<div <div
className="view-folder-children" className="page-folder-children"
style={{ height: this.getFolderChildrenHeight() }} style={{ height: this.getFolderChildrenHeight() }}
onClick={this.onClickFolderChildren} onClick={this.onClickFolderChildren}
> >
{view.children && {page.children &&
view.children.map((item, index) => { page.children.map((item, index) => {
return this.renderView(item, index, pagesLength, isOnlyOneView); return this.renderPage(item, index, pagesLength, isOnlyOnePage);
}) })
} }
</div> </div>
@@ -312,17 +297,17 @@ class ViewItem extends Component {
} }
} }
ViewItem.propTypes = { PageItem.propTypes = {
isOver: PropTypes.bool, isOver: PropTypes.bool,
canDrop: PropTypes.bool, canDrop: PropTypes.bool,
isDragging: PropTypes.bool, isDragging: PropTypes.bool,
draggedPage: PropTypes.object, draggedPage: PropTypes.object,
isEditMode: PropTypes.bool, isEditMode: PropTypes.bool,
infolder: PropTypes.bool, infolder: PropTypes.bool,
view: PropTypes.object, page: PropTypes.object,
folder: PropTypes.object, folder: PropTypes.object,
views: PropTypes.array, pages: PropTypes.array,
viewIndex: PropTypes.number, pageIndex: PropTypes.number,
folderId: PropTypes.string, folderId: PropTypes.string,
pagesLength: PropTypes.number, pagesLength: PropTypes.number,
connectDragSource: PropTypes.func, connectDragSource: PropTypes.func,
@@ -331,12 +316,12 @@ ViewItem.propTypes = {
renderFolderMenuItems: PropTypes.func, renderFolderMenuItems: PropTypes.func,
duplicatePage: PropTypes.func, duplicatePage: PropTypes.func,
onSetFolderId: PropTypes.func, onSetFolderId: PropTypes.func,
onSelectView: PropTypes.func, setCurrentPage: PropTypes.func,
onUpdatePage: PropTypes.func, onUpdatePage: PropTypes.func,
onDeleteView: PropTypes.func, onDeletePage: PropTypes.func,
onMoveViewToFolder: PropTypes.func, onMovePageToFolder: PropTypes.func,
onMoveView: PropTypes.func, onMovePage: PropTypes.func,
isOnlyOneView: PropTypes.bool, isOnlyOnePage: PropTypes.bool,
onMoveFolder: PropTypes.func, onMoveFolder: PropTypes.func,
pathStr: PropTypes.string, pathStr: PropTypes.string,
currentPageId: PropTypes.string, currentPageId: PropTypes.string,
@@ -345,4 +330,4 @@ ViewItem.propTypes = {
toggleExpand: PropTypes.func, toggleExpand: PropTypes.func,
}; };
export default ViewItem; export default PageItem;

View File

@@ -1,10 +1,10 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import CommonAddTool from '../../../components/common/common-add-tool'; import CommonAddTool from '../../../components/common/common-add-tool';
import AddViewDropdownMenu from './add-view-dropdownmenu'; import AddPageDropdownMenu from './add-page-dropdownmenu';
import { gettext } from '../../../utils/constants'; import { gettext } from '../../../utils/constants';
class ViewStructureFooter extends Component { class WikiNavFooter extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -20,17 +20,17 @@ class ViewStructureFooter extends Component {
render() { render() {
return ( return (
<div className='view-structure-footer'> <div className='wiki-nav-footer'>
<div className='add-view-wrapper'> <div className='add-wiki-page-wrapper'>
<CommonAddTool <CommonAddTool
className='add-view-btn' className='add-wiki-page-btn'
callBack={this.toggleDropdown} callBack={this.toggleDropdown}
footerName={gettext('Add page or folder')} footerName={gettext('Add page or folder')}
/> />
{this.state.isShowDropdownMenu && {this.state.isShowDropdownMenu &&
<AddViewDropdownMenu <AddPageDropdownMenu
toggleDropdown={this.toggleDropdown} toggleDropdown={this.toggleDropdown}
onToggleAddView={this.props.onToggleAddView} onToggleAddPage={this.props.onToggleAddPage}
onToggleAddFolder={this.props.onToggleAddFolder} onToggleAddFolder={this.props.onToggleAddFolder}
/> />
} }
@@ -40,9 +40,9 @@ class ViewStructureFooter extends Component {
} }
} }
ViewStructureFooter.propTypes = { WikiNavFooter.propTypes = {
onToggleAddView: PropTypes.func, onToggleAddPage: PropTypes.func,
onToggleAddFolder: PropTypes.func, onToggleAddFolder: PropTypes.func,
}; };
export default ViewStructureFooter; export default WikiNavFooter;

View File

@@ -4,28 +4,28 @@ import { DropdownItem } from 'reactstrap';
import { DropTarget, DragLayer } from 'react-dnd'; import { DropTarget, DragLayer } from 'react-dnd';
import html5DragDropContext from './html5DragDropContext'; import html5DragDropContext from './html5DragDropContext';
import DraggedFolderItem from './folders/dragged-folder-item'; import DraggedFolderItem from './folders/dragged-folder-item';
import DraggedViewItem from './views/dragged-view-item'; import DraggedPageItem from './pages/dragged-page-item';
import ViewStructureFooter from './view-structure-footer'; import WikiNavFooter from './wiki-nav-footer';
import { repoID } from '../../../utils/constants'; import { repoID } from '../../../utils/constants';
import '../css/view-structure.css'; import '../css/wiki-nav.css';
class ViewStructure extends Component { class WikiNav extends Component {
static propTypes = { static propTypes = {
isEditMode: PropTypes.bool, isEditMode: PropTypes.bool,
navigation: PropTypes.array, navigation: PropTypes.array,
views: PropTypes.array, pages: PropTypes.array,
onTogglePinViewList: PropTypes.func, onTogglePinViewList: PropTypes.func,
onToggleAddView: PropTypes.func, onToggleAddPage: PropTypes.func,
onToggleAddFolder: PropTypes.func, onToggleAddFolder: PropTypes.func,
onModifyFolder: PropTypes.func, onModifyFolder: PropTypes.func,
onDeleteFolder: PropTypes.func, onDeleteFolder: PropTypes.func,
onMoveFolder: PropTypes.func, onMoveFolder: PropTypes.func,
onSelectView: PropTypes.func, setCurrentPage: PropTypes.func,
onUpdatePage: PropTypes.func, onUpdatePage: PropTypes.func,
onDeleteView: PropTypes.func, onDeletePage: PropTypes.func,
onMoveView: PropTypes.func, onMovePage: PropTypes.func,
moveFolderToFolder: PropTypes.func, moveFolderToFolder: PropTypes.func,
movePageOut: PropTypes.func, movePageOut: PropTypes.func,
duplicatePage: PropTypes.func, duplicatePage: PropTypes.func,
@@ -64,24 +64,24 @@ class ViewStructure extends Component {
this.idFoldedStatusMap = idFoldedStatusMap; this.idFoldedStatusMap = idFoldedStatusMap;
}; };
onMoveViewToFolder = (source_view_folder_id, moved_view_id, target_view_folder_id) => { onMovePageToFolder = (source_page_folder_id, moved_page_id, target_page_folder_id) => {
this.props.onMoveView({ this.props.onMovePage({
moved_view_id, moved_page_id,
source_view_folder_id, source_page_folder_id,
target_view_folder_id, target_page_folder_id,
target_view_id: null, target_page_id: null,
move_position: 'move_below' move_position: 'move_below'
}); });
}; };
renderFolderMenuItems = ({ currentFolderId, onMoveViewToFolder }) => { renderFolderMenuItems = ({ currentFolderId, onMovePageToFolder }) => {
// folder lists (in the root directory) // folder lists (in the root directory)
const { navigation } = this.props; const { navigation } = this.props;
let renderFolders = navigation.filter(item => item.type === 'folder' && item.id !== currentFolderId); let renderFolders = navigation.filter(item => item.type === 'folder' && item.id !== currentFolderId);
return renderFolders.map(folder => { return renderFolders.map(folder => {
const { id, name } = folder; const { id, name } = folder;
return ( return (
<DropdownItem key={`move-to-folder-${id}`} onClick={onMoveViewToFolder.bind(this, id)}> <DropdownItem key={`move-to-folder-${id}`} onClick={onMovePageToFolder.bind(this, id)}>
<span className="folder-name text-truncate" title={name}>{name}</span> <span className="folder-name text-truncate" title={name}>{name}</span>
</DropdownItem> </DropdownItem>
); );
@@ -96,31 +96,31 @@ class ViewStructure extends Component {
return this.folderClassNameCache; return this.folderClassNameCache;
}; };
renderFolder = (folder, index, pagesLength, isOnlyOneView, id_view_map, layerDragProps) => { renderFolder = (folder, index, pagesLength, isOnlyOnePage, id_page_map, layerDragProps) => {
const { isEditMode, views } = this.props; const { isEditMode, pages } = this.props;
const folderId = folder.id; const folderId = folder.id;
return ( return (
<DraggedFolderItem <DraggedFolderItem
key={`view-folder-${folderId}`} key={`page-folder-${folderId}`}
isEditMode={isEditMode} isEditMode={isEditMode}
folder={folder} folder={folder}
folderIndex={index} folderIndex={index}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
id_view_map={id_view_map} id_page_map={id_page_map}
renderFolderMenuItems={this.renderFolderMenuItems} renderFolderMenuItems={this.renderFolderMenuItems}
toggleExpand={this.toggleExpand} toggleExpand={this.toggleExpand}
onToggleAddView={this.props.onToggleAddView} onToggleAddPage={this.props.onToggleAddPage}
onDeleteFolder={this.props.onDeleteFolder} onDeleteFolder={this.props.onDeleteFolder}
onMoveFolder={this.props.onMoveFolder} onMoveFolder={this.props.onMoveFolder}
onSelectView={this.props.onSelectView} setCurrentPage={this.props.setCurrentPage}
onUpdatePage={this.props.onUpdatePage} onUpdatePage={this.props.onUpdatePage}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onDeleteView={this.props.onDeleteView} onDeletePage={this.props.onDeletePage}
onMoveViewToFolder={this.onMoveViewToFolder} onMovePageToFolder={this.onMovePageToFolder}
onMoveView={this.props.onMoveView} onMovePage={this.props.onMovePage}
views={views} pages={pages}
moveFolderToFolder={this.props.moveFolderToFolder} moveFolderToFolder={this.props.moveFolderToFolder}
pathStr={folderId} pathStr={folderId}
layerDragProps={layerDragProps} layerDragProps={layerDragProps}
@@ -135,34 +135,34 @@ class ViewStructure extends Component {
); );
}; };
renderView = (view, index, pagesLength, isOnlyOneView, id_view_map) => { renderPage = (page, index, pagesLength, isOnlyOnePage, id_page_map) => {
const { isEditMode, views } = this.props; const { isEditMode, pages } = this.props;
const id = view.id; const id = page.id;
if (!views.find(item => item.id === id)) return; if (!pages.find(item => item.id === id)) return;
const folderId = null; // Pages in the root directory, no folders, use null const folderId = null; // Pages in the root directory, no folders, use null
return ( return (
<DraggedViewItem <DraggedPageItem
key={id} key={id}
pagesLength={pagesLength} pagesLength={pagesLength}
isOnlyOneView={isOnlyOneView} isOnlyOnePage={isOnlyOnePage}
infolder={false} infolder={false}
view={Object.assign({}, views.find(item => item.id === id), view)} page={Object.assign({}, pages.find(item => item.id === id), page)}
views={views} pages={pages}
viewIndex={index} pageIndex={index}
folderId={folderId} folderId={folderId}
isEditMode={isEditMode} isEditMode={isEditMode}
renderFolderMenuItems={this.renderFolderMenuItems} renderFolderMenuItems={this.renderFolderMenuItems}
duplicatePage={this.props.duplicatePage} duplicatePage={this.props.duplicatePage}
onSetFolderId={this.props.onSetFolderId} onSetFolderId={this.props.onSetFolderId}
onSelectView={this.props.onSelectView} setCurrentPage={this.props.setCurrentPage}
onUpdatePage={this.props.onUpdatePage} onUpdatePage={this.props.onUpdatePage}
onDeleteView={this.props.onDeleteView} onDeletePage={this.props.onDeletePage}
onMoveViewToFolder={(targetFolderId) => { onMovePageToFolder={(targetFolderId) => {
this.onMoveViewToFolder(folderId, view.id, targetFolderId); this.onMovePageToFolder(folderId, page.id, targetFolderId);
}} }}
onMoveView={this.props.onMoveView} onMovePage={this.props.onMovePage}
onMoveFolder={this.props.onMoveFolder} onMoveFolder={this.props.onMoveFolder}
pathStr={view.id} pathStr={page.id}
currentPageId={this.props.currentPageId} currentPageId={this.props.currentPageId}
addPageInside={this.props.addPageInside} addPageInside={this.props.addPageInside}
getFoldState={this.getFoldState} getFoldState={this.getFoldState}
@@ -173,21 +173,21 @@ class ViewStructure extends Component {
// eslint-disable-next-line // eslint-disable-next-line
renderStructureBody = React.forwardRef((layerDragProps, ref) => { renderStructureBody = React.forwardRef((layerDragProps, ref) => {
const { navigation, views, isEditMode } = this.props; const { navigation, pages, isEditMode } = this.props;
let isOnlyOneView = false; let isOnlyOnePage = false;
if (views.length === 1) { if (pages.length === 1) {
isOnlyOneView = true; isOnlyOnePage = true;
} }
const pagesLength = views.length; const pagesLength = pages.length;
let id_view_map = {}; let id_page_map = {};
views.forEach(view => id_view_map[view.id] = view); pages.forEach(page => id_page_map[page.id] = page);
const style = { maxHeight: isEditMode ? 'calc(100% - 40px)' : '100%' }; const style = { maxHeight: isEditMode ? 'calc(100% - 40px)' : '100%' };
return ( return (
<div className='view-structure-body' style={style}> <div className='wiki-nav-body' style={style}>
{navigation.map((item, index) => { {navigation.map((item, index) => {
return item.type === 'folder' ? return item.type === 'folder' ?
this.renderFolder(item, index, pagesLength, isOnlyOneView, id_view_map, layerDragProps) : this.renderFolder(item, index, pagesLength, isOnlyOnePage, id_page_map, layerDragProps) :
this.renderView(item, index, pagesLength, isOnlyOneView, id_view_map); this.renderPage(item, index, pagesLength, isOnlyOnePage, id_page_map);
})} })}
</div> </div>
); );
@@ -204,16 +204,16 @@ class ViewStructure extends Component {
render() { render() {
const StructureBody = html5DragDropContext( const StructureBody = html5DragDropContext(
DropTarget('ViewStructure', {}, connect => ({ DropTarget('WikiNav', {}, connect => ({
connectDropTarget: connect.dropTarget() connectDropTarget: connect.dropTarget()
}))(DragLayer(this.collect)(this.renderStructureBody)) }))(DragLayer(this.collect)(this.renderStructureBody))
); );
return ( return (
<div className='view-structure view-structure-light'> <div className='wiki-nav'>
<StructureBody /> <StructureBody />
{(this.props.isEditMode) && {(this.props.isEditMode) &&
<ViewStructureFooter <WikiNavFooter
onToggleAddView={this.props.onToggleAddView} onToggleAddPage={this.props.onToggleAddPage}
onToggleAddFolder={this.props.onToggleAddFolder} onToggleAddFolder={this.props.onToggleAddFolder}
/> />
} }
@@ -222,4 +222,4 @@ class ViewStructure extends Component {
} }
} }
export default ViewStructure; export default WikiNav;