1 | import {Component} from "../widgets/component";
|
2 | import {Autowired, Context, PostConstruct} from "../context/context";
|
3 | import {GridOptionsWrapper} from "../gridOptionsWrapper";
|
4 | import {ColumnGroupChild} from "../entities/columnGroupChild";
|
5 | import {ColumnGroup} from "../entities/columnGroup";
|
6 | import {ColumnController} from "../columnController/columnController";
|
7 | import {Column} from "../entities/column";
|
8 | import {DropTarget} from "../dragAndDrop/dragAndDropService";
|
9 | import {EventService} from "../eventService";
|
10 | import {Events} from "../events";
|
11 | import {Promise, Utils as _} from "../utils";
|
12 | import {HeaderWrapperComp} from "./header/headerWrapperComp";
|
13 | import {HeaderGroupWrapperComp} from "./headerGroup/headerGroupWrapperComp";
|
14 | import {FilterManager} from "../filter/filterManager";
|
15 | import {IFloatingFilterWrapperComp} from "../filter/floatingFilterWrapper";
|
16 | import {IComponent} from "../interfaces/iComponent";
|
17 | import {FloatingFilterChange, IFloatingFilterParams} from "../filter/floatingFilter";
|
18 | import {ComponentRecipes} from "../components/framework/componentRecipes";
|
19 | import {IFilterComp} from "../interfaces/iFilter";
|
20 | import {GridApi} from "../gridApi";
|
21 | import {CombinedFilter} from "../filter/baseFilter";
|
22 |
|
23 | export enum HeaderRowType {
|
24 | COLUMN_GROUP, COLUMN, FLOATING_FILTER
|
25 | }
|
26 |
|
27 | export class HeaderRowComp extends Component {
|
28 |
|
29 | @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
|
30 | @Autowired('gridApi') private gridApi: GridApi;
|
31 | @Autowired('columnController') private columnController: ColumnController;
|
32 | @Autowired('context') private context: Context;
|
33 | @Autowired('eventService') private eventService: EventService;
|
34 | @Autowired('filterManager') private filterManager: FilterManager;
|
35 | @Autowired('componentRecipes') private componentRecipes: ComponentRecipes;
|
36 |
|
37 | private dept: number;
|
38 | private pinned: string;
|
39 |
|
40 | private headerComps: { [key: string]: IComponent<any> } = {};
|
41 |
|
42 | private dropTarget: DropTarget;
|
43 |
|
44 | private type: HeaderRowType;
|
45 |
|
46 | constructor(dept: number, type: HeaderRowType, pinned: string, dropTarget: DropTarget) {
|
47 | super(`<div class="ag-header-row" role="presentation"/>`);
|
48 | this.dept = dept;
|
49 | this.type = type;
|
50 | this.pinned = pinned;
|
51 | this.dropTarget = dropTarget;
|
52 | }
|
53 |
|
54 | public forEachHeaderElement(callback: (comp: IComponent<any>) => void): void {
|
55 | Object.keys(this.headerComps).forEach(key => {
|
56 | callback(this.headerComps[key]);
|
57 | });
|
58 | }
|
59 |
|
60 | public destroy(): void {
|
61 | let idsOfAllChildren = Object.keys(this.headerComps);
|
62 | this.removeAndDestroyChildComponents(idsOfAllChildren);
|
63 | super.destroy();
|
64 | }
|
65 |
|
66 | private removeAndDestroyChildComponents(idsToDestroy: string[]): void {
|
67 | idsToDestroy.forEach(id => {
|
68 | let childHeaderComp: IComponent<any> = this.headerComps[id];
|
69 | this.getGui().removeChild(childHeaderComp.getGui());
|
70 | if (childHeaderComp.destroy) {
|
71 | childHeaderComp.destroy();
|
72 | }
|
73 | delete this.headerComps[id];
|
74 | });
|
75 | }
|
76 |
|
77 | private onRowHeightChanged(): void {
|
78 | let headerRowCount = this.columnController.getHeaderRowCount();
|
79 | let sizes: number[] = [];
|
80 |
|
81 | let numberOfFloating = 0;
|
82 | let groupHeight: number;
|
83 | let headerHeight: number;
|
84 | if (!this.columnController.isPivotMode()) {
|
85 | if (this.gridOptionsWrapper.isFloatingFilter()) {
|
86 | headerRowCount++;
|
87 | }
|
88 | numberOfFloating = (this.gridOptionsWrapper.isFloatingFilter()) ? 1 : 0;
|
89 | groupHeight = this.gridOptionsWrapper.getGroupHeaderHeight();
|
90 | headerHeight = this.gridOptionsWrapper.getHeaderHeight();
|
91 | } else {
|
92 | numberOfFloating = 0;
|
93 | groupHeight = this.gridOptionsWrapper.getPivotGroupHeaderHeight();
|
94 | headerHeight = this.gridOptionsWrapper.getPivotHeaderHeight();
|
95 | }
|
96 | let numberOfNonGroups = 1 + numberOfFloating;
|
97 | let numberOfGroups = headerRowCount - numberOfNonGroups;
|
98 |
|
99 | for (let i = 0; i < numberOfGroups; i++) { sizes.push(groupHeight); }
|
100 | sizes.push(headerHeight);
|
101 | for (let i = 0; i < numberOfFloating; i++) { sizes.push(this.gridOptionsWrapper.getFloatingFiltersHeight()); }
|
102 |
|
103 | let rowHeight = 0;
|
104 | for (let i = 0; i < this.dept; i++) { rowHeight += sizes[i]; }
|
105 |
|
106 | this.getGui().style.top = rowHeight + 'px';
|
107 | this.getGui().style.height = sizes[this.dept] + 'px';
|
108 | }
|
109 |
|
110 |
|
111 | @PostConstruct
|
112 | private init(): void {
|
113 |
|
114 | this.onRowHeightChanged();
|
115 | this.onVirtualColumnsChanged();
|
116 | this.setWidth();
|
117 |
|
118 | this.addDestroyableEventListener(this.gridOptionsWrapper, GridOptionsWrapper.PROP_HEADER_HEIGHT, this.onRowHeightChanged.bind(this));
|
119 | this.addDestroyableEventListener(this.gridOptionsWrapper, GridOptionsWrapper.PROP_PIVOT_HEADER_HEIGHT, this.onRowHeightChanged.bind(this));
|
120 |
|
121 | this.addDestroyableEventListener(this.gridOptionsWrapper, GridOptionsWrapper.PROP_GROUP_HEADER_HEIGHT, this.onRowHeightChanged.bind(this));
|
122 | this.addDestroyableEventListener(this.gridOptionsWrapper, GridOptionsWrapper.PROP_PIVOT_GROUP_HEADER_HEIGHT, this.onRowHeightChanged.bind(this));
|
123 |
|
124 | this.addDestroyableEventListener(this.gridOptionsWrapper, GridOptionsWrapper.PROP_FLOATING_FILTERS_HEIGHT, this.onRowHeightChanged.bind(this));
|
125 |
|
126 | this.addDestroyableEventListener(this.eventService, Events.EVENT_VIRTUAL_COLUMNS_CHANGED, this.onVirtualColumnsChanged.bind(this));
|
127 | this.addDestroyableEventListener(this.eventService, Events.EVENT_DISPLAYED_COLUMNS_CHANGED, this.onDisplayedColumnsChanged.bind(this));
|
128 | this.addDestroyableEventListener(this.eventService, Events.EVENT_COLUMN_RESIZED, this.onColumnResized.bind(this));
|
129 | this.addDestroyableEventListener(this.eventService, Events.EVENT_GRID_COLUMNS_CHANGED, this.onGridColumnsChanged.bind(this));
|
130 | }
|
131 |
|
132 | private onColumnResized(): void {
|
133 | this.setWidth();
|
134 | }
|
135 |
|
136 | private setWidth(): void {
|
137 | let mainRowWidth = this.columnController.getContainerWidth(this.pinned) + 'px';
|
138 | this.getGui().style.width = mainRowWidth;
|
139 | }
|
140 |
|
141 | private onGridColumnsChanged(): void {
|
142 | this.removeAndDestroyAllChildComponents();
|
143 | }
|
144 |
|
145 | private removeAndDestroyAllChildComponents(): void {
|
146 | let idsOfAllChildren = Object.keys(this.headerComps);
|
147 | this.removeAndDestroyChildComponents(idsOfAllChildren);
|
148 | }
|
149 |
|
150 | private onDisplayedColumnsChanged(): void {
|
151 | this.onVirtualColumnsChanged();
|
152 | this.setWidth();
|
153 | }
|
154 |
|
155 | private onVirtualColumnsChanged(): void {
|
156 |
|
157 | let currentChildIds = Object.keys(this.headerComps);
|
158 |
|
159 | let itemsAtDepth = this.columnController.getVirtualHeaderGroupRow(
|
160 | this.pinned,
|
161 | this.type == HeaderRowType.FLOATING_FILTER ?
|
162 | this.dept - 1 :
|
163 | this.dept
|
164 | );
|
165 |
|
166 | let ensureDomOrder = this.gridOptionsWrapper.isEnsureDomOrder();
|
167 | let eBefore: HTMLElement;
|
168 |
|
169 | itemsAtDepth.forEach((child: ColumnGroupChild) => {
|
170 |
|
171 |
|
172 |
|
173 |
|
174 | if (child.isEmptyGroup()) {
|
175 | return;
|
176 | }
|
177 |
|
178 | let idOfChild = child.getUniqueId();
|
179 | let eParentContainer = this.getGui();
|
180 |
|
181 |
|
182 | let colAlreadyInDom = currentChildIds.indexOf(idOfChild) >= 0;
|
183 | let headerComp: IComponent<any>;
|
184 | let eHeaderCompGui: HTMLElement;
|
185 | if (colAlreadyInDom) {
|
186 | _.removeFromArray(currentChildIds, idOfChild);
|
187 | headerComp = this.headerComps[idOfChild];
|
188 | eHeaderCompGui = headerComp.getGui();
|
189 | if (ensureDomOrder) {
|
190 | _.ensureDomOrder(eParentContainer, eHeaderCompGui, eBefore);
|
191 | }
|
192 | eBefore = eHeaderCompGui;
|
193 | } else {
|
194 | headerComp = this.createHeaderComp(child);
|
195 | this.headerComps[idOfChild] = headerComp;
|
196 | eHeaderCompGui = headerComp.getGui();
|
197 | if (ensureDomOrder) {
|
198 | _.insertWithDomOrder(eParentContainer, eHeaderCompGui, eBefore);
|
199 | } else {
|
200 | eParentContainer.appendChild(eHeaderCompGui);
|
201 | }
|
202 | eBefore = eHeaderCompGui;
|
203 | }
|
204 | });
|
205 |
|
206 |
|
207 | this.removeAndDestroyChildComponents(currentChildIds);
|
208 | }
|
209 |
|
210 | private createHeaderComp(columnGroupChild: ColumnGroupChild): IComponent<any> {
|
211 | let result: IComponent<any>;
|
212 |
|
213 | switch (this.type) {
|
214 | case HeaderRowType.COLUMN :
|
215 | result = new HeaderWrapperComp(<Column> columnGroupChild, this.dropTarget, this.pinned);
|
216 | break;
|
217 | case HeaderRowType.COLUMN_GROUP :
|
218 | result = new HeaderGroupWrapperComp(<ColumnGroup> columnGroupChild, this.dropTarget, this.pinned);
|
219 | break;
|
220 | case HeaderRowType.FLOATING_FILTER :
|
221 | let column = <Column> columnGroupChild;
|
222 | result = this.createFloatingFilterWrapper(column);
|
223 | break;
|
224 | }
|
225 |
|
226 | this.context.wireBean(result);
|
227 |
|
228 | return result;
|
229 | }
|
230 |
|
231 | private createFloatingFilterWrapper(column: Column): IFloatingFilterWrapperComp<any, any, any, any> {
|
232 | let floatingFilterParams: IFloatingFilterParams<any, any> = this.createFloatingFilterParams(column);
|
233 |
|
234 | let floatingFilterWrapper: IFloatingFilterWrapperComp<any, any, any, any> = this.componentRecipes.newFloatingFilterWrapperComponent(
|
235 | column,
|
236 | <null>floatingFilterParams
|
237 | );
|
238 |
|
239 | this.addDestroyableEventListener(column, Column.EVENT_FILTER_CHANGED, () => {
|
240 | let filterComponentPromise: Promise<IFilterComp> = this.filterManager.getFilterComponent(column);
|
241 | floatingFilterWrapper.onParentModelChanged(filterComponentPromise.resolveNow(null, filter => filter.getModel()));
|
242 | });
|
243 | let cachedFilter = <any>this.filterManager.cachedFilter(column);
|
244 | if (cachedFilter) {
|
245 | let filterComponentPromise: Promise<IFilterComp> = this.filterManager.getFilterComponent(column);
|
246 | floatingFilterWrapper.onParentModelChanged(filterComponentPromise.resolveNow(null, filter => filter.getModel()));
|
247 | }
|
248 |
|
249 | return floatingFilterWrapper;
|
250 | }
|
251 |
|
252 | private createFloatingFilterParams<M, F extends FloatingFilterChange>(column: Column): IFloatingFilterParams<M, F> {
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | let baseParams: IFloatingFilterParams<M, F> = {
|
259 | api: this.gridApi,
|
260 | column: column,
|
261 | currentParentModel: (): M => {
|
262 | let filterComponentPromise: Promise<IFilterComp> = <any>this.filterManager.getFilterComponent(column);
|
263 | let wholeParentFilter: CombinedFilter<M> | M= filterComponentPromise.resolveNow(null, (filter: any) =>
|
264 | (filter.getNullableModel) ?
|
265 | filter.getNullableModel() :
|
266 | filter.getModel()
|
267 | );
|
268 | return (<CombinedFilter<M>>wholeParentFilter).operator != null ? (<CombinedFilter<M>>wholeParentFilter).condition1 : <M>wholeParentFilter;
|
269 | },
|
270 | onFloatingFilterChanged: (change: F | M): boolean => {
|
271 | let captureModelChangedResolveFunc: (modelChanged: boolean) => void;
|
272 | let modelChanged: Promise<boolean> = new Promise((resolve) => {
|
273 | captureModelChangedResolveFunc = resolve;
|
274 | });
|
275 | let filterComponentPromise: Promise<IFilterComp> = <any>this.filterManager.getFilterComponent(column);
|
276 | filterComponentPromise.then(filterComponent => {
|
277 | if (filterComponent.onFloatingFilterChanged) {
|
278 |
|
279 |
|
280 |
|
281 | let result: boolean = filterComponent.onFloatingFilterChanged(<F>change);
|
282 | captureModelChangedResolveFunc(result);
|
283 | } else {
|
284 |
|
285 |
|
286 |
|
287 |
|
288 | filterComponent.setModel(<M>change);
|
289 | this.filterManager.onFilterChanged();
|
290 | captureModelChangedResolveFunc(true);
|
291 | }
|
292 | });
|
293 | return modelChanged.resolveNow(true, modelChanged => modelChanged);
|
294 | },
|
295 |
|
296 | suppressFilterButton: false
|
297 | };
|
298 | return baseParams;
|
299 | }
|
300 |
|
301 | } |
\ | No newline at end of file |