From dec0d4dc4e872c147bd714f2a78688356a4d3b2f Mon Sep 17 00:00:00 2001 From: Vladislav Tasev Date: Mon, 6 Apr 2020 14:39:00 +0300 Subject: [PATCH] feat(ui5-carousel): Allow different number of items per page based on component width (#1434) --- packages/main/src/Carousel.hbs | 2 +- packages/main/src/Carousel.js | 79 ++++++++++++-- packages/main/test/pages/Carousel.html | 141 ++++++++++++++++++++++++- 3 files changed, 210 insertions(+), 12 deletions(-) diff --git a/packages/main/src/Carousel.hbs b/packages/main/src/Carousel.hbs index cfe754b34ccc..07a08152073e 100644 --- a/packages/main/src/Carousel.hbs +++ b/packages/main/src/Carousel.hbs @@ -56,7 +56,7 @@ > {{/each}} {{else}} - {{currenlySelectedIndexToShow}} {{ofText}} {{pages.length}} + {{selectedIndexToShow}} {{ofText}} {{pages.length}} {{/if}} diff --git a/packages/main/src/Carousel.js b/packages/main/src/Carousel.js index 9681bf665fbd..e8889ae761b8 100644 --- a/packages/main/src/Carousel.js +++ b/packages/main/src/Carousel.js @@ -12,6 +12,7 @@ import { getI18nBundle, } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import ScrollEnablement from "@ui5/webcomponents-base/dist/delegate/ScrollEnablement.js"; +import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js"; import AnimationMode from "@ui5/webcomponents-base/dist/types/AnimationMode.js"; import { getAnimationMode } from "@ui5/webcomponents-base/dist/config/AnimationMode.js"; @@ -40,17 +41,39 @@ const metadata = { * @defaultvalue false * @public */ - cycling: { + cyclic: { type: Boolean, }, /** - * Sets the amount of items per page. If this property is set, on mobile devices it will always fallback to 1. + * Sets the number of items per page on small size (up to 640px). One item per page shown by default. * @type {Integer} * @defaultvalue 1 * @public */ - itemsPerPage: { + itemsPerPageS: { + type: Integer, + defaultValue: 1, + }, + + /** + * Sets the number of items per page on medium size (from 640px to 1024px). One item per page shown by default. + * @type {Integer} + * @defaultvalue 1 + * @public + */ + itemsPerPageM: { + type: Integer, + defaultValue: 1, + }, + + /** + * Sets the number of items per page on large size (more than 1024px). One item per page shown by default. + * @type {Integer} + * @defaultvalue 1 + * @public + */ + itemsPerPageL: { type: Integer, defaultValue: 1, }, @@ -96,6 +119,14 @@ const metadata = { type: CarouselArrowsPlacement, defaultValue: CarouselArrowsPlacement.Content, }, + + /** + * Defines the carousel width in pixels + * @private + */ + _width: { + type: Integer, + }, }, managedSlots: true, slots: /** @lends sap.ui.webcomponents.main.Carousel.prototype */ { @@ -177,12 +208,38 @@ class Carousel extends UI5Element { }); this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + this._onResizeBound = this._onResize.bind(this); } onAfterRendering() { this._scrollEnablement.scrollContainer = this.getDomRef(); } + onEnterDOM() { + ResizeHandler.register(this, this._onResizeBound); + } + + onExitDOM() { + ResizeHandler.deregister(this, this._onResizeBound); + } + + _onResize() { + const oldItemsPerPage = this.effectiveItemsPerPage; + + // Change transitively effectiveItemsPerPage by modifying _width + this._width = this.offsetWidth; + + // Items per page did not change, therefore page index does not need to be re-adjusted + if (this.effectiveItemsPerPage === oldItemsPerPage) { + return; + } + + // Whenever the number of items per page changes, the selected index needs to be re-adjusted so that the items + // that were visible before, can be visible as much as possible afterwards. + const adjustment = oldItemsPerPage / this.effectiveItemsPerPage; + this.selectedIndex = Math.round(this.selectedIndex * adjustment); + } + _updateScrolling(event) { if (!event) { return; @@ -209,7 +266,7 @@ class Carousel extends UI5Element { navigateLeft() { if (this.selectedIndex - 1 < 0) { - if (this.cycling) { + if (this.cyclic) { this.selectedIndex = this.pages.length - 1; } } else { @@ -219,7 +276,7 @@ class Carousel extends UI5Element { navigateRight() { if (this.selectedIndex + 1 > this.pages.length - 1) { - if (this.cycling) { + if (this.cyclic) { this.selectedIndex = 0; } } else { @@ -261,7 +318,15 @@ class Carousel extends UI5Element { } get effectiveItemsPerPage() { - return isDesktop() ? this.itemsPerPage : 1; + if (this._width <= 640) { + return this.itemsPerPageS; + } + + if (this._width <= 1024) { + return this.itemsPerPageM; + } + + return this.itemsPerPageL; } get styles() { @@ -316,7 +381,7 @@ class Carousel extends UI5Element { return this.i18nBundle.getText(CAROUSEL_OF_TEXT); } - get currenlySelectedIndexToShow() { + get selectedIndexToShow() { return this.selectedIndex + 1; } diff --git a/packages/main/test/pages/Carousel.html b/packages/main/test/pages/Carousel.html index 1090c2ca3910..f3040c3c52ba 100644 --- a/packages/main/test/pages/Carousel.html +++ b/packages/main/test/pages/Carousel.html @@ -25,7 +25,7 @@ } - + - + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + Marketing plans + + + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + Template Based Segmentation + Segmentation Models + + + + + + Template Based Segmentation + Segmentation Models + + + + + + + + Button 1 Button 2 Button 3 @@ -215,7 +348,7 @@ - + Button 1 Button 2 Button 3 @@ -229,7 +362,7 @@ Carousel with one page The arrows and dots are not displayed - + Button 1 Button 2 Button 3