Skip to content

Commit

Permalink
Fixed #1967 and #1968 - For Tree
Browse files Browse the repository at this point in the history
  • Loading branch information
mertsincan committed Apr 20, 2021
1 parent 4099a73 commit 8fa96ea
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 31 deletions.
23 changes: 23 additions & 0 deletions src/components/tree/Tree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ declare namespace Tree {

type FilterModeType = 'lenient' | 'strict';

type HeaderTemplateType = React.ReactNode | ((options: HeaderTemplateOptions) => React.ReactNode);

type FooterTemplateType = React.ReactNode | ((props: TreeProps) => React.ReactNode);

interface HeaderTemplateOptions {
filterContainerClassName: string;
filterIconClasssName: string;
filterInput: FilterInputOptions;
filterElement: JSX.Element;
element: JSX.Element;
props: TreeProps;
}

interface FilterInputOptions {
className: string;
onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void;
onChange(event: React.KeyboardEvent<HTMLInputElement>): void;
}

interface SelectionKeysType {
[key: string]: boolean;
}
Expand Down Expand Up @@ -58,7 +77,10 @@ declare namespace Tree {
loading?: boolean;
loadingIcon?: string;
dragdropScope?: string;
header?: HeaderTemplateType;
footer?: FooterTemplateType;
filter?: boolean;
filterValue?: string;
filterBy?: string;
filterMode?: FilterModeType;
filterPlaceholder?: string;
Expand All @@ -73,6 +95,7 @@ declare namespace Tree {
onToggle?(e: ExpandedParams): void;
onDragDrop?(e: DragDropParams): void;
onContextMenu?(e: EventNodeParams): void;
onFilterValueChange?(e: React.FormEvent<HTMLInputElement>): void;
}
}

Expand Down
125 changes: 94 additions & 31 deletions src/components/tree/Tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { classNames } from '../utils/ClassNames';
import ObjectUtils from '../utils/ObjectUtils';
import {UITreeNode} from './UITreeNode';
import { UITreeNode } from './UITreeNode';

export class Tree extends Component {

Expand All @@ -26,7 +26,10 @@ export class Tree extends Component {
loading: false,
loadingIcon: 'pi pi-spinner',
dragdropScope: null,
header: null,
footer: null,
filter: false,
filterValue: null,
filterBy: 'label',
filterMode: 'lenient',
filterPlaceholder: null,
Expand All @@ -38,7 +41,8 @@ export class Tree extends Component {
onCollapse: null,
onToggle: null,
onDragDrop: null,
onContextMenu: null
onContextMenu: null,
onFilterValueChange: null
}

static propTypes = {
Expand All @@ -61,7 +65,10 @@ export class Tree extends Component {
loading: PropTypes.bool,
loadingIcon: PropTypes.string,
dragdropScope: PropTypes.string,
header: PropTypes.any,
footer: PropTypes.any,
filter: PropTypes.bool,
filterValue: PropTypes.string,
filterBy: PropTypes.any,
filterMode: PropTypes.string,
filterPlaceholder: PropTypes.string,
Expand All @@ -73,15 +80,18 @@ export class Tree extends Component {
onCollapse: PropTypes.func,
onToggle: PropTypes.func,
onDragDrop: PropTypes.func,
onContextMenu: PropTypes.func
onContextMenu: PropTypes.func,
onFilterValueChange: PropTypes.func
}

constructor(props) {
super(props);

this.state = {
filter: ''
};
this.state = {};

if (!this.props.onFilterValueChange) {
this.state['filterValue'] = '';
}

if (!this.props.onToggle) {
this.state['expandedKeys'] = this.props.expandedKeys;
Expand All @@ -97,6 +107,10 @@ export class Tree extends Component {
this.onFilterInputKeyDown = this.onFilterInputKeyDown.bind(this);
}

getFilterValue() {
return this.props.onFilterValueChange ? this.props.filterValue : this.state.filterValue;
}

getExpandedKeys() {
return this.props.onToggle ? this.props.expandedKeys : this.state.expandedKeys;
}
Expand Down Expand Up @@ -240,7 +254,7 @@ export class Tree extends Component {
let validateDrop = this.validateDrop(this.dragState.path, event.path);
if (validateDrop) {
//child dropped to next sibling's drop point
if (event.position === -1 && this.areSiblings(this.dragState.path, event.path) && (this.dragState.index +1 === event.index)) {
if (event.position === -1 && this.areSiblings(this.dragState.path, event.path) && (this.dragState.index + 1 === event.index)) {
return false;
}

Expand Down Expand Up @@ -289,25 +303,34 @@ export class Tree extends Component {

onFilterInputChange(event) {
this.filterChanged = true;
this.setState({filter: event.target.value});
let filterValue = event.target.value;

if (this.props.onFilterValueChange) {
this.props.onFilterValueChange(filterValue);
}
else {
this.setState({ filterValue });
}
}

filter() {
if (!this.filterChanged) {
return;
}

if (this.state.filter === '') {
const filterValue = this.getFilterValue();

if (filterValue === '') {
this.filteredNodes = this.props.value;
}
else {
this.filteredNodes = [];
const searchFields = this.props.filterBy.split(',');
const filterText = this.state.filter.toLocaleLowerCase(this.props.filterLocale);
const filterText = filterValue.toLocaleLowerCase(this.props.filterLocale);
const isStrictMode = this.props.filterMode === 'strict';
for(let node of this.props.value) {
let copyNode = {...node};
let paramsWithoutNode = {searchFields, filterText, isStrictMode};
for (let node of this.props.value) {
let copyNode = { ...node };
let paramsWithoutNode = { searchFields, filterText, isStrictMode };
if ((isStrictMode && (this.findFilteredNodes(copyNode, paramsWithoutNode) || this.isFilterMatched(copyNode, paramsWithoutNode))) ||
(!isStrictMode && (this.isFilterMatched(copyNode, paramsWithoutNode) || this.findFilteredNodes(copyNode, paramsWithoutNode)))) {
this.filteredNodes.push(copyNode);
Expand All @@ -325,7 +348,7 @@ export class Tree extends Component {
let childNodes = [...node.children];
node.children = [];
for (let childNode of childNodes) {
let copyChildNode = {...childNode};
let copyChildNode = { ...childNode };
if (this.isFilterMatched(copyChildNode, paramsWithoutNode)) {
matched = true;
node.children.push(copyChildNode);
Expand All @@ -339,31 +362,31 @@ export class Tree extends Component {
}
}

isFilterMatched(node, {searchFields, filterText, isStrictMode}) {
isFilterMatched(node, { searchFields, filterText, isStrictMode }) {
let matched = false;
for(let field of searchFields) {
for (let field of searchFields) {
let fieldValue = String(ObjectUtils.resolveFieldData(node, field)).toLocaleLowerCase(this.props.filterLocale);
if(fieldValue.indexOf(filterText) > -1) {
if (fieldValue.indexOf(filterText) > -1) {
matched = true;
}
}

if (!matched || (isStrictMode && !this.isNodeLeaf(node))) {
matched = this.findFilteredNodes(node, {searchFields, filterText, isStrictMode}) || matched;
matched = this.findFilteredNodes(node, { searchFields, filterText, isStrictMode }) || matched;
}

return matched;
}

renderRootChild(node, index, last) {
return (
<UITreeNode key={node.key||node.label} node={node} index={index} last={last} path={String(index)} disabled={this.props.disabled} selectionMode={this.props.selectionMode}
selectionKeys={this.props.selectionKeys} onSelectionChange={this.props.onSelectionChange} metaKeySelection={this.props.metaKeySelection}
contextMenuSelectionKey={this.props.contextMenuSelectionKey} onContextMenuSelectionChange={this.props.onContextMenuSelectionChange} onContextMenu={this.props.onContextMenu}
propagateSelectionDown={this.props.propagateSelectionDown} propagateSelectionUp={this.props.propagateSelectionUp}
onExpand={this.props.onExpand} onCollapse={this.props.onCollapse} onSelect={this.props.onSelect} onUnselect={this.props.onUnselect}
expandedKeys={this.getExpandedKeys()} onToggle={this.onToggle} nodeTemplate={this.props.nodeTemplate} isNodeLeaf={this.isNodeLeaf}
dragdropScope={this.props.dragdropScope} onDragStart={this.onDragStart} onDragEnd={this.onDragEnd} onDrop={this.onDrop} onDropPoint={this.onDropPoint} />
<UITreeNode key={node.key || node.label} node={node} index={index} last={last} path={String(index)} disabled={this.props.disabled} selectionMode={this.props.selectionMode}
selectionKeys={this.props.selectionKeys} onSelectionChange={this.props.onSelectionChange} metaKeySelection={this.props.metaKeySelection}
contextMenuSelectionKey={this.props.contextMenuSelectionKey} onContextMenuSelectionChange={this.props.onContextMenuSelectionChange} onContextMenu={this.props.onContextMenu}
propagateSelectionDown={this.props.propagateSelectionDown} propagateSelectionUp={this.props.propagateSelectionUp}
onExpand={this.props.onExpand} onCollapse={this.props.onCollapse} onSelect={this.props.onSelect} onUnselect={this.props.onUnselect}
expandedKeys={this.getExpandedKeys()} onToggle={this.onToggle} nodeTemplate={this.props.nodeTemplate} isNodeLeaf={this.isNodeLeaf}
dragdropScope={this.props.dragdropScope} onDragStart={this.onDragStart} onDragEnd={this.onDragEnd} onDrop={this.onDrop} onDropPoint={this.onDropPoint} />
);
}

Expand Down Expand Up @@ -411,15 +434,53 @@ export class Tree extends Component {
renderFilter() {
if (this.props.filter) {
return <div className="p-tree-filter-container">
<input type="text" autoComplete="off" className="p-tree-filter p-inputtext p-component" placeholder={this.props.filterPlaceholder}
onKeyDown={this.onFilterInputKeyDown} onChange={this.onFilterInputChange} disabled={this.props.disabled}/>
<span className="p-tree-filter-icon pi pi-search"></span>
</div>;
<input type="text" autoComplete="off" className="p-tree-filter p-inputtext p-component" placeholder={this.props.filterPlaceholder}
onKeyDown={this.onFilterInputKeyDown} onChange={this.onFilterInputChange} disabled={this.props.disabled} />
<span className="p-tree-filter-icon pi pi-search"></span>
</div>;
}

return null;
}

renderHeader() {
const filterElement = this.renderFilter();
let content = filterElement;

if (this.props.headerTemplate) {
const defaultContentOptions = {
filterContainerClassName: 'p-tree-filter-container',
filterIconClasssName: 'p-tree-filter-icon pi pi-search',
filterInput: {
className: 'p-tree-filter p-inputtext p-component',
onKeyDown: this.onFilterInputKeyDown,
onChange: this.onFilterInputChange
},
filterElement,
element: content,
props: this.props
};

content = ObjectUtils.getJSXElement(this.props.header, defaultContentOptions);
}

return (
<div className="p-tree-header">
{content}
</div>
);
}

renderFooter() {
const content = ObjectUtils.getJSXElement(this.props.footer, this.props);

return (
<div className="p-tree-footer">
{content}
</div>
);
}

render() {
const className = classNames('p-tree p-component', this.props.className, {
'p-tree-selectable': this.props.selectionMode,
Expand All @@ -428,13 +489,15 @@ export class Tree extends Component {
});
const loader = this.renderLoader();
const content = this.renderModel();
const filter = this.renderFilter();
const header = this.renderHeader();
const footer = this.renderFooter();

return (
<div id={this.props.id} className={className} style={this.props.style}>
{loader}
{filter}
{header}
{content}
{footer}
</div>
);
}
Expand Down
23 changes: 23 additions & 0 deletions src/showcase/tree/TreeDoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,18 @@ export const TreeContextMenuDemo = () => {
<td>false</td>
<td>Unique key to enable dragdrop functionality.</td>
</tr>
<tr>
<td>header</td>
<td>any</td>
<td>null</td>
<td>The template of header.</td>
</tr>
<tr>
<td>footer</td>
<td>any</td>
<td>null</td>
<td>The template of footer.</td>
</tr>
<tr>
<td>ariaLabel</td>
<td>string</td>
Expand All @@ -803,6 +815,12 @@ export const TreeContextMenuDemo = () => {
<td>false</td>
<td>When specified, displays an input field to filter the items.</td>
</tr>
<tr>
<td>filterValue</td>
<td>string</td>
<td>null</td>
<td>When filtering is enabled, the value of input field.</td>
</tr>
<tr>
<td>filterBy</td>
<td>string</td>
Expand Down Expand Up @@ -902,6 +920,11 @@ export const TreeContextMenuDemo = () => {
event.node: Selected node instance.</td>
<td>Callback to invoke when a node is selected with a context menu.</td>
</tr>
<tr>
<td>onFilterValueChange</td>
<td>event: browser event</td>
<td>Callback to invoke when the filter value is changed.</td>
</tr>
</tbody>
</table>
</div>
Expand Down

0 comments on commit 8fa96ea

Please sign in to comment.