Previously grid sidebar could be partially hidden by "overflow: hidden" of an ancestor component. Now it's in an overlay and the hierarchy doesn't affect it. Grid tests were also updated for new DOM structure. Change-Id: Ic5fb125d9c097be0f0141c121dfe74d30e650dd0tags/7.6.0.beta2
@@ -100,6 +100,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co | |||
padding: 0; | |||
z-index: 5; | |||
&.#{$primaryStyleName}-sidebar-popup { | |||
right: auto; | |||
} | |||
.#{$primaryStyleName}-sidebar-button { | |||
background: transparent; | |||
border: none; |
@@ -54,6 +54,8 @@ import com.google.gwt.event.dom.client.KeyDownEvent; | |||
import com.google.gwt.event.dom.client.KeyDownHandler; | |||
import com.google.gwt.event.dom.client.KeyEvent; | |||
import com.google.gwt.event.dom.client.MouseEvent; | |||
import com.google.gwt.event.logical.shared.CloseEvent; | |||
import com.google.gwt.event.logical.shared.CloseHandler; | |||
import com.google.gwt.event.logical.shared.ValueChangeEvent; | |||
import com.google.gwt.event.logical.shared.ValueChangeHandler; | |||
import com.google.gwt.event.shared.HandlerRegistration; | |||
@@ -71,6 +73,7 @@ import com.google.gwt.user.client.ui.HasEnabled; | |||
import com.google.gwt.user.client.ui.HasWidgets; | |||
import com.google.gwt.user.client.ui.MenuBar; | |||
import com.google.gwt.user.client.ui.MenuItem; | |||
import com.google.gwt.user.client.ui.PopupPanel; | |||
import com.google.gwt.user.client.ui.ResizeComposite; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.client.BrowserInfo; | |||
@@ -85,6 +88,7 @@ import com.vaadin.client.renderers.Renderer; | |||
import com.vaadin.client.renderers.WidgetRenderer; | |||
import com.vaadin.client.ui.FocusUtil; | |||
import com.vaadin.client.ui.SubPartAware; | |||
import com.vaadin.client.ui.VOverlay; | |||
import com.vaadin.client.ui.dd.DragAndDropHandler; | |||
import com.vaadin.client.ui.dd.DragAndDropHandler.DragAndDropCallback; | |||
import com.vaadin.client.ui.dd.DragHandle; | |||
@@ -3579,25 +3583,7 @@ public class Grid<T> extends ResizeComposite implements | |||
private final Grid<?> grid; | |||
private NativePreviewHandler clickOutsideToCloseHandler = new NativePreviewHandler() { | |||
@Override | |||
public void onPreviewNativeEvent(NativePreviewEvent event) { | |||
if (event.getTypeInt() != Event.ONMOUSEDOWN) { | |||
return; | |||
} | |||
// Click outside the panel | |||
EventTarget clickTarget = event.getNativeEvent() | |||
.getEventTarget(); | |||
if (!rootContainer.getElement().isOrHasChild( | |||
Element.as(clickTarget))) { | |||
close(); | |||
} | |||
} | |||
}; | |||
private HandlerRegistration clickOutsideToCloseHandlerRegistration; | |||
private VOverlay overlay; | |||
private Sidebar(Grid<?> grid) { | |||
this.grid = grid; | |||
@@ -3624,6 +3610,8 @@ public class Grid<T> extends ResizeComposite implements | |||
} | |||
}; | |||
createOverlay(); | |||
menuBar = new MenuBar(true) { | |||
@Override | |||
@@ -3683,6 +3671,25 @@ public class Grid<T> extends ResizeComposite implements | |||
menuBar.addDomHandler(keyDownHandler, KeyDownEvent.getType()); | |||
} | |||
/** | |||
* Creates and initializes the overlay. | |||
*/ | |||
private void createOverlay() { | |||
overlay = GWT.create(VOverlay.class); | |||
overlay.setAutoHideEnabled(true); | |||
overlay.setOwner(grid); | |||
overlay.addStyleDependentName("popup"); | |||
overlay.add(content); | |||
overlay.addAutoHidePartner(rootContainer.getElement()); | |||
overlay.addCloseHandler(new CloseHandler<PopupPanel>() { | |||
@Override | |||
public void onClose(CloseEvent<PopupPanel> event) { | |||
removeStyleName("open"); | |||
addStyleName("closed"); | |||
} | |||
}); | |||
} | |||
/** | |||
* Opens the sidebar if not yet opened. Opening the sidebar has no | |||
* effect if it is empty. | |||
@@ -3691,9 +3698,7 @@ public class Grid<T> extends ResizeComposite implements | |||
if (!isOpen() && isInDOM()) { | |||
addStyleName("open"); | |||
removeStyleName("closed"); | |||
rootContainer.add(content); | |||
clickOutsideToCloseHandlerRegistration = Event | |||
.addNativePreviewHandler(clickOutsideToCloseHandler); | |||
overlay.showRelativeTo(rootContainer); | |||
} | |||
} | |||
@@ -3701,17 +3706,7 @@ public class Grid<T> extends ResizeComposite implements | |||
* Closes the sidebar if not yet closed. | |||
*/ | |||
public void close() { | |||
if (isOpen()) { | |||
removeStyleName("open"); | |||
addStyleName("closed"); | |||
content.removeFromParent(); | |||
// adjust open button to header height when closed | |||
setHeightToHeaderCellHeight(); | |||
if (clickOutsideToCloseHandlerRegistration != null) { | |||
clickOutsideToCloseHandlerRegistration.removeHandler(); | |||
clickOutsideToCloseHandlerRegistration = null; | |||
} | |||
} | |||
overlay.hide(); | |||
} | |||
/** | |||
@@ -3720,12 +3715,13 @@ public class Grid<T> extends ResizeComposite implements | |||
* @return <code>true</code> if open, <code>false</code> if not | |||
*/ | |||
public boolean isOpen() { | |||
return content != null && content.getParent() == rootContainer; | |||
return overlay != null && overlay.isShowing(); | |||
} | |||
@Override | |||
public void setStylePrimaryName(String styleName) { | |||
super.setStylePrimaryName(styleName); | |||
overlay.setStylePrimaryName(styleName); | |||
content.setStylePrimaryName(styleName + "-content"); | |||
openCloseButton.setStylePrimaryName(styleName + "-button"); | |||
if (isOpen()) { | |||
@@ -3737,6 +3733,18 @@ public class Grid<T> extends ResizeComposite implements | |||
} | |||
} | |||
@Override | |||
public void addStyleName(String style) { | |||
super.addStyleName(style); | |||
overlay.addStyleName(style); | |||
} | |||
@Override | |||
public void removeStyleName(String style) { | |||
super.removeStyleName(style); | |||
overlay.removeStyleName(style); | |||
} | |||
private void setHeightToHeaderCellHeight() { | |||
RowContainer header = grid.escalator.getHeader(); | |||
if (header.getRowCount() == 0 |
@@ -0,0 +1,60 @@ | |||
/* | |||
* Copyright 2000-2014 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 com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.ui.CssLayout; | |||
import com.vaadin.ui.Grid; | |||
import com.vaadin.ui.VerticalLayout; | |||
public class GridInGridLayout extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
final VerticalLayout layout = new VerticalLayout(); | |||
final CssLayout cssLayout = new CssLayout(); | |||
cssLayout.setWidth("100%"); | |||
layout.setHeight("320px"); | |||
layout.setMargin(true); | |||
addComponent(cssLayout); | |||
cssLayout.addComponent(layout); | |||
final Grid grid = new Grid(); | |||
grid.setSizeFull(); | |||
for (int i = 0; i < 20; i++) { | |||
Grid.Column column = grid.addColumn("" + i); | |||
column.setHidable(true); | |||
column.setEditable(true); | |||
} | |||
grid.setEditorEnabled(true); | |||
grid.setColumnReorderingAllowed(true); | |||
for (int i = 0; i < 300; i++) { | |||
grid.addRow("Foo", "Bar", "far", "bar", "bar", "Foo", "Bar", "Bar", | |||
"bar", "bar", "Foo", "Bar", "Bar", "bar", "bar", "Foo", | |||
"Bar", "Bar", "bar", "bar"); | |||
} | |||
layout.addComponent(grid); | |||
grid.setHeight("300px"); | |||
grid.setWidth("400px"); | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 18698; | |||
} | |||
} |
@@ -50,6 +50,8 @@ public class GridInitiallyHiddenColumnsTest extends SingleBrowserTest { | |||
} | |||
// TODO: as to the getX methods reuse ones from GridBasicFeaturesTest? | |||
protected WebElement getSidebarOpenButton(GridElement grid) { | |||
List<WebElement> elements = grid.findElements(By | |||
.className("v-grid-sidebar-button")); | |||
@@ -73,7 +75,8 @@ public class GridInitiallyHiddenColumnsTest extends SingleBrowserTest { | |||
} | |||
protected WebElement getSidebar(GridElement grid) { | |||
List<WebElement> elements = findElements(By.className("v-grid-sidebar")); | |||
List<WebElement> elements = findElements(By | |||
.className("v-grid-sidebar-popup")); | |||
return elements.isEmpty() ? null : elements.get(0); | |||
} | |||
@@ -217,8 +217,19 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { | |||
.contains("focused")); | |||
} | |||
protected WebElement getSidebar() { | |||
List<WebElement> elements = findElements(By.className("v-grid-sidebar")); | |||
protected WebElement getSidebarPopup() { | |||
List<WebElement> elements = findElements(By | |||
.className("v-grid-sidebar-popup")); | |||
if (elements.isEmpty()) { | |||
getSidebarOpenButton().click(); | |||
elements = findElements(By.className("v-grid-sidebar-popup")); | |||
} | |||
return elements.isEmpty() ? null : elements.get(0); | |||
} | |||
protected WebElement getSidebarPopupIfPresent() { | |||
List<WebElement> elements = findElements(By | |||
.className("v-grid-sidebar-popup")); | |||
return elements.isEmpty() ? null : elements.get(0); | |||
} | |||
@@ -233,7 +244,7 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest { | |||
* index, or null if not found. | |||
*/ | |||
protected WebElement getColumnHidingToggle(int columnIndex) { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarPopup(); | |||
List<WebElement> elements = sidebar.findElements(By | |||
.className("column-hiding-toggle")); | |||
for (WebElement e : elements) { |
@@ -188,12 +188,12 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest { | |||
@Test | |||
public void testColumnHidability_onTriggerColumnHidability_showsSidebarButton() { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarOpenButton(); | |||
assertNull(sidebar); | |||
toggleHidableColumnAPI(0); | |||
sidebar = getSidebar(); | |||
sidebar = getSidebarOpenButton(); | |||
assertNotNull(sidebar); | |||
} | |||
@@ -998,7 +998,7 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest { | |||
} | |||
private void verifyColumnHidingTogglesOrder(int... indices) { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarPopup(); | |||
List<WebElement> elements = sidebar.findElements(By | |||
.className("column-hiding-toggle")); | |||
for (int i = 0; i < indices.length; i++) { | |||
@@ -1015,45 +1015,32 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest { | |||
} | |||
private void verifySidebarOpened() { | |||
WebElement sidebar = getSidebar(); | |||
assertTrue(sidebar.getAttribute("class").contains("open")); | |||
WebElement sidebar = getSidebarPopupIfPresent(); | |||
assertNotNull(sidebar); | |||
} | |||
private void verifySidebarClosed() { | |||
WebElement sidebar = getSidebar(); | |||
assertFalse(sidebar.getAttribute("class").contains("open")); | |||
WebElement sidebar = getSidebarPopupIfPresent(); | |||
assertNull(sidebar); | |||
} | |||
private void verifySidebarNotVisible() { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarOpenButton(); | |||
assertNull(sidebar); | |||
} | |||
private void verifySidebarVisible() { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarOpenButton(); | |||
assertNotNull(sidebar); | |||
} | |||
@Override | |||
protected WebElement getSidebar() { | |||
List<WebElement> elements = findElements(By.className("v-grid-sidebar")); | |||
return elements.isEmpty() ? null : elements.get(0); | |||
} | |||
@Override | |||
protected WebElement getSidebarOpenButton() { | |||
List<WebElement> elements = findElements(By | |||
.className("v-grid-sidebar-button")); | |||
return elements.isEmpty() ? null : elements.get(0); | |||
} | |||
/** | |||
* Returns the toggle inside the sidebar for hiding the column at the given | |||
* index, or null if not found. | |||
*/ | |||
@Override | |||
protected WebElement getColumnHidingToggle(int columnIndex) { | |||
WebElement sidebar = getSidebar(); | |||
WebElement sidebar = getSidebarPopup(); | |||
List<WebElement> elements = sidebar.findElements(By | |||
.className("column-hiding-toggle")); | |||
for (WebElement e : elements) { |
@@ -30,24 +30,23 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
@Test | |||
public void testSidebarWithHidableColumn() { | |||
openTestURL(); | |||
CustomGridElement gridElement = getGridElement(); | |||
Assert.assertEquals("Sidebar should not be initially present", 0, | |||
countBySelector(".v-grid-sidebar")); | |||
countBySelector(".v-grid-sidebar-button")); | |||
selectMenuPath("Component", "Columns", "Column 0", "Hidable"); | |||
gridElement.findElement(By.className("v-grid-sidebar-button")).click(); | |||
getSidebarOpenButton().click(); | |||
WebElement toggle = gridElement.findElement(By | |||
.className("column-hiding-toggle")); | |||
WebElement toggle = getSidebarPopup().findElement( | |||
By.className("column-hiding-toggle")); | |||
Assert.assertEquals("Column 0 should be togglable", "Header (0,0)", | |||
toggle.getText()); | |||
selectMenuPath("Component", "Columns", "Column 0", "Hidable"); | |||
Assert.assertEquals("Sidebar should disappear without toggable column", | |||
0, countBySelector(".v-grid-sidebar")); | |||
0, countBySelector(".v-grid-sidebar-button")); | |||
} | |||
@@ -60,8 +59,8 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
gridElement.findElement(By.className("v-grid-sidebar-button")).click(); | |||
WebElement sidebarItem = gridElement.findElement(By | |||
.cssSelector(".v-grid-sidebar-content .gwt-MenuItem")); | |||
WebElement sidebarItem = getSidebarPopup().findElement( | |||
By.cssSelector(".v-grid-sidebar-content .gwt-MenuItem")); | |||
sidebarItem.click(); | |||
@@ -84,7 +83,6 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
@Test | |||
public void testBasicSidebarOrder() { | |||
openTestURL(); | |||
CustomGridElement gridElement = getGridElement(); | |||
// First add custom content | |||
selectMenuPath("Component", "Sidebar", "Add separator to end"); | |||
@@ -101,7 +99,6 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
@Test | |||
public void testSidebarOrderAbuse() { | |||
openTestURL(); | |||
CustomGridElement gridElement = getGridElement(); | |||
selectMenuPath("Component", "Columns", "Column 0", "Hidable"); | |||
selectMenuPath("Component", "Columns", "Column 1", "Hidable"); | |||
@@ -125,7 +122,7 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
} | |||
private void assertSidebarMenuItems(String... items) { | |||
List<WebElement> menuItems = getGridElement().findElements( | |||
List<WebElement> menuItems = getSidebarPopup().findElements( | |||
By.cssSelector(".v-grid-sidebar-content td")); | |||
Assert.assertEquals("Expected " + items.length + " menu items", | |||
@@ -145,8 +142,6 @@ public class GridSidebarContentTest extends GridBasicClientFeaturesTest { | |||
} | |||
private int countBySelector(String cssSelector) { | |||
return getGridElement().findElements(By.cssSelector(cssSelector)) | |||
.size(); | |||
return findElements(By.cssSelector(cssSelector)).size(); | |||
} | |||
} |