diff --git a/packages/stark-ui/src/modules.ts b/packages/stark-ui/src/modules.ts index 80a64343c3..b85c266949 100644 --- a/packages/stark-ui/src/modules.ts +++ b/packages/stark-ui/src/modules.ts @@ -1,15 +1,15 @@ export * from "./modules/action-bar"; export * from "./modules/app-logo"; export * from "./modules/app-logout"; +export * from "./modules/app-sidebar"; export * from "./modules/breadcrumb"; export * from "./modules/collapsible"; -export * from "./modules/app-sidebar"; -export * from "./modules/keyboard-directives"; export * from "./modules/date-picker"; export * from "./modules/date-range-picker"; export * from "./modules/dropdown"; export * from "./modules/keyboard-directives"; export * from "./modules/language-selector"; +export * from "./modules/pagination"; export * from "./modules/pretty-print"; export * from "./modules/slider"; export * from "./modules/svg-view-box"; diff --git a/packages/stark-ui/src/modules/pagination.ts b/packages/stark-ui/src/modules/pagination.ts new file mode 100644 index 0000000000..be06e59348 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination.ts @@ -0,0 +1,2 @@ +export * from "./pagination/pagination.module"; +export * from "./pagination/components"; diff --git a/packages/stark-ui/src/modules/pagination/components.ts b/packages/stark-ui/src/modules/pagination/components.ts new file mode 100644 index 0000000000..82d047bd70 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components.ts @@ -0,0 +1,2 @@ +export * from "./components/pagination.component"; +export * from "./components/pagination-config.intf"; diff --git a/packages/stark-ui/src/modules/pagination/components/_pagination-theme.scss b/packages/stark-ui/src/modules/pagination/components/_pagination-theme.scss new file mode 100644 index 0000000000..fc03d33dc1 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/_pagination-theme.scss @@ -0,0 +1,23 @@ +/********** PAGINATION THEME **********/ +/* stark: src/modules/pagination/components/_pagination-theme.scss */ + +@media #{$tablet-query} { + .stark-pagination > div { + .pagination-enter-page { + & input { + border: solid 1px $divider-color; + } + } + + .page-numbers { + &.active { + a { + color: mat-color(map-get($base-theme, primary-palette)); + opacity: 1; + } + } + } + } +} + +/* END stark: src/modules/pagination/components/_pagination-theme.scss */ diff --git a/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss b/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss new file mode 100644 index 0000000000..22464a8846 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/_pagination.component.scss @@ -0,0 +1,68 @@ +/********** PAGINATION **********/ +/* stark: src/modules/pagination/components/_pagination.component.scss */ +.stark-pagination > div { + align-items: center; + display: flex; + justify-content: flex-start; + ul { + align-items: center; + display: flex; + list-style: none; + margin: 0; + margin-right: 18px; + padding: 0; + } + .pagination-enter-page { + display: none; + } + + .pagination-items-per-page { + .stark-dropdown .mat-form-field { + width: 50px; + } + } + + .page-numbers { + display: none; + } +} + +@media #{$tablet-query} { + .stark-pagination > div { + font-size: mat-font-size($typography-config, caption); + font-weight: mat-font-weight($typography-config, caption); + line-height: mat-line-height($typography-config, caption); + + .pagination-enter-page { + align-items: center; + display: flex; + margin-right: 40px; + & input { + margin-right: 4px; + width: 26px; + height: 24px; + padding: 4px; + border-radius: 2px; + text-align: center; + } + } + + .page-numbers { + cursor: pointer; + display: flex; + a { + color: inherit; + padding: 15px; + opacity: 0.5; + } + } + + &.compact { + .pagination-enter-page { + margin-right: 5px; + } + } + } +} + +/* END stark: src/modules/pagination/components/_pagination.component.scss */ diff --git a/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts b/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts new file mode 100644 index 0000000000..baf518eaf3 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination-config.intf.ts @@ -0,0 +1,52 @@ +/** + * Defines the config object to be used with the Pagination component. + */ +export interface StarkPaginationConfig { + /** + * If true, the component will be displayed in "extended" mode (an "extended-pagination" class is added to the element). + * Default: false + */ + isExtended?: boolean; + + /** + * Number of items displayed on each page. The number of available pages for pagination is calculated based on this number. + * Default: itemsPerPageOptions[0] + */ + itemsPerPage?: number; + + /** + * Available options for items per page dropdown. + * Default : [5,10,15] + */ + itemsPerPageOptions?: number[]; + + /** + * If false, then itemsPerPage dropdown will not be present. + * Default: true + */ + itemsPerPageIsPresent?: boolean; + + /** + * Current page index. + * Default: 0 + */ + page?: number; + + /** + * If false, then page nav bar will not be present. + * Default: true + */ + pageNavIsPresent?: boolean; + + /** + * f false, then input box for page selection will not be present. + * Default: true + */ + pageInputIsPresent?: boolean; + + /** + * Number of items being paged in order to calculate number of pages for pagination. + * Default: 0 + */ + totalItems?: number; +} diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.html b/packages/stark-ui/src/modules/pagination/components/pagination.component.html new file mode 100644 index 0000000000..0ca1974aed --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.html @@ -0,0 +1,74 @@ +
+ +
+ + {{ getTotalPages() }} +
+
+ +
+
+ +
+ +
diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts b/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts new file mode 100644 index 0000000000..1ea3e3d386 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.spec.ts @@ -0,0 +1,1084 @@ +import { async, ComponentFixture, TestBed, fakeAsync, tick } from "@angular/core/testing"; +import { FormsModule } from "@angular/forms"; +import { MatInputModule } from "@angular/material/input"; +import { MatMenuModule } from "@angular/material/menu"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatButtonModule } from "@angular/material/button"; +import { NoopAnimationsModule } from "@angular/platform-browser/animations"; +import { Component, DebugElement, NO_ERRORS_SCHEMA, ViewChild } from "@angular/core"; +import { By } from "@angular/platform-browser"; +import { TranslateModule } from "@ngx-translate/core"; +import { STARK_LOGGING_SERVICE } from "@nationalbankbelgium/stark-core"; +import { MockStarkLoggingService } from "@nationalbankbelgium/stark-core/testing"; +import { Observer } from "rxjs"; +import { StarkPaginateEvent, StarkPaginationComponent } from "./pagination.component"; +import { StarkPaginationConfig } from "./pagination-config.intf"; +import { StarkDropdownComponent, StarkDropdownModule } from "../../dropdown"; +import { StarkKeyboardDirectivesModule } from "../../keyboard-directives"; +import SpyObj = jasmine.SpyObj; +import createSpyObj = jasmine.createSpyObj; + +@Component({ + selector: `host-component`, + template: ` + + ` +}) +class TestHostComponent { + @ViewChild(StarkPaginationComponent) + public paginationComponent: StarkPaginationComponent; + + public htmlSuffixId: string; + public paginationConfig: StarkPaginationConfig; +} + +fdescribe("PaginationComponent", () => { + let hostComponent: TestHostComponent; + let hostFixture: ComponentFixture; + let component: StarkPaginationComponent; + + const paginationConfig: StarkPaginationConfig = { + page: 2, + itemsPerPage: 4, + itemsPerPageOptions: [4, 8, 12], + totalItems: 6, + isExtended: true + }; + + const assertPageNavSelection: Function = (paginationElement: DebugElement, selectedOption: string) => { + const pageNavElement: DebugElement = paginationElement.query(By.css("ul")); + const pageNavOptionElements: DebugElement[] = pageNavElement.queryAll(By.css("li")); + + for (const pageNavOption of pageNavOptionElements) { + if (pageNavOption.properties["value"] === selectedOption) { + expect(pageNavOption.classes["active"]).toBe(true); + } else { + expect(pageNavOption.classes["active"]).toBeFalsy(); // can be undefined or false + } + } + }; + + const changeInputValueAndPressEnter: Function = (rootElement: DebugElement, value: string) => { + const querySelector: string = "div.pagination-enter-page input"; + const pageSelectorInput: DebugElement = rootElement.query(By.css(querySelector)); + + (pageSelectorInput.nativeElement).value = value; + (pageSelectorInput.nativeElement).dispatchEvent(new Event("input")); + + const changeEvent: Event = document.createEvent("Event"); + changeEvent.initEvent("change", true, true); + pageSelectorInput.triggerEventHandler("change", changeEvent); + + const keypressEvent: Event = document.createEvent("Event"); + keypressEvent.initEvent("keypress", true, true); + keypressEvent["which"] = 13; + pageSelectorInput.triggerEventHandler("keypress", keypressEvent); + }; + + const assertPageInputSelection: Function = (rootElement: DebugElement, selectedOption: string) => { + const querySelector: string = "div.pagination-enter-page input"; + const pageSelectorInput: DebugElement = rootElement.query(By.css(querySelector)); + expect(pageSelectorInput.properties["value"].toString()).toBe(selectedOption); + }; + + beforeEach(async(() => { + return TestBed.configureTestingModule({ + imports: [ + FormsModule, + MatButtonModule, + MatInputModule, + MatMenuModule, + MatPaginatorModule, + MatTooltipModule, + NoopAnimationsModule, + TranslateModule.forRoot(), + StarkDropdownModule, + StarkKeyboardDirectivesModule + ], + declarations: [StarkPaginationComponent, TestHostComponent], + providers: [{ provide: STARK_LOGGING_SERVICE, useValue: new MockStarkLoggingService() }], + schemas: [NO_ERRORS_SCHEMA] // to avoid errors due to "mat-icon" directive not known (which we don't want to add in these tests) + }).compileComponents(); + })); + + beforeEach(() => { + hostFixture = TestBed.createComponent(TestHostComponent); + hostComponent = hostFixture.componentInstance; + hostFixture.detectChanges(); + + component = hostComponent.paginationComponent; + }); + + describe("on initialization", () => { + it("should set internal component properties", () => { + expect(hostFixture).toBeDefined(); + expect(component).toBeDefined(); + + expect(component.logger).not.toBeNull(); + expect(component.logger).toBeDefined(); + }); + + it("should NOT have any inputs set", () => { + expect(component.htmlSuffixId).toBe("pagination"); + expect(component.mode).toBeUndefined(); + expect(component.paginationConfig).toBeDefined(); + }); + + it("should render the appropriate content in normal mode", () => { + hostComponent.paginationConfig = { + page: 2, + itemsPerPage: 4, + itemsPerPageOptions: [4, 8, 12], + totalItems: 10, + isExtended: false, + pageNavIsPresent: true, + pageInputIsPresent: true, + itemsPerPageIsPresent: true + }; + hostFixture.detectChanges(); + + const pageNavElement: DebugElement = hostFixture.debugElement.query(By.css("ul")); + expect(pageNavElement).toBeDefined(); + expect(pageNavElement.nativeElement.innerHTML).toContain('
  • elements to "0" instead of "..." + const morePagesElement: DebugElement = hostFixture.debugElement.query(By.css("li[value='0']")); + morePagesElement.triggerEventHandler("click", {}); + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "1"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "1"); + })); + }); + + describe("on paginationConfig change", () => { + beforeEach(fakeAsync(() => { + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 10 }; + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + })); + + it("should change pageNumbers if totalItems has changed", () => { + const previousPageNumbersLength: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 13 }; + hostFixture.detectChanges(); + const currentPageNumbersElement: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + expect(currentPageNumbersElement).not.toEqual(previousPageNumbersLength); + }); + + it("should not change pageNumbers if totalItems has not changed", () => { + const previousPageNumbersLength: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + hostComponent.paginationConfig = { ...paginationConfig, totalItems: 10 }; + hostFixture.detectChanges(); + const currentPageNumbersElement: number = hostFixture.debugElement.queryAll(By.css("li.page-numbers")).length; + expect(currentPageNumbersElement).toEqual(previousPageNumbersLength); + }); + + it("should set current page to 1 when it is undefined in config", fakeAsync(() => { + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "2"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "2"); + + hostComponent.paginationConfig = { ...paginationConfig, page: undefined }; + hostFixture.detectChanges(); + tick(); // since values are set on ngModel asynchronously (see https://github.com/angular/angular/issues/22606) + + assertPageNavSelection(hostFixture.debugElement.childNodes[0], "1"); + assertPageInputSelection(hostFixture.debugElement.childNodes[0], "1"); + })); + }); +}); diff --git a/packages/stark-ui/src/modules/pagination/components/pagination.component.ts b/packages/stark-ui/src/modules/pagination/components/pagination.component.ts new file mode 100644 index 0000000000..35e4c3d104 --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/components/pagination.component.ts @@ -0,0 +1,430 @@ +"use strict"; + +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + HostBinding, + Inject, + Input, + OnChanges, + OnInit, + Output, + Renderer2, + SimpleChanges, + ViewEncapsulation +} from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkPaginationConfig } from "./pagination-config.intf"; +import { MatPaginator, MatPaginatorIntl, PageEvent } from "@angular/material/paginator"; + +const _isEqual: Function = require("lodash/isEqual"); + +const componentName: string = "stark-pagination"; + +export type StarkPaginationComponentMode = "compact"; + +export interface StarkPaginateEvent { + /** + * Current page after pagination + */ + page: number; + + /** + * Current number of items displayed per page + */ + itemsPerPage: number; +} + +/** + * Component to display pagination bar to be used with a collection of items. + * It extends the MatPaginator class from Angular Material so it can be integrated as well with the MatTable. + * {@link https://material.angular.io/components/paginator/api|MatPaginator} + */ +@Component({ + selector: "stark-pagination", + templateUrl: "./pagination.component.html", + encapsulation: ViewEncapsulation.None +}) +export class StarkPaginationComponent extends MatPaginator implements OnInit, OnChanges, AfterViewInit { + /** + * Adds class="stark-pagination" attribute on the host component + */ + @HostBinding("class") + public class: string = componentName; + + /** + * Suffix id given to items per page dropdown + * (items-per-page-) and pageSelector dropdown (page-selector-) + * Default: "pagination" + */ + @Input() + public htmlSuffixId?: string; + + /** + * Desired layout or flavour: + * - compact: Displayed in a compact mode. + * - default: basic implementation with everything + */ + @Input() + public mode?: StarkPaginationComponentMode; + + /** + * StarkPaginationConfig object containing main information for the pagination. + */ + @Input() + public paginationConfig: StarkPaginationConfig; + + /** + * Output event emitter that will emit the paginate event when the pagination changed. + */ + @Output() + public paginated: EventEmitter = new EventEmitter(); + + public get paginationInput(): number { + return this._paginationInput; + } + + public set paginationInput(newValue: number) { + // store the previous pagination input value in case the new one is not valid + // so it can be reverted to the previous value when that happens + if (this._paginationInput && (newValue > this.getTotalPages() || newValue === 0)) { + this.previousPaginationInput = this._paginationInput; + } + this._paginationInput = newValue; + } + + public _paginationInput: number; + public previousPaginationInput: number; + public previousPageIndex: number; + public pageNumbers: (string | number)[]; + + public constructor( + @Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService, + public element: ElementRef, + public renderer: Renderer2, + public cdRef: ChangeDetectorRef + ) { + // we don't use the MatPaginatorIntl service to translate the labels but it is needed for the MatPaginator base class + // see https://material.angular.io/components/paginator/api#services + super(new MatPaginatorIntl(), cdRef); + } + + /** + * Component lifecycle hook + */ + public ngOnInit(): void { + this.paginationConfig = this.normalizePaginationConfig(this.paginationConfig); + this.setMatPaginatorProperties(this.paginationConfig); + this.previousPageIndex = 0; + + this.htmlSuffixId = this.htmlSuffixId || "pagination"; + + this.setPageNumbers(); + + super.ngOnInit(); + this.logger.debug(componentName + ": controller initialized"); + } + + /** + * Component lifecycle hook + */ + public ngAfterViewInit(): void { + if (this.paginationConfig.isExtended) { + this.renderer.addClass(this.element.nativeElement, "extended-pagination"); + } + } + + /** + * Component lifecycle hook + */ + public ngOnChanges(changesObj: SimpleChanges): void { + if (changesObj["paginationConfig"]) { + // Set local variable to prevent shadow changes + const paginationConfigOriginalChange: StarkPaginationConfig = { ...this.paginationConfig }; + this.paginationConfig = this.normalizePaginationConfig(this.paginationConfig); + this.logger.debug(componentName + ": paginationConfig changed...", this.paginationConfig); + + // If normalization has changed the page or itemsPerPage, that means the paginationConfig is not the same in the pagination controller + // and in the parent controller. So pagination hast to trigger onPaginate callback to pass the new values. + if ( + typeof paginationConfigOriginalChange === "undefined" || + paginationConfigOriginalChange.page !== this.paginationConfig.page || + paginationConfigOriginalChange.itemsPerPage !== this.paginationConfig.itemsPerPage + ) { + this.onChangePagination(); + } else if ( + !_isEqual(paginationConfigOriginalChange, changesObj["paginationConfig"].previousValue) || + paginationConfigOriginalChange.totalItems !== this.paginationConfig.totalItems || + paginationConfigOriginalChange.itemsPerPageOptions !== this.paginationConfig.itemsPerPageOptions + ) { + this.setPageNumbers(); + } + this.paginationInput = this.paginationConfig.page; + } + } + + /** + * Creates a normalized paginationConfig to be used by this component. + * If the given config is undefined it will set totalItems only, otherwise it sets default values for the missing properties + */ + // FIXME: refactor this function to reduce its cognitive complexity + public normalizePaginationConfig(config: StarkPaginationConfig | undefined): StarkPaginationConfig { + let normalizedConfig: StarkPaginationConfig; + if (!config) { + // initialize paginationConfig to prevent errors in other functions depending on this config + normalizedConfig = { + totalItems: 0 + }; + this.logger.warn(componentName + ": No configuration defined. TotalItems set to 0 by default"); + } else { + normalizedConfig = { + itemsPerPageOptions: config.itemsPerPageOptions || [5, 10, 15], + itemsPerPage: config.itemsPerPage || (config.itemsPerPageOptions ? config.itemsPerPageOptions[0] : 5), + page: config.page || 1, + isExtended: config.isExtended !== undefined ? config.isExtended : false, + itemsPerPageIsPresent: config.itemsPerPageIsPresent !== undefined ? config.itemsPerPageIsPresent : true, + pageNavIsPresent: config.pageNavIsPresent !== undefined ? config.pageNavIsPresent : true, + pageInputIsPresent: config.pageInputIsPresent !== undefined ? config.pageInputIsPresent : true, + totalItems: config.totalItems !== undefined ? config.totalItems : 0 + }; + this.logger.debug(componentName + ": normalized pagination config: ", normalizedConfig); + } + + return normalizedConfig; + } + + /** + * Set the properties needed for the MatPaginator base class based on the given pagination configuration + * {@link https://material.angular.io/components/paginator/api#MatPaginator|MatPaginator API} + * @param config - The config object which be used to set the MatPaginator properties + */ + public setMatPaginatorProperties(config: StarkPaginationConfig): void { + // The set of provided page size options to display to the user. + this.pageSizeOptions = config.itemsPerPageOptions; + // Number of items to display on a page. By default set to 50. + this.pageSize = config.itemsPerPage; + // The zero-based page index of the displayed list of items. Defaulted to 0. + this.pageIndex = config.page - 1; // zero-based + // The length of the total number of items that are being paginated. Defaulted to 0. + this.length = config.totalItems; + } + + /** + * Check whether the given value is equal to zero (as number 0 or as string "0"). + */ + public isZero(numberToCheck: string | number): boolean { + return numberToCheck === 0 || numberToCheck === "0"; + } + + /** + * Check whether there is a page after the current one. + */ + public hasNext(): boolean { + return this.paginationConfig && this.paginationConfig.page < this.getTotalPages(); + } + + /** + * Check whether there is a page before the current one. + */ + public hasPrevious(): boolean { + return this.paginationConfig && this.paginationConfig.page > 1; + } + + /** + * Change page to first one. + */ + public goToFirst(): void { + if (this.hasPrevious()) { + this.goToPage(1); + } + } + + /** + * Change page to previous one. + */ + public goToPrevious(): void { + if (this.hasPrevious()) { + this.goToPage(this.paginationConfig.page - 1); + } + } + + /** + * Change page to next one. + */ + public goToNext(): void { + if (this.hasNext()) { + this.goToPage(this.paginationConfig.page + 1); + } + } + + /** + * Change page to last one. + */ + public goToLast(): void { + if (this.hasNext()) { + this.goToPage(this.getTotalPages()); + } + } + + /** + * Emit the stark paginate event and the MatPagination event. + * Then reload pageNumbers variable. + */ + public onChangePagination(): void { + if ( + this.paginationConfig && + // Check the types of page & itemsPerPage to be sure they are not undefined + typeof this.paginationConfig.page === "number" && + typeof this.paginationConfig.itemsPerPage === "number" + ) { + this.paginated.emit({ + page: this.paginationConfig.page, + itemsPerPage: this.paginationConfig.itemsPerPage + }); + + this.setMatPaginatorProperties(this.paginationConfig); + this.emitMatPaginationEvent(); + } + this.setPageNumbers(); + this.paginationInput = this.paginationConfig.page; + } + + /** + * Get total number of pages available based on itemsPerPage and totalItems. + */ + public getTotalPages(): number { + let calculatedTotalPages: number = 0; + if (this.paginationConfig) { + const itemsPerPage: number = this.isZero(this.paginationConfig.itemsPerPage) + ? 1 + : this.paginationConfig.itemsPerPage; + calculatedTotalPages = Math.ceil(this.paginationConfig.totalItems / itemsPerPage); + } + + if (calculatedTotalPages === 0) { + return 1; + } + return calculatedTotalPages; + } + + /** + * Set page to first then call onChangePagination function. + */ + public onChangeItemsPerPage(itemsPerPage: number): void { + this.paginationConfig.page = 1; + this.paginationConfig.itemsPerPage = itemsPerPage; + this.onChangePagination(); + } + + /** + * Set pageNumbers variable. + */ + // FIXME: refactor this function to reduce its cognitive complexity + public setPageNumbers(): void { + let min: number; + let max: number; + let i: number; + let j: number; + + const input: (string | number)[] = []; + + if (this.isCompactMode()) { + min = this.paginationConfig.page > 1 ? this.paginationConfig.page - 1 : 1; + max = min + 2; + + for (j = 0, i = min; i <= max && i <= this.getTotalPages(); i++, j++) { + input[j] = i; + } + } else { + // default mode: stark + min = 1; + max = this.getTotalPages(); + + if (max < 6) { + for (j = 0, i = min; i <= max; i++, j++) { + input[j] = i; + } + } else { + input[0] = min; + input[4] = max; + + if (this.paginationConfig.page === min + 2 || this.paginationConfig.page === min + 1) { + input[2] = min + 2; + } else if (this.paginationConfig.page === max - 2 || this.paginationConfig.page === max - 1) { + input[2] = max - 2; + } else if (this.paginationConfig.page === max || this.paginationConfig.page === min) { + input[2] = Math.ceil(max / 2); + } else { + input[2] = this.paginationConfig.page; + } + + if (input[2] - 1 === min + 1) { + input[1] = min + 1; + } else { + input[1] = "..."; + } + + if (input[2] + 1 === max - 1) { + input[3] = max - 1; + } else { + input[3] = "..."; + } + } + } + + this.pageNumbers = input; + } + + /** + * Change to the given page if it is different than "...". It calls onChangePagination afterwards. + */ + public goToPage(page: number | "..."): void { + if (page !== "...") { + this.previousPageIndex = this.paginationConfig.page; + this.paginationConfig.page = page; + this.onChangePagination(); + } + } + + public changePageOnEnter(): void { + const newPage: number = typeof this.paginationInput === "string" ? parseInt(this.paginationInput, 10) : this.paginationInput; + if (newPage <= this.getTotalPages() && newPage > 0) { + this.goToPage(newPage); + } else { + this.logger.warn(componentName + ": the page ", newPage, " does not exist"); + this.paginationInput = this.previousPaginationInput; // revert the pagination input value + } + } + + public getPageInputMaxDigits(): number { + return this.getTotalPages().toString().length; + } + + public isCompactMode(): boolean { + return typeof this.mode !== "undefined" && this.mode === "compact"; + } + + /** + * Emit the PageEvent according to the MatPaginator API + * {@link https://material.angular.io/components/paginator/api#PageEvent|MatPaginator PageEvent} + */ + public emitMatPaginationEvent(): void { + const pageEvent: PageEvent = { + pageIndex: this.pageIndex, + pageSize: this.pageSize, + length: this.length, + previousPageIndex: this.previousPageIndex + }; + this.page.emit(pageEvent); + } + + /** + * @ignore + */ + public trackPageNumberFn(_index: number): number { + return _index; + } +} diff --git a/packages/stark-ui/src/modules/pagination/pagination.module.ts b/packages/stark-ui/src/modules/pagination/pagination.module.ts new file mode 100644 index 0000000000..21b71c08dc --- /dev/null +++ b/packages/stark-ui/src/modules/pagination/pagination.module.ts @@ -0,0 +1,30 @@ +import { NgModule } from "@angular/core"; +import { FormsModule } from "@angular/forms"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { MatIconModule } from "@angular/material/icon"; +import { MatInputModule } from "@angular/material/input"; +import { MatButtonModule } from "@angular/material/button"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatPaginatorModule } from "@angular/material/paginator"; +import { StarkPaginationComponent } from "./components"; +import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; +import { StarkKeyboardDirectivesModule } from "../keyboard-directives/keyboard-directives.module"; +import { StarkDropdownModule } from "../dropdown/dropdown.module"; + +@NgModule({ + declarations: [StarkPaginationComponent], + exports: [StarkPaginationComponent], + imports: [ + BrowserAnimationsModule, + FormsModule, + MatButtonModule, + MatIconModule, + MatInputModule, + MatPaginatorModule, + MatTooltipModule, + StarkKeyboardDirectivesModule, + StarkSvgViewBoxModule, + StarkDropdownModule + ] +}) +export class StarkPaginationModule {} diff --git a/packages/stark-ui/src/modules/table/components/column.component.html b/packages/stark-ui/src/modules/table/components/column.component.html index 52c6118778..8e906f6078 100644 --- a/packages/stark-ui/src/modules/table/components/column.component.html +++ b/packages/stark-ui/src/modules/table/components/column.component.html @@ -1,5 +1,6 @@ +
    diff --git a/packages/stark-ui/src/modules/table/components/table.component.html b/packages/stark-ui/src/modules/table/components/table.component.html index 67d686a442..8d619dbe82 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.html +++ b/packages/stark-ui/src/modules/table/components/table.component.html @@ -3,22 +3,29 @@
    - +
    - - + +
    @@ -31,17 +38,27 @@ - + {{ context.displayedValue }} @@ -51,7 +68,8 @@ - + @@ -59,5 +77,8 @@
    - + - +
    - + +
    diff --git a/packages/stark-ui/src/modules/table/components/table.component.ts b/packages/stark-ui/src/modules/table/components/table.component.ts index b9bb419183..f0b32f4674 100644 --- a/packages/stark-ui/src/modules/table/components/table.component.ts +++ b/packages/stark-ui/src/modules/table/components/table.component.ts @@ -18,9 +18,9 @@ import { ViewEncapsulation } from "@angular/core"; import { MatDialog, MatDialogRef } from "@angular/material/dialog"; -import { MatPaginator } from "@angular/material/paginator"; import { MatColumnDef, MatTable, MatTableDataSource } from "@angular/material/table"; import { SelectionModel } from "@angular/cdk/collections"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; import { StarkTableColumnComponent, StarkTableColumnSortingDirection } from "./column.component"; import { StarkSortingRule, StarkTableMultisortDialogComponent, StarkTableMultisortDialogData } from "./dialogs/multisort.component"; @@ -28,7 +28,8 @@ import { StarkActionBarConfig } from "../../action-bar/components/action-bar-con import { StarkAction } from "../../action-bar/components/action.intf"; import { StarkTableColumnProperties } from "./column-properties.intf"; import { StarkTableFilter } from "./table-filter.intf"; -import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkPaginationConfig, StarkPaginationComponent } from "../../pagination/components"; +import { StarkPaginateEvent } from "../../pagination/components/pagination.component"; /** * Name of the component @@ -37,7 +38,7 @@ const componentName: string = "stark-table"; /* tslint:disable:enforce-component-selector */ @Component({ - selector: componentName, + selector: "stark-table", templateUrl: "./table.component.html", encapsulation: ViewEncapsulation.None }) @@ -47,7 +48,13 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI * Adds class="stark-table" attribute on the host component */ @HostBinding("class") - public class: string = "stark-table"; + public class: string = componentName; + + /** + * HTML id of the table + */ + @Input() + public htmlId: string; /** * Data that will be display inside your table. @@ -85,6 +92,12 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI @Input() public paginate: boolean = false; + /** + * + */ + @Input() + public paginationConfig: StarkPaginationConfig; + /** * Allows multiple row selection. Setting the attribute to "true" or empty will enable this feature. */ @@ -121,6 +134,20 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI @Output() public filterChanged: EventEmitter = new EventEmitter(); + /** + * Callback function to be called when the pagination changes. Two parameters + * will be passed to the callback function: + * -- page (number) + * -- itemsPerPage (number) + * + * When you declare it in html tags you have to declare it like 'on-paginate="yourFunction(page,itemsPerPage)"' + * If no callback function is passed, the data will be paginated automatically by the component. + * + * When set onPaginate, these attributes are required : totalItems + */ + @Output() + public paginationChanged: EventEmitter = new EventEmitter(); + /** * Reference to the MatTable embedded in this component */ @@ -130,8 +157,8 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI /** * Reference to the MatPaginator embedded in this component */ - @ViewChild(MatPaginator) - public paginator: MatPaginator; + @ViewChild(StarkPaginationComponent) + public starkPaginator: StarkPaginationComponent; /** * Columns added automatically by this component according to the columnProperties input @@ -284,7 +311,6 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI // using the internal prop from mat-table to get the custom column definitions (no other way for now) const oldColumns: Set = this.table["_customColumnDefs"]; oldColumns.forEach((oldColumn: MatColumnDef) => { - this.logger.debug("CCR==========> removing oldColumns value", oldColumn.name); this.table.removeColumnDef(oldColumn); // removing column also from the displayed columns (such array should match the dataSource!) this.displayedColumns.splice(this.displayedColumns.findIndex((column: string) => column === oldColumn.name), 1); @@ -337,7 +363,20 @@ export class StarkTableComponent implements OnInit, AfterContentInit, AfterViewI */ private initializeDataSource(): void { this.dataSource = new MatTableDataSource(this.data); - this.dataSource.paginator = this.paginator; + + // if there are observers subscribed to the StarkPagination event, it means that the developer will take care of the pagination + // so we just re-emit the event from the Stark Pagination component (online mode) + if (this.paginationChanged.observers.length > 0) { + this.starkPaginator.paginated.subscribe((paginateEvent: StarkPaginateEvent) => { + this.paginationChanged.emit(paginateEvent); + }); + } else { + // if there are no observers, then the data will be paginated internally in the MatTable via the Stark paginator event (offline mode) + this.dataSource.paginator = this.starkPaginator; + } + + this.starkPaginator.emitMatPaginationEvent(); + this.dataSource.filterPredicate = (rowData: any, globalFilter: string) => { const matchFilter: boolean[] = []; diff --git a/packages/stark-ui/src/modules/table/table.module.ts b/packages/stark-ui/src/modules/table/table.module.ts index b03d6d02dc..207291aea6 100644 --- a/packages/stark-ui/src/modules/table/table.module.ts +++ b/packages/stark-ui/src/modules/table/table.module.ts @@ -6,17 +6,16 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; import { MatDialogModule } from "@angular/material/dialog"; import { MatIconModule } from "@angular/material/icon"; import { MatInputModule } from "@angular/material/input"; -import { MatListModule } from "@angular/material/list"; import { MatMenuModule } from "@angular/material/menu"; -import { MatPaginatorModule } from "@angular/material/paginator"; import { MatSelectModule } from "@angular/material/select"; import { MatSortModule } from "@angular/material/sort"; import { MatTableModule } from "@angular/material/table"; import { MatTooltipModule } from "@angular/material/tooltip"; +import { TranslateModule } from "@ngx-translate/core"; import { StarkTableComponent, StarkTableColumnComponent } from "./components"; import { StarkTableMultisortDialogComponent } from "./components/dialogs/multisort.component"; -import { TranslateModule } from "@ngx-translate/core"; import { StarkActionBarModule } from "../action-bar/action-bar.module"; +import { StarkPaginationModule } from "../pagination/pagination.module"; import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; @NgModule({ @@ -31,15 +30,14 @@ import { StarkSvgViewBoxModule } from "../svg-view-box/svg-view-box.module"; MatDialogModule, MatIconModule, MatInputModule, - MatListModule, MatMenuModule, - MatPaginatorModule, MatSelectModule, MatSortModule, MatTableModule, MatTooltipModule, TranslateModule, StarkActionBarModule, + StarkPaginationModule, StarkSvgViewBoxModule ] }) diff --git a/showcase/src/app/app.component.html b/showcase/src/app/app.component.html index 5d527b12d5..e9cbd32a5d 100644 --- a/showcase/src/app/app.component.html +++ b/showcase/src/app/app.component.html @@ -46,6 +46,9 @@ Logout + + Pagination + Pretty Print @@ -115,11 +118,13 @@

    App Data

    -
    diff --git a/showcase/src/app/app.module.ts b/showcase/src/app/app.module.ts index b170a356d5..b745f20022 100644 --- a/showcase/src/app/app.module.ts +++ b/showcase/src/app/app.module.ts @@ -18,8 +18,8 @@ import { MatCheckboxModule } from "@angular/material/checkbox"; import { MatListModule } from "@angular/material/list"; import { MatSidenavModule } from "@angular/material/sidenav"; import { MatTooltipModule } from "@angular/material/tooltip"; -import { SharedModule } from "./shared/shared.module"; import { DateAdapter } from "@angular/material/core"; +import { SharedModule } from "./shared/shared.module"; import { STARK_APP_CONFIG, diff --git a/showcase/src/app/app.routes.ts b/showcase/src/app/app.routes.ts index d78a51282b..6c26d5ad47 100644 --- a/showcase/src/app/app.routes.ts +++ b/showcase/src/app/app.routes.ts @@ -6,6 +6,7 @@ import { DemoBreadcrumbComponent, DemoCardComponent, DemoColorsComponent, + DemoCollapsibleComponent, DemoSidebarComponent, DemoDropdownComponent, ExampleViewerComponent, @@ -13,11 +14,11 @@ import { KeyboardDirectivesComponent, DemoLanguageSelectorComponent, LogoutComponent, + DemoPaginationComponent, DemoPrettyPrintComponent, SliderComponent, + DemoTableComponent, DemoToastComponent, - TableComponent, - DemoCollapsibleComponent, DemoTypographyComponent } from "./demo"; import { HomeComponent } from "./home"; @@ -36,17 +37,18 @@ export const APP_STATES: Ng2StateDeclaration[] = [ { name: "demo-colors", url: "/demo/colors", component: DemoColorsComponent }, { name: "demo-date-picker", url: "/demo/date-picker", component: DatePickerComponent }, { name: "demo-date-range-picker", url: "/demo/date-range-picker", component: DateRangePickerComponent }, + { name: "demo-dropdown", url: "/demo/dropdown", component: DemoDropdownComponent }, { name: "stark-header", url: "/demo/stark-header", component: HeaderComponent }, { name: "demo-example-viewer", url: "/demo/example-viewer", component: ExampleViewerComponent }, { name: "demo-keyboard-directives", url: "/demo/keyboard-directives", component: KeyboardDirectivesComponent }, { name: "demo-language-selector", url: "/demo/language-selector", component: DemoLanguageSelectorComponent }, { name: "demo-logout", url: "/demo/logout", component: LogoutComponent }, + { name: "demo-pagination", url: "/demo/pagination", component: DemoPaginationComponent }, { name: "demo-pretty-print", url: "/demo/pretty-print", component: DemoPrettyPrintComponent }, { name: "demo-slider", url: "/demo/slider", component: SliderComponent }, { name: "demo-sidebar", url: "/demo/sidebar", component: DemoSidebarComponent }, - { name: "demo-table", url: "/demo/table", component: TableComponent }, + { name: "demo-table", url: "/demo/table", component: DemoTableComponent }, { name: "demo-toast", url: "/demo/toast", component: DemoToastComponent }, - { name: "demo-dropdown", url: "/demo/dropdown", component: DemoDropdownComponent }, { name: "demo-typography", url: "/demo/typography", component: DemoTypographyComponent }, { name: "otherwise", url: "/otherwise", component: NoContentComponent } ]; diff --git a/showcase/src/app/demo/demo.module.ts b/showcase/src/app/demo/demo.module.ts index 4e810a0cee..0859988627 100644 --- a/showcase/src/app/demo/demo.module.ts +++ b/showcase/src/app/demo/demo.module.ts @@ -1,19 +1,18 @@ -import { - MatButtonModule, - MatButtonToggleModule, - MatCardModule, - MatCheckboxModule, - MatDividerModule, - MatIconModule, - MatTabsModule, - MatTooltipModule, - MatSnackBarModule, - MatFormFieldModule, - MatInputModule -} from "@angular/material"; -import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; import { FormsModule } from "@angular/forms"; +import { MAT_DATE_FORMATS } from "@angular/material/core"; +import { MatCheckboxModule } from "@angular/material/checkbox"; +import { MatButtonModule } from "@angular/material/button"; +import { MatButtonToggleModule } from "@angular/material/button-toggle"; +import { MatCardModule } from "@angular/material/card"; +import { MatDividerModule } from "@angular/material/divider"; +import { MatIconModule } from "@angular/material/icon"; +import { MatTabsModule } from "@angular/material/tabs"; +import { MatTooltipModule } from "@angular/material/tooltip"; +import { MatSnackBarModule } from "@angular/material/snack-bar"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatInputModule } from "@angular/material/input"; import { TranslateModule } from "@ngx-translate/core"; import { ActionBarComponent } from "./action-bar/action-bar.component"; import { DemoBreadcrumbComponent } from "./breadcrumb/breadcrumb.component"; @@ -30,9 +29,10 @@ import { HeaderComponent } from "./header/header.component"; import { KeyboardDirectivesComponent } from "./keyboard-directives/keyboard-directives.component"; import { DemoLanguageSelectorComponent } from "./language-selector/demo-language-selector.component"; import { LogoutComponent } from "./logout/logout.component"; +import { DemoPaginationComponent } from "./pagination/demo-pagination.component"; import { DemoPrettyPrintComponent } from "./pretty-print/demo-pretty-print.component"; import { SliderComponent } from "./slider/slider.component"; -import { TableComponent } from "./table/table.component"; +import { DemoTableComponent } from "./table/demo-table.component"; import { DemoTypographyComponent } from "./typography/demo-typography.component"; import { DemoToastComponent } from "./toast/demo-toast-notification.component"; import { SharedModule } from "../shared/shared.module"; @@ -46,13 +46,13 @@ import { StarkDropdownModule, StarkKeyboardDirectivesModule, StarkLanguageSelectorModule, + StarkPaginationModule, StarkPrettyPrintModule, StarkSliderModule, StarkSvgViewBoxModule, StarkTableModule, StarkCollapsibleModule } from "@nationalbankbelgium/stark-ui"; -import { MAT_DATE_FORMATS } from "@angular/material/core"; @NgModule({ imports: [ @@ -76,6 +76,7 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; StarkDropdownModule, StarkKeyboardDirectivesModule, StarkLanguageSelectorModule, + StarkPaginationModule, StarkPrettyPrintModule, StarkDatePickerModule, StarkDateRangePickerModule, @@ -101,6 +102,7 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; KeyboardDirectivesComponent, DemoLanguageSelectorComponent, LogoutComponent, + DemoPaginationComponent, DemoPrettyPrintComponent, SliderComponent, DemoToastComponent, @@ -109,7 +111,7 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; DemoSidebarComponent, ExampleViewerComponent, KeyboardDirectivesComponent, - TableComponent + DemoTableComponent ], exports: [ ActionBarComponent, @@ -127,9 +129,10 @@ import { MAT_DATE_FORMATS } from "@angular/material/core"; KeyboardDirectivesComponent, DemoLanguageSelectorComponent, LogoutComponent, + DemoPaginationComponent, DemoPrettyPrintComponent, SliderComponent, - TableComponent, + DemoTableComponent, DemoToastComponent ], providers: [{ provide: MAT_DATE_FORMATS, useValue: STARK_DATE_FORMATS }] diff --git a/showcase/src/app/demo/index.ts b/showcase/src/app/demo/index.ts index 1e9f1cbe62..b3b1d77dc7 100644 --- a/showcase/src/app/demo/index.ts +++ b/showcase/src/app/demo/index.ts @@ -6,16 +6,17 @@ export * from "./colors"; export * from "./card"; export * from "./date-picker"; export * from "./date-range-picker"; -export * from "./sidebar"; export * from "./dropdown"; export * from "./example-viewer"; export * from "./header"; export * from "./keyboard-directives"; export * from "./language-selector"; +export * from "./logout"; +export * from "./pagination"; export * from "./pretty-print"; +export * from "./sidebar"; export * from "./slider"; export * from "./table"; export * from "./typography"; export * from "./toast"; export * from "./demo.module"; -export * from "./logout"; diff --git a/showcase/src/app/demo/pagination/demo-pagination.component.html b/showcase/src/app/demo/pagination/demo-pagination.component.html new file mode 100644 index 0000000000..e194ed3b20 --- /dev/null +++ b/showcase/src/app/demo/pagination/demo-pagination.component.html @@ -0,0 +1,45 @@ +

    SHOWCASE.DEMO.PAGINATION.TITLE

    +
    + + + +
    +

    {{ 'SHOWCASE.DEMO.PAGINATION.EMITTED_PAGINATE_EVENT' | translate }}:

    + +
    +
    +
    + +
    + + + +
    +

    {{ 'SHOWCASE.DEMO.PAGINATION.EMITTED_PAGINATE_EVENT' | translate }}:

    + +
    +
    +
    + +
    + + + +
    +

    {{ 'SHOWCASE.DEMO.PAGINATION.EMITTED_PAGINATE_EVENT' | translate }}:

    + +
    +
    +
    + +
    + + + +
    +

    {{ 'SHOWCASE.DEMO.PAGINATION.EMITTED_PAGINATE_EVENT' | translate }}:

    + +
    +
    +
    diff --git a/showcase/src/app/demo/pagination/demo-pagination.component.scss b/showcase/src/app/demo/pagination/demo-pagination.component.scss new file mode 100644 index 0000000000..d246cccf51 --- /dev/null +++ b/showcase/src/app/demo/pagination/demo-pagination.component.scss @@ -0,0 +1,5 @@ +pre code { + display: block; + height: 30px; + background-color: #cfcfcf; +} diff --git a/showcase/src/app/demo/pagination/demo-pagination.component.ts b/showcase/src/app/demo/pagination/demo-pagination.component.ts new file mode 100644 index 0000000000..8f159778b2 --- /dev/null +++ b/showcase/src/app/demo/pagination/demo-pagination.component.ts @@ -0,0 +1,72 @@ +import { Component, Inject, OnInit } from "@angular/core"; +import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; +import { StarkPaginateEvent, StarkPaginationConfig } from "@nationalbankbelgium/stark-ui"; + +@Component({ + selector: "demo-pagination", + templateUrl: "./demo-pagination.component.html", + styleUrls: ["./demo-pagination.component.scss"] +}) +export class DemoPaginationComponent implements OnInit { + public paginationSimpleConfig: StarkPaginationConfig; + public paginationExtendedConfig: StarkPaginationConfig; + public paginationAdvancedConfig: StarkPaginationConfig; + public paginationCompactConfig: StarkPaginationConfig; + public paginateEventSimple: string; + public paginateEventExtended: string; + public paginateEventAdvanced: string; + public paginateEventCompact: string; + + public constructor(@Inject(STARK_LOGGING_SERVICE) public logger: StarkLoggingService) {} + + public ngOnInit(): void { + this.paginationSimpleConfig = { + totalItems: 20, + page: 1, + itemsPerPage: 10, + itemsPerPageOptions: [2, 4, 6, 8, 10, 20] + }; + + this.paginationExtendedConfig = { + totalItems: 20, + page: 1, + itemsPerPage: 2, + itemsPerPageOptions: [2, 4, 6, 8, 10, 20], + isExtended: true + }; + + this.paginationAdvancedConfig = { + totalItems: 20, + page: 1, + itemsPerPage: 4, + itemsPerPageOptions: [2, 4, 6, 8, 10, 20], + itemsPerPageIsPresent: true, + pageInputIsPresent: false, + pageNavIsPresent: true + }; + + this.paginationCompactConfig = { + totalItems: 20, + page: 1, + itemsPerPage: 4, + itemsPerPageOptions: [2, 4, 6, 8, 10, 20] + }; + } + + public onPaginationChange(paginateEvent: StarkPaginateEvent, config: "simple" | "extended" | "advanced" | "compact"): void { + switch (config) { + case "extended": + this.paginateEventExtended = JSON.stringify(paginateEvent); + break; + case "advanced": + this.paginateEventAdvanced = JSON.stringify(paginateEvent); + break; + case "compact": + this.paginateEventCompact = JSON.stringify(paginateEvent); + break; + default: + this.paginateEventSimple = JSON.stringify(paginateEvent); + break; + } + } +} diff --git a/showcase/src/app/demo/pagination/index.ts b/showcase/src/app/demo/pagination/index.ts new file mode 100644 index 0000000000..1ec57bad84 --- /dev/null +++ b/showcase/src/app/demo/pagination/index.ts @@ -0,0 +1 @@ +export * from "./demo-pagination.component"; diff --git a/showcase/src/app/demo/table/demo-table.component.html b/showcase/src/app/demo/table/demo-table.component.html new file mode 100644 index 0000000000..66964907a6 --- /dev/null +++ b/showcase/src/app/demo/table/demo-table.component.html @@ -0,0 +1,49 @@ + + +

    Table with regular action bar

    +
    +
    + + + +

    Table with alternative action bar

    +
    +
    + + + +
    +
    +

    Table with transcluded action bar

    + +
    +
    +
    +
    diff --git a/showcase/src/app/demo/table/table.component.scss b/showcase/src/app/demo/table/demo-table.component.scss similarity index 100% rename from showcase/src/app/demo/table/table.component.scss rename to showcase/src/app/demo/table/demo-table.component.scss diff --git a/showcase/src/app/demo/table/table.component.ts b/showcase/src/app/demo/table/demo-table.component.ts similarity index 85% rename from showcase/src/app/demo/table/table.component.ts rename to showcase/src/app/demo/table/demo-table.component.ts index 6e2f6a4343..54a9fba492 100644 --- a/showcase/src/app/demo/table/table.component.ts +++ b/showcase/src/app/demo/table/demo-table.component.ts @@ -1,14 +1,20 @@ import { Component, Inject, OnInit, ViewEncapsulation } from "@angular/core"; -import { StarkActionBarConfig, StarkTableColumnProperties, StarkTableFilter, StarkAction } from "@nationalbankbelgium/stark-ui"; +import { + StarkActionBarConfig, + StarkPaginationConfig, + StarkTableColumnProperties, + StarkTableFilter, + StarkAction +} from "@nationalbankbelgium/stark-ui"; import { STARK_LOGGING_SERVICE, StarkLoggingService } from "@nationalbankbelgium/stark-core"; @Component({ - selector: "showcase-demo-table", - styleUrls: ["./table.component.scss"], - templateUrl: "./table.component.html", + selector: "demo-table", + styleUrls: ["./demo-table.component.scss"], + templateUrl: "./demo-table.component.html", encapsulation: ViewEncapsulation.None //Here to add a shadow inside the table, we will fix that when we take care of #509 }) -export class TableComponent implements OnInit { +export class DemoTableComponent implements OnInit { public getTitle = (data: any): string => { return "~" + data.title.label; }; @@ -27,6 +33,9 @@ export class TableComponent implements OnInit { public columnsProperties: StarkTableColumnProperties[]; public customTableActions: StarkAction[]; public tableRowsActionBarConfig: StarkActionBarConfig; + public paginationConfig1: StarkPaginationConfig; + public paginationConfig2: StarkPaginationConfig; + public paginationConfig3: StarkPaginationConfig; public columns: any[]; public orderProperties: string[]; public filter: StarkTableFilter; @@ -175,6 +184,15 @@ export class TableComponent implements OnInit { columns: [] }; + this.paginationConfig1 = { + totalItems: this.dummyData.length, + page: 1, + itemsPerPage: 10, + itemsPerPageOptions: [10, 12, 15, 18, 20, 25, 50, 100] + }; + this.paginationConfig2 = { ...this.paginationConfig1, itemsPerPage: 4, itemsPerPageOptions: [2, 4, 6, 8, 10] }; + this.paginationConfig3 = { ...this.paginationConfig1, itemsPerPage: 2, itemsPerPageOptions: [2, 4, 6, 8, 10], isExtended: true }; + this.tableRowsActionBarConfig = { actions: [ { diff --git a/showcase/src/app/demo/table/index.ts b/showcase/src/app/demo/table/index.ts index 4f364c859f..5f5ca4a13e 100644 --- a/showcase/src/app/demo/table/index.ts +++ b/showcase/src/app/demo/table/index.ts @@ -1 +1 @@ -export * from "./table.component"; +export * from "./demo-table.component"; diff --git a/showcase/src/app/demo/table/table.component.html b/showcase/src/app/demo/table/table.component.html index e376850ad5..9327cd835e 100644 --- a/showcase/src/app/demo/table/table.component.html +++ b/showcase/src/app/demo/table/table.component.html @@ -3,30 +3,36 @@

    SHOWCASE.DEMO.TABLE.TITLE

    SHOWCASE.DEMO.SHARED.EXAMPLE_VIEWER_LIST

    -
    -

    Table with regular action bar

    -
    + [filter]="filter" [multiselect]="true" multiSort [orderProperties]="orderProperties" + [tableRowsActionBarConfig]="tableRowsActionBarConfig"> +

    Table with regular action bar

    - -
    -

    Table with alternative action bar

    -
    + +

    Table with alternative action bar

    + multiSort [orderProperties]="orderProperties" + [tableRowsActionBarConfig]="tableRowsActionBarConfig">

    Table with transcluded action bar

    - +
    diff --git a/showcase/src/assets/translations/en.json b/showcase/src/assets/translations/en.json index 73acf0e6ec..36345bacbd 100644 --- a/showcase/src/assets/translations/en.json +++ b/showcase/src/assets/translations/en.json @@ -142,6 +142,14 @@ "LOGOUT_CUSTOM_ICON": "Logout button - Custom icon", "TITLE": "Stark logout" }, + "PAGINATION": { + "ADVANCED_CONFIGURATION": "Pagination with advanced configuration", + "COMPACT_CONFIGURATION": "Pagination in compact mode", + "EMITTED_PAGINATE_EVENT": "Emitted paginate event", + "EXTENDED_CONFIGURATION": "Pagination with extended page selector", + "SIMPLE_CONFIGURATION": "Pagination with simple configuration", + "TITLE": "Stark Pagination" + }, "PRETTY_PRINT": { "CSS": "Pretty-Print CSS", "ENABLE_HIGHLIGHTING": "Enable highlighting", diff --git a/showcase/src/assets/translations/fr.json b/showcase/src/assets/translations/fr.json index 9df8d53d86..0d7822b861 100644 --- a/showcase/src/assets/translations/fr.json +++ b/showcase/src/assets/translations/fr.json @@ -141,6 +141,14 @@ "LOGOUT_CUSTOM_ICON": "Bouton logout - IcĂ´ne custom", "TITLE": "Stark logout" }, + "PAGINATION": { + "ADVANCED_CONFIGURATION": "Pagination with advanced configuration", + "COMPACT_CONFIGURATION": "Pagination in compact mode", + "EMITTED_PAGINATE_EVENT": "Emitted paginate event", + "EXTENDED_CONFIGURATION": "Pagination with extended page selector", + "SIMPLE_CONFIGURATION": "Pagination with simple configuration", + "TITLE": "Stark Pagination" + }, "PRETTY_PRINT": { "CSS": "Pretty-Print CSS", "ENABLE_HIGHLIGHTING": "Mettre en surbrillance", diff --git a/showcase/src/assets/translations/nl.json b/showcase/src/assets/translations/nl.json index 8cde159ec1..869ffe8bc3 100644 --- a/showcase/src/assets/translations/nl.json +++ b/showcase/src/assets/translations/nl.json @@ -142,6 +142,14 @@ "LOGOUT_CUSTOM_ICON": "Logout-knop - Aangepast pictogram", "TITLE": "Stark logout" }, + "PAGINATION": { + "ADVANCED_CONFIGURATION": "Pagination met geavanceerde configuratie", + "COMPACT_CONFIGURATION": "Pagination in compacte modus", + "EMITTED_PAGINATE_EVENT": "Verzonden Paginate event", + "EXTENDED_CONFIGURATION": "Pagination met uitgebreide paginakiezer", + "SIMPLE_CONFIGURATION": "Pagination met eenvoudige configuratie", + "TITLE": "Stark Pagination" + }, "PRETTY_PRINT": { "CSS": "Pretty-Print CSS", "ENABLE_HIGHLIGHTING": "Highlighting activeren", diff --git a/showcase/src/styles/_stark-styles.scss b/showcase/src/styles/_stark-styles.scss index 9bb9af9768..003f018e84 100644 --- a/showcase/src/styles/_stark-styles.scss +++ b/showcase/src/styles/_stark-styles.scss @@ -17,6 +17,8 @@ IMPORTANT: Stark styles are provided as SCSS styles so they should be imported i @import "~@nationalbankbelgium/stark-ui/src/modules/date-range-picker/components/date-range-picker.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/language-selector/components/language-selector.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/slider/components/slider-theme"; +@import "~@nationalbankbelgium/stark-ui/src/modules/pagination/components/pagination.component"; +@import "~@nationalbankbelgium/stark-ui/src/modules/pagination/components/pagination-theme"; @import "~@nationalbankbelgium/stark-ui/src/modules/pretty-print/components/pretty-print.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/table/components/table.component"; @import "~@nationalbankbelgium/stark-ui/src/modules/table/components/dialogs/multisort.component";