1+ import { isEqual } from 'lodash' ;
12import PropTypes from 'prop-types' ;
23import React from 'react' ;
34import shortid from 'shortid' ;
@@ -34,32 +35,47 @@ class CheckboxTree extends React.Component {
3435 constructor ( props ) {
3536 super ( props ) ;
3637
38+ this . id = `rct-${ shortid . generate ( ) } ` ;
39+ this . nodes = { } ;
40+
41+ this . flattenNodes ( props . nodes ) ;
42+ this . unserializeLists ( {
43+ checked : props . checked ,
44+ expanded : props . expanded ,
45+ } ) ;
46+
3747 this . onCheck = this . onCheck . bind ( this ) ;
3848 this . onExpand = this . onExpand . bind ( this ) ;
49+ }
3950
40- this . id = `rct-${ shortid . generate ( ) } ` ;
51+ componentWillReceiveProps ( { nodes, checked, expanded } ) {
52+ if ( ! isEqual ( this . props . nodes , nodes ) ) {
53+ this . flattenNodes ( nodes ) ;
54+ }
55+
56+ this . unserializeLists ( { checked, expanded } ) ;
4157 }
4258
4359 onCheck ( node ) {
44- const { checked , onCheck } = this . props ;
60+ const { onCheck } = this . props ;
4561
46- onCheck ( this . toggleChecked ( [ ...checked ] , node , node . checked ) ) ;
62+ this . toggleChecked ( node , node . checked ) ;
63+ onCheck ( this . serializeList ( 'checked' ) ) ;
4764 }
4865
4966 onExpand ( node ) {
50- const { expanded , onExpand } = this . props ;
67+ const { onExpand } = this . props ;
5168
52- onExpand ( this . toggleNode ( [ ...expanded ] , node , node . expanded ) ) ;
69+ this . toggleNode ( 'expanded' , node , node . expanded ) ;
70+ onExpand ( this . serializeList ( 'expanded' ) ) ;
5371 }
5472
5573 getFormattedNodes ( nodes ) {
56- const { checked, expanded } = this . props ;
57-
5874 return nodes . map ( ( node ) => {
5975 const formatted = { ...node } ;
6076
61- formatted . checked = checked . indexOf ( node . value ) > - 1 ;
62- formatted . expanded = expanded . indexOf ( node . value ) > - 1 ;
77+ formatted . checked = this . nodes [ node . value ] . checked ;
78+ formatted . expanded = this . nodes [ node . value ] . expanded ;
6379
6480 if ( Array . isArray ( node . children ) && node . children . length > 0 ) {
6581 formatted . children = this . getFormattedNodes ( formatted . children ) ;
@@ -87,29 +103,58 @@ class CheckboxTree extends React.Component {
87103 return 0 ;
88104 }
89105
90- toggleChecked ( checked , node , isChecked ) {
106+ toggleChecked ( node , isChecked ) {
91107 if ( node . children !== null ) {
92108 // Percolate check status down to all children
93109 node . children . forEach ( ( child ) => {
94- this . toggleChecked ( checked , child , isChecked ) ;
110+ this . toggleChecked ( child , isChecked ) ;
95111 } ) ;
96112 } else {
97113 // Set leaf to check/unchecked state
98- this . toggleNode ( checked , node , isChecked ) ;
114+ this . toggleNode ( ' checked' , node , isChecked ) ;
99115 }
100-
101- return checked ;
102116 }
103117
104- toggleNode ( list , node , toggleValue ) {
105- const index = list . indexOf ( node . value ) ;
118+ toggleNode ( key , node , toggleValue ) {
119+ this . nodes [ node . value ] [ key ] = toggleValue ;
120+ }
106121
107- if ( index > - 1 && ! toggleValue ) {
108- list . splice ( index , 1 ) ;
109- } else if ( index === - 1 && toggleValue ) {
110- list . push ( node . value ) ;
122+ flattenNodes ( nodes ) {
123+ if ( ! Array . isArray ( nodes ) || nodes . length === 0 ) {
124+ return ;
111125 }
112126
127+ nodes . forEach ( ( node ) => {
128+ this . nodes [ node . value ] = { } ;
129+ this . flattenNodes ( node . children ) ;
130+ } ) ;
131+ }
132+
133+ unserializeLists ( lists ) {
134+ // Reset values to false
135+ Object . keys ( this . nodes ) . forEach ( ( value ) => {
136+ Object . keys ( lists ) . forEach ( ( listKey ) => {
137+ this . nodes [ value ] [ listKey ] = false ;
138+ } ) ;
139+ } ) ;
140+
141+ // Unserialize values and set their nodes to true
142+ Object . keys ( lists ) . forEach ( ( listKey ) => {
143+ lists [ listKey ] . forEach ( ( value ) => {
144+ this . nodes [ value ] [ listKey ] = true ;
145+ } ) ;
146+ } ) ;
147+ }
148+
149+ serializeList ( key ) {
150+ const list = [ ] ;
151+
152+ Object . keys ( this . nodes ) . forEach ( ( value ) => {
153+ if ( this . nodes [ value ] [ key ] ) {
154+ list . push ( value ) ;
155+ }
156+ } ) ;
157+
113158 return list ;
114159 }
115160
@@ -134,8 +179,8 @@ class CheckboxTree extends React.Component {
134179 }
135180
136181 renderTreeNodes ( nodes ) {
137- const treeNodes = nodes . map ( ( node , index ) => {
138- const key = `${ index } - ${ node . value } ` ;
182+ const treeNodes = nodes . map ( ( node ) => {
183+ const key = `${ node . value } ` ;
139184 const checked = this . getCheckState ( node ) ;
140185 const children = this . renderChildNodes ( node ) ;
141186
0 commit comments