From 6c7823097b32e27016e76d823a41e2c6be9c4bfa Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 24 Jun 2018 18:39:20 +0800 Subject: [PATCH] feat: compress singleton folder --- src/components/FileExplorer.js | 6 +-- src/utils/treeParser.js | 3 +- src/utils/visibleNodesGenerator.js | 79 ++++++++++++++++++++++++------ 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/components/FileExplorer.js b/src/components/FileExplorer.js index d50a282..82e3869 100644 --- a/src/components/FileExplorer.js +++ b/src/components/FileExplorer.js @@ -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 diff --git a/src/utils/treeParser.js b/src/utils/treeParser.js index 37f75ee..39df1f4 100644 --- a/src/utils/treeParser.js +++ b/src/utils/treeParser.js @@ -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()), } } diff --git a/src/utils/visibleNodesGenerator.js b/src/utils/visibleNodesGenerator.js index 8a735ef..06a400c 100644 --- a/src/utils/visibleNodesGenerator.js +++ b/src/utils/visibleNodesGenerator.js @@ -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