160 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			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); | ||
|  | } |