freeCodeCamp/common/app/Map/redux/utils.js

160 lines
3.5 KiB
JavaScript

import protect from '../../utils/empty-protector';
const throwIfUndefined = () => {
throw new Error('Challenge does not have a title');
};
export function createSearchTitle(
name = throwIfUndefined(),
challengeMap = {}
) {
return challengeMap[name] || name;
}
// interface Node {
// isHidden: Boolean,
// children: Void|[ ...Node ],
// isOpen?: Boolean
// }
//
// interface MapUi
// {
// children: [...{
// name: (superBlock: String),
// isOpen: Boolean,
// isHidden: Boolean,
// children: [...{
// name: (blockName: String),
// isOpen: Boolean,
// isHidden: Boolean,
// children: [...{
// name: (challengeName: String),
// isHidden: Boolean
// }]
// }]
// }]
// }
export function createMapUi(
{
block: blockMap,
challenge: challengeMap,
superBlock: superBlockMap
} = {},
{ superBlocks } = {}
) {
if (!superBlocks || !superBlockMap || !blockMap) {
return {};
}
return {
children: superBlocks.map(superBlock => {
return {
name: superBlock,
isOpen: false,
isHidden: false,
children: protect(superBlockMap[superBlock]).blocks.map(block => {
return {
name: block,
isOpen: false,
isHidden: false,
children: protect(blockMap[block]).challenges.map(challenge => {
return {
name: challenge,
title: createSearchTitle(challenge, challengeMap),
isHidden: false,
children: null
};
})
};
})
};
})
};
}
// synchronise
// traverseMapUi(
// tree: MapUi|Node,
// update: ((MapUi|Node) => MapUi|Node)
// ) => MapUi|Node
export function traverseMapUi(tree, update) {
let childrenChanged;
if (!Array.isArray(tree.children)) {
return update(tree);
}
const newChildren = tree.children.map(node => {
const newNode = traverseMapUi(node, update);
if (!childrenChanged && newNode !== node) {
childrenChanged = true;
}
return newNode;
});
if (childrenChanged) {
tree = {
...tree,
children: newChildren
};
}
return update(tree);
}
// synchronise
// getNode(tree: MapUi, name: String) => MapUi
export function getNode(tree, name) {
let node;
traverseMapUi(tree, thisNode => {
if (thisNode.name === name) {
node = thisNode;
}
return thisNode;
});
return node;
}
// synchronise
// updateSingelNode(
// tree: MapUi,
// name: String,
// update(MapUi|Node) => MapUi|Node
// ) => MapUi
export function updateSingleNode(tree, name, update) {
return traverseMapUi(tree, node => {
if (name !== node.name) {
return node;
}
return update(node);
});
}
// synchronise
// toggleThisPanel(tree: MapUi, name: String) => MapUi
export function toggleThisPanel(tree, name) {
return updateSingleNode(tree, name, node => {
return {
...node,
isOpen: !node.isOpen
};
});
}
// toggleAllPanels(tree: MapUi, isOpen: Boolean = false ) => MapUi
export function toggleAllPanels(tree, isOpen = false) {
return traverseMapUi(tree, node => {
if (!Array.isArray(node.children) || node.isOpen === isOpen) {
return node;
}
return {
...node,
isOpen
};
});
}
// collapseAllPanels(tree: MapUi) => MapUi
export function collapseAllPanels(tree) {
return toggleAllPanels(tree);
}
// expandAllPanels(tree: MapUi) => MapUi
export function expandAllPanels(tree) {
return toggleAllPanels(tree, true);
}