UNPKG

carbon-components-angular

Version:
907 lines 94.2 kB
import { Component, Input, Output, EventEmitter, HostBinding } from "@angular/core"; import { Subscription, fromEvent } from "rxjs"; import { TableModel } from "./table-model.class"; import { TableHeaderItem } from "./table-header-item.class"; import { TableItem } from "./table-item.class"; import { getFocusElementList, tabbableSelectorIgnoreTabIndex } from "carbon-components-angular/common"; import { merge } from "carbon-components-angular/utils"; import { DataGridInteractionModel } from "./data-grid-interaction-model.class"; import { TableDomAdapter } from "./table-adapter.class"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "@angular/common"; import * as i3 from "./table.directive"; import * as i4 from "./head/table-head.component"; import * as i5 from "./body/table-body.component"; /** * Build your table with this component by extending things that differ from default. * * [See demo](../../?path=/story/components-table--basic) * * Instead of the usual write-your-own-html approach you had with `<table>`, * carbon table uses model-view-controller approach. * * Here, you create a view (with built-in controller) and provide it a model. * Changes you make to the model are reflected in the view. Provide same model you use * in the table to the `<cds-pagination>` components. * They provide a different view over the same data. * * ## Basic usage * * ```html * <cds-table [model]="model"></cds-table> * ``` * * ```typescript * public model = new TableModel(); * * this.model.data = [ * [new TableItem({data: "asdf"}), new TableItem({data: "qwer"})], * [new TableItem({data: "csdf"}), new TableItem({data: "zwer"})], * [new TableItem({data: "bsdf"}), new TableItem({data: "swer"})], * [new TableItem({data: "csdf"}), new TableItem({data: "twer"})] * ]; * ``` * * ## Customization * * If you have custom data in your table, you need a way to display it. You can do that * by providing a template to `TableItem`. * * ```html * <ng-template #customTableItemTemplate let-data="data"> * <a [routerLink]="data.link">{{data.name}} {{data.surname}}</a> * </ng-template> * ``` * * ```typescript * customTableItemTemplate: TemplateRef<any>; * * this.customModel.data = [ * [new TableItem({data: "asdf"}), new TableItem({data: {name: "Lessy", link: "/table"}, template: this.customTableItemTemplate})], * [new TableItem({data: "csdf"}), new TableItem({data: "swer"})], * [new TableItem({data: "bsdf"}), new TableItem({data: {name: "Alice", surname: "Bob"}, template: this.customTableItemTemplate})], * [new TableItem({data: "csdf"}), new TableItem({data: "twer"})], * ]; * ``` * * ### Sorting and filtering * * In case you need custom sorting and/or filtering you should subclass `TableHeaderItem` * and override needed functions. * * ```typescript * class FilterableHeaderItem extends TableHeaderItem { * // custom filter function * filter(item: TableItem): boolean { * if (typeof item.data === "string" && item.data.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 || * item.data.name && item.data.name.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0 || * item.data.surname && item.data.surname.toLowerCase().indexOf(this.filterData.data.toLowerCase()) >= 0) { * return false; * } * return true; * } * * set filterCount(n) {} * get filterCount() { * return (this.filterData && this.filterData.data && this.filterData.data.length > 0) ? 1 : 0; * } * * // used for custom sorting * compare(one: TableItem, two: TableItem) { * const stringOne = (one.data.name || one.data.surname || one.data).toLowerCase(); * const stringTwo = (two.data.name || two.data.surname || two.data).toLowerCase(); * * if (stringOne > stringTwo) { * return 1; * } else if (stringOne < stringTwo) { * return -1; * } else { * return 0; * } * } * } * ``` * * If you want to do your sorting on the backend or query for sorted data as a result of user * clicking the table header, check table [`sort`](#sort) output documentation * * See `TableHeaderItem` class for more information. * * ## No data template * * When table has no data to show, it can show a message you provide it instead. * * ```html * <cds-table [model]="model">No data.</cds-table> * ``` * * ... will show `No data.` message, but you can get creative and provide any template you want * to replace table's default `tbody`. * * ## Use pagination as table footer * * ```html * <cds-pagination [model]="model" (selectPage)="selectPage($event)"></cds-pagination> * ``` * * `selectPage()` function should fetch the data from backend, create new `data`, apply it to `model.data`, * and update `model.currentPage`. * * If the data your server returns is a two dimensional array of objects, it would look something like this: * * ```typescript * selectPage(page) { * this.getPage(page).then((data: Array<Array<any>>) => { * // set the data and update page * this.model.data = this.prepareData(data); * this.model.currentPage = page; * }); * } * * protected prepareData(data: Array<Array<any>>) { * // create new data from the service data * let newData = []; * data.forEach(dataRow => { * let row = []; * dataRow.forEach(dataElement => { * row.push(new TableItem({ * data: dataElement, * template: typeof dataElement === "string" ? undefined : this.paginationTableItemTemplate * // your template can handle all the data types so you don't have to conditionally set it * // you can also set different templates for different columns based on index * })); * }); * newData.push(row); * }); * return newData; * } * ``` */ export class Table { /** * Creates an instance of Table. */ constructor(elementRef, applicationRef, i18n) { this.elementRef = elementRef; this.applicationRef = applicationRef; this.i18n = i18n; /** * Size of the table rows. */ this.size = "md"; /** * Set to `true` for a loading table. */ this.skeleton = false; /** * Setting sortable to false will disable all headers including headers which are sortable. Is is * possible to set the sortable state on the header item to disable/enable sorting for only some headers. */ this.sortable = true; this.noBorder = true; /** * Controls whether to show the selection checkboxes column or not. */ this.showSelectionColumn = true; /** * Controls whether to enable multiple or single row selection. */ this.enableSingleSelect = false; /** * Distance (in px) from the bottom that view has to reach before * `scrollLoad` event is emitted. */ this.scrollLoadDistance = 0; /** * Set to `false` to remove table rows (zebra) stripes. */ this.striped = true; /** * Allows table content to scroll horizontally */ this.tableContent = true; /** * Set to `true` to stick the header to the top of the table */ this.stickyHeader = false; /** * Emits an index of the column that wants to be sorted. * * If no observers are provided (default), table will attempt to do a simple sort of the data loaded * into the model. * * If an observer is provided, table will not attempt any sorting of its own and it is up to the observer * to sort the table. This is what you typically want if you're using a backend query to get the sorted * data or want to sort data across multiple pages. * * Usage: * * ```typescript * @Component({ * selector: "app-table", * template: ` * <cds-table * [model]="model" * (sort)="simpleSort($event)"> * No data. * </cds-table> * ` * }) * export class TableApp implements OnInit, OnChanges { * @Input() model = new TableModel(); * * ngOnInit() { * this.model.header = [ * new TableHeaderItem({ data: "Name" }), * new TableHeaderItem({ data: "hwer" }) * ]; * * this.model.data = [ * [new TableItem({ data: "Name 1" }), new TableItem({ data: "qwer" })], * [new TableItem({ data: "Name 3" }), new TableItem({ data: "zwer" })], * [new TableItem({ data: "Name 2" }), new TableItem({ data: "swer" })], * [new TableItem({ data: "Name 4" }), new TableItem({data: "twer"})], * [new TableItem({ data: "Name 5" }), new TableItem({data: "twer"})], * [new TableItem({ data: "Name 6" }), new TableItem({data: "twer"})] * ]; * } * * simpleSort(index: number) { * // this function does a simple sort, which is the default for the table and if that's * // all you want, you don't need to do this. * * // here you can query your backend and update the model.data based on the result * if (this.model.header[index].sorted) { * // if already sorted flip sorting direction * this.model.header[index].ascending = this.model.header[index].descending; * } * this.model.sort(index); * } * } * ``` */ this.sort = new EventEmitter(); /** * Emits if all rows are selected. * * @param model */ this.selectAll = new EventEmitter(); /** * Emits if all rows are deselected. * * @param model */ this.deselectAll = new EventEmitter(); /** * Emits if a single row is selected. * * @param ({model: this.model, selectedRowIndex: index}) */ this.selectRow = new EventEmitter(); /** * Emits if a single row is deselected. * * @param ({model: this.model, deselectedRowIndex: index}) */ this.deselectRow = new EventEmitter(); /** * Emits if a row item excluding expandButtons, checkboxes, or radios is clicked. */ this.rowClick = new EventEmitter(); /** * Emits when table requires more data to be loaded. */ this.scrollLoad = new EventEmitter(); /** * Controls if all checkboxes are viewed as selected. */ this.selectAllCheckbox = false; /** * Controls the indeterminate state of the header checkbox. */ this.selectAllCheckboxSomeSelected = false; this.isColumnDragging = false; this.columnDraggedHoverIndex = -1; this.columnDraggedPosition = ""; this._isDataGrid = false; // flag to prevent getters/setters from querying the view before it's fully instantiated this.isViewReady = false; this.subscriptions = new Subscription(); this._expandButtonAriaLabel = this.i18n.getOverridable("TABLE.EXPAND_BUTTON"); this._sortDescendingLabel = this.i18n.getOverridable("TABLE.SORT_DESCENDING"); this._sortAscendingLabel = this.i18n.getOverridable("TABLE.SORT_ASCENDING"); this._checkboxHeaderLabel = this.i18n.getOverridable("TABLE.CHECKBOX_HEADER"); this._checkboxRowLabel = this.i18n.getOverridable("TABLE.CHECKBOX_ROW"); this._endOfDataText = this.i18n.getOverridable("TABLE.END_OF_DATA"); this._scrollTopText = this.i18n.getOverridable("TABLE.SCROLL_TOP"); this._filterTitle = this.i18n.getOverridable("TABLE.FILTER"); } /** * Creates a skeleton model with a row and column count specified by the user * * Example: * * ```typescript * this.model = Table.skeletonModel(5, 5); * ``` */ static skeletonModel(rowCount, columnCount) { const model = new TableModel(); let header = new Array(); let data = new Array(); let row = new Array(); for (let i = 0; i < columnCount; i++) { header.push(new TableHeaderItem()); row.push(new TableItem()); } for (let i = 0; i < rowCount - 1; i++) { data.push(row); } model.header = header; model.data = data; return model; } static setTabIndex(element, index) { const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex); if (element.firstElementChild && element.firstElementChild.classList.contains("cds--table-sort") && focusElementList.length > 1) { focusElementList[1].tabIndex = index; } else if (focusElementList.length > 0) { focusElementList[0].tabIndex = index; } else { element.tabIndex = index; } } static focus(element) { const focusElementList = getFocusElementList(element, tabbableSelectorIgnoreTabIndex); if ((element.firstElementChild?.classList.contains("cds--table-sort") && focusElementList.length > 1) || focusElementList.length > 0) { focusElementList[0].focus(); } else { element.focus(); } } /** * `TableModel` with data the table is to display. */ set model(m) { if (this._model) { this.subscriptions.unsubscribe(); // Need to create a new subscription instance here because unsubscribing prevents any new subscriptions // from being added for some reason. When a new model is set, none of the subscriptions would exist. this.subscriptions = new Subscription(); } this._model = m; const rowsChange = this._model.rowsSelectedChange.subscribe(() => this.updateSelectAllCheckbox()); const dataChange = this._model.dataChange.subscribe(() => { if (this.isDataGrid) { this.resetTabIndex(); } this.updateSelectAllCheckbox(); }); this.subscriptions.add(rowsChange); this.subscriptions.add(dataChange); if (this.isDataGrid) { const expandedChange = this._model.rowsExpandedChange.subscribe(() => { // Allows the expanded row to have a focus state when it exists in the DOM setTimeout(() => { const expandedRows = this.elementRef.nativeElement.querySelectorAll(".cds--expandable-row:not(.cds--parent-row)"); Array.from(expandedRows).forEach(row => { if (row.firstElementChild.tabIndex === undefined || row.firstElementChild.tabIndex !== -1) { row.firstElementChild.tabIndex = -1; } }); }); }); this.subscriptions.add(expandedChange); } } get model() { return this._model; } /** * Set to `true` for a data grid with keyboard interactions. */ set isDataGrid(value) { this._isDataGrid = value; if (this.isViewReady) { if (value) { this.enableDataGridInteractions(); } else { this.disableDataGridInteractions(); } } } get isDataGrid() { return this._isDataGrid; } /** * @todo - Enable column resize when Carbon officially supports feature * Set to `true` to enable users to resize columns. * * Works for columns with width set in pixels. * */ // @Input() columnsResizable = false; /** * @todo - Enable columns drag & drop when Carbon officially supports feature * Set to `true` to enable users to drag and drop columns. * * Changing the column order in table changes table model. Be aware of it when you add additional data * to the model. * */ // @Input() columnsDraggable = false; set expandButtonAriaLabel(value) { this._expandButtonAriaLabel.override(value); } get expandButtonAriaLabel() { return this._expandButtonAriaLabel.value; } set sortDescendingLabel(value) { this._sortDescendingLabel.override(value); } get sortDescendingLabel() { return this._sortDescendingLabel.value; } set sortAscendingLabel(value) { this._sortAscendingLabel.override(value); } get sortAscendingLabel() { return this._sortAscendingLabel.value; } /** * Expects an object that contains some or all of: * ``` * { * "FILTER": "Filter", * "END_OF_DATA": "You've reached the end of your content", * "SCROLL_TOP": "Scroll to top", * "CHECKBOX_HEADER": "Select all rows", * "CHECKBOX_ROW": "Select row" * } * ``` */ set translations(value) { const valueWithDefaults = merge(this.i18n.getMultiple("TABLE"), value); this._filterTitle.override(valueWithDefaults.FILTER); this._endOfDataText.override(valueWithDefaults.END_OF_DATA); this._scrollTopText.override(valueWithDefaults.SCROLL_TOP); this._checkboxHeaderLabel.override(valueWithDefaults.CHECKBOX_HEADER); this._checkboxRowLabel.override(valueWithDefaults.CHECKBOX_ROW); } get noData() { return !this.model.data || this.model.data.length === 0 || this.model.data.length === 1 && this.model.data[0].length === 0; } ngOnInit() { // Manually trigger check to see if all checkboxes are selected // This is since subscription is made AFTER checkboxes are selected this.updateSelectAllCheckbox(); } ngAfterViewInit() { this.isViewReady = true; if (this.isDataGrid) { this.enableDataGridInteractions(); } } ngOnDestroy() { this.subscriptions.unsubscribe(); if (this.positionSubscription) { this.positionSubscription.unsubscribe(); } } enableDataGridInteractions() { // if we have an `interactioModel` we've already enabled datagrid if (this.interactionModel) { return; } const table = this.elementRef.nativeElement.querySelector("table"); const tableAdapter = new TableDomAdapter(table); const keydownEventStream = fromEvent(table, "keydown"); const clickEventStream = fromEvent(table, "click"); this.interactionModel = new DataGridInteractionModel(keydownEventStream, clickEventStream, tableAdapter); this.positionSubscription = this.interactionModel.position.subscribe(event => { const [currentRow, currentColumn] = event.current; const [previousRow, previousColumn] = event.previous; const currentElement = tableAdapter.getCell(currentRow, currentColumn); Table.setTabIndex(currentElement, 0); // if the model has just initialized don't focus or reset anything if (previousRow === -1 || previousColumn === -1) { return; } // Make the previous cell unfocusable (if it's not the current) if (previousRow !== currentRow || previousColumn !== currentColumn) { const previousElement = tableAdapter.getCell(previousRow, previousColumn); Table.setTabIndex(previousElement, -1); } Table.focus(currentElement); }); // call this after assigning `this.interactionModel` since it depends on it this.resetTabIndex(); } disableDataGridInteractions() { // unsubscribe first so we don't cause the focus to fly around if (this.positionSubscription) { this.positionSubscription.unsubscribe(); } // undo tab indexing (also resets the model) this.resetTabIndex(0); // null out the model ref this.interactionModel = null; } onSelectAll() { this.model.selectAll(true); this.selectAll.emit(this.model); } onDeselectAll() { this.model.selectAll(false); this.deselectAll.emit(this.model); } onSelectRow(event) { // check for the existence of the selectedRowIndex property if (Object.keys(event).includes("selectedRowIndex")) { if (this.enableSingleSelect) { this.model.selectAll(false); } this.model.selectRow(event.selectedRowIndex, true); this.selectRow.emit(event); } else { this.model.selectRow(event.deselectedRowIndex, false); this.deselectRow.emit(event); } } onRowClick(index) { this.rowClick.emit(index); } updateSelectAllCheckbox() { const selectedRowsCount = this.model.selectedRowsCount(); if (selectedRowsCount <= 0) { // reset select all checkbox if nothing selected this.selectAllCheckbox = false; this.selectAllCheckboxSomeSelected = false; } else if (selectedRowsCount < this.model.data.length) { this.selectAllCheckbox = true; this.selectAllCheckboxSomeSelected = true; } else { this.selectAllCheckbox = true; this.selectAllCheckboxSomeSelected = false; } } resetTabIndex(newTabIndex = -1) { // ensure the view is ready for the reset before we preform the actual reset setTimeout(() => { // reset all the tabIndexes we can find const focusElementList = getFocusElementList(this.elementRef.nativeElement, tabbableSelectorIgnoreTabIndex); if (focusElementList) { focusElementList.forEach(tabbable => { tabbable.tabIndex = newTabIndex; }); } // reset interaction model positions and tabIndexes if (this.interactionModel) { this.interactionModel.resetTabIndexes(newTabIndex); } }); } columnResizeStart(event, column) { this.columnResizeWidth = parseInt(column.style.width, 10); this.columnResizeMouseX = event.clientX; event.preventDefault(); this.mouseMoveSubscription = fromEvent(document.body, "mousemove").subscribe(event => { this.columnResizeProgress(event, column); }); this.mouseUpSubscription = fromEvent(document.body, "mouseup").subscribe(event => { this.columnResizeEnd(event, column); }); } columnResizeProgress(event, column) { const move = event.clientX - this.columnResizeMouseX; column.style.width = `${this.columnResizeWidth + move}px`; } columnResizeEnd(event, column) { this.mouseMoveSubscription.unsubscribe(); this.mouseUpSubscription.unsubscribe(); } /** * Triggered when the user scrolls on the `<tbody>` element. * Emits the `scrollLoad` event. */ onScroll(event) { const distanceFromBottom = event.target.scrollHeight - event.target.clientHeight - event.target.scrollTop; if (distanceFromBottom <= this.scrollLoadDistance) { this.scrollLoad.emit(this.model); } else { this.model.isEnd = false; } } columnDragStart(event, columnIndex) { this.isColumnDragging = true; this.columnDraggedHoverIndex = columnIndex; event.dataTransfer.setData("columnIndex", JSON.stringify(columnIndex)); } columnDragEnd(event, columnIndex) { this.isColumnDragging = false; this.columnDraggedHoverIndex = -1; } columnDragEnter(event, position, columnIndex) { this.columnDraggedPosition = position; this.columnDraggedHoverIndex = columnIndex; } columnDragLeave(event, position, columnIndex) { this.columnDraggedPosition = ""; } columnDragover(event, position, columnIndex) { this.columnDraggedHoverIndex = columnIndex; this.columnDraggedPosition = position; // needed to tell browser to allow dropping event.preventDefault(); } columnDrop(event, position, columnIndex) { this.isColumnDragging = false; this.columnDraggedHoverIndex = -1; this.columnDraggedPosition = ""; this.model.moveColumn(parseInt(event.dataTransfer.getData("columnIndex"), 10), columnIndex + (position === "right" ? 1 : 0)); } doSort(index) { if (this.sort.observers.length === 0) { // no sort provided so do the simple sort this.model.cycleSortState(index); this.model.sort(index); } this.sort.emit(index); } /** * Triggered when the user scrolls on the `<tbody>` element. * Emits the `scrollLoad` event. */ scrollToTop(event) { event.target.parentElement.parentElement.parentElement.parentElement.children[1].scrollTop = 0; this.model.isEnd = false; } getSelectionLabelValue(row) { if (!this.selectionLabelColumn) { return { value: this.i18n.get().TABLE.ROW }; } return { value: row[this.selectionLabelColumn].data }; } getExpandButtonAriaLabel() { return this._expandButtonAriaLabel.subject; } getSortDescendingLabel() { return this._sortDescendingLabel.subject; } getSortAscendingLabel() { return this._sortAscendingLabel.subject; } getCheckboxHeaderLabel() { return this._checkboxHeaderLabel.subject; } getCheckboxRowLabel() { return this._checkboxRowLabel.subject; } getEndOfDataText() { return this._endOfDataText.subject; } getScrollTopText() { return this._scrollTopText.subject; } getFilterTitle() { return this._filterTitle.subject; } } Table.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Table, deps: [{ token: i0.ElementRef }, { token: i0.ApplicationRef }, { token: i1.I18n }], target: i0.ɵɵFactoryTarget.Component }); Table.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Table, selector: "cds-table, ibm-table", inputs: { ariaLabelledby: "ariaLabelledby", ariaDescribedby: "ariaDescribedby", model: "model", size: "size", skeleton: "skeleton", isDataGrid: "isDataGrid", sortable: "sortable", noBorder: "noBorder", showSelectionColumn: "showSelectionColumn", enableSingleSelect: "enableSingleSelect", scrollLoadDistance: "scrollLoadDistance", expandButtonAriaLabel: "expandButtonAriaLabel", sortDescendingLabel: "sortDescendingLabel", sortAscendingLabel: "sortAscendingLabel", translations: "translations", striped: "striped", stickyHeader: "stickyHeader", footerTemplate: "footerTemplate", selectionLabelColumn: "selectionLabelColumn" }, outputs: { sort: "sort", selectAll: "selectAll", deselectAll: "deselectAll", selectRow: "selectRow", deselectRow: "deselectRow", rowClick: "rowClick", scrollLoad: "scrollLoad" }, host: { properties: { "class.cds--data-table-content": "this.tableContent", "class.cds--data-table_inner-container": "this.stickyHeader" } }, ngImport: i0, template: ` <table cdsTable [sortable]="sortable" [noBorder]="noBorder" [ngClass]="{'cds--data-table--sticky-header': stickyHeader}" [size]="size" [striped]="striped" [skeleton]="skeleton" [attr.aria-labelledby]="ariaLabelledby" [attr.aria-describedby]="ariaDescribedby"> <thead cdsTableHead [sortable]="sortable" (deselectAll)="onDeselectAll()" (selectAll)="onSelectAll()" (sort)="doSort($event)" [checkboxHeaderLabel]="getCheckboxHeaderLabel()" [filterTitle]="getFilterTitle()" [model]="model" [selectAllCheckbox]="selectAllCheckbox" [selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected" [showSelectionColumn]="showSelectionColumn" [enableSingleSelect]="enableSingleSelect" [skeleton]="skeleton" [sortAscendingLabel]="sortAscendingLabel" [sortDescendingLabel]="sortDescendingLabel" [stickyHeader]="stickyHeader"> </thead> <tbody cdsTableBody (deselectRow)="onSelectRow($event)" (scroll)="onScroll($event)" (selectRow)="onSelectRow($event)" [checkboxRowLabel]="getCheckboxRowLabel()" [enableSingleSelect]="enableSingleSelect" (rowClick)="onRowClick($event)" [expandButtonAriaLabel]="expandButtonAriaLabel" [model]="model" [size]="size" [ngStyle]="{'overflow-y': 'scroll'}" [selectionLabelColumn]="selectionLabelColumn" [showSelectionColumn]="showSelectionColumn" [skeleton]="skeleton" *ngIf="!noData; else noDataTemplate"> </tbody> <ng-template #noDataTemplate><ng-content></ng-content></ng-template> <tfoot> <ng-template [ngTemplateOutlet]="footerTemplate"> </ng-template> <tr *ngIf="this.model.isLoading"> <td class="table_loading-indicator"> <div class="cds--loading cds--loading--small"> <svg class="cds--loading__svg" viewBox="-75 -75 150 150"> <circle class="cds--loading__stroke" cx="0" cy="0" r="37.5" /> </svg> </div> </td> </tr> <tr *ngIf="this.model.isEnd"> <td class="table_end-indicator"> <h5>{{getEndOfDataText() | async}}</h5> <button (click)="scrollToTop($event)" class="btn--secondary-sm"> {{getScrollTopText() | async}} </button> </td> </tr> </tfoot> </table> `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i3.TableDirective, selector: "[cdsTable], [ibmTable]", inputs: ["sortable", "noBorder", "striped", "skeleton", "size"] }, { kind: "component", type: i4.TableHead, selector: "[cdsTableHead], [ibmTableHead]", inputs: ["model", "showSelectionColumn", "enableSingleSelect", "selectAllCheckboxSomeSelected", "selectAllCheckbox", "skeleton", "stickyHeader", "sortable", "checkboxHeaderLabel", "sortDescendingLabel", "sortAscendingLabel", "filterTitle"], outputs: ["sort", "selectAll", "deselectAll"] }, { kind: "component", type: i5.TableBody, selector: "[cdsTableBody], [ibmTableBody]", inputs: ["model", "enableSingleSelect", "expandButtonAriaLabel", "checkboxRowLabel", "showSelectionColumn", "size", "selectionLabelColumn", "skeleton"], outputs: ["selectRow", "deselectRow", "rowClick"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Table, decorators: [{ type: Component, args: [{ selector: "cds-table, ibm-table", template: ` <table cdsTable [sortable]="sortable" [noBorder]="noBorder" [ngClass]="{'cds--data-table--sticky-header': stickyHeader}" [size]="size" [striped]="striped" [skeleton]="skeleton" [attr.aria-labelledby]="ariaLabelledby" [attr.aria-describedby]="ariaDescribedby"> <thead cdsTableHead [sortable]="sortable" (deselectAll)="onDeselectAll()" (selectAll)="onSelectAll()" (sort)="doSort($event)" [checkboxHeaderLabel]="getCheckboxHeaderLabel()" [filterTitle]="getFilterTitle()" [model]="model" [selectAllCheckbox]="selectAllCheckbox" [selectAllCheckboxSomeSelected]="selectAllCheckboxSomeSelected" [showSelectionColumn]="showSelectionColumn" [enableSingleSelect]="enableSingleSelect" [skeleton]="skeleton" [sortAscendingLabel]="sortAscendingLabel" [sortDescendingLabel]="sortDescendingLabel" [stickyHeader]="stickyHeader"> </thead> <tbody cdsTableBody (deselectRow)="onSelectRow($event)" (scroll)="onScroll($event)" (selectRow)="onSelectRow($event)" [checkboxRowLabel]="getCheckboxRowLabel()" [enableSingleSelect]="enableSingleSelect" (rowClick)="onRowClick($event)" [expandButtonAriaLabel]="expandButtonAriaLabel" [model]="model" [size]="size" [ngStyle]="{'overflow-y': 'scroll'}" [selectionLabelColumn]="selectionLabelColumn" [showSelectionColumn]="showSelectionColumn" [skeleton]="skeleton" *ngIf="!noData; else noDataTemplate"> </tbody> <ng-template #noDataTemplate><ng-content></ng-content></ng-template> <tfoot> <ng-template [ngTemplateOutlet]="footerTemplate"> </ng-template> <tr *ngIf="this.model.isLoading"> <td class="table_loading-indicator"> <div class="cds--loading cds--loading--small"> <svg class="cds--loading__svg" viewBox="-75 -75 150 150"> <circle class="cds--loading__stroke" cx="0" cy="0" r="37.5" /> </svg> </div> </td> </tr> <tr *ngIf="this.model.isEnd"> <td class="table_end-indicator"> <h5>{{getEndOfDataText() | async}}</h5> <button (click)="scrollToTop($event)" class="btn--secondary-sm"> {{getScrollTopText() | async}} </button> </td> </tr> </tfoot> </table> `, styles: [":host{display:block}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ApplicationRef }, { type: i1.I18n }]; }, propDecorators: { ariaLabelledby: [{ type: Input }], ariaDescribedby: [{ type: Input }], model: [{ type: Input }], size: [{ type: Input }], skeleton: [{ type: Input }], isDataGrid: [{ type: Input }], sortable: [{ type: Input }], noBorder: [{ type: Input }], showSelectionColumn: [{ type: Input }], enableSingleSelect: [{ type: Input }], scrollLoadDistance: [{ type: Input }], expandButtonAriaLabel: [{ type: Input }], sortDescendingLabel: [{ type: Input }], sortAscendingLabel: [{ type: Input }], translations: [{ type: Input }], striped: [{ type: Input }], tableContent: [{ type: HostBinding, args: ["class.cds--data-table-content"] }], stickyHeader: [{ type: HostBinding, args: ["class.cds--data-table_inner-container"] }, { type: Input }], footerTemplate: [{ type: Input }], selectionLabelColumn: [{ type: Input }], sort: [{ type: Output }], selectAll: [{ type: Output }], deselectAll: [{ type: Output }], selectRow: [{ type: Output }], deselectRow: [{ type: Output }], rowClick: [{ type: Output }], scrollLoad: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RhYmxlL3RhYmxlLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUVULEtBQUssRUFFTCxNQUFNLEVBQ04sWUFBWSxFQUtaLFdBQVcsRUFDWCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBYyxNQUFNLE1BQU0sQ0FBQztBQUUzRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUvQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUV2RyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDeEQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDL0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHVCQUF1QixDQUFDOzs7Ozs7O0FBR3hEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnSkc7QUFnRkgsTUFBTSxPQUFPLEtBQUs7SUF3WWpCOztPQUVHO0lBQ0gsWUFDVyxVQUFzQixFQUN0QixjQUE4QixFQUM5QixJQUFVO1FBRlYsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQUN0QixtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsU0FBSSxHQUFKLElBQUksQ0FBTTtRQXBTckI7O1dBRUc7UUFDTSxTQUFJLEdBQWlCLElBQUksQ0FBQztRQUNuQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFlMUI7OztXQUdHO1FBQ00sYUFBUSxHQUFHLElBQUksQ0FBQztRQUVoQixhQUFRLEdBQUcsSUFBSSxDQUFDO1FBTXpCOztXQUVHO1FBQ00sd0JBQW1CLEdBQUcsSUFBSSxDQUFDO1FBRXBDOztXQUVHO1FBQ00sdUJBQWtCLEdBQUcsS0FBSyxDQUFDO1FBRXBDOzs7V0FHRztRQUNNLHVCQUFrQixHQUFHLENBQUMsQ0FBQztRQWlFaEM7O1dBRUc7UUFDTSxZQUFPLEdBQUcsSUFBSSxDQUFDO1FBRXhCOztXQUVHO1FBQzJDLGlCQUFZLEdBQUcsSUFBSSxDQUFDO1FBRWxFOztXQUVHO1FBQzRELGlCQUFZLEdBQUcsS0FBSyxDQUFDO1FBbUJwRjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztXQXVERztRQUNPLFNBQUksR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBRTVDOzs7O1dBSUc7UUFDTyxjQUFTLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUVqRDs7OztXQUlHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBRW5EOzs7O1dBSUc7UUFDTyxjQUFTLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUVqRDs7OztXQUlHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBRW5EOztXQUVHO1FBQ08sYUFBUSxHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7UUFFaEQ7O1dBRUc7UUFDTyxlQUFVLEdBQUcsSUFBSSxZQUFZLEVBQWMsQ0FBQztRQUV0RDs7V0FFRztRQUNILHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQUUxQjs7V0FFRztRQUNILGtDQUE2QixHQUFHLEtBQUssQ0FBQztRQVEvQixxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFDekIsNEJBQXVCLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDN0IsMEJBQXFCLEdBQUcsRUFBRSxDQUFDO1FBR3hCLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQzlCLHdGQUF3RjtRQUM5RSxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUVwQixrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFNbkMsMkJBQXNCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN6RSx5QkFBb0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQ3pFLHdCQUFtQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDdkUseUJBQW9CLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUN6RSxzQkFBaUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ25FLG1CQUFjLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUMvRCxtQkFBYyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDOUQsaUJBQVksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQWM5RCxDQUFDO0lBOVlMOzs7Ozs7OztPQVFHO0lBQ0gsTUFBTSxDQUFDLGFBQWEsQ0FBQyxRQUFnQixFQUFFLFdBQW1CO1FBQ3pELE1BQU0sS0FBSyxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDL0IsSUFBSSxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQW1CLENBQUM7UUFDMUMsSUFBSSxJQUFJLEdBQUcsSUFBSSxLQUFLLEVBQW9CLENBQUM7UUFDekMsSUFBSSxHQUFHLEdBQUcsSUFBSSxLQUFLLEVBQWEsQ0FBQztRQUVqQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsV0FBVyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3JDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxlQUFlLEVBQUUsQ0FBQyxDQUFDO1lBQ25DLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1NBQzFCO1FBQ0QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFFBQVEsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNmO1FBRUQsS0FBSyxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDdEIsS0FBSyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDbEIsT0FBTyxLQUFLLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUFvQixFQUFFLEtBQWE7UUFDckQsTUFBTSxnQkFBZ0IsR0FBRyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsOEJBQThCLENBQUMsQ0FBQztRQUN0RixJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsSUFBSSxPQUFPLENBQUMsaUJBQWlCLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDaEksZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztTQUNyQzthQUFNLElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUN2QyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1NBQ3JDO2FBQU07WUFDTixPQUFPLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztTQUN6QjtJQUNGLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQW9CO1FBQ2hDLE1BQU0sZ0JBQWdCLEdBQUcsbUJBQW1CLENBQUMsT0FBTyxFQUFFLDhCQUE4QixDQUFDLENBQUM7UUFDdEYsSUFDQyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUNqRyxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUMxQjtZQUNELGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO1NBQzVCO2FBQU07WUFDTixPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7U0FDaEI7SUFDRixDQUFDO0lBV0Q7O09BRUc7SUFDSCxJQUNJLEtBQUssQ0FBQyxDQUFhO1FBQ3RCLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNoQixJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pDLHVHQUF1RztZQUN2RyxvR0FBb0c7WUFDcEcsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1NBQ3hDO1FBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFFaEIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUMsQ0FBQztRQUNsRyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQ3hELElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDcEIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2FBQ3JCO1lBQ0QsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7UUFDaEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVuQyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDcEIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO2dCQUNwRSwwRUFBMEU7Z0JBQzFFLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ2YsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQUMsNENBQTRDLENBQUMsQ0FBQztvQkFDbEgsS0FBSyxDQUFDLElBQUksQ0FBTSxZQUFZLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7d0JBQzNDLElBQUksR0FBRyxDQUFDLGlCQUFpQixDQUFDLFFBQVEsS0FBSyxTQUFTLElBQUksR0FBRyxDQUFDLGlCQUFpQixDQUFDLFFBQVEsS0FBSyxDQUFDLENBQUMsRUFBRTs0QkFDMUYsR0FBRyxDQUFDLGlCQUFpQixDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsQ0FBQzt5QkFDcEM7b0JBQ0YsQ0FBQyxDQUFDLENBQUM7Z0JBQ0osQ0FBQyxDQUFDLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUNILElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1NBQ3ZDO0lBQ0YsQ0FBQztJQUVELElBQUksS0FBSztRQUNSLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQztJQUNwQixDQUFDO0lBVUQ7O09BRUc7SUFDSCxJQUFhLFVBQVUsQ0FBQyxLQUFjO1FBQ3JDLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUNyQixJQUFJLEtBQUssRUFBRTtnQkFDVixJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQzthQUNsQztpQkFBTTtnQkFDTixJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQzthQUNuQztTQUNEO0lBQ0YsQ0FBQztJQVVELElBQUksVUFBVTtRQUNiLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUN6QixDQUFDO0lBa0JEOzs7Ozs7T0FNRztJQUNILHFDQUFxQztJQUVyQzs7Ozs7OztPQU9HO0lBQ0gscUNBQXFDO0lBRXJDLElBQ0kscUJBQXFCLENBQUMsS0FBa0M7UUFDM0QsSUFBSSxDQUFDLHNCQUFzQixDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBQ0QsSUFBSSxxQkFBcUI7UUFDeEIsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxDQUFDO0lBQzFDLENBQUM7SUFDRCxJQUNJLG1CQUFtQixDQUFDLEtBQWtDO1FBQ3pELElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUNELElBQUksbUJBQW1CO1FBQ3RCLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDLEtBQUssQ0FBQztJQUN4QyxDQUFDO0lBQ0QsSUFDSSxrQkFBa0IsQ0FBQyxLQUFrQztRQUN4RCxJQUFJLENBQUMsbUJBQW1CLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFDRCxJQUFJLGtCQUFrQjtRQUNyQixPQUFPLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLENBQUM7SUFDdkMsQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsSUFDSSxZQUFZLENBQUMsS0FBSztRQUNyQixNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN2RSxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDakUsQ0FBQztJQTRJRCxJQUFJLE1BQU07UUFDVCxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJO1lBQ3RCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQzVCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBd0NELFFBQVE7UUFDUCwrREFBK0Q7UUFDL0QsbUVBQW1FO1FBQ25FLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRCxlQUFlO1FBQ2QsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDeEIsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ3BCLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1NBQ2xDO0lBQ0YsQ0FBQztJQUVELFdBQVc7UUFDVixJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pDLElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFO1lBQzlCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztTQUN4QztJQUNGLENBQUM7SUFFRCwwQkFBMEI7UUFDekIsaUVBQWlFO1FBQ2pFLElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO1lBQzFCLE9BQU87U0FDUDtRQUNELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQXFCLENBQUM7UUFDdkYsTUFBTSxZQUFZLEdBQUcsSUFBSSxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDaEQsTUFBTSxrQkFBa0IsR0FBRyxTQUFTLENBQWdCLEtBQUssRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN0RSxNQUFNLGdCQUFnQixHQUFHLFNBQVMsQ0FBYSxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDL0QsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksd0JBQXdCLENBQUMsa0JBQWtCLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDekcsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQzVFLE1BQU0sQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztZQUNsRCxNQUFNLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUM7WUFFckQsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDdkUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFFckMsa0VBQWtFO1lBQ2xFLElBQUksV0FBVyxLQUFLLENBQUMsQ0FBQyxJQUFJLGNBQWMsS0FBSyxDQUFDLENBQUMsRUFBRTtnQkFBRSxPQUFPO2FBQUU7WUFDNUQsK0RBQStEO1lBQy9ELElBQUksV0FBVyxLQUFLLFVBQVUsSUFBSSxjQUFjLEtBQUssYUFBYSxFQUFFO2dCQUNuRSxNQUFNLGVBQWUsR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxjQUFjLENBQUMsQ0FBQztnQkFDMUUsS0FBSyxDQUFDLFdBQVcsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUN2QztZQUNELEtBQUssQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDN0IsQ0FBQyxDQUFDLENBQUM7UUFDSCwyRUFBMkU7UUFDM0UsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRCwyQkFBMkI7UUFDMUIsOERBQThEO1FBQzlELElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFO1lBQzlCLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztTQUN4QztRQUNELDRDQUE0QztRQUM1QyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RCLHlCQUF5QjtRQUN6QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDO0lBQzlCLENBQUM7SUFFRCxXQUFXO1FBQ1YsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDM0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxhQUFhO1FBQ1osSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFFRCxXQUFXLENBQUMsS0FBSztRQUNoQiwyREFBMkQ7UUFDM0QsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFO1lBQ3BELElBQUksSUFBSSxDQUFDLGtCQUFrQixFQUFFO2dCQUM1QixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQzthQUM1QjtZQUNELElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNuRCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUMzQjthQUFNO1lBQ04sSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLGtCQUFrQixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3RELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQzdCO0lBQ0YsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3ZCLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCx1QkFBdUI7UUFDdEIsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFFekQsSUFBSSxpQkFBaUIsSUFBSSxDQUFDLEVBQUU7WUFDM0IsZ0RBQWdEO1lBQ2hELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUM7WUFDL0IsSUFBSSxDQUFDLDZCQUE2QixHQUFHLEtBQUssQ0FBQztTQUMzQzthQUFNLElBQUksaUJBQWlCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ3RELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7WUFDOUIsSUFBSSxDQUFDLDZCQUE2QixHQUFHLElBQUksQ0FBQztTQUMxQzthQUFNO1lBQ04sSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztZQUM5QixJQUFJLENBQUMsNkJBQTZCLEdBQUcsS0FBSyxDQUFDO1NBQzNDO0lBQ0YsQ0FBQztJQUVELGFBQWEsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1FBQzdCLDRFQUE0RTtRQUM1RSxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQ2YsdUNBQXVDO1lBQ3ZDLE1BQU0sZ0JBQWdCLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLEVBQUUsOEJBQThCLENBQUMsQ0FBQztZQUM1RyxJQUFJLGdCQUFnQixFQUFFO2dCQUNyQixnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUU7b0JBQ25DLFFBQVEsQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDO2dCQUNqQyxDQUFDLENBQUMsQ0FBQzthQUNIO1lBQ0QsbURBQW1EO1lBQ25ELElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFO2dCQUMxQixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxDQUFDO2FBQ25EO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0lBRUQsaUJBQWlCLENBQUMsS0FBSyxFQUFFLE1BQU07UUFDOUIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztRQUN4QyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFFdkIsSUFBSSxDQUFDLHFCQUFxQixHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNwRixJQUFJLENBQUMsb0JBQW9CLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzFDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNoRixJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNyQyxDQUFDLENBQUMsQ0FBQztJQUNKLENBQUM7SUFFRCxvQkFBb0IsQ0FBQyxLQUFLLEVBQUUsTUFBTTtRQUNqQyxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztRQUNyRCxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLElBQUksQ0FBQztJQUMzRCxDQUFDO0lBRUQsZUFBZSxDQU