mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 15:09:14 +00:00
[wiki] change drag page into another page (#6422)
* 01 change drag page into another page * 02 delete useless codes * update move page * fix invalid position * delete useless codes --------- Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com>
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wiki-nav-body {
|
.wiki-nav-body {
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 1rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
@@ -234,21 +234,29 @@
|
|||||||
margin: 0.2rem 0;
|
margin: 0.2rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-nav .wiki-page-item.page-can-drop::after,
|
.wiki-nav .wiki-page-item.page-can-drop-bottom::after,
|
||||||
.wiki-nav .wiki-page-item.page-can-drop-top::after {
|
.wiki-nav .wiki-page-item.page-can-drop-top::after {
|
||||||
content: '';
|
content: '';
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 1px;
|
height: 5px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 39px;
|
background-color: rgb(200, 220, 240) !important;
|
||||||
background-color: #666 !important;
|
}
|
||||||
|
|
||||||
|
.wiki-nav .wiki-page-item.page-can-drop-bottom::after {
|
||||||
|
top: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-nav .wiki-page-item.page-can-drop-top::after {
|
.wiki-nav .wiki-page-item.page-can-drop-top::after {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wiki-nav .wiki-page-item.dragged-page-over {
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: rgb(200, 220, 240) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.dtable-dropdown-menu .dropdown-item .sf3-font {
|
.dtable-dropdown-menu .dropdown-item .sf3-font {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
@@ -89,8 +89,7 @@ class SidePanel extends Component {
|
|||||||
movePage = ({ moved_page_id, target_page_id, move_position }) => {
|
movePage = ({ moved_page_id, target_page_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_page_id, target_page_id, move_position);
|
config.navigation = PageUtils.movePage(navigation, moved_page_id, target_page_id, move_position);
|
||||||
config.navigation = navigation;
|
|
||||||
JSON.stringify(config);
|
JSON.stringify(config);
|
||||||
this.props.updateWikiConfig(config);
|
this.props.updateWikiConfig(config);
|
||||||
};
|
};
|
||||||
|
@@ -63,21 +63,29 @@ export default class PageUtils {
|
|||||||
return pages.findIndex(page => page.id === pageId);
|
return pages.findIndex(page => page.id === pageId);
|
||||||
};
|
};
|
||||||
|
|
||||||
static insertPage(navigation, page_id, target_page_id, target_id, move_position) {
|
static generatePaths = (tree) => {
|
||||||
if (!target_id) {
|
tree._path = '';
|
||||||
let insertIndex = target_page_id ? navigation.findIndex(item => item.id === target_page_id) : -1;
|
function runNode(node) {
|
||||||
if (insertIndex < 0) {
|
const newPath = node._path ? (node._path + '-' + node.id) : (node.id || '');
|
||||||
this.addPage(navigation, page_id, target_id);
|
if (node.children) {
|
||||||
return true;
|
node.children.forEach(child => {
|
||||||
|
if (child) {
|
||||||
|
child._path = newPath;
|
||||||
|
runNode(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (move_position === 'move_below') {
|
|
||||||
insertIndex++;
|
|
||||||
}
|
|
||||||
navigation.splice(insertIndex, 0, new NewPage(page_id));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
runNode(tree);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* move page to another page
|
||||||
|
* @param {object} navigation
|
||||||
|
* @param {string} moved_page_id
|
||||||
|
* @param {string} target_page_id
|
||||||
|
* @param {string} move_position, one of'move_into', 'move_below', 'move_into'
|
||||||
|
*/
|
||||||
static movePage(navigation, moved_page_id, target_page_id, move_position) {
|
static movePage(navigation, moved_page_id, target_page_id, move_position) {
|
||||||
let movedPage = null;
|
let movedPage = null;
|
||||||
function _cutPageRecursion(item, page_id) {
|
function _cutPageRecursion(item, page_id) {
|
||||||
@@ -101,42 +109,47 @@ export default class PageUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function _insertPageRecursion(item, page_id, target_page_id, target_id, move_position) {
|
|
||||||
if (item.id === target_id) {
|
|
||||||
if (item.children) {
|
|
||||||
let insertIndex = target_page_id ? item.children.findIndex(item => item.id === target_page_id) : -1;
|
|
||||||
if (move_position === 'move_below') {
|
|
||||||
insertIndex++;
|
|
||||||
}
|
|
||||||
item.children.splice(insertIndex, 0, movedPage);
|
|
||||||
} else {
|
|
||||||
item.children = [];
|
|
||||||
item.children.push(movedPage);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
item.children && item.children.forEach(item => {
|
|
||||||
_insertPageRecursion(item, page_id, target_page_id, target_id, move_position);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function _insertPage(navigation, page_id, target_page_id, target_id, move_position) {
|
|
||||||
if (!target_id) {
|
|
||||||
let insertIndex = target_page_id ? navigation.findIndex(item => item.id === target_page_id) : -1;
|
|
||||||
if (insertIndex < 0) {
|
|
||||||
navigation.splice(0, 0, movedPage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (move_position === 'move_below') {
|
|
||||||
insertIndex++;
|
|
||||||
}
|
|
||||||
navigation.splice(insertIndex, 0, movedPage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
navigation.forEach(item => {
|
|
||||||
_insertPageRecursion(item, page_id, target_page_id, target_id, move_position);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_cutPage(navigation, moved_page_id);
|
_cutPage(navigation, moved_page_id);
|
||||||
_insertPage(navigation, moved_page_id, target_page_id, target_page_id, move_position);
|
if (!movedPage) return;
|
||||||
|
|
||||||
|
function _insertPage(tree, target_page_id, move_position) {
|
||||||
|
if (!tree) return;
|
||||||
|
if (!Array.isArray(tree.children)) {
|
||||||
|
tree.children = [];
|
||||||
|
}
|
||||||
|
const target_page = tree.children.find(item => item.id === target_page_id);
|
||||||
|
const target_index = tree.children.findIndex(item => item.id === target_page_id);
|
||||||
|
if (target_page) {
|
||||||
|
switch (move_position) {
|
||||||
|
case 'move_into': {
|
||||||
|
if (!Array.isArray(target_page.children)) {
|
||||||
|
target_page.children = [];
|
||||||
|
}
|
||||||
|
target_page.children.push(movedPage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'move_above': {
|
||||||
|
tree.children.splice(target_index, 0, movedPage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'move_below': {
|
||||||
|
tree.children.splice(target_index + 1, 0, movedPage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tree.children.forEach(child => {
|
||||||
|
_insertPage(child, target_page_id, move_position);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tree = {};
|
||||||
|
tree.children = navigation;
|
||||||
|
_insertPage(tree, target_page_id, move_position);
|
||||||
|
this.generatePaths(tree);
|
||||||
|
return tree.children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,30 +31,36 @@ const dragSource = {
|
|||||||
const dropTarget = {
|
const dropTarget = {
|
||||||
drop(props, monitor) {
|
drop(props, monitor) {
|
||||||
const dragSource = monitor.getItem();
|
const dragSource = monitor.getItem();
|
||||||
if (dragSource.mode === 'wiki-page') {
|
const className = props.getClassName();
|
||||||
const { pageIndex: targetIndex, page: targetPage } = props;
|
let move_position;
|
||||||
const draggedPageId = dragSource.data.id;
|
if (className.includes('page-can-drop-bottom')) {
|
||||||
const targetPageId = targetPage.id;
|
move_position = 'move_below';
|
||||||
if (draggedPageId !== targetPageId) {
|
} else if (className.includes('page-can-drop-top')) {
|
||||||
const sourceIndex = dragSource.idx;
|
move_position = 'move_above';
|
||||||
const move_position = sourceIndex > targetIndex ? 'move_above' : 'move_below';
|
} else if (className.includes('dragged-page-over')) {
|
||||||
wikiAPI.moveWiki2Page(wikiId, draggedPageId, targetPageId, move_position).then(res => {
|
move_position = 'move_into';
|
||||||
props.onMovePage({
|
|
||||||
moved_page_id: draggedPageId,
|
|
||||||
target_page_id: targetPageId,
|
|
||||||
move_position,
|
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.response && error.response.status === 400 && error.response.data.error_msg === 'Internal Server Error') {
|
|
||||||
toaster.danger(gettext('Cannot move parent page to child page'));
|
|
||||||
} else {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (!move_position) return;
|
||||||
|
if (dragSource.mode === 'wiki-page') {
|
||||||
|
const targetPage = props.page;
|
||||||
|
const draggedPage = dragSource.data;
|
||||||
|
const moved_page_id = draggedPage.id;
|
||||||
|
const target_page_id = targetPage.id;
|
||||||
|
if (moved_page_id === target_page_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (targetPage._path && targetPage._path.includes(moved_page_id)) {
|
||||||
|
toaster.danger(gettext('Cannot move parent page to child page'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wikiAPI.moveWiki2Page(wikiId, moved_page_id, target_page_id, move_position).then(res => {
|
||||||
|
props.onMovePage({ moved_page_id, target_page_id, move_position });
|
||||||
|
}).catch((error) => {
|
||||||
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -143,6 +143,9 @@ class PageItem extends Component {
|
|||||||
addPageInside={this.props.addPageInside}
|
addPageInside={this.props.addPageInside}
|
||||||
getFoldState={this.props.getFoldState}
|
getFoldState={this.props.getFoldState}
|
||||||
toggleExpand={this.props.toggleExpand}
|
toggleExpand={this.props.toggleExpand}
|
||||||
|
setClassName={this.props.setClassName}
|
||||||
|
getClassName={this.props.getClassName}
|
||||||
|
layerDragProps={this.props.layerDragProps}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -157,17 +160,32 @@ class PageItem extends Component {
|
|||||||
this.props.addPageInside(Object.assign({ parentPageId: this.props.page.id }, newPage));
|
this.props.addPageInside(Object.assign({ parentPageId: this.props.page.id }, newPage));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
getPageClassName = () => {
|
||||||
const {
|
const { isOver, canDrop, isEditMode, layerDragProps } = this.props;
|
||||||
connectDragSource, connectDragPreview, connectDropTarget, isOver, canDrop, isDragging,
|
|
||||||
page, pagesLength, isEditMode, isOnlyOnePage, pathStr,
|
|
||||||
} = this.props;
|
|
||||||
const { isShowNameEditor, pageName, isSelected } = this.state;
|
|
||||||
const isOverPage = isOver && canDrop;
|
const isOverPage = isOver && canDrop;
|
||||||
|
if (!isOverPage || ! layerDragProps || !layerDragProps.clientOffset) {
|
||||||
|
return classnames('wiki-page-item', { 'selected-page': this.state.isSelected }, { 'readonly': !isEditMode });
|
||||||
|
}
|
||||||
|
let y = layerDragProps.clientOffset.y;
|
||||||
|
let top = this.pageItemRef.getBoundingClientRect().y;
|
||||||
|
const className = classnames(
|
||||||
|
'wiki-page-item',
|
||||||
|
{ 'dragged-page-over': (top + 10 < y && y < top + 30) },
|
||||||
|
{ 'page-can-drop-top': (top + 10 > y) },
|
||||||
|
{ 'page-can-drop-bottom': (top + 30 < y) },
|
||||||
|
{ 'selected-page': this.state.isSelected },
|
||||||
|
{ 'readonly': !isEditMode },
|
||||||
|
);
|
||||||
|
this.props.setClassName(className);
|
||||||
|
return className;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { connectDragSource, connectDragPreview, connectDropTarget,
|
||||||
|
page, pagesLength, isEditMode, isOnlyOnePage, pathStr } = this.props;
|
||||||
|
const { isShowNameEditor, pageName, isSelected } = this.state;
|
||||||
if (isSelected) this.setDocUuid(page.docUuid);
|
if (isSelected) this.setDocUuid(page.docUuid);
|
||||||
|
|
||||||
let pageCanDropTop = isOverPage && isDragging;
|
|
||||||
let pageCanDrop = isOverPage && !isDragging;
|
|
||||||
let navItemId = `page-editor-${page.id}`;
|
let navItemId = `page-editor-${page.id}`;
|
||||||
let fn = isEditMode ? connectDragSource : (argu) => { argu; };
|
let fn = isEditMode ? connectDragSource : (argu) => { argu; };
|
||||||
let childNumber = Array.isArray(page.children) ? page.children.length : 0;
|
let childNumber = Array.isArray(page.children) ? page.children.length : 0;
|
||||||
@@ -180,12 +198,7 @@ class PageItem extends Component {
|
|||||||
fn(connectDropTarget(
|
fn(connectDropTarget(
|
||||||
connectDragPreview(
|
connectDragPreview(
|
||||||
<div
|
<div
|
||||||
className={classnames('wiki-page-item',
|
className={this.getPageClassName()}
|
||||||
{ 'selected-page': isSelected },
|
|
||||||
{ 'page-can-drop-top': pageCanDropTop },
|
|
||||||
{ 'page-can-drop': pageCanDrop },
|
|
||||||
{ 'readonly': !isEditMode },
|
|
||||||
)}
|
|
||||||
ref={ref => this.pageItemRef = ref}
|
ref={ref => this.pageItemRef = ref}
|
||||||
onMouseEnter={this.onMouseEnter}
|
onMouseEnter={this.onMouseEnter}
|
||||||
onMouseMove={this.onMouseMove}
|
onMouseMove={this.onMouseMove}
|
||||||
@@ -296,6 +309,8 @@ PageItem.propTypes = {
|
|||||||
getFoldState: PropTypes.func,
|
getFoldState: PropTypes.func,
|
||||||
toggleExpand: PropTypes.func,
|
toggleExpand: PropTypes.func,
|
||||||
updateWikiConfig: PropTypes.func,
|
updateWikiConfig: PropTypes.func,
|
||||||
|
getClassName: PropTypes.func,
|
||||||
|
setClassName: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PageItem;
|
export default PageItem;
|
||||||
|
@@ -25,6 +25,7 @@ class WikiNav extends Component {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.folderClassNameCache = '';
|
||||||
this.idFoldedStatusMap = this.getFoldedFromLocal();
|
this.idFoldedStatusMap = this.getFoldedFromLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +53,14 @@ class WikiNav extends Component {
|
|||||||
this.idFoldedStatusMap = idFoldedStatusMap;
|
this.idFoldedStatusMap = idFoldedStatusMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setClassName = (name) => {
|
||||||
|
this.folderClassNameCache = name;
|
||||||
|
};
|
||||||
|
|
||||||
|
getClassName = () => {
|
||||||
|
return this.folderClassNameCache;
|
||||||
|
};
|
||||||
|
|
||||||
renderPage = (page, index, pagesLength, isOnlyOnePage, id_page_map, layerDragProps) => {
|
renderPage = (page, index, pagesLength, isOnlyOnePage, id_page_map, layerDragProps) => {
|
||||||
const { isEditMode, pages } = this.props;
|
const { isEditMode, pages } = this.props;
|
||||||
const id = page.id;
|
const id = page.id;
|
||||||
@@ -78,6 +87,8 @@ class WikiNav extends Component {
|
|||||||
toggleExpand={this.toggleExpand}
|
toggleExpand={this.toggleExpand}
|
||||||
id_page_map={id_page_map}
|
id_page_map={id_page_map}
|
||||||
layerDragProps={layerDragProps}
|
layerDragProps={layerDragProps}
|
||||||
|
setClassName={this.setClassName}
|
||||||
|
getClassName={this.getClassName}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -571,6 +571,13 @@ class Wiki2PagesView(APIView):
|
|||||||
id_set = get_all_wiki_ids(navigation)
|
id_set = get_all_wiki_ids(navigation)
|
||||||
target_page_id = request.data.get('target_id', '')
|
target_page_id = request.data.get('target_id', '')
|
||||||
moved_page_id = request.data.get('moved_id', '')
|
moved_page_id = request.data.get('moved_id', '')
|
||||||
|
move_position = request.data.get('move_position', '')
|
||||||
|
# check arguments
|
||||||
|
valid_move_positions = ['move_below', 'move_above', 'move_into']
|
||||||
|
if move_position not in valid_move_positions:
|
||||||
|
error_msg = 'Invalid move_position value: ' + move_position
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
if (target_page_id not in id_set) or (moved_page_id not in id_set):
|
if (target_page_id not in id_set) or (moved_page_id not in id_set):
|
||||||
error_msg = 'Page not found'
|
error_msg = 'Page not found'
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
@@ -583,7 +590,7 @@ class Wiki2PagesView(APIView):
|
|||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
move_nav(navigation, target_page_id, moved_nav)
|
move_nav(navigation, target_page_id, moved_nav, move_position)
|
||||||
wiki_config['navigation'] = navigation
|
wiki_config['navigation'] = navigation
|
||||||
wiki_config = json.dumps(wiki_config)
|
wiki_config = json.dumps(wiki_config)
|
||||||
|
|
||||||
|
@@ -244,14 +244,23 @@ def pop_nav(navigation, page_id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def move_nav(navigation, target_id, moved_nav):
|
def move_nav(navigation, target_id, moved_nav, move_position):
|
||||||
for nav in navigation:
|
def move_item(nav_list, nav_index, moved_nav, move_position):
|
||||||
|
if move_position == 'move_below':
|
||||||
|
nav_list.insert(nav_index + 1, moved_nav)
|
||||||
|
elif move_position == 'move_above':
|
||||||
|
nav_list.insert(nav_index, moved_nav)
|
||||||
|
|
||||||
|
for nav_index, nav in enumerate(navigation):
|
||||||
if nav['id'] == target_id:
|
if nav['id'] == target_id:
|
||||||
if 'children' in nav:
|
if move_position == 'move_below' or move_position == 'move_above':
|
||||||
nav['children'].insert(0, moved_nav)
|
move_item(navigation, nav_index, moved_nav, move_position)
|
||||||
else:
|
if move_position == 'move_into':
|
||||||
nav['children'] = [moved_nav]
|
if 'children' in nav:
|
||||||
|
nav['children'].append(moved_nav)
|
||||||
|
else:
|
||||||
|
nav['children'] = [moved_nav]
|
||||||
return
|
return
|
||||||
if 'children' in nav:
|
if 'children' in nav:
|
||||||
move_nav(nav['children'], target_id, moved_nav)
|
move_nav(nav['children'], target_id, moved_nav, move_position)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user