1 | import {Component} from "../../widgets/component";
|
2 | import {Column} from "../../entities/column";
|
3 | import {Utils as _} from "../../utils";
|
4 | import {Autowired} from "../../context/context";
|
5 | import {IMenuFactory} from "../../interfaces/iMenuFactory";
|
6 | import {GridOptionsWrapper} from "../../gridOptionsWrapper";
|
7 | import {SortController} from "../../sortController";
|
8 | import {LongTapEvent, TouchListener} from "../../widgets/touchListener";
|
9 | import {IComponent} from "../../interfaces/iComponent";
|
10 | import {EventService} from "../../eventService";
|
11 | import {RefSelector} from "../../widgets/componentAnnotations";
|
12 | import {Events} from "../../events";
|
13 | import {ColumnApi} from "../../columnController/columnApi";
|
14 | import {GridApi} from "../../gridApi";
|
15 |
|
16 | export interface IHeaderParams {
|
17 | column: Column;
|
18 | displayName: string;
|
19 | enableSorting: boolean;
|
20 | enableMenu: boolean;
|
21 | showColumnMenu: (source:HTMLElement)=>void;
|
22 | progressSort: (multiSort?: boolean)=>void;
|
23 | setSort: (sort: string, multiSort?: boolean)=>void;
|
24 | columnApi: ColumnApi,
|
25 | api: GridApi,
|
26 | context: any,
|
27 | template: string
|
28 | }
|
29 |
|
30 | export interface IHeader {
|
31 |
|
32 | }
|
33 |
|
34 | export interface IHeaderComp extends IHeader, IComponent<IHeaderParams> {
|
35 |
|
36 | }
|
37 |
|
38 | export class HeaderComp extends Component implements IHeaderComp {
|
39 |
|
40 | private static TEMPLATE =
|
41 | '<div class="ag-cell-label-container" role="presentation">' +
|
42 | ' <span ref="eMenu" class="ag-header-icon ag-header-cell-menu-button" aria-hidden="true"></span>' +
|
43 | ' <div ref="eLabel" class="ag-header-cell-label" role="presentation">' +
|
44 | ' <span ref="eText" class="ag-header-cell-text" role="columnheader"></span>' +
|
45 | ' <span ref="eFilter" class="ag-header-icon ag-filter-icon" aria-hidden="true"></span>' +
|
46 | ' <span ref="eSortOrder" class="ag-header-icon ag-sort-order" aria-hidden="true"></span>' +
|
47 | ' <span ref="eSortAsc" class="ag-header-icon ag-sort-ascending-icon" aria-hidden="true"></span>' +
|
48 | ' <span ref="eSortDesc" class="ag-header-icon ag-sort-descending-icon" aria-hidden="true"></span>' +
|
49 | ' <span ref="eSortNone" class="ag-header-icon ag-sort-none-icon" aria-hidden="true"></span>' +
|
50 | ' </div>' +
|
51 | '</div>';
|
52 |
|
53 | @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
|
54 | @Autowired('sortController') private sortController: SortController;
|
55 | @Autowired('menuFactory') private menuFactory: IMenuFactory;
|
56 | @Autowired('eventService') private eventService: EventService;
|
57 |
|
58 | @RefSelector('eFilter') private eFilter: HTMLElement;
|
59 | @RefSelector('eSortAsc') private eSortAsc: HTMLElement;
|
60 |
|
61 | @RefSelector('eSortDesc') private eSortDesc: HTMLElement;
|
62 | @RefSelector('eSortNone') private eSortNone: HTMLElement;
|
63 | @RefSelector('eSortOrder') private eSortOrder: HTMLElement;
|
64 | @RefSelector('eMenu') private eMenu: HTMLElement;
|
65 | @RefSelector('eLabel') private eLabel: HTMLElement;
|
66 | @RefSelector('eText') private eText: HTMLElement;
|
67 |
|
68 | private params:IHeaderParams;
|
69 |
|
70 | private lastMovingChanged = 0;
|
71 |
|
72 | public init(params: IHeaderParams): void {
|
73 | let template:string = _.firstExistingValue(
|
74 | params.template,
|
75 | HeaderComp.TEMPLATE
|
76 | );
|
77 |
|
78 | this.setTemplate(template);
|
79 | this.params = params;
|
80 |
|
81 | this.setupTap();
|
82 | this.setupIcons(params.column);
|
83 | this.setupMenu();
|
84 | this.setupSort();
|
85 | this.setupFilterIcon();
|
86 | this.setupText(params.displayName);
|
87 | }
|
88 |
|
89 | private setupText(displayName: string): void {
|
90 | if (this.eText) {
|
91 | this.eText.innerHTML = displayName;
|
92 | }
|
93 | }
|
94 |
|
95 | private setupIcons(column:Column): void {
|
96 | this.addInIcon('sortAscending', this.eSortAsc, column);
|
97 | this.addInIcon('sortDescending', this.eSortDesc, column);
|
98 | this.addInIcon('sortUnSort', this.eSortNone, column);
|
99 | this.addInIcon('menu', this.eMenu, column);
|
100 | this.addInIcon('filter', this.eFilter, column);
|
101 | }
|
102 |
|
103 | private addInIcon(iconName: string, eParent: HTMLElement, column: Column): void {
|
104 | if (eParent == null) return;
|
105 |
|
106 | let eIcon = _.createIconNoSpan(iconName, this.gridOptionsWrapper, column);
|
107 | eParent.appendChild(eIcon);
|
108 | }
|
109 |
|
110 | private setupTap(): void {
|
111 | if (this.gridOptionsWrapper.isSuppressTouch()) { return; }
|
112 |
|
113 | let touchListener = new TouchListener(this.getGui());
|
114 |
|
115 | if (this.params.enableMenu) {
|
116 | let longTapListener = (event: LongTapEvent)=> {
|
117 | this.gridOptionsWrapper.getApi().showColumnMenuAfterMouseClick(this.params.column, event.touchStart);
|
118 | };
|
119 | this.addDestroyableEventListener(touchListener, TouchListener.EVENT_LONG_TAP, longTapListener);
|
120 | }
|
121 |
|
122 | if (this.params.enableSorting) {
|
123 | let tapListener = ()=> {
|
124 | this.sortController.progressSort(this.params.column, false, "uiColumnSorted");
|
125 | };
|
126 |
|
127 | this.addDestroyableEventListener(touchListener, TouchListener.EVENT_TAP, tapListener);
|
128 | }
|
129 |
|
130 | this.addDestroyFunc( ()=> touchListener.destroy() );
|
131 | }
|
132 |
|
133 | private setupMenu(): void {
|
134 |
|
135 |
|
136 | if (!this.eMenu) {
|
137 | return;
|
138 | }
|
139 |
|
140 |
|
141 |
|
142 | let dontShowMenu = !this.params.enableMenu || _.isUserAgentIPad();
|
143 |
|
144 | if (dontShowMenu) {
|
145 | _.removeFromParent(this.eMenu);
|
146 | return;
|
147 | }
|
148 |
|
149 | this.eMenu.addEventListener('click', ()=> this.showMenu(this.eMenu));
|
150 |
|
151 | if (!this.gridOptionsWrapper.isSuppressMenuHide()) {
|
152 | this.eMenu.style.opacity = '0';
|
153 | this.addGuiEventListener('mouseover', ()=> {
|
154 | this.eMenu.style.opacity = '1';
|
155 | });
|
156 | this.addGuiEventListener('mouseout', ()=> {
|
157 | this.eMenu.style.opacity = '0';
|
158 | });
|
159 | }
|
160 | let style = <any> this.eMenu.style;
|
161 | style['transition'] = 'opacity 0.2s, border 0.2s';
|
162 | style['-webkit-transition'] = 'opacity 0.2s, border 0.2s';
|
163 | }
|
164 |
|
165 | public showMenu(eventSource: HTMLElement) {
|
166 | this.menuFactory.showMenuAfterButtonClick(this.params.column, eventSource);
|
167 | }
|
168 |
|
169 | private removeSortIcons(): void {
|
170 | _.removeFromParent(this.eSortAsc);
|
171 | _.removeFromParent(this.eSortDesc);
|
172 | _.removeFromParent(this.eSortNone);
|
173 | _.removeFromParent(this.eSortOrder);
|
174 | }
|
175 |
|
176 | public setupSort(): void {
|
177 | let enableSorting = this.params.enableSorting;
|
178 |
|
179 | if (!enableSorting) {
|
180 | this.removeSortIcons();
|
181 | return;
|
182 | }
|
183 |
|
184 | let sortUsingCtrl = this.gridOptionsWrapper.isMultiSortKeyCtrl();
|
185 |
|
186 |
|
187 | this.addDestroyableEventListener(this.params.column, Column.EVENT_MOVING_CHANGED, ()=> {
|
188 | this.lastMovingChanged = new Date().getTime();
|
189 | });
|
190 |
|
191 |
|
192 | if (this.eLabel) {
|
193 | this.addDestroyableEventListener(this.eLabel, 'click', (event:MouseEvent) => {
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | let moving = this.params.column.isMoving();
|
199 | let nowTime = new Date().getTime();
|
200 |
|
201 | let movedRecently = (nowTime - this.lastMovingChanged) < 50;
|
202 | let columnMoving = moving || movedRecently;
|
203 |
|
204 | if (!columnMoving) {
|
205 | let multiSort = sortUsingCtrl ? (event.ctrlKey || event.metaKey) : event.shiftKey;
|
206 | this.params.progressSort(multiSort);
|
207 | } else {
|
208 | console.log(`kipping sort cos of moving ${this.lastMovingChanged}`);
|
209 | }
|
210 | });
|
211 | }
|
212 |
|
213 | this.addDestroyableEventListener(this.params.column, Column.EVENT_SORT_CHANGED, this.onSortChanged.bind(this));
|
214 | this.onSortChanged();
|
215 |
|
216 | this.addDestroyableEventListener(this.eventService, Events.EVENT_SORT_CHANGED, this.setMultiSortOrder.bind(this));
|
217 | this.setMultiSortOrder();
|
218 | }
|
219 |
|
220 | private onSortChanged(): void {
|
221 |
|
222 | _.addOrRemoveCssClass(this.getGui(), 'ag-header-cell-sorted-asc', this.params.column.isSortAscending());
|
223 | _.addOrRemoveCssClass(this.getGui(), 'ag-header-cell-sorted-desc', this.params.column.isSortDescending());
|
224 | _.addOrRemoveCssClass(this.getGui(), 'ag-header-cell-sorted-none', this.params.column.isSortNone());
|
225 |
|
226 | if (this.eSortAsc) {
|
227 | _.addOrRemoveCssClass(this.eSortAsc, 'ag-hidden', !this.params.column.isSortAscending());
|
228 | }
|
229 |
|
230 | if (this.eSortDesc) {
|
231 | _.addOrRemoveCssClass(this.eSortDesc, 'ag-hidden', !this.params.column.isSortDescending());
|
232 | }
|
233 |
|
234 | if (this.eSortNone) {
|
235 | let alwaysHideNoSort = !this.params.column.getColDef().unSortIcon && !this.gridOptionsWrapper.isUnSortIcon();
|
236 | _.addOrRemoveCssClass(this.eSortNone, 'ag-hidden', alwaysHideNoSort || !this.params.column.isSortNone());
|
237 | }
|
238 | }
|
239 |
|
240 |
|
241 |
|
242 |
|
243 | private setMultiSortOrder(): void {
|
244 |
|
245 | if (!this.eSortOrder) {
|
246 | return;
|
247 | }
|
248 |
|
249 | let col = this.params.column;
|
250 | let allColumnsWithSorting = this.sortController.getColumnsWithSortingOrdered();
|
251 | let indexThisCol = allColumnsWithSorting.indexOf(col);
|
252 | let moreThanOneColSorting = allColumnsWithSorting.length > 1;
|
253 | let showIndex = col.isSorting() && moreThanOneColSorting;
|
254 |
|
255 | _.setVisible(this.eSortOrder, showIndex);
|
256 |
|
257 | if (indexThisCol>=0) {
|
258 | this.eSortOrder.innerHTML = (indexThisCol+1).toString();
|
259 | } else {
|
260 | this.eSortOrder.innerHTML = '';
|
261 | }
|
262 | }
|
263 |
|
264 | private setupFilterIcon(): void {
|
265 |
|
266 | if (!this.eFilter) {
|
267 | return;
|
268 | }
|
269 |
|
270 | this.addDestroyableEventListener(this.params.column, Column.EVENT_FILTER_CHANGED, this.onFilterChanged.bind(this));
|
271 | this.onFilterChanged();
|
272 | }
|
273 |
|
274 | private onFilterChanged(): void {
|
275 | let filterPresent = this.params.column.isFilterActive();
|
276 | _.addOrRemoveCssClass(this.eFilter, 'ag-hidden', !filterPresent);
|
277 | }
|
278 |
|
279 | }
|