<commit_before>import React from "react";
import SearchInput from "./search-input";
import NestedObjects from "nested-objects";
import _ from 'lodash'

/*
 *  @class InfinityMenu
 */
export default class InfinityMenu extends React.Component {
	/*
	 *  @constructs InfinityMenu
	 */
	constructor(props) {
		super(props);
		this.state = {
			search: {
				isSearching: false,
				searchInput: ""
			}
		};
		this.setSearchInput = this.setSearchInput.bind(this);
		this.stopSearching = this.stopSearching.bind(this);
		this.startSearching = this.startSearching.bind(this);
	}
	/*
	 *	@function onNodeClick
	 *	@description open or close folder
	 *
	 *	@param {string} folder - key name of folder object
	 */
	onNodeClick(tree, node, keyPath, event) {
		event.preventDefault();
		if (!this.state.search.isSearching || !this.state.search.searchInput.length) {
			node.isOpen = !node.isOpen;
			node.maxLeaves = this.props.maxLeaves;
			NestedObjects.set(tree, keyPath, node);
			if (this.props.onNodeMouseClick) {
				const currLevel = Math.floor(keyPath.split(".").length / 2);
				this.props.onNodeMouseClick(event, tree, node, currLevel, keyPath);
			}
		}
	}

	onLoadMoreClick(tree, node, keyPath, event) {
		event.preventDefault();
		// get parent node so we can increment it's unique max leaves property
		const keyPathArray = keyPath.split('.')
		const parentPath = Object.assign([],keyPathArray).splice(0, keyPathArray.length - 2)
		const parentNode = _.get(this.props.tree, parentPath)
		// set new max leaves - if none exist use component default property
		parentNode.maxLeaves = (!parentNode.maxLeaves) ? this.props.maxLeaves : parentNode.maxLeaves + this.props.maxLeaves;
		if (this.props.onNodeMouseClick) {
			const currLevel = Math.floor(keyPath.split(".").length / 2);
			this.props.onNodeMouseClick(event, tree, node, currLevel, keyPath);
		}
	}
	/*
	* @function shouldComponentUpdate
	* @returns {boolean} return based on user pass in shouldComponentUpdate or return true
	*/
	shouldComponentUpdate(nextProps, nextState) {
		if (nextProps.shouldComponentUpdate) {
			return nextProps.shouldComponentUpdate(this.props, this.state, nextProps, nextState);
		}
		else {
			return true;
		}
	}
	/*
	 *	@function startSearching
	 *	@description when not searching and search icon clicked, set state to start
	 */
	startSearching() {
		this.setState({
			search: {
				isSearching: true,
				searchInput: ""
			}
		});
	}
	/*
	 *	@function stopSearching
	 *	@description when searching and close icon clicked, set state to stop
	 */
	stopSearching() {
		this.setState({
			search: {
				isSearching: false,
				searchInput: ""
			}
		});
	}
	/*
	 *	@function setSearchInput
	 *	@description when user types in search input, set phrase in state for filter
	 */
	setSearchInput(event) {
		this.setState({
			search: {
				isSearching: true,
				searchInput: event.target.value
			}
		});
	}

	findFiltered(trees, node, key) {
		if (!node.children) {
			const nodeMatchesSearchFilter = this.props.filter(node, this.state.search.searchInput);
			if (nodeMatchesSearchFilter) {
				node.isSearchDisplay = true;
				trees[key] = node;
				return trees;
			}
			else {
				node.isSearchDisplay = false;
				trees[key] = node;
				return trees;
			}
		}
		else {
			const filteredSubFolder = node.children.length ? node.children.reduce((p, c, k) => {
				return this.findFiltered(p, c, k);
			}, []) : [];
			const shouldDisplay = filteredSubFolder.some(child => child.isSearchDisplay);

			if (shouldDisplay) {
				node.isSearchOpen = true;
				node.children = filteredSubFolder;
				node.isSearchDisplay = true;
				node.maxLeaves = (node.maxLeaves) ? node.maxLeaves : this.props.maxLeaves;
				trees[key] = node;
				return trees;
			}
			else {
				node.isSearchOpen = false;
				node.isSearchDisplay = false;
				trees[key] = node;
				return trees;
			}
		}
	}

	/*
	 *	@function setDisplayTree
	 *	@description recursive go through the tree and set the render tree
	 *
	 *	@param {array} tree - whole tree
	 *	@param {array} prevs - the whole rendering array
	 *	@param {object} curr - current node/leaf
	 *	@param {string} keyPath - the path to current node/leaf, e.g.  "0.children.1"
	 */
	setDisplayTree(tree, prevs, curr, keyPath) {
		const currLevel = Math.floor(keyPath.length / 2);
		const currCustomComponent = typeof curr.customComponent === 'string' ? this.props.customComponentMappings[curr.customComponent] : curr.customComponent;
		const currCustomloadMoreComponent = (this.props.loadMoreComponent) ? this.props.loadMoreComponent : null
		const isSearching = this.state.search.isSearching && this.state.search.searchInput;
		const shouldDisplay = (isSearching && curr.isSearchDisplay) || !isSearching;
		/*the leaves*/

		if (!curr.children) {
			const keyPathArray = keyPath.split('.')
			const parentPath = Object.assign([],keyPathArray).splice(0, keyPathArray.length - 2)
			const parentNode = _.get(this.props.tree, parentPath)
			const filteredChildren = (_.some(parentNode.children,{isSearchDisplay: true})) ? _.filter(parentNode.children,{isSearchDisplay: true}) : parentNode.children

			const itemKey = "infinity-menu-leaf-" + curr.id;

			const visIds = filteredChildren.map((e) => e.id)
			curr.keyPath = keyPath;

			let relativeIndex = visIds.indexOf(curr.id)
			relativeIndex = (relativeIndex === -1) ? Infinity : relativeIndex

			let parentMaxLeaves = parentNode.maxLeaves || this.props.maxLeaves
			if (shouldDisplay && parentMaxLeaves > relativeIndex ) {
				if (curr.customComponent) {
					const componentProps = {
						key: itemKey,
						onMouseDown: this.props.onLeafMouseDown,
						onMouseUp: this.props.onLeafMouseUp,
						onClick: this.props.onLeafMouseClick,
						name: curr.name,
						icon: curr.icon,
						data: curr
					};<commit_msg>pass curr leaf object to customize component onClick<commit_after>import React from "react";
import SearchInput from "./search-input";
import NestedObjects from "nested-objects";
import _ from 'lodash'

/*
 *  @class InfinityMenu
 */
export default class InfinityMenu extends React.Component {
	/*
	 *  @constructs InfinityMenu
	 */
	constructor(props) {
		super(props);
		this.state = {
			search: {
				isSearching: false,
				searchInput: ""
			}
		};
		this.setSearchInput = this.setSearchInput.bind(this);
		this.stopSearching = this.stopSearching.bind(this);
		this.startSearching = this.startSearching.bind(this);
	}
	/*
	 *	@function onNodeClick
	 *	@description open or close folder
	 *
	 *	@param {string} folder - key name of folder object
	 */
	onNodeClick(tree, node, keyPath, event) {
		event.preventDefault();
		if (!this.state.search.isSearching || !this.state.search.searchInput.length) {
			node.isOpen = !node.isOpen;
			node.maxLeaves = this.props.maxLeaves;
			NestedObjects.set(tree, keyPath, node);
			if (this.props.onNodeMouseClick) {
				const currLevel = Math.floor(keyPath.split(".").length / 2);
				this.props.onNodeMouseClick(event, tree, node, currLevel, keyPath);
			}
		}
	}

	onLoadMoreClick(tree, node, keyPath, event) {
		event.preventDefault();
		// get parent node so we can increment it's unique max leaves property
		const keyPathArray = keyPath.split('.')
		const parentPath = Object.assign([],keyPathArray).splice(0, keyPathArray.length - 2)
		const parentNode = _.get(this.props.tree, parentPath)
		// set new max leaves - if none exist use component default property
		parentNode.maxLeaves = (!parentNode.maxLeaves) ? this.props.maxLeaves : parentNode.maxLeaves + this.props.maxLeaves;
		if (this.props.onNodeMouseClick) {
			const currLevel = Math.floor(keyPath.split(".").length / 2);
			this.props.onNodeMouseClick(event, tree, node, currLevel, keyPath);
		}
	}
	/*
	* @function shouldComponentUpdate
	* @returns {boolean} return based on user pass in shouldComponentUpdate or return true
	*/
	shouldComponentUpdate(nextProps, nextState) {
		if (nextProps.shouldComponentUpdate) {
			return nextProps.shouldComponentUpdate(this.props, this.state, nextProps, nextState);
		}
		else {
			return true;
		}
	}
	/*
	 *	@function startSearching
	 *	@description when not searching and search icon clicked, set state to start
	 */
	startSearching() {
		this.setState({
			search: {
				isSearching: true,
				searchInput: ""
			}
		});
	}
	/*
	 *	@function stopSearching
	 *	@description when searching and close icon clicked, set state to stop
	 */
	stopSearching() {
		this.setState({
			search: {
				isSearching: false,
				searchInput: ""
			}
		});
	}
	/*
	 *	@function setSearchInput
	 *	@description when user types in search input, set phrase in state for filter
	 */
	setSearchInput(event) {
		this.setState({
			search: {
				isSearching: true,
				searchInput: event.target.value
			}
		});
	}

	findFiltered(trees, node, key) {
		if (!node.children) {
			const nodeMatchesSearchFilter = this.props.filter(node, this.state.search.searchInput);
			if (nodeMatchesSearchFilter) {
				node.isSearchDisplay = true;
				trees[key] = node;
				return trees;
			}
			else {
				node.isSearchDisplay = false;
				trees[key] = node;
				return trees;
			}
		}
		else {
			const filteredSubFolder = node.children.length ? node.children.reduce((p, c, k) => {
				return this.findFiltered(p, c, k);
			}, []) : [];
			const shouldDisplay = filteredSubFolder.some(child => child.isSearchDisplay);

			if (shouldDisplay) {
				node.isSearchOpen = true;
				node.children = filteredSubFolder;
				node.isSearchDisplay = true;
				node.maxLeaves = (node.maxLeaves) ? node.maxLeaves : this.props.maxLeaves;
				trees[key] = node;
				return trees;
			}
			else {
				node.isSearchOpen = false;
				node.isSearchDisplay = false;
				trees[key] = node;
				return trees;
			}
		}
	}

	/*
	 *	@function setDisplayTree
	 *	@description recursive go through the tree and set the render tree
	 *
	 *	@param {array} tree - whole tree
	 *	@param {array} prevs - the whole rendering array
	 *	@param {object} curr - current node/leaf
	 *	@param {string} keyPath - the path to current node/leaf, e.g.  "0.children.1"
	 */
	setDisplayTree(tree, prevs, curr, keyPath) {
		const currLevel = Math.floor(keyPath.length / 2);
		const currCustomComponent = typeof curr.customComponent === 'string' ? this.props.customComponentMappings[curr.customComponent] : curr.customComponent;
		const currCustomloadMoreComponent = (this.props.loadMoreComponent) ? this.props.loadMoreComponent : null
		const isSearching = this.state.search.isSearching && this.state.search.searchInput;
		const shouldDisplay = (isSearching && curr.isSearchDisplay) || !isSearching;
		curr.keyPath = keyPath;

		/*the leaves*/
		if (!curr.children) {
			const keyPathArray = keyPath.split('.')
			const parentPath = Object.assign([],keyPathArray).splice(0, keyPathArray.length - 2)
			const parentNode = _.get(this.props.tree, parentPath)
			const filteredChildren = (_.some(parentNode.children,{isSearchDisplay: true})) ? _.filter(parentNode.children,{isSearchDisplay: true}) : parentNode.children
			const itemKey = "infinity-menu-leaf-" + curr.id;
			const visIds = filteredChildren.map((e) => e.id)


			let relativeIndex = visIds.indexOf(curr.id)
			relativeIndex = (relativeIndex === -1) ? Infinity : relativeIndex

			let parentMaxLeaves = parentNode.maxLeaves || this.props.maxLeaves
			if (shouldDisplay && parentMaxLeaves > relativeIndex ) {
				if (curr.customComponent) {
					const componentProps = {
						key: itemKey,
						onMouseDown: (e) => {this.props.onLeafMouseDown ? this.props.onLeafMouseDown(e, curr) : null},
						onMouseUp: (e) => {this.props.onLeafMouseUp ? this.props.onLeafMouseUp(e, curr) : null},
						onClick: (e) => {this.props.onLeafMouseClick ? this.props.onLeafMouseClick(e, curr) : null},
						name: curr.name,
						icon: curr.icon,
						data: curr
					};
{'fraction_non_alphanumeric': 0.12421463745967057, 'fraction_numerical': 0.0016980811682798438, 'mean_word_length': 3.6538917423943107, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1316705', 'n_tokens_mistral': 4303, 'n_tokens_neox': 3766, 'n_words': 863}