UNPKG

@uppy/provider-views

Version:

View library for Uppy remote provider plugins.

95 lines (92 loc) 3.89 kB
import shallowClone from './shallowClone.js'; /* FROM | TO root | root folder | folder folder ✅︎ | folder ✅︎ file | file ✅︎ file | file ✅︎ folder | folder ✅︎ file | file ✅︎ file | file file | file */ const percolateDown = (tree, id, shouldMarkAsChecked) => { const children = tree.filter((item) => item.type !== 'root' && item.parentId === id); children.forEach((item) => { item.status = shouldMarkAsChecked && !(item.type === 'file' && item.restrictionError) ? 'checked' : 'unchecked'; percolateDown(tree, item.id, shouldMarkAsChecked); }); }; /* FROM | TO root | root folder | folder folder | folder [▬] ('partial' status) file | file folder | folder ✅︎ file ✅︎ | file ✅︎ file | file file | file */ const percolateUp = (tree, id) => { const folder = tree.find((item) => item.id === id); if (folder.type === 'root') return; const validChildren = tree.filter((item) => // is a child item.type !== 'root' && item.parentId === folder.id && // does pass validations !(item.type === 'file' && item.restrictionError)); const areAllChildrenChecked = validChildren.every((item) => item.status === 'checked'); const areAllChildrenUnchecked = validChildren.every((item) => item.status === 'unchecked'); /** * We should *only* set parent folder to checked/unchecked if it has been fully read (`cached`). * Otherwise, checking a nested folder from the search view also marks its parent as checked, * which could be incorrect because there might be more unselected (unloaded) files. * * Example: /foo/bar/new/myfolder * If we search for "myfolder", we only build the minimal path (using ProviderView.#buildSearchResultPath) * up to that folder adding nodes for "bar", "new", and "myfolder" (assuming "foo" is already * present in the partialTree as part of the root folder). * Since "foo", "bar", and "new" aren’t fully fetched yet, we don’t know if they have other children. * If the user checks "myfolder" from the search results and we propagate the checked state * upward without verifying parent.cached, it would incorrectly mark all its parents as checked. * Later, when the user navigates to any of "foo", "bar", "new" through the Normal View (via breadcrumbs or manually), * PartialTreeUtils.afterOpenFolder would then incorrectly mark and display all its children as checked. */ if (areAllChildrenChecked && folder.cached) { folder.status = 'checked'; } else if (areAllChildrenUnchecked) { folder.status = 'unchecked'; } else { folder.status = 'partial'; } percolateUp(tree, folder.parentId); }; const afterToggleCheckbox = (oldTree, checkedIds) => { const tree = shallowClone(oldTree); const newlyCheckedItems = tree.filter((item) => item.type !== 'root' && checkedIds.includes(item.id)); newlyCheckedItems.forEach((item) => { // allow toggling: const newStatus = item.status === 'checked' ? 'unchecked' : 'checked'; // and if it's a file, we need to respect restrictions if (item.type === 'file') { item.status = item.restrictionError ? 'unchecked' : newStatus; } else { item.status = newStatus; } percolateDown(tree, item.id, item.status === 'checked'); }); // all checked items have the same parent so we only need to perlocate the first item percolateUp(tree, newlyCheckedItems[0].parentId); return tree; }; export default afterToggleCheckbox;