PPTist/src/hooks/useOrderElement.ts
2021-02-09 19:49:23 +08:00

212 lines
8.8 KiB
TypeScript

import { computed } from 'vue'
import { MutationTypes, useStore } from '@/store'
import { PPTElement, Slide } from '@/types/slides'
import { ElementOrderCommand, ElementOrderCommands } from '@/types/edit'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
export default () => {
const store = useStore()
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
const { addHistorySnapshot } = useHistorySnapshot()
/**
* 获取组合元素层级范围
* @param elementList 本页所有元素列表
* @param combineElementList 组合元素列表
*/
const getCombineElementLevelRange = (elementList: PPTElement[], combineElementList: PPTElement[]) => {
return {
minLevel: elementList.findIndex(_element => _element.id === combineElementList[0].id),
maxLevel: elementList.findIndex(_element => _element.id === combineElementList[combineElementList.length - 1].id),
}
}
/**
* 上移一层
* @param elementList 本页所有元素列表
* @param element 当前操作的元素
*/
const moveUpElement = (elementList: PPTElement[], element: PPTElement) => {
const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList))
// 如果被操作的元素是组合元素成员,需要将该组合全部成员一起进行移动
if (element.groupId) {
// 获取到该组合全部成员,以及所有成员的层级范围
const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId)
const { minLevel, maxLevel } = getCombineElementLevelRange(elementList, combineElementList)
// 已经处在顶层,无法继续移动
if (maxLevel === elementList.length - 1) return
// 通过组合成员范围的最大值,获取到该组合上一层的元素,然后将该组合元素从元素列表中移除(并缓存被移除的元素列表)
// 若上层元素处在另一个组合中,则将上述被移除的组合元素插入到该上层组合上方
// 若上层元素不处于任何分组中,则将上述被移除的组合元素插入到该上层元素上方
const nextElement = copyOfElementList[maxLevel + 1]
const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length)
if (nextElement.groupId) {
const nextCombineElementList = copyOfElementList.filter(_element => _element.groupId === nextElement.groupId)
copyOfElementList.splice(minLevel + nextCombineElementList.length, 0, ...movedElementList)
}
else copyOfElementList.splice(minLevel + 1, 0, ...movedElementList)
}
// 如果被操作的元素不是组合元素成员
else {
// 获取该元素在列表中的层级
const level = elementList.findIndex(item => item.id === element.id)
// 已经处在顶层,无法继续移动
if (level === elementList.length - 1) return
// 获取到该组合上一层的元素,然后将该组合元素从元素列表中移除(并缓存被移除的元素列表)
const nextElement = copyOfElementList[level + 1]
const movedElement = copyOfElementList.splice(level, 1)[0]
// 通过组合成员范围的最大值,获取到该组合上一层的元素,然后将该组合元素从元素列表中移除(并缓存被移除的元素列表)
// 若上层元素处在另一个组合中,则将上述被移除的组合元素插入到该上层组合上方
// 若上层元素不处于任何分组中,则将上述被移除的组合元素插入到该上层元素上方
if (nextElement.groupId) {
const combineElementList = copyOfElementList.filter(_element => _element.groupId === nextElement.groupId)
copyOfElementList.splice(level + combineElementList.length, 0, movedElement)
}
else copyOfElementList.splice(level + 1, 0, movedElement)
}
return copyOfElementList
}
/**
* 下移一层,操作方式同上移
* @param elementList 本页所有元素列表
* @param element 当前操作的元素
*/
const moveDownElement = (elementList: PPTElement[], element: PPTElement) => {
const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList))
if (element.groupId) {
const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId)
const { minLevel } = getCombineElementLevelRange(elementList, combineElementList)
if (minLevel === 0) return
const prevElement = copyOfElementList[minLevel - 1]
const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length)
if (prevElement.groupId) {
const prevCombineElementList = copyOfElementList.filter(_element => _element.groupId === prevElement.groupId)
copyOfElementList.splice(minLevel - prevCombineElementList.length, 0, ...movedElementList)
}
else copyOfElementList.splice(minLevel - 1, 0, ...movedElementList)
}
else {
const level = elementList.findIndex(item => item.id === element.id)
if (level === 0) return
const prevElement = copyOfElementList[level - 1]
const movedElement = copyOfElementList.splice(level, 1)[0]
if (prevElement.groupId) {
const combineElementList = copyOfElementList.filter(_element => _element.groupId === prevElement.groupId)
copyOfElementList.splice(level - combineElementList.length, 0, movedElement)
}
else copyOfElementList.splice(level - 1, 0, movedElement)
}
return copyOfElementList
}
/**
* 置顶层
* @param elementList 本页所有元素列表
* @param element 当前操作的元素
*/
const moveTopElement = (elementList: PPTElement[], element: PPTElement) => {
const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList))
// 如果被操作的元素是组合元素成员,需要将该组合全部成员一起进行移动
if (element.groupId) {
// 获取到该组合全部成员,以及所有成员的层级范围
const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId)
const { minLevel, maxLevel } = getCombineElementLevelRange(elementList, combineElementList)
// 已经处在顶层,无法继续移动
if (maxLevel === elementList.length - 1) return null
// 将该组合元素从元素列表中移除,然后将被移除的元素添加到元素列表顶部
const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length)
copyOfElementList.push(...movedElementList)
}
// 如果被操作的元素不是组合元素成员
else {
// 获取该元素在列表中的层级
const level = elementList.findIndex(item => item.id === element.id)
// 已经处在顶层,无法继续移动
if (level === elementList.length - 1) return null
// 将该组合元素从元素列表中移除,然后将被移除的元素添加到元素列表底部
copyOfElementList.splice(level, 1)
copyOfElementList.push(element)
}
return copyOfElementList
}
/**
* 置底层,操作方式同置顶
* @param elementList 本页所有元素列表
* @param element 当前操作的元素
*/
const moveBottomElement = (elementList: PPTElement[], element: PPTElement) => {
const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList))
if (element.groupId) {
const combineElementList = copyOfElementList.filter(_element => _element.groupId === element.groupId)
const { minLevel } = getCombineElementLevelRange(elementList, combineElementList)
if (minLevel === 0) return
const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length)
copyOfElementList.unshift(...movedElementList)
}
else {
const level = elementList.findIndex(item => item.id === element.id)
if (level === 0) return
copyOfElementList.splice(level, 1)
copyOfElementList.unshift(element)
}
return copyOfElementList
}
/**
* 调整元素层级
* @param element 需要调整层级的元素
* @param command 调整命令:上移、下移、置顶、置底
*/
const orderElement = (element: PPTElement, command: ElementOrderCommand) => {
let newElementList
if (command === ElementOrderCommands.UP) newElementList = moveUpElement(currentSlide.value.elements, element)
else if (command === ElementOrderCommands.DOWN) newElementList = moveDownElement(currentSlide.value.elements, element)
else if (command === ElementOrderCommands.TOP) newElementList = moveTopElement(currentSlide.value.elements, element)
else if (command === ElementOrderCommands.BOTTOM) newElementList = moveBottomElement(currentSlide.value.elements, element)
if (!newElementList) return
store.commit(MutationTypes.UPDATE_SLIDE, { elements: newElementList })
addHistorySnapshot()
}
return {
orderElement,
}
}