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
<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> |
import com.google.gwt.user.client.ui.HasWidgets; | import com.google.gwt.user.client.ui.HasWidgets; | ||||
import com.google.gwt.user.client.ui.Widget; | import com.google.gwt.user.client.ui.Widget; | ||||
import com.vaadin.client.ApplicationConfiguration.ErrorMessage; | import com.vaadin.client.ApplicationConfiguration.ErrorMessage; | ||||
import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; | |||||
import com.vaadin.client.ResourceLoader.ResourceLoadEvent; | import com.vaadin.client.ResourceLoader.ResourceLoadEvent; | ||||
import com.vaadin.client.ResourceLoader.ResourceLoadListener; | import com.vaadin.client.ResourceLoader.ResourceLoadListener; | ||||
import com.vaadin.client.communication.HasJavaScriptConnectorHelper; | import com.vaadin.client.communication.HasJavaScriptConnectorHelper; |
return detectedScrollbarSize; | 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. | * Run workaround for webkits overflow auto issue. | ||||
* | * |
* Ensures the column alignments are correct at initial loading. <br/> | * Ensures the column alignments are correct at initial loading. <br/> | ||||
* (child components widths are correct) | * (child components widths are correct) | ||||
*/ | */ | ||||
Scheduler.get().scheduleDeferred(new Command() { | |||||
@Override | |||||
public void execute() { | |||||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||||
} | |||||
}); | |||||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||||
hadScrollBars = willHaveScrollbarz; | hadScrollBars = willHaveScrollbarz; | ||||
} | } | ||||
Util.notifyParentOfSizeChange(VScrollTable.this, rendering); | Util.notifyParentOfSizeChange(VScrollTable.this, rendering); | ||||
} | } | ||||
} | } | ||||
Scheduler.get().scheduleDeferred(new Command() { | |||||
@Override | |||||
public void execute() { | |||||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||||
} | |||||
}); | |||||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||||
forceRealignColumnHeaders(); | forceRealignColumnHeaders(); | ||||
} | } | ||||
// We must run the fix as a deferred command to prevent it from | // We must run the fix as a deferred command to prevent it from | ||||
// overwriting the scroll position with an outdated value, see | // overwriting the scroll position with an outdated value, see | ||||
// #7607. | // #7607. | ||||
Scheduler.get().scheduleDeferred(new Command() { | |||||
@Override | |||||
public void execute() { | |||||
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); | |||||
} | |||||
}); | |||||
Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); | |||||
} | } | ||||
triggerLazyColumnAdjustment(false); | triggerLazyColumnAdjustment(false); |
/* | /* | ||||
* Copyright 2000-2014 Vaadin Ltd. | * Copyright 2000-2014 Vaadin Ltd. | ||||
* | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | * 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 | * use this file except in compliance with the License. You may obtain a copy of | ||||
* the License at | * the License at | ||||
* | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
/** | /** | ||||
* "Sub window" component. | * "Sub window" component. | ||||
* | |||||
* | |||||
* @author Vaadin Ltd | * @author Vaadin Ltd | ||||
*/ | */ | ||||
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, | ||||
/** | /** | ||||
* Returns true if this window is the topmost VWindow | * Returns true if this window is the topmost VWindow | ||||
* | |||||
* | |||||
* @return | * @return | ||||
*/ | */ | ||||
private boolean isActive() { | private boolean isActive() { | ||||
* is prevented. | * is prevented. | ||||
* <p> | * <p> | ||||
* This message is not visible on the screen. | * This message is not visible on the screen. | ||||
* | |||||
* | |||||
* @param topMessage | * @param topMessage | ||||
* String provided when the user navigates with Shift-Tab keys to | * String provided when the user navigates with Shift-Tab keys to | ||||
* the top of the window | * the top of the window | ||||
* key is prevented. | * key is prevented. | ||||
* <p> | * <p> | ||||
* This message is not visible on the screen. | * This message is not visible on the screen. | ||||
* | |||||
* | |||||
* @param bottomMessage | * @param bottomMessage | ||||
* String provided when the user navigates with the Tab key to | * String provided when the user navigates with the Tab key to | ||||
* the bottom of the window | * the bottom of the window | ||||
* Gets the message that is provided to users of assistive devices when the | * 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 | * user reaches the top of the window when leaving a window with the tab key | ||||
* is prevented. | * is prevented. | ||||
* | |||||
* | |||||
* @return the top message | * @return the top message | ||||
*/ | */ | ||||
public String getTabStopTopAssistiveText() { | public String getTabStopTopAssistiveText() { | ||||
* Gets the message that is provided to users of assistive devices when the | * 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 | * user reaches the bottom of the window when leaving a window with the tab | ||||
* key is prevented. | * key is prevented. | ||||
* | |||||
* | |||||
* @return the bottom message | * @return the bottom message | ||||
*/ | */ | ||||
public String getTabStopBottomAssistiveText() { | public String getTabStopBottomAssistiveText() { | ||||
/* | /* | ||||
* Shake up the DOM a bit to make the window shed unnecessary | * 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()); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Sets the closable state of the window. Additionally hides/shows the close | * Sets the closable state of the window. Additionally hides/shows the close | ||||
* button according to the new state. | * button according to the new state. | ||||
* | |||||
* | |||||
* @param closable | * @param closable | ||||
* true if the window can be closed by the user | * true if the window can be closed by the user | ||||
*/ | */ | ||||
* Returns the closable state of the sub window. If the sub window is | * 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 | * closable a decoration (typically an X) is shown to the user. By clicking | ||||
* on the X the user can close the window. | * on the X the user can close the window. | ||||
* | |||||
* | |||||
* @return true if the sub window is closable | * @return true if the sub window is closable | ||||
*/ | */ | ||||
protected boolean isClosable() { | protected boolean isClosable() { | ||||
/** | /** | ||||
* Setter for the text for assistive devices the window caption is prefixed | * Setter for the text for assistive devices the window caption is prefixed | ||||
* with. | * with. | ||||
* | |||||
* | |||||
* @param assistivePrefix | * @param assistivePrefix | ||||
* the assistivePrefix to set | * the assistivePrefix to set | ||||
*/ | */ | ||||
/** | /** | ||||
* Getter for the text for assistive devices the window caption is prefixed | * Getter for the text for assistive devices the window caption is prefixed | ||||
* with. | * with. | ||||
* | |||||
* | |||||
* @return the assistivePrefix | * @return the assistivePrefix | ||||
*/ | */ | ||||
public String getAssistivePrefix() { | public String getAssistivePrefix() { | ||||
/** | /** | ||||
* Setter for the text for assistive devices the window caption is postfixed | * Setter for the text for assistive devices the window caption is postfixed | ||||
* with. | * with. | ||||
* | |||||
* | |||||
* @param assistivePostfix | * @param assistivePostfix | ||||
* the assistivePostfix to set | * the assistivePostfix to set | ||||
*/ | */ | ||||
/** | /** | ||||
* Getter for the text for assistive devices the window caption is postfixed | * Getter for the text for assistive devices the window caption is postfixed | ||||
* with. | * with. | ||||
* | |||||
* | |||||
* @return the assistivePostfix | * @return the assistivePostfix | ||||
*/ | */ | ||||
public String getAssistivePostfix() { | public String getAssistivePostfix() { | ||||
/** | /** | ||||
* TODO check if we need to support this with touch based devices. | * 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 | * Checks if the cursor was inside the browser content area when the event | ||||
* happened. | * happened. | ||||
* | |||||
* | |||||
* @param event | * @param event | ||||
* The event to be checked | * The event to be checked | ||||
* @return true, if the cursor is inside the browser content area | * @return true, if the cursor is inside the browser content area | ||||
* | |||||
* | |||||
* false, otherwise | * false, otherwise | ||||
*/ | */ | ||||
private boolean cursorInsideBrowserContentArea(Event event) { | private boolean cursorInsideBrowserContentArea(Event event) { | ||||
* assistive devices when it is opened. | * assistive devices when it is opened. | ||||
* <p> | * <p> | ||||
* When the provided array is empty, an existing description is removed. | * When the provided array is empty, an existing description is removed. | ||||
* | |||||
* | |||||
* @param connectors | * @param connectors | ||||
* with the connectors of the widgets to use as description | * with the connectors of the widgets to use as description | ||||
*/ | */ | ||||
* Gets the connectors that are used as assistive description. Text | * Gets the connectors that are used as assistive description. Text | ||||
* contained in these connectors will be read by assistive devices when the | * contained in these connectors will be read by assistive devices when the | ||||
* window is opened. | * window is opened. | ||||
* | |||||
* | |||||
* @return list of previously set connectors | * @return list of previously set connectors | ||||
*/ | */ | ||||
public List<Connector> getAssistiveDescription() { | public List<Connector> getAssistiveDescription() { | ||||
/** | /** | ||||
* Sets the WAI-ARIA role the window. | * Sets the WAI-ARIA role the window. | ||||
* | |||||
* | |||||
* This role defines how an assistive device handles a window. Available | * This role defines how an assistive device handles a window. Available | ||||
* roles are alertdialog and dialog (@see <a | * roles are alertdialog and dialog (@see <a | ||||
* href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles | * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles | ||||
* Model</a>). | * Model</a>). | ||||
* | |||||
* | |||||
* The default role is dialog. | * The default role is dialog. | ||||
* | |||||
* | |||||
* @param role | * @param role | ||||
* WAI-ARIA role to set for the window | * WAI-ARIA role to set for the window | ||||
*/ | */ | ||||
* The value of the parameter doTabStop is stored and used for non-modal | * The value of the parameter doTabStop is stored and used for non-modal | ||||
* windows. For modal windows, the handlers are always registered, while | * windows. For modal windows, the handlers are always registered, while | ||||
* preserving the stored value. | * preserving the stored value. | ||||
* | |||||
* | |||||
* @param doTabStop | * @param doTabStop | ||||
* true to prevent leaving the window, false to allow leaving the | * true to prevent leaving the window, false to allow leaving the | ||||
* window for non modal windows | * window for non modal windows | ||||
/** | /** | ||||
* Adds a Handler for when user moves the window. | * Adds a Handler for when user moves the window. | ||||
* | |||||
* | |||||
* @since 7.1.9 | * @since 7.1.9 | ||||
* | |||||
* | |||||
* @return {@link HandlerRegistration} used to remove the handler | * @return {@link HandlerRegistration} used to remove the handler | ||||
*/ | */ | ||||
public HandlerRegistration addMoveHandler(WindowMoveHandler handler) { | public HandlerRegistration addMoveHandler(WindowMoveHandler handler) { |
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | import com.google.gwt.core.client.Scheduler.ScheduledCommand; | ||||
import com.google.gwt.dom.client.Element; | import com.google.gwt.dom.client.Element; | ||||
import com.google.gwt.dom.client.Style.Position; | 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.google.gwt.user.client.ui.Widget; | ||||
import com.vaadin.client.ApplicationConnection; | import com.vaadin.client.ApplicationConnection; | ||||
import com.vaadin.client.BrowserInfo; | import com.vaadin.client.BrowserInfo; | ||||
// by changing overflows as the length of the contents | // by changing overflows as the length of the contents | ||||
// *shouldn't* have changed (unless the number of rows | // *shouldn't* have changed (unless the number of rows | ||||
// or the height of the widget has also changed) | // 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 { | } else { | ||||
getWidget().initializeRows(uidl, rowData); | getWidget().initializeRows(uidl, rowData); |
/* | |||||
* 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; | |||||
} | |||||
} |
/* | |||||
* 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"); | |||||
} | |||||
} |