feat: compress singleton folder

This commit is contained in:
EnixCoda 2018-06-24 18:39:20 +08:00
parent 568221171d
commit 6c7823097b
3 changed files with 67 additions and 21 deletions

View file

@ -30,12 +30,12 @@ const tasksAfterRender = []
const visibleNodesGenerator = new VisibleNodesGenerator()
const init = dispatch => () => dispatch(async (state, { treeData, metaData, accessToken }) => {
const { root, nodes } = treeParser.parse(treeData, metaData)
visibleNodesGenerator.plantTree(root, nodes)
const { root } = treeParser.parse(treeData, metaData)
await visibleNodesGenerator.plantTree(root)
const currentPath = URLHelper.getCurrentPath(true)
tasksAfterRender.push(DOMHelper.focusSearchInput)
if (currentPath.length) {
const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath)
const nodeExpandedTo = visibleNodesGenerator.expandTo(currentPath.join('/'))
if (nodeExpandedTo) {
visibleNodesGenerator.focusNode(nodeExpandedTo)
const { nodes } = visibleNodesGenerator.visibleNodes

View file

@ -11,7 +11,7 @@ const nodeTemplate = {
function sortFoldersToFront(root) {
const isFolder = node => node.type === 'tree'
const isNotFolder = (...args) => !isFolder(...args)
const isNotFolder = node => !isFolder(node)
function depthFirstSearch(root) {
const nodes = root.contents
if (nodes) {
@ -73,7 +73,6 @@ function parse(treeData, metaData) {
setParentNode(root)
return {
root: sortFoldersToFront(root),
nodes: Array.from(pathToNode.values()),
}
}

View file

@ -26,7 +26,7 @@ function getFilterFunc(keyRegex) {
}
function search(treeNodes, searchKey) {
if (!searchKey) return
if (!searchKey) return treeNodes
/**
* if searchKey is 'abcd'
* then keyRegex will be /a.*?b.*?c.*?d/i
@ -53,27 +53,67 @@ function debounce(func, delay) {
export const debouncedSearch = debounce(search, 250)
function getNodes(root) {
if (!root.contents) return []
return [].concat(
...root.contents.map(node => [node, ...getNodes(node)])
)
}
function compressTree(root, prefix = []) {
if (root.contents) {
if (root.contents.length === 1) {
const singleton = root.contents[0]
if (singleton.type === 'tree') {
return compressTree(singleton, [...prefix, root.name])
}
}
}
return {
...root,
name: [...prefix, root.name].join('/'),
contents: root.contents
? root.contents.map(node => compressTree(node))
: undefined,
}
}
export default class VisibleNodesGenerator {
// LEVEL 1
root = null
nodes = null
plantTree(root, nodes) {
this.root = root
this.nodes = nodes
compressed = false
// a simplified sync 'search'
this.searchedNodes = this.root.contents
this.generateVisibleNodes()
getRoot() {
return this.compress && this.compressed
? this.compressedRoot
: this.root
}
async plantTree(root) {
this.root = root
this.nodes = getNodes(root)
this.compressedRoot = compressTree(root)
await this.search()
}
// LEVEL 2
searchedNodes = null
async search(searchKey) {
this.searchedNodes = (await debouncedSearch(this.nodes, searchKey)) || this.root.contents
this.compressed = !Boolean(searchKey)
this.searchedNodes = searchKey
? await debouncedSearch(this.nodes, searchKey)
: this.getRoot().contents
this.expandedNodes.clear()
this.generateVisibleNodes()
}
setCompress(compress) {
this.compress = compress
}
// LEVEL 3
expandedNodes = new Set()
depths = new Map()
@ -92,15 +132,22 @@ export default class VisibleNodesGenerator {
}
expandTo(path) {
let rootNode = this.root
let targetPath
for (const step of path) {
targetPath = rootNode.path ? `${rootNode.path}/${step}` : step
rootNode = rootNode.contents.find(node => node.path === targetPath)
if (!rootNode) return
this.setExpand(rootNode, true)
let root = this.getRoot()
const findNode = (root) => {
if (path.indexOf(root.path) === 0) {
if (root.path === path) return root
this.setExpand(root, true)
if (root.contents) {
for (const content of root.contents) {
const node = findNode(content)
if (node) return node
}
}
}
}
return rootNode
const node = findNode(root)
this.focusNode(node)
return node
}
visibleNodes = null