-
Notifications
You must be signed in to change notification settings - Fork 77
/
Copy pathui-grid.treeBase.js
1815 lines (1622 loc) · 69.6 KB
/
ui-grid.treeBase.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*!
* ui-grid - v4.12.0 - 2023-01-12
* http://ui-grid.info/
* Copyright (c) 2023 UI Grid Team; License: MIT
*/
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 953:
/***/ ((module) => {
module.exports = "<div\n class=\"ui-grid-tree-base-row-header-buttons\"\n tabindex=\"0\"\n ng-class=\"headerButtonClass()\"\n ng-click=\"headerButtonClick($event)\"\n ng-keydown=\"headerButtonKeyDown($event)\">\n</div>\n"
/***/ }),
/***/ 589:
/***/ ((module) => {
module.exports = "<div>\n <div\n class=\"ui-grid-cell-contents\"\n col-index=\"renderIndex\">\n <ui-grid-tree-base-expand-all-buttons\n ng-if=\"grid.options.enableExpandAll\">\n </ui-grid-tree-base-expand-all-buttons>\n </div>\n</div>\n"
/***/ }),
/***/ 825:
/***/ ((module) => {
module.exports = "<div\n class=\"ui-grid-cell-contents\">\n <ui-grid-tree-base-row-header-buttons>\n </ui-grid-tree-base-row-header-buttons>\n</div>\n"
/***/ }),
/***/ 670:
/***/ ((module) => {
module.exports = "<div\n class=\"ui-grid-tree-base-row-header-buttons\"\n ng-class=\"{'ui-grid-tree-base-header': row.treeLevel > -1 }\"\n tabindex=\"0\"\n ng-keydown=\"treeButtonKeyDown(row, $event)\"\n ng-click=\"treeButtonClick(row, $event)\">\n <i\n ng-class=\"treeButtonClass(row)\"\n ng-style=\"{'padding-left': grid.options.treeIndent * row.treeLevel + 'px'}\">\n </i>\n \n</div>\n"
/***/ }),
/***/ 145:
/***/ (() => {
(function () {
'use strict';
/**
* @ngdoc overview
* @name ui.grid.treeBase
* @description
*
* # ui.grid.treeBase
*
* <div class="alert alert-warning" role="alert"><strong>Beta</strong> This feature is ready for testing, but it either hasn't seen a lot of use or has some known bugs.</div>
*
* This module provides base tree handling functions that are shared by other features, notably grouping
* and treeView. It provides a tree view of the data, with nodes in that
* tree and leaves.
*
* Design information:
* -------------------
*
* The raw data that is provided must come with a $$treeLevel on any non-leaf node. Grouping will create
* these on all the group header rows, treeView will expect these to be set in the raw data by the user.
* TreeBase will run a rowsProcessor that:
* - builds `treeBase.tree` out of the provided rows
* - permits a recursive sort of the tree
* - maintains the expand/collapse state of each node
* - provides the expand/collapse all button and the expand/collapse buttons
* - maintains the count of children for each node
*
* Each row is updated with a link to the tree node that represents it. Refer {@link ui.grid.treeBase.grid:treeBase.tree tree documentation}
* for information.
*
* TreeBase adds information to the rows
* - treeLevel: if present and > -1 tells us the level (level 0 is the top level)
* - treeNode: pointer to the node in the grid.treeBase.tree that refers
* to this row, allowing us to manipulate the state
*
* Since the logic is baked into the rowsProcessors, it should get triggered whenever
* row order or filtering or anything like that is changed. We recall the expanded state
* across invocations of the rowsProcessors by the reference to the treeNode on the individual
* rows. We rebuild the tree itself quite frequently, when we do this we use the saved treeNodes to
* get the state, but we overwrite the other data in that treeNode.
*
* By default rows are collapsed, which means all data rows have their visible property
* set to false, and only level 0 group rows are set to visible.
*
* We rely on the rowsProcessors to do the actual expanding and collapsing, so we set the flags we want into
* grid.treeBase.tree, then call refresh. This is because we can't easily change the visible
* row cache without calling the processors, and once we've built the logic into the rowProcessors we may as
* well use it all the time.
*
* Tree base provides sorting (on non-grouped columns).
*
* Sorting works in two passes. The standard sorting is performed for any columns that are important to building
* the tree (for example, any grouped columns). Then after the tree is built, a recursive tree sort is performed
* for the remaining sort columns (including the original sort) - these columns are sorted within each tree level
* (so all the level 1 nodes are sorted, then all the level 2 nodes within each level 1 node etc).
*
* To achieve this we make use of the `ignoreSort` property on the sort configuration. The parent feature (treeView or grouping)
* must provide a rowsProcessor that runs with very low priority (typically in the 60-65 range), and that sets
* the `ignoreSort`on any sort that it wants to run on the tree. TreeBase will clear the ignoreSort on all sorts - so it
* will turn on any sorts that haven't run. It will then call a recursive sort on the tree.
*
* Tree base provides treeAggregation. It checks the treeAggregation configuration on each column, and aggregates based on
* the logic provided as it builds the tree. Footer aggregation from the uiGrid core should not be used with treeBase aggregation,
* since it operates on all visible rows, as opposed to to leaf nodes only. Setting `showColumnFooter: true` will show the
* treeAggregations in the column footer. Aggregation information will be collected in the format:
*
* ```
* {
* type: 'count',
* value: 4,
* label: 'count: ',
* rendered: 'count: 4'
* }
* ```
*
* A callback is provided to format the value once it is finalised (aka a valueFilter).
*
* <br/>
* <br/>
*
* <div doc-module-components="ui.grid.treeBase"></div>
*/
var module = angular.module('ui.grid.treeBase', ['ui.grid']);
/**
* @ngdoc object
* @name ui.grid.treeBase.constant:uiGridTreeBaseConstants
*
* @description constants available in treeBase module.
*
* These constants are manually copied into grouping and treeView,
* as I haven't found a way to simply include them, and it's not worth
* investing time in for something that changes very infrequently.
*
*/
module.constant('uiGridTreeBaseConstants', {
featureName: "treeBase",
rowHeaderColName: 'treeBaseRowHeaderCol',
EXPANDED: 'expanded',
COLLAPSED: 'collapsed',
aggregation: {
COUNT: 'count',
SUM: 'sum',
MAX: 'max',
MIN: 'min',
AVG: 'avg'
}
});
/**
* @ngdoc service
* @name ui.grid.treeBase.service:uiGridTreeBaseService
*
* @description Services for treeBase feature
*/
/**
* @ngdoc object
* @name ui.grid.treeBase.api:ColumnDef
*
* @description ColumnDef for tree feature, these are available to be
* set using the ui-grid {@link ui.grid.class:GridOptions.columnDef gridOptions.columnDefs}
*/
module.service('uiGridTreeBaseService', ['$q', 'uiGridTreeBaseConstants', 'gridUtil', 'GridRow', 'gridClassFactory', 'i18nService', 'uiGridConstants', 'rowSorter',
function ($q, uiGridTreeBaseConstants, gridUtil, GridRow, gridClassFactory, i18nService, uiGridConstants, rowSorter) {
var service = {
initializeGrid: function (grid) {
// add feature namespace and any properties to grid for needed
/**
* @ngdoc object
* @name ui.grid.treeBase.grid:treeBase
*
* @description Grid properties and functions added for treeBase
*/
grid.treeBase = {};
/**
* @ngdoc property
* @propertyOf ui.grid.treeBase.grid:treeBase
* @name numberLevels
*
* @description Total number of tree levels currently used, calculated by the rowsProcessor by
* retaining the highest tree level it sees
*/
grid.treeBase.numberLevels = 0;
/**
* @ngdoc property
* @propertyOf ui.grid.treeBase.grid:treeBase
* @name expandAll
*
* @description Whether or not the expandAll box is selected
*/
grid.treeBase.expandAll = false;
/**
* @ngdoc property
* @propertyOf ui.grid.treeBase.grid:treeBase
* @name tree
*
* @description Tree represented as a nested array that holds the state of each node, along with a
* pointer to the row. The array order is material - we will display the children in the order
* they are stored in the array
*
* Each node stores:
*
* - the state of this node
* - an array of children of this node
* - a pointer to the parent of this node (reverse pointer, allowing us to walk up the tree)
* - the number of children of this node
* - aggregation information calculated from the nodes
*
* ```
* [{
* state: 'expanded',
* row: <reference to row>,
* parentRow: null,
* aggregations: [{
* type: 'count',
* col: <gridCol>,
* value: 2,
* label: 'count: ',
* rendered: 'count: 2'
* }],
* children: [
* {
* state: 'expanded',
* row: <reference to row>,
* parentRow: <reference to row>,
* aggregations: [{
* type: 'count',
* col: '<gridCol>,
* value: 4,
* label: 'count: ',
* rendered: 'count: 4'
* }],
* children: [
* { state: 'expanded', row: <reference to row>, parentRow: <reference to row> },
* { state: 'collapsed', row: <reference to row>, parentRow: <reference to row> },
* { state: 'expanded', row: <reference to row>, parentRow: <reference to row> },
* { state: 'collapsed', row: <reference to row>, parentRow: <reference to row> }
* ]
* },
* {
* state: 'collapsed',
* row: <reference to row>,
* parentRow: <reference to row>,
* aggregations: [{
* type: 'count',
* col: <gridCol>,
* value: 3,
* label: 'count: ',
* rendered: 'count: 3'
* }],
* children: [
* { state: 'expanded', row: <reference to row>, parentRow: <reference to row> },
* { state: 'collapsed', row: <reference to row>, parentRow: <reference to row> },
* { state: 'expanded', row: <reference to row>, parentRow: <reference to row> }
* ]
* }
* ]
* }, {<another level 0 node maybe>} ]
* ```
* Missing state values are false - meaning they aren't expanded.
*
* This is used because the rowProcessors run every time the grid is refreshed, so
* we'd lose the expanded state every time the grid was refreshed. This instead gives
* us a reliable lookup that persists across rowProcessors.
*
* This tree is rebuilt every time we run the rowsProcessors. Since each row holds a pointer
* to it's tree node we can persist expand/collapse state across calls to rowsProcessor, we discard
* all transient information on the tree (children, childCount) and recalculate it
*
*/
grid.treeBase.tree = [];
service.defaultGridOptions(grid.options);
grid.registerRowsProcessor(service.treeRows, 410);
grid.registerColumnBuilder( service.treeBaseColumnBuilder );
service.createRowHeader( grid );
/**
* @ngdoc object
* @name ui.grid.treeBase.api:PublicApi
*
* @description Public Api for treeBase feature
*/
var publicApi = {
events: {
treeBase: {
/**
* @ngdoc event
* @eventOf ui.grid.treeBase.api:PublicApi
* @name rowExpanded
* @description raised whenever a row is expanded. If you are dynamically
* rendering your tree you can listen to this event, and then retrieve
* the children of this row and load them into the grid data.
*
* When the data is loaded the grid will automatically refresh to show these new rows
*
* <pre>
* gridApi.treeBase.on.rowExpanded(scope,function(row) {})
* </pre>
* @param {gridRow} row the row that was expanded. You can also
* retrieve the grid from this row with row.grid
*/
rowExpanded: {},
/**
* @ngdoc event
* @eventOf ui.grid.treeBase.api:PublicApi
* @name rowCollapsed
* @description raised whenever a row is collapsed. Doesn't really have
* a purpose at the moment, included for symmetry
*
* <pre>
* gridApi.treeBase.on.rowCollapsed(scope,function(row) {})
* </pre>
* @param {gridRow} row the row that was collapsed. You can also
* retrieve the grid from this row with row.grid
*/
rowCollapsed: {}
}
},
methods: {
treeBase: {
/**
* @ngdoc function
* @name expandAllRows
* @methodOf ui.grid.treeBase.api:PublicApi
* @description Expands all tree rows
*/
expandAllRows: function () {
service.expandAllRows(grid);
},
/**
* @ngdoc function
* @name collapseAllRows
* @methodOf ui.grid.treeBase.api:PublicApi
* @description collapse all tree rows
*/
collapseAllRows: function () {
service.collapseAllRows(grid);
},
/**
* @ngdoc function
* @name toggleRowTreeState
* @methodOf ui.grid.treeBase.api:PublicApi
* @description call expand if the row is collapsed, collapse if it is expanded
* @param {gridRow} row the row you wish to toggle
*/
toggleRowTreeState: function (row) {
service.toggleRowTreeState(grid, row);
},
/**
* @ngdoc function
* @name expandRow
* @methodOf ui.grid.treeBase.api:PublicApi
* @description expand the immediate children of the specified row
* @param {gridRow} row the row you wish to expand
* @param {boolean} recursive true if you wish to expand the row's ancients
*/
expandRow: function (row, recursive) {
service.expandRow(grid, row, recursive);
},
/**
* @ngdoc function
* @name expandRowChildren
* @methodOf ui.grid.treeBase.api:PublicApi
* @description expand all children of the specified row
* @param {gridRow} row the row you wish to expand
*/
expandRowChildren: function (row) {
service.expandRowChildren(grid, row);
},
/**
* @ngdoc function
* @name collapseRow
* @methodOf ui.grid.treeBase.api:PublicApi
* @description collapse the specified row. When
* you expand the row again, all grandchildren will retain their state
* @param {gridRow} row the row you wish to collapse
*/
collapseRow: function ( row ) {
service.collapseRow(grid, row);
},
/**
* @ngdoc function
* @name collapseRowChildren
* @methodOf ui.grid.treeBase.api:PublicApi
* @description collapse all children of the specified row. When
* you expand the row again, all grandchildren will be collapsed
* @param {gridRow} row the row you wish to collapse children for
*/
collapseRowChildren: function ( row ) {
service.collapseRowChildren(grid, row);
},
/**
* @ngdoc function
* @name getTreeState
* @methodOf ui.grid.treeBase.api:PublicApi
* @description Get the tree state for this grid,
* used by the saveState feature
* Returned treeState as an object
* `{ expandedState: { uid: 'expanded', uid: 'collapsed' } }`
* where expandedState is a hash of row uid and the current expanded state
*
* @returns {object} tree state
*
* TODO - this needs work - we need an identifier that persists across instantiations,
* not uid. This really means we need a row identity defined, but that won't work for
* grouping. Perhaps this needs to be moved up to treeView and grouping, rather than
* being in base.
*/
getTreeExpandedState: function () {
return { expandedState: service.getTreeState(grid) };
},
/**
* @ngdoc function
* @name setTreeState
* @methodOf ui.grid.treeBase.api:PublicApi
* @description Set the expanded states of the tree
* @param {object} config the config you want to apply, in the format
* provided by getTreeState
*/
setTreeState: function ( config ) {
service.setTreeState( grid, config );
},
/**
* @ngdoc function
* @name getRowChildren
* @methodOf ui.grid.treeBase.api:PublicApi
* @description Get the children of the specified row
* @param {GridRow} row the row you want the children of
* @returns {Array} array of children of this row, the children
* are all gridRows
*/
getRowChildren: function ( row ) {
return row.treeNode.children.map( function( childNode ) {
return childNode.row;
});
}
}
}
};
grid.api.registerEventsFromObject(publicApi.events);
grid.api.registerMethodsFromObject(publicApi.methods);
},
defaultGridOptions: function (gridOptions) {
// default option to true unless it was explicitly set to false
/**
* @ngdoc object
* @name ui.grid.treeBase.api:GridOptions
*
* @description GridOptions for treeBase feature, these are available to be
* set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
*/
/**
* @ngdoc object
* @name treeRowHeaderBaseWidth
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description Base width of the tree header, provides for a single level of tree. This
* is incremented by `treeIndent` for each extra level
* <br/>Defaults to 30
*/
gridOptions.treeRowHeaderBaseWidth = gridOptions.treeRowHeaderBaseWidth || 30;
/**
* @ngdoc object
* @name treeIndent
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description Number of pixels of indent for the icon at each tree level, wider indents are visually more pleasing,
* but will make the tree row header wider
* <br/>Defaults to 10
*/
gridOptions.treeIndent = (gridOptions.treeIndent != null) ? gridOptions.treeIndent : 10;
/**
* @ngdoc object
* @name showTreeRowHeader
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description If set to false, don't create the row header. You'll need to programmatically control the expand
* states
* <br/>Defaults to true
*/
gridOptions.showTreeRowHeader = gridOptions.showTreeRowHeader !== false;
/**
* @ngdoc object
* @name showTreeExpandNoChildren
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description If set to true, show the expand/collapse button even if there are no
* children of a node. You'd use this if you're planning to dynamically load the children
*
* <br/>Defaults to true, grouping overrides to false
*/
gridOptions.showTreeExpandNoChildren = gridOptions.showTreeExpandNoChildren !== false;
/**
* @ngdoc object
* @name treeRowHeaderAlwaysVisible
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description If set to true, row header even if there are no tree nodes
*
* <br/>Defaults to true
*/
gridOptions.treeRowHeaderAlwaysVisible = gridOptions.treeRowHeaderAlwaysVisible !== false;
/**
* @ngdoc object
* @name treeCustomAggregations
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description Define custom aggregation functions. The properties of this object will be
* aggregation types available for use on columnDef with {@link ui.grid.treeBase.api:ColumnDef treeAggregationType} or through the column menu.
* If a function defined here uses the same name as one of the native aggregations, this one will take precedence.
* The object format is:
*
* <pre>
* {
* aggregationName: {
* label: (optional) string,
* aggregationFn: function( aggregation, fieldValue, numValue, row ) {...},
* finalizerFn: (optional) function( aggregation ) {...}
* },
* mean: {
* label: 'mean',
* aggregationFn: function( aggregation, fieldValue, numValue ) {
* aggregation.count = (aggregation.count || 1) + 1;
* aggregation.sum = (aggregation.sum || 0) + numValue;
* },
* finalizerFn: function( aggregation ) {
* aggregation.value = aggregation.sum / aggregation.count
* }
* }
* }
* </pre>
*
* <br/>The `finalizerFn` may be used to manipulate the value before rendering, or to
* apply a custom rendered value. If `aggregation.rendered` is left undefined, the value will be
* rendered. Note that the native aggregation functions use an `finalizerFn` to concatenate
* the label and the value.
*
* <br/>Defaults to {}
*/
gridOptions.treeCustomAggregations = gridOptions.treeCustomAggregations || {};
/**
* @ngdoc object
* @name enableExpandAll
* @propertyOf ui.grid.treeBase.api:GridOptions
* @description Enable the expand all button at the top of the row header
*
* <br/>Defaults to true
*/
gridOptions.enableExpandAll = gridOptions.enableExpandAll !== false;
},
/**
* @ngdoc function
* @name treeBaseColumnBuilder
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Sets the tree defaults based on the columnDefs
*
* @param {object} colDef columnDef we're basing on
* @param {GridColumn} col the column we're to update
* @param {object} gridOptions the options we should use
* @returns {promise} promise for the builder - actually we do it all inline so it's immediately resolved
*/
treeBaseColumnBuilder: function (colDef, col, gridOptions) {
/**
* @ngdoc object
* @name customTreeAggregationFn
* @propertyOf ui.grid.treeBase.api:ColumnDef
* @description A custom function that aggregates rows into some form of
* total. Aggregations run row-by-row, the function needs to be capable of
* creating a running total.
*
* The function will be provided the aggregation item (in which you can store running
* totals), the row value that is to be aggregated, and that same row value converted to
* a number (most aggregations work on numbers)
* @example
* <pre>
* customTreeAggregationFn = function ( aggregation, fieldValue, numValue, row ) {
* // calculates the average of the squares of the values
* if ( typeof(aggregation.count) === 'undefined' ) {
* aggregation.count = 0;
* }
* aggregation.count++;
*
* if ( !isNaN(numValue) ) {
* if ( typeof(aggregation.total) === 'undefined' ) {
* aggregation.total = 0;
* }
* aggregation.total = aggregation.total + numValue * numValue;
* }
*
* aggregation.value = aggregation.total / aggregation.count;
* }
* </pre>
* <br/>Defaults to undefined. May be overwritten by treeAggregationType, the two options should not be used together.
*/
if ( typeof(colDef.customTreeAggregationFn) !== 'undefined' ) {
col.treeAggregationFn = colDef.customTreeAggregationFn;
}
/**
* @ngdoc object
* @name treeAggregationType
* @propertyOf ui.grid.treeBase.api:ColumnDef
* @description Use one of the native or grid-level aggregation methods for calculating aggregations on this column.
* Native method are in the constants file and include: SUM, COUNT, MIN, MAX, AVG. This may also be the property the
* name of an aggregation function defined with {@link ui.grid.treeBase.api:GridOptions treeCustomAggregations}.
*
* <pre>
* treeAggregationType = uiGridTreeBaseConstants.aggregation.SUM,
* }
* </pre>
*
* If you are using aggregations you should either:
*
* - also use grouping, in which case the aggregations are displayed in the group header, OR
* - use treeView, in which case you can set `treeAggregationUpdateEntity: true` in the colDef, and
* treeBase will store the aggregation information in the entity, or you can set `treeAggregationUpdateEntity: false`
* in the colDef, and you need to manual retrieve the calculated aggregations from the row.treeNode.aggregations
*
* <br/>Takes precendence over a treeAggregationFn, the two options should not be used together.
* <br/>Defaults to undefined.
*/
if ( typeof(colDef.treeAggregationType) !== 'undefined' ) {
col.treeAggregation = { type: colDef.treeAggregationType };
if ( typeof(gridOptions.treeCustomAggregations[colDef.treeAggregationType]) !== 'undefined' ) {
col.treeAggregationFn = gridOptions.treeCustomAggregations[colDef.treeAggregationType].aggregationFn;
col.treeAggregationFinalizerFn = gridOptions.treeCustomAggregations[colDef.treeAggregationType].finalizerFn;
col.treeAggregation.label = gridOptions.treeCustomAggregations[colDef.treeAggregationType].label;
}
else if ( typeof(service.nativeAggregations()[colDef.treeAggregationType]) !== 'undefined' ) {
col.treeAggregationFn = service.nativeAggregations()[colDef.treeAggregationType].aggregationFn;
col.treeAggregation.label = service.nativeAggregations()[colDef.treeAggregationType].label;
}
}
/**
* @ngdoc object
* @name treeAggregationLabel
* @propertyOf ui.grid.treeBase.api:ColumnDef
* @description A custom label to use for this aggregation. If provided we don't use native i18n.
*/
if ( typeof(colDef.treeAggregationLabel) !== 'undefined' ) {
if (typeof(col.treeAggregation) === 'undefined' ) {
col.treeAggregation = {};
}
col.treeAggregation.label = colDef.treeAggregationLabel;
}
/**
* @ngdoc object
* @name treeAggregationUpdateEntity
* @propertyOf ui.grid.treeBase.api:ColumnDef
* @description Store calculated aggregations into the entity, allowing them
* to be displayed in the grid using a standard cellTemplate. This defaults to true,
* if you are using grouping then you shouldn't set it to false, as then the aggregations won't
* display.
*
* If you are using treeView in most cases you'll want to set this to true. This will result in
* getCellValue returning the aggregation rather than whatever was stored in the cell attribute on
* the entity. If you want to render the underlying entity value (and do something else with the aggregation)
* then you could use a custom cellTemplate to display `row.entity.myAttribute`, rather than using getCellValue.
*
* <br/>Defaults to true
*
* @example
* <pre>
* gridOptions.columns = [{
* name: 'myCol',
* treeAggregation: { type: uiGridTreeBaseConstants.aggregation.SUM },
* treeAggregationUpdateEntity: true
* cellTemplate: '<div>{{row.entity.myCol + " " + row.treeNode.aggregations[0].rendered}}</div>'
* }];
* </pre>
*/
col.treeAggregationUpdateEntity = colDef.treeAggregationUpdateEntity !== false;
/**
* @ngdoc object
* @name customTreeAggregationFinalizerFn
* @propertyOf ui.grid.treeBase.api:ColumnDef
* @description A custom function that populates aggregation.rendered, this is called when
* a particular aggregation has been fully calculated, and we want to render the value.
*
* With the native aggregation options we just concatenate `aggregation.label` and
* `aggregation.value`, but if you wanted to apply a filter or otherwise manipulate the label
* or the value, you can do so with this function. This function will be called after the
* the default `finalizerFn`.
*
* @example
* <pre>
* customTreeAggregationFinalizerFn = function ( aggregation ) {
* aggregation.rendered = aggregation.label + aggregation.value / 100 + '%';
* }
* </pre>
* <br/>Defaults to undefined.
*/
if ( typeof(col.customTreeAggregationFinalizerFn) === 'undefined' ) {
col.customTreeAggregationFinalizerFn = colDef.customTreeAggregationFinalizerFn;
}
},
/**
* @ngdoc function
* @name createRowHeader
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Create the rowHeader. If treeRowHeaderAlwaysVisible then
* set it to visible, otherwise set it to invisible
*
* @param {Grid} grid grid object
*/
createRowHeader: function( grid ) {
var rowHeaderColumnDef = {
name: uiGridTreeBaseConstants.rowHeaderColName,
displayName: '',
width: grid.options.treeRowHeaderBaseWidth,
minWidth: 10,
cellTemplate: 'ui-grid/treeBaseRowHeader',
headerCellTemplate: 'ui-grid/treeBaseHeaderCell',
enableColumnResizing: false,
enableColumnMenu: false,
exporterSuppressExport: true,
allowCellFocus: true
};
rowHeaderColumnDef.visible = grid.options.treeRowHeaderAlwaysVisible;
grid.addRowHeaderColumn(rowHeaderColumnDef, -100);
},
/**
* @ngdoc function
* @name expandAllRows
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Expands all nodes in the tree
*
* @param {Grid} grid grid object
*/
expandAllRows: function (grid) {
grid.treeBase.tree.forEach( function( node ) {
service.setAllNodes( grid, node, uiGridTreeBaseConstants.EXPANDED);
});
grid.treeBase.expandAll = true;
grid.queueGridRefresh();
},
/**
* @ngdoc function
* @name collapseAllRows
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Collapses all nodes in the tree
*
* @param {Grid} grid grid object
*/
collapseAllRows: function (grid) {
grid.treeBase.tree.forEach( function( node ) {
service.setAllNodes( grid, node, uiGridTreeBaseConstants.COLLAPSED);
});
grid.treeBase.expandAll = false;
grid.queueGridRefresh();
},
/**
* @ngdoc function
* @name setAllNodes
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Works through a subset of grid.treeBase.rowExpandedStates, setting
* all child nodes (and their descendents) of the provided node to the given state.
*
* Calls itself recursively on all nodes so as to achieve this.
*
* @param {Grid} grid the grid we're operating on (so we can raise events)
* @param {object} treeNode a node in the tree that we want to update
* @param {string} targetState the state we want to set it to
*/
setAllNodes: function (grid, treeNode, targetState) {
if ( typeof(treeNode.state) !== 'undefined' && treeNode.state !== targetState ) {
treeNode.state = targetState;
if ( targetState === uiGridTreeBaseConstants.EXPANDED ) {
grid.api.treeBase.raise.rowExpanded(treeNode.row);
}
else {
grid.api.treeBase.raise.rowCollapsed(treeNode.row);
}
}
// set all child nodes
if ( treeNode.children ) {
treeNode.children.forEach(function( childNode ) {
service.setAllNodes(grid, childNode, targetState);
});
}
},
/**
* @ngdoc function
* @name toggleRowTreeState
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Toggles the expand or collapse state of this grouped row, if
* it's a parent row
*
* @param {Grid} grid grid object
* @param {GridRow} row the row we want to toggle
*/
toggleRowTreeState: function ( grid, row ) {
if ( typeof(row.treeLevel) === 'undefined' || row.treeLevel === null || row.treeLevel < 0 ) {
return;
}
if (row.treeNode.state === uiGridTreeBaseConstants.EXPANDED) {
service.collapseRow(grid, row);
}
else {
service.expandRow(grid, row, false);
}
grid.queueGridRefresh();
},
/**
* @ngdoc function
* @name expandRow
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Expands this specific row, showing only immediate children.
*
* @param {Grid} grid grid object
* @param {GridRow} row the row we want to expand
* @param {boolean} recursive true if you wish to expand the row's ancients
*/
expandRow: function ( grid, row, recursive ) {
if ( recursive ) {
var parents = [];
while ( row && typeof(row.treeLevel) !== 'undefined' && row.treeLevel !== null && row.treeLevel >= 0 && row.treeNode.state !== uiGridTreeBaseConstants.EXPANDED ) {
parents.push(row);
row = row.treeNode.parentRow;
}
if ( parents.length > 0 ) {
row = parents.pop();
while ( row ) {
row.treeNode.state = uiGridTreeBaseConstants.EXPANDED;
grid.api.treeBase.raise.rowExpanded(row);
row = parents.pop();
}
grid.treeBase.expandAll = service.allExpanded(grid.treeBase.tree);
grid.queueGridRefresh();
}
}
else {
if ( typeof(row.treeLevel) === 'undefined' || row.treeLevel === null || row.treeLevel < 0 ) {
return;
}
if ( row.treeNode.state !== uiGridTreeBaseConstants.EXPANDED ) {
row.treeNode.state = uiGridTreeBaseConstants.EXPANDED;
grid.api.treeBase.raise.rowExpanded(row);
grid.treeBase.expandAll = service.allExpanded(grid.treeBase.tree);
grid.queueGridRefresh();
}
}
},
/**
* @ngdoc function
* @name expandRowChildren
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Expands this specific row, showing all children.
*
* @param {Grid} grid grid object
* @param {GridRow} row the row we want to expand
*/
expandRowChildren: function ( grid, row ) {
if ( typeof(row.treeLevel) === 'undefined' || row.treeLevel === null || row.treeLevel < 0 ) {
return;
}
service.setAllNodes(grid, row.treeNode, uiGridTreeBaseConstants.EXPANDED);
grid.treeBase.expandAll = service.allExpanded(grid.treeBase.tree);
grid.queueGridRefresh();
},
/**
* @ngdoc function
* @name collapseRow
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Collapses this specific row
*
* @param {Grid} grid grid object
* @param {GridRow} row the row we want to collapse
*/
collapseRow: function( grid, row ) {
if ( typeof(row.treeLevel) === 'undefined' || row.treeLevel === null || row.treeLevel < 0 ) {
return;
}
if ( row.treeNode.state !== uiGridTreeBaseConstants.COLLAPSED ) {
row.treeNode.state = uiGridTreeBaseConstants.COLLAPSED;
grid.treeBase.expandAll = false;
grid.api.treeBase.raise.rowCollapsed(row);
grid.queueGridRefresh();
}
},
/**
* @ngdoc function
* @name collapseRowChildren
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Collapses this specific row and all children
*
* @param {Grid} grid grid object
* @param {GridRow} row the row we want to collapse
*/
collapseRowChildren: function( grid, row ) {
if ( typeof(row.treeLevel) === 'undefined' || row.treeLevel === null || row.treeLevel < 0 ) {
return;
}
service.setAllNodes(grid, row.treeNode, uiGridTreeBaseConstants.COLLAPSED);
grid.treeBase.expandAll = false;
grid.queueGridRefresh();
},
/**
* @ngdoc function
* @name allExpanded
* @methodOf ui.grid.treeBase.service:uiGridTreeBaseService
* @description Returns true if all rows are expanded, false
* if they're not. Walks the tree to determine this. Used
* to set the expandAll state.
*
* If the node has no children, then return true (it's immaterial
* whether it is expanded). If the node has children, then return
* false if this node is collapsed, or if any child node is not all expanded
*
* @param {object} tree the grid to check
* @returns {boolean} whether or not the tree is all expanded
*/
allExpanded: function( tree ) {
var allExpanded = true;
tree.forEach(function( node ) {
if ( !service.allExpandedInternal( node ) ) {
allExpanded = false;
}
});
return allExpanded;
},
allExpandedInternal: function( treeNode ) {
if ( treeNode.children && treeNode.children.length > 0 ) {
if ( treeNode.state === uiGridTreeBaseConstants.COLLAPSED ) {
return false;
}
var allExpanded = true;
treeNode.children.forEach( function( node ) {
if ( !service.allExpandedInternal( node ) ) {
allExpanded = false;
}