@@ -2,17 +2,30 @@ const Features = (() => {
2
2
let features = { } ;
3
3
let defines_dictionary = { } ;
4
4
let labels_dictionary = { } ;
5
+ let category_dictionary = { } ;
5
6
6
7
function resetDictionaries ( ) {
7
- defines_dictionary = { } ; // clear old dictionary
8
- labels_dictionary = { } ; // clear old dictionary
8
+ // clear old dictionaries
9
+ defines_dictionary = { } ;
10
+ labels_dictionary = { } ;
11
+ category_dictionary = { } ;
12
+
9
13
features . forEach ( ( category ) => {
14
+ category_dictionary [ category . name ] = category ;
10
15
category [ 'options' ] . forEach ( ( option ) => {
11
16
defines_dictionary [ option . define ] = labels_dictionary [ option . label ] = option ;
12
17
} ) ;
13
18
} ) ;
14
19
}
15
20
21
+ function store_category_in_options ( ) {
22
+ features . forEach ( ( category ) => {
23
+ category [ 'options' ] . forEach ( ( option ) => {
24
+ option . category_name = category . name ;
25
+ } ) ;
26
+ } ) ;
27
+ }
28
+
16
29
function updateRequiredFor ( ) {
17
30
features . forEach ( ( category ) => {
18
31
category [ 'options' ] . forEach ( ( option ) => {
@@ -33,6 +46,7 @@ const Features = (() => {
33
46
features = new_features ;
34
47
resetDictionaries ( ) ;
35
48
updateRequiredFor ( ) ;
49
+ store_category_in_options ( ) ;
36
50
}
37
51
38
52
function getOptionByDefine ( define ) {
@@ -43,6 +57,14 @@ const Features = (() => {
43
57
return labels_dictionary [ label ] ;
44
58
}
45
59
60
+ function getCategoryByName ( category_name ) {
61
+ return category_dictionary [ category_name ] ;
62
+ }
63
+
64
+ function getCategoryIdByName ( category_name ) {
65
+ return 'category_' + category_name . split ( " " ) . join ( "_" ) ;
66
+ }
67
+
46
68
function updateDefaults ( defines_array ) {
47
69
// updates default on the basis of define array passed
48
70
// the define array consists define in format, EXAMPLE_DEFINE or !EXAMPLE_DEFINE
@@ -56,13 +78,7 @@ const Features = (() => {
56
78
}
57
79
}
58
80
59
- function fixDepencencyHelper ( feature_label , visited ) {
60
- if ( visited [ feature_label ] != undefined ) {
61
- return ;
62
- }
63
-
64
- visited [ feature_label ] = true ;
65
- document . getElementById ( feature_label ) . checked = true ;
81
+ function enableDependenciesForFeature ( feature_label ) {
66
82
let feature = getOptionByLabel ( feature_label ) ;
67
83
68
84
if ( feature . dependency == null ) {
@@ -71,34 +87,93 @@ const Features = (() => {
71
87
72
88
let children = feature . dependency . split ( ',' ) ;
73
89
children . forEach ( ( child ) => {
74
- fixDepencencyHelper ( child , visited ) ;
90
+ const check = true ;
91
+ checkUncheckOptionByLabel ( child , check ) ;
75
92
} ) ;
76
93
}
77
94
78
- function fixAllDependencies ( ) {
79
- var visited = { } ;
80
- Object . keys ( labels_dictionary ) . forEach ( ( label ) => {
81
- if ( document . getElementById ( label ) . checked ) {
82
- fixDepencencyHelper ( label , visited ) ;
95
+ function handleOptionStateChange ( feature_label , triggered_by_ui ) {
96
+ if ( document . getElementById ( feature_label ) . checked ) {
97
+ enableDependenciesForFeature ( feature_label ) ;
98
+ } else {
99
+ if ( triggered_by_ui ) {
100
+ askToDisableDependentsForFeature ( feature_label ) ;
101
+ } else {
102
+ disabledDependentsForFeature ( feature_label ) ;
83
103
}
104
+ }
105
+
106
+ updateCategoryCheckboxState ( getOptionByLabel ( feature_label ) . category_name ) ;
107
+ }
108
+
109
+ function askToDisableDependentsForFeature ( feature_label ) {
110
+ let enabled_dependent_features = getEnabledDependentFeaturesFor ( feature_label ) ;
111
+
112
+ if ( enabled_dependent_features . length <= 0 ) {
113
+ return ;
114
+ }
115
+
116
+ document . getElementById ( 'modalBody' ) . innerHTML = "The feature(s) <strong>" + enabled_dependent_features . join ( ", " ) + "</strong> is/are dependant on <strong>" + feature_label + "</strong>" +
117
+ " and hence will be disabled too.<br><strong>Do you want to continue?</strong>" ;
118
+ document . getElementById ( 'modalDisableButton' ) . onclick = ( ) => { disabledDependentsForFeature ( feature_label ) ; } ;
119
+ document . getElementById ( 'modalCancelButton' ) . onclick = document . getElementById ( 'modalCloseButton' ) . onclick = ( ) => {
120
+ const check = true ;
121
+ checkUncheckOptionByLabel ( feature_label , check ) ;
122
+ } ;
123
+ var confirmationModal = bootstrap . Modal . getOrCreateInstance ( document . getElementById ( 'dependencyCheckModal' ) ) ;
124
+ confirmationModal . show ( ) ;
125
+ }
126
+
127
+ function disabledDependentsForFeature ( feature_label ) {
128
+ let feature = getOptionByLabel ( feature_label ) ;
129
+
130
+ if ( feature . requiredFor == undefined ) {
131
+ return ;
132
+ }
133
+
134
+ let dependents = feature . requiredFor ;
135
+ dependents . forEach ( ( dependent ) => {
136
+ const check = false ;
137
+ checkUncheckOptionByLabel ( dependent , false ) ;
84
138
} ) ;
85
139
}
86
140
87
- function handleDependenciesForFeature ( feature_label ) {
88
- var visited = { } ;
89
- if ( document . getElementById ( feature_label ) . checked ) {
90
- fixDepencencyHelper ( feature_label , visited ) ;
91
- } else {
92
- enabled_dependent_features = getEnabledDependentFeaturesFor ( feature_label ) ;
93
- if ( enabled_dependent_features . length > 0 ) {
94
- document . getElementById ( 'modalBody' ) . innerHTML = "The feature(s) <strong>" + enabled_dependent_features . join ( ", " ) + "</strong> is/are dependant on <strong>" + feature_label + "</strong>" +
95
- " and hence will be disabled too.<br><strong>Do you want to continue?</strong>" ;
96
- document . getElementById ( 'modalDisableButton' ) . onclick = ( ) => { disableCheckboxesByIds ( enabled_dependent_features ) ; }
97
- document . getElementById ( 'modalCancelButton' ) . onclick = document . getElementById ( 'modalCloseButton' ) . onclick = ( ) => { document . getElementById ( feature_label ) . checked = true ; } ;
98
- var confirmationModal = bootstrap . Modal . getOrCreateInstance ( document . getElementById ( 'dependencyCheckModal' ) ) ;
99
- confirmationModal . show ( ) ;
141
+ function updateCategoryCheckboxState ( category_name ) {
142
+ let category = getCategoryByName ( category_name ) ;
143
+
144
+ if ( category == undefined ) {
145
+ console . log ( "Could not find category by given name" ) ;
146
+ }
147
+
148
+ let checked_options_count = 0 ;
149
+
150
+ category . options . forEach ( ( option ) => {
151
+ let element = document . getElementById ( option . label ) ;
152
+
153
+ if ( element && element . checked ) {
154
+ checked_options_count += 1 ;
100
155
}
156
+ } ) ;
157
+
158
+ let category_checkbox_element = document . getElementById ( getCategoryIdByName ( category_name ) ) ;
159
+ if ( category_checkbox_element == undefined ) {
160
+ console . log ( "Could not find element for given category" ) ;
161
+ }
162
+
163
+ let indeterminate_state = false ;
164
+ switch ( checked_options_count ) {
165
+ case 0 :
166
+ category_checkbox_element . checked = false ;
167
+ break ;
168
+ case category . options . length :
169
+ category_checkbox_element . checked = true ;
170
+ break ;
171
+ default :
172
+ indeterminate_state = true ;
173
+ break ;
101
174
}
175
+
176
+ category_checkbox_element . indeterminate = indeterminate_state ;
102
177
}
103
178
104
179
function getEnabledDependentFeaturesHelper ( feature_label , visited , dependent_features ) {
@@ -132,40 +207,38 @@ const Features = (() => {
132
207
return dependent_features ;
133
208
}
134
209
135
- function disableDependents ( feature_label ) {
136
- if ( getOptionByLabel ( feature_label ) . requiredFor == undefined ) {
137
- return ;
138
- }
139
-
140
- getOptionByLabel ( feature_label ) . requiredFor . forEach ( ( dependent_feature ) => {
141
- document . getElementById ( dependent_feature ) . checked = false ;
142
- } ) ;
143
- }
144
-
145
210
function applyDefaults ( ) {
146
211
features . forEach ( category => {
147
212
category [ 'options' ] . forEach ( option => {
148
- element = document . getElementById ( option [ 'label' ] ) ;
149
- if ( element != undefined ) {
150
- element . checked = ( option [ 'default' ] == 1 ) ;
151
- }
213
+ const check = option [ 'default' ] == 1 ;
214
+ checkUncheckOptionByLabel ( option . label , check ) ;
152
215
} ) ;
153
216
} ) ;
154
- fixAllDependencies ( ) ;
217
+ }
218
+
219
+ function checkUncheckOptionByLabel ( label , check ) {
220
+ let element = document . getElementById ( label ) ;
221
+ if ( element == undefined || element . checked == check ) {
222
+ return ;
223
+ }
224
+ element . checked = check ;
225
+ const triggered_by_ui = false ;
226
+ handleOptionStateChange ( label , triggered_by_ui ) ;
155
227
}
156
228
157
229
function checkUncheckAll ( check ) {
158
230
features . forEach ( category => {
159
- category [ 'options' ] . forEach ( option => {
160
- element = document . getElementById ( option [ 'label' ] ) ;
161
- if ( element != undefined ) {
162
- element . checked = check ;
163
- }
164
- } ) ;
231
+ checkUncheckCategory ( category . name , check ) ;
165
232
} ) ;
166
233
}
167
234
168
- return { reset, handleDependenciesForFeature, disableDependents, updateDefaults, applyDefaults, checkUncheckAll} ;
235
+ function checkUncheckCategory ( category_name , check ) {
236
+ getCategoryByName ( category_name ) . options . forEach ( option => {
237
+ checkUncheckOptionByLabel ( option . label , check ) ;
238
+ } ) ;
239
+ }
240
+
241
+ return { reset, handleOptionStateChange, getCategoryIdByName, updateDefaults, applyDefaults, checkUncheckAll, checkUncheckCategory} ;
169
242
} ) ( ) ;
170
243
171
244
var init_categories_expanded = false ;
@@ -200,15 +273,6 @@ function setSpinnerToDiv(id, message) {
200
273
}
201
274
}
202
275
203
- function disableCheckboxesByIds ( ids ) {
204
- ids . forEach ( ( id ) => {
205
- box_element = document . getElementById ( id ) ;
206
- if ( box_element ) {
207
- box_element . checked = false ;
208
- }
209
- } )
210
- }
211
-
212
276
function onVehicleChange ( new_vehicle ) {
213
277
// following elemets will be blocked (disabled) when we make the request
214
278
let elements_to_block = [ 'vehicle' , 'branch' , 'board' , 'submit' , 'reset_def' , 'exp_col_button' ] ;
@@ -359,20 +423,25 @@ function createCategoryCard(category_name, options, expanded) {
359
423
options_html = "" ;
360
424
options . forEach ( option => {
361
425
options_html += '<div class="form-check">' +
362
- '<input class="form-check-input" type="checkbox" value="1" name="' + option [ 'label' ] + '" id="' + option [ 'label' ] + '" onclick="Features.handleDependenciesForFeature (this.id);">' +
363
- '<label class="form-check-label" for="' + option [ 'label' ] + '">' +
426
+ '<input class="form-check-input" type="checkbox" value="1" name="' + option [ 'label' ] + '" id="' + option [ 'label' ] + '" onclick="Features.handleOptionStateChange (this.id, true );">' +
427
+ '<label class="form-check-label ms-2 " for="' + option [ 'label' ] + '">' +
364
428
option [ 'description' ] . replace ( / e n a b l e / i, "" ) +
365
429
'</label>' +
366
430
'</div>' ;
367
431
} ) ;
368
432
369
- let id_prefix = category_name . split ( " " ) . join ( "_" ) ;
433
+ let id_prefix = Features . getCategoryIdByName ( category_name ) ;
370
434
let card_element = document . createElement ( 'div' ) ;
371
435
card_element . setAttribute ( 'class' , 'card ' + ( expanded == true ? 'h-100' : '' ) ) ;
372
436
card_element . id = id_prefix + '_card' ;
373
- card_element . innerHTML = '<div class="card-header">' +
437
+ card_element . innerHTML = '<div class="card-header ps-3 ">' +
374
438
'<div class="d-flex justify-content-between">' +
375
- '<span class="d-flex align-items-center"><strong>' + category_name + '</strong></span>' +
439
+ '<div class="d-inline-flex">' +
440
+ '<span class="align-middle me-3"><input class="form-check-input" type="checkbox" id="' + Features . getCategoryIdByName ( category_name ) + '" onclick="Features.checkUncheckCategory(\'' + category_name + '\', this.checked);"></span>' +
441
+ '<strong>' +
442
+ '<label for="check-uncheck-category">' + category_name + '</label>' +
443
+ '</strong>' +
444
+ '</div>' +
376
445
'<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#' + id_prefix + '_collapse" aria-expanded="false" aria-controls="' + id_prefix + '_collapse">' +
377
446
'<i class="bi bi-chevron-' + ( expanded == true ? 'up' : 'down' ) + '" id="' + id_prefix + '_icon' + '"></i>' +
378
447
'</button>' +
@@ -381,7 +450,7 @@ function createCategoryCard(category_name, options, expanded) {
381
450
let collapse_element = document . createElement ( 'div' ) ;
382
451
collapse_element . setAttribute ( 'class' , 'feature-group collapse ' + ( expanded == true ? 'show' : '' ) ) ;
383
452
collapse_element . id = id_prefix + '_collapse' ;
384
- collapse_element . innerHTML = '<div class="container-fluid px-2 py-2">' + options_html + '</div>' ;
453
+ collapse_element . innerHTML = '<div class="container-fluid px-3 py-2">' + options_html + '</div>' ;
385
454
card_element . appendChild ( collapse_element ) ;
386
455
387
456
// add relevent event listeners
@@ -393,6 +462,7 @@ function createCategoryCard(category_name, options, expanded) {
393
462
card_element . classList . add ( 'h-100' ) ;
394
463
document . getElementById ( id_prefix + '_icon' ) . setAttribute ( 'class' , 'bi bi-chevron-up' ) ;
395
464
} ) ;
465
+
396
466
return card_element ;
397
467
}
398
468
0 commit comments