Skip to content

Commit

Permalink
Merge f87e135 into 3924fbd
Browse files Browse the repository at this point in the history
  • Loading branch information
sallerli1 committed Oct 20, 2022
2 parents 3924fbd + f87e135 commit dd043cb
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,7 @@ exports[`ProTransfer > tree transfer render work 1`] = `
class="ix-transfer-header-label"
>
待选 (18)
待选 (27)
</span>
<!---->
Expand Down Expand Up @@ -3113,7 +3113,7 @@ exports[`ProTransfer > tree transfer render work 1`] = `
class="ix-transfer-header-label"
>
已选 (2)
已选 (3)
</span>
<!---->
Expand Down
161 changes: 109 additions & 52 deletions packages/pro/transfer/src/composables/useTreeDataStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,29 @@ import { type ComputedRef, type Ref, ref, watch } from 'vue'
import { type CascaderStrategy } from '@idux/components/cascader'

import { combineTrees, filterTree, flattenTree, genFlattenedTreeKeys, traverseTree } from '../utils'
import { useTreeDataStrategyContext } from './useTreeDataStrategyContext'
import { type TreeDataStrategyContext, useTreeDataStrategyContext } from './useTreeDataStrategyContext'

export function useTreeDataStrategies<C extends VKey>(
props: ProTransferProps,
childrenKey: ComputedRef<C>,
cascadeStrategy: ComputedRef<CascaderStrategy>,
): {
dataKeyMap: Map<VKey, TreeTransferData<C>>
parentKeyMap: Map<VKey, VKey | undefined>
dataStrategy: Ref<TransferDataStrategyProp<TreeTransferData<C>>>
context: TreeDataStrategyContext<C>
mergedDataStrategy: Ref<TransferDataStrategyProp<TreeTransferData<C>>>
} {
const { cachedTargetData, dataKeyMap, parentKeyMap, dataStrategy } = useTreeDataStrategyContext(props, childrenKey)

const context = useTreeDataStrategyContext(props, childrenKey)
const getMergedDataStrategy = () => ({
...dataStrategy,
...createStrategy(
childrenKey,
cachedTargetData,
parentKeyMap,
dataKeyMap,
cascadeStrategy.value,
props.flatTargetData,
),
...context.baseDataStrategy,
...createStrategy(context, childrenKey, cascadeStrategy.value, props.flatTargetData),
})
const mergedDataStrategy = ref<TransferDataStrategyProp<TreeTransferData<C>>>(getMergedDataStrategy())
watch([cascadeStrategy, childrenKey], () => {
mergedDataStrategy.value = getMergedDataStrategy()
})

return {
dataKeyMap,
parentKeyMap,
dataStrategy: mergedDataStrategy,
context,
mergedDataStrategy,
}
}

Expand Down Expand Up @@ -122,8 +112,10 @@ function createSeparateDataSourceFn<C extends VKey>(
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
cascaderStrategy: CascaderStrategy,
flatTargetData: boolean | 'all' = false,
targetDataCount: Ref<number>,
): Exclude<TransferDataStrategyProp<TreeTransferData<C>>['separateDataSource'], undefined> {
const targetDataKeySet = new Set<VKey>()

const getFilterFn = (
selectedKeySet: Set<VKey>,
getKey: GetKeyFn,
Expand All @@ -144,18 +136,23 @@ function createSeparateDataSourceFn<C extends VKey>(
}
})()

return (data, isSource) => {
if (isSource || (cascaderStrategy !== 'off' && !flatTargetData)) {
return filterTree(data, childrenKey.value, (item, parent) => filterFn(item, parent, isSource), 'or')
}

return flattenTree(
return (data, isSource) =>
filterTree(
data,
childrenKey.value,
item => ({ ...item, children: undefined }),
flatTargetData !== 'all' && cascaderStrategy !== 'off',
).filter(item => selectedKeySet.has(getKey(item)))
}
(item, parent) => {
const filterRes = filterFn(item, parent, isSource)

// set targetDataKeySet to collect targetData count later
// we collect this during filter process to avoid unecessary traveral
if (!isSource && filterRes) {
targetDataKeySet.add(getKey(item))
}

return filterRes
},
'or',
)
}

return (data, _, selectedKeySet, getKey) => {
Expand All @@ -164,6 +161,9 @@ function createSeparateDataSourceFn<C extends VKey>(
const newTargetData = filterData(data, false)
const previousTargetData = filterData(cachedTargetData.value, false)

targetDataCount.value = targetDataKeySet.size
targetDataKeySet.clear()

// combine new data with previous data
// beacause we intend to cache selected data after dataSource changes
const targetData = combineTrees(newTargetData, previousTargetData, childrenKey.value, getKey)
Expand All @@ -176,48 +176,90 @@ function createSeparateDataSourceFn<C extends VKey>(
}
}

function createStrategy<C extends VKey>(
function createSeparateDataSourceFnWithFlatten<C extends VKey>(
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
parentKeyMap: Map<VKey, VKey | undefined>,
dataKeyMap: Map<VKey, TreeTransferData<C>>,
cascaderStrategy: CascaderStrategy,
targetDataCount: Ref<number>,
flatTargetData: boolean | 'all' = false,
): Exclude<TransferDataStrategyProp<TreeTransferData<C>>['separateDataSource'], undefined> {
const fn = createSeparateDataSourceFn(childrenKey, cachedTargetData, cascaderStrategy, targetDataCount)

return (...args) => {
const { sourceData, targetData } = fn(...args)

return {
sourceData,
targetData: flattenTargetTree(targetData, childrenKey.value, cascaderStrategy, flatTargetData),
}
}
}

function flattenTargetTree<C extends VKey>(
data: TreeTransferData<C>[],
childrenKey: C,
cascaderStrategy: CascaderStrategy,
flatTargetData: boolean | 'all',
) {
if (cascaderStrategy !== 'off' && !flatTargetData) {
return data
}

return flattenTree(
data,
childrenKey,
item => ({ ...item, children: undefined }),
flatTargetData !== 'all' && cascaderStrategy !== 'off',
)
}

function createStrategy<C extends VKey>(
context: TreeDataStrategyContext<C>,
childrenKey: ComputedRef<C>,
cascaderStrategy: CascaderStrategy,
flatTargetData: boolean | 'all',
) {
switch (cascaderStrategy) {
case 'parent':
return createParentStrategy(childrenKey, cachedTargetData, dataKeyMap, flatTargetData)
return createParentStrategy(context, childrenKey, flatTargetData)
case 'child':
return createChildStrategy(childrenKey, cachedTargetData, parentKeyMap, flatTargetData)
return createChildStrategy(context, childrenKey, flatTargetData)
case 'off':
return createOffStrategy(childrenKey, cachedTargetData, flatTargetData)
return createOffStrategy(context, childrenKey, flatTargetData)
case 'all':
default:
return createAllStrategy(childrenKey, cachedTargetData, parentKeyMap, flatTargetData)
return createAllStrategy(context, childrenKey, flatTargetData)
}
}

function createAllStrategy<C extends VKey>(
context: TreeDataStrategyContext<C>,
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
parentKeyMap: Map<VKey, VKey | undefined>,
flatTargetData: boolean | 'all',
): TransferDataStrategyProp<TreeTransferData<C>> {
const { cachedTargetData, parentKeyMap, targetDataCount } = context
return {
genDisabledKeys: (data, getKey) => genDisabledKeys(data, getKey, childrenKey.value, true),
separateDataSource: createSeparateDataSourceFn(childrenKey, cachedTargetData, 'all', flatTargetData),
separateDataSource: createSeparateDataSourceFnWithFlatten(
childrenKey,
cachedTargetData,
'all',
targetDataCount,
flatTargetData,
),
getAllSelectedKeys: (selected, data, selectedKeySet, disabledKeySet, getKey) =>
getAllSelectedKeys(selected, data, selectedKeySet, disabledKeySet, getKey, childrenKey.value),
remove: (keys, selectedKeySet) => commonRemoveFn(keys, selectedKeySet, parentKeyMap),
}
}

function createChildStrategy<C extends VKey>(
context: TreeDataStrategyContext<C>,
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
parentKeyMap: Map<VKey, VKey | undefined>,
flatTargetData: boolean | 'all',
): TransferDataStrategyProp<TreeTransferData<C>> {
const { cachedTargetData, parentKeyMap, targetDataCount } = context

return {
genDisabledKeys: (data, getKey) => genDisabledKeys(data, getKey, childrenKey.value, true),
getAllSelectedKeys(selected, data, selectedKeySet, disabledKeySet, getKey) {
Expand All @@ -237,19 +279,24 @@ function createChildStrategy<C extends VKey>(

return keys
},
separateDataSource: createSeparateDataSourceFn(childrenKey, cachedTargetData, 'child', flatTargetData),
separateDataSource: createSeparateDataSourceFnWithFlatten(
childrenKey,
cachedTargetData,
'child',
targetDataCount,
flatTargetData,
),
remove: (keys, selectedKeySet) => commonRemoveFn(keys, selectedKeySet, parentKeyMap),
}
}

function createParentStrategy<C extends VKey>(
context: TreeDataStrategyContext<C>,
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
dataKeyMap: Map<VKey, TreeTransferData<C>>,
flatTargetData: boolean | 'all',
): TransferDataStrategyProp<TreeTransferData<C>> {
const separateDataSource = createSeparateDataSourceFn(childrenKey, cachedTargetData, 'parent', flatTargetData)
let targetData: TreeTransferData<C>[] = []
const { cachedTargetData, dataKeyMap, targetDataCount } = context
const separateDataSource = createSeparateDataSourceFn(childrenKey, cachedTargetData, 'parent', targetDataCount)

return {
genDisabledKeys: (data, getKey) => genDisabledKeys(data, getKey, childrenKey.value, true),
Expand Down Expand Up @@ -287,9 +334,11 @@ function createParentStrategy<C extends VKey>(
return keys
},
separateDataSource(data, _, selectedKeySet, getKey) {
const separatedData = separateDataSource(data, _, selectedKeySet, getKey)
targetData = separatedData.targetData
return separatedData
const { sourceData, targetData } = separateDataSource(data, _, selectedKeySet, getKey)
return {
sourceData,
targetData: flattenTargetTree(targetData, childrenKey.value, 'parent', flatTargetData),
}
},
append(keys, selectedKey, getKey) {
const newKeySet = new Set([...selectedKey, ...keys])
Expand Down Expand Up @@ -317,7 +366,7 @@ function createParentStrategy<C extends VKey>(
}

// it is not possible to get the correct selected keys from bottom to top
traverseTree(targetData, childrenKey.value, (item, parents) => {
traverseTree(cachedTargetData.value, childrenKey.value, (item, parents) => {
if (keySet.has(getKey(item))) {
const keysInChain = [item, ...parents].map(getKey)
const selectedKeyIdx = keysInChain.findIndex(key => newKeySet.has(key))
Expand Down Expand Up @@ -351,13 +400,21 @@ function createParentStrategy<C extends VKey>(
}

function createOffStrategy<C extends VKey>(
context: TreeDataStrategyContext<C>,
childrenKey: ComputedRef<C>,
cachedTargetData: Ref<TreeTransferData<C>[]>,
flatTargetData: boolean | 'all',
): TransferDataStrategyProp<TreeTransferData<C>> {
const { cachedTargetData, targetDataCount } = context

return {
genDisabledKeys: (data, getKey) => genDisabledKeys(data, getKey, childrenKey.value, false),
separateDataSource: createSeparateDataSourceFn(childrenKey, cachedTargetData, 'off', flatTargetData),
separateDataSource: createSeparateDataSourceFnWithFlatten(
childrenKey,
cachedTargetData,
'off',
targetDataCount,
flatTargetData,
),
getAllSelectedKeys: (selected, data, selectedKeySet, disabledKeySet, getKey) =>
getAllSelectedKeys(selected, data, selectedKeySet, disabledKeySet, getKey, childrenKey.value),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ import { type ComputedRef, type Ref, onUnmounted, ref } from 'vue'

import { filterTree, genFlattenedTreeKeys, traverseTree } from '../utils'

export function useTreeDataStrategyContext<C extends VKey>(
props: ProTransferProps,
childrenKey: ComputedRef<C>,
): {
export interface TreeDataStrategyContext<C extends VKey> {
baseDataStrategy: TransferDataStrategyProp<TreeTransferData<C>>
dataKeyMap: Map<VKey, TreeTransferData<C>>
parentKeyMap: Map<VKey, VKey | undefined>
cachedTargetData: Ref<TreeTransferData<C>[]>
dataStrategy: TransferDataStrategyProp<TreeTransferData<C>>
} {
targetDataCount: Ref<number>
}

export function useTreeDataStrategyContext<C extends VKey>(
props: ProTransferProps,
childrenKey: ComputedRef<C>,
): TreeDataStrategyContext<C> {
const cachedTargetData = ref(props.defaultTargetData ?? []) as Ref<TreeTransferData<C>[]>
const targetDataCount = ref(0)
const dataKeyMap: Map<VKey, TreeTransferData<C>> = new Map()
const parentKeyMap: Map<VKey, VKey | undefined> = new Map()

Expand All @@ -33,10 +37,11 @@ export function useTreeDataStrategyContext<C extends VKey>(
})

return {
cachedTargetData,
targetDataCount,
dataKeyMap,
parentKeyMap,
cachedTargetData,
dataStrategy: {
baseDataStrategy: {
genDataKeys: (data, getKey) => {
return new Set(genFlattenedTreeKeys(data, childrenKey.value, getKey))
},
Expand Down
Loading

0 comments on commit dd043cb

Please sign in to comment.