@@ -10,24 +10,6 @@ define([
10
10
] , function ( $ ) {
11
11
'use strict' ;
12
12
13
- /**
14
- * Recursively adds the 'lastNode' property to the nodes in the nested object.
15
- *
16
- * @param {Array } nodes
17
- * @returns {Array }
18
- */
19
- function addLastNodeProperty ( nodes ) {
20
- return nodes . map ( node => {
21
- return node . children ? {
22
- ...node ,
23
- children : addLastNodeProperty ( node . children )
24
- } : {
25
- ...node ,
26
- lastNode : true
27
- } ;
28
- } ) ;
29
- }
30
-
31
13
/**
32
14
* Main function that creates the jstree
33
15
*
@@ -48,142 +30,93 @@ define([
48
30
rootId : config . rootId ,
49
31
expanded : config . expanded ,
50
32
categoryId : config . categoryId ,
51
- treeJson : addLastNodeProperty ( config . treeJson )
33
+ treeJson : config . treeJson
52
34
} ,
53
- checkedNodes = [ ] ;
35
+ initialSelection = [ ] ;
54
36
55
37
/**
56
38
* Get the jstree element by its ID
57
39
*/
58
40
const treeId = $ ( '#' + options . divId ) ;
59
41
60
42
/**
61
- * Function to check child nodes based on the checkedNodes array
62
- *
63
- * @param {Object } node
43
+ * @return {Element }
64
44
*/
65
- function getCheckedNodeIds ( node ) {
66
- if ( node . children_d && node . children_d . length > 0 ) {
67
- const selectChildrenNodes = node . children_d . filter ( item => checkedNodes . includes ( item ) ) ;
68
-
69
- if ( selectChildrenNodes . length > 0 ) {
70
- treeId . jstree ( false ) . select_node ( selectChildrenNodes ) ;
71
- }
72
- }
45
+ function getTargetInput ( ) {
46
+ return options . jsFormObject . updateElement ;
73
47
}
74
48
75
49
/**
76
- * Initialize the jstree with configuration options
77
- */
78
- treeId . jstree ( {
79
- core : {
80
- data : options . treeJson ,
81
- check_callback : true
82
- } ,
83
- plugins : [ 'checkbox' ] ,
84
- checkbox : {
85
- three_state : false
86
- }
87
- } ) ;
88
-
89
- /**
90
- * Event handler for 'loaded.jstree' event
50
+ * Recursively marks nodes which children are not loaded.
51
+ *
52
+ * @param {Array } nodes
53
+ * @returns {Array }
91
54
*/
92
- treeId . on ( 'loaded.jstree' , function ( ) {
55
+ function prepareNodes ( nodes ) {
56
+ return nodes . map (
57
+ function ( node ) {
58
+ let obj = { ...node , state : { } } ;
59
+
60
+ if ( Array . isArray ( obj . children ) ) {
61
+ if ( obj . children . length > 0 ) {
62
+ obj . children = prepareNodes ( obj . children ) ;
63
+ } else {
64
+ obj . children = true ;
65
+ }
66
+ }
93
67
94
- /**
95
- * Get each node in the tree
96
- */
97
- $ ( treeId . jstree ( ) . get_json ( '#' , {
98
- flat : false
99
- } ) ) . each ( function ( ) {
100
- let node = treeId . jstree ( ) . get_node ( this . id , false ) ;
68
+ if ( obj . expanded ) {
69
+ obj . state . opened = true ;
70
+ }
101
71
102
- if ( node . original . expanded ) {
103
- treeId . jstree ( true ) . open_node ( node ) ;
104
- }
72
+ if ( initialSelection . includes ( obj . id ) ) {
73
+ obj . state . selected = true ;
74
+ }
105
75
106
- if ( options . jsFormObject . updateElement . defaultValue ) {
107
- checkedNodes = options . jsFormObject . updateElement . defaultValue . split ( ',' ) ;
76
+ return obj ;
108
77
}
109
- } ) ;
110
- } ) ;
111
-
112
- /**
113
- * Event handler for 'load_node.jstree' event
114
- */
115
- treeId . on ( 'load_node.jstree' , function ( e , data ) {
116
- getCheckedNodeIds ( data . node ) ;
117
- } ) ;
118
-
119
- /**
120
- * Add lastNode property to child who doesn't have children property
121
- *
122
- * @param {Object } treeData
123
- */
124
- function addLastNodeFlag ( treeData ) {
125
- if ( treeData . children ) {
126
- treeData . children . forEach ( ( child ) => addLastNodeFlag ( child ) ) ;
127
- } else {
128
- treeData . lastNode = true ;
129
- }
78
+ ) ;
130
79
}
131
80
132
81
/**
133
- * Function to handle the 'success' callback of the AJAX request
82
+ * Load the node and execute the callback function
134
83
*
135
- * @param {Array } response
136
- * @param {Object } childNode
137
- * @param {Object } data
84
+ * @param {Object } node
85
+ * @param {Function } callback
138
86
*/
139
- function handleSuccessResponse ( response , childNode , data ) {
140
- if ( response . length > 0 ) {
141
- response . forEach ( function ( newNode ) {
142
- addLastNodeFlag ( newNode ) ;
143
-
144
- /**
145
- * Create the new node and execute node callback
146
- */
147
- data . instance . create_node ( childNode , newNode , 'last' , function ( node ) {
148
- if ( checkedNodes . includes ( node . id ) ) {
149
- treeId . jstree ( false ) . select_node ( node . id ) ;
150
- }
151
- getCheckedNodeIds ( node ) ;
152
- } ) ;
87
+ function load ( node , callback ) {
88
+ let target = getTargetInput ( ) ,
89
+ instance = this ;
90
+
91
+ if ( node . id === $ . jstree . root ) {
92
+ callback . call ( instance , prepareNodes ( options . treeJson ) ) ;
93
+ } else if ( Array . isArray ( node . children ) && node . children . length === 0 ) {
94
+ $ . ajax ( {
95
+ url : options . dataUrl ,
96
+ data : {
97
+ id : node . id ,
98
+ selected : target . value
99
+ } ,
100
+ dataType : 'json' ,
101
+ success : function ( response ) {
102
+ callback . call ( instance , prepareNodes ( response ) ) ;
103
+ } ,
104
+ error : function ( jqXHR , status , error ) {
105
+ console . log ( status + ': ' + error + '\nResponse text:\n' + jqXHR . responseText ) ;
106
+ }
153
107
} ) ;
108
+ } else {
109
+ callback . call ( instance , false ) ;
154
110
}
155
111
}
156
112
157
113
/**
158
- * Event handler for 'open_node .jstree' event
114
+ * Event handler for 'init .jstree' event
159
115
*/
160
- treeId . on ( 'open_node.jstree' , function ( e , data ) {
161
- let parentNode = data . node ;
162
-
163
- if ( parentNode . children . length > 0 ) {
164
- let childNode = data . instance . get_node ( parentNode . children , false ) ;
165
-
166
- /**
167
- * Check if the child node has no children (is not yet loaded)
168
- */
169
- if ( childNode . children && childNode . children . length === 0
170
- && childNode . original && ! childNode . original . lastNode ) {
171
- $ . ajax ( {
172
- url : options . dataUrl ,
173
- data : {
174
- id : childNode . id ,
175
- selected : options . jsFormObject . updateElement . value
176
- } ,
177
- dataType : 'json' ,
178
- success : function ( response ) {
179
- handleSuccessResponse ( response , childNode , data ) ;
180
- } ,
181
- error : function ( jqXHR , status , error ) {
182
- console . log ( status + ': ' + error + '\nResponse text:\n' + jqXHR . responseText ) ;
183
- }
184
- } ) ;
185
- }
186
- }
116
+ treeId . on ( 'init.jstree' , function ( ) {
117
+ let target = getTargetInput ( ) ;
118
+
119
+ initialSelection = target . value ? target . value . split ( ',' ) . map ( id => id . trim ( ) ) : [ ] ;
187
120
} ) ;
188
121
189
122
/**
@@ -193,19 +126,34 @@ define([
193
126
if ( data . action === 'ready' ) {
194
127
return ;
195
128
}
196
- const clickedNodeID = data . node . id , currentCheckedNodes = data . instance . get_checked ( ) ;
197
-
198
- if ( data . action === 'select_node' && ! checkedNodes . includes ( clickedNodeID ) ) {
199
- checkedNodes = currentCheckedNodes ;
200
- } else if ( data . action === 'deselect_node' ) {
201
- checkedNodes = currentCheckedNodes . filter ( ( nodeID ) => nodeID !== clickedNodeID ) ;
202
- }
203
- checkedNodes . sort ( ( a , b ) => a - b ) ;
204
129
205
130
/**
206
131
* Update the value of the corresponding form element with the checked node IDs
132
+ *
133
+ * keep the checked nodes that are not in the tree yet,
134
+ * and merge them with the currently checked nodes
135
+ * then sort the resulted array
207
136
*/
208
- options . jsFormObject . updateElement . value = checkedNodes . join ( ', ' ) ;
137
+ let target = getTargetInput ( ) ,
138
+ selected = initialSelection
139
+ . filter ( node => data . instance . get_node ( node ) === false )
140
+ . concat ( data . instance . get_checked ( ) ) ;
141
+
142
+ target . value = [ ...new Set ( selected ) ] . sort ( ( a , b ) => a - b ) . join ( ',' ) ;
143
+ } ) ;
144
+
145
+ /**
146
+ * Initialize the jstree with configuration options
147
+ */
148
+ treeId . jstree ( {
149
+ core : {
150
+ data : load ,
151
+ check_callback : true
152
+ } ,
153
+ plugins : [ 'checkbox' ] ,
154
+ checkbox : {
155
+ three_state : false
156
+ }
209
157
} ) ;
210
158
} ;
211
159
} ) ;
0 commit comments