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 {
|
||||
padding-bottom: 0.5rem;
|
||||
padding-bottom: 1rem;
|
||||
overflow: auto;
|
||||
user-select: none;
|
||||
max-height: 100%;
|
||||
@@ -234,21 +234,29 @@
|
||||
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 {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 39px;
|
||||
background-color: #666 !important;
|
||||
background-color: rgb(200, 220, 240) !important;
|
||||
}
|
||||
|
||||
.wiki-nav .wiki-page-item.page-can-drop-bottom::after {
|
||||
top: 32px;
|
||||
}
|
||||
|
||||
.wiki-nav .wiki-page-item.page-can-drop-top::after {
|
||||
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 {
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
|
@@ -89,8 +89,7 @@ class SidePanel extends Component {
|
||||
movePage = ({ moved_page_id, target_page_id, move_position }) => {
|
||||
let config = deepCopy(this.props.config);
|
||||
let { navigation } = config;
|
||||
PageUtils.movePage(navigation, moved_page_id, target_page_id, move_position);
|
||||
config.navigation = navigation;
|
||||
config.navigation = PageUtils.movePage(navigation, moved_page_id, target_page_id, move_position);
|
||||
JSON.stringify(config);
|
||||
this.props.updateWikiConfig(config);
|
||||
};
|
||||
|
@@ -63,21 +63,29 @@ export default class PageUtils {
|
||||
return pages.findIndex(page => page.id === pageId);
|
||||
};
|
||||
|
||||
static 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) {
|
||||
this.addPage(navigation, page_id, target_id);
|
||||
return true;
|
||||
static generatePaths = (tree) => {
|
||||
tree._path = '';
|
||||
function runNode(node) {
|
||||
const newPath = node._path ? (node._path + '-' + node.id) : (node.id || '');
|
||||
if (node.children) {
|
||||
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) {
|
||||
let movedPage = null;
|
||||
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);
|
||||
_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,31 +31,37 @@ const dragSource = {
|
||||
const dropTarget = {
|
||||
drop(props, monitor) {
|
||||
const dragSource = monitor.getItem();
|
||||
const className = props.getClassName();
|
||||
let move_position;
|
||||
if (className.includes('page-can-drop-bottom')) {
|
||||
move_position = 'move_below';
|
||||
} else if (className.includes('page-can-drop-top')) {
|
||||
move_position = 'move_above';
|
||||
} else if (className.includes('dragged-page-over')) {
|
||||
move_position = 'move_into';
|
||||
}
|
||||
if (!move_position) return;
|
||||
if (dragSource.mode === 'wiki-page') {
|
||||
const { pageIndex: targetIndex, page: targetPage } = props;
|
||||
const draggedPageId = dragSource.data.id;
|
||||
const targetPageId = targetPage.id;
|
||||
if (draggedPageId !== targetPageId) {
|
||||
const sourceIndex = dragSource.idx;
|
||||
const move_position = sourceIndex > targetIndex ? 'move_above' : 'move_below';
|
||||
wikiAPI.moveWiki2Page(wikiId, draggedPageId, targetPageId, move_position).then(res => {
|
||||
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') {
|
||||
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'));
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const dragCollect = (connect, monitor) => ({
|
||||
|
@@ -143,6 +143,9 @@ class PageItem extends Component {
|
||||
addPageInside={this.props.addPageInside}
|
||||
getFoldState={this.props.getFoldState}
|
||||
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));
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
connectDragSource, connectDragPreview, connectDropTarget, isOver, canDrop, isDragging,
|
||||
page, pagesLength, isEditMode, isOnlyOnePage, pathStr,
|
||||
} = this.props;
|
||||
const { isShowNameEditor, pageName, isSelected } = this.state;
|
||||
getPageClassName = () => {
|
||||
const { isOver, canDrop, isEditMode, layerDragProps } = this.props;
|
||||
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);
|
||||
|
||||
let pageCanDropTop = isOverPage && isDragging;
|
||||
let pageCanDrop = isOverPage && !isDragging;
|
||||
let navItemId = `page-editor-${page.id}`;
|
||||
let fn = isEditMode ? connectDragSource : (argu) => { argu; };
|
||||
let childNumber = Array.isArray(page.children) ? page.children.length : 0;
|
||||
@@ -180,12 +198,7 @@ class PageItem extends Component {
|
||||
fn(connectDropTarget(
|
||||
connectDragPreview(
|
||||
<div
|
||||
className={classnames('wiki-page-item',
|
||||
{ 'selected-page': isSelected },
|
||||
{ 'page-can-drop-top': pageCanDropTop },
|
||||
{ 'page-can-drop': pageCanDrop },
|
||||
{ 'readonly': !isEditMode },
|
||||
)}
|
||||
className={this.getPageClassName()}
|
||||
ref={ref => this.pageItemRef = ref}
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseMove={this.onMouseMove}
|
||||
@@ -296,6 +309,8 @@ PageItem.propTypes = {
|
||||
getFoldState: PropTypes.func,
|
||||
toggleExpand: PropTypes.func,
|
||||
updateWikiConfig: PropTypes.func,
|
||||
getClassName: PropTypes.func,
|
||||
setClassName: PropTypes.func,
|
||||
};
|
||||
|
||||
export default PageItem;
|
||||
|
@@ -25,6 +25,7 @@ class WikiNav extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.folderClassNameCache = '';
|
||||
this.idFoldedStatusMap = this.getFoldedFromLocal();
|
||||
}
|
||||
|
||||
@@ -52,6 +53,14 @@ class WikiNav extends Component {
|
||||
this.idFoldedStatusMap = idFoldedStatusMap;
|
||||
};
|
||||
|
||||
setClassName = (name) => {
|
||||
this.folderClassNameCache = name;
|
||||
};
|
||||
|
||||
getClassName = () => {
|
||||
return this.folderClassNameCache;
|
||||
};
|
||||
|
||||
renderPage = (page, index, pagesLength, isOnlyOnePage, id_page_map, layerDragProps) => {
|
||||
const { isEditMode, pages } = this.props;
|
||||
const id = page.id;
|
||||
@@ -78,6 +87,8 @@ class WikiNav extends Component {
|
||||
toggleExpand={this.toggleExpand}
|
||||
id_page_map={id_page_map}
|
||||
layerDragProps={layerDragProps}
|
||||
setClassName={this.setClassName}
|
||||
getClassName={this.getClassName}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@@ -571,6 +571,13 @@ class Wiki2PagesView(APIView):
|
||||
id_set = get_all_wiki_ids(navigation)
|
||||
target_page_id = request.data.get('target_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):
|
||||
error_msg = 'Page not found'
|
||||
logger.error(error_msg)
|
||||
@@ -583,7 +590,7 @@ class Wiki2PagesView(APIView):
|
||||
logger.error(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 = json.dumps(wiki_config)
|
||||
|
||||
|
@@ -244,14 +244,23 @@ def pop_nav(navigation, page_id):
|
||||
return None
|
||||
|
||||
|
||||
def move_nav(navigation, target_id, moved_nav):
|
||||
for nav in navigation:
|
||||
def move_nav(navigation, target_id, moved_nav, move_position):
|
||||
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 move_position == 'move_below' or move_position == 'move_above':
|
||||
move_item(navigation, nav_index, moved_nav, move_position)
|
||||
if move_position == 'move_into':
|
||||
if 'children' in nav:
|
||||
nav['children'].insert(0, moved_nav)
|
||||
nav['children'].append(moved_nav)
|
||||
else:
|
||||
nav['children'] = [moved_nav]
|
||||
return
|
||||
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