Skip to content

Commit

Permalink
fix #994 ScrollingPagination performance for large number of pages
Browse files Browse the repository at this point in the history
  • Loading branch information
vegegoku committed Jan 5, 2025
1 parent 7ffed09 commit 503fe12
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 1,349 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import elemental2.dom.EventListener;
import elemental2.dom.HTMLElement;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;
import org.dominokit.domino.ui.forms.suggest.Select;
import org.dominokit.domino.ui.forms.suggest.SelectOption;
Expand All @@ -47,6 +49,7 @@ public class AdvancedPagination extends BasePagination<AdvancedPagination> {

private Select<Integer> pagesSelect;
private PagerNavItem totalPagesCount;
private List<PagerNavItem> allPages = new LinkedList<>();

/**
* Creates a new instance of {@link AdvancedPagination} with default settings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ public abstract class BasePagination<T extends BasePagination<T>>
protected NavElement pager;
protected UListElement pagesList;
protected PagerNavItem activePage;
protected List<PagerNavItem> allPages = new LinkedList<>();

private final Set<ChangeListener<? super Integer>> pageChangeListeners = new HashSet<>();
private boolean changeListenersPaused = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
package org.dominokit.domino.ui.pagination;

import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.utils.Domino.*;
import static org.dominokit.domino.ui.style.SpacingCss.dui_text_ellipsis;
import static org.dominokit.domino.ui.utils.Domino.text;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;
import org.dominokit.domino.ui.icons.lib.Icons;
import org.dominokit.domino.ui.utils.BaseDominoElement;
Expand Down Expand Up @@ -50,6 +53,7 @@ public class ScrollingPagination extends BasePagination<ScrollingPagination> {
protected PagerNavItem prevSet;
protected PagerNavItem nextSet;
private final PagerNavItem totalCountNavItem;
private Map<Integer, PagerNavItem> activeWindow = new HashMap<>();

/**
* Creates a ScrollingPagination instance with default settings.
Expand Down Expand Up @@ -165,10 +169,10 @@ public ScrollingPagination(int pages, int pageSize, int windowSize) {
lastPage
.expand()
.getLink()
.addClickListener(evt -> moveToPage(allPages.size(), isChangeListenersPaused()))
.addClickListener(evt -> moveToPage(pagesCount, isChangeListenersPaused()))
.onKeyDown(
keyEvents ->
keyEvents.onEnter(evt -> moveToPage(allPages.size(), isChangeListenersPaused())));
keyEvents.onEnter(evt -> moveToPage(pagesCount, isChangeListenersPaused())));
nextSet
.expand()
.getLink()
Expand Down Expand Up @@ -235,25 +239,7 @@ public ScrollingPagination updatePages(int pages, int pageSize, boolean silent)
clearPages();

if (pages > 0) {
IntStream.rangeClosed(1, pages)
.forEach(
p -> {
PagerNavItem page =
PagerNavItem.page(p)
.addClickListener(evt -> moveToPage(p, isChangeListenersPaused()))
.onKeyDown(
keyEvents ->
keyEvents.onEnter(evt -> moveToPage(p, isChangeListenersPaused())));

if (p <= windowSize) {
if (allPages.isEmpty()) {
pagesList.insertAfter(page, prevPage);
} else {
pagesList.insertAfter(page, allPages.get(allPages.size() - 1));
}
}
allPages.add(page);
});
scrollToWindow(0);
}

dots.expand();
Expand Down Expand Up @@ -281,10 +267,37 @@ public ScrollingPagination updatePages(int pages, int pageSize, boolean silent)
return this;
}

private void scrollToWindow(int windowIndex) {
activeWindow.values().forEach(BaseDominoElement::remove);
activeWindow.clear();
final PagerNavItem[] lastPage = new PagerNavItem[1];
IntStream.rangeClosed(
(windowIndex * windowSize) + 1,
Math.min((windowIndex * windowSize) + windowSize, pagesCount))
.forEach(
p -> {
PagerNavItem page =
PagerNavItem.page(p)
.addClickListener(evt -> moveToPage(p, isChangeListenersPaused()))
.onKeyDown(
keyEvents ->
keyEvents.onEnter(evt -> moveToPage(p, isChangeListenersPaused())));

if (activeWindow.isEmpty()) {
pagesList.insertAfter(page, prevPage);
} else {
pagesList.insertAfter(page, lastPage[0]);
}
lastPage[0] = page;
activeWindow.put(p, page);
});
this.windowIndex = windowIndex;
}

/** Clears all pages from the pagination. */
private void clearPages() {
allPages.forEach(BaseDominoElement::remove);
allPages.clear();
activeWindow.values().forEach(BaseDominoElement::remove);
activeWindow.clear();
}

/**
Expand All @@ -298,9 +311,11 @@ protected void moveToPage(int page, boolean silent) {
PagerNavItem oldPage = activePage;
if (page > 0 && page <= pagesCount) {

showPageWindow(page);

index = page;
if (markActivePage) {
gotoPage(allPages.get(page - 1));
gotoPage(activeWindow.get(page));
}

if (!silent) {
Expand All @@ -326,8 +341,6 @@ protected void moveToPage(int page, boolean silent) {
prevSet.enable();
firstPage.enable();
}

showPageWindow(page);
}
}

Expand All @@ -337,47 +350,14 @@ protected void moveToPage(int page, boolean silent) {
* @param page The current page index.
*/
private void showPageWindow(int page) {
if (page % windowSize == 0) {
showWindow((page / windowSize) - 1);
} else {
showWindow(page / windowSize);
}

if (windowIndex == 0) {
prevSet.disable();
} else {
prevSet.enable();
if (activeWindow.containsKey(page)) {
return;
}

int windowCount = (allPages.size() / windowSize) + (allPages.size() % windowSize > 0 ? 1 : 0);
if (windowIndex >= windowCount - 1) {
nextSet.disable();
if (page % windowSize == 0) {
scrollToWindow((page / windowSize) - 1);
} else {
nextSet.enable();
}
}

private void showWindow(int index) {
if (index != this.windowIndex) {
int windowMinLimit = windowIndex * windowSize;
int windowMaxLimit = windowMinLimit + windowSize;

for (int i = windowMinLimit; i < windowMaxLimit; i++) {
if (i < allPages.size()) {
allPages.get(i).remove();
}
}

int targetWindowMinLimit = index * windowSize;
int targetWindowMaxLimit = targetWindowMinLimit + windowSize;

for (int i = targetWindowMinLimit; i < targetWindowMaxLimit; i++) {
if (i < allPages.size()) {
pagesList.insertBefore(allPages.get(i), dots);
}
}

this.windowIndex = index;
scrollToWindow(page / windowSize);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import static java.util.Objects.nonNull;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;
import org.dominokit.domino.ui.utils.BaseDominoElement;

Expand All @@ -39,6 +41,8 @@
*/
public class SimplePagination extends BasePagination<SimplePagination> {

private List<PagerNavItem> allPages = new LinkedList<>();

/**
* Creates a new instance of SimplePagination with default settings (0 pages and a page size of
* 10).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static org.dominokit.domino.ui.utils.ElementsFactory.elements;

import elemental2.dom.DOMRect;
import elemental2.dom.DomGlobal;
import elemental2.dom.Element;
import elemental2.dom.Event;
import elemental2.dom.EventListener;
Expand Down Expand Up @@ -141,7 +142,10 @@ public void run() {
private void stopCurrentWave() {
if (nonNull(delayTimer)) delayTimer.cancel();
if (nonNull(removeTimer)) removeTimer.cancel();
if (nonNull(ripple)) ripple.remove();
if (nonNull(ripple)) {
final DivElement temp = ripple;
DomGlobal.setTimeout(p -> temp.remove(), 100);
}
}

private String convertStyle(JsPropertyMap<String> rippleStyle) {
Expand Down Expand Up @@ -186,7 +190,6 @@ public void handleEvent(Event evt) {

ripple = elements.div().addCss("dui-waves-ripple", "dui-waves-rippling");
target.appendChild(ripple);

ElementOffset position = offset(target.element());
double relativeY = (mouseEvent.pageY - position.top);
double relativeX = (mouseEvent.pageX - position.left);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package org.dominokit.domino.ui.utils;

import static elemental2.dom.DomGlobal.document;
import static org.dominokit.domino.ui.utils.ElementsFactory.elements;

import elemental2.core.JsArray;
import elemental2.dom.CustomEvent;
Expand Down Expand Up @@ -80,11 +79,11 @@ static void startObserving() {
private static void onElementAttributesChanged(MutationRecord record) {
CustomEventInit<MutationRecord> ceinit = CustomEventInit.create();
ceinit.setDetail(record);
DominoElement<Element> element = elements.elementOf(Js.<Element>uncheckedCast(record.target));
String type = ObserverEventType.attributeType(element);
Element target = Js.uncheckedCast(record.target);
String type = ObserverEventType.attributeType(target);

CustomEvent<MutationRecord> event = new CustomEvent<>(type, ceinit);
element.element().dispatchEvent(event);
target.dispatchEvent(event);
}

private static void observe() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package org.dominokit.domino.ui.utils;

import elemental2.dom.Element;

/** A utility class for generating event types related to attaching and detaching elements. */
public class ObserverEventType {

Expand All @@ -38,6 +40,17 @@ public static String detachedType(HasAttributes<?> element) {
return "dui-detached-" + element.getAttribute(BaseDominoElement.DETACH_UID_KEY);
}

/**
* Generates an event type for a detached element.
*
* @param element The element that has been detached.
* @return A string representing the event type for detached elements.
*/
public static String attributeType(Element element) {
return "dui-attribute-change-"
+ element.getAttribute(BaseDominoElement.ATTRIBUTE_CHANGE_UID_KEY);
}

/**
* Generates an event type for a detached element.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@
.dui-breadcrumb li.dui .dui.mdi,
.dui-breadcrumb li.dui a.dui .dui.mdi {
margin: var(--dui-bc-icon-margin);
line-height: 24px;
line-height: var(--dui-spc-px-24);
}

.dui-breadcrumb li.dui .dui.mdi.mdi-18px {
line-height: 18px;
line-height: var(--dui-spc-px-18);
}
.dui-breadcrumb li.dui .dui.mdi.mdi-24px {
line-height: 24px;
line-height: var(--dui-spc-px-24);
}
.dui-breadcrumb li.dui .dui.mdi.mdi-36px {
line-height: 36px;
line-height: var(--dui-spc-px-36);
}
.dui-breadcrumb li.dui .dui.mdi.mdi-48px {
line-height: 48px;
line-height: var(--dui-spc-px-48);
}

.dui-breadcrumb[disabled] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
text-align: center;
min-width: var(--dui-info-icon-size);
width: var(--dui-info-icon-size);
min-height: var(--dui-info-icon-size);
height: var(--dui-info-icon-size);
color: var(--dui-info-icon-color);
background-color: var(--dui-bg, var(--dui-info-icon-background));
}
Expand All @@ -31,10 +33,15 @@
min-height: var(--dui-info-icon-size);
}

.dui-info-icon i.dui.mdi,
.dui-info-icon i.dui.mdi:before {
font-size: var(--dui-info-icon-font-size);
transform: translate(calc(var(--dui-info-icon-size) / 3* -1), calc(var(--dui-info-icon-size) / 3* -1));
}

.dui-info-icon i.dui.mdi,
.dui-info-icon i.dui.mdi:before {
min-width: var(--dui-info-icon-size);
min-height: var(--dui-info-icon-size);
line-height: var(--dui-info-icon-size);
}

Expand Down Expand Up @@ -85,7 +92,7 @@
background-color: rgba(0, 0, 0, 0.05);
content: ".";
position: absolute;
left: 70px;
left: var(--dui-info-icon-size);
top: 0;
width: 0;
height: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
font:var(--dui-pager-page-link-font);
text-align: center;
display: inline-block;
width: var(--dui-pager-page-link-size);
height: var(--dui-pager-page-link-size);
min-width: var(--dui-pager-page-link-size);
min-height: var(--dui-pager-page-link-size);
border-radius: var(--dui-pager-page-link-border-radius);
line-height: var(--dui-pager-page-link-size);
cursor: var(--dui-pager-page-link-cursor);
Expand Down
Loading

0 comments on commit 503fe12

Please sign in to comment.