Browse Source

Improvements to ScrollDestination sanity checks (#11772)

- The new top row logical index should always be within the logical
range and high enough up to avoid leaving a gap if possible.
- Added regression testing for using the different scroll destination
types for scrolling to the top and to the bottom by index.

Fixes #11732
tags/8.10.0.alpha1
Anna Koskinen 4 years ago
parent
commit
1167c3bc4e
No account linked to committer's email address

+ 26
- 8
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

break; break;
case END: case END:
// target row at the bottom of the viewport // target row at the bottom of the viewport
newTopRowLogicalIndex = Math.min(
lastVisibleIndexIfScrollingDown + 1, getRowCount() - 1)
newTopRowLogicalIndex = lastVisibleIndexIfScrollingDown + 1
- visualRangeLength + 1; - visualRangeLength + 1;
newTopRowLogicalIndex = ensureTopRowLogicalIndexSanity(
newTopRowLogicalIndex);
if ((newTopRowLogicalIndex > oldTopRowLogicalIndex) if ((newTopRowLogicalIndex > oldTopRowLogicalIndex)
&& (newTopRowLogicalIndex && (newTopRowLogicalIndex
- oldTopRowLogicalIndex < visualRangeLength)) { - oldTopRowLogicalIndex < visualRangeLength)) {
// target row at the middle of the viewport, padding has to be // target row at the middle of the viewport, padding has to be
// zero or we never would have reached this far // zero or we never would have reached this far
newTopRowLogicalIndex = targetRowIndex - visualRangeLength / 2; newTopRowLogicalIndex = targetRowIndex - visualRangeLength / 2;
// ensure we don't attempt to go beyond the bottom row
if (newTopRowLogicalIndex + visualRangeLength > getRowCount()) {
newTopRowLogicalIndex = getRowCount() - visualRangeLength;
}
newTopRowLogicalIndex = ensureTopRowLogicalIndexSanity(
newTopRowLogicalIndex);
if (newTopRowLogicalIndex < oldTopRowLogicalIndex) { if (newTopRowLogicalIndex < oldTopRowLogicalIndex) {
logicalTargetIndex = newTopRowLogicalIndex; logicalTargetIndex = newTopRowLogicalIndex;
} else if (newTopRowLogicalIndex > oldTopRowLogicalIndex) { } else if (newTopRowLogicalIndex > oldTopRowLogicalIndex) {
case START: case START:
// target row at the top of the viewport, include buffer // target row at the top of the viewport, include buffer
// row if there is room for one // row if there is room for one
newTopRowLogicalIndex = Math
.max(firstVisibleIndexIfScrollingUp - 1, 0);
newTopRowLogicalIndex = firstVisibleIndexIfScrollingUp - 1;
newTopRowLogicalIndex = ensureTopRowLogicalIndexSanity(
newTopRowLogicalIndex);
if (getVisibleRowRange().contains(newTopRowLogicalIndex)) { if (getVisibleRowRange().contains(newTopRowLogicalIndex)) {
logicalTargetIndex = oldTopRowLogicalIndex logicalTargetIndex = oldTopRowLogicalIndex
+ visualRangeLength; + visualRangeLength;
} }
} }


/**
* Modifies the proposed top row logical index to fit within the logical
* range and to not leave gaps if it is avoidable.
*
* @param proposedTopRowLogicalIndex
* @return an adjusted index, or the original if no changes were
* necessary
*/
private int ensureTopRowLogicalIndexSanity(
int proposedTopRowLogicalIndex) {
int newTopRowLogicalIndex = Math.max(proposedTopRowLogicalIndex, 0);
int visualRangeLength = visualRowOrder.size();
if (newTopRowLogicalIndex + visualRangeLength > getRowCount()) {
newTopRowLogicalIndex = getRowCount() - visualRangeLength;
}
return newTopRowLogicalIndex;
}

/** /**
* Checks that scrolling is allowed and resets the scroll position if * Checks that scrolling is allowed and resets the scroll position if
* it's not. * it's not.

+ 92
- 0
uitest/src/test/java/com/vaadin/tests/components/grid/GridScrollDestinationTest.java View File

import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.NativeSelectElement; import com.vaadin.testbench.elements.NativeSelectElement;
import com.vaadin.testbench.elements.TextFieldElement;
import com.vaadin.tests.tb3.SingleBrowserTest; import com.vaadin.tests.tb3.SingleBrowserTest;


public class GridScrollDestinationTest extends SingleBrowserTest { public class GridScrollDestinationTest extends SingleBrowserTest {


private TextFieldElement textField;
private ButtonElement button; private ButtonElement button;
private GridElement grid; private GridElement grid;
private TestBenchElement header; private TestBenchElement header;
public void setup() throws Exception { public void setup() throws Exception {
super.setup(); super.setup();
openTestURL(); openTestURL();
textField = $(TextFieldElement.class).first();
button = $(ButtonElement.class).first(); button = $(ButtonElement.class).first();
grid = $(GridElement.class).first(); grid = $(GridElement.class).first();
header = grid.getHeader(); header = grid.getHeader();
rows = grid.getBody().findElements(By.className("v-grid-row")); rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(6); row = rows.get(6);
assertEquals("50", row.getText()); assertEquals("50", row.getText());

// scroll to beginning using scroll destination
textField.setValue("0");
button.click();

// expect to be scrolled all the way up
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(0);
assertEquals("0", row.getText());

assertElementAtTop(row);

// scroll to end using scroll destination
textField.setValue("99");
button.click();

// expect to be scrolled all the way down
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(rows.size() - 1);
assertEquals("99", row.getText());

assertElementAtBottom(row);
} }


@Test @Test
assertEquals("50", row.getText()); assertEquals("50", row.getText());


assertElementAtBottom(row); assertElementAtBottom(row);

// scroll to beginning using scroll destination
textField.setValue("0");
button.click();
button.click();

// expect to be scrolled all the way up
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(0);
assertEquals("0", row.getText());

assertElementAtTop(row);

// scroll to end using scroll destination
textField.setValue("99");
button.click();

// expect to be scrolled all the way down
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(rows.size() - 1);
assertEquals("99", row.getText());

assertElementAtBottom(row);
} }


@Test @Test
assertEquals("50", row.getText()); assertEquals("50", row.getText());


assertElementAtTop(row); assertElementAtTop(row);

// scroll to beginning using scroll destination
textField.setValue("0");
button.click();

// expect to be scrolled all the way up
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(0);
assertEquals("0", row.getText());

assertElementAtTop(row);

// scroll to end using scroll destination
textField.setValue("99");
button.click();

// expect to be scrolled all the way down
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(rows.size() - 1);
assertEquals("99", row.getText());

assertElementAtBottom(row);
} }


@Test @Test
assertEquals("50", row.getText()); assertEquals("50", row.getText());


assertElementAtMiddle(row); assertElementAtMiddle(row);

// scroll to beginning using scroll destination
textField.setValue("0");
button.click();

// expect to be scrolled all the way up
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(0);
assertEquals("0", row.getText());

assertElementAtTop(row);

// scroll to end using scroll destination
textField.setValue("99");
button.click();

// expect to be scrolled all the way down
rows = grid.getBody().findElements(By.className("v-grid-row"));
row = rows.get(rows.size() - 1);
assertEquals("99", row.getText());

assertElementAtBottom(row);
} }
} }

Loading…
Cancel
Save