Due to old fix for (#11994) the v-scrollable div of the window would expand to 110% of its size then immediately back to the original size. The first action, expanding the v-scrollable to 110% would decrease the scrollTop value of our panel, while increasing its height. When the revert back action would set the v-scrollable to its own size, the panel's scrollTop would remain decreased, causing the scroll bar to move up, hiding the ~10% at the bottom. Fixed by calling Util.runWebkitOverflowAutoFix(); instead of changing the height. Change-Id: I79eafd1f9500c2e4c10dadbfc7100608c0732e04tags/7.3.0.rc1
@@ -0,0 +1,96 @@ | |||
<html> | |||
<head> | |||
<title>Bottom component scroll when focus - test with plain html to see the default behaviour</title> | |||
<link rel="stylesheet" type="text/css" href="./../VAADIN/themes/reindeer/styles.css"> | |||
<script> | |||
function setScrollOnPanel() { | |||
var popups = document.getElementsByClassName("v-panel-content"); | |||
popups[0].scrollTop = 756; | |||
console.log("popups[0]: " + popups[0].scrollTop); | |||
} | |||
</script> | |||
</head> | |||
<body> | |||
<div id="runBottomComponentScrollsUp-1897366330-overlays" class="v-app reindeer v-overlay-container" aria-live="assertive" aria-label="This content is announced automatically and does not need to be navigated into." aria-relevant="additions"> | |||
<div class="v-tooltip" role="tooltip" aria-live="assertive" aria-relevant="additions" style="margin-left: 0px; margin-top: 0px; left: -4990px; top: -4990px; z-index: 20000; visibility: visible; position: absolute; overflow: visible;"> | |||
<div class="popupContent"><div><div class="v-errormessage" aria-hidden="true" style="display: none;"></div><div class="v-tooltip-text"> </div></div></div></div> | |||
<div class="v-window v-widget v-has-width v-has-height" role="dialog" aria-relevant="additions" aria-labelledby="gwt-uid-2" style="margin-left: 0px; margin-top: 0px; left: 400px; top: 19px; z-index: 10000; width: 300px; height: 300px; visibility: visible; position: absolute; overflow: visible; min-width: 66px; min-height: 52px;"> | |||
<div class="popupContent"> | |||
<div class="v-window-wrap"> | |||
<div tabindex="0" aria-label="Top of dialog"></div> | |||
<div class="v-window-outerheader"> | |||
<div class="v-window-header" id="gwt-uid-2"> | |||
<span class="v-assistive-device-only"></span> | |||
<span class="v-assistive-device-only"></span> | |||
</div> | |||
</div> | |||
<div class="v-window-maximizebox" tabindex="0" role="button" aria-label="maximize button" id="28_window_maximizerestore"></div> | |||
<div class="v-window-closebox" tabindex="0" role="button" aria-label="close button" id="28_window_close"></div> | |||
<div class="v-window-contents" style="padding-top: 37px; margin-top: -37px; padding-bottom: 15px; margin-bottom: -15px;"> | |||
<div tabindex="0" class="v-scrollable" style="zoom: 1; position: relative;"> | |||
<div class="v-panel v-widget v-has-width v-has-height" style="overflow: hidden; width: 100%; height: 100%; position: absolute; padding-top: 1px; padding-bottom: 1px;"> | |||
<div class="v-panel-captionwrap" style="margin-top: -1px;"> | |||
<div class="v-panel-nocaption"><span></span> | |||
</div> | |||
</div> | |||
<div class="v-panel-content v-scrollable" tabindex="-1" style="position: relative;"> | |||
<div class="v-verticallayout v-layout v-vertical v-widget v-has-width v-has-height" style="width: 100%; height: 1000px;"> | |||
<div class="v-expand" style="padding-top: 0px;"> | |||
<div class="v-slot" style="height: 50%; margin-top: 0px;"> | |||
<div role="combobox" class="v-filterselect v-widget v-filterselect-prompt"> | |||
<input type="text" class="v-filterselect-input" tabindex="0" style="width: 129px;"> | |||
<div class="v-filterselect-button" aria-hidden="true" role="button"></div> | |||
</div> | |||
</div> | |||
<div class="v-slot v-align-center v-align-bottom" style="height: 50%;"> | |||
<div tabindex="0" role="button" class="v-button v-widget v-has-height" style="height: 100px;" onclick="setScrollOnPanel();"> | |||
<span class="v-button-wrap"><span class="v-button-caption">Press me</span></span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="v-panel-deco" style="margin-bottom: -1px;"></div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="v-window-footer"> | |||
<div class="v-window-resizebox"></div> | |||
</div> | |||
<div tabindex="0" aria-label="Bottom of Dialog"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</body> | |||
</html> |
@@ -66,7 +66,6 @@ import com.google.gwt.user.client.Window.ClosingHandler; | |||
import com.google.gwt.user.client.ui.HasWidgets; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.client.ApplicationConfiguration.ErrorMessage; | |||
import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; | |||
import com.vaadin.client.ResourceLoader.ResourceLoadEvent; | |||
import com.vaadin.client.ResourceLoader.ResourceLoadListener; | |||
import com.vaadin.client.communication.HasJavaScriptConnectorHelper; |
@@ -468,6 +468,24 @@ public class Util { | |||
return detectedScrollbarSize; | |||
} | |||
/** | |||
* Defers the execution of {@link #runWebkitOverflowAutoFix(Element)} | |||
* | |||
* @since | |||
* @param elem | |||
* with overflow auto | |||
*/ | |||
public static void runWebkitOverflowAutoFixDeferred(final Element elem) { | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
Util.runWebkitOverflowAutoFix(elem); | |||
} | |||
}); | |||
} | |||
/** | |||
* Run workaround for webkits overflow auto issue. | |||
* |
@@ -2251,13 +2251,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, | |||
* Ensures the column alignments are correct at initial loading. <br/> | |||
* (child components widths are correct) | |||
*/ | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||
} | |||
}); | |||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||
hadScrollBars = willHaveScrollbarz; | |||
} | |||
@@ -6720,13 +6714,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, | |||
Util.notifyParentOfSizeChange(VScrollTable.this, rendering); | |||
} | |||
} | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||
} | |||
}); | |||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||
forceRealignColumnHeaders(); | |||
} | |||
@@ -6863,13 +6852,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, | |||
// We must run the fix as a deferred command to prevent it from | |||
// overwriting the scroll position with an outdated value, see | |||
// #7607. | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||
} | |||
}); | |||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||
} | |||
triggerLazyColumnAdjustment(false); |
@@ -1,12 +1,12 @@ | |||
/* | |||
* 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 | |||
@@ -73,7 +73,7 @@ import com.vaadin.shared.ui.window.WindowRole; | |||
/** | |||
* "Sub window" component. | |||
* | |||
* | |||
* @author Vaadin Ltd | |||
*/ | |||
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
@@ -295,7 +295,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Returns true if this window is the topmost VWindow | |||
* | |||
* | |||
* @return | |||
*/ | |||
private boolean isActive() { | |||
@@ -437,7 +437,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* is prevented. | |||
* <p> | |||
* This message is not visible on the screen. | |||
* | |||
* | |||
* @param topMessage | |||
* String provided when the user navigates with Shift-Tab keys to | |||
* the top of the window | |||
@@ -452,7 +452,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* key is prevented. | |||
* <p> | |||
* This message is not visible on the screen. | |||
* | |||
* | |||
* @param bottomMessage | |||
* String provided when the user navigates with the Tab key to | |||
* the bottom of the window | |||
@@ -465,7 +465,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* Gets the message that is provided to users of assistive devices when the | |||
* user reaches the top of the window when leaving a window with the tab key | |||
* is prevented. | |||
* | |||
* | |||
* @return the top message | |||
*/ | |||
public String getTabStopTopAssistiveText() { | |||
@@ -476,7 +476,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* Gets the message that is provided to users of assistive devices when the | |||
* user reaches the bottom of the window when leaving a window with the tab | |||
* key is prevented. | |||
* | |||
* | |||
* @return the bottom message | |||
*/ | |||
public String getTabStopBottomAssistiveText() { | |||
@@ -554,41 +554,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/* | |||
* Shake up the DOM a bit to make the window shed unnecessary | |||
* scrollbars and resize correctly afterwards. This resulting code | |||
* took over a week to summon forth, and involved some pretty hairy | |||
* black magic. Don't touch it unless you know what you're doing! | |||
* Fixes ticket #11994 | |||
* scrollbars and resize correctly afterwards. The version fixing | |||
* ticket #11994 which was changing the size to 110% was replaced | |||
* with this due to ticket #12943 | |||
*/ | |||
Scheduler.get().scheduleFinally(new ScheduledCommand() { | |||
@Override | |||
public void execute() { | |||
final com.google.gwt.dom.client.Element scrollable = contents | |||
.getFirstChildElement(); | |||
// Adjusting the width or height may change the scroll | |||
// position, so store the current position | |||
int horizontalScrollPosition = scrollable.getScrollLeft(); | |||
int verticalScrollPosition = scrollable.getScrollTop(); | |||
final String oldWidth = scrollable.getStyle().getWidth(); | |||
final String oldHeight = scrollable.getStyle().getHeight(); | |||
scrollable.getStyle().setWidth(110, Unit.PCT); | |||
scrollable.getOffsetWidth(); | |||
scrollable.getStyle().setProperty("width", oldWidth); | |||
scrollable.getStyle().setHeight(110, Unit.PCT); | |||
scrollable.getOffsetHeight(); | |||
scrollable.getStyle().setProperty("height", oldHeight); | |||
// Restore the scroll position | |||
scrollable.setScrollLeft(horizontalScrollPosition); | |||
scrollable.setScrollTop(verticalScrollPosition); | |||
updateContentsSize(); | |||
positionOrSizeUpdated(); | |||
} | |||
}); | |||
Util.runWebkitOverflowAutoFix(contents.getFirstChildElement()); | |||
} | |||
} | |||
@@ -616,7 +586,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Sets the closable state of the window. Additionally hides/shows the close | |||
* button according to the new state. | |||
* | |||
* | |||
* @param closable | |||
* true if the window can be closed by the user | |||
*/ | |||
@@ -638,7 +608,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* Returns the closable state of the sub window. If the sub window is | |||
* closable a decoration (typically an X) is shown to the user. By clicking | |||
* on the X the user can close the window. | |||
* | |||
* | |||
* @return true if the sub window is closable | |||
*/ | |||
protected boolean isClosable() { | |||
@@ -902,7 +872,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Setter for the text for assistive devices the window caption is prefixed | |||
* with. | |||
* | |||
* | |||
* @param assistivePrefix | |||
* the assistivePrefix to set | |||
*/ | |||
@@ -913,7 +883,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Getter for the text for assistive devices the window caption is prefixed | |||
* with. | |||
* | |||
* | |||
* @return the assistivePrefix | |||
*/ | |||
public String getAssistivePrefix() { | |||
@@ -923,7 +893,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Setter for the text for assistive devices the window caption is postfixed | |||
* with. | |||
* | |||
* | |||
* @param assistivePostfix | |||
* the assistivePostfix to set | |||
*/ | |||
@@ -934,7 +904,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Getter for the text for assistive devices the window caption is postfixed | |||
* with. | |||
* | |||
* | |||
* @return the assistivePostfix | |||
*/ | |||
public String getAssistivePostfix() { | |||
@@ -1086,14 +1056,14 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* TODO check if we need to support this with touch based devices. | |||
* | |||
* | |||
* Checks if the cursor was inside the browser content area when the event | |||
* happened. | |||
* | |||
* | |||
* @param event | |||
* The event to be checked | |||
* @return true, if the cursor is inside the browser content area | |||
* | |||
* | |||
* false, otherwise | |||
*/ | |||
private boolean cursorInsideBrowserContentArea(Event event) { | |||
@@ -1382,7 +1352,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* assistive devices when it is opened. | |||
* <p> | |||
* When the provided array is empty, an existing description is removed. | |||
* | |||
* | |||
* @param connectors | |||
* with the connectors of the widgets to use as description | |||
*/ | |||
@@ -1420,7 +1390,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* Gets the connectors that are used as assistive description. Text | |||
* contained in these connectors will be read by assistive devices when the | |||
* window is opened. | |||
* | |||
* | |||
* @return list of previously set connectors | |||
*/ | |||
public List<Connector> getAssistiveDescription() { | |||
@@ -1429,14 +1399,14 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Sets the WAI-ARIA role the window. | |||
* | |||
* | |||
* This role defines how an assistive device handles a window. Available | |||
* roles are alertdialog and dialog (@see <a | |||
* href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles | |||
* Model</a>). | |||
* | |||
* | |||
* The default role is dialog. | |||
* | |||
* | |||
* @param role | |||
* WAI-ARIA role to set for the window | |||
*/ | |||
@@ -1455,7 +1425,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
* The value of the parameter doTabStop is stored and used for non-modal | |||
* windows. For modal windows, the handlers are always registered, while | |||
* preserving the stored value. | |||
* | |||
* | |||
* @param doTabStop | |||
* true to prevent leaving the window, false to allow leaving the | |||
* window for non modal windows | |||
@@ -1472,9 +1442,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | |||
/** | |||
* Adds a Handler for when user moves the window. | |||
* | |||
* | |||
* @since 7.1.9 | |||
* | |||
* | |||
* @return {@link HandlerRegistration} used to remove the handler | |||
*/ | |||
public HandlerRegistration addMoveHandler(WindowMoveHandler handler) { |
@@ -21,7 +21,6 @@ import com.google.gwt.core.client.Scheduler; | |||
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.Style.Position; | |||
import com.google.gwt.user.client.Command; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.client.ApplicationConnection; | |||
import com.vaadin.client.BrowserInfo; | |||
@@ -210,13 +209,8 @@ public class TableConnector extends AbstractHasComponentsConnector implements | |||
// by changing overflows as the length of the contents | |||
// *shouldn't* have changed (unless the number of rows | |||
// or the height of the widget has also changed) | |||
Scheduler.get().scheduleDeferred(new Command() { | |||
@Override | |||
public void execute() { | |||
Util.runWebkitOverflowAutoFix(getWidget().scrollBodyPanel | |||
.getElement()); | |||
} | |||
}); | |||
Util.runWebkitOverflowAutoFixDeferred(getWidget().scrollBodyPanel | |||
.getElement()); | |||
} | |||
} else { | |||
getWidget().initializeRows(uidl, rowData); |
@@ -0,0 +1,103 @@ | |||
/* | |||
* 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.window; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.ui.Alignment; | |||
import com.vaadin.ui.Button; | |||
import com.vaadin.ui.Button.ClickEvent; | |||
import com.vaadin.ui.Button.ClickListener; | |||
import com.vaadin.ui.Panel; | |||
import com.vaadin.ui.VerticalLayout; | |||
import com.vaadin.ui.Window; | |||
/** | |||
* Reproducing bug #12943 where an action on a Button or ComboBox placed at the | |||
* bottom of a window in a scroll panel, will scroll up the parent panel. | |||
* | |||
* This was due to the fact that with the state confirmation notification from | |||
* the server, the window.setVisible would be call again, and the hack that | |||
* solved the scrollbars in a window (#11994) would cause the our bug. | |||
* | |||
* @since | |||
* @author Vaadin Ltd | |||
*/ | |||
@SuppressWarnings("serial") | |||
public class BottomComponentScrollsUp extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
Button b = new Button("Open window"); | |||
addComponent(b); | |||
b.addClickListener(new ClickListener() { | |||
@Override | |||
public void buttonClick(ClickEvent event) { | |||
openWindow(); | |||
} | |||
}); | |||
openWindow(); | |||
} | |||
private void openWindow() { | |||
Window w = new Window(); | |||
w.setWidth("300px"); | |||
w.setHeight("300px"); | |||
w.center(); | |||
Panel p = createPanel(); | |||
p.setSizeFull(); | |||
w.setContent(p); | |||
addWindow(w); | |||
} | |||
private Panel createPanel() { | |||
Panel p = new Panel(); | |||
VerticalLayout content = new VerticalLayout(); | |||
p.setContent(content); | |||
content.setHeight("500px"); | |||
List<String> items = new ArrayList<String>(); | |||
items.add("1"); | |||
items.add("2"); | |||
items.add("3"); | |||
Button button = new Button("Press me"); | |||
content.addComponent(button); | |||
content.setComponentAlignment(button, Alignment.BOTTOM_CENTER); | |||
return p; | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Interacting with a component at the bottom of scrollable panel within a subwindow scrolls up"; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 12943; | |||
} | |||
} |
@@ -0,0 +1,71 @@ | |||
/* | |||
* 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.window; | |||
import java.io.IOException; | |||
import org.junit.Test; | |||
import org.openqa.selenium.By; | |||
import org.openqa.selenium.Dimension; | |||
import org.openqa.selenium.WebElement; | |||
import org.openqa.selenium.interactions.Actions; | |||
import com.vaadin.testbench.TestBenchElement; | |||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||
/** | |||
* Automatic test for fix for #12943. | |||
* | |||
* While testing without the fix, the test failed on both Chrome and PhantomJS. | |||
* | |||
* @since | |||
* @author Vaadin Ltd | |||
*/ | |||
public class BottomComponentScrollsUpTest extends MultiBrowserTest { | |||
@Override | |||
public void setup() throws Exception { | |||
super.setup(); | |||
openTestURL(); | |||
} | |||
@Test | |||
public void windowScrollTest() throws IOException, InterruptedException { | |||
TestBenchElement panelScrollable = (TestBenchElement) getDriver() | |||
.findElement(By.className("v-panel-content")); | |||
Dimension panelScrollableSize = panelScrollable.getSize(); | |||
WebElement verticalLayout = panelScrollable.findElement(By | |||
.className("v-verticallayout")); | |||
Dimension verticalLayoutSize = verticalLayout.getSize(); | |||
panelScrollable.scroll(verticalLayoutSize.height); | |||
WebElement button = verticalLayout | |||
.findElement(By.className("v-button")); | |||
button.click(); | |||
// Loose the focus from the button. | |||
new Actions(getDriver()) | |||
.moveToElement(panelScrollable, panelScrollableSize.width / 2, | |||
panelScrollableSize.height / 2).click().build() | |||
.perform(); | |||
compareScreen("window"); | |||
} | |||
} |