import {Component} from "../../widgets/component"; import {Autowired, Context, PostConstruct} from "../../context/context"; import {Column} from "../../entities/column"; import {Utils as _} from "../../utils"; import { DragAndDropService, DragItem, DragSource, DragSourceType, DropTarget } from "../../dragAndDrop/dragAndDropService"; import {IHeaderComp, IHeaderParams} from "./headerComp"; import {ColumnApi, ColumnController} from "../../columnController/columnController"; import {HorizontalDragService} from "../horizontalDragService"; import {GridOptionsWrapper} from "../../gridOptionsWrapper"; import {CssClassApplier} from "../cssClassApplier"; import {SetLeftFeature} from "../../rendering/features/setLeftFeature"; import {IAfterGuiAttachedParams, IComponent} from "../../interfaces/iComponent"; import {IMenuFactory} from "../../interfaces/iMenuFactory"; import {GridApi} from "../../gridApi"; import {SortController} from "../../sortController"; import {EventService} from "../../eventService"; import {ComponentRecipes} from "../../components/framework/componentRecipes"; import {AgCheckbox} from "../../widgets/agCheckbox"; import {RefSelector} from "../../widgets/componentAnnotations"; import {SelectAllFeature} from "./selectAllFeature"; import {Events} from "../../events"; import {ColumnHoverService} from "../../rendering/columnHoverService"; import {Beans} from "../../rendering/beans"; export class HeaderWrapperComp extends Component { private static TEMPLATE = ''; @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper; @Autowired('dragAndDropService') private dragAndDropService: DragAndDropService; @Autowired('columnController') private columnController: ColumnController; @Autowired('horizontalDragService') private horizontalDragService: HorizontalDragService; @Autowired('context') private context: Context; @Autowired('menuFactory') private menuFactory: IMenuFactory; @Autowired('gridApi') private gridApi: GridApi; @Autowired('columnApi') private columnApi: ColumnApi; @Autowired('sortController') private sortController: SortController; @Autowired('eventService') private eventService: EventService; @Autowired('componentRecipes') private componentRecipes: ComponentRecipes; @Autowired('columnHoverService') private columnHoverService: ColumnHoverService; @Autowired('beans') private beans: Beans; @RefSelector('eResize') private eResize: HTMLElement; @RefSelector('cbSelectAll') private cbSelectAll: AgCheckbox; private column: Column; private eRoot: HTMLElement; private dragSourceDropTarget: DropTarget; private pinned: string; private startWidth: number; constructor(column: Column, eRoot: HTMLElement, dragSourceDropTarget: DropTarget, pinned: string) { super(HeaderWrapperComp.TEMPLATE); this.column = column; this.eRoot = eRoot; this.dragSourceDropTarget = dragSourceDropTarget; this.pinned = pinned; } public getColumn(): Column { return this.column; } @PostConstruct public init(): void { this.instantiate(this.context); let displayName = this.columnController.getDisplayNameForColumn(this.column, 'header', true); let enableSorting = this.gridOptionsWrapper.isEnableSorting() && !this.column.getColDef().suppressSorting; let enableMenu = this.menuFactory.isMenuEnabled(this.column) && !this.column.getColDef().suppressMenu; let headerComp = this.appendHeaderComp(displayName, enableSorting, enableMenu); this.setupWidth(); this.setupMovingCss(); this.setupTooltip(); this.setupResize(); this.setupMenuClass(); this.setupMove(_.ensureElement(headerComp.getGui()), displayName); this.setupSortableClass(enableSorting); this.addColumnHoverListener(); this.addDestroyableEventListener(this.column, Column.EVENT_FILTER_ACTIVE_CHANGED, this.onFilterChanged.bind(this)); this.onFilterChanged(); this.addFeature(this.context, new SelectAllFeature(this.cbSelectAll, this.column)); let setLeftFeature = new SetLeftFeature(this.column, this.getHtmlElement(), this.beans); setLeftFeature.init(); this.addDestroyFunc(setLeftFeature.destroy.bind(setLeftFeature)); this.addAttributes(); const colDef = this.column.getColDef(); if (colDef.checkboxSelection && !colDef.headerCheckboxSelection && this.gridOptionsWrapper.isRowSelectionMulti() && colDef.checkAll !== false) {// 冗余,但理论上在init时设置更合理 this.cbSelectAll.setVisible(true); } CssClassApplier.addHeaderClassesFromColDef(this.column.getColDef(), this.getHtmlElement(), this.gridOptionsWrapper, this.column, null); } private addColumnHoverListener(): void { this.addDestroyableEventListener(this.eventService, Events.EVENT_COLUMN_HOVER_CHANGED, this.onColumnHover.bind(this)); this.onColumnHover(); } private onColumnHover(): void { let isHovered = this.columnHoverService.isHovered(this.column); _.addOrRemoveCssClass(this.getHtmlElement(), 'ag-column-hover', isHovered) } private setupSortableClass(enableSorting:boolean):void{ if (enableSorting) { let element = this.getHtmlElement(); _.addCssClass(element, 'ag-header-cell-sortable'); } } private onFilterChanged(): void { let filterPresent = this.column.isFilterActive(); _.addOrRemoveCssClass(this.getHtmlElement(), 'ag-header-cell-filtered', filterPresent); } private appendHeaderComp(displayName: string, enableSorting: boolean, enableMenu: boolean): IComponent { let params = { column: this.column, displayName: displayName, enableSorting: enableSorting, enableMenu: enableMenu, showColumnMenu: (source:HTMLElement) => { this.gridApi.showColumnMenuAfterButtonClick(this.column, source) }, progressSort: (multiSort?:boolean) => { this.sortController.progressSort(this.column, !!multiSort); }, setSort: (sort: string, multiSort?: boolean) => { this.sortController.setSortForColumn(this.column, sort, !!multiSort); }, api: this.gridApi, columnApi: this.columnApi, context: this.gridOptionsWrapper.getContext() }; let headerComp: IHeaderComp = this.componentRecipes.newHeaderComponent(params); this.appendChild(headerComp); return headerComp; } private onColumnMovingChanged(): void { // this function adds or removes the moving css, based on if the col is moving. // this is what makes the header go dark when it is been moved (gives impression to // user that the column was picked up). if (this.column.isMoving()) { _.addCssClass(this.getHtmlElement(), 'ag-header-cell-moving'); } else { _.removeCssClass(this.getHtmlElement(), 'ag-header-cell-moving'); } } private setupMove(eHeaderCellLabel: HTMLElement, displayName: string): void { let suppressMove = this.gridOptionsWrapper.isSuppressMovableColumns() || this.column.getColDef().suppressMovable || this.gridOptionsWrapper.isForPrint(); if (suppressMove) { return; } if (eHeaderCellLabel) { let dragSource: DragSource = { type: DragSourceType.HeaderCell, eElement: eHeaderCellLabel, dragItemCallback: () => this.createDragItem(), dragItemName: displayName, dragSourceDropTarget: this.dragSourceDropTarget }; this.dragAndDropService.addDragSource(dragSource, true); this.addDestroyFunc( ()=> this.dragAndDropService.removeDragSource(dragSource) ); } } private createDragItem(): DragItem { let visibleState: { [key: string]: boolean } = {}; visibleState[this.column.getId()] = this.column.isVisible(); return { columns: [this.column], visibleState: visibleState }; } private setupResize(): void { let colDef = this.column.getColDef(); // if no eResize in template, do nothing if (!this.eResize) { return; } if (!this.column.isResizable()) { _.removeFromParent(this.eResize); return; } this.horizontalDragService.addDragHandling({ eDraggableElement: this.eResize, eBody: this.eRoot, cursor: 'col-resize', startAfterPixels: 0, onDragStart: this.onDragStart.bind(this), onDragging: this.onDragging.bind(this) }); let weWantAutoSize = !this.gridOptionsWrapper.isSuppressAutoSize() && !colDef.suppressAutoSize; if (weWantAutoSize) { this.addDestroyableEventListener(this.eResize, 'dblclick', () => { this.columnController.autoSizeColumn(this.column); }); } } public onDragging(dragChange: number, finished: boolean): void { let dragChangeNormalised = this.normaliseDragChange(dragChange); let newWidth = this.startWidth + dragChangeNormalised; this.columnController.setColumnWidth(this.column, newWidth, finished); } public onDragStart(): void { this.startWidth = this.column.getActualWidth(); } private setupTooltip(): void { let colDef = this.column.getColDef(); // add tooltip if exists if (colDef.headerTooltip) { this.getHtmlElement().title = colDef.headerTooltip; } } private setupMovingCss(): void { this.addDestroyableEventListener(this.column, Column.EVENT_MOVING_CHANGED, this.onColumnMovingChanged.bind(this)); this.onColumnMovingChanged(); } private addAttributes(): void { this.getHtmlElement().setAttribute("col-id", this.column.getColId()); } private setupWidth(): void { this.addDestroyableEventListener(this.column, Column.EVENT_WIDTH_CHANGED, this.onColumnWidthChanged.bind(this)); this.onColumnWidthChanged(); } private setupMenuClass(): void { this.addDestroyableEventListener(this.column, Column.EVENT_MENU_VISIBLE_CHANGED, this.onMenuVisible.bind(this)); this.onColumnWidthChanged(); } private onMenuVisible(): void { this.addOrRemoveCssClass('ag-column-menu-visible', this.column.isMenuVisible()); } private onColumnWidthChanged(): void { this.getHtmlElement().style.width = this.column.getActualWidth() + 'px'; } // optionally inverts the drag, depending on pinned and RTL // note - this method is duplicated in RenderedHeaderGroupCell - should refactor out? private normaliseDragChange(dragChange: number): number { let result = dragChange; if (this.gridOptionsWrapper.isEnableRtl()) { // for RTL, dragging left makes the col bigger, except when pinning left if (this.pinned !== Column.PINNED_LEFT) { result *= -1; } } else { // for LTR (ie normal), dragging left makes the col smaller, except when pinning right if (this.pinned === Column.PINNED_RIGHT) { result *= -1; } } return result; } }