Pagination

    Hinweis

    Noch nicht public

    Die Pagination wurde voerst nur für das Projekt "Der Fährmann" umgesetzt. Der ViewHelper und die dafür benötigte Erweiterung (PHP) sind aber schon im Core.
    Es waren noch Fragen offen, z. B. ob man 1 oder gleich 2-3 partials machen und anbieten sollte oder doch lieber mit einem Render ViewHelper, wie und ob man das Routing dynamisch macht etc. ...

    Setup

    Pagination ViewHelper bh:pagination ist bereits im Core:
    src/repository/bh/Classes/ViewHelpers/PaginationViewHelper.php

    Folgende Erweiterung für die verbesserte Pagination (wird mit TYPO3 12 released) ist auch schon im Core:
    src/repository/bh/Classes/Pagination/SlidingWindowPagination.php

    Folgendes muss momentan für eine funktionierende Pagination gemacht werden:

    1. Config (Routing)

    Folgender Code muss in die config.yaml unter routeEnhancers eingefügt werden:

    JSON
    routeEnhancers: pagination: type: Simple limitToPages: - 11 - 31 routePath: "/{page}" defaults: page: "1" requirements: page: "[0-9]{1,5}" _arguments: page: currentPage

    Unter limitToPages kann und sollte man die Pagination auf mind. eine Seite beschränken.
    * wird in Zukunft wahrscheinlich dynamisch oder anders gemacht...

    2. HTML

    Verwendung des bh:pagination ViewHelpers für coo_news items inkl. HTML-Struktur für die eigentliche Sliding Pagination:

    HTML
    {namespace bh=TYPO3\Bh\ViewHelpers} {namespace items=TYPO3\CooNews\ViewHelpers} <bh:tmpl.element object="{cObj}"> <items:list type="{cObj.allSettings.filter.type}" filter="{cObj.allSettings.filter}" as="items"> <!-- pagination --> <bh:pagination items="{items}" itemsPerPage="20" maxNumberOfLinks="4" as="paginationItems"> <!-- rendered items --> <section class="news-list-items-wrapper bh-gap-normal"> <f:for each="{paginationItems}" as="item"> <f:render partial="../partials/el-news-item" arguments="{_all}" /> </f:for> </section> <!-- pagination nav & links --> <f:if condition="{pagination.displayRangeStart} != {pagination.displayRangeEnd}"> <nav class="bh-pagination-wrapper" aria-label="Pagination"> <ul class="bh-pagination"> <li class="bh-pagination__item bh-pagination__item--jump bh-pagination__item--jump-first {f:if(condition: '!{pagination.hasLessPages}', then: 'bh-pagination__item--inactive')} {f:if(condition: '{pagination.paginator.numberOfPages} <= {pagination.maximumNumberOfLinks}', then: 'bh-pagination__item--disabled')}"> <f:link.page class="bh-pagination__link" additionalParams="{page:pagination.firstPageNumber}" rel="first"> <span class="bh-pagination__link-icon bh-font-skip-back" aria-hidden="true"></span> <span class="bh-pagination__link-text"> <f:translate key="pagination-first-page" extensionName="bh" /> </span> </f:link.page> </li> <li class="bh-pagination__item bh-pagination__item--navigate bh-pagination__item--navigate-prev {f:if(condition: '{pagination.paginator.currentPageNumber} == {pagination.firstPageNumber}', then: 'bh-pagination__item--inactive')}"> <f:link.page class="bh-pagination__link" additionalParams="{page:pagination.previousPageNumber}" rel="prev"> <span class="bh-pagination__link-icon bh-font-arrow-simple-left" aria-hidden="true"></span> <span class="bh-pagination__link-text"> <f:translate key="pagination-previous-page" extensionName="bh" /> </span> </f:link.page> </li> <li class="bh-pagination__item-wrapper"> <ul class="bh-pagination-inner"> <f:if condition="{pagination.hasLessPages}"> <li class="bh-pagination__item bh-pagination__item--slide" aria-hidden="true"> <span class="bh-pagination__link">...</span> </li> </f:if> <f:for each="{pagination.allPageNumbers}" as="pageNumber"> <li class="bh-pagination__item bh-pagination__item--number {f:if(condition: '{pageNumber} == {pagination.paginator.currentPageNumber}', then: 'bh-pagination__item--active')}"> <f:link.page class="bh-pagination__link" additionalParams="{page:pageNumber}" aria="{f:if(condition: '{pageNumber} == {pagination.paginator.currentPageNumber}', then: '{current: \'page\'}')}"> <span class="bh-pagination__link-text">{pageNumber}</span> </f:link.page> </li> </f:for> <f:if condition="{pagination.hasMorePages}"> <li class="bh-pagination__item bh-pagination__item--slide" aria-hidden="true"> <span class="bh-pagination__link">...</span> </li> </f:if> </ul> </li> <li class="bh-pagination__item bh-pagination__item--navigate bh-pagination__item--navigate-next {f:if(condition: '{pagination.paginator.currentPageNumber} == {pagination.lastPageNumber}', then: 'bh-pagination__item--inactive')}"> <f:link.page class="bh-pagination__link" additionalParams="{page:pagination.nextPageNumber}" rel="next"> <span class="bh-pagination__link-text"> <f:translate key="pagination-next-page" extensionName="bh" /> </span> <span class="bh-pagination__link-icon bh-font-arrow-simple-right" aria-hidden="true"></span> </f:link.page> </li> <li class="bh-pagination__item bh-pagination__item--jump bh-pagination__item--jump-last {f:if(condition: '!{pagination.hasMorePages}', then: 'bh-pagination__item--inactive')} {f:if(condition: '{pagination.paginator.numberOfPages} <= {pagination.maximumNumberOfLinks}', then: 'bh-pagination__item--disabled')}"> <f:link.page class="bh-pagination__link" additionalParams="{page:pagination.lastPageNumber}" rel="last"> <span class="bh-pagination__link-text"> <f:translate key="pagination-last-page" extensionName="bh" /> </span> <span class="bh-pagination__link-icon bh-font-skip-forward" aria-hidden="true"></span> </f:link.page> </li> </ul> </nav> </f:if> </bh:pagination> </items:list> </bh:tmpl.element>

    3. Styling (CSS)

    minimales Styling:

    CSS
    .bh-pagination-wrapper { display: flex; justify-content: center; } .bh-pagination, .bh-pagination-inner { display: flex; margin: 0; padding: 0; list-style: none; } .bh-pagination__item--jump.bh-pagination__item--inactive, .bh-pagination__item--navigate.bh-pagination__item--inactive { opacity: 0.5; pointer-events: none; } .bh-pagination__item--jump.bh-pagination__item--disabled { display: none; } .bh-pagination__link { display: flex; align-items: center; padding: 0.6rem 1rem; text-align: center; } .bh-pagination__item--slide .bh-pagination__link { pointer-events: none; } .bh-pagination__link-text { line-height: 1; } @media (max-width: 990px) { /* screen-reader only - see .bh-visually-hidden in design.css */ .bh-pagination__item--jump .bh-pagination__link-text, .bh-pagination__item--navigate .bh-pagination__link-text { overflow: hidden; position: absolute; margin: -1px; border: 0; padding: 0; width: 1px; height: 1px; -webkit-clip-path: inset(50%); clip-path: inset(50%); white-space: nowrap; } }

    projekt-spezifisches Styling für "Der Fährmann":

    CSS
    .news-list-wrapper .bh-pagination-wrapper { margin-top: var(--margin-normal); } .news-list-wrapper .bh-pagination, .news-list-wrapper .bh-pagination-inner { gap: 1rem; } .news-list-wrapper .bh-pagination__item-wrapper { display: flex; align-items: center; } .news-list-wrapper .bh-pagination__link { font-weight: var(--font-weight-main); font-size: 1.3rem; line-height: 1.3; color: var(--font-color-main); } .news-list-wrapper .bh-pagination__item--number .bh-pagination__link { border-bottom: var(--border-main); font-weight: var(--font-weight-highlight); font-size: 1.6rem; font-feature-settings: 'salt' on; transition: border var(--transition-main); } .news-list-wrapper .bh-pagination__item--active .bh-pagination__link { border-color: var(--background-light); color: var(--font-color-highlight); background-color: var(--background-light); } .news-list-wrapper .bh-pagination__item--number .bh-pagination__link:hover, .news-list-wrapper .bh-pagination__item--number .bh-pagination__link:focus-visible { border-color: currentcolor; } .news-list-wrapper .bh-pagination__item--jump .bh-pagination__link, .news-list-wrapper .bh-pagination__item--navigate .bh-pagination__link { justify-content: center; padding: 0; width: 4rem; height: 8rem; color: var(--font-color-light); background-color: var(--color-highlight); transition: background var(--transition-main); } .news-list-wrapper .bh-pagination__item--jump .bh-pagination__link:hover, .news-list-wrapper .bh-pagination__item--jump .bh-pagination__link:focus-visible, .news-list-wrapper .bh-pagination__item--navigate .bh-pagination__link:hover, .news-list-wrapper .bh-pagination__item--navigate .bh-pagination__link:focus-visible { background-color: rgba(var(--color-green-dark-rgb), 0.88); } .news-list-wrapper .bh-pagination__item--jump .bh-pagination__link-text, .news-list-wrapper .bh-pagination__item--navigate .bh-pagination__link-text { /* screen-reader only - see .bh-visually-hidden in design.css */ overflow: hidden; position: absolute; margin: -1px; border: 0; padding: 0; width: 1px; height: 1px; -webkit-clip-path: inset(50%); clip-path: inset(50%); white-space: nowrap; } .news-list-wrapper .bh-pagination__link-icon { font-size: var(--icon-size-main); } @media (max-width: 767.98px) { .news-list-wrapper .bh-pagination, .news-list-wrapper .bh-pagination-inner { gap: 0.6rem; } } @media (max-width: 575.98px) { .news-list-wrapper .bh-pagination__link { padding: 0.6rem; } .news-list-wrapper .bh-pagination__item--jump .bh-pagination__link, .news-list-wrapper .bh-pagination__item--navigate .bh-pagination__link { width: 3rem; height: 6rem; } }

    Ergebnis