import * as React from 'react'; import { cloneChoice, getMmuiCheckedDropChoices } from './utils'; import { MmuiDropChoiceComponent, Props } from './MmuiDropChoiceComponent'; /** * Drop Choice Component * A multi-select dropdown that allows for choice filtering. * * token: a thing serving as a visible or tangible representation of a fact */ export interface MmuiDropChoiceMultipleProps extends Props { hasParentSelection: boolean; } export class MmuiDropChoiceMultipleComponent< P extends MmuiDropChoiceMultipleProps > extends MmuiDropChoiceComponent
{ static defaultProps = { hasParentSelection: true, }; /** * Constructor * @param props * */ constructor(props: P) { super(props); } getCheckedChoices() { return getMmuiCheckedDropChoices(this.state.choices); } /** * Update the state of the choice that matches the provided changed choice. * @param changedChoice */ updateChoice(changedChoice) { let choice, newChoice, childChoice, newChildChoice, newChoices = [], selectedChoiceCount = 0; for (let p = 0; p < this.state.choices.length; p++) { choice = this.state.choices[p]; newChoice = cloneChoice(choice); // if changed choice is a parent if (newChoice.id == changedChoice.id) { newChoice.isChecked = changedChoice.isChecked; newChoice.isIndeterminate = false; if (choice.children && choice.children.length > 0) { newChoice.children = []; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); //set all children to the same state as parent newChildChoice.isChecked = newChoice.isChecked; newChoice.children.push(newChildChoice); } } } else if (choice.children && choice.children.length > 0) { newChoice.children = []; let isAllChecked = true, isAnyChecked = false; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); if (newChildChoice.id === changedChoice.id) { newChildChoice.isChecked = changedChoice.isChecked; } isAllChecked = isAllChecked && newChildChoice.isChecked; isAnyChecked = isAnyChecked || newChildChoice.isChecked; newChoice.children.push(newChildChoice); } newChoice.isChecked = isAllChecked; if (isAllChecked) { newChoice.isIndeterminate = false; } else { newChoice.isIndeterminate = isAnyChecked; } } if (newChoice.isChecked) { selectedChoiceCount = selectedChoiceCount + 1; } newChoices.push(newChoice); } this.setState({ choices: newChoices, selectedChoiceCount: selectedChoiceCount, }); } applyFilter(filterValue: string) { let isVisibleParent, hasVisibleChildren, choice, newChoice, childChoice, newChildChoice, newChoices = []; for (let p = 0; p < this.state.choices.length; p++) { choice = this.state.choices[p]; newChoice = cloneChoice(choice); if (filterValue) { isVisibleParent = newChoice.display .toLowerCase() .includes(filterValue.toLowerCase()); hasVisibleChildren = false; if (choice.children && choice.children.length > 0) { newChoice.children = []; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); newChildChoice.isVisible = newChildChoice.display .toLowerCase() .includes(filterValue.toLowerCase()); hasVisibleChildren = hasVisibleChildren || newChildChoice.isVisible; newChoice.children.push(newChildChoice); } } newChoice.isVisible = isVisibleParent || hasVisibleChildren; } else { newChoice.isVisible = true; if (choice.children && choice.children.length > 0) { newChoice.children = []; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); newChildChoice.isVisible = true; newChoice.children.push(newChildChoice); } } } newChoices.push(newChoice); } this.setState({ choices: newChoices }); } /** * Called when the component's props or state has been updated. */ componentDidUpdate() { if (this.props.hasParentSelection) { let choice, choiceElmt; for (let p = 0; p < this.state.choices.length; p++) { choice = this.state.choices[p]; choiceElmt = document.getElementById(choice.id); choiceElmt.indeterminate = choice.isIndeterminate; } } } removeToken(choiceId: string, config?: any) { let choice, newChoice, childChoice, newChildChoice, newChoices = [], selectedChoiceCount = 0; for (let p = 0; p < this.state.choices.length; p++) { choice = this.state.choices[p]; newChoice = cloneChoice(choice); if (newChoice.id === choiceId) { newChoice.isChecked = false; if (choice.children && choice.children.length > 0) { newChoice.children = []; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); newChildChoice.isChecked = false; newChoice.children.push(newChildChoice); } } } else if (choice.children && choice.children.length > 0) { newChoice.children = []; let isAnyChecked = false; for (let c = 0; c < choice.children.length; c++) { childChoice = choice.children[c]; newChildChoice = cloneChoice(childChoice); if (newChildChoice.id === choiceId) { newChildChoice.isChecked = false; newChoice.isChecked = false; } isAnyChecked = isAnyChecked || newChildChoice.isChecked; newChoice.children.push(newChildChoice); } if (!newChoice.isChecked) { newChoice.isIndeterminate = isAnyChecked; } } if (newChoice.isChecked) { selectedChoiceCount = selectedChoiceCount + 1; } newChoices.push(newChoice); } const setStateCallback = config && config.setStateCallback ? config.setStateCallback : undefined; this.setState( { choices: newChoices, selectedChoiceCount: selectedChoiceCount, }, setStateCallback ); } /** * Build the summary of selected choices using just text. */ getTextSummaryRender() { let summaryDisplayRender, summaryCountDisplay, //Converts the choice option object into a display value to be used in the summary. // eslint-disable-next-line @typescript-eslint/no-unused-vars choiceDisplayMapper = (choice, index = 0, parent = undefined) => { let display = choice.display, isCheckedParent = choice.isChecked && choice.children && choice.children.length > 0; if (parent) { display = `${parent.display} - ${display}`; } else if (isCheckedParent) { display = `${display} - All`; } return display; }; if (this.state.choices.length > 0) { let choice, choiceChild, choiceDisplays = []; for (let i = 0; i < this.state.choices.length; i++) { choice = this.state.choices[i]; if (choice.isChecked) { choiceDisplays.push(choiceDisplayMapper(choice, i)); } else if (choice.children) { for (let j = 0; j < choice.children.length; j++) { choiceChild = choice.children[j]; if (choiceChild.isChecked) { choiceDisplays.push( choiceDisplayMapper(choiceChild, j, choice) ); } } } } if (choiceDisplays.length > 0) { if (this.state.isOpen) { summaryDisplayRender = (