Browse Source

Grid editor open (#10674)

tags/8.4.0.alpha1
Anna Koskinen 6 years ago
parent
commit
1187cf22f0

+ 41
- 10
client/src/main/java/com/vaadin/client/WidgetUtil.java View File

@@ -51,6 +51,37 @@ import com.vaadin.shared.util.SharedUtil;
*/
public class WidgetUtil {

/**
* Simple object to store another object.
*
* @param <T>
* the object type to store
* @since
*/
public static class Reference<T> {

T reference = null;

/**
* Gets the current object.
*
* @return the stored object
*/
public T get() {
return reference;
}

/**
* Sets the current object.
*
* @param reference
* the object to store
*/
public void set(T reference) {
this.reference = reference;
}
}

/**
* Helper method for debugging purposes.
*
@@ -778,7 +809,7 @@ public class WidgetUtil {
com.google.gwt.dom.client.Element el, String p)
/*-{
try {
if (el.currentStyle) {
// IE
return el.currentStyle[p];
@@ -793,7 +824,7 @@ public class WidgetUtil {
} catch (e) {
return "";
}
}-*/;

/**
@@ -807,7 +838,7 @@ public class WidgetUtil {
try {
el.focus();
} catch (e) {
}
}-*/;

@@ -1158,7 +1189,7 @@ public class WidgetUtil {
if ($wnd.document.activeElement) {
return $wnd.document.activeElement;
}
return null;
}-*/;

@@ -1229,11 +1260,11 @@ public class WidgetUtil {
/*-{
var top = elem.offsetTop;
var height = elem.offsetHeight;
if (elem.parentNode != elem.offsetParent) {
top -= elem.parentNode.offsetTop;
}
var cur = elem.parentNode;
while (cur && (cur.nodeType == 1)) {
if (top < cur.scrollTop) {
@@ -1242,12 +1273,12 @@ public class WidgetUtil {
if (top + height > cur.scrollTop + cur.clientHeight) {
cur.scrollTop = (top + height) - cur.clientHeight;
}
var offsetTop = cur.offsetTop;
if (cur.parentNode != cur.offsetParent) {
offsetTop -= cur.parentNode.offsetTop;
}
top += offsetTop - cur.scrollTop;
cur = cur.parentNode;
}
@@ -1696,7 +1727,7 @@ public class WidgetUtil {
}
var heightWithoutBorder = cloneElement.offsetHeight;
parentElement.removeChild(cloneElement);
return heightWithBorder - heightWithoutBorder;
}
}-*/;
@@ -1873,7 +1904,7 @@ public class WidgetUtil {
* ancestors has the style {@code display: none} applied.
*
* @param element
* the element to test for visibility
* the element to test for visibility
* @return {@code true} if the element is displayed, {@code false} otherwise
* @since 8.3.2
*/

+ 1
- 13
client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java View File

@@ -66,12 +66,7 @@ public class EditorConnector extends AbstractExtensionConnector {
public void bind(final int rowIndex) {
// call this deferred to avoid issues with editing on init
Scheduler.get().scheduleDeferred(() -> {
currentEditedRow = rowIndex;
// might need to wait for available data,
// if data is available, ensureAvailability will immediately trigger the handler anyway,
// so no need for alternative "immediately available" logic
waitingForAvailableData = true;
getParent().getDataSource().ensureAvailability(rowIndex, 1);
getParent().getWidget().editRow(rowIndex);
});
}

@@ -218,13 +213,6 @@ public class EditorConnector extends AbstractExtensionConnector {
protected void extend(ServerConnector target) {
Grid<JsonObject> grid = getParent().getWidget();
grid.getEditor().setHandler(new CustomEditorHandler());
grid.addDataAvailableHandler((event) -> {
Range range = event.getAvailableRows();
if (waitingForAvailableData && currentEditedRow != null && range.contains(currentEditedRow)) {
getParent().getWidget().editRow(currentEditedRow);
waitingForAvailableData = false;
}
});
}

@Override

+ 81
- 15
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -80,6 +80,7 @@ import com.vaadin.client.BrowserInfo;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.WidgetUtil.Reference;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.data.DataSource.RowHandle;
@@ -1437,7 +1438,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
private String styleName = null;

private HandlerRegistration hScrollHandler;
private HandlerRegistration vScrollHandler;

private final Button saveButton;
private final Button cancelButton;
@@ -1680,20 +1680,10 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
state = State.ACTIVATING;

final Escalator escalator = grid.getEscalator();
if (escalator.getVisibleRowRange().contains(rowIndex)) {
show(rowIndex, columnIndexDOM);
} else {
vScrollHandler = grid.addScrollHandler(event -> {
if (escalator.getVisibleRowRange().contains(rowIndex)) {
show(rowIndex, columnIndexDOM);
vScrollHandler.removeHandler();
}
});
grid.scrollToRow(rowIndex,
isBuffered() ? ScrollDestination.MIDDLE
: ScrollDestination.ANY);
}
grid.scrollToRow(rowIndex,
isBuffered() ? ScrollDestination.MIDDLE
: ScrollDestination.ANY,
() -> show(rowIndex, columnIndexDOM));
}

/**
@@ -7383,6 +7373,45 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
: GridConstants.DEFAULT_PADDING);
}

/**
* Helper method for making sure desired row is visible and it is properly
* rendered.
*
* @param rowIndex
* the row to look for
* @param destination
* the desired scroll destination
* @param callback
* the callback command to execute when row is available
* @since
*/
public void scrollToRow(int rowIndex, ScrollDestination destination,
Runnable callback) {
waitUntilVisible(rowIndex, destination, () -> {
Reference<HandlerRegistration> registration = new Reference<>();
registration.set(addDataAvailableHandler(event -> {
if (event.getAvailableRows().contains(rowIndex)) {
registration.get().removeHandler();
callback.run();
}
}));
});
}

/**
* Helper method for making sure desired row is visible and it is properly
* rendered.
*
* @param rowIndex
* the row to look for
* @param whenRendered
* the callback command to execute when row is available
* @since
*/
public void scrollToRow(int rowIndex, Runnable whenRendered) {
scrollToRow(rowIndex, ScrollDestination.ANY, whenRendered);
}

/**
* Scrolls to a certain row using only user-specified parameters.
* <p>
@@ -7420,6 +7449,43 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
escalator.scrollToRowAndSpacer(rowIndex, destination, paddingPx);
}

/**
* Helper method for scrolling and making sure row is visible.
*
* @param rowIndex
* the row index to make visible
* @param destination
* the desired scroll destination
* @param whenVisible
* the callback method to call when row is visible
*/
private void waitUntilVisible(int rowIndex, ScrollDestination destination,
Runnable whenVisible) {
final Escalator escalator = getEscalator();
if (escalator.getVisibleRowRange().contains(rowIndex)) {
TableRowElement rowElement = escalator.getBody()
.getRowElement(rowIndex);
long bottomBorder = Math.round(WidgetUtil.getBorderBottomThickness(
rowElement.getFirstChildElement()) + 0.5d);
if (rowElement.getAbsoluteTop() >= escalator.getHeader()
.getElement().getAbsoluteBottom()
&& rowElement.getAbsoluteBottom() <= escalator.getFooter()
.getElement().getAbsoluteTop() + bottomBorder) {
whenVisible.run();
return;
}
}

Reference<HandlerRegistration> registration = new Reference<>();
registration.set(addScrollHandler(event -> {
if (escalator.getVisibleRowRange().contains(rowIndex)) {
registration.get().removeHandler();
whenVisible.run();
}
}));
scrollToRow(rowIndex, destination);
}

/**
* Scrolls to the beginning of the very first row.
*/

+ 97
- 0
uitest/src/main/java/com/vaadin/tests/components/grid/GridEditRow.java View File

@@ -0,0 +1,97 @@
package com.vaadin.tests.components.grid;

import java.util.ArrayList;

import com.vaadin.annotations.Widgetset;
import com.vaadin.data.provider.ListDataProvider;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;
import com.vaadin.ui.TextField;

@Widgetset("com.vaadin.DefaultWidgetSet")
public class GridEditRow extends AbstractTestUI {

private ArrayList<TestBean> items = new ArrayList<>();
private TestBean bean = null;
private int counter = 0;

@SuppressWarnings("unchecked")
@Override
protected void setup(VaadinRequest request) {

Grid<TestBean> grid = new Grid<TestBean>(TestBean.class);
grid.setDataProvider(new ListDataProvider<>(items));
grid.setWidth("100%");
grid.setHeight("400px");
grid.getEditor().setEnabled(true);
grid.getColumn("name").setEditorComponent(new TextField());
grid.getColumn("value").setEditorComponent(new TextField());

getLayout().addComponent(new Button("Add", event -> {
bean = new TestBean();
items.add(bean);
grid.getDataProvider().refreshAll();
}));
getLayout().addComponent(new Button("Add, Select & Edit", event -> {
bean = new TestBean();
items.add(bean);
grid.getDataProvider().refreshAll();
grid.select(bean);
int row = ((ArrayList<TestBean>) ((ListDataProvider<TestBean>) grid
.getDataProvider()).getItems()).indexOf(bean);
grid.getEditor().editRow(row);
}));
getLayout().addComponent(new Button("Edit", event -> {
int row = ((ArrayList<TestBean>) ((ListDataProvider<TestBean>) grid
.getDataProvider()).getItems()).indexOf(bean);
grid.getEditor().editRow(row);
}));
getLayout().addComponent(new Button("Select & Edit", event -> {
grid.select(bean);
int row = ((ArrayList<TestBean>) ((ListDataProvider<TestBean>) grid
.getDataProvider()).getItems()).indexOf(bean);
grid.getEditor().editRow(row);
}));

getLayout().addComponent(grid);
}

@Override
protected Integer getTicketNumber() {
return 10558;
}

@Override
protected String getTestDescription() {
return "Calling editRow shouldn't cause any other rows to be emptied.";
}

public class TestBean {
private String name = "name" + counter;
private String value = "value" + counter;

public TestBean() {
++counter;
}

public String getName() {
return name;
}

public void setName(String inName) {
name = inName;
}

public String getValue() {
return value;
}

public void setValue(String inValue) {
value = inValue;
}

}

}

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

@@ -0,0 +1,116 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.tests.components.grid;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;

import org.junit.Test;

import com.vaadin.testbench.By;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.testbench.elements.GridElement;
import com.vaadin.testbench.elements.GridElement.GridEditorElement;
import com.vaadin.testbench.parallel.TestCategory;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* Tests for ensuring that the furthest away visible rows don't get emptied when
* editRow is called, and that the editor doesn't open beyond the lower border
* of the Grid.
*
*/
@TestCategory("grid")
public class GridEditRowTest extends MultiBrowserTest {

private GridElement grid;
private ButtonElement addButton;
private ButtonElement editButton;

@Override
public void setup() throws Exception {
super.setup();
openTestURL();
grid = $(GridElement.class).first();
addButton = $(ButtonElement.class).caption("Add").first();
editButton = $(ButtonElement.class).caption("Edit").first();
}

public void addRows(int count) {
for (int i = 0; i < count; ++i) {
addButton.click();
}
}

public void editLastRow() {
editButton.click();
}

private void assertRowContents(int rowIndex) {
assertThat(grid.getCell(rowIndex, 0).getText(), is("name" + rowIndex));
}

private void assertEditorWithinGrid() {
GridEditorElement editor = grid.getEditor();
assertThat(editor.getLocation().y + editor.getSize().height,
not(greaterThan(grid.getLocation().y + grid.getSize().height)));
}

@Test
public void testEditWhenAllRowsVisible() {
addRows(7);

assertRowContents(0);

editLastRow();

assertRowContents(0);

waitForElementVisible(By.className("v-grid-editor"));

assertEditorWithinGrid();
}

@Test
public void testEditWhenSomeRowsNotVisible() {
addRows(11);

assertRowContents(3);

editLastRow();

waitForElementVisible(By.className("v-grid-editor"));

assertRowContents(3);
assertEditorWithinGrid();
}

@Test
public void testEditWhenSomeRowsOutsideOfCache() {
addRows(100);

assertRowContents(91);

editLastRow();

waitForElementVisible(By.className("v-grid-editor"));

assertRowContents(91);
assertEditorWithinGrid();
}
}

Loading…
Cancel
Save